@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.
- package/dist/error-boundary.mjs +1 -1
- package/dist/internal/client.d.mts +1 -3
- package/dist/internal/client.d.mts.map +1 -1
- package/dist/internal/client.mjs +24 -8
- package/dist/internal/client.mjs.map +1 -1
- package/dist/internal/context.d.mts +1 -1
- package/dist/internal/context.d.mts.map +1 -1
- package/dist/internal/context.mjs +5 -11
- package/dist/internal/context.mjs.map +1 -1
- package/dist/internal/envelope.d.mts +1 -1
- package/dist/internal/envelope.mjs.map +1 -1
- package/dist/provider.d.mts +2 -11
- package/dist/provider.d.mts.map +1 -1
- package/dist/provider.mjs +3 -20
- package/dist/provider.mjs.map +1 -1
- package/dist/transport/http.d.mts.map +1 -1
- package/dist/transport/http.mjs +17 -4
- package/dist/transport/http.mjs.map +1 -1
- package/dist/transport/queue.d.mts.map +1 -1
- package/dist/transport/queue.mjs +4 -1
- package/dist/transport/queue.mjs.map +1 -1
- package/package.json +1 -1
package/dist/error-boundary.mjs
CHANGED
|
@@ -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):
|
|
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":";;;;
|
|
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"}
|
package/dist/internal/client.mjs
CHANGED
|
@@ -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
|
-
|
|
18
|
+
function init(opts = {}) {
|
|
18
19
|
if (state !== "idle") return;
|
|
19
|
-
|
|
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:
|
|
30
|
+
context: collectContext(),
|
|
24
31
|
environment: normalizeEnv(typeof process !== "undefined" ? process.env.NODE_ENV : void 0),
|
|
25
32
|
runtime: inferRuntime(),
|
|
26
|
-
buildId
|
|
27
|
-
releaseId:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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():
|
|
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":";;;
|
|
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
|
-
|
|
4
|
-
async function getDeviceMetadata() {
|
|
5
|
-
if (cachedUa) return cachedUa;
|
|
3
|
+
function getDeviceMetadata() {
|
|
6
4
|
if (typeof navigator === "undefined") return null;
|
|
7
|
-
|
|
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
|
|
20
|
+
orientation: screen.orientation?.type
|
|
26
21
|
} }
|
|
27
22
|
};
|
|
28
23
|
}
|
|
29
|
-
|
|
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\
|
|
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
|
|
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
|
|
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"}
|
package/dist/provider.d.mts
CHANGED
|
@@ -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
|
-
}:
|
|
19
|
+
}: PropsWithChildren): ReactNode;
|
|
29
20
|
declare function useInterfere(): InterfereContextValue;
|
|
30
21
|
declare function useSession(): string | null;
|
|
31
22
|
//#endregion
|
|
32
|
-
export { InterfereProvider,
|
|
23
|
+
export { InterfereProvider, useInterfere, useSession };
|
package/dist/provider.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.mts","names":[],"sources":["../src/provider.tsx"],"mappings":"
|
|
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
|
|
4
|
-
import { createContext, useContext
|
|
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({
|
|
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,
|
package/dist/provider.mjs.map
CHANGED
|
@@ -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
|
|
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,
|
|
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"}
|
package/dist/transport/http.mjs
CHANGED
|
@@ -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
|
|
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\
|
|
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;
|
|
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"}
|
package/dist/transport/queue.mjs
CHANGED
|
@@ -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
|
|
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"}
|