@mcp-fe/mcp-worker 0.0.5 → 0.0.7
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/{src/index.ts → index.d.ts} +1 -0
- package/index.d.ts.map +1 -0
- package/index.js +255 -0
- package/lib/database.d.ts +27 -0
- package/lib/database.d.ts.map +1 -0
- package/lib/mcp-controller.d.ts +22 -0
- package/lib/mcp-controller.d.ts.map +1 -0
- package/lib/mcp-server.d.ts +36 -0
- package/lib/mcp-server.d.ts.map +1 -0
- package/lib/service-worker.d.ts +8 -0
- package/lib/service-worker.d.ts.map +1 -0
- package/lib/shared-worker.d.ts +9 -0
- package/lib/shared-worker.d.ts.map +1 -0
- package/lib/websocket-transport.d.ts +16 -0
- package/lib/websocket-transport.d.ts.map +1 -0
- package/lib/worker-client.d.ts +20 -0
- package/lib/worker-client.d.ts.map +1 -0
- package/package.json +1 -1
- package/eslint.config.mjs +0 -22
- package/project.json +0 -9
- package/src/lib/database.ts +0 -122
- package/src/lib/mcp-controller.ts +0 -199
- package/src/lib/mcp-server.ts +0 -209
- package/src/lib/service-worker.ts +0 -87
- package/src/lib/shared-worker.ts +0 -109
- package/src/lib/websocket-transport.ts +0 -43
- package/src/lib/worker-client.ts +0 -369
- package/tsconfig.json +0 -25
- package/tsconfig.lib.json +0 -24
- package/tsconfig.spec.json +0 -28
- package/vite.config.mts +0 -59
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../libs/mcp-worker/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
|
package/index.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
class W {
|
|
2
|
+
serviceWorkerRegistration = null;
|
|
3
|
+
sharedWorker = null;
|
|
4
|
+
sharedWorkerPort = null;
|
|
5
|
+
workerType = null;
|
|
6
|
+
pendingAuthToken = null;
|
|
7
|
+
// connection status subscribers
|
|
8
|
+
connectionStatusCallbacks = /* @__PURE__ */ new Set();
|
|
9
|
+
serviceWorkerMessageHandler = null;
|
|
10
|
+
// Mutex/promise to prevent concurrent init runs
|
|
11
|
+
initPromise = null;
|
|
12
|
+
// Initialize and choose worker implementation (prefer SharedWorker)
|
|
13
|
+
async init(e) {
|
|
14
|
+
return this.initPromise ? this.initPromise.then(async () => {
|
|
15
|
+
e && this.workerType !== "service" && await this.init(e);
|
|
16
|
+
}) : (this.initPromise = (async () => {
|
|
17
|
+
try {
|
|
18
|
+
if (e) {
|
|
19
|
+
this.serviceWorkerRegistration = e, this.workerType = "service", console.log("[WorkerClient] Using ServiceWorker (explicit registration)"), this.pendingAuthToken && (this.sendAuthTokenToServiceWorker(this.pendingAuthToken), this.pendingAuthToken = null);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (typeof SharedWorker < "u")
|
|
23
|
+
try {
|
|
24
|
+
if (this.sharedWorker = new SharedWorker("/shared-worker.js", { type: "module" }), this.sharedWorkerPort = this.sharedWorker.port, this.sharedWorkerPort.start(), this.pendingAuthToken && this.sharedWorkerPort)
|
|
25
|
+
try {
|
|
26
|
+
this.sharedWorkerPort.postMessage({ type: "SET_AUTH_TOKEN", token: this.pendingAuthToken });
|
|
27
|
+
} catch (o) {
|
|
28
|
+
console.warn("[WorkerClient] Immediate postMessage to SharedWorker failed (will retry after init):", o);
|
|
29
|
+
}
|
|
30
|
+
this.sharedWorker.onerror = (o) => {
|
|
31
|
+
console.error("[WorkerClient] SharedWorker error:", o.message || o.error || o), this.workerType !== "shared" && this.initServiceWorkerFallback().catch((s) => {
|
|
32
|
+
console.error("[WorkerClient] Failed to initialize ServiceWorker fallback:", s);
|
|
33
|
+
});
|
|
34
|
+
}, await new Promise((o, s) => {
|
|
35
|
+
let n = !1;
|
|
36
|
+
const c = setTimeout(() => {
|
|
37
|
+
if (!n) {
|
|
38
|
+
const r = this.sharedWorkerPort;
|
|
39
|
+
r && (r.onmessage = null), s(new Error("SharedWorker initialization timeout"));
|
|
40
|
+
}
|
|
41
|
+
}, 2e3), a = this.sharedWorkerPort;
|
|
42
|
+
if (!a)
|
|
43
|
+
return clearTimeout(c), s(new Error("SharedWorker port not available"));
|
|
44
|
+
a.onmessage = (r) => {
|
|
45
|
+
try {
|
|
46
|
+
const i = r.data;
|
|
47
|
+
i && i.type === "CONNECTION_STATUS" && (clearTimeout(c), n = !0, this.workerType = "shared", a.onmessage = null, o());
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
const t = this.sharedWorkerPort;
|
|
53
|
+
if (this.pendingAuthToken && t)
|
|
54
|
+
try {
|
|
55
|
+
t.postMessage({ type: "SET_AUTH_TOKEN", token: this.pendingAuthToken }), this.pendingAuthToken = null;
|
|
56
|
+
} catch (o) {
|
|
57
|
+
console.error("[WorkerClient] Failed to send pending auth token to SharedWorker:", o);
|
|
58
|
+
}
|
|
59
|
+
t && (t.onmessage = (o) => {
|
|
60
|
+
try {
|
|
61
|
+
const s = o.data;
|
|
62
|
+
if (s && s.type === "CONNECTION_STATUS") {
|
|
63
|
+
const n = !!s.connected;
|
|
64
|
+
this.connectionStatusCallbacks.forEach((c) => {
|
|
65
|
+
try {
|
|
66
|
+
c(n);
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
}), console.log("[WorkerClient] Using SharedWorker");
|
|
74
|
+
return;
|
|
75
|
+
} catch (t) {
|
|
76
|
+
console.warn("[WorkerClient] SharedWorker not available, falling back to ServiceWorker:", t);
|
|
77
|
+
}
|
|
78
|
+
console.log("this should not be called"), await this.initServiceWorkerFallback(), this.pendingAuthToken && this.workerType === "service" && (this.sendAuthTokenToServiceWorker(this.pendingAuthToken), this.pendingAuthToken = null);
|
|
79
|
+
} finally {
|
|
80
|
+
this.initPromise = null;
|
|
81
|
+
}
|
|
82
|
+
})(), this.initPromise);
|
|
83
|
+
}
|
|
84
|
+
async initServiceWorkerFallback() {
|
|
85
|
+
if (console.log("initServiceWorkerFallback called"), "serviceWorker" in navigator)
|
|
86
|
+
try {
|
|
87
|
+
const e = await navigator.serviceWorker.getRegistration();
|
|
88
|
+
if (e) {
|
|
89
|
+
this.serviceWorkerRegistration = e, this.workerType = "service", console.log("[WorkerClient] Using existing ServiceWorker registration");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const t = await navigator.serviceWorker.register("/sw.js");
|
|
93
|
+
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 = (o) => {
|
|
94
|
+
try {
|
|
95
|
+
const s = o.data;
|
|
96
|
+
if (s && s.type === "CONNECTION_STATUS") {
|
|
97
|
+
const n = !!s.connected;
|
|
98
|
+
this.connectionStatusCallbacks.forEach((c) => {
|
|
99
|
+
try {
|
|
100
|
+
c(n);
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}, navigator.serviceWorker.addEventListener("message", this.serviceWorkerMessageHandler);
|
|
108
|
+
} catch (e) {
|
|
109
|
+
throw console.error("[WorkerClient] Failed to register ServiceWorker:", e), e;
|
|
110
|
+
}
|
|
111
|
+
else
|
|
112
|
+
throw new Error("Neither SharedWorker nor ServiceWorker is supported");
|
|
113
|
+
}
|
|
114
|
+
// Low-level request that expects a reply via MessageChannel
|
|
115
|
+
async request(e, t, o = 5e3) {
|
|
116
|
+
if (this.workerType === "shared" && this.sharedWorkerPort)
|
|
117
|
+
return new Promise((s, n) => {
|
|
118
|
+
const c = new MessageChannel(), a = setTimeout(() => {
|
|
119
|
+
c.port1.onmessage = null, n(new Error("Request timeout"));
|
|
120
|
+
}, o);
|
|
121
|
+
c.port1.onmessage = (r) => {
|
|
122
|
+
clearTimeout(a), r.data && r.data.success ? s(r.data) : r.data && r.data.success === !1 ? n(new Error(r.data.error || "Worker error")) : s(r.data);
|
|
123
|
+
};
|
|
124
|
+
try {
|
|
125
|
+
const r = this.sharedWorkerPort;
|
|
126
|
+
if (!r)
|
|
127
|
+
return clearTimeout(a), n(new Error("SharedWorker port not available"));
|
|
128
|
+
r.postMessage({ type: e, ...t || {} }, [c.port2]);
|
|
129
|
+
} catch (r) {
|
|
130
|
+
clearTimeout(a), n(r instanceof Error ? r : new Error(String(r)));
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
if (this.workerType === "service" && this.serviceWorkerRegistration) {
|
|
134
|
+
const s = this.serviceWorkerRegistration;
|
|
135
|
+
if (!s) throw new Error("Service worker registration missing");
|
|
136
|
+
if (!s.active && (await navigator.serviceWorker.ready, !s.active))
|
|
137
|
+
throw new Error("Service worker not active");
|
|
138
|
+
return new Promise((n, c) => {
|
|
139
|
+
const a = new MessageChannel(), r = setTimeout(() => {
|
|
140
|
+
a.port1.onmessage = null, c(new Error("Request timeout"));
|
|
141
|
+
}, o);
|
|
142
|
+
a.port1.onmessage = (i) => {
|
|
143
|
+
clearTimeout(r), i.data && i.data.success ? n(i.data) : i.data && i.data.success === !1 ? c(new Error(i.data.error || "Worker error")) : n(i.data);
|
|
144
|
+
};
|
|
145
|
+
try {
|
|
146
|
+
const i = s.active;
|
|
147
|
+
if (!i)
|
|
148
|
+
return clearTimeout(r), c(new Error("Service worker active instance not available"));
|
|
149
|
+
i.postMessage({ type: e, ...t || {} }, [a.port2]);
|
|
150
|
+
} catch (i) {
|
|
151
|
+
clearTimeout(r), c(i instanceof Error ? i : new Error(String(i)));
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
throw new Error("No worker registered");
|
|
156
|
+
}
|
|
157
|
+
// Fire-and-forget postMessage (no response expected)
|
|
158
|
+
async post(e, t) {
|
|
159
|
+
if (this.workerType === "shared" && this.sharedWorkerPort) {
|
|
160
|
+
try {
|
|
161
|
+
this.sharedWorkerPort.postMessage({ type: e, ...t || {} });
|
|
162
|
+
} catch (o) {
|
|
163
|
+
console.error("[WorkerClient] Failed to post to SharedWorker:", o);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (this.workerType === "service" && this.serviceWorkerRegistration?.active) {
|
|
168
|
+
try {
|
|
169
|
+
this.serviceWorkerRegistration.active.postMessage({ type: e, ...t || {} });
|
|
170
|
+
} catch (o) {
|
|
171
|
+
console.error("[WorkerClient] Failed to post to ServiceWorker (active):", o);
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
|
|
176
|
+
try {
|
|
177
|
+
navigator.serviceWorker.controller.postMessage({ type: e, ...t || {} });
|
|
178
|
+
} catch (o) {
|
|
179
|
+
console.error("[WorkerClient] Failed to post to ServiceWorker.controller:", o);
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (e === "SET_AUTH_TOKEN" && t) {
|
|
184
|
+
const o = t.token;
|
|
185
|
+
typeof o == "string" && (this.pendingAuthToken = o);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
sendAuthTokenToServiceWorker(e) {
|
|
189
|
+
if (this.serviceWorkerRegistration?.active)
|
|
190
|
+
try {
|
|
191
|
+
this.serviceWorkerRegistration.active.postMessage({ type: "SET_AUTH_TOKEN", token: e });
|
|
192
|
+
} catch (t) {
|
|
193
|
+
console.error("[WorkerClient] Failed to send auth token to ServiceWorker:", t);
|
|
194
|
+
}
|
|
195
|
+
else if ("serviceWorker" in navigator && navigator.serviceWorker.controller)
|
|
196
|
+
try {
|
|
197
|
+
navigator.serviceWorker.controller.postMessage({ type: "SET_AUTH_TOKEN", token: e });
|
|
198
|
+
} catch (t) {
|
|
199
|
+
console.error("[WorkerClient] Failed to send auth token to ServiceWorker.controller:", t);
|
|
200
|
+
}
|
|
201
|
+
else
|
|
202
|
+
this.pendingAuthToken = e;
|
|
203
|
+
}
|
|
204
|
+
// Subscription API for consumers to listen for connection status updates
|
|
205
|
+
onConnectionStatus(e) {
|
|
206
|
+
this.connectionStatusCallbacks.add(e);
|
|
207
|
+
}
|
|
208
|
+
offConnectionStatus(e) {
|
|
209
|
+
this.connectionStatusCallbacks.delete(e);
|
|
210
|
+
}
|
|
211
|
+
async getConnectionStatus() {
|
|
212
|
+
try {
|
|
213
|
+
const e = await this.request("GET_CONNECTION_STATUS", void 0, 2e3);
|
|
214
|
+
return e && typeof e == "object" && "connected" in e, !!e.connected;
|
|
215
|
+
} catch {
|
|
216
|
+
return !1;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
setAuthToken(e) {
|
|
220
|
+
if (this.pendingAuthToken = e, this.workerType === "shared" && this.sharedWorkerPort)
|
|
221
|
+
try {
|
|
222
|
+
this.sharedWorkerPort.postMessage({ type: "SET_AUTH_TOKEN", token: e }), this.pendingAuthToken = null;
|
|
223
|
+
} catch (t) {
|
|
224
|
+
console.error("[WorkerClient] Failed to set auth token on SharedWorker:", t);
|
|
225
|
+
}
|
|
226
|
+
else this.workerType === "service" && (this.sendAuthTokenToServiceWorker(e), this.pendingAuthToken = null);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const d = "user-activity-db", u = 1, h = "user-events";
|
|
230
|
+
async function g() {
|
|
231
|
+
return new Promise((l, e) => {
|
|
232
|
+
const t = indexedDB.open(d, u);
|
|
233
|
+
t.onerror = () => e(t.error), t.onsuccess = () => l(t.result), t.onupgradeneeded = (o) => {
|
|
234
|
+
const s = o.target.result;
|
|
235
|
+
if (!s.objectStoreNames.contains(h)) {
|
|
236
|
+
const n = s.createObjectStore(h, { keyPath: "id" });
|
|
237
|
+
n.createIndex("timestamp", "timestamp", { unique: !1 }), n.createIndex("type", "type", { unique: !1 }), n.createIndex("path", "path", { unique: !1 });
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
async function T(l) {
|
|
243
|
+
const s = (await g()).transaction([h], "readonly").objectStore(h).index("timestamp");
|
|
244
|
+
return new Promise((n, c) => {
|
|
245
|
+
const a = s.getAll();
|
|
246
|
+
a.onsuccess = () => {
|
|
247
|
+
let r = a.result;
|
|
248
|
+
l?.type && (r = r.filter((i) => i.type === l.type)), l?.startTime && (r = r.filter((i) => i.timestamp >= l.startTime)), l?.endTime && (r = r.filter((i) => i.timestamp <= l.endTime)), l?.path && (r = r.filter((i) => i.path?.includes(l.path))), r.sort((i, k) => k.timestamp - i.timestamp), l?.limit && (r = r.slice(0, l.limit)), n(r);
|
|
249
|
+
}, a.onerror = () => c(a.error);
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
export {
|
|
253
|
+
W as WorkerClient,
|
|
254
|
+
T as queryEvents
|
|
255
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IndexedDB operations for storing and querying user events
|
|
3
|
+
*/
|
|
4
|
+
export interface UserEvent {
|
|
5
|
+
id: string;
|
|
6
|
+
type: 'navigation' | 'click' | 'input' | 'custom';
|
|
7
|
+
timestamp: number;
|
|
8
|
+
path?: string;
|
|
9
|
+
from?: string;
|
|
10
|
+
to?: string;
|
|
11
|
+
element?: string;
|
|
12
|
+
elementId?: string;
|
|
13
|
+
elementClass?: string;
|
|
14
|
+
elementText?: string;
|
|
15
|
+
metadata?: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export interface EventFilters {
|
|
18
|
+
type?: string;
|
|
19
|
+
startTime?: number;
|
|
20
|
+
endTime?: number;
|
|
21
|
+
path?: string;
|
|
22
|
+
limit?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function initDB(): Promise<IDBDatabase>;
|
|
25
|
+
export declare function storeEvent(event: Omit<UserEvent, 'id'>): Promise<void>;
|
|
26
|
+
export declare function queryEvents(filters?: EventFilters): Promise<UserEvent[]>;
|
|
27
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../../libs/mcp-worker/src/lib/database.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,YAAY,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAA;IACjD,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAGD,wBAAsB,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CAiBnD;AAGD,wBAAsB,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B5E;AAGD,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAqC9E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { queryEvents, UserEvent } from './database';
|
|
2
|
+
export type BroadcastFn = (message: unknown) => void;
|
|
3
|
+
export declare class MCPController {
|
|
4
|
+
private backendUrl;
|
|
5
|
+
private broadcastFn;
|
|
6
|
+
private socket;
|
|
7
|
+
private transport;
|
|
8
|
+
private reconnectAttempts;
|
|
9
|
+
private authToken;
|
|
10
|
+
private keepAliveInterval;
|
|
11
|
+
private requireAuth;
|
|
12
|
+
constructor(backendUrl: string, broadcastFn: BroadcastFn, requireAuth?: boolean);
|
|
13
|
+
private startKeepAlive;
|
|
14
|
+
private stopKeepAlive;
|
|
15
|
+
connectWebSocket(): Promise<void>;
|
|
16
|
+
setAuthToken(token: string | null): void;
|
|
17
|
+
handleStoreEvent(userEvent: UserEvent): Promise<void>;
|
|
18
|
+
handleGetEvents(): Promise<ReturnType<typeof queryEvents>>;
|
|
19
|
+
getConnectionStatus(): boolean;
|
|
20
|
+
dispose(): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=mcp-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-controller.d.ts","sourceRoot":"","sources":["../../../../libs/mcp-worker/src/lib/mcp-controller.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,OAAO,EAAc,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOhE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;AAErD,qBAAa,aAAa;IAQZ,OAAO,CAAC,UAAU;IAAU,OAAO,CAAC,WAAW;IAP3D,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,iBAAiB,CAA+C;IACxE,OAAO,CAAC,WAAW,CAAU;gBAET,UAAU,EAAE,MAAM,EAAU,WAAW,EAAE,WAAW,EAAE,WAAW,UAAO;IAI5F,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,aAAa;IAOR,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAyGvC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAkBlC,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD,eAAe,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;IAIhE,mBAAmB,IAAI,OAAO;IAI9B,OAAO,IAAI,IAAI;CAWvB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
export declare const mcpServer: Server<{
|
|
3
|
+
method: string;
|
|
4
|
+
params?: {
|
|
5
|
+
[x: string]: unknown;
|
|
6
|
+
_meta?: {
|
|
7
|
+
[x: string]: unknown;
|
|
8
|
+
progressToken?: string | number | undefined;
|
|
9
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
10
|
+
taskId: string;
|
|
11
|
+
} | undefined;
|
|
12
|
+
} | undefined;
|
|
13
|
+
} | undefined;
|
|
14
|
+
}, {
|
|
15
|
+
method: string;
|
|
16
|
+
params?: {
|
|
17
|
+
[x: string]: unknown;
|
|
18
|
+
_meta?: {
|
|
19
|
+
[x: string]: unknown;
|
|
20
|
+
progressToken?: string | number | undefined;
|
|
21
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
22
|
+
taskId: string;
|
|
23
|
+
} | undefined;
|
|
24
|
+
} | undefined;
|
|
25
|
+
} | undefined;
|
|
26
|
+
}, {
|
|
27
|
+
[x: string]: unknown;
|
|
28
|
+
_meta?: {
|
|
29
|
+
[x: string]: unknown;
|
|
30
|
+
progressToken?: string | number | undefined;
|
|
31
|
+
"io.modelcontextprotocol/related-task"?: {
|
|
32
|
+
taskId: string;
|
|
33
|
+
} | undefined;
|
|
34
|
+
} | undefined;
|
|
35
|
+
}>;
|
|
36
|
+
//# sourceMappingURL=mcp-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../../../libs/mcp-worker/src/lib/mcp-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AAMlE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUrB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-worker.d.ts","sourceRoot":"","sources":["../../../../libs/mcp-worker/src/lib/service-worker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharedWorker MCP Server
|
|
3
|
+
*
|
|
4
|
+
* This SharedWorker acts as an MCP (Model Context Protocol) server,
|
|
5
|
+
* storing user events and exposing them via MCP protocol endpoints.
|
|
6
|
+
* Falls back to ServiceWorker if SharedWorker is not supported.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=shared-worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-worker.d.ts","sourceRoot":"","sources":["../../../../libs/mcp-worker/src/lib/shared-worker.ts"],"names":[],"mappings":"AACA;;;;;;GAMG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
2
|
+
import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Custom MCP Transport for WebSocket in Service Worker
|
|
5
|
+
*/
|
|
6
|
+
export declare class WebSocketTransport implements Transport {
|
|
7
|
+
private ws;
|
|
8
|
+
onclose?: () => void;
|
|
9
|
+
onerror?: (error: Error) => void;
|
|
10
|
+
onmessage?: (message: JSONRPCMessage) => void;
|
|
11
|
+
constructor(ws: WebSocket);
|
|
12
|
+
start(): Promise<void>;
|
|
13
|
+
send(message: JSONRPCMessage): Promise<void>;
|
|
14
|
+
close(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=websocket-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-transport.d.ts","sourceRoot":"","sources":["../../../../libs/mcp-worker/src/lib/websocket-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEpE;;GAEG;AACH,qBAAa,kBAAmB,YAAW,SAAS;IAMtC,OAAO,CAAC,EAAE;IAJtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAE1B,EAAE,EAAE,SAAS;IAE3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare class WorkerClient {
|
|
2
|
+
private serviceWorkerRegistration;
|
|
3
|
+
private sharedWorker;
|
|
4
|
+
private sharedWorkerPort;
|
|
5
|
+
private workerType;
|
|
6
|
+
private pendingAuthToken;
|
|
7
|
+
private connectionStatusCallbacks;
|
|
8
|
+
private serviceWorkerMessageHandler;
|
|
9
|
+
private initPromise;
|
|
10
|
+
init(registration?: ServiceWorkerRegistration): Promise<void>;
|
|
11
|
+
private initServiceWorkerFallback;
|
|
12
|
+
request<T = any>(type: string, payload?: Record<string, unknown>, timeoutMs?: number): Promise<T>;
|
|
13
|
+
post(type: string, payload?: Record<string, unknown>): Promise<void>;
|
|
14
|
+
private sendAuthTokenToServiceWorker;
|
|
15
|
+
onConnectionStatus(cb: (connected: boolean) => void): void;
|
|
16
|
+
offConnectionStatus(cb: (connected: boolean) => void): void;
|
|
17
|
+
getConnectionStatus(): Promise<boolean>;
|
|
18
|
+
setAuthToken(token: string): void;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=worker-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-client.d.ts","sourceRoot":"","sources":["../../../../libs/mcp-worker/src/lib/worker-client.ts"],"names":[],"mappings":"AAEA,qBAAa,YAAY;IACvB,OAAO,CAAC,yBAAyB,CAA0C;IAC3E,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,gBAAgB,CAAuB;IAE/C,OAAO,CAAC,yBAAyB,CAAgD;IACjF,OAAO,CAAC,2BAA2B,CAA6C;IAGhF,OAAO,CAAC,WAAW,CAA8B;IAGpC,IAAI,CAAC,YAAY,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;YAsI5D,yBAAyB;IA4C1B,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAoF/F,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCjF,OAAO,CAAC,4BAA4B;IAoB7B,kBAAkB,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAI1D,mBAAmB,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAIrD,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAU7C,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAiBzC"}
|
package/package.json
CHANGED
package/eslint.config.mjs
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import baseConfig from '../../eslint.config.mjs';
|
|
2
|
-
|
|
3
|
-
export default [
|
|
4
|
-
...baseConfig,
|
|
5
|
-
{
|
|
6
|
-
files: ['**/*.json'],
|
|
7
|
-
rules: {
|
|
8
|
-
'@nx/dependency-checks': [
|
|
9
|
-
'error',
|
|
10
|
-
{
|
|
11
|
-
ignoredFiles: [
|
|
12
|
-
'{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
|
|
13
|
-
'{projectRoot}/vite.config.{js,ts,mjs,mts}',
|
|
14
|
-
],
|
|
15
|
-
},
|
|
16
|
-
],
|
|
17
|
-
},
|
|
18
|
-
languageOptions: {
|
|
19
|
-
parser: await import('jsonc-eslint-parser'),
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
];
|
package/project.json
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mcp-worker",
|
|
3
|
-
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"sourceRoot": "libs/mcp-worker/src",
|
|
5
|
-
"projectType": "library",
|
|
6
|
-
"tags": [],
|
|
7
|
-
"// targets": "to see all targets run: nx show project mcp-worker --web",
|
|
8
|
-
"targets": {}
|
|
9
|
-
}
|
package/src/lib/database.ts
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* IndexedDB operations for storing and querying user events
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const DB_NAME = 'user-activity-db'
|
|
6
|
-
const DB_VERSION = 1
|
|
7
|
-
const STORE_NAME = 'user-events'
|
|
8
|
-
|
|
9
|
-
export interface UserEvent {
|
|
10
|
-
id: string
|
|
11
|
-
type: 'navigation' | 'click' | 'input' | 'custom'
|
|
12
|
-
timestamp: number
|
|
13
|
-
path?: string
|
|
14
|
-
from?: string
|
|
15
|
-
to?: string
|
|
16
|
-
element?: string
|
|
17
|
-
elementId?: string
|
|
18
|
-
elementClass?: string
|
|
19
|
-
elementText?: string
|
|
20
|
-
metadata?: Record<string, unknown>
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface EventFilters {
|
|
24
|
-
type?: string
|
|
25
|
-
startTime?: number
|
|
26
|
-
endTime?: number
|
|
27
|
-
path?: string
|
|
28
|
-
limit?: number
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Initialize IndexedDB
|
|
32
|
-
export async function initDB(): Promise<IDBDatabase> {
|
|
33
|
-
return new Promise((resolve, reject) => {
|
|
34
|
-
const request = indexedDB.open(DB_NAME, DB_VERSION)
|
|
35
|
-
|
|
36
|
-
request.onerror = () => reject(request.error)
|
|
37
|
-
request.onsuccess = () => resolve(request.result)
|
|
38
|
-
|
|
39
|
-
request.onupgradeneeded = (event) => {
|
|
40
|
-
const db = (event.target as IDBOpenDBRequest).result
|
|
41
|
-
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
42
|
-
const store = db.createObjectStore(STORE_NAME, { keyPath: 'id' })
|
|
43
|
-
store.createIndex('timestamp', 'timestamp', { unique: false })
|
|
44
|
-
store.createIndex('type', 'type', { unique: false })
|
|
45
|
-
store.createIndex('path', 'path', { unique: false })
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
})
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Store event in IndexedDB
|
|
52
|
-
export async function storeEvent(event: Omit<UserEvent, 'id'>): Promise<void> {
|
|
53
|
-
const db = await initDB()
|
|
54
|
-
const transaction = db.transaction([STORE_NAME], 'readwrite')
|
|
55
|
-
const store = transaction.objectStore(STORE_NAME)
|
|
56
|
-
|
|
57
|
-
const eventWithId: UserEvent = {
|
|
58
|
-
...event,
|
|
59
|
-
id: `${event.timestamp}-${Math.random().toString(36).substr(2, 9)}`,
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
await new Promise<void>((resolve, reject) => {
|
|
63
|
-
const request = store.add(eventWithId)
|
|
64
|
-
request.onsuccess = () => resolve()
|
|
65
|
-
request.onerror = () => reject(request.error)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
// Clean up old events (keep last 1000 events)
|
|
69
|
-
const countRequest = store.count()
|
|
70
|
-
countRequest.onsuccess = () => {
|
|
71
|
-
if (countRequest.result > 1000) {
|
|
72
|
-
const index = store.index('timestamp')
|
|
73
|
-
const getAllRequest = index.getAll()
|
|
74
|
-
getAllRequest.onsuccess = () => {
|
|
75
|
-
const events = getAllRequest.result as UserEvent[]
|
|
76
|
-
events.sort((a, b) => a.timestamp - b.timestamp)
|
|
77
|
-
const toDelete = events.slice(0, events.length - 1000)
|
|
78
|
-
toDelete.forEach((event) => store.delete(event.id))
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Query events from IndexedDB
|
|
85
|
-
export async function queryEvents(filters?: EventFilters): Promise<UserEvent[]> {
|
|
86
|
-
const db = await initDB()
|
|
87
|
-
const transaction = db.transaction([STORE_NAME], 'readonly')
|
|
88
|
-
const store = transaction.objectStore(STORE_NAME)
|
|
89
|
-
const index = store.index('timestamp')
|
|
90
|
-
|
|
91
|
-
return new Promise((resolve, reject) => {
|
|
92
|
-
const request = index.getAll()
|
|
93
|
-
request.onsuccess = () => {
|
|
94
|
-
let events = request.result as UserEvent[]
|
|
95
|
-
|
|
96
|
-
// Apply filters
|
|
97
|
-
if (filters?.type) {
|
|
98
|
-
events = events.filter((e) => e.type === filters.type)
|
|
99
|
-
}
|
|
100
|
-
if (filters?.startTime) {
|
|
101
|
-
events = events.filter((e) => e.timestamp >= filters.startTime!)
|
|
102
|
-
}
|
|
103
|
-
if (filters?.endTime) {
|
|
104
|
-
events = events.filter((e) => e.timestamp <= filters.endTime!)
|
|
105
|
-
}
|
|
106
|
-
if (filters?.path) {
|
|
107
|
-
events = events.filter((e) => e.path?.includes(filters.path!))
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Sort by timestamp descending (newest first)
|
|
111
|
-
events.sort((a, b) => b.timestamp - a.timestamp)
|
|
112
|
-
|
|
113
|
-
// Apply limit
|
|
114
|
-
if (filters?.limit) {
|
|
115
|
-
events = events.slice(0, filters.limit)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
resolve(events)
|
|
119
|
-
}
|
|
120
|
-
request.onerror = () => reject(request.error)
|
|
121
|
-
})
|
|
122
|
-
}
|