diff --git a/npm/ng-packs/packages/oauth/package.json b/npm/ng-packs/packages/oauth/package.json index 99c4a06485..60839d84fb 100644 --- a/npm/ng-packs/packages/oauth/package.json +++ b/npm/ng-packs/packages/oauth/package.json @@ -6,6 +6,9 @@ "type": "git", "url": "https://github.com/abpframework/abp.git" }, + "scripts": { + "build:worker": "esbuild src/lib/workers/token-storage.worker.ts --bundle --format=esm --target=es2022 --outfile=src/lib/workers/token-storage.worker.js" + }, "dependencies": { "@abp/ng.core": "~10.0.1", "@abp/utils": "~10.0.1", diff --git a/npm/ng-packs/packages/oauth/project.json b/npm/ng-packs/packages/oauth/project.json index 61662f4811..98c7cba04f 100644 --- a/npm/ng-packs/packages/oauth/project.json +++ b/npm/ng-packs/packages/oauth/project.json @@ -5,6 +5,13 @@ "sourceRoot": "packages/oauth/src", "prefix": "abp", "targets": { + "build-worker": { + "executor": "nx:run-commands", + "options": { + "command": "esbuild src/lib/workers/token-storage.worker.ts --bundle --format=esm --target=es2022 --outfile=src/lib/workers/token-storage.worker.js", + "cwd": "packages/oauth" + } + }, "build": { "executor": "@nx/angular:package", "outputs": ["{workspaceRoot}/dist/packages/oauth"], @@ -19,7 +26,8 @@ "tsConfig": "packages/oauth/tsconfig.lib.json" } }, - "defaultConfiguration": "production" + "defaultConfiguration": "production", + "dependsOn": ["build-worker"] }, "test": { "executor": "@nx/jest:jest", diff --git a/npm/ng-packs/packages/oauth/src/lib/services/memory-token-storage.service.ts b/npm/ng-packs/packages/oauth/src/lib/services/memory-token-storage.service.ts index 218b02ac22..06402c842b 100644 --- a/npm/ng-packs/packages/oauth/src/lib/services/memory-token-storage.service.ts +++ b/npm/ng-packs/packages/oauth/src/lib/services/memory-token-storage.service.ts @@ -31,7 +31,7 @@ export class MemoryTokenStorageService implements OAuthStorage { // @ts-ignore this.worker = new SharedWorker( new URL( - '../workers/token-storage.worker.js', + '../workers/token-storage.worker.ts', import.meta.url ), { name: 'oauth-token-storage', type: "module" } diff --git a/npm/ng-packs/packages/oauth/src/lib/workers/token-storage.worker.js b/npm/ng-packs/packages/oauth/src/lib/workers/token-storage.worker.js index 2e12c54b07..b4032ce09a 100644 --- a/npm/ng-packs/packages/oauth/src/lib/workers/token-storage.worker.js +++ b/npm/ng-packs/packages/oauth/src/lib/workers/token-storage.worker.js @@ -1,65 +1,62 @@ -// ESM SharedWorker - -const tokenStore = new Map(); -const ports = new Set(); - -// Broadcast message to all ports except the sender and remove dead ports +// src/lib/workers/token-storage.worker.ts +var tokenStore = /* @__PURE__ */ new Map(); +var ports = /* @__PURE__ */ new Set(); function broadcastToOtherPorts(senderPort, message) { const deadPorts = []; - - ports.forEach(p => { + ports.forEach((p) => { if (p !== senderPort) { try { p.postMessage(message); } catch (error) { - console.log('Dead port detected, removing...'); + console.log("Dead port detected, removing..."); deadPorts.push(p); } } }); - - // Clean up dead ports - deadPorts.forEach(p => ports.delete(p)); + deadPorts.forEach((p) => ports.delete(p)); + if (deadPorts.length > 0) { + console.log("Cleaned up dead ports. Total ports:", ports.size); + } } - self.onconnect = (event) => { const port = event.ports[0]; ports.add(port); - - // Clean up port when it's closed - port.addEventListener('messageerror', () => { + console.log("Port connected. Total ports:", ports.size); + port.addEventListener("messageerror", () => { ports.delete(port); - console.log('Port disconnected (error). Total ports:', ports.size); + console.log("Port disconnected (error). Total ports:", ports.size); }); - port.onmessage = (e) => { const { action, key, value } = e.data; switch (action) { - case 'set': - if (key && value !== undefined) { + case "set": + if (key && value !== void 0) { tokenStore.set(key, value); - broadcastToOtherPorts(port, { action: 'set', key, value }); + broadcastToOtherPorts(port, { action: "set", key, value }); } break; - case 'remove': + case "remove": if (key) { + console.log("remove", key); tokenStore.delete(key); - broadcastToOtherPorts(port, { action: 'remove', key }); + broadcastToOtherPorts(port, { action: "remove", key }); } break; - case 'clear': + case "clear": + console.log("clear user"); tokenStore.clear(); - broadcastToOtherPorts(port, { action: 'clear' }); + broadcastToOtherPorts(port, { action: "clear" }); break; - case 'get': + case "get": + console.log("get user"); if (key) { - const value = tokenStore.get(key) ?? null; - port.postMessage({ action: 'get', key, value }); + const value2 = tokenStore.get(key) ?? null; + port.postMessage({ action: "get", key, value: value2 }); } break; + default: + console.warn("Unknown action:", action); } }; port.start(); }; - -export {}; diff --git a/npm/ng-packs/packages/oauth/src/lib/workers/token-storage.worker.ts b/npm/ng-packs/packages/oauth/src/lib/workers/token-storage.worker.ts new file mode 100644 index 0000000000..a5c422738a --- /dev/null +++ b/npm/ng-packs/packages/oauth/src/lib/workers/token-storage.worker.ts @@ -0,0 +1,98 @@ +/// + +// Message types for type safety +interface TokenMessage { + action: 'set' | 'remove' | 'clear' | 'get'; + key?: string; + value?: string; +} + +interface TokenResponse { + action: 'set' | 'remove' | 'clear' | 'get'; + key?: string; + value?: string | null; +} + +declare const self: SharedWorkerGlobalScope; + +const tokenStore = new Map(); +const ports = new Set(); + +// Broadcast message to all ports except the sender +// Automatically cleans up dead ports +function broadcastToOtherPorts(senderPort: MessagePort, message: TokenResponse): void { + const deadPorts: MessagePort[] = []; + + ports.forEach(p => { + if (p !== senderPort) { + try { + p.postMessage(message); + } catch (error) { + // Port is dead/closed, mark for removal + console.log('Dead port detected, removing...'); + deadPorts.push(p); + } + } + }); + + // Clean up dead ports + deadPorts.forEach(p => ports.delete(p)); + + if (deadPorts.length > 0) { + console.log('Cleaned up dead ports. Total ports:', ports.size); + } +} + +self.onconnect = (event: MessageEvent) => { + const port = event.ports[0]; + ports.add(port); + console.log('Port connected. Total ports:', ports.size); + + // Clean up port when it's closed + port.addEventListener('messageerror', () => { + ports.delete(port); + console.log('Port disconnected (error). Total ports:', ports.size); + }); + + port.onmessage = (e: MessageEvent) => { + const { action, key, value } = e.data; + + switch (action) { + case 'set': + if (key && value !== undefined) { + tokenStore.set(key, value); + broadcastToOtherPorts(port, { action: 'set', key, value }); + } + break; + + case 'remove': + if (key) { + console.log('remove', key); + tokenStore.delete(key); + broadcastToOtherPorts(port, { action: 'remove', key }); + } + break; + + case 'clear': + console.log('clear user'); + tokenStore.clear(); + broadcastToOtherPorts(port, { action: 'clear' }); + break; + + case 'get': + console.log('get user'); + if (key) { + const value = tokenStore.get(key) ?? null; + port.postMessage({ action: 'get', key, value } as TokenResponse); + } + break; + + default: + console.warn('Unknown action:', action); + } + }; + + port.start(); +}; + +export {};