@genn-inc/cluebase-frontend-sdk 0.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.
- package/README.md +222 -0
- package/dist/_generated/correlation-attribute-keys.d.ts +2 -0
- package/dist/_generated/correlation-attribute-keys.js +33 -0
- package/dist/_generated/identity-pii-policy.d.ts +38 -0
- package/dist/_generated/identity-pii-policy.js +103 -0
- package/dist/_generated/ingest-privacy-tables.d.ts +120 -0
- package/dist/_generated/ingest-privacy-tables.js +890 -0
- package/dist/_generated/otel-resource-keys.d.ts +21 -0
- package/dist/_generated/otel-resource-keys.js +72 -0
- package/dist/_generated/otel-span-conversion.d.ts +48 -0
- package/dist/_generated/otel-span-conversion.js +69 -0
- package/dist/_generated/parameter-snapshot-leaf.d.ts +11 -0
- package/dist/_generated/parameter-snapshot-leaf.js +37 -0
- package/dist/_generated/sdk-runtime-policy.d.ts +7 -0
- package/dist/_generated/sdk-runtime-policy.js +14 -0
- package/dist/_generated/usage-governor-tables.d.ts +15 -0
- package/dist/_generated/usage-governor-tables.js +44 -0
- package/dist/context/browser-storage.d.ts +15 -0
- package/dist/context/browser-storage.js +38 -0
- package/dist/context/environment.d.ts +37 -0
- package/dist/context/environment.js +229 -0
- package/dist/context/identity.d.ts +16 -0
- package/dist/context/identity.js +139 -0
- package/dist/context/organization.d.ts +16 -0
- package/dist/context/organization.js +60 -0
- package/dist/context/session.d.ts +28 -0
- package/dist/context/session.js +130 -0
- package/dist/context/tab.d.ts +22 -0
- package/dist/context/tab.js +117 -0
- package/dist/context/trace.d.ts +76 -0
- package/dist/context/trace.js +163 -0
- package/dist/exporter/batch.d.ts +94 -0
- package/dist/exporter/batch.js +485 -0
- package/dist/exporter/browser-outbox-records.d.ts +159 -0
- package/dist/exporter/browser-outbox-records.js +341 -0
- package/dist/exporter/browser-outbox.d.ts +112 -0
- package/dist/exporter/browser-outbox.js +876 -0
- package/dist/exporter/client.d.ts +92 -0
- package/dist/exporter/client.js +541 -0
- package/dist/exporter/delivery-response-contract.d.ts +103 -0
- package/dist/exporter/delivery-response-contract.js +147 -0
- package/dist/exporter/delivery-response.d.ts +37 -0
- package/dist/exporter/delivery-response.js +151 -0
- package/dist/exporter/diagnostics.d.ts +42 -0
- package/dist/exporter/diagnostics.js +148 -0
- package/dist/exporter/event-id.d.ts +10 -0
- package/dist/exporter/event-id.js +75 -0
- package/dist/exporter/frontend-resource.d.ts +20 -0
- package/dist/exporter/frontend-resource.js +52 -0
- package/dist/exporter/local-minimization.d.ts +29 -0
- package/dist/exporter/local-minimization.js +87 -0
- package/dist/exporter/observation-source-event-exporter.d.ts +69 -0
- package/dist/exporter/observation-source-event-exporter.js +154 -0
- package/dist/exporter/parameter-snapshot.d.ts +14 -0
- package/dist/exporter/parameter-snapshot.js +215 -0
- package/dist/exporter/path-template.d.ts +1 -0
- package/dist/exporter/path-template.js +67 -0
- package/dist/exporter/raw-event-to-source-signal.d.ts +12 -0
- package/dist/exporter/raw-event-to-source-signal.js +297 -0
- package/dist/exporter/retry.d.ts +8 -0
- package/dist/exporter/retry.js +8 -0
- package/dist/exporter/sanitize.d.ts +30 -0
- package/dist/exporter/sanitize.js +177 -0
- package/dist/exporter/schema-evidence.d.ts +20 -0
- package/dist/exporter/schema-evidence.js +232 -0
- package/dist/exporter/source-event.d.ts +99 -0
- package/dist/exporter/source-event.js +13 -0
- package/dist/exporter/span-to-source-signal.d.ts +8 -0
- package/dist/exporter/span-to-source-signal.js +174 -0
- package/dist/exporter/text-fingerprint.d.ts +9 -0
- package/dist/exporter/text-fingerprint.js +16 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +158 -0
- package/dist/instrumentation/action.d.ts +2 -0
- package/dist/instrumentation/action.js +171 -0
- package/dist/instrumentation/cluebase-authored-attributes.d.ts +4 -0
- package/dist/instrumentation/cluebase-authored-attributes.js +32 -0
- package/dist/instrumentation/common.d.ts +73 -0
- package/dist/instrumentation/common.js +90 -0
- package/dist/instrumentation/dom.d.ts +63 -0
- package/dist/instrumentation/dom.js +640 -0
- package/dist/instrumentation/drag.d.ts +2 -0
- package/dist/instrumentation/drag.js +82 -0
- package/dist/instrumentation/error.d.ts +2 -0
- package/dist/instrumentation/error.js +318 -0
- package/dist/instrumentation/form.d.ts +2 -0
- package/dist/instrumentation/form.js +132 -0
- package/dist/instrumentation/input.d.ts +2 -0
- package/dist/instrumentation/input.js +180 -0
- package/dist/instrumentation/location.d.ts +11 -0
- package/dist/instrumentation/location.js +69 -0
- package/dist/instrumentation/naming-evidence.d.ts +20 -0
- package/dist/instrumentation/naming-evidence.js +11 -0
- package/dist/instrumentation/navigation.d.ts +2 -0
- package/dist/instrumentation/navigation.js +144 -0
- package/dist/instrumentation/network-request.d.ts +103 -0
- package/dist/instrumentation/network-request.js +285 -0
- package/dist/instrumentation/network-span-attributes.d.ts +25 -0
- package/dist/instrumentation/network-span-attributes.js +153 -0
- package/dist/instrumentation/network.d.ts +16 -0
- package/dist/instrumentation/network.js +502 -0
- package/dist/instrumentation/page.d.ts +2 -0
- package/dist/instrumentation/page.js +56 -0
- package/dist/instrumentation/performance.d.ts +2 -0
- package/dist/instrumentation/performance.js +365 -0
- package/dist/integrations/next-router.d.ts +16 -0
- package/dist/integrations/next-router.js +18 -0
- package/dist/integrations/react-router.d.ts +7 -0
- package/dist/integrations/react-router.js +61 -0
- package/dist/internal/internal-log.d.ts +23 -0
- package/dist/internal/internal-log.js +47 -0
- package/dist/internal/metrics.d.ts +10 -0
- package/dist/internal/metrics.js +50 -0
- package/dist/provider/_version.d.ts +1 -0
- package/dist/provider/_version.js +3 -0
- package/dist/provider/config.d.ts +12 -0
- package/dist/provider/config.js +177 -0
- package/dist/provider/constants.d.ts +62 -0
- package/dist/provider/constants.js +118 -0
- package/dist/provider/contracts.d.ts +51 -0
- package/dist/provider/contracts.js +46 -0
- package/dist/provider/privacy-policy-store.d.ts +20 -0
- package/dist/provider/privacy-policy-store.js +56 -0
- package/dist/provider/sampling.d.ts +2 -0
- package/dist/provider/sampling.js +17 -0
- package/dist/provider/sdk-event-pipeline.d.ts +60 -0
- package/dist/provider/sdk-event-pipeline.js +478 -0
- package/dist/provider/sdk-input-normalization.d.ts +7 -0
- package/dist/provider/sdk-input-normalization.js +113 -0
- package/dist/provider/sdk-otel-pipeline.d.ts +14 -0
- package/dist/provider/sdk-otel-pipeline.js +148 -0
- package/dist/provider/sdk-runtime-surfaces.d.ts +49 -0
- package/dist/provider/sdk-runtime-surfaces.js +216 -0
- package/dist/provider/sdk.d.ts +2 -0
- package/dist/provider/sdk.js +614 -0
- package/dist/provider/types.d.ts +323 -0
- package/dist/provider/types.js +1 -0
- package/dist/provider/usage-governor.d.ts +7 -0
- package/dist/provider/usage-governor.js +116 -0
- package/package.json +59 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { trace } from "@opentelemetry/api";
|
|
2
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
3
|
+
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
4
|
+
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
|
|
5
|
+
import { resolveBrowserTokenEndpoint, resolveCanonicalIngestEndpoint, } from "../exporter/client.js";
|
|
6
|
+
import { ObservationSourceEventExporter } from "../exporter/observation-source-event-exporter.js";
|
|
7
|
+
import { createFrontendResourceAttributes } from "../exporter/frontend-resource.js";
|
|
8
|
+
import { createCluebaseNetworkPropagator } from "../instrumentation/network.js";
|
|
9
|
+
import { getSessionCaptureEligibility } from "./sdk-event-pipeline.js";
|
|
10
|
+
export const createCluebaseOtelPipeline = ({ resolved, getTransport, getContext, }) => {
|
|
11
|
+
if (!getTransport()) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const resource = resourceFromAttributes(createFrontendResourceAttributes(resolved));
|
|
15
|
+
const collectionPermits = new WeakMap();
|
|
16
|
+
const exporter = new ObservationSourceEventExporter({
|
|
17
|
+
enqueueImpl: (event, permit) => {
|
|
18
|
+
const transport = getTransport();
|
|
19
|
+
if (!transport) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
transport.enqueue(event, permit);
|
|
23
|
+
},
|
|
24
|
+
getCollectionPermit: (span) => {
|
|
25
|
+
const transport = getTransport();
|
|
26
|
+
if (!transport)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (span) {
|
|
29
|
+
return collectionPermits.get(span);
|
|
30
|
+
}
|
|
31
|
+
if (getSessionCaptureEligibility(transport) === false) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return transport.capturePermit();
|
|
35
|
+
},
|
|
36
|
+
flushImpl: async () => {
|
|
37
|
+
const transport = getTransport();
|
|
38
|
+
if (!transport) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
await transport.flush();
|
|
42
|
+
},
|
|
43
|
+
shutdownImpl: async () => {
|
|
44
|
+
const transport = getTransport();
|
|
45
|
+
if (!transport) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
await transport.flush();
|
|
49
|
+
},
|
|
50
|
+
getContext,
|
|
51
|
+
deniedKeys: resolved.privacy?.deniedKeys ?? [],
|
|
52
|
+
ignoreUrlPrefixes: [
|
|
53
|
+
resolveCanonicalIngestEndpoint(resolved.endpoint),
|
|
54
|
+
resolveCanonicalIngestEndpoint(resolved.originalEndpoint),
|
|
55
|
+
resolveBrowserTokenEndpoint(resolved.endpoint),
|
|
56
|
+
resolveBrowserTokenEndpoint(resolved.originalEndpoint),
|
|
57
|
+
...(resolved.localSetupCheckEndpoint
|
|
58
|
+
? [resolved.localSetupCheckEndpoint]
|
|
59
|
+
: []),
|
|
60
|
+
].filter((url) => typeof url === "string" && url.length > 0),
|
|
61
|
+
});
|
|
62
|
+
const provider = new WebTracerProvider({
|
|
63
|
+
resource,
|
|
64
|
+
spanProcessors: [
|
|
65
|
+
new BatchSpanProcessor(exporter, {
|
|
66
|
+
scheduledDelayMillis: resolved.batch.flushIntervalMs,
|
|
67
|
+
maxQueueSize: 2048,
|
|
68
|
+
maxExportBatchSize: 512,
|
|
69
|
+
}),
|
|
70
|
+
collectionPermitProcessor(getTransport, collectionPermits),
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
const mode = resolved.otelProviderMode;
|
|
74
|
+
const shouldRegister = mode === "register" || (mode === "detect" && !hasHostInstalledProvider());
|
|
75
|
+
if (shouldRegister) {
|
|
76
|
+
provider.register({
|
|
77
|
+
propagator: createCluebaseNetworkPropagator(),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return provider;
|
|
81
|
+
};
|
|
82
|
+
const collectionPermitProcessor = (getTransport, permits) => ({
|
|
83
|
+
onStart(span) {
|
|
84
|
+
const transport = getTransport();
|
|
85
|
+
if (transport && getSessionCaptureEligibility(transport) !== false) {
|
|
86
|
+
permits.set(span, transport.capturePermit());
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
onEnding() { },
|
|
90
|
+
onEnd() { },
|
|
91
|
+
forceFlush: async () => undefined,
|
|
92
|
+
shutdown: async () => undefined,
|
|
93
|
+
});
|
|
94
|
+
export const shutdownCluebaseOtelProvider = (provider) => {
|
|
95
|
+
if (!provider) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
void provider.shutdown().catch(() => undefined);
|
|
99
|
+
};
|
|
100
|
+
export const shutdownCluebaseOtelProviderAsync = async (provider) => {
|
|
101
|
+
if (!provider) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
await provider.shutdown();
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// shutdown is best-effort per OTel contract.
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
export const forceFlushCluebaseOtelProvider = async (provider, signal) => {
|
|
112
|
+
if (!provider) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
await awaitWithAbort(provider.forceFlush(), signal);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// forceFlush is best-effort per OTel contract.
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const awaitWithAbort = async (promise, signal) => {
|
|
123
|
+
if (!signal)
|
|
124
|
+
return await promise;
|
|
125
|
+
if (signal.aborted)
|
|
126
|
+
throw new DOMException("aborted", "AbortError");
|
|
127
|
+
return await new Promise((resolve, reject) => {
|
|
128
|
+
const abort = () => reject(new DOMException("aborted", "AbortError"));
|
|
129
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
130
|
+
void promise.then((value) => {
|
|
131
|
+
signal.removeEventListener("abort", abort);
|
|
132
|
+
resolve(value);
|
|
133
|
+
}, (error) => {
|
|
134
|
+
signal.removeEventListener("abort", abort);
|
|
135
|
+
reject(error);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
const hasHostInstalledProvider = () => {
|
|
140
|
+
try {
|
|
141
|
+
const current = trace.getTracerProvider();
|
|
142
|
+
const ctorName = current?.constructor?.name ?? "";
|
|
143
|
+
return ctorName !== "" && ctorName !== "ProxyTracerProvider";
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TraceManager } from "../context/trace.js";
|
|
2
|
+
import { type IngestClient } from "../exporter/client.js";
|
|
3
|
+
import type { BatchTransport } from "../exporter/batch.js";
|
|
4
|
+
import type { InternalMetricsStore } from "../internal/metrics.js";
|
|
5
|
+
import type { CluebaseOtelProvider } from "./sdk-otel-pipeline.js";
|
|
6
|
+
import type { CaptureModuleContext, CluebaseConsentState, CluebaseInternalLogger, RawCapturedEvent, ResolvedCluebaseConfig } from "./types.js";
|
|
7
|
+
type ProviderRuntimeSurfacesOptions = {
|
|
8
|
+
internalMetrics: InternalMetricsStore;
|
|
9
|
+
logger: CluebaseInternalLogger;
|
|
10
|
+
enqueueRawEvent: (event: RawCapturedEvent) => void;
|
|
11
|
+
getViewId: () => string | null;
|
|
12
|
+
getConsent: () => CluebaseConsentState;
|
|
13
|
+
getObservationContext: () => {
|
|
14
|
+
anonymousId: string | null;
|
|
15
|
+
userId: string | null;
|
|
16
|
+
organizationId?: string | null;
|
|
17
|
+
sessionId: string | null;
|
|
18
|
+
tabId: string | null;
|
|
19
|
+
};
|
|
20
|
+
getTraceManager: () => TraceManager | null;
|
|
21
|
+
getTransport: () => BatchTransport | null;
|
|
22
|
+
getTracerProvider: () => CluebaseOtelProvider | null;
|
|
23
|
+
};
|
|
24
|
+
export declare class ProviderRuntimeSurfaces {
|
|
25
|
+
private readonly internalMetrics;
|
|
26
|
+
private readonly logger;
|
|
27
|
+
private readonly enqueueRawEvent;
|
|
28
|
+
private readonly getViewId;
|
|
29
|
+
private readonly getConsent;
|
|
30
|
+
private readonly getObservationContext;
|
|
31
|
+
private readonly getTraceManager;
|
|
32
|
+
private readonly getTransport;
|
|
33
|
+
private readonly getTracerProvider;
|
|
34
|
+
private captureHandles;
|
|
35
|
+
private unloadHandlers;
|
|
36
|
+
private flushDebounceTimer;
|
|
37
|
+
private browserTokenWarmupController;
|
|
38
|
+
constructor(options: ProviderRuntimeSurfacesOptions);
|
|
39
|
+
buildCaptureContext(): CaptureModuleContext;
|
|
40
|
+
warmupBrowserToken(client: IngestClient): void;
|
|
41
|
+
startCaptureModules(config: ResolvedCluebaseConfig): void;
|
|
42
|
+
stopCaptureModules(): void;
|
|
43
|
+
abortBrowserTokenWarmup(): void;
|
|
44
|
+
flushCaptureSummaries(reason: string): Promise<void>;
|
|
45
|
+
installUnloadHandlers(onUnloadSessionEnd: () => void): void;
|
|
46
|
+
isCaptureActive(): boolean;
|
|
47
|
+
stopRuntimeSurfaces(): void;
|
|
48
|
+
}
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { TraceManager } from "../context/trace.js";
|
|
2
|
+
import { resolveBrowserTokenEndpoint, resolveCanonicalIngestEndpoint, } from "../exporter/client.js";
|
|
3
|
+
import { startActionCapture } from "../instrumentation/action.js";
|
|
4
|
+
import { startDragCapture } from "../instrumentation/drag.js";
|
|
5
|
+
import { startErrorCapture } from "../instrumentation/error.js";
|
|
6
|
+
import { startFormCapture } from "../instrumentation/form.js";
|
|
7
|
+
import { startInputCapture } from "../instrumentation/input.js";
|
|
8
|
+
import { startNavigationCapture } from "../instrumentation/navigation.js";
|
|
9
|
+
import { startNetworkCapture } from "../instrumentation/network.js";
|
|
10
|
+
import { startPageCapture } from "../instrumentation/page.js";
|
|
11
|
+
import { startPerformanceCapture } from "../instrumentation/performance.js";
|
|
12
|
+
const FLUSH_DEBOUNCE_MS = 200;
|
|
13
|
+
export class ProviderRuntimeSurfaces {
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.captureHandles = [];
|
|
16
|
+
this.unloadHandlers = [];
|
|
17
|
+
this.flushDebounceTimer = null;
|
|
18
|
+
this.browserTokenWarmupController = null;
|
|
19
|
+
this.internalMetrics = options.internalMetrics;
|
|
20
|
+
this.logger = options.logger;
|
|
21
|
+
this.enqueueRawEvent = options.enqueueRawEvent;
|
|
22
|
+
this.getViewId = options.getViewId;
|
|
23
|
+
this.getConsent = options.getConsent;
|
|
24
|
+
this.getObservationContext = options.getObservationContext;
|
|
25
|
+
this.getTraceManager = options.getTraceManager;
|
|
26
|
+
this.getTransport = options.getTransport;
|
|
27
|
+
this.getTracerProvider = options.getTracerProvider;
|
|
28
|
+
}
|
|
29
|
+
buildCaptureContext() {
|
|
30
|
+
return {
|
|
31
|
+
onEvent: (event) => {
|
|
32
|
+
this.enqueueRawEvent(event);
|
|
33
|
+
},
|
|
34
|
+
onInternalError: (source, _error) => {
|
|
35
|
+
this.internalMetrics.increment("capture_error_count");
|
|
36
|
+
this.logger.error("capture module error", {
|
|
37
|
+
source,
|
|
38
|
+
error_code: "capture_module_error",
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
getViewId: () => this.getViewId(),
|
|
42
|
+
getConsent: () => this.getConsent(),
|
|
43
|
+
getObservationContext: () => this.getObservationContext(),
|
|
44
|
+
shouldIgnoreElement: () => false,
|
|
45
|
+
startInteraction: (input) => {
|
|
46
|
+
return (this.getTraceManager()?.startInteraction(input) ??
|
|
47
|
+
input.interactionId ??
|
|
48
|
+
null);
|
|
49
|
+
},
|
|
50
|
+
requestFlush: () => {
|
|
51
|
+
void this.flushCaptureSummaries("capture_flush");
|
|
52
|
+
if (this.flushDebounceTimer)
|
|
53
|
+
return;
|
|
54
|
+
this.flushDebounceTimer = setTimeout(() => {
|
|
55
|
+
this.flushDebounceTimer = null;
|
|
56
|
+
const transport = this.getTransport();
|
|
57
|
+
if (!transport)
|
|
58
|
+
return;
|
|
59
|
+
transport.flush().catch((_err) => {
|
|
60
|
+
this.logger.warn("auto-flush after capture event failed", {
|
|
61
|
+
error_code: "capture_flush_failed",
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}, FLUSH_DEBOUNCE_MS);
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
warmupBrowserToken(client) {
|
|
69
|
+
this.browserTokenWarmupController?.abort();
|
|
70
|
+
const controller = new AbortController();
|
|
71
|
+
this.browserTokenWarmupController = controller;
|
|
72
|
+
void client
|
|
73
|
+
.warmupBrowserToken(controller.signal)
|
|
74
|
+
.catch((_error) => {
|
|
75
|
+
if (controller.signal.aborted) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.logger.warn("browser token warmup failed", {
|
|
79
|
+
error_code: "browser_token_warmup_failed",
|
|
80
|
+
});
|
|
81
|
+
})
|
|
82
|
+
.finally(() => {
|
|
83
|
+
if (this.browserTokenWarmupController === controller) {
|
|
84
|
+
this.browserTokenWarmupController = null;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
startCaptureModules(config) {
|
|
89
|
+
const captureContext = this.buildCaptureContext();
|
|
90
|
+
const handles = [];
|
|
91
|
+
handles.push(startInputCapture(captureContext));
|
|
92
|
+
handles.push(startPageCapture(captureContext));
|
|
93
|
+
handles.push(startNavigationCapture(captureContext));
|
|
94
|
+
handles.push(startActionCapture(captureContext));
|
|
95
|
+
handles.push(startFormCapture(captureContext));
|
|
96
|
+
handles.push(startDragCapture(captureContext));
|
|
97
|
+
if (config.captureNetwork) {
|
|
98
|
+
handles.push(startNetworkCapture(captureContext, {
|
|
99
|
+
tracerProvider: this.getTracerProvider() ?? undefined,
|
|
100
|
+
deniedKeys: config.privacy.deniedKeys,
|
|
101
|
+
ignoreUrlPrefixes: [
|
|
102
|
+
resolveCanonicalIngestEndpoint(config.endpoint),
|
|
103
|
+
resolveBrowserTokenEndpoint(config.endpoint),
|
|
104
|
+
],
|
|
105
|
+
tracePropagationOrigins: config.network.tracePropagationOrigins,
|
|
106
|
+
createRequestTraceContext: (input) => {
|
|
107
|
+
const traceManager = this.getTraceManager();
|
|
108
|
+
if (traceManager) {
|
|
109
|
+
return traceManager.createRequestContext(input);
|
|
110
|
+
}
|
|
111
|
+
return new TraceManager().createRequestContext(input);
|
|
112
|
+
},
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
if (config.capturePerformance) {
|
|
116
|
+
handles.push(startPerformanceCapture(captureContext));
|
|
117
|
+
}
|
|
118
|
+
if (config.captureErrors) {
|
|
119
|
+
handles.push(startErrorCapture(captureContext));
|
|
120
|
+
}
|
|
121
|
+
this.captureHandles = handles;
|
|
122
|
+
}
|
|
123
|
+
stopCaptureModules() {
|
|
124
|
+
for (const handle of this.captureHandles) {
|
|
125
|
+
try {
|
|
126
|
+
handle.stop();
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
this.logger.warn("failed to stop capture module", {
|
|
130
|
+
error_code: "capture_stop_failed",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
this.captureHandles = [];
|
|
135
|
+
}
|
|
136
|
+
abortBrowserTokenWarmup() {
|
|
137
|
+
this.browserTokenWarmupController?.abort();
|
|
138
|
+
this.browserTokenWarmupController = null;
|
|
139
|
+
}
|
|
140
|
+
async flushCaptureSummaries(reason) {
|
|
141
|
+
const pending = [];
|
|
142
|
+
for (const handle of this.captureHandles) {
|
|
143
|
+
try {
|
|
144
|
+
const result = handle.flush?.(reason);
|
|
145
|
+
if (result && typeof result.then === "function") {
|
|
146
|
+
pending.push(result);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
this.logger.warn("failed to flush capture module", {
|
|
151
|
+
error_code: "capture_flush_failed",
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (pending.length === 0)
|
|
156
|
+
return;
|
|
157
|
+
const results = await Promise.allSettled(pending);
|
|
158
|
+
for (const result of results) {
|
|
159
|
+
if (result.status === "rejected") {
|
|
160
|
+
this.logger.warn("failed to flush capture module", {
|
|
161
|
+
error_code: "capture_flush_failed",
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
installUnloadHandlers(onUnloadSessionEnd) {
|
|
167
|
+
if (typeof window === "undefined") {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
let handled = false;
|
|
171
|
+
const handler = () => {
|
|
172
|
+
if (handled) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
handled = true;
|
|
176
|
+
onUnloadSessionEnd();
|
|
177
|
+
this.getTransport()?.flushOnUnload();
|
|
178
|
+
};
|
|
179
|
+
const visibilityHandler = () => {
|
|
180
|
+
if (document.visibilityState !== "hidden") {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
this.getTransport()?.flushOnUnload();
|
|
184
|
+
};
|
|
185
|
+
window.addEventListener("pagehide", handler, { capture: true });
|
|
186
|
+
window.addEventListener("beforeunload", handler, { capture: true });
|
|
187
|
+
document.addEventListener("visibilitychange", visibilityHandler, {
|
|
188
|
+
capture: true,
|
|
189
|
+
});
|
|
190
|
+
this.unloadHandlers.push(() => {
|
|
191
|
+
window.removeEventListener("pagehide", handler, true);
|
|
192
|
+
window.removeEventListener("beforeunload", handler, true);
|
|
193
|
+
document.removeEventListener("visibilitychange", visibilityHandler, true);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
isCaptureActive() {
|
|
197
|
+
return this.captureHandles.length > 0;
|
|
198
|
+
}
|
|
199
|
+
stopRuntimeSurfaces() {
|
|
200
|
+
this.stopCaptureModules();
|
|
201
|
+
if (this.flushDebounceTimer) {
|
|
202
|
+
clearTimeout(this.flushDebounceTimer);
|
|
203
|
+
this.flushDebounceTimer = null;
|
|
204
|
+
}
|
|
205
|
+
this.abortBrowserTokenWarmup();
|
|
206
|
+
for (const dispose of this.unloadHandlers) {
|
|
207
|
+
try {
|
|
208
|
+
dispose();
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Ignore.
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
this.unloadHandlers = [];
|
|
215
|
+
}
|
|
216
|
+
}
|