@interfere/react 0.1.0-alpha.0 → 0.1.0-alpha.25

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.
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { capture } from "./internal/client.mjs";
3
2
  import { seen } from "./internal/errors.mjs";
3
+ import { capture } from "./internal/client.mjs";
4
4
  import { toExceptions } from "@interfere/types/sdk/errors";
5
5
  import { Component } from "react";
6
6
  //#region src/error-boundary.tsx
@@ -3,11 +3,9 @@ import { EnvelopePayload, EventType } from "@interfere/types/sdk/envelope";
3
3
 
4
4
  //#region src/internal/client.d.ts
5
5
  interface ClientOptions {
6
- buildId?: string | null;
7
6
  plugins?: PluginOverrides;
8
- releaseId?: string | null;
9
7
  }
10
- declare function init(opts?: ClientOptions): Promise<void>;
8
+ declare function init(opts?: ClientOptions): void;
11
9
  declare function capture<T extends EventType>(type: T, payload: EnvelopePayload<T>): void;
12
10
  declare function flush(): void;
13
11
  declare function close(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.mts","names":[],"sources":["../../src/internal/client.ts"],"mappings":";;;;UAgBiB,aAAA;EACf,OAAA;EACA,OAAA,GAAU,eAAA;EACV,SAAA;AAAA;AAAA,iBAQoB,IAAA,CAAK,IAAA,GAAM,aAAA,GAAqB,OAAA;AAAA,iBAqCtC,OAAA,WAAkB,SAAA,CAAA,CAChC,IAAA,EAAM,CAAA,EACN,OAAA,EAAS,eAAA,CAAgB,CAAA;AAAA,iBAeX,KAAA,CAAA;AAAA,iBAIA,KAAA,CAAA"}
1
+ {"version":3,"file":"client.d.mts","names":[],"sources":["../../src/internal/client.ts"],"mappings":";;;;UAiBiB,aAAA;EACf,OAAA,GAAU,eAAA;AAAA;AAAA,iBAQI,IAAA,CAAK,IAAA,GAAM,aAAA;AAAA,iBA0DX,OAAA,WAAkB,SAAA,CAAA,CAChC,IAAA,EAAM,CAAA,EACN,OAAA,EAAS,eAAA,CAAgB,CAAA;AAAA,iBAeX,KAAA,CAAA;AAAA,iBAIA,KAAA,CAAA"}
@@ -1,3 +1,4 @@
1
+ import errorsPlugin from "../plugins/errors.mjs";
1
2
  import { createLogger } from "../util/log.mjs";
2
3
  import { loadPlugins } from "../plugins/lib/loader.mjs";
3
4
  import { bootstrap, session, teardown } from "../tracking/api.mjs";
@@ -14,27 +15,42 @@ let state = "idle";
14
15
  let queue = null;
15
16
  let metadata = null;
16
17
  let cleanups = [];
17
- async function init(opts = {}) {
18
+ function init(opts = {}) {
18
19
  if (state !== "idle") return;
19
- state = "initializing";
20
+ const buildId = globalThis.__INTERFERE_BUILD_ID__;
21
+ const releaseId = globalThis.__INTERFERE_RELEASE_ID__;
22
+ if (!buildId) {
23
+ log.error("buildId not found — ensure withInterfere() is configured in next.config and instrumentation-client.ts exists in your project root.");
24
+ return;
25
+ }
20
26
  const targets = resolveTargets();
21
27
  bootstrap(targets.session, opts.plugins);
28
+ log.info("target: %s", targets.ingest.url);
22
29
  metadata = {
23
- context: await collectContext(),
30
+ context: collectContext(),
24
31
  environment: normalizeEnv(typeof process !== "undefined" ? process.env.NODE_ENV : void 0),
25
32
  runtime: inferRuntime(),
26
- buildId: opts.buildId ?? null,
27
- releaseId: opts.releaseId ?? null
33
+ buildId,
34
+ releaseId: releaseId ?? null
28
35
  };
29
36
  registerServiceWorker();
30
37
  queue = new BatchQueue({ transport: new HttpTransport(targets.ingest) });
31
38
  queue.start();
32
- cleanups = await loadPlugins(opts.plugins, {
39
+ const pluginCtx = {
33
40
  capture: (type, payload) => capture(type, payload),
34
41
  getSessionId: () => session.getId() ?? ""
35
- });
42
+ };
43
+ const errorCleanup = errorsPlugin.setup(pluginCtx);
44
+ cleanups = errorCleanup ? [errorCleanup] : [];
36
45
  state = "ready";
37
- log.info("initialized (plugins=%d)", cleanups.length);
46
+ loadPlugins({
47
+ ...opts.plugins,
48
+ errors: false
49
+ }, pluginCtx).then((c) => {
50
+ cleanups.push(...c);
51
+ }).catch(() => {
52
+ log.warn("non-critical plugin loading failed");
53
+ });
38
54
  }
39
55
  function capture(type, payload) {
40
56
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"client.mjs","names":[],"sources":["../../src/internal/client.ts"],"sourcesContent":["import type { EnvelopePayload, EventType } from \"@interfere/types/sdk/envelope\";\nimport { inferRuntime, normalizeEnv } from \"@interfere/types/sdk/runtime\";\n\nimport { loadPlugins, type PluginOverrides } from \"../plugins/lib/loader.js\";\nimport type { PluginCleanup, PluginContext } from \"../plugins/lib/types.js\";\nimport { bootstrap, session, teardown } from \"../tracking/api.js\";\nimport { HttpTransport } from \"../transport/http.js\";\nimport { BatchQueue } from \"../transport/queue.js\";\nimport { createLogger } from \"../util/log.js\";\nimport { resolveTargets } from \"./config.js\";\nimport { collectContext } from \"./context.js\";\nimport { buildEnvelope, type EnvelopeMetadata } from \"./envelope.js\";\nimport { registerServiceWorker } from \"./sw.js\";\n\nconst log = createLogger(\"client\");\n\nexport interface ClientOptions {\n buildId?: string | null;\n plugins?: PluginOverrides;\n releaseId?: string | null;\n}\n\nlet state: \"idle\" | \"initializing\" | \"ready\" | \"closed\" = \"idle\";\nlet queue: BatchQueue | null = null;\nlet metadata: EnvelopeMetadata | null = null;\nlet cleanups: PluginCleanup[] = [];\n\nexport async function init(opts: ClientOptions = {}): Promise<void> {\n if (state !== \"idle\") {\n return;\n }\n state = \"initializing\";\n\n const targets = resolveTargets();\n bootstrap(targets.session, opts.plugins);\n\n const context = await collectContext();\n\n metadata = {\n context,\n environment: normalizeEnv(\n typeof process !== \"undefined\" ? process.env.NODE_ENV : undefined\n ),\n runtime: inferRuntime(),\n buildId: opts.buildId ?? null,\n releaseId: opts.releaseId ?? null,\n };\n\n registerServiceWorker();\n\n const transport = new HttpTransport(targets.ingest);\n queue = new BatchQueue({ transport });\n queue.start();\n\n const pluginCtx: PluginContext = {\n capture: (type, payload) => capture(type, payload),\n getSessionId: () => session.getId() ?? \"\",\n };\n\n cleanups = await loadPlugins(opts.plugins, pluginCtx);\n state = \"ready\";\n log.info(\"initialized (plugins=%d)\", cleanups.length);\n}\n\nexport function capture<T extends EventType>(\n type: T,\n payload: EnvelopePayload<T>\n): void {\n try {\n const sessionId = session.getId();\n\n if (state !== \"ready\" || !sessionId || !queue || !metadata) {\n return;\n }\n\n queue.enqueue(buildEnvelope(type, payload, sessionId, metadata));\n } catch (err) {\n log.warn(\"capture failed\", err);\n }\n}\n\nexport function flush(): void {\n queue?.flush();\n}\n\nexport function close(): void {\n if (state === \"closed\") {\n return;\n }\n state = \"closed\";\n\n for (const cleanup of cleanups) {\n try {\n cleanup();\n } catch {\n /* best-effort */\n }\n }\n cleanups = [];\n teardown();\n\n queue?.dispose();\n queue = null;\n metadata = null;\n}\n"],"mappings":";;;;;;;;;;;AAcA,MAAM,MAAM,aAAa,SAAS;AAQlC,IAAI,QAAsD;AAC1D,IAAI,QAA2B;AAC/B,IAAI,WAAoC;AACxC,IAAI,WAA4B,EAAE;AAElC,eAAsB,KAAK,OAAsB,EAAE,EAAiB;AAClE,KAAI,UAAU,OACZ;AAEF,SAAQ;CAER,MAAM,UAAU,gBAAgB;AAChC,WAAU,QAAQ,SAAS,KAAK,QAAQ;AAIxC,YAAW;EACT,SAHc,MAAM,gBAAgB;EAIpC,aAAa,aACX,OAAO,YAAY,cAAc,QAAQ,IAAI,WAAW,KAAA,EACzD;EACD,SAAS,cAAc;EACvB,SAAS,KAAK,WAAW;EACzB,WAAW,KAAK,aAAa;EAC9B;AAED,wBAAuB;AAGvB,SAAQ,IAAI,WAAW,EAAE,WADP,IAAI,cAAc,QAAQ,OAAO,EACf,CAAC;AACrC,OAAM,OAAO;AAOb,YAAW,MAAM,YAAY,KAAK,SALD;EAC/B,UAAU,MAAM,YAAY,QAAQ,MAAM,QAAQ;EAClD,oBAAoB,QAAQ,OAAO,IAAI;EACxC,CAEoD;AACrD,SAAQ;AACR,KAAI,KAAK,4BAA4B,SAAS,OAAO;;AAGvD,SAAgB,QACd,MACA,SACM;AACN,KAAI;EACF,MAAM,YAAY,QAAQ,OAAO;AAEjC,MAAI,UAAU,WAAW,CAAC,aAAa,CAAC,SAAS,CAAC,SAChD;AAGF,QAAM,QAAQ,cAAc,MAAM,SAAS,WAAW,SAAS,CAAC;UACzD,KAAK;AACZ,MAAI,KAAK,kBAAkB,IAAI;;;AAInC,SAAgB,QAAc;AAC5B,QAAO,OAAO;;AAGhB,SAAgB,QAAc;AAC5B,KAAI,UAAU,SACZ;AAEF,SAAQ;AAER,MAAK,MAAM,WAAW,SACpB,KAAI;AACF,WAAS;SACH;AAIV,YAAW,EAAE;AACb,WAAU;AAEV,QAAO,SAAS;AAChB,SAAQ;AACR,YAAW"}
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../../src/internal/client.ts"],"sourcesContent":["import type { EnvelopePayload, EventType } from \"@interfere/types/sdk/envelope\";\nimport { inferRuntime, normalizeEnv } from \"@interfere/types/sdk/runtime\";\n\nimport errorsPlugin from \"../plugins/errors.js\";\nimport { loadPlugins, type PluginOverrides } from \"../plugins/lib/loader.js\";\nimport type { PluginCleanup, PluginContext } from \"../plugins/lib/types.js\";\nimport { bootstrap, session, teardown } from \"../tracking/api.js\";\nimport { HttpTransport } from \"../transport/http.js\";\nimport { BatchQueue } from \"../transport/queue.js\";\nimport { createLogger } from \"../util/log.js\";\nimport { resolveTargets } from \"./config.js\";\nimport { collectContext } from \"./context.js\";\nimport { buildEnvelope, type EnvelopeMetadata } from \"./envelope.js\";\nimport { registerServiceWorker } from \"./sw.js\";\n\nconst log = createLogger(\"client\");\n\nexport interface ClientOptions {\n plugins?: PluginOverrides;\n}\n\nlet state: \"idle\" | \"ready\" | \"closed\" = \"idle\";\nlet queue: BatchQueue | null = null;\nlet metadata: EnvelopeMetadata | null = null;\nlet cleanups: PluginCleanup[] = [];\n\nexport function init(opts: ClientOptions = {}): void {\n if (state !== \"idle\") {\n return;\n }\n\n const buildId = (globalThis as Record<string, unknown>)\n .__INTERFERE_BUILD_ID__ as string | undefined;\n\n const releaseId = (globalThis as Record<string, unknown>)\n .__INTERFERE_RELEASE_ID__ as string | null | undefined;\n\n if (!buildId) {\n log.error(\n \"buildId not found — ensure withInterfere() is configured in \" +\n \"next.config and instrumentation-client.ts exists in your project root.\"\n );\n return;\n }\n\n const targets = resolveTargets();\n bootstrap(targets.session, opts.plugins);\n\n log.info(\"target: %s\", targets.ingest.url);\n\n metadata = {\n context: collectContext(),\n environment: normalizeEnv(\n typeof process !== \"undefined\" ? process.env.NODE_ENV : undefined\n ),\n runtime: inferRuntime(),\n buildId,\n releaseId: releaseId ?? null,\n };\n\n registerServiceWorker();\n\n const transport = new HttpTransport(targets.ingest);\n queue = new BatchQueue({ transport });\n queue.start();\n\n const pluginCtx: PluginContext = {\n capture: (type, payload) => capture(type, payload),\n getSessionId: () => session.getId() ?? \"\",\n };\n\n const errorCleanup = errorsPlugin.setup(pluginCtx);\n cleanups = errorCleanup ? [errorCleanup] : [];\n state = \"ready\";\n\n loadPlugins({ ...opts.plugins, errors: false }, pluginCtx)\n .then((c) => {\n cleanups.push(...c);\n })\n .catch(() => {\n log.warn(\"non-critical plugin loading failed\");\n });\n}\n\nexport function capture<T extends EventType>(\n type: T,\n payload: EnvelopePayload<T>\n): void {\n try {\n const sessionId = session.getId();\n\n if (state !== \"ready\" || !sessionId || !queue || !metadata) {\n return;\n }\n\n queue.enqueue(buildEnvelope(type, payload, sessionId, metadata));\n } catch (err) {\n log.warn(\"capture failed\", err);\n }\n}\n\nexport function flush(): void {\n queue?.flush();\n}\n\nexport function close(): void {\n if (state === \"closed\") {\n return;\n }\n state = \"closed\";\n\n for (const cleanup of cleanups) {\n try {\n cleanup();\n } catch {\n /* best-effort */\n }\n }\n cleanups = [];\n teardown();\n\n queue?.dispose();\n queue = null;\n metadata = null;\n}\n"],"mappings":";;;;;;;;;;;;AAeA,MAAM,MAAM,aAAa,SAAS;AAMlC,IAAI,QAAqC;AACzC,IAAI,QAA2B;AAC/B,IAAI,WAAoC;AACxC,IAAI,WAA4B,EAAE;AAElC,SAAgB,KAAK,OAAsB,EAAE,EAAQ;AACnD,KAAI,UAAU,OACZ;CAGF,MAAM,UAAW,WACd;CAEH,MAAM,YAAa,WAChB;AAEH,KAAI,CAAC,SAAS;AACZ,MAAI,MACF,qIAED;AACD;;CAGF,MAAM,UAAU,gBAAgB;AAChC,WAAU,QAAQ,SAAS,KAAK,QAAQ;AAExC,KAAI,KAAK,cAAc,QAAQ,OAAO,IAAI;AAE1C,YAAW;EACT,SAAS,gBAAgB;EACzB,aAAa,aACX,OAAO,YAAY,cAAc,QAAQ,IAAI,WAAW,KAAA,EACzD;EACD,SAAS,cAAc;EACvB;EACA,WAAW,aAAa;EACzB;AAED,wBAAuB;AAGvB,SAAQ,IAAI,WAAW,EAAE,WADP,IAAI,cAAc,QAAQ,OAAO,EACf,CAAC;AACrC,OAAM,OAAO;CAEb,MAAM,YAA2B;EAC/B,UAAU,MAAM,YAAY,QAAQ,MAAM,QAAQ;EAClD,oBAAoB,QAAQ,OAAO,IAAI;EACxC;CAED,MAAM,eAAe,aAAa,MAAM,UAAU;AAClD,YAAW,eAAe,CAAC,aAAa,GAAG,EAAE;AAC7C,SAAQ;AAER,aAAY;EAAE,GAAG,KAAK;EAAS,QAAQ;EAAO,EAAE,UAAU,CACvD,MAAM,MAAM;AACX,WAAS,KAAK,GAAG,EAAE;GACnB,CACD,YAAY;AACX,MAAI,KAAK,qCAAqC;GAC9C;;AAGN,SAAgB,QACd,MACA,SACM;AACN,KAAI;EACF,MAAM,YAAY,QAAQ,OAAO;AAEjC,MAAI,UAAU,WAAW,CAAC,aAAa,CAAC,SAAS,CAAC,SAChD;AAGF,QAAM,QAAQ,cAAc,MAAM,SAAS,WAAW,SAAS,CAAC;UACzD,KAAK;AACZ,MAAI,KAAK,kBAAkB,IAAI;;;AAInC,SAAgB,QAAc;AAC5B,QAAO,OAAO;;AAGhB,SAAgB,QAAc;AAC5B,KAAI,UAAU,SACZ;AAEF,SAAQ;AAER,MAAK,MAAM,WAAW,SACpB,KAAI;AACF,WAAS;SACH;AAIV,YAAW,EAAE;AACb,WAAU;AAEV,QAAO,SAAS;AAChB,SAAQ;AACR,YAAW"}
@@ -1,6 +1,6 @@
1
1
  import { BrowserContext } from "@interfere/types/sdk/plugins/context/browser";
2
2
 
3
3
  //#region src/internal/context.d.ts
4
- declare function collectContext(): Promise<BrowserContext>;
4
+ declare function collectContext(): BrowserContext;
5
5
  //#endregion
6
6
  export { collectContext };
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.mts","names":[],"sources":["../../src/internal/context.ts"],"mappings":";;;iBAsDsB,cAAA,CAAA,GAAkB,OAAA,CAAQ,cAAA"}
1
+ {"version":3,"file":"context.d.mts","names":[],"sources":["../../src/internal/context.ts"],"mappings":";;;iBAwCgB,cAAA,CAAA,GAAkB,cAAA"}
@@ -1,13 +1,8 @@
1
1
  import { UAParser } from "@ua-parser-js/pro-enterprise";
2
2
  //#region src/internal/context.ts
3
- let cachedUa = null;
4
- async function getDeviceMetadata() {
5
- if (cachedUa) return cachedUa;
3
+ function getDeviceMetadata() {
6
4
  if (typeof navigator === "undefined") return null;
7
- const result = UAParser(navigator.userAgent);
8
- if (!result) return null;
9
- cachedUa = await result.withClientHints();
10
- return cachedUa;
5
+ return UAParser(navigator.userAgent) ?? null;
11
6
  }
12
7
  function getBrowserMetadata() {
13
8
  if ([
@@ -22,16 +17,15 @@ function getBrowserMetadata() {
22
17
  display: { screen: {
23
18
  height: screen.availHeight,
24
19
  width: screen.availWidth,
25
- orientation: screen.orientation.type
20
+ orientation: screen.orientation?.type
26
21
  } }
27
22
  };
28
23
  }
29
- async function collectContext() {
30
- const device = await getDeviceMetadata();
24
+ function collectContext() {
31
25
  return {
32
26
  runtime: "browser",
33
27
  browser: getBrowserMetadata(),
34
- device
28
+ device: getDeviceMetadata()
35
29
  };
36
30
  }
37
31
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"context.mjs","names":[],"sources":["../../src/internal/context.ts"],"sourcesContent":["import type {\n BrowserContext,\n BrowserMetadata,\n DeviceMetadata,\n} from \"@interfere/types/sdk/plugins/context/browser\";\n\nimport { UAParser } from \"@ua-parser-js/pro-enterprise\";\n\nlet cachedUa: DeviceMetadata | null = null;\n\nasync function getDeviceMetadata(): Promise<DeviceMetadata | null> {\n if (cachedUa) {\n return cachedUa;\n }\n\n if (typeof navigator === \"undefined\") {\n return null;\n }\n\n const result = UAParser(navigator.userAgent);\n\n if (!result) {\n return null;\n }\n\n cachedUa = await result.withClientHints();\n\n return cachedUa;\n}\n\nfunction getBrowserMetadata(): BrowserMetadata | null {\n if (\n [typeof navigator, typeof screen, typeof globalThis].some(\n (x) => x === \"undefined\"\n )\n ) {\n return null;\n }\n\n const { language } = navigator;\n\n return {\n language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n display: {\n screen: {\n height: screen.availHeight,\n width: screen.availWidth,\n orientation: screen.orientation.type,\n },\n },\n };\n}\n\nexport async function collectContext(): Promise<BrowserContext> {\n const device = await getDeviceMetadata();\n const browser = getBrowserMetadata();\n\n return {\n runtime: \"browser\",\n browser,\n device,\n };\n}\n"],"mappings":";;AAQA,IAAI,WAAkC;AAEtC,eAAe,oBAAoD;AACjE,KAAI,SACF,QAAO;AAGT,KAAI,OAAO,cAAc,YACvB,QAAO;CAGT,MAAM,SAAS,SAAS,UAAU,UAAU;AAE5C,KAAI,CAAC,OACH,QAAO;AAGT,YAAW,MAAM,OAAO,iBAAiB;AAEzC,QAAO;;AAGT,SAAS,qBAA6C;AACpD,KACE;EAAC,OAAO;EAAW,OAAO;EAAQ,OAAO;EAAW,CAAC,MAClD,MAAM,MAAM,YACd,CAED,QAAO;CAGT,MAAM,EAAE,aAAa;AAErB,QAAO;EACL;EACA,UAAU,KAAK,gBAAgB,CAAC,iBAAiB,CAAC;EAClD,SAAS,EACP,QAAQ;GACN,QAAQ,OAAO;GACf,OAAO,OAAO;GACd,aAAa,OAAO,YAAY;GACjC,EACF;EACF;;AAGH,eAAsB,iBAA0C;CAC9D,MAAM,SAAS,MAAM,mBAAmB;AAGxC,QAAO;EACL,SAAS;EACT,SAJc,oBAAoB;EAKlC;EACD"}
1
+ {"version":3,"file":"context.mjs","names":[],"sources":["../../src/internal/context.ts"],"sourcesContent":["import type {\n BrowserContext,\n BrowserMetadata,\n DeviceMetadata,\n} from \"@interfere/types/sdk/plugins/context/browser\";\n\nimport { UAParser } from \"@ua-parser-js/pro-enterprise\";\n\nfunction getDeviceMetadata(): DeviceMetadata | null {\n if (typeof navigator === \"undefined\") {\n return null;\n }\n\n return UAParser(navigator.userAgent) ?? null;\n}\n\nfunction getBrowserMetadata(): BrowserMetadata | null {\n if (\n [typeof navigator, typeof screen, typeof globalThis].some(\n (x) => x === \"undefined\"\n )\n ) {\n return null;\n }\n\n const { language } = navigator;\n\n return {\n language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n display: {\n screen: {\n height: screen.availHeight,\n width: screen.availWidth,\n orientation: screen.orientation?.type,\n },\n },\n };\n}\n\nexport function collectContext(): BrowserContext {\n return {\n runtime: \"browser\",\n browser: getBrowserMetadata(),\n device: getDeviceMetadata(),\n };\n}\n"],"mappings":";;AAQA,SAAS,oBAA2C;AAClD,KAAI,OAAO,cAAc,YACvB,QAAO;AAGT,QAAO,SAAS,UAAU,UAAU,IAAI;;AAG1C,SAAS,qBAA6C;AACpD,KACE;EAAC,OAAO;EAAW,OAAO;EAAQ,OAAO;EAAW,CAAC,MAClD,MAAM,MAAM,YACd,CAED,QAAO;CAGT,MAAM,EAAE,aAAa;AAErB,QAAO;EACL;EACA,UAAU,KAAK,gBAAgB,CAAC,iBAAiB,CAAC;EAClD,SAAS,EACP,QAAQ;GACN,QAAQ,OAAO;GACf,OAAO,OAAO;GACd,aAAa,OAAO,aAAa;GAClC,EACF;EACF;;AAGH,SAAgB,iBAAiC;AAC/C,QAAO;EACL,SAAS;EACT,SAAS,oBAAoB;EAC7B,QAAQ,mBAAmB;EAC5B"}
@@ -3,7 +3,7 @@ import { Envelope, EnvelopeContext, EnvelopePayload, EventType } from "@interfer
3
3
 
4
4
  //#region src/internal/envelope.d.ts
5
5
  interface EnvelopeMetadata {
6
- buildId: string | null;
6
+ buildId: string;
7
7
  context: EnvelopeContext;
8
8
  environment: Env;
9
9
  releaseId: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.mjs","names":["uuidv7"],"sources":["../../src/internal/envelope.ts"],"sourcesContent":["import type {\n Envelope,\n EnvelopeContext,\n EnvelopePayload,\n EventType,\n} from \"@interfere/types/sdk/envelope\";\nimport type { Env, Runtime } from \"@interfere/types/sdk/runtime\";\n\nimport { v7 as uuidv7 } from \"uuid\";\n\nexport interface EnvelopeMetadata {\n buildId: string | null;\n context: EnvelopeContext;\n environment: Env;\n releaseId: string | null;\n runtime: Runtime;\n}\n\nexport function buildEnvelope<T extends EventType>(\n type: T,\n payload: EnvelopePayload<T>,\n sessionId: string,\n metadata: EnvelopeMetadata\n): Envelope<T> {\n return {\n uuid: uuidv7(),\n v: 0 as const,\n type,\n payload,\n context: metadata.context,\n runtime: metadata.runtime,\n environment: metadata.environment,\n buildId: metadata.buildId,\n releaseId: metadata.releaseId,\n clientTs: Date.now(),\n sessionId,\n sessionSource: \"client\" as const,\n } as Envelope<T>;\n}\n"],"mappings":";;AAkBA,SAAgB,cACd,MACA,SACA,WACA,UACa;AACb,QAAO;EACL,MAAMA,IAAQ;EACd,GAAG;EACH;EACA;EACA,SAAS,SAAS;EAClB,SAAS,SAAS;EAClB,aAAa,SAAS;EACtB,SAAS,SAAS;EAClB,WAAW,SAAS;EACpB,UAAU,KAAK,KAAK;EACpB;EACA,eAAe;EAChB"}
1
+ {"version":3,"file":"envelope.mjs","names":["uuidv7"],"sources":["../../src/internal/envelope.ts"],"sourcesContent":["import type {\n Envelope,\n EnvelopeContext,\n EnvelopePayload,\n EventType,\n} from \"@interfere/types/sdk/envelope\";\nimport type { Env, Runtime } from \"@interfere/types/sdk/runtime\";\n\nimport { v7 as uuidv7 } from \"uuid\";\n\nexport interface EnvelopeMetadata {\n buildId: string;\n context: EnvelopeContext;\n environment: Env;\n releaseId: string | null;\n runtime: Runtime;\n}\n\nexport function buildEnvelope<T extends EventType>(\n type: T,\n payload: EnvelopePayload<T>,\n sessionId: string,\n metadata: EnvelopeMetadata\n): Envelope<T> {\n return {\n uuid: uuidv7(),\n v: 0 as const,\n type,\n payload,\n context: metadata.context,\n runtime: metadata.runtime,\n environment: metadata.environment,\n buildId: metadata.buildId,\n releaseId: metadata.releaseId,\n clientTs: Date.now(),\n sessionId,\n sessionSource: \"client\" as const,\n } as Envelope<T>;\n}\n"],"mappings":";;AAkBA,SAAgB,cACd,MACA,SACA,WACA,UACa;AACb,QAAO;EACL,MAAMA,IAAQ;EACd,GAAG;EACH;EACA;EACA,SAAS,SAAS;EAClB,SAAS,SAAS;EAClB,aAAa,SAAS;EACtB,SAAS,SAAS;EAClB,WAAW,SAAS;EACpB,UAAU,KAAK,KAAK;EACpB;EACA,eAAe;EAChB"}
@@ -1,4 +1,3 @@
1
- import { PluginOverrides } from "./plugins/lib/loader.mjs";
2
1
  import { PropsWithChildren, ReactNode } from "react";
3
2
  import { EnvelopePayload, EventType } from "@interfere/types/sdk/envelope";
4
3
  import { IdentifyParams } from "@interfere/types/sdk/identify";
@@ -15,18 +14,10 @@ interface InterfereContextValue {
15
14
  getWindowId(): string | null;
16
15
  };
17
16
  }
18
- interface InterfereProviderProps extends PropsWithChildren {
19
- buildId?: string | null;
20
- plugins?: PluginOverrides;
21
- releaseId?: string | null;
22
- }
23
17
  declare function InterfereProvider({
24
- plugins,
25
- buildId,
26
- releaseId,
27
18
  children
28
- }: InterfereProviderProps): ReactNode;
19
+ }: PropsWithChildren): ReactNode;
29
20
  declare function useInterfere(): InterfereContextValue;
30
21
  declare function useSession(): string | null;
31
22
  //#endregion
32
- export { InterfereProvider, InterfereProviderProps, useInterfere, useSession };
23
+ export { InterfereProvider, useInterfere, useSession };
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.mts","names":[],"sources":["../src/provider.tsx"],"mappings":";;;;;;UAiBU,qBAAA;EACR,OAAA,WAAkB,SAAA,EAAW,IAAA,EAAM,CAAA,EAAG,OAAA,EAAS,eAAA,CAAgB,CAAA;EAC/D,QAAA;IACE,GAAA,IAAO,cAAA;IACP,GAAA,CAAI,MAAA,EAAQ,cAAA;EAAA;EAEd,OAAA;IACE,KAAA;IACA,WAAA;EAAA;AAAA;AAAA,UAMa,sBAAA,SAA+B,iBAAA;EAC9C,OAAA;EACA,OAAA,GAFsC,eAAA;EAGtC,SAAA;AAAA;AAAA,iBAGc,iBAAA,CAAA;EACd,OAAA;EACA,OAAA;EACA,SAAA;EACA;AAAA,GACC,sBAAA,GAAyB,SAAA;AAAA,iBA0BZ,YAAA,CAAA,GAAgB,qBAAA;AAAA,iBAQhB,UAAA,CAAA"}
1
+ {"version":3,"file":"provider.d.mts","names":[],"sources":["../src/provider.tsx"],"mappings":";;;;;UAeU,qBAAA;EACR,OAAA,WAAkB,SAAA,EAAW,IAAA,EAAM,CAAA,EAAG,OAAA,EAAS,eAAA,CAAgB,CAAA;EAC/D,QAAA;IACE,GAAA,IAAO,cAAA;IACP,GAAA,CAAI,MAAA,EAAQ,cAAA;EAAA;EAEd,OAAA;IACE,KAAA;IACA,WAAA;EAAA;AAAA;AAAA,iBAMY,iBAAA,CAAA;EAAoB;AAAA,GAAY,iBAAA,GAAoB,SAAA;AAAA,iBAUpD,YAAA,CAAA,GAAgB,qBAAA;AAAA,iBAQhB,UAAA,CAAA"}
package/dist/provider.mjs CHANGED
@@ -1,28 +1,11 @@
1
1
  "use client";
2
2
  import { identity, session } from "./tracking/api.mjs";
3
- import { capture, close, init } from "./internal/client.mjs";
4
- import { createContext, useContext, useEffect, useRef } from "react";
3
+ import { capture } from "./internal/client.mjs";
4
+ import { createContext, useContext } from "react";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region src/provider.tsx
7
7
  const InterfereContext = createContext(null);
8
- function InterfereProvider({ plugins, buildId, releaseId, children }) {
9
- const initialized = useRef(false);
10
- useEffect(() => {
11
- if (initialized.current) return;
12
- initialized.current = true;
13
- init({
14
- plugins,
15
- buildId,
16
- releaseId
17
- }).catch(() => {});
18
- return () => {
19
- close();
20
- };
21
- }, [
22
- plugins,
23
- buildId,
24
- releaseId
25
- ]);
8
+ function InterfereProvider({ children }) {
26
9
  return /* @__PURE__ */ jsx(InterfereContext, {
27
10
  value: {
28
11
  capture,
@@ -1 +1 @@
1
- {"version":3,"file":"provider.mjs","names":[],"sources":["../src/provider.tsx"],"sourcesContent":["\"use client\";\n\nimport type { EnvelopePayload, EventType } from \"@interfere/types/sdk/envelope\";\nimport type { IdentifyParams } from \"@interfere/types/sdk/identify\";\n\nimport {\n createContext,\n type PropsWithChildren,\n type ReactNode,\n useContext,\n useEffect,\n useRef,\n} from \"react\";\n\nimport { capture, close, init } from \"./internal/client.js\";\nimport { identity, session } from \"./tracking/api.js\";\n\ninterface InterfereContextValue {\n capture<T extends EventType>(type: T, payload: EnvelopePayload<T>): void;\n identity: {\n get(): IdentifyParams | null;\n set(params: IdentifyParams): void;\n };\n session: {\n getId(): string | null;\n getWindowId(): string | null;\n };\n}\n\nconst InterfereContext = createContext<InterfereContextValue | null>(null);\n\nexport interface InterfereProviderProps extends PropsWithChildren {\n buildId?: string | null;\n plugins?: import(\"./plugins/lib/loader.js\").PluginOverrides;\n releaseId?: string | null;\n}\n\nexport function InterfereProvider({\n plugins,\n buildId,\n releaseId,\n children,\n}: InterfereProviderProps): ReactNode {\n const initialized = useRef(false);\n\n useEffect(() => {\n if (initialized.current) {\n return;\n }\n initialized.current = true;\n init({ plugins, buildId, releaseId }).catch(() => {\n /* best-effort */\n });\n\n return () => {\n close();\n };\n }, [plugins, buildId, releaseId]);\n\n const value: InterfereContextValue = {\n capture,\n identity,\n session,\n };\n\n return <InterfereContext value={value}>{children}</InterfereContext>;\n}\n\nexport function useInterfere(): InterfereContextValue {\n const ctx = useContext(InterfereContext);\n if (!ctx) {\n throw new Error(\"useInterfere must be used within <InterfereProvider>\");\n }\n return ctx;\n}\n\nexport function useSession(): string | null {\n return useInterfere().session.getId();\n}\n"],"mappings":";;;;;;AA6BA,MAAM,mBAAmB,cAA4C,KAAK;AAQ1E,SAAgB,kBAAkB,EAChC,SACA,SACA,WACA,YACoC;CACpC,MAAM,cAAc,OAAO,MAAM;AAEjC,iBAAgB;AACd,MAAI,YAAY,QACd;AAEF,cAAY,UAAU;AACtB,OAAK;GAAE;GAAS;GAAS;GAAW,CAAC,CAAC,YAAY,GAEhD;AAEF,eAAa;AACX,UAAO;;IAER;EAAC;EAAS;EAAS;EAAU,CAAC;AAQjC,QAAO,oBAAC,kBAAD;EAAkB,OANY;GACnC;GACA;GACA;GACD;EAEuC;EAA4B,CAAA;;AAGtE,SAAgB,eAAsC;CACpD,MAAM,MAAM,WAAW,iBAAiB;AACxC,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,uDAAuD;AAEzE,QAAO;;AAGT,SAAgB,aAA4B;AAC1C,QAAO,cAAc,CAAC,QAAQ,OAAO"}
1
+ {"version":3,"file":"provider.mjs","names":[],"sources":["../src/provider.tsx"],"sourcesContent":["\"use client\";\n\nimport type { EnvelopePayload, EventType } from \"@interfere/types/sdk/envelope\";\nimport type { IdentifyParams } from \"@interfere/types/sdk/identify\";\n\nimport {\n createContext,\n type PropsWithChildren,\n type ReactNode,\n useContext,\n} from \"react\";\n\nimport { capture } from \"./internal/client.js\";\nimport { identity, session } from \"./tracking/api.js\";\n\ninterface InterfereContextValue {\n capture<T extends EventType>(type: T, payload: EnvelopePayload<T>): void;\n identity: {\n get(): IdentifyParams | null;\n set(params: IdentifyParams): void;\n };\n session: {\n getId(): string | null;\n getWindowId(): string | null;\n };\n}\n\nconst InterfereContext = createContext<InterfereContextValue | null>(null);\n\nexport function InterfereProvider({ children }: PropsWithChildren): ReactNode {\n const value: InterfereContextValue = {\n capture,\n identity,\n session,\n };\n\n return <InterfereContext value={value}>{children}</InterfereContext>;\n}\n\nexport function useInterfere(): InterfereContextValue {\n const ctx = useContext(InterfereContext);\n if (!ctx) {\n throw new Error(\"useInterfere must be used within <InterfereProvider>\");\n }\n return ctx;\n}\n\nexport function useSession(): string | null {\n return useInterfere().session.getId();\n}\n"],"mappings":";;;;;;AA2BA,MAAM,mBAAmB,cAA4C,KAAK;AAE1E,SAAgB,kBAAkB,EAAE,YAA0C;AAO5E,QAAO,oBAAC,kBAAD;EAAkB,OANY;GACnC;GACA;GACA;GACD;EAEuC;EAA4B,CAAA;;AAGtE,SAAgB,eAAsC;CACpD,MAAM,MAAM,WAAW,iBAAiB;AACxC,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,uDAAuD;AAEzE,QAAO;;AAGT,SAAgB,aAA4B;AAC1C,QAAO,cAAc,CAAC,QAAQ,OAAO"}
@@ -1 +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,cAuBW,aAAA;EAAA,iBACM,MAAA;EAAA,QACT,gBAAA;cAEI,MAAA,EAAQ,YAAA;EAId,IAAA,CAAK,SAAA,EAAW,QAAA,KAAa,OAAA;AAAA"}
1
+ {"version":3,"file":"http.d.mts","names":[],"sources":["../../src/transport/http.ts"],"mappings":";;;UAUiB,YAAA;EACf,OAAA,EAAS,OAAA;EACT,GAAA;AAAA;AAAA,cA+BW,aAAA;EAAA,iBACM,MAAA;EAAA,QACT,gBAAA;cAEI,MAAA,EAAQ,YAAA;EAId,IAAA,CAAK,SAAA,EAAW,QAAA,KAAa,OAAA;AAAA"}
@@ -4,8 +4,6 @@ import { session } from "../tracking/api.mjs";
4
4
  import { make } from "tctx/traceparent";
5
5
  //#region src/transport/http.ts
6
6
  const log = createLogger("http");
7
- const KEEPALIVE_BUDGET_BYTES = 61440;
8
- const MAX_CONCURRENT_KEEPALIVE = 15;
9
7
  function buildHeaders(base) {
10
8
  const h = Object.fromEntries(base.entries());
11
9
  h.traceparent = String(make());
@@ -15,6 +13,11 @@ function buildHeaders(base) {
15
13
  if (visitorId) h["x-interfere-visitor"] = visitorId;
16
14
  return h;
17
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;
18
21
  var HttpTransport = class {
19
22
  target;
20
23
  pendingKeepalive = 0;
@@ -23,14 +26,24 @@ var HttpTransport = class {
23
26
  }
24
27
  async send(envelopes) {
25
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
+ }
26
39
  const bytes = new TextEncoder().encode(body).byteLength;
27
40
  const useKeepalive = bytes < KEEPALIVE_BUDGET_BYTES && this.pendingKeepalive < MAX_CONCURRENT_KEEPALIVE;
28
41
  if (useKeepalive) this.pendingKeepalive++;
29
- log.debug("POST %d envelopes (%d bytes, keepalive=%s)", envelopes.length, bytes, useKeepalive);
42
+ log.debug("POST %d envelopes direct (%d bytes, keepalive=%s)", envelopes.length, bytes, useKeepalive);
30
43
  try {
31
44
  await fetch(this.target.url, {
32
45
  method: "POST",
33
- headers: buildHeaders(this.target.headers),
46
+ headers,
34
47
  body,
35
48
  keepalive: useKeepalive
36
49
  });
@@ -1 +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\nconst KEEPALIVE_BUDGET_BYTES = 61_440; // 60 KB\nconst MAX_CONCURRENT_KEEPALIVE = 15;\n\nfunction 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\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 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 (%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: buildHeaders(this.target.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,MAAM,yBAAyB;AAC/B,MAAM,2BAA2B;AAEjC,SAAS,aAAa,MAAuC;CAC3D,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,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,QAAQ,IAAI,aAAa,CAAC,OAAO,KAAK,CAAC;EAC7C,MAAM,eACJ,QAAQ,0BACR,KAAK,mBAAmB;AAE1B,MAAI,aACF,MAAK;AAGP,MAAI,MACF,8CACA,UAAU,QACV,OACA,aACD;AAED,MAAI;AACF,SAAM,MAAM,KAAK,OAAO,KAAK;IAC3B,QAAQ;IACR,SAAS,aAAa,KAAK,OAAO,QAAQ;IAC1C;IACA,WAAW;IACZ,CAAC;YACM;AACR,OAAI,aACF,MAAK"}
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\nfunction 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,SAAS,aAAa,MAAuC;CAC3D,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"}
@@ -1 +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;EAUA,OAAA,CAAA;EAAA,iBAiBiB,kBAAA;EAAA,iBAMA,cAAA;AAAA"}
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"}
@@ -32,7 +32,10 @@ var BatchQueue = class {
32
32
  while (this.buffer.length > 0) {
33
33
  const batch = this.buffer.splice(0, this.batchSize);
34
34
  log.debug("flushing %d envelopes", batch.length);
35
- this.transport.send(batch).catch(() => {});
35
+ this.transport.send(batch).catch(() => {
36
+ log.warn("send failed, re-queuing %d envelopes", batch.length);
37
+ this.buffer.unshift(...batch);
38
+ });
36
39
  }
37
40
  }
38
41
  dispose() {
@@ -1 +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 /* SW handles retry */\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,GAErC;;;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"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interfere/react",
3
- "version": "0.1.0-alpha.0",
3
+ "version": "0.1.0-alpha.25",
4
4
  "license": "MIT",
5
5
  "description": "Client-side React SDK for Interfere. Error tracking, session replay, and analytics.",
6
6
  "keywords": [