@mcp-fe/event-tracker 0.0.5 → 0.0.11
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 +327 -0
- package/lib/event-tracker.d.ts +25 -0
- package/lib/event-tracker.d.ts.map +1 -0
- package/package.json +2 -2
- package/eslint.config.mjs +0 -22
- package/project.json +0 -9
- package/src/lib/event-tracker.ts +0 -102
- package/tsconfig.json +0 -24
- package/tsconfig.lib.json +0 -25
- 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/event-tracker/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC"}
|
package/index.js
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
class g {
|
|
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("/mcp-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 (t) {
|
|
28
|
+
console.warn("[WorkerClient] Immediate postMessage to SharedWorker failed (will retry after init):", t);
|
|
29
|
+
}
|
|
30
|
+
this.sharedWorker.onerror = (t) => {
|
|
31
|
+
console.error("[WorkerClient] SharedWorker error:", t.message || t.error || t), this.workerType !== "shared" && this.initServiceWorkerFallback().catch((n) => {
|
|
32
|
+
console.error("[WorkerClient] Failed to initialize ServiceWorker fallback:", n);
|
|
33
|
+
});
|
|
34
|
+
}, await new Promise((t, n) => {
|
|
35
|
+
let s = !1;
|
|
36
|
+
const a = setTimeout(() => {
|
|
37
|
+
if (!s) {
|
|
38
|
+
const i = this.sharedWorkerPort;
|
|
39
|
+
i && (i.onmessage = null), n(new Error("SharedWorker initialization timeout"));
|
|
40
|
+
}
|
|
41
|
+
}, 2e3), l = this.sharedWorkerPort;
|
|
42
|
+
if (!l)
|
|
43
|
+
return clearTimeout(a), n(new Error("SharedWorker port not available"));
|
|
44
|
+
l.onmessage = (i) => {
|
|
45
|
+
try {
|
|
46
|
+
const c = i.data;
|
|
47
|
+
c && c.type === "CONNECTION_STATUS" && (clearTimeout(a), s = !0, this.workerType = "shared", l.onmessage = null, t());
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
const r = this.sharedWorkerPort;
|
|
53
|
+
if (this.pendingAuthToken && r)
|
|
54
|
+
try {
|
|
55
|
+
r.postMessage({ type: "SET_AUTH_TOKEN", token: this.pendingAuthToken }), this.pendingAuthToken = null;
|
|
56
|
+
} catch (t) {
|
|
57
|
+
console.error("[WorkerClient] Failed to send pending auth token to SharedWorker:", t);
|
|
58
|
+
}
|
|
59
|
+
r && (r.onmessage = (t) => {
|
|
60
|
+
try {
|
|
61
|
+
const n = t.data;
|
|
62
|
+
if (n && n.type === "CONNECTION_STATUS") {
|
|
63
|
+
const s = !!n.connected;
|
|
64
|
+
this.connectionStatusCallbacks.forEach((a) => {
|
|
65
|
+
try {
|
|
66
|
+
a(s);
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
}), console.log("[WorkerClient] Using SharedWorker");
|
|
74
|
+
return;
|
|
75
|
+
} catch (r) {
|
|
76
|
+
console.warn("[WorkerClient] SharedWorker not available, falling back to ServiceWorker:", r);
|
|
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 r = await navigator.serviceWorker.register("/mcp-service-worker.js");
|
|
93
|
+
this.serviceWorkerRegistration = r, this.workerType = "service", console.log("[WorkerClient] Using ServiceWorker (fallback)"), this.serviceWorkerMessageHandler && (navigator.serviceWorker.removeEventListener("message", this.serviceWorkerMessageHandler), this.serviceWorkerMessageHandler = null), this.serviceWorkerMessageHandler = (t) => {
|
|
94
|
+
try {
|
|
95
|
+
const n = t.data;
|
|
96
|
+
if (n && n.type === "CONNECTION_STATUS") {
|
|
97
|
+
const s = !!n.connected;
|
|
98
|
+
this.connectionStatusCallbacks.forEach((a) => {
|
|
99
|
+
try {
|
|
100
|
+
a(s);
|
|
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, r, t = 5e3) {
|
|
116
|
+
if (this.workerType === "shared" && this.sharedWorkerPort)
|
|
117
|
+
return new Promise((n, s) => {
|
|
118
|
+
const a = new MessageChannel(), l = setTimeout(() => {
|
|
119
|
+
a.port1.onmessage = null, s(new Error("Request timeout"));
|
|
120
|
+
}, t);
|
|
121
|
+
a.port1.onmessage = (i) => {
|
|
122
|
+
clearTimeout(l), i.data && i.data.success ? n(i.data) : i.data && i.data.success === !1 ? s(new Error(i.data.error || "Worker error")) : n(i.data);
|
|
123
|
+
};
|
|
124
|
+
try {
|
|
125
|
+
const i = this.sharedWorkerPort;
|
|
126
|
+
if (!i)
|
|
127
|
+
return clearTimeout(l), s(new Error("SharedWorker port not available"));
|
|
128
|
+
i.postMessage({ type: e, ...r || {} }, [a.port2]);
|
|
129
|
+
} catch (i) {
|
|
130
|
+
clearTimeout(l), s(i instanceof Error ? i : new Error(String(i)));
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
if (this.workerType === "service" && this.serviceWorkerRegistration) {
|
|
134
|
+
const n = this.serviceWorkerRegistration;
|
|
135
|
+
if (!n) throw new Error("Service worker registration missing");
|
|
136
|
+
if (!n.active && (await navigator.serviceWorker.ready, !n.active))
|
|
137
|
+
throw new Error("Service worker not active");
|
|
138
|
+
return new Promise((s, a) => {
|
|
139
|
+
const l = new MessageChannel(), i = setTimeout(() => {
|
|
140
|
+
l.port1.onmessage = null, a(new Error("Request timeout"));
|
|
141
|
+
}, t);
|
|
142
|
+
l.port1.onmessage = (c) => {
|
|
143
|
+
clearTimeout(i), c.data && c.data.success ? s(c.data) : c.data && c.data.success === !1 ? a(new Error(c.data.error || "Worker error")) : s(c.data);
|
|
144
|
+
};
|
|
145
|
+
try {
|
|
146
|
+
const c = n.active;
|
|
147
|
+
if (!c)
|
|
148
|
+
return clearTimeout(i), a(new Error("Service worker active instance not available"));
|
|
149
|
+
c.postMessage({ type: e, ...r || {} }, [l.port2]);
|
|
150
|
+
} catch (c) {
|
|
151
|
+
clearTimeout(i), a(c instanceof Error ? c : new Error(String(c)));
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
throw new Error("No worker registered");
|
|
156
|
+
}
|
|
157
|
+
// Fire-and-forget postMessage (no response expected)
|
|
158
|
+
async post(e, r) {
|
|
159
|
+
if (this.workerType === "shared" && this.sharedWorkerPort) {
|
|
160
|
+
try {
|
|
161
|
+
this.sharedWorkerPort.postMessage({ type: e, ...r || {} });
|
|
162
|
+
} catch (t) {
|
|
163
|
+
console.error("[WorkerClient] Failed to post to SharedWorker:", t);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (this.workerType === "service" && this.serviceWorkerRegistration?.active) {
|
|
168
|
+
try {
|
|
169
|
+
this.serviceWorkerRegistration.active.postMessage({ type: e, ...r || {} });
|
|
170
|
+
} catch (t) {
|
|
171
|
+
console.error("[WorkerClient] Failed to post to ServiceWorker (active):", t);
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
|
|
176
|
+
try {
|
|
177
|
+
navigator.serviceWorker.controller.postMessage({ type: e, ...r || {} });
|
|
178
|
+
} catch (t) {
|
|
179
|
+
console.error("[WorkerClient] Failed to post to ServiceWorker.controller:", t);
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (e === "SET_AUTH_TOKEN" && r) {
|
|
184
|
+
const t = r.token;
|
|
185
|
+
typeof t == "string" && (this.pendingAuthToken = t);
|
|
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 (r) {
|
|
193
|
+
console.error("[WorkerClient] Failed to send auth token to ServiceWorker:", r);
|
|
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 (r) {
|
|
199
|
+
console.error("[WorkerClient] Failed to send auth token to ServiceWorker.controller:", r);
|
|
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 (r) {
|
|
224
|
+
console.error("[WorkerClient] Failed to set auth token on SharedWorker:", r);
|
|
225
|
+
}
|
|
226
|
+
else this.workerType === "service" && (this.sendAuthTokenToServiceWorker(e), this.pendingAuthToken = null);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const W = "user-activity-db", p = 1, k = "user-events";
|
|
230
|
+
async function v() {
|
|
231
|
+
return new Promise((o, e) => {
|
|
232
|
+
const r = indexedDB.open(W, p);
|
|
233
|
+
r.onerror = () => e(r.error), r.onsuccess = () => o(r.result), r.onupgradeneeded = (t) => {
|
|
234
|
+
const n = t.target.result;
|
|
235
|
+
if (!n.objectStoreNames.contains(k)) {
|
|
236
|
+
const s = n.createObjectStore(k, { keyPath: "id" });
|
|
237
|
+
s.createIndex("timestamp", "timestamp", { unique: !1 }), s.createIndex("type", "type", { unique: !1 }), s.createIndex("path", "path", { unique: !1 });
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
async function T(o) {
|
|
243
|
+
const n = (await v()).transaction([k], "readonly").objectStore(k).index("timestamp");
|
|
244
|
+
return new Promise((s, a) => {
|
|
245
|
+
const l = n.getAll();
|
|
246
|
+
l.onsuccess = () => {
|
|
247
|
+
let i = l.result;
|
|
248
|
+
i.sort((c, d) => d.timestamp - c.timestamp), s(i);
|
|
249
|
+
}, l.onerror = () => a(l.error);
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
const h = new g();
|
|
253
|
+
async function f(o) {
|
|
254
|
+
return h.init(o);
|
|
255
|
+
}
|
|
256
|
+
async function u(o) {
|
|
257
|
+
const e = { ...o, timestamp: Date.now() };
|
|
258
|
+
await h.request("STORE_EVENT", { event: e });
|
|
259
|
+
}
|
|
260
|
+
async function m() {
|
|
261
|
+
const o = await T();
|
|
262
|
+
return Array.isArray(o) ? o : [];
|
|
263
|
+
}
|
|
264
|
+
async function S() {
|
|
265
|
+
return h.getConnectionStatus();
|
|
266
|
+
}
|
|
267
|
+
function w(o) {
|
|
268
|
+
h.setAuthToken(o);
|
|
269
|
+
}
|
|
270
|
+
function y(o) {
|
|
271
|
+
h.onConnectionStatus(o);
|
|
272
|
+
}
|
|
273
|
+
function C(o) {
|
|
274
|
+
h.offConnectionStatus(o);
|
|
275
|
+
}
|
|
276
|
+
async function E(o, e, r) {
|
|
277
|
+
return u({ type: "navigation", from: o, to: e, path: r || e });
|
|
278
|
+
}
|
|
279
|
+
async function A(o, e, r) {
|
|
280
|
+
const t = o.id || void 0, n = o.className || void 0, s = o.textContent?.trim().substring(0, 100) || void 0, a = o.tagName.toLowerCase();
|
|
281
|
+
return u({
|
|
282
|
+
type: "click",
|
|
283
|
+
element: a,
|
|
284
|
+
elementId: t,
|
|
285
|
+
elementClass: n,
|
|
286
|
+
elementText: s,
|
|
287
|
+
path: e || window.location.pathname,
|
|
288
|
+
metadata: r
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
async function N(o, e, r) {
|
|
292
|
+
const t = o.id || void 0, n = o.className || void 0, s = o.tagName.toLowerCase();
|
|
293
|
+
return u({
|
|
294
|
+
type: "input",
|
|
295
|
+
element: s,
|
|
296
|
+
elementId: t,
|
|
297
|
+
elementClass: n,
|
|
298
|
+
path: r || window.location.pathname,
|
|
299
|
+
metadata: {
|
|
300
|
+
valueLength: e?.length || 0,
|
|
301
|
+
value: e
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
async function b(o, e, r) {
|
|
306
|
+
return u({
|
|
307
|
+
type: "custom",
|
|
308
|
+
path: r || window.location.pathname,
|
|
309
|
+
metadata: {
|
|
310
|
+
eventName: o,
|
|
311
|
+
...e
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
export {
|
|
316
|
+
S as getConnectionStatus,
|
|
317
|
+
m as getStoredEvents,
|
|
318
|
+
f as initEventTracker,
|
|
319
|
+
C as offConnectionStatus,
|
|
320
|
+
y as onConnectionStatus,
|
|
321
|
+
w as setAuthToken,
|
|
322
|
+
A as trackClick,
|
|
323
|
+
b as trackCustom,
|
|
324
|
+
u as trackEvent,
|
|
325
|
+
N as trackInput,
|
|
326
|
+
E as trackNavigation
|
|
327
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { UserEvent } from '@mcp-fe/mcp-worker';
|
|
2
|
+
export type { UserEvent } from '@mcp-fe/mcp-worker';
|
|
3
|
+
export interface UserEventData {
|
|
4
|
+
type: 'navigation' | 'click' | 'input' | 'custom';
|
|
5
|
+
path?: string;
|
|
6
|
+
from?: string;
|
|
7
|
+
to?: string;
|
|
8
|
+
element?: string;
|
|
9
|
+
elementId?: string;
|
|
10
|
+
elementClass?: string;
|
|
11
|
+
elementText?: string;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export declare function initEventTracker(registration?: ServiceWorkerRegistration): Promise<void>;
|
|
15
|
+
export declare function trackEvent(event: UserEventData): Promise<void>;
|
|
16
|
+
export declare function getStoredEvents(): Promise<UserEvent[]>;
|
|
17
|
+
export declare function getConnectionStatus(): Promise<boolean>;
|
|
18
|
+
export declare function setAuthToken(token: string): void;
|
|
19
|
+
export declare function onConnectionStatus(cb: (connected: boolean) => void): void;
|
|
20
|
+
export declare function offConnectionStatus(cb: (connected: boolean) => void): void;
|
|
21
|
+
export declare function trackNavigation(from: string, to: string, path?: string): Promise<void>;
|
|
22
|
+
export declare function trackClick(element: HTMLElement, path?: string, metadata?: Record<string, unknown>): Promise<void>;
|
|
23
|
+
export declare function trackInput(element: HTMLElement, value?: string, path?: string): Promise<void>;
|
|
24
|
+
export declare function trackCustom(eventName: string, metadata?: Record<string, unknown>, path?: string): Promise<void>;
|
|
25
|
+
//# sourceMappingURL=event-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-tracker.d.ts","sourceRoot":"","sources":["../../../../libs/event-tracker/src/lib/event-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,SAAS,EAAgB,MAAM,oBAAoB,CAAC;AAC/E,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,YAAY,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAMD,wBAAsB,gBAAgB,CAAC,YAAY,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9F;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpE;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAG5D;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAE5D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEhD;AAGD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAEzE;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAE1E;AAGD,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5F;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAevH;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBnG;AAED,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASrH"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-fe/event-tracker",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
7
7
|
"types": "./index.d.ts",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@mcp-fe/mcp-worker": "0.0.
|
|
9
|
+
"@mcp-fe/mcp-worker": "0.0.11"
|
|
10
10
|
},
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
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": "event-tracker",
|
|
3
|
-
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"sourceRoot": "libs/event-tracker/src",
|
|
5
|
-
"projectType": "library",
|
|
6
|
-
"tags": [],
|
|
7
|
-
"// targets": "to see all targets run: nx show project event-tracker --web",
|
|
8
|
-
"targets": {}
|
|
9
|
-
}
|
package/src/lib/event-tracker.ts
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { queryEvents, type UserEvent, WorkerClient } from '@mcp-fe/mcp-worker';
|
|
2
|
-
export type { UserEvent } from '@mcp-fe/mcp-worker';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface UserEventData {
|
|
6
|
-
type: 'navigation' | 'click' | 'input' | 'custom';
|
|
7
|
-
path?: string;
|
|
8
|
-
from?: string;
|
|
9
|
-
to?: string;
|
|
10
|
-
element?: string;
|
|
11
|
-
elementId?: string;
|
|
12
|
-
elementClass?: string;
|
|
13
|
-
elementText?: string;
|
|
14
|
-
metadata?: Record<string, unknown>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Singleton client used by exported functions
|
|
18
|
-
const workerClient = new WorkerClient();
|
|
19
|
-
|
|
20
|
-
// Public API - thin wrappers around workerClient
|
|
21
|
-
export async function initEventTracker(registration?: ServiceWorkerRegistration): Promise<void> {
|
|
22
|
-
return workerClient.init(registration);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function trackEvent(event: UserEventData): Promise<void> {
|
|
26
|
-
const userEvent = { ...event, timestamp: Date.now() };
|
|
27
|
-
// use request to ensure the worker stored the event; mimic previous behavior
|
|
28
|
-
await workerClient.request('STORE_EVENT', { event: userEvent });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export async function getStoredEvents(): Promise<UserEvent[]> {
|
|
32
|
-
const res = await queryEvents();
|
|
33
|
-
return Array.isArray(res) ? res : [];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export async function getConnectionStatus(): Promise<boolean> {
|
|
37
|
-
return workerClient.getConnectionStatus();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function setAuthToken(token: string): void {
|
|
41
|
-
workerClient.setAuthToken(token);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Connection status subscription helpers
|
|
45
|
-
export function onConnectionStatus(cb: (connected: boolean) => void): void {
|
|
46
|
-
workerClient.onConnectionStatus(cb);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function offConnectionStatus(cb: (connected: boolean) => void): void {
|
|
50
|
-
workerClient.offConnectionStatus(cb);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Convenience helpers (kept outside for ergonomic API)
|
|
54
|
-
export async function trackNavigation(from: string, to: string, path?: string): Promise<void> {
|
|
55
|
-
return trackEvent({ type: 'navigation', from, to, path: path || to });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export async function trackClick(element: HTMLElement, path?: string, metadata?: Record<string, unknown>): Promise<void> {
|
|
59
|
-
const elementId = element.id || undefined;
|
|
60
|
-
const elementClass = element.className || undefined;
|
|
61
|
-
const elementText = element.textContent?.trim().substring(0, 100) || undefined;
|
|
62
|
-
const tagName = element.tagName.toLowerCase();
|
|
63
|
-
|
|
64
|
-
return trackEvent({
|
|
65
|
-
type: 'click',
|
|
66
|
-
element: tagName,
|
|
67
|
-
elementId,
|
|
68
|
-
elementClass,
|
|
69
|
-
elementText,
|
|
70
|
-
path: path || window.location.pathname,
|
|
71
|
-
metadata,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export async function trackInput(element: HTMLElement, value?: string, path?: string): Promise<void> {
|
|
76
|
-
const elementId = element.id || undefined;
|
|
77
|
-
const elementClass = element.className || undefined;
|
|
78
|
-
const tagName = element.tagName.toLowerCase();
|
|
79
|
-
|
|
80
|
-
return trackEvent({
|
|
81
|
-
type: 'input',
|
|
82
|
-
element: tagName,
|
|
83
|
-
elementId,
|
|
84
|
-
elementClass,
|
|
85
|
-
path: path || window.location.pathname,
|
|
86
|
-
metadata: {
|
|
87
|
-
valueLength: value?.length || 0,
|
|
88
|
-
value: value,
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export async function trackCustom(eventName: string, metadata?: Record<string, unknown>, path?: string): Promise<void> {
|
|
94
|
-
return trackEvent({
|
|
95
|
-
type: 'custom',
|
|
96
|
-
path: path || window.location.pathname,
|
|
97
|
-
metadata: {
|
|
98
|
-
eventName,
|
|
99
|
-
...metadata,
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"forceConsistentCasingInFileNames": true,
|
|
6
|
-
"strict": true,
|
|
7
|
-
"importHelpers": true,
|
|
8
|
-
"noImplicitOverride": true,
|
|
9
|
-
"noImplicitReturns": true,
|
|
10
|
-
"noFallthroughCasesInSwitch": true,
|
|
11
|
-
"noPropertyAccessFromIndexSignature": true,
|
|
12
|
-
"lib": ["esnext", "dom", "webworker"]
|
|
13
|
-
},
|
|
14
|
-
"files": [],
|
|
15
|
-
"include": [],
|
|
16
|
-
"references": [
|
|
17
|
-
{
|
|
18
|
-
"path": "./tsconfig.lib.json"
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"path": "./tsconfig.spec.json"
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}
|
package/tsconfig.lib.json
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "esnext",
|
|
5
|
-
"outDir": "../../dist/out-tsc",
|
|
6
|
-
"declaration": true,
|
|
7
|
-
"types": ["node", "vite/client"]
|
|
8
|
-
},
|
|
9
|
-
"include": ["src/**/*.ts"],
|
|
10
|
-
"exclude": [
|
|
11
|
-
"vite.config.ts",
|
|
12
|
-
"vite.config.mts",
|
|
13
|
-
"vitest.config.ts",
|
|
14
|
-
"vitest.config.mts",
|
|
15
|
-
"src/**/*.test.ts",
|
|
16
|
-
"src/**/*.spec.ts",
|
|
17
|
-
"src/**/*.test.tsx",
|
|
18
|
-
"src/**/*.spec.tsx",
|
|
19
|
-
"src/**/*.test.js",
|
|
20
|
-
"src/**/*.spec.js",
|
|
21
|
-
"src/**/*.test.jsx",
|
|
22
|
-
"src/**/*.spec.jsx"
|
|
23
|
-
],
|
|
24
|
-
"references": []
|
|
25
|
-
}
|
package/tsconfig.spec.json
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "../../dist/out-tsc",
|
|
5
|
-
"types": [
|
|
6
|
-
"vitest/globals",
|
|
7
|
-
"vitest/importMeta",
|
|
8
|
-
"vite/client",
|
|
9
|
-
"node",
|
|
10
|
-
"vitest"
|
|
11
|
-
]
|
|
12
|
-
},
|
|
13
|
-
"include": [
|
|
14
|
-
"vite.config.ts",
|
|
15
|
-
"vite.config.mts",
|
|
16
|
-
"vitest.config.ts",
|
|
17
|
-
"vitest.config.mts",
|
|
18
|
-
"src/**/*.test.ts",
|
|
19
|
-
"src/**/*.spec.ts",
|
|
20
|
-
"src/**/*.test.tsx",
|
|
21
|
-
"src/**/*.spec.tsx",
|
|
22
|
-
"src/**/*.test.js",
|
|
23
|
-
"src/**/*.spec.js",
|
|
24
|
-
"src/**/*.test.jsx",
|
|
25
|
-
"src/**/*.spec.jsx",
|
|
26
|
-
"src/**/*.d.ts"
|
|
27
|
-
]
|
|
28
|
-
}
|
package/vite.config.mts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/// <reference types='vitest' />
|
|
2
|
-
import { defineConfig } from 'vite';
|
|
3
|
-
import dts from 'vite-plugin-dts';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
|
6
|
-
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
|
7
|
-
|
|
8
|
-
export default defineConfig(() => ({
|
|
9
|
-
root: import.meta.dirname,
|
|
10
|
-
cacheDir: '../../node_modules/.vite/libs/event-tracker',
|
|
11
|
-
plugins: [
|
|
12
|
-
nxViteTsPaths(),
|
|
13
|
-
nxCopyAssetsPlugin(['*.md']),
|
|
14
|
-
dts({
|
|
15
|
-
entryRoot: 'src',
|
|
16
|
-
tsconfigPath: path.join(import.meta.dirname, 'tsconfig.lib.json'),
|
|
17
|
-
pathsToAliases: false,
|
|
18
|
-
}),
|
|
19
|
-
],
|
|
20
|
-
// Uncomment this if you are using workers.
|
|
21
|
-
// worker: {
|
|
22
|
-
// plugins: () => [ nxViteTsPaths() ],
|
|
23
|
-
// },
|
|
24
|
-
// Configuration for building your library.
|
|
25
|
-
// See: https://vite.dev/guide/build.html#library-mode
|
|
26
|
-
build: {
|
|
27
|
-
outDir: '../../dist/libs/event-tracker',
|
|
28
|
-
emptyOutDir: true,
|
|
29
|
-
reportCompressedSize: true,
|
|
30
|
-
commonjsOptions: {
|
|
31
|
-
transformMixedEsModules: true,
|
|
32
|
-
},
|
|
33
|
-
lib: {
|
|
34
|
-
// Could also be a dictionary or array of multiple entry points.
|
|
35
|
-
entry: 'src/index.ts',
|
|
36
|
-
name: 'event-tracker',
|
|
37
|
-
fileName: 'index',
|
|
38
|
-
// Change this to the formats you want to support.
|
|
39
|
-
// Don't forget to update your package.json as well.
|
|
40
|
-
formats: ['es' as const],
|
|
41
|
-
},
|
|
42
|
-
rollupOptions: {
|
|
43
|
-
// External packages that should not be bundled into your library.
|
|
44
|
-
external: [],
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
test: {
|
|
48
|
-
name: 'event-tracker',
|
|
49
|
-
watch: false,
|
|
50
|
-
globals: true,
|
|
51
|
-
environment: 'node',
|
|
52
|
-
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
|
53
|
-
reporters: ['default'],
|
|
54
|
-
coverage: {
|
|
55
|
-
reportsDirectory: '../../coverage/libs/event-tracker',
|
|
56
|
-
provider: 'v8' as const,
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
}));
|