@mcp-fe/mcp-worker 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -6
- package/index.js +353 -155
- package/mcp-service-worker.js +28101 -29
- package/mcp-shared-worker.js +28146 -45
- package/package.json +1 -1
- package/src/index.d.ts +5 -0
- package/src/index.d.ts.map +1 -0
- package/src/lib/database.d.ts.map +1 -0
- package/{lib → src/lib}/mcp-controller.d.ts +11 -0
- package/src/lib/mcp-controller.d.ts.map +1 -0
- package/{lib → src/lib}/mcp-server.d.ts +4 -0
- package/src/lib/mcp-server.d.ts.map +1 -0
- package/src/lib/websocket-transport.d.ts.map +1 -0
- package/src/lib/worker-client.d.ts +69 -0
- package/src/lib/worker-client.d.ts.map +1 -0
- package/src/mcp-service-worker.d.ts.map +1 -0
- package/src/mcp-shared-worker.d.ts.map +1 -0
- package/database.js +0 -49
- package/database.js.map +0 -1
- package/index.d.ts +0 -3
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/lib/database.d.ts.map +0 -1
- package/lib/mcp-controller.d.ts.map +0 -1
- package/lib/mcp-server.d.ts.map +0 -1
- package/lib/websocket-transport.d.ts.map +0 -1
- package/lib/worker-client.d.ts +0 -20
- package/lib/worker-client.d.ts.map +0 -1
- package/mcp-controller.js +0 -10565
- package/mcp-controller.js.map +0 -1
- package/mcp-service-worker.d.ts.map +0 -1
- package/mcp-service-worker.js.map +0 -1
- package/mcp-shared-worker.d.ts.map +0 -1
- package/mcp-shared-worker.js.map +0 -1
- /package/{lib → src/lib}/database.d.ts +0 -0
- /package/{lib → src/lib}/websocket-transport.d.ts +0 -0
- /package/{mcp-service-worker.d.ts → src/mcp-service-worker.d.ts} +0 -0
- /package/{mcp-shared-worker.d.ts → src/mcp-shared-worker.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,11 +1,62 @@
|
|
|
1
|
-
# mcp-worker
|
|
1
|
+
# @mcp-fe/mcp-worker
|
|
2
2
|
|
|
3
|
-
This library
|
|
3
|
+
This library provides a client adapter and ready-to-use worker scripts for working with MCP (Model Context Protocol).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Exports
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- `index` — the main client module (exports the `workerClient` singleton and related types). Import this in your client application.
|
|
8
|
+
- `mcp-service-worker.js` — Service Worker implementation intended to be registered via `navigator.serviceWorker.register(...)`.
|
|
9
|
+
- `mcp-shared-worker.js` — SharedWorker implementation intended to be started via `new SharedWorker(...)`.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
Note: Worker script files (service/shared) must be available on your application's public path so the browser can fetch them (for example `/mcp-service-worker.js` and `/mcp-shared-worker.js`).
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
Quick start
|
|
14
|
+
|
|
15
|
+
1) Make worker files available on your public path
|
|
16
|
+
|
|
17
|
+
- Copy the worker files (`mcp-service-worker.js`, `mcp-shared-worker.js`) into the folder your webserver serves as public (for example `public/` or `dist/`).
|
|
18
|
+
- Important: the URL used during registration must match the actual location of the files. The `WorkerClient` defaults to `/mcp-shared-worker.js` and `/mcp-service-worker.js`.
|
|
19
|
+
If you place them elsewhere, pass the correct URLs to `init`.
|
|
20
|
+
|
|
21
|
+
3) Import and initialize in your client app
|
|
22
|
+
|
|
23
|
+
Example (TypeScript):
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { workerClient } from '@mcp-fe/mcp-worker';
|
|
27
|
+
|
|
28
|
+
// Optionally provide custom worker URLs and backend WebSocket URL
|
|
29
|
+
await workerClient.init({
|
|
30
|
+
sharedWorkerUrl: '/mcp-shared-worker.js',
|
|
31
|
+
serviceWorkerUrl: '/mcp-service-worker.js',
|
|
32
|
+
backendWsUrl: 'wss://your-backend.example/ws'
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Set an auth token (if you use authentication)
|
|
36
|
+
workerClient.setAuthToken('Bearer ...');
|
|
37
|
+
|
|
38
|
+
// Send an event to the worker (fire-and-forget)
|
|
39
|
+
await workerClient.post('STORE_EVENT', { event: { /* ... */ } });
|
|
40
|
+
|
|
41
|
+
// Request events (request/response)
|
|
42
|
+
const res = await workerClient.request('GET_EVENTS');
|
|
43
|
+
if (res && (res as any).events) {
|
|
44
|
+
console.log('Events:', (res as any).events);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Alternatively, register the Service Worker yourself and pass the registration to `init`:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// register the service worker (e.g. in your app entry file)
|
|
52
|
+
const registration = await navigator.serviceWorker.register('/mcp-service-worker.js');
|
|
53
|
+
await workerClient.init(registration);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Notes & best practices
|
|
57
|
+
|
|
58
|
+
- `WorkerClient` prefers `SharedWorker` (shared across windows/iframes on the same origin). If `SharedWorker` is not available, it will automatically fall back to `ServiceWorker`.
|
|
59
|
+
- If you need different worker URLs, pass `sharedWorkerUrl` and `serviceWorkerUrl` to `workerClient.init(...)`.
|
|
60
|
+
- Worker scripts must be served from the same origin as your app.
|
|
61
|
+
- Calling `workerClient.setAuthToken(...)` before initialization is allowed: the client will queue the token and send it when a worker becomes available.
|
|
62
|
+
- The default worker URLs are `/mcp-shared-worker.js` and `/mcp-service-worker.js`.
|
package/index.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
class
|
|
1
|
+
// libs/mcp-worker/src/lib/worker-client.ts
|
|
2
|
+
var WorkerClient = class {
|
|
3
|
+
// Configurable worker script URLs (defaults kept for backward compatibility)
|
|
4
|
+
sharedWorkerUrl = "/mcp-shared-worker.js";
|
|
5
|
+
serviceWorkerUrl = "/mcp-service-worker.js";
|
|
6
|
+
// Backend websocket URL to pass into the worker(s)
|
|
7
|
+
backendWsUrl = "ws://localhost:3001";
|
|
3
8
|
serviceWorkerRegistration = null;
|
|
4
9
|
sharedWorker = null;
|
|
5
10
|
sharedWorkerPort = null;
|
|
@@ -7,228 +12,421 @@ class l {
|
|
|
7
12
|
pendingAuthToken = null;
|
|
8
13
|
// connection status subscribers
|
|
9
14
|
connectionStatusCallbacks = /* @__PURE__ */ new Set();
|
|
10
|
-
serviceWorkerMessageHandler = null;
|
|
11
15
|
// Mutex/promise to prevent concurrent init runs
|
|
12
16
|
initPromise = null;
|
|
13
17
|
// Initialize and choose worker implementation (prefer SharedWorker)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
// Accept either a ServiceWorkerRegistration OR WorkerInitOptions to configure URLs
|
|
19
|
+
async init(registrationOrOptions) {
|
|
20
|
+
let explicitRegistration;
|
|
21
|
+
const maybeReg = registrationOrOptions;
|
|
22
|
+
if (maybeReg && typeof maybeReg.scope === "string") {
|
|
23
|
+
explicitRegistration = registrationOrOptions;
|
|
24
|
+
} else if (registrationOrOptions) {
|
|
25
|
+
const opts = registrationOrOptions;
|
|
26
|
+
if (opts.sharedWorkerUrl)
|
|
27
|
+
this.sharedWorkerUrl = opts.sharedWorkerUrl;
|
|
28
|
+
if (opts.serviceWorkerUrl)
|
|
29
|
+
this.serviceWorkerUrl = opts.serviceWorkerUrl;
|
|
30
|
+
if (opts.backendWsUrl)
|
|
31
|
+
this.backendWsUrl = opts.backendWsUrl;
|
|
32
|
+
}
|
|
33
|
+
if (this.initPromise) {
|
|
34
|
+
return this.initPromise.then(async () => {
|
|
35
|
+
if (explicitRegistration && this.workerType !== "service") {
|
|
36
|
+
await this.init(explicitRegistration);
|
|
22
37
|
}
|
|
23
|
-
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
this.initPromise = (async () => {
|
|
41
|
+
try {
|
|
42
|
+
if (explicitRegistration) {
|
|
43
|
+
this.serviceWorkerRegistration = explicitRegistration;
|
|
44
|
+
this.workerType = "service";
|
|
45
|
+
console.log(
|
|
46
|
+
"[WorkerClient] Using ServiceWorker (explicit registration)"
|
|
47
|
+
);
|
|
24
48
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
});
|
|
35
|
-
}, await new Promise((r, i) => {
|
|
36
|
-
let a = !1;
|
|
37
|
-
const n = setTimeout(() => {
|
|
38
|
-
if (!a) {
|
|
39
|
-
const o = this.sharedWorkerPort;
|
|
40
|
-
o && (o.onmessage = null), i(new Error("SharedWorker initialization timeout"));
|
|
41
|
-
}
|
|
42
|
-
}, 2e3), c = this.sharedWorkerPort;
|
|
43
|
-
if (!c)
|
|
44
|
-
return clearTimeout(n), i(new Error("SharedWorker port not available"));
|
|
45
|
-
c.onmessage = (o) => {
|
|
46
|
-
try {
|
|
47
|
-
const s = o.data;
|
|
48
|
-
s && s.type === "CONNECTION_STATUS" && (clearTimeout(n), a = !0, this.workerType = "shared", c.onmessage = null, r());
|
|
49
|
-
} catch {
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
});
|
|
53
|
-
const t = this.sharedWorkerPort;
|
|
54
|
-
if (this.pendingAuthToken && t)
|
|
55
|
-
try {
|
|
56
|
-
t.postMessage({ type: "SET_AUTH_TOKEN", token: this.pendingAuthToken }), this.pendingAuthToken = null;
|
|
57
|
-
} catch (r) {
|
|
58
|
-
console.error("[WorkerClient] Failed to send pending auth token to SharedWorker:", r);
|
|
59
|
-
}
|
|
60
|
-
t && (t.onmessage = (r) => {
|
|
61
|
-
try {
|
|
62
|
-
const i = r.data;
|
|
63
|
-
if (i && i.type === "CONNECTION_STATUS") {
|
|
64
|
-
const a = !!i.connected;
|
|
65
|
-
this.connectionStatusCallbacks.forEach((n) => {
|
|
66
|
-
try {
|
|
67
|
-
n(a);
|
|
68
|
-
} catch {
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
} catch {
|
|
73
|
-
}
|
|
74
|
-
}), console.log("[WorkerClient] Using SharedWorker");
|
|
75
|
-
return;
|
|
76
|
-
} catch (t) {
|
|
77
|
-
console.warn("[WorkerClient] SharedWorker not available, falling back to ServiceWorker:", t);
|
|
49
|
+
const initMsg = { type: "INIT", backendUrl: this.backendWsUrl };
|
|
50
|
+
if (this.pendingAuthToken)
|
|
51
|
+
initMsg["token"] = this.pendingAuthToken;
|
|
52
|
+
if (this.serviceWorkerRegistration.active) {
|
|
53
|
+
this.serviceWorkerRegistration.active.postMessage(initMsg);
|
|
54
|
+
} else if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
|
|
55
|
+
navigator.serviceWorker.controller.postMessage(initMsg);
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
78
58
|
}
|
|
79
|
-
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const sharedOk = await this.initSharedWorker();
|
|
62
|
+
if (sharedOk)
|
|
63
|
+
return;
|
|
64
|
+
await this.initServiceWorkerFallback();
|
|
80
65
|
} finally {
|
|
81
66
|
this.initPromise = null;
|
|
82
67
|
}
|
|
83
|
-
})()
|
|
68
|
+
})();
|
|
69
|
+
return this.initPromise;
|
|
84
70
|
}
|
|
85
|
-
async
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
71
|
+
async initSharedWorker() {
|
|
72
|
+
if (typeof SharedWorker === "undefined") {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
this.sharedWorker = new SharedWorker(this.sharedWorkerUrl, {
|
|
77
|
+
type: "module"
|
|
78
|
+
});
|
|
79
|
+
this.sharedWorkerPort = this.sharedWorker.port;
|
|
80
|
+
this.sharedWorkerPort.start();
|
|
81
|
+
await new Promise((resolve, reject) => {
|
|
82
|
+
let resolved = false;
|
|
83
|
+
const timeout = setTimeout(() => {
|
|
84
|
+
if (!resolved) {
|
|
85
|
+
const p2 = this.sharedWorkerPort;
|
|
86
|
+
if (p2)
|
|
87
|
+
p2.onmessage = null;
|
|
88
|
+
reject(new Error("SharedWorker initialization timeout"));
|
|
89
|
+
}
|
|
90
|
+
}, 2e3);
|
|
91
|
+
const p = this.sharedWorkerPort;
|
|
92
|
+
if (!p) {
|
|
93
|
+
clearTimeout(timeout);
|
|
94
|
+
return reject(new Error("SharedWorker port not available"));
|
|
92
95
|
}
|
|
93
|
-
|
|
94
|
-
this.serviceWorkerRegistration = t, this.workerType = "service", console.log("[WorkerClient] Using ServiceWorker (fallback)"), this.serviceWorkerMessageHandler && (navigator.serviceWorker.removeEventListener("message", this.serviceWorkerMessageHandler), this.serviceWorkerMessageHandler = null), this.serviceWorkerMessageHandler = (r) => {
|
|
96
|
+
p.onmessage = (ev) => {
|
|
95
97
|
try {
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const data = ev.data;
|
|
99
|
+
if (data && data.type === "CONNECTION_STATUS") {
|
|
100
|
+
clearTimeout(timeout);
|
|
101
|
+
resolved = true;
|
|
102
|
+
this.workerType = "shared";
|
|
103
|
+
p.onmessage = null;
|
|
104
|
+
resolve();
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
const portAfterInit = this.sharedWorkerPort;
|
|
111
|
+
if (portAfterInit) {
|
|
112
|
+
try {
|
|
113
|
+
const initMsg = { type: "INIT", backendUrl: this.backendWsUrl };
|
|
114
|
+
if (this.pendingAuthToken)
|
|
115
|
+
initMsg["token"] = this.pendingAuthToken;
|
|
116
|
+
portAfterInit.postMessage(initMsg);
|
|
117
|
+
this.pendingAuthToken = null;
|
|
118
|
+
} catch (e) {
|
|
119
|
+
console.warn("[WorkerClient] Failed to send INIT to SharedWorker port:", e);
|
|
120
|
+
}
|
|
121
|
+
portAfterInit.onmessage = (ev) => {
|
|
122
|
+
try {
|
|
123
|
+
const data = ev.data;
|
|
124
|
+
if (data && data.type === "CONNECTION_STATUS") {
|
|
125
|
+
const connected = !!data.connected;
|
|
126
|
+
this.connectionStatusCallbacks.forEach((cb) => {
|
|
100
127
|
try {
|
|
101
|
-
|
|
128
|
+
cb(connected);
|
|
102
129
|
} catch {
|
|
103
130
|
}
|
|
104
131
|
});
|
|
105
132
|
}
|
|
106
133
|
} catch {
|
|
107
134
|
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
console.log("[WorkerClient] Using SharedWorker");
|
|
138
|
+
return true;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.warn(
|
|
141
|
+
"[WorkerClient] SharedWorker not available, falling back to ServiceWorker:",
|
|
142
|
+
error
|
|
143
|
+
);
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async initServiceWorkerFallback() {
|
|
148
|
+
if ("serviceWorker" in navigator) {
|
|
149
|
+
try {
|
|
150
|
+
const existingRegistration = await navigator.serviceWorker.getRegistration();
|
|
151
|
+
if (existingRegistration) {
|
|
152
|
+
this.serviceWorkerRegistration = existingRegistration;
|
|
153
|
+
this.workerType = "service";
|
|
154
|
+
console.log(
|
|
155
|
+
"[WorkerClient] Using existing ServiceWorker registration"
|
|
156
|
+
);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
this.serviceWorkerRegistration = await navigator.serviceWorker.register(
|
|
160
|
+
this.serviceWorkerUrl
|
|
161
|
+
);
|
|
162
|
+
this.workerType = "service";
|
|
163
|
+
console.log("[WorkerClient] Using MCP ServiceWorker (fallback)");
|
|
164
|
+
try {
|
|
165
|
+
const initMsg = { type: "INIT", backendUrl: this.backendWsUrl };
|
|
166
|
+
if (this.pendingAuthToken)
|
|
167
|
+
initMsg["token"] = this.pendingAuthToken;
|
|
168
|
+
if (this.serviceWorkerRegistration.active) {
|
|
169
|
+
this.serviceWorkerRegistration.active.postMessage(initMsg);
|
|
170
|
+
} else if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
|
|
171
|
+
navigator.serviceWorker.controller.postMessage(initMsg);
|
|
172
|
+
}
|
|
173
|
+
this.pendingAuthToken = null;
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error(
|
|
178
|
+
"[WorkerClient] Failed to register ServiceWorker:",
|
|
179
|
+
error
|
|
180
|
+
);
|
|
181
|
+
throw error;
|
|
111
182
|
}
|
|
112
|
-
else
|
|
183
|
+
} else {
|
|
113
184
|
throw new Error("Neither SharedWorker nor ServiceWorker is supported");
|
|
185
|
+
}
|
|
114
186
|
}
|
|
115
187
|
// Low-level request that expects a reply via MessageChannel
|
|
116
|
-
async request(
|
|
117
|
-
if (this.workerType === "shared" && this.sharedWorkerPort)
|
|
118
|
-
return new Promise((
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
188
|
+
async request(type, payload, timeoutMs = 5e3) {
|
|
189
|
+
if (this.workerType === "shared" && this.sharedWorkerPort) {
|
|
190
|
+
return new Promise((resolve, reject) => {
|
|
191
|
+
const mc = new MessageChannel();
|
|
192
|
+
const timer = setTimeout(() => {
|
|
193
|
+
mc.port1.onmessage = null;
|
|
194
|
+
reject(new Error("Request timeout"));
|
|
195
|
+
}, timeoutMs);
|
|
196
|
+
mc.port1.onmessage = (ev) => {
|
|
197
|
+
clearTimeout(timer);
|
|
198
|
+
if (ev.data && ev.data.success) {
|
|
199
|
+
resolve(ev.data);
|
|
200
|
+
} else if (ev.data && ev.data.success === false) {
|
|
201
|
+
reject(new Error(ev.data.error || "Worker error"));
|
|
202
|
+
} else {
|
|
203
|
+
resolve(ev.data);
|
|
204
|
+
}
|
|
124
205
|
};
|
|
125
206
|
try {
|
|
126
|
-
const
|
|
127
|
-
if (!
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
207
|
+
const port = this.sharedWorkerPort;
|
|
208
|
+
if (!port) {
|
|
209
|
+
clearTimeout(timer);
|
|
210
|
+
return reject(new Error("SharedWorker port not available"));
|
|
211
|
+
}
|
|
212
|
+
port.postMessage({ type, ...payload || {} }, [mc.port2]);
|
|
213
|
+
} catch (e) {
|
|
214
|
+
clearTimeout(timer);
|
|
215
|
+
reject(e instanceof Error ? e : new Error(String(e)));
|
|
132
216
|
}
|
|
133
217
|
});
|
|
218
|
+
}
|
|
134
219
|
if (this.workerType === "service" && this.serviceWorkerRegistration) {
|
|
135
|
-
const
|
|
136
|
-
if (!
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
220
|
+
const reg = this.serviceWorkerRegistration;
|
|
221
|
+
if (!reg)
|
|
222
|
+
throw new Error("Service worker registration missing");
|
|
223
|
+
if (!reg.active) {
|
|
224
|
+
await navigator.serviceWorker.ready;
|
|
225
|
+
if (!reg.active) {
|
|
226
|
+
throw new Error("Service worker not active");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return new Promise((resolve, reject) => {
|
|
230
|
+
const mc = new MessageChannel();
|
|
231
|
+
const timer = setTimeout(() => {
|
|
232
|
+
mc.port1.onmessage = null;
|
|
233
|
+
reject(new Error("Request timeout"));
|
|
234
|
+
}, timeoutMs);
|
|
235
|
+
mc.port1.onmessage = (ev) => {
|
|
236
|
+
clearTimeout(timer);
|
|
237
|
+
if (ev.data && ev.data.success) {
|
|
238
|
+
resolve(ev.data);
|
|
239
|
+
} else if (ev.data && ev.data.success === false) {
|
|
240
|
+
reject(new Error(ev.data.error || "Worker error"));
|
|
241
|
+
} else {
|
|
242
|
+
resolve(ev.data);
|
|
243
|
+
}
|
|
145
244
|
};
|
|
146
245
|
try {
|
|
147
|
-
const
|
|
148
|
-
if (!
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
246
|
+
const active = reg.active;
|
|
247
|
+
if (!active) {
|
|
248
|
+
clearTimeout(timer);
|
|
249
|
+
return reject(
|
|
250
|
+
new Error("Service worker active instance not available")
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
active.postMessage({ type, ...payload || {} }, [mc.port2]);
|
|
254
|
+
} catch (e) {
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
reject(e instanceof Error ? e : new Error(String(e)));
|
|
153
257
|
}
|
|
154
258
|
});
|
|
155
259
|
}
|
|
156
260
|
throw new Error("No worker registered");
|
|
157
261
|
}
|
|
158
262
|
// Fire-and-forget postMessage (no response expected)
|
|
159
|
-
async post(
|
|
263
|
+
async post(type, payload) {
|
|
160
264
|
if (this.workerType === "shared" && this.sharedWorkerPort) {
|
|
161
265
|
try {
|
|
162
|
-
this.sharedWorkerPort.postMessage({ type
|
|
163
|
-
} catch (
|
|
164
|
-
console.error("[WorkerClient] Failed to post to SharedWorker:",
|
|
266
|
+
this.sharedWorkerPort.postMessage({ type, ...payload || {} });
|
|
267
|
+
} catch (e) {
|
|
268
|
+
console.error("[WorkerClient] Failed to post to SharedWorker:", e);
|
|
165
269
|
}
|
|
166
270
|
return;
|
|
167
271
|
}
|
|
168
272
|
if (this.workerType === "service" && this.serviceWorkerRegistration?.active) {
|
|
169
273
|
try {
|
|
170
|
-
this.serviceWorkerRegistration.active.postMessage({
|
|
171
|
-
|
|
172
|
-
|
|
274
|
+
this.serviceWorkerRegistration.active.postMessage({
|
|
275
|
+
type,
|
|
276
|
+
...payload || {}
|
|
277
|
+
});
|
|
278
|
+
} catch (e) {
|
|
279
|
+
console.error(
|
|
280
|
+
"[WorkerClient] Failed to post to ServiceWorker (active):",
|
|
281
|
+
e
|
|
282
|
+
);
|
|
173
283
|
}
|
|
174
284
|
return;
|
|
175
285
|
}
|
|
176
286
|
if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
|
|
177
287
|
try {
|
|
178
|
-
navigator.serviceWorker.controller.postMessage({
|
|
179
|
-
|
|
180
|
-
|
|
288
|
+
navigator.serviceWorker.controller.postMessage({
|
|
289
|
+
type,
|
|
290
|
+
...payload || {}
|
|
291
|
+
});
|
|
292
|
+
} catch (e) {
|
|
293
|
+
console.error(
|
|
294
|
+
"[WorkerClient] Failed to post to ServiceWorker.controller:",
|
|
295
|
+
e
|
|
296
|
+
);
|
|
181
297
|
}
|
|
182
298
|
return;
|
|
183
299
|
}
|
|
184
|
-
if (
|
|
185
|
-
const
|
|
186
|
-
typeof
|
|
300
|
+
if (type === "SET_AUTH_TOKEN" && payload) {
|
|
301
|
+
const token = payload["token"];
|
|
302
|
+
if (typeof token === "string")
|
|
303
|
+
this.pendingAuthToken = token;
|
|
187
304
|
}
|
|
188
305
|
}
|
|
189
|
-
sendAuthTokenToServiceWorker(
|
|
190
|
-
if (this.serviceWorkerRegistration?.active)
|
|
306
|
+
sendAuthTokenToServiceWorker(token) {
|
|
307
|
+
if (this.serviceWorkerRegistration?.active) {
|
|
191
308
|
try {
|
|
192
|
-
this.serviceWorkerRegistration.active.postMessage({
|
|
193
|
-
|
|
194
|
-
|
|
309
|
+
this.serviceWorkerRegistration.active.postMessage({
|
|
310
|
+
type: "SET_AUTH_TOKEN",
|
|
311
|
+
token
|
|
312
|
+
});
|
|
313
|
+
} catch (e) {
|
|
314
|
+
console.error(
|
|
315
|
+
"[WorkerClient] Failed to send auth token to ServiceWorker:",
|
|
316
|
+
e
|
|
317
|
+
);
|
|
195
318
|
}
|
|
196
|
-
else if ("serviceWorker" in navigator && navigator.serviceWorker.controller)
|
|
319
|
+
} else if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
|
|
197
320
|
try {
|
|
198
|
-
navigator.serviceWorker.controller.postMessage({
|
|
199
|
-
|
|
200
|
-
|
|
321
|
+
navigator.serviceWorker.controller.postMessage({
|
|
322
|
+
type: "SET_AUTH_TOKEN",
|
|
323
|
+
token
|
|
324
|
+
});
|
|
325
|
+
} catch (e) {
|
|
326
|
+
console.error(
|
|
327
|
+
"[WorkerClient] Failed to send auth token to ServiceWorker.controller:",
|
|
328
|
+
e
|
|
329
|
+
);
|
|
201
330
|
}
|
|
202
|
-
else
|
|
203
|
-
this.pendingAuthToken =
|
|
331
|
+
} else {
|
|
332
|
+
this.pendingAuthToken = token;
|
|
333
|
+
}
|
|
204
334
|
}
|
|
205
335
|
// Subscription API for consumers to listen for connection status updates
|
|
206
|
-
onConnectionStatus(
|
|
207
|
-
this.connectionStatusCallbacks.add(
|
|
336
|
+
onConnectionStatus(cb) {
|
|
337
|
+
this.connectionStatusCallbacks.add(cb);
|
|
208
338
|
}
|
|
209
|
-
offConnectionStatus(
|
|
210
|
-
this.connectionStatusCallbacks.delete(
|
|
339
|
+
offConnectionStatus(cb) {
|
|
340
|
+
this.connectionStatusCallbacks.delete(cb);
|
|
211
341
|
}
|
|
212
342
|
async getConnectionStatus() {
|
|
213
343
|
try {
|
|
214
|
-
const
|
|
215
|
-
|
|
344
|
+
const res = await this.request(
|
|
345
|
+
"GET_CONNECTION_STATUS",
|
|
346
|
+
void 0,
|
|
347
|
+
2e3
|
|
348
|
+
);
|
|
349
|
+
if (res && typeof res === "object" && "connected" in res)
|
|
350
|
+
return !!res.connected;
|
|
351
|
+
return !!res?.connected;
|
|
216
352
|
} catch {
|
|
217
|
-
return
|
|
353
|
+
return false;
|
|
218
354
|
}
|
|
219
355
|
}
|
|
220
|
-
setAuthToken(
|
|
221
|
-
|
|
356
|
+
setAuthToken(token) {
|
|
357
|
+
this.pendingAuthToken = token;
|
|
358
|
+
if (this.workerType === "shared" && this.sharedWorkerPort) {
|
|
222
359
|
try {
|
|
223
|
-
this.sharedWorkerPort.postMessage({ type: "SET_AUTH_TOKEN", token
|
|
224
|
-
|
|
225
|
-
|
|
360
|
+
this.sharedWorkerPort.postMessage({ type: "SET_AUTH_TOKEN", token });
|
|
361
|
+
this.pendingAuthToken = null;
|
|
362
|
+
} catch (e) {
|
|
363
|
+
console.error(
|
|
364
|
+
"[WorkerClient] Failed to set auth token on SharedWorker:",
|
|
365
|
+
e
|
|
366
|
+
);
|
|
226
367
|
}
|
|
227
|
-
else this.workerType === "service"
|
|
368
|
+
} else if (this.workerType === "service") {
|
|
369
|
+
this.sendAuthTokenToServiceWorker(token);
|
|
370
|
+
this.pendingAuthToken = null;
|
|
371
|
+
} else {
|
|
372
|
+
}
|
|
228
373
|
}
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
// libs/mcp-worker/src/lib/database.ts
|
|
377
|
+
var DB_NAME = "user-activity-db";
|
|
378
|
+
var DB_VERSION = 1;
|
|
379
|
+
var STORE_NAME = "user-events";
|
|
380
|
+
async function initDB() {
|
|
381
|
+
return new Promise((resolve, reject) => {
|
|
382
|
+
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
|
383
|
+
request.onerror = () => reject(request.error);
|
|
384
|
+
request.onsuccess = () => resolve(request.result);
|
|
385
|
+
request.onupgradeneeded = (event) => {
|
|
386
|
+
const db = event.target.result;
|
|
387
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
388
|
+
const store = db.createObjectStore(STORE_NAME, { keyPath: "id" });
|
|
389
|
+
store.createIndex("timestamp", "timestamp", { unique: false });
|
|
390
|
+
store.createIndex("type", "type", { unique: false });
|
|
391
|
+
store.createIndex("path", "path", { unique: false });
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
async function queryEvents(filters) {
|
|
397
|
+
const db = await initDB();
|
|
398
|
+
const transaction = db.transaction([STORE_NAME], "readonly");
|
|
399
|
+
const store = transaction.objectStore(STORE_NAME);
|
|
400
|
+
const index = store.index("timestamp");
|
|
401
|
+
return new Promise((resolve, reject) => {
|
|
402
|
+
const request = index.getAll();
|
|
403
|
+
request.onsuccess = () => {
|
|
404
|
+
let events = request.result;
|
|
405
|
+
if (filters?.type) {
|
|
406
|
+
events = events.filter((e) => e.type === filters.type);
|
|
407
|
+
}
|
|
408
|
+
if (filters?.startTime) {
|
|
409
|
+
events = events.filter((e) => e.timestamp >= filters.startTime);
|
|
410
|
+
}
|
|
411
|
+
if (filters?.endTime) {
|
|
412
|
+
events = events.filter((e) => e.timestamp <= filters.endTime);
|
|
413
|
+
}
|
|
414
|
+
if (filters?.path) {
|
|
415
|
+
events = events.filter((e) => e.path?.includes(filters.path));
|
|
416
|
+
}
|
|
417
|
+
events.sort((a, b) => b.timestamp - a.timestamp);
|
|
418
|
+
if (filters?.limit) {
|
|
419
|
+
events = events.slice(0, filters.limit);
|
|
420
|
+
}
|
|
421
|
+
resolve(events);
|
|
422
|
+
};
|
|
423
|
+
request.onerror = () => reject(request.error);
|
|
424
|
+
});
|
|
229
425
|
}
|
|
426
|
+
|
|
427
|
+
// libs/mcp-worker/src/index.ts
|
|
428
|
+
var workerClient = new WorkerClient();
|
|
230
429
|
export {
|
|
231
|
-
|
|
232
|
-
|
|
430
|
+
queryEvents,
|
|
431
|
+
workerClient
|
|
233
432
|
};
|
|
234
|
-
//# sourceMappingURL=index.js.map
|