@interfere/react 1.0.0-alpha.7 → 1.0.1

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.
Files changed (92) hide show
  1. package/dist/error-boundary.d.mts +27 -0
  2. package/dist/error-boundary.d.mts.map +1 -0
  3. package/dist/error-boundary.mjs +44 -0
  4. package/dist/error-boundary.mjs.map +1 -0
  5. package/dist/internal/client.d.mts +32 -0
  6. package/dist/internal/client.d.mts.map +1 -0
  7. package/dist/internal/client.mjs +100 -0
  8. package/dist/internal/client.mjs.map +1 -0
  9. package/dist/internal/config.d.mts +9 -0
  10. package/dist/internal/config.d.mts.map +1 -0
  11. package/dist/internal/config.mjs +27 -0
  12. package/dist/internal/config.mjs.map +1 -0
  13. package/dist/internal/consent.d.mts +15 -0
  14. package/dist/internal/consent.d.mts.map +1 -0
  15. package/dist/internal/consent.mjs +25 -0
  16. package/dist/internal/consent.mjs.map +1 -0
  17. package/dist/internal/context.d.mts +6 -0
  18. package/dist/internal/context.d.mts.map +1 -0
  19. package/dist/internal/context.mjs +32 -0
  20. package/dist/internal/context.mjs.map +1 -0
  21. package/dist/internal/envelope.d.mts +14 -0
  22. package/dist/internal/envelope.d.mts.map +1 -0
  23. package/dist/internal/envelope.mjs +20 -0
  24. package/dist/internal/envelope.mjs.map +1 -0
  25. package/dist/internal/errors.d.mts +4 -0
  26. package/dist/internal/errors.d.mts.map +1 -0
  27. package/dist/internal/errors.mjs +4 -0
  28. package/dist/internal/errors.mjs.map +1 -0
  29. package/dist/internal/plugin-runtime.d.mts +26 -0
  30. package/dist/internal/plugin-runtime.d.mts.map +1 -0
  31. package/dist/internal/plugin-runtime.mjs +85 -0
  32. package/dist/internal/plugin-runtime.mjs.map +1 -0
  33. package/dist/internal/sw.d.mts +4 -0
  34. package/dist/internal/sw.d.mts.map +1 -0
  35. package/dist/internal/sw.mjs +10 -0
  36. package/dist/internal/sw.mjs.map +1 -0
  37. package/dist/plugins/errors.d.mts +6 -0
  38. package/dist/plugins/errors.d.mts.map +1 -0
  39. package/dist/plugins/errors.mjs +59 -0
  40. package/dist/plugins/errors.mjs.map +1 -0
  41. package/dist/plugins/fingerprint.d.mts +6 -0
  42. package/dist/plugins/fingerprint.d.mts.map +1 -0
  43. package/dist/plugins/fingerprint.mjs +13 -0
  44. package/dist/plugins/fingerprint.mjs.map +1 -0
  45. package/dist/plugins/lib/loader.d.mts +10 -0
  46. package/dist/plugins/lib/loader.d.mts.map +1 -0
  47. package/dist/plugins/lib/loader.mjs +43 -0
  48. package/dist/plugins/lib/loader.mjs.map +1 -0
  49. package/dist/plugins/lib/types.d.mts +14 -0
  50. package/dist/plugins/lib/types.d.mts.map +1 -0
  51. package/dist/plugins/lib/types.mjs +1 -0
  52. package/dist/plugins/pages.d.mts +6 -0
  53. package/dist/plugins/pages.d.mts.map +1 -0
  54. package/dist/plugins/pages.mjs +102 -0
  55. package/dist/plugins/pages.mjs.map +1 -0
  56. package/dist/plugins/rage-clicks.d.mts +6 -0
  57. package/dist/plugins/rage-clicks.d.mts.map +1 -0
  58. package/dist/plugins/rage-clicks.mjs +53 -0
  59. package/dist/plugins/rage-clicks.mjs.map +1 -0
  60. package/dist/plugins/replay.d.mts +6 -0
  61. package/dist/plugins/replay.d.mts.map +1 -0
  62. package/dist/plugins/replay.mjs +62 -0
  63. package/dist/plugins/replay.mjs.map +1 -0
  64. package/dist/provider.d.mts +30 -0
  65. package/dist/provider.d.mts.map +1 -0
  66. package/dist/provider.mjs +30 -0
  67. package/dist/provider.mjs.map +1 -0
  68. package/dist/tracking/api.d.mts +17 -0
  69. package/dist/tracking/api.d.mts.map +1 -0
  70. package/dist/tracking/api.mjs +76 -0
  71. package/dist/tracking/api.mjs.map +1 -0
  72. package/dist/tracking/session.d.mts +19 -0
  73. package/dist/tracking/session.d.mts.map +1 -0
  74. package/dist/tracking/session.mjs +76 -0
  75. package/dist/tracking/session.mjs.map +1 -0
  76. package/dist/tracking/visitor.d.mts +7 -0
  77. package/dist/tracking/visitor.d.mts.map +1 -0
  78. package/dist/tracking/visitor.mjs +40 -0
  79. package/dist/tracking/visitor.mjs.map +1 -0
  80. package/dist/transport/http.d.mts +16 -0
  81. package/dist/transport/http.d.mts.map +1 -0
  82. package/dist/transport/http.mjs +56 -0
  83. package/dist/transport/http.mjs.map +1 -0
  84. package/dist/transport/queue.d.mts +25 -0
  85. package/dist/transport/queue.d.mts.map +1 -0
  86. package/dist/transport/queue.mjs +60 -0
  87. package/dist/transport/queue.mjs.map +1 -0
  88. package/dist/util/log.d.mts +13 -0
  89. package/dist/util/log.d.mts.map +1 -0
  90. package/dist/util/log.mjs +37 -0
  91. package/dist/util/log.mjs.map +1 -0
  92. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.mjs","names":[],"sources":["../../src/tracking/api.ts"],"sourcesContent":["import type { IdentifyParams } from \"@interfere/types/sdk/identify\";\n\nimport { buildHeaders, type IngestTarget } from \"../transport/http.js\";\nimport { createLogger } from \"../util/log.js\";\nimport { SessionManager } from \"./session.js\";\nimport { getVisitorId, whenVisitorReady } from \"./visitor.js\";\n\nconst log = createLogger(\"tracking\");\n\nlet mgr: SessionManager | null = null;\nlet target: IngestTarget | null = null;\nlet currentIdentity: IdentifyParams | null = null;\nlet identifiedSessionId: string | null = null;\n\nfunction fire(\n url: string,\n method: \"POST\" | \"PUT\",\n headers: Headers,\n body: unknown\n): void {\n fetch(url, {\n method,\n headers: buildHeaders(headers),\n body: JSON.stringify(body),\n keepalive: true,\n }).catch(() => {\n log.warn(\"fire-and-forget %s failed\", method);\n });\n}\n\nasync function onRotate(sessionId: string): Promise<void> {\n if (!target) {\n return;\n }\n const visitorId = await whenVisitorReady();\n log.debug(\"POST session %s (visitor=%s)\", sessionId, visitorId ?? \"pending\");\n fire(target.url, \"POST\", target.headers, { sessionId, visitorId });\n}\n\nexport function bootstrap(sessionTarget: IngestTarget): void {\n target = sessionTarget;\n\n mgr = new SessionManager((id) => {\n onRotate(id).catch(() => {\n /* best-effort */\n });\n });\n}\n\nexport const session = {\n getId(): string | null {\n return mgr?.getSessionId() ?? null;\n },\n\n getWindowId(): string | null {\n return mgr?.getWindowId() ?? null;\n },\n};\n\nexport const identity = {\n get(): IdentifyParams | null {\n return currentIdentity;\n },\n\n set(params: IdentifyParams): void {\n if (!(mgr && target)) {\n return;\n }\n const sessionId = mgr.getSessionId();\n if (identifiedSessionId === sessionId) {\n log.debug(\"skipped, already identified for session %s\", sessionId);\n return;\n }\n\n currentIdentity = params;\n identifiedSessionId = sessionId;\n\n const visitorId = getVisitorId();\n log.info(\"PUT session %s → user %s\", sessionId, params.identifier);\n fire(target.url, \"PUT\", target.headers, {\n sessionId,\n visitorId,\n ...params,\n });\n },\n\n clear(): void {\n currentIdentity = null;\n identifiedSessionId = null;\n },\n};\n\nexport function teardown(): void {\n identity.clear();\n mgr = null;\n target = null;\n}\n"],"mappings":";;;;;AAOA,MAAM,MAAM,aAAa,WAAW;AAEpC,IAAI,MAA6B;AACjC,IAAI,SAA8B;AAClC,IAAI,kBAAyC;AAC7C,IAAI,sBAAqC;AAEzC,SAAS,KACP,KACA,QACA,SACA,MACM;AACN,OAAM,KAAK;EACT;EACA,SAAS,aAAa,QAAQ;EAC9B,MAAM,KAAK,UAAU,KAAK;EAC1B,WAAW;EACZ,CAAC,CAAC,YAAY;AACb,MAAI,KAAK,6BAA6B,OAAO;GAC7C;;AAGJ,eAAe,SAAS,WAAkC;AACxD,KAAI,CAAC,OACH;CAEF,MAAM,YAAY,MAAM,kBAAkB;AAC1C,KAAI,MAAM,gCAAgC,WAAW,aAAa,UAAU;AAC5E,MAAK,OAAO,KAAK,QAAQ,OAAO,SAAS;EAAE;EAAW;EAAW,CAAC;;AAGpE,SAAgB,UAAU,eAAmC;AAC3D,UAAS;AAET,OAAM,IAAI,gBAAgB,OAAO;AAC/B,WAAS,GAAG,CAAC,YAAY,GAEvB;GACF;;AAGJ,MAAa,UAAU;CACrB,QAAuB;AACrB,SAAO,KAAK,cAAc,IAAI;;CAGhC,cAA6B;AAC3B,SAAO,KAAK,aAAa,IAAI;;CAEhC;AAED,MAAa,WAAW;CACtB,MAA6B;AAC3B,SAAO;;CAGT,IAAI,QAA8B;AAChC,MAAI,EAAE,OAAO,QACX;EAEF,MAAM,YAAY,IAAI,cAAc;AACpC,MAAI,wBAAwB,WAAW;AACrC,OAAI,MAAM,8CAA8C,UAAU;AAClE;;AAGF,oBAAkB;AAClB,wBAAsB;EAEtB,MAAM,YAAY,cAAc;AAChC,MAAI,KAAK,4BAA4B,WAAW,OAAO,WAAW;AAClE,OAAK,OAAO,KAAK,OAAO,OAAO,SAAS;GACtC;GACA;GACA,GAAG;GACJ,CAAC;;CAGJ,QAAc;AACZ,oBAAkB;AAClB,wBAAsB;;CAEzB;AAED,SAAgB,WAAiB;AAC/B,UAAS,OAAO;AAChB,OAAM;AACN,UAAS"}
@@ -0,0 +1,19 @@
1
+ //#region src/tracking/session.d.ts
2
+ type OnRotate = (sessionId: string) => void;
3
+ declare class SessionManager {
4
+ sessionId: string | null;
5
+ windowId: string | null;
6
+ private readonly local;
7
+ private readonly session;
8
+ private readonly onRotate;
9
+ private lastActivityMs;
10
+ constructor(onRotate?: OnRotate);
11
+ getSessionId(): string;
12
+ getWindowId(): string;
13
+ private restore;
14
+ private rotate;
15
+ private touch;
16
+ private isExpired;
17
+ }
18
+ //#endregion
19
+ export { OnRotate, SessionManager };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.mts","names":[],"sources":["../../src/tracking/session.ts"],"mappings":";KAoBY,QAAA,IAAY,SAAA;AAAA,cAEX,cAAA;EACX,SAAA;EACA,QAAA;EAAA,iBACiB,KAAA;EAAA,iBACA,OAAA;EAAA,iBACA,QAAA;EAAA,QACT,cAAA;cAEI,QAAA,GAAW,QAAA;EAOvB,YAAA,CAAA;EAQA,WAAA,CAAA;EAAA,QAgBQ,OAAA;EAAA,QAWA,MAAA;EAAA,QAQA,KAAA;EAAA,QAKA,SAAA;AAAA"}
@@ -0,0 +1,76 @@
1
+ import { nanoid } from "nanoid";
2
+ import { v7 } from "uuid";
3
+ //#region src/tracking/session.ts
4
+ const SESSION_ID_KEY = "interfere:session_id";
5
+ const LAST_ACTIVITY_KEY = "interfere:last_activity";
6
+ const WINDOW_ID_KEY = "interfere:window_id";
7
+ const SESSION_TIMEOUT_MS = 1800 * 1e3;
8
+ function tryStorage(type) {
9
+ try {
10
+ const s = globalThis[type];
11
+ const key = "__interfere_probe__";
12
+ s.setItem(key, "1");
13
+ s.removeItem(key);
14
+ return s;
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+ var SessionManager = class {
20
+ sessionId = null;
21
+ windowId = null;
22
+ local;
23
+ session;
24
+ onRotate = null;
25
+ lastActivityMs = 0;
26
+ constructor(onRotate) {
27
+ this.local = tryStorage("localStorage");
28
+ this.session = tryStorage("sessionStorage");
29
+ this.onRotate = onRotate ?? null;
30
+ this.restore();
31
+ }
32
+ getSessionId() {
33
+ if (this.sessionId && !this.isExpired()) {
34
+ this.touch();
35
+ return this.sessionId;
36
+ }
37
+ return this.rotate();
38
+ }
39
+ getWindowId() {
40
+ if (this.windowId) return this.windowId;
41
+ const stored = this.session?.getItem(WINDOW_ID_KEY);
42
+ if (stored) {
43
+ this.windowId = stored;
44
+ return stored;
45
+ }
46
+ this.windowId = `win_${nanoid(10)}`;
47
+ this.session?.setItem(WINDOW_ID_KEY, this.windowId);
48
+ return this.windowId;
49
+ }
50
+ restore() {
51
+ const stored = this.local?.getItem(SESSION_ID_KEY);
52
+ if (stored && !this.isExpired()) {
53
+ this.sessionId = stored;
54
+ this.touch();
55
+ } else this.rotate();
56
+ }
57
+ rotate() {
58
+ this.sessionId = v7();
59
+ this.local?.setItem(SESSION_ID_KEY, this.sessionId);
60
+ this.touch();
61
+ this.onRotate?.(this.sessionId);
62
+ return this.sessionId;
63
+ }
64
+ touch() {
65
+ this.lastActivityMs = Date.now();
66
+ this.local?.setItem(LAST_ACTIVITY_KEY, String(this.lastActivityMs));
67
+ }
68
+ isExpired() {
69
+ const raw = this.local?.getItem(LAST_ACTIVITY_KEY);
70
+ const ts = raw ? Number(raw) : this.lastActivityMs;
71
+ if (ts === 0) return true;
72
+ return Date.now() - ts > SESSION_TIMEOUT_MS;
73
+ }
74
+ };
75
+ //#endregion
76
+ export { SessionManager };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.mjs","names":["uuidv7"],"sources":["../../src/tracking/session.ts"],"sourcesContent":["import { nanoid } from \"nanoid\";\nimport { v7 as uuidv7 } from \"uuid\";\n\nconst SESSION_ID_KEY = \"interfere:session_id\";\nconst LAST_ACTIVITY_KEY = \"interfere:last_activity\";\nconst WINDOW_ID_KEY = \"interfere:window_id\";\nconst SESSION_TIMEOUT_MS = 30 * 60 * 1000;\n\nfunction tryStorage(type: \"localStorage\" | \"sessionStorage\"): Storage | null {\n try {\n const s = globalThis[type];\n const key = \"__interfere_probe__\";\n s.setItem(key, \"1\");\n s.removeItem(key);\n return s;\n } catch {\n return null;\n }\n}\n\nexport type OnRotate = (sessionId: string) => void;\n\nexport class SessionManager {\n sessionId: string | null = null;\n windowId: string | null = null;\n private readonly local: Storage | null;\n private readonly session: Storage | null;\n private readonly onRotate: OnRotate | null = null;\n private lastActivityMs = 0;\n\n constructor(onRotate?: OnRotate) {\n this.local = tryStorage(\"localStorage\");\n this.session = tryStorage(\"sessionStorage\");\n this.onRotate = onRotate ?? null;\n this.restore();\n }\n\n getSessionId(): string {\n if (this.sessionId && !this.isExpired()) {\n this.touch();\n return this.sessionId;\n }\n return this.rotate();\n }\n\n getWindowId(): string {\n if (this.windowId) {\n return this.windowId;\n }\n\n const stored = this.session?.getItem(WINDOW_ID_KEY);\n if (stored) {\n this.windowId = stored;\n return stored;\n }\n\n this.windowId = `win_${nanoid(10)}`;\n this.session?.setItem(WINDOW_ID_KEY, this.windowId);\n return this.windowId;\n }\n\n private restore(): void {\n const stored = this.local?.getItem(SESSION_ID_KEY);\n\n if (stored && !this.isExpired()) {\n this.sessionId = stored;\n this.touch();\n } else {\n this.rotate();\n }\n }\n\n private rotate(): string {\n this.sessionId = uuidv7();\n this.local?.setItem(SESSION_ID_KEY, this.sessionId);\n this.touch();\n this.onRotate?.(this.sessionId);\n return this.sessionId;\n }\n\n private touch(): void {\n this.lastActivityMs = Date.now();\n this.local?.setItem(LAST_ACTIVITY_KEY, String(this.lastActivityMs));\n }\n\n private isExpired(): boolean {\n const raw = this.local?.getItem(LAST_ACTIVITY_KEY);\n const ts = raw ? Number(raw) : this.lastActivityMs;\n\n if (ts === 0) {\n return true;\n }\n return Date.now() - ts > SESSION_TIMEOUT_MS;\n }\n}\n"],"mappings":";;;AAGA,MAAM,iBAAiB;AACvB,MAAM,oBAAoB;AAC1B,MAAM,gBAAgB;AACtB,MAAM,qBAAqB,OAAU;AAErC,SAAS,WAAW,MAAyD;AAC3E,KAAI;EACF,MAAM,IAAI,WAAW;EACrB,MAAM,MAAM;AACZ,IAAE,QAAQ,KAAK,IAAI;AACnB,IAAE,WAAW,IAAI;AACjB,SAAO;SACD;AACN,SAAO;;;AAMX,IAAa,iBAAb,MAA4B;CAC1B,YAA2B;CAC3B,WAA0B;CAC1B;CACA;CACA,WAA6C;CAC7C,iBAAyB;CAEzB,YAAY,UAAqB;AAC/B,OAAK,QAAQ,WAAW,eAAe;AACvC,OAAK,UAAU,WAAW,iBAAiB;AAC3C,OAAK,WAAW,YAAY;AAC5B,OAAK,SAAS;;CAGhB,eAAuB;AACrB,MAAI,KAAK,aAAa,CAAC,KAAK,WAAW,EAAE;AACvC,QAAK,OAAO;AACZ,UAAO,KAAK;;AAEd,SAAO,KAAK,QAAQ;;CAGtB,cAAsB;AACpB,MAAI,KAAK,SACP,QAAO,KAAK;EAGd,MAAM,SAAS,KAAK,SAAS,QAAQ,cAAc;AACnD,MAAI,QAAQ;AACV,QAAK,WAAW;AAChB,UAAO;;AAGT,OAAK,WAAW,OAAO,OAAO,GAAG;AACjC,OAAK,SAAS,QAAQ,eAAe,KAAK,SAAS;AACnD,SAAO,KAAK;;CAGd,UAAwB;EACtB,MAAM,SAAS,KAAK,OAAO,QAAQ,eAAe;AAElD,MAAI,UAAU,CAAC,KAAK,WAAW,EAAE;AAC/B,QAAK,YAAY;AACjB,QAAK,OAAO;QAEZ,MAAK,QAAQ;;CAIjB,SAAyB;AACvB,OAAK,YAAYA,IAAQ;AACzB,OAAK,OAAO,QAAQ,gBAAgB,KAAK,UAAU;AACnD,OAAK,OAAO;AACZ,OAAK,WAAW,KAAK,UAAU;AAC/B,SAAO,KAAK;;CAGd,QAAsB;AACpB,OAAK,iBAAiB,KAAK,KAAK;AAChC,OAAK,OAAO,QAAQ,mBAAmB,OAAO,KAAK,eAAe,CAAC;;CAGrE,YAA6B;EAC3B,MAAM,MAAM,KAAK,OAAO,QAAQ,kBAAkB;EAClD,MAAM,KAAK,MAAM,OAAO,IAAI,GAAG,KAAK;AAEpC,MAAI,OAAO,EACT,QAAO;AAET,SAAO,KAAK,KAAK,GAAG,KAAK"}
@@ -0,0 +1,7 @@
1
+ //#region src/tracking/visitor.d.ts
2
+ declare function initVisitor(): void;
3
+ declare function getVisitorId(): string | null;
4
+ declare function whenVisitorReady(): Promise<string | null>;
5
+ declare function resetVisitor(): void;
6
+ //#endregion
7
+ export { getVisitorId, initVisitor, resetVisitor, whenVisitorReady };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor.d.mts","names":[],"sources":["../../src/tracking/visitor.ts"],"mappings":";iBAcgB,WAAA,CAAA;AAAA,iBA+BA,YAAA,CAAA;AAAA,iBAIA,gBAAA,CAAA,GAAoB,OAAA;AAAA,iBAOpB,YAAA,CAAA"}
@@ -0,0 +1,40 @@
1
+ import { createLogger } from "../util/log.mjs";
2
+ //#region src/tracking/visitor.ts
3
+ const log = createLogger("visitor");
4
+ let visitorId = null;
5
+ let pending = null;
6
+ function resolveApiKey() {
7
+ if (typeof process === "undefined") return;
8
+ return process.env.INTERFERE_FINGERPRINT_KEY ?? void 0;
9
+ }
10
+ function initVisitor() {
11
+ if (visitorId || pending) return;
12
+ const apiKey = resolveApiKey();
13
+ if (!apiKey) {
14
+ log.info("no INTERFERE_FINGERPRINT_KEY, skipping");
15
+ return;
16
+ }
17
+ pending = (async () => {
18
+ try {
19
+ visitorId = (await (await (await import("@fingerprintjs/fingerprintjs-pro")).load({ apiKey })).get()).visitorId;
20
+ log.debug("resolved %s", visitorId);
21
+ return visitorId;
22
+ } catch {
23
+ log.error("fingerprint failed");
24
+ return null;
25
+ }
26
+ })();
27
+ }
28
+ function getVisitorId() {
29
+ return visitorId;
30
+ }
31
+ function whenVisitorReady() {
32
+ if (visitorId) return Promise.resolve(visitorId);
33
+ return pending ?? Promise.resolve(null);
34
+ }
35
+ function resetVisitor() {
36
+ visitorId = null;
37
+ pending = null;
38
+ }
39
+ //#endregion
40
+ export { getVisitorId, initVisitor, resetVisitor, whenVisitorReady };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor.mjs","names":[],"sources":["../../src/tracking/visitor.ts"],"sourcesContent":["import { createLogger } from \"../util/log.js\";\n\nconst log = createLogger(\"visitor\");\n\nlet visitorId: string | null = null;\nlet pending: Promise<string | null> | null = null;\n\nfunction resolveApiKey(): string | undefined {\n if (typeof process === \"undefined\") {\n return undefined;\n }\n return process.env.INTERFERE_FINGERPRINT_KEY ?? undefined;\n}\n\nexport function initVisitor(): void {\n if (visitorId || pending) {\n return;\n }\n\n const apiKey = resolveApiKey();\n if (!apiKey) {\n log.info(\"no INTERFERE_FINGERPRINT_KEY, skipping\");\n return;\n }\n\n pending = (async () => {\n try {\n const FingerprintJS = await import(\"@fingerprintjs/fingerprintjs-pro\");\n\n const fp = await FingerprintJS.load({ apiKey });\n const result = await fp.get();\n\n visitorId = result.visitorId;\n\n log.debug(\"resolved %s\", visitorId);\n\n return visitorId;\n } catch {\n log.error(\"fingerprint failed\");\n\n return null;\n }\n })();\n}\n\nexport function getVisitorId(): string | null {\n return visitorId;\n}\n\nexport function whenVisitorReady(): Promise<string | null> {\n if (visitorId) {\n return Promise.resolve(visitorId);\n }\n return pending ?? Promise.resolve(null);\n}\n\nexport function resetVisitor(): void {\n visitorId = null;\n pending = null;\n}\n"],"mappings":";;AAEA,MAAM,MAAM,aAAa,UAAU;AAEnC,IAAI,YAA2B;AAC/B,IAAI,UAAyC;AAE7C,SAAS,gBAAoC;AAC3C,KAAI,OAAO,YAAY,YACrB;AAEF,QAAO,QAAQ,IAAI,6BAA6B,KAAA;;AAGlD,SAAgB,cAAoB;AAClC,KAAI,aAAa,QACf;CAGF,MAAM,SAAS,eAAe;AAC9B,KAAI,CAAC,QAAQ;AACX,MAAI,KAAK,yCAAyC;AAClD;;AAGF,YAAW,YAAY;AACrB,MAAI;AAMF,gBAFe,OADJ,OAFW,MAAM,OAAO,qCAEJ,KAAK,EAAE,QAAQ,CAAC,EACvB,KAAK,EAEV;AAEnB,OAAI,MAAM,eAAe,UAAU;AAEnC,UAAO;UACD;AACN,OAAI,MAAM,qBAAqB;AAE/B,UAAO;;KAEP;;AAGN,SAAgB,eAA8B;AAC5C,QAAO;;AAGT,SAAgB,mBAA2C;AACzD,KAAI,UACF,QAAO,QAAQ,QAAQ,UAAU;AAEnC,QAAO,WAAW,QAAQ,QAAQ,KAAK;;AAGzC,SAAgB,eAAqB;AACnC,aAAY;AACZ,WAAU"}
@@ -0,0 +1,16 @@
1
+ import { Envelope } from "@interfere/types/sdk/envelope";
2
+
3
+ //#region src/transport/http.d.ts
4
+ interface IngestTarget {
5
+ headers: Headers;
6
+ url: string;
7
+ }
8
+ declare function buildHeaders(base: Headers): Record<string, string>;
9
+ declare class HttpTransport {
10
+ private readonly target;
11
+ private pendingKeepalive;
12
+ constructor(target: IngestTarget);
13
+ send(envelopes: Envelope[]): Promise<void>;
14
+ }
15
+ //#endregion
16
+ export { HttpTransport, IngestTarget, buildHeaders };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.mts","names":[],"sources":["../../src/transport/http.ts"],"mappings":";;;UAUiB,YAAA;EACf,OAAA,EAAS,OAAA;EACT,GAAA;AAAA;AAAA,iBAGc,YAAA,CAAa,IAAA,EAAM,OAAA,GAAU,MAAA;AAAA,cA4BhC,aAAA;EAAA,iBACM,MAAA;EAAA,QACT,gBAAA;cAEI,MAAA,EAAQ,YAAA;EAId,IAAA,CAAK,SAAA,EAAW,QAAA,KAAa,OAAA;AAAA"}
@@ -0,0 +1,56 @@
1
+ import { createLogger } from "../util/log.mjs";
2
+ import { getVisitorId } from "../tracking/visitor.mjs";
3
+ import { session } from "../tracking/api.mjs";
4
+ import { make } from "tctx/traceparent";
5
+ //#region src/transport/http.ts
6
+ const log = createLogger("http");
7
+ function buildHeaders(base) {
8
+ const h = Object.fromEntries(base.entries());
9
+ h.traceparent = String(make());
10
+ const sessionId = session.getId();
11
+ if (sessionId) h["x-interfere-session"] = sessionId;
12
+ const visitorId = getVisitorId();
13
+ if (visitorId) h["x-interfere-visitor"] = visitorId;
14
+ return h;
15
+ }
16
+ function hasServiceWorker() {
17
+ return typeof navigator !== "undefined" && "serviceWorker" in navigator && navigator.serviceWorker.controller !== null;
18
+ }
19
+ const KEEPALIVE_BUDGET_BYTES = 61440;
20
+ const MAX_CONCURRENT_KEEPALIVE = 15;
21
+ var HttpTransport = class {
22
+ target;
23
+ pendingKeepalive = 0;
24
+ constructor(target) {
25
+ this.target = target;
26
+ }
27
+ async send(envelopes) {
28
+ const body = JSON.stringify(envelopes);
29
+ const headers = buildHeaders(this.target.headers);
30
+ if (hasServiceWorker()) {
31
+ log.debug("POST %d envelopes via SW", envelopes.length);
32
+ await fetch(this.target.url, {
33
+ method: "POST",
34
+ headers,
35
+ body
36
+ });
37
+ return;
38
+ }
39
+ const bytes = new TextEncoder().encode(body).byteLength;
40
+ const useKeepalive = bytes < KEEPALIVE_BUDGET_BYTES && this.pendingKeepalive < MAX_CONCURRENT_KEEPALIVE;
41
+ if (useKeepalive) this.pendingKeepalive++;
42
+ log.debug("POST %d envelopes direct (%d bytes, keepalive=%s)", envelopes.length, bytes, useKeepalive);
43
+ try {
44
+ await fetch(this.target.url, {
45
+ method: "POST",
46
+ headers,
47
+ body,
48
+ keepalive: useKeepalive
49
+ });
50
+ } finally {
51
+ if (useKeepalive) this.pendingKeepalive--;
52
+ }
53
+ }
54
+ };
55
+ //#endregion
56
+ export { HttpTransport, buildHeaders };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.mjs","names":[],"sources":["../../src/transport/http.ts"],"sourcesContent":["import type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport { make } from \"tctx/traceparent\";\n\nimport { session } from \"../tracking/api.js\";\nimport { getVisitorId } from \"../tracking/visitor.js\";\nimport { createLogger } from \"../util/log.js\";\n\nconst log = createLogger(\"http\");\n\nexport interface IngestTarget {\n headers: Headers;\n url: string;\n}\n\nexport function buildHeaders(base: Headers): Record<string, string> {\n const h: Record<string, string> = Object.fromEntries(base.entries());\n h.traceparent = String(make());\n\n const sessionId = session.getId();\n if (sessionId) {\n h[\"x-interfere-session\"] = sessionId;\n }\n\n const visitorId = getVisitorId();\n if (visitorId) {\n h[\"x-interfere-visitor\"] = visitorId;\n }\n\n return h;\n}\n\nfunction hasServiceWorker(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n \"serviceWorker\" in navigator &&\n navigator.serviceWorker.controller !== null\n );\n}\n\nconst KEEPALIVE_BUDGET_BYTES = 61_440;\nconst MAX_CONCURRENT_KEEPALIVE = 15;\n\nexport class HttpTransport {\n private readonly target: IngestTarget;\n private pendingKeepalive = 0;\n\n constructor(target: IngestTarget) {\n this.target = target;\n }\n\n async send(envelopes: Envelope[]): Promise<void> {\n const body = JSON.stringify(envelopes);\n const headers = buildHeaders(this.target.headers);\n\n if (hasServiceWorker()) {\n log.debug(\"POST %d envelopes via SW\", envelopes.length);\n await fetch(this.target.url, {\n method: \"POST\",\n headers,\n body,\n });\n return;\n }\n\n const bytes = new TextEncoder().encode(body).byteLength;\n const useKeepalive =\n bytes < KEEPALIVE_BUDGET_BYTES &&\n this.pendingKeepalive < MAX_CONCURRENT_KEEPALIVE;\n\n if (useKeepalive) {\n this.pendingKeepalive++;\n }\n\n log.debug(\n \"POST %d envelopes direct (%d bytes, keepalive=%s)\",\n envelopes.length,\n bytes,\n useKeepalive\n );\n\n try {\n await fetch(this.target.url, {\n method: \"POST\",\n headers,\n body,\n keepalive: useKeepalive,\n });\n } finally {\n if (useKeepalive) {\n this.pendingKeepalive--;\n }\n }\n }\n}\n"],"mappings":";;;;;AAQA,MAAM,MAAM,aAAa,OAAO;AAOhC,SAAgB,aAAa,MAAuC;CAClE,MAAM,IAA4B,OAAO,YAAY,KAAK,SAAS,CAAC;AACpE,GAAE,cAAc,OAAO,MAAM,CAAC;CAE9B,MAAM,YAAY,QAAQ,OAAO;AACjC,KAAI,UACF,GAAE,yBAAyB;CAG7B,MAAM,YAAY,cAAc;AAChC,KAAI,UACF,GAAE,yBAAyB;AAG7B,QAAO;;AAGT,SAAS,mBAA4B;AACnC,QACE,OAAO,cAAc,eACrB,mBAAmB,aACnB,UAAU,cAAc,eAAe;;AAI3C,MAAM,yBAAyB;AAC/B,MAAM,2BAA2B;AAEjC,IAAa,gBAAb,MAA2B;CACzB;CACA,mBAA2B;CAE3B,YAAY,QAAsB;AAChC,OAAK,SAAS;;CAGhB,MAAM,KAAK,WAAsC;EAC/C,MAAM,OAAO,KAAK,UAAU,UAAU;EACtC,MAAM,UAAU,aAAa,KAAK,OAAO,QAAQ;AAEjD,MAAI,kBAAkB,EAAE;AACtB,OAAI,MAAM,4BAA4B,UAAU,OAAO;AACvD,SAAM,MAAM,KAAK,OAAO,KAAK;IAC3B,QAAQ;IACR;IACA;IACD,CAAC;AACF;;EAGF,MAAM,QAAQ,IAAI,aAAa,CAAC,OAAO,KAAK,CAAC;EAC7C,MAAM,eACJ,QAAQ,0BACR,KAAK,mBAAmB;AAE1B,MAAI,aACF,MAAK;AAGP,MAAI,MACF,qDACA,UAAU,QACV,OACA,aACD;AAED,MAAI;AACF,SAAM,MAAM,KAAK,OAAO,KAAK;IAC3B,QAAQ;IACR;IACA;IACA,WAAW;IACZ,CAAC;YACM;AACR,OAAI,aACF,MAAK"}
@@ -0,0 +1,25 @@
1
+ import { HttpTransport } from "./http.mjs";
2
+ import { Envelope } from "@interfere/types/sdk/envelope";
3
+
4
+ //#region src/transport/queue.d.ts
5
+ interface QueueOptions {
6
+ batchMs?: number;
7
+ batchSize?: number;
8
+ transport: HttpTransport;
9
+ }
10
+ declare class BatchQueue {
11
+ private readonly buffer;
12
+ private timer;
13
+ private readonly batchSize;
14
+ private readonly batchMs;
15
+ private readonly transport;
16
+ constructor(opts: QueueOptions);
17
+ start(): void;
18
+ enqueue(envelope: Envelope): void;
19
+ flush(): void;
20
+ dispose(): void;
21
+ private readonly onVisibilityChange;
22
+ private readonly onBeforeUnload;
23
+ }
24
+ //#endregion
25
+ export { BatchQueue, QueueOptions };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.mts","names":[],"sources":["../../src/transport/queue.ts"],"mappings":";;;;UAUiB,YAAA;EACf,OAAA;EACA,SAAA;EACA,SAAA,EAAW,aAAA;AAAA;AAAA,cAGA,UAAA;EAAA,iBACM,MAAA;EAAA,QACT,KAAA;EAAA,iBACS,SAAA;EAAA,iBACA,OAAA;EAAA,iBACA,SAAA;cAEL,IAAA,EAAM,YAAA;EAMlB,KAAA,CAAA;EAeA,OAAA,CAAQ,QAAA,EAAU,QAAA;EAOlB,KAAA,CAAA;EAWA,OAAA,CAAA;EAAA,iBAiBiB,kBAAA;EAAA,iBAMA,cAAA;AAAA"}
@@ -0,0 +1,60 @@
1
+ import { createLogger } from "../util/log.mjs";
2
+ //#region src/transport/queue.ts
3
+ const log = createLogger("queue");
4
+ const DEFAULT_BATCH_SIZE = 10;
5
+ const DEFAULT_BATCH_MS = 250;
6
+ var BatchQueue = class {
7
+ buffer = [];
8
+ timer = null;
9
+ batchSize;
10
+ batchMs;
11
+ transport;
12
+ constructor(opts) {
13
+ this.batchSize = opts.batchSize ?? DEFAULT_BATCH_SIZE;
14
+ this.batchMs = opts.batchMs ?? DEFAULT_BATCH_MS;
15
+ this.transport = opts.transport;
16
+ }
17
+ start() {
18
+ if (this.timer) return;
19
+ this.timer = setInterval(() => {
20
+ this.flush();
21
+ }, this.batchMs);
22
+ if (typeof globalThis.addEventListener === "function") {
23
+ globalThis.addEventListener("visibilitychange", this.onVisibilityChange);
24
+ globalThis.addEventListener("beforeunload", this.onBeforeUnload);
25
+ }
26
+ }
27
+ enqueue(envelope) {
28
+ this.buffer.push(envelope);
29
+ if (this.buffer.length >= this.batchSize) this.flush();
30
+ }
31
+ flush() {
32
+ while (this.buffer.length > 0) {
33
+ const batch = this.buffer.splice(0, this.batchSize);
34
+ log.debug("flushing %d envelopes", batch.length);
35
+ this.transport.send(batch).catch(() => {
36
+ log.warn("send failed, re-queuing %d envelopes", batch.length);
37
+ this.buffer.unshift(...batch);
38
+ });
39
+ }
40
+ }
41
+ dispose() {
42
+ if (this.timer) {
43
+ clearInterval(this.timer);
44
+ this.timer = null;
45
+ }
46
+ if (typeof globalThis.removeEventListener === "function") {
47
+ globalThis.removeEventListener("visibilitychange", this.onVisibilityChange);
48
+ globalThis.removeEventListener("beforeunload", this.onBeforeUnload);
49
+ }
50
+ this.flush();
51
+ }
52
+ onVisibilityChange = () => {
53
+ if (document.visibilityState === "hidden") this.flush();
54
+ };
55
+ onBeforeUnload = () => {
56
+ this.flush();
57
+ };
58
+ };
59
+ //#endregion
60
+ export { BatchQueue };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.mjs","names":[],"sources":["../../src/transport/queue.ts"],"sourcesContent":["import type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport { createLogger } from \"../util/log.js\";\nimport type { HttpTransport } from \"./http.js\";\n\nconst log = createLogger(\"queue\");\n\nconst DEFAULT_BATCH_SIZE = 10;\nconst DEFAULT_BATCH_MS = 250;\n\nexport interface QueueOptions {\n batchMs?: number;\n batchSize?: number;\n transport: HttpTransport;\n}\n\nexport class BatchQueue {\n private readonly buffer: Envelope[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly batchSize: number;\n private readonly batchMs: number;\n private readonly transport: HttpTransport;\n\n constructor(opts: QueueOptions) {\n this.batchSize = opts.batchSize ?? DEFAULT_BATCH_SIZE;\n this.batchMs = opts.batchMs ?? DEFAULT_BATCH_MS;\n this.transport = opts.transport;\n }\n\n start(): void {\n if (this.timer) {\n return;\n }\n\n this.timer = setInterval(() => {\n this.flush();\n }, this.batchMs);\n\n if (typeof globalThis.addEventListener === \"function\") {\n globalThis.addEventListener(\"visibilitychange\", this.onVisibilityChange);\n globalThis.addEventListener(\"beforeunload\", this.onBeforeUnload);\n }\n }\n\n enqueue(envelope: Envelope): void {\n this.buffer.push(envelope);\n if (this.buffer.length >= this.batchSize) {\n this.flush();\n }\n }\n\n flush(): void {\n while (this.buffer.length > 0) {\n const batch = this.buffer.splice(0, this.batchSize);\n log.debug(\"flushing %d envelopes\", batch.length);\n this.transport.send(batch).catch(() => {\n log.warn(\"send failed, re-queuing %d envelopes\", batch.length);\n this.buffer.unshift(...batch);\n });\n }\n }\n\n dispose(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n\n if (typeof globalThis.removeEventListener === \"function\") {\n globalThis.removeEventListener(\n \"visibilitychange\",\n this.onVisibilityChange\n );\n globalThis.removeEventListener(\"beforeunload\", this.onBeforeUnload);\n }\n\n this.flush();\n }\n\n private readonly onVisibilityChange = (): void => {\n if (document.visibilityState === \"hidden\") {\n this.flush();\n }\n };\n\n private readonly onBeforeUnload = (): void => {\n this.flush();\n };\n}\n"],"mappings":";;AAKA,MAAM,MAAM,aAAa,QAAQ;AAEjC,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;AAQzB,IAAa,aAAb,MAAwB;CACtB,SAAsC,EAAE;CACxC,QAAuD;CACvD;CACA;CACA;CAEA,YAAY,MAAoB;AAC9B,OAAK,YAAY,KAAK,aAAa;AACnC,OAAK,UAAU,KAAK,WAAW;AAC/B,OAAK,YAAY,KAAK;;CAGxB,QAAc;AACZ,MAAI,KAAK,MACP;AAGF,OAAK,QAAQ,kBAAkB;AAC7B,QAAK,OAAO;KACX,KAAK,QAAQ;AAEhB,MAAI,OAAO,WAAW,qBAAqB,YAAY;AACrD,cAAW,iBAAiB,oBAAoB,KAAK,mBAAmB;AACxE,cAAW,iBAAiB,gBAAgB,KAAK,eAAe;;;CAIpE,QAAQ,UAA0B;AAChC,OAAK,OAAO,KAAK,SAAS;AAC1B,MAAI,KAAK,OAAO,UAAU,KAAK,UAC7B,MAAK,OAAO;;CAIhB,QAAc;AACZ,SAAO,KAAK,OAAO,SAAS,GAAG;GAC7B,MAAM,QAAQ,KAAK,OAAO,OAAO,GAAG,KAAK,UAAU;AACnD,OAAI,MAAM,yBAAyB,MAAM,OAAO;AAChD,QAAK,UAAU,KAAK,MAAM,CAAC,YAAY;AACrC,QAAI,KAAK,wCAAwC,MAAM,OAAO;AAC9D,SAAK,OAAO,QAAQ,GAAG,MAAM;KAC7B;;;CAIN,UAAgB;AACd,MAAI,KAAK,OAAO;AACd,iBAAc,KAAK,MAAM;AACzB,QAAK,QAAQ;;AAGf,MAAI,OAAO,WAAW,wBAAwB,YAAY;AACxD,cAAW,oBACT,oBACA,KAAK,mBACN;AACD,cAAW,oBAAoB,gBAAgB,KAAK,eAAe;;AAGrE,OAAK,OAAO;;CAGd,2BAAkD;AAChD,MAAI,SAAS,oBAAoB,SAC/B,MAAK,OAAO;;CAIhB,uBAA8C;AAC5C,OAAK,OAAO"}
@@ -0,0 +1,13 @@
1
+ //#region src/util/log.d.ts
2
+ type LogLevel = "debug" | "info" | "warn" | "error" | "none";
3
+ declare function setLogLevel(level: LogLevel): void;
4
+ declare function getLogLevel(): LogLevel;
5
+ interface Logger {
6
+ debug(...args: unknown[]): void;
7
+ error(...args: unknown[]): void;
8
+ info(...args: unknown[]): void;
9
+ warn(...args: unknown[]): void;
10
+ }
11
+ declare function createLogger(scope: string): Logger;
12
+ //#endregion
13
+ export { LogLevel, Logger, createLogger, getLogLevel, setLogLevel };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.mts","names":[],"sources":["../../src/util/log.ts"],"mappings":";KAAY,QAAA;AAAA,iBAsBI,WAAA,CAAY,KAAA,EAAO,QAAA;AAAA,iBAInB,WAAA,CAAA,GAAe,QAAA;AAAA,UAKd,MAAA;EACf,KAAA,IAAS,IAAA;EACT,KAAA,IAAS,IAAA;EACT,IAAA,IAAQ,IAAA;EACR,IAAA,IAAQ,IAAA;AAAA;AAAA,iBAeM,YAAA,CAAa,KAAA,WAAgB,MAAA"}
@@ -0,0 +1,37 @@
1
+ //#region src/util/log.ts
2
+ const PRIORITY = {
3
+ debug: 0,
4
+ info: 1,
5
+ warn: 2,
6
+ error: 3,
7
+ none: 4
8
+ };
9
+ const CONSOLE_FN = {
10
+ debug: "debug",
11
+ info: "info",
12
+ warn: "warn",
13
+ error: "error"
14
+ };
15
+ let threshold = PRIORITY.warn;
16
+ function setLogLevel(level) {
17
+ threshold = PRIORITY[level];
18
+ }
19
+ function getLogLevel() {
20
+ return Object.entries(PRIORITY).find(([, v]) => v === threshold)?.[0] ?? "warn";
21
+ }
22
+ function emit(level, prefix, args) {
23
+ if (PRIORITY[level] < threshold) return;
24
+ const fn = CONSOLE_FN[level];
25
+ globalThis.console[fn](prefix, ...args);
26
+ }
27
+ function createLogger(scope) {
28
+ const prefix = `[Interfere:${scope}]`;
29
+ return {
30
+ debug: (...args) => emit("debug", prefix, args),
31
+ info: (...args) => emit("info", prefix, args),
32
+ warn: (...args) => emit("warn", prefix, args),
33
+ error: (...args) => emit("error", prefix, args)
34
+ };
35
+ }
36
+ //#endregion
37
+ export { createLogger, getLogLevel, setLogLevel };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.mjs","names":[],"sources":["../../src/util/log.ts"],"sourcesContent":["export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\nconst PRIORITY: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n};\n\nconst CONSOLE_FN: Record<\n Exclude<LogLevel, \"none\">,\n \"debug\" | \"info\" | \"warn\" | \"error\"\n> = {\n debug: \"debug\",\n info: \"info\",\n warn: \"warn\",\n error: \"error\",\n};\n\nlet threshold = PRIORITY.warn;\n\nexport function setLogLevel(level: LogLevel): void {\n threshold = PRIORITY[level];\n}\n\nexport function getLogLevel(): LogLevel {\n const entry = Object.entries(PRIORITY).find(([, v]) => v === threshold);\n return (entry?.[0] ?? \"warn\") as LogLevel;\n}\n\nexport interface Logger {\n debug(...args: unknown[]): void;\n error(...args: unknown[]): void;\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n}\n\nfunction emit(\n level: Exclude<LogLevel, \"none\">,\n prefix: string,\n args: unknown[]\n): void {\n if (PRIORITY[level] < threshold) {\n return;\n }\n const fn = CONSOLE_FN[level];\n globalThis.console[fn](prefix, ...args);\n}\n\nexport function createLogger(scope: string): Logger {\n const prefix = `[Interfere:${scope}]`;\n return {\n debug: (...args) => emit(\"debug\", prefix, args),\n info: (...args) => emit(\"info\", prefix, args),\n warn: (...args) => emit(\"warn\", prefix, args),\n error: (...args) => emit(\"error\", prefix, args),\n };\n}\n"],"mappings":";AAEA,MAAM,WAAqC;CACzC,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP,MAAM;CACP;AAED,MAAM,aAGF;CACF,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR;AAED,IAAI,YAAY,SAAS;AAEzB,SAAgB,YAAY,OAAuB;AACjD,aAAY,SAAS;;AAGvB,SAAgB,cAAwB;AAEtC,QADc,OAAO,QAAQ,SAAS,CAAC,MAAM,GAAG,OAAO,MAAM,UAAU,GACvD,MAAM;;AAUxB,SAAS,KACP,OACA,QACA,MACM;AACN,KAAI,SAAS,SAAS,UACpB;CAEF,MAAM,KAAK,WAAW;AACtB,YAAW,QAAQ,IAAI,QAAQ,GAAG,KAAK;;AAGzC,SAAgB,aAAa,OAAuB;CAClD,MAAM,SAAS,cAAc,MAAM;AACnC,QAAO;EACL,QAAQ,GAAG,SAAS,KAAK,SAAS,QAAQ,KAAK;EAC/C,OAAO,GAAG,SAAS,KAAK,QAAQ,QAAQ,KAAK;EAC7C,OAAO,GAAG,SAAS,KAAK,QAAQ,QAAQ,KAAK;EAC7C,QAAQ,GAAG,SAAS,KAAK,SAAS,QAAQ,KAAK;EAChD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interfere/react",
3
- "version": "1.0.0-alpha.7",
3
+ "version": "1.0.1",
4
4
  "license": "MIT",
5
5
  "description": "Client-side React SDK for Interfere. Error tracking, session replay, and analytics.",
6
6
  "keywords": [