@amplitude/session-replay-browser 1.47.0-sr-trc-debug-log.4 → 1.47.0
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 +203 -0
- package/lib/cjs/beacon-transport.d.ts +2 -0
- package/lib/cjs/beacon-transport.d.ts.map +1 -1
- package/lib/cjs/beacon-transport.js +39 -1
- package/lib/cjs/beacon-transport.js.map +1 -1
- package/lib/cjs/config/joined-config.d.ts +1 -6
- package/lib/cjs/config/joined-config.d.ts.map +1 -1
- package/lib/cjs/config/joined-config.js +23 -64
- package/lib/cjs/config/joined-config.js.map +1 -1
- package/lib/cjs/config/local-config.d.ts +4 -6
- package/lib/cjs/config/local-config.d.ts.map +1 -1
- package/lib/cjs/config/local-config.js +3 -19
- package/lib/cjs/config/local-config.js.map +1 -1
- package/lib/cjs/config/types.d.ts +74 -19
- package/lib/cjs/config/types.d.ts.map +1 -1
- package/lib/cjs/config/types.js.map +1 -1
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/plugins/url-tracking-plugin.d.ts +0 -13
- package/lib/cjs/plugins/url-tracking-plugin.d.ts.map +1 -1
- package/lib/cjs/plugins/url-tracking-plugin.js +2 -6
- package/lib/cjs/plugins/url-tracking-plugin.js.map +1 -1
- package/lib/cjs/session-replay.d.ts +0 -33
- package/lib/cjs/session-replay.d.ts.map +1 -1
- package/lib/cjs/session-replay.js +40 -339
- package/lib/cjs/session-replay.js.map +1 -1
- package/lib/cjs/targeting/targeting-manager.d.ts +1 -4
- package/lib/cjs/targeting/targeting-manager.d.ts.map +1 -1
- package/lib/cjs/targeting/targeting-manager.js +10 -56
- package/lib/cjs/targeting/targeting-manager.js.map +1 -1
- package/lib/cjs/track-destination.d.ts +5 -1
- package/lib/cjs/track-destination.d.ts.map +1 -1
- package/lib/cjs/track-destination.js +212 -55
- package/lib/cjs/track-destination.js.map +1 -1
- package/lib/cjs/version.d.ts +1 -1
- package/lib/cjs/version.d.ts.map +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/cjs/version.js.map +1 -1
- package/lib/cjs/worker/index.js +1 -1
- package/lib/esm/beacon-transport.d.ts +2 -0
- package/lib/esm/beacon-transport.d.ts.map +1 -1
- package/lib/esm/beacon-transport.js +39 -1
- package/lib/esm/beacon-transport.js.map +1 -1
- package/lib/esm/config/joined-config.d.ts +1 -6
- package/lib/esm/config/joined-config.d.ts.map +1 -1
- package/lib/esm/config/joined-config.js +23 -64
- package/lib/esm/config/joined-config.js.map +1 -1
- package/lib/esm/config/local-config.d.ts +4 -6
- package/lib/esm/config/local-config.d.ts.map +1 -1
- package/lib/esm/config/local-config.js +4 -20
- package/lib/esm/config/local-config.js.map +1 -1
- package/lib/esm/config/types.d.ts +74 -19
- package/lib/esm/config/types.d.ts.map +1 -1
- package/lib/esm/config/types.js.map +1 -1
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.d.ts.map +1 -1
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/plugins/url-tracking-plugin.d.ts +0 -13
- package/lib/esm/plugins/url-tracking-plugin.d.ts.map +1 -1
- package/lib/esm/plugins/url-tracking-plugin.js +2 -6
- package/lib/esm/plugins/url-tracking-plugin.js.map +1 -1
- package/lib/esm/session-replay.d.ts +0 -33
- package/lib/esm/session-replay.d.ts.map +1 -1
- package/lib/esm/session-replay.js +40 -339
- package/lib/esm/session-replay.js.map +1 -1
- package/lib/esm/targeting/targeting-manager.d.ts +1 -4
- package/lib/esm/targeting/targeting-manager.d.ts.map +1 -1
- package/lib/esm/targeting/targeting-manager.js +10 -56
- package/lib/esm/targeting/targeting-manager.js.map +1 -1
- package/lib/esm/track-destination.d.ts +5 -1
- package/lib/esm/track-destination.d.ts.map +1 -1
- package/lib/esm/track-destination.js +212 -55
- package/lib/esm/track-destination.js.map +1 -1
- package/lib/esm/version.d.ts +1 -1
- package/lib/esm/version.d.ts.map +1 -1
- package/lib/esm/version.js +1 -1
- package/lib/esm/version.js.map +1 -1
- package/lib/esm/worker/index.js +1 -1
- package/lib/scripts/index-min.js +1 -1
- package/lib/scripts/index-min.js.gz +0 -0
- package/lib/scripts/index-min.js.map +1 -1
- package/lib/scripts/observers-min.js +1 -1
- package/lib/scripts/observers-min.js.gz +0 -0
- package/lib/scripts/session-replay-browser-min.js +1 -1
- package/lib/scripts/session-replay-browser-min.js.gz +0 -0
- package/lib/scripts/session-replay-browser-min.js.map +1 -1
- package/lib/scripts/targeting-min.js +1 -1
- package/lib/scripts/targeting-min.js.gz +0 -0
- package/lib/scripts/worker-min.js +1 -1
- package/lib/scripts/worker-min.js.gz +0 -0
- package/package.json +4 -4
- package/lib/cjs/diagnostics.d.ts +0 -50
- package/lib/cjs/diagnostics.d.ts.map +0 -1
- package/lib/cjs/diagnostics.js +0 -67
- package/lib/cjs/diagnostics.js.map +0 -1
- package/lib/esm/diagnostics.d.ts +0 -50
- package/lib/esm/diagnostics.d.ts.map +0 -1
- package/lib/esm/diagnostics.js +0 -64
- package/lib/esm/diagnostics.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"targeting-manager.js","sourceRoot":"","sources":["../../../src/targeting/targeting-manager.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"targeting-manager.js","sourceRoot":"","sources":["../../../src/targeting/targeting-manager.ts"],"names":[],"mappings":";;;;AAIA,6DAA0D;AAEnD,IAAM,yBAAyB,GAAG,UAAO,EAc/C;QAbC,SAAS,eAAA,EACT,eAAe,qBAAA,EACf,cAAc,oBAAA,EACd,MAAM,YAAA,EACN,eAAe,qBAAA,EACf,iBAAiB,EAAjB,SAAS,mBAAG,KAAK,KAAA;;;;;wBASjB,qBAAM,uCAAiB,CAAC,uBAAuB,CAAC;wBAC9C,cAAc,EAAE,cAAc;wBAC9B,MAAM,EAAE,MAAM;wBACd,gBAAgB,EAAE,SAAS;qBAC5B,CAAC,EAAA;;oBAJF,SAIE,CAAC;oBAEuB,qBAAM,uCAAiB,CAAC,2BAA2B,CAAC;4BAC5E,cAAc,EAAE,cAAc;4BAC9B,MAAM,EAAE,MAAM;4BACd,SAAS,EAAE,SAAS;yBACrB,CAAC,EAAA;;oBAJI,iBAAiB,GAAG,SAIxB;oBACF,4FAA4F;oBAC5F,qFAAqF;oBACrF,IAAI,iBAAiB,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE;wBAC5C,sBAAO,IAAI,EAAC;qBACb;oBAKG,qBAAqB,GAAG,IAAI,CAAC;;;;oBAGyB,8FAAa,sBAAsB,QAAC;;oBAAjE,wBAAwB,GAAK,CAAA,SAAoC,CAAA,kBAAzC;oBAE7C,MAAM,yCACP,eAAe,KAClB,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,EAC9E,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,cAAc,GAC/B,CAAC;oBACsB,qBAAM,wBAAwB,CAAC,MAAM,CAAC,EAAA;;oBAAxD,eAAe,GAAG,SAAsC;oBAC9D,IAAI,eAAe,IAAI,eAAe,CAAC,mBAAmB,EAAE;wBAC1D,qBAAqB,GAAG,eAAe,CAAC,mBAAmB,CAAC,GAAG,KAAK,IAAI,CAAC;qBAC1E;oBAED,KAAK,uCAAiB,CAAC,6BAA6B,CAAC;wBACnD,cAAc,EAAE,cAAc;wBAC9B,MAAM,EAAE,MAAM;wBACd,SAAS,EAAE,SAAS;wBACpB,cAAc,EAAE,qBAAqB;qBACtC,CAAC,CAAC;;;;oBAEG,UAAU,GAAG,KAAY,CAAC;oBAChC,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;;wBAE1C,sBAAO,qBAAqB,EAAC;;;;CAC9B,CAAC;AA/DW,QAAA,yBAAyB,6BA+DpC","sourcesContent":["import type { TargetingParameters } from '@amplitude/targeting';\nimport { TargetingConfig } from '../config/types';\nimport { Logger } from '@amplitude/analytics-types';\nimport { SessionReplayTargetingInput } from '../typings/session-replay';\nimport { targetingIDBStore } from './targeting-idb-store';\n\nexport const evaluateTargetingAndStore = async ({\n sessionId,\n targetingConfig,\n loggerProvider,\n apiKey,\n targetingParams,\n urlChange = false,\n}: {\n sessionId: string | number;\n targetingConfig: TargetingConfig;\n loggerProvider: Logger;\n apiKey: string;\n targetingParams?: SessionReplayTargetingInput;\n urlChange?: boolean;\n}) => {\n await targetingIDBStore.clearStoreOfOldSessions({\n loggerProvider: loggerProvider,\n apiKey: apiKey,\n currentSessionId: sessionId,\n });\n\n const idbTargetingMatch = await targetingIDBStore.getTargetingMatchForSession({\n loggerProvider: loggerProvider,\n apiKey: apiKey,\n sessionId: sessionId,\n });\n // Skip IDB cache when re-evaluating with a new page (e.g. URL change); otherwise we'd never\n // re-evaluate and would keep returning true after navigating to a non-matching page.\n if (idbTargetingMatch === true && !urlChange) {\n return true;\n }\n\n // If the targeting config is undefined or an empty object,\n // assume the response was valid but no conditions were set,\n // so all users match targeting\n let sessionTargetingMatch = true;\n try {\n // Dynamic import of the targeting package\n const { evaluateTargeting: evaluateTargetingPackage } = await import('@amplitude/targeting');\n\n const params: TargetingParameters = {\n ...targetingParams,\n flag: targetingConfig,\n sessionId: typeof sessionId === 'string' ? parseInt(sessionId, 10) : sessionId,\n apiKey: apiKey,\n loggerProvider: loggerProvider,\n };\n const targetingResult = await evaluateTargetingPackage(params);\n if (targetingResult && targetingResult.sr_targeting_config) {\n sessionTargetingMatch = targetingResult.sr_targeting_config.key === 'on';\n }\n\n void targetingIDBStore.storeTargetingMatchForSession({\n loggerProvider: loggerProvider,\n apiKey: apiKey,\n sessionId: sessionId,\n targetingMatch: sessionTargetingMatch,\n });\n } catch (err: unknown) {\n const knownError = err as Error;\n loggerProvider.warn(knownError.message);\n }\n return sessionTargetingMatch;\n};\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ILogger, ServerZone } from '@amplitude/analytics-core';
|
|
2
2
|
import { SessionReplayTrackDestination as AmplitudeSessionReplayTrackDestination, SessionReplayDestination, SessionReplayDestinationContext } from './typings/session-replay';
|
|
3
|
+
import { SessionReplaySendEventsHandler } from './config/types';
|
|
3
4
|
export type PayloadBatcher = ({ version, events }: {
|
|
4
5
|
version: number;
|
|
5
6
|
events: string[];
|
|
@@ -26,13 +27,15 @@ export declare class SessionReplayTrackDestination implements AmplitudeSessionRe
|
|
|
26
27
|
private coalesceNextFlush;
|
|
27
28
|
private mergeLogFiredThisPause;
|
|
28
29
|
private killedSessions;
|
|
29
|
-
|
|
30
|
+
private handleSendEvents?;
|
|
31
|
+
constructor({ trackServerUrl, loggerProvider, payloadBatcher, workerScript, enableTransportCompression, sendTimeoutMs, handleSendEvents, }: {
|
|
30
32
|
trackServerUrl?: string;
|
|
31
33
|
loggerProvider: ILogger;
|
|
32
34
|
payloadBatcher?: PayloadBatcher;
|
|
33
35
|
workerScript?: string;
|
|
34
36
|
enableTransportCompression?: boolean;
|
|
35
37
|
sendTimeoutMs?: number;
|
|
38
|
+
handleSendEvents?: SessionReplaySendEventsHandler;
|
|
36
39
|
});
|
|
37
40
|
sendEventsList(destinationData: SessionReplayDestination): void;
|
|
38
41
|
/**
|
|
@@ -99,6 +102,7 @@ export declare class SessionReplayTrackDestination implements AmplitudeSessionRe
|
|
|
99
102
|
send(context: SessionReplayDestinationContext, useRetry?: boolean): Promise<void>;
|
|
100
103
|
private sendViaWorker;
|
|
101
104
|
private rememberTimedOutRequest;
|
|
105
|
+
private handleDelegatedFetch;
|
|
102
106
|
private sendOnMainThread;
|
|
103
107
|
handleReponse(status: number, context: SessionReplayDestinationContext, responseBody?: string): Promise<void>;
|
|
104
108
|
handlePayloadTooLargeResponse(context: SessionReplayDestinationContext, isWaf: boolean): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-destination.d.ts","sourceRoot":"","sources":["../../src/track-destination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,OAAO,EAAE,UAAU,EAAU,MAAM,2BAA2B,CAAC;AAUvG,OAAO,EACL,6BAA6B,IAAI,sCAAsC,EACvE,wBAAwB,EACxB,+BAA+B,EAChC,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"track-destination.d.ts","sourceRoot":"","sources":["../../src/track-destination.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,9 +15,33 @@ var MAX_KILLED_SESSIONS = 256;
|
|
|
15
15
|
// In normal operation each entry is removed when the worker's late message arrives; this
|
|
16
16
|
// cap only guards the pathological case of a wedged worker that never replies at all.
|
|
17
17
|
var MAX_TIMED_OUT_WORKER_REQUESTS = 256;
|
|
18
|
+
// Settles with `promise`, but rejects early with an AbortError when `signal` fires. Used to apply
|
|
19
|
+
// the send timeout to a custom transport whose own promise can't be cancelled: a hung transport
|
|
20
|
+
// then surfaces as a retryable timeout (matching the built-in fetch and worker delegation paths)
|
|
21
|
+
// instead of blocking the serial flush loop. The transport's promise keeps running; we just stop
|
|
22
|
+
// awaiting it. `signal` is always supplied with the send-timeout controller's signal.
|
|
23
|
+
function abortable(promise, signal) {
|
|
24
|
+
return new Promise(function (resolve, reject) {
|
|
25
|
+
var onAbort = function () {
|
|
26
|
+
// Match how browsers reject an aborted fetch (DOMException 'AbortError'); sendOnMainThread's
|
|
27
|
+
// catch keys off the name to route it through the retry budget rather than failing fatally.
|
|
28
|
+
var err = new Error('Custom session replay transport aborted by send timeout');
|
|
29
|
+
err.name = 'AbortError';
|
|
30
|
+
reject(err);
|
|
31
|
+
};
|
|
32
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
33
|
+
promise.then(function (value) {
|
|
34
|
+
signal.removeEventListener('abort', onAbort);
|
|
35
|
+
resolve(value);
|
|
36
|
+
}, function (err) {
|
|
37
|
+
signal.removeEventListener('abort', onAbort);
|
|
38
|
+
reject(err);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
18
42
|
var SessionReplayTrackDestination = /** @class */ (function () {
|
|
19
43
|
function SessionReplayTrackDestination(_a) {
|
|
20
|
-
var trackServerUrl = _a.trackServerUrl, loggerProvider = _a.loggerProvider, payloadBatcher = _a.payloadBatcher, workerScript = _a.workerScript, enableTransportCompression = _a.enableTransportCompression, sendTimeoutMs = _a.sendTimeoutMs;
|
|
44
|
+
var trackServerUrl = _a.trackServerUrl, loggerProvider = _a.loggerProvider, payloadBatcher = _a.payloadBatcher, workerScript = _a.workerScript, enableTransportCompression = _a.enableTransportCompression, sendTimeoutMs = _a.sendTimeoutMs, handleSendEvents = _a.handleSendEvents;
|
|
21
45
|
var _this = this;
|
|
22
46
|
this.storageKey = '';
|
|
23
47
|
this.retryTimeout = 1000;
|
|
@@ -53,6 +77,7 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
53
77
|
this.trackServerUrl = trackServerUrl;
|
|
54
78
|
this.enableTransportCompression = enableTransportCompression !== null && enableTransportCompression !== void 0 ? enableTransportCompression : true;
|
|
55
79
|
this.sendTimeoutMs = sendTimeoutMs !== null && sendTimeoutMs !== void 0 ? sendTimeoutMs : constants_1.SEND_TIMEOUT_MS;
|
|
80
|
+
this.handleSendEvents = handleSendEvents;
|
|
56
81
|
if (workerScript) {
|
|
57
82
|
try {
|
|
58
83
|
var blob = new Blob([workerScript], { type: 'application/javascript' });
|
|
@@ -144,6 +169,16 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
144
169
|
}
|
|
145
170
|
}
|
|
146
171
|
}
|
|
172
|
+
else if (msg.type === 'fetch-request') {
|
|
173
|
+
// Worker is delegating one network attempt to the custom transport (which lives on
|
|
174
|
+
// the main thread). Run it and post the result back into the worker's retry loop.
|
|
175
|
+
// Guard the fire-and-forget call: if posting the result back fails (e.g. the worker
|
|
176
|
+
// was terminated mid-flight), surface it to the logger instead of leaving an
|
|
177
|
+
// unhandled rejection.
|
|
178
|
+
void _this.handleDelegatedFetch(worker_1, msg).catch(function (e) {
|
|
179
|
+
loggerProvider.warn('Failed to handle delegated session replay fetch:', e);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
147
182
|
};
|
|
148
183
|
this.worker = worker_1;
|
|
149
184
|
}
|
|
@@ -181,6 +216,7 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
181
216
|
* to cover the remaining incremental events since the last fetch flush.
|
|
182
217
|
*/
|
|
183
218
|
SessionReplayTrackDestination.prototype.sendBeacon = function (_a) {
|
|
219
|
+
var _this = this;
|
|
184
220
|
var _b, _c;
|
|
185
221
|
var events = _a.events, sessionId = _a.sessionId, deviceId = _a.deviceId, apiKey = _a.apiKey, serverZone = _a.serverZone;
|
|
186
222
|
var MAX_BEACON_BYTES = 64 * 1024;
|
|
@@ -208,6 +244,37 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
208
244
|
if (trimmedEvents.length === 0) {
|
|
209
245
|
return;
|
|
210
246
|
}
|
|
247
|
+
// Custom-transport page-exit path: navigator.sendBeacon cannot carry custom headers, so a
|
|
248
|
+
// JWT customer's exit batch would go out unauthenticated and be rejected by their proxy.
|
|
249
|
+
// Instead, route it through the callback with keepalive (which survives unload AND carries
|
|
250
|
+
// headers). Mirrors the main-send request shape: Authorization header + device_id/session_id/
|
|
251
|
+
// type params (api_key is NOT placed in the URL, unlike the legacy beacon path below).
|
|
252
|
+
if (this.handleSendEvents) {
|
|
253
|
+
var exitParams = new URLSearchParams({
|
|
254
|
+
device_id: deviceId,
|
|
255
|
+
session_id: String(sessionId),
|
|
256
|
+
type: 'replay',
|
|
257
|
+
});
|
|
258
|
+
var exitUrl = "".concat((0, helpers_1.getServerUrl)(serverZone, this.trackServerUrl), "?").concat(exitParams.toString());
|
|
259
|
+
var headers = {
|
|
260
|
+
'Content-Type': 'application/json',
|
|
261
|
+
Accept: '*/*',
|
|
262
|
+
Authorization: "Bearer ".concat(apiKey),
|
|
263
|
+
};
|
|
264
|
+
this.loggerProvider.debug("Routing session replay exit batch (".concat(trimmedEvents.length, " events) through custom transport for session id ").concat(sessionId, "."));
|
|
265
|
+
try {
|
|
266
|
+
// Fire-and-forget: we cannot await during unload. The request is well under 64 KB
|
|
267
|
+
// (trimmed above) and keepalive: true is requested so it survives page teardown.
|
|
268
|
+
void this.handleSendEvents({ url: exitUrl, method: 'POST', headers: headers, body: payload, keepalive: true }).catch(function (e) {
|
|
269
|
+
// best effort on exit, but still surface the failure so it's diagnosable in logs.
|
|
270
|
+
_this.loggerProvider.warn('Custom transport failed to send session replay exit batch:', e);
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
catch (e) {
|
|
274
|
+
this.loggerProvider.warn('Custom transport threw while sending session replay exit batch:', e);
|
|
275
|
+
}
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
211
278
|
var urlParams = new URLSearchParams({
|
|
212
279
|
device_id: deviceId,
|
|
213
280
|
session_id: String(sessionId),
|
|
@@ -576,6 +643,10 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
576
643
|
id: id,
|
|
577
644
|
payload: payload,
|
|
578
645
|
useRetry: useRetry,
|
|
646
|
+
// Tell the worker to delegate each network attempt back to the main thread, where the
|
|
647
|
+
// custom transport callback lives (functions can't cross postMessage). Absent/false
|
|
648
|
+
// keeps the worker's own internal fetch — the unchanged path for existing integrations.
|
|
649
|
+
useCustomTransport: !!_this.handleSendEvents,
|
|
579
650
|
context: {
|
|
580
651
|
apiKey: context.apiKey,
|
|
581
652
|
deviceId: context.deviceId,
|
|
@@ -619,12 +690,82 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
619
690
|
}
|
|
620
691
|
}
|
|
621
692
|
};
|
|
693
|
+
// Runs the custom transport on the main thread for a single attempt the worker delegated,
|
|
694
|
+
// then posts the result back into the worker's retry loop as a 'fetch-response'. We read only
|
|
695
|
+
// what the worker's status handling needs: the skip header on a 2xx and the body text on a
|
|
696
|
+
// 413 (for WAF detection). A thrown/rejected transport is reported as an error so the worker
|
|
697
|
+
// surfaces it the same way a thrown fetch would (no retry) — matching the main-thread path.
|
|
698
|
+
SessionReplayTrackDestination.prototype.handleDelegatedFetch = function (worker, msg) {
|
|
699
|
+
var _a, _b, _c;
|
|
700
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
701
|
+
var requestId, url, method, headers, body, keepalive, res, status_1, skipHeader, responseBody, _d, e_7;
|
|
702
|
+
return tslib_1.__generator(this, function (_e) {
|
|
703
|
+
switch (_e.label) {
|
|
704
|
+
case 0:
|
|
705
|
+
requestId = msg.requestId, url = msg.url, method = msg.method, headers = msg.headers, body = msg.body, keepalive = msg.keepalive;
|
|
706
|
+
_e.label = 1;
|
|
707
|
+
case 1:
|
|
708
|
+
_e.trys.push([1, 10, , 11]);
|
|
709
|
+
res = void 0;
|
|
710
|
+
if (!this.handleSendEvents) return [3 /*break*/, 3];
|
|
711
|
+
return [4 /*yield*/, this.handleSendEvents({ url: url, method: method, headers: headers, body: body, keepalive: keepalive })];
|
|
712
|
+
case 2:
|
|
713
|
+
res = _e.sent();
|
|
714
|
+
return [3 /*break*/, 5];
|
|
715
|
+
case 3:
|
|
716
|
+
// Defensive only: the worker emits 'fetch-request' solely when useCustomTransport is set,
|
|
717
|
+
// so this branch shouldn't be reachable. Warn so a regression that delegates without a
|
|
718
|
+
// transport is diagnosable rather than silently routing to the built-in fetch.
|
|
719
|
+
this.loggerProvider.warn('Delegated session replay fetch received without a custom transport configured; falling back to built-in fetch.');
|
|
720
|
+
return [4 /*yield*/, fetch(url, { method: method, headers: headers, body: body, keepalive: keepalive })];
|
|
721
|
+
case 4:
|
|
722
|
+
res = _e.sent();
|
|
723
|
+
_e.label = 5;
|
|
724
|
+
case 5:
|
|
725
|
+
status_1 = res.status;
|
|
726
|
+
skipHeader = null;
|
|
727
|
+
responseBody = '';
|
|
728
|
+
if (status_1 >= 200 && status_1 < 300) {
|
|
729
|
+
skipHeader = (_c = (_b = (_a = res.headers) === null || _a === void 0 ? void 0 : _a.get) === null || _b === void 0 ? void 0 : _b.call(_a, constants_1.EVENT_SKIPPED_HEADER)) !== null && _c !== void 0 ? _c : null;
|
|
730
|
+
}
|
|
731
|
+
if (!(status_1 === 413)) return [3 /*break*/, 9];
|
|
732
|
+
_e.label = 6;
|
|
733
|
+
case 6:
|
|
734
|
+
_e.trys.push([6, 8, , 9]);
|
|
735
|
+
return [4 /*yield*/, res.text()];
|
|
736
|
+
case 7:
|
|
737
|
+
responseBody = _e.sent();
|
|
738
|
+
return [3 /*break*/, 9];
|
|
739
|
+
case 8:
|
|
740
|
+
_d = _e.sent();
|
|
741
|
+
return [3 /*break*/, 9];
|
|
742
|
+
case 9:
|
|
743
|
+
this.loggerProvider.debug("Delegated session replay fetch (request ".concat(requestId, ") returned status ").concat(status_1, "."));
|
|
744
|
+
worker.postMessage({ type: 'fetch-response', requestId: requestId, status: status_1, skipHeader: skipHeader, body: responseBody });
|
|
745
|
+
return [3 /*break*/, 11];
|
|
746
|
+
case 10:
|
|
747
|
+
e_7 = _e.sent();
|
|
748
|
+
this.loggerProvider.debug("Delegated session replay fetch (request ".concat(requestId, ") failed:"), e_7);
|
|
749
|
+
worker.postMessage({
|
|
750
|
+
type: 'fetch-response',
|
|
751
|
+
requestId: requestId,
|
|
752
|
+
status: 0,
|
|
753
|
+
skipHeader: null,
|
|
754
|
+
body: String(e_7),
|
|
755
|
+
error: true,
|
|
756
|
+
});
|
|
757
|
+
return [3 /*break*/, 11];
|
|
758
|
+
case 11: return [2 /*return*/];
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
});
|
|
762
|
+
};
|
|
622
763
|
SessionReplayTrackDestination.prototype.sendOnMainThread = function (apiKey, deviceId, context, payload, useRetry) {
|
|
623
764
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
624
765
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
625
|
-
var url, version, sampleRate, urlParams, sessionReplayLibrary, payloadJson, globalScope, gzipped, _h, payloadSize, controller_1, options, serverUrl, sendTimeout, res, skipCode, responseBody, responseBody,
|
|
626
|
-
return tslib_1.__generator(this, function (
|
|
627
|
-
switch (
|
|
766
|
+
var url, version, sampleRate, urlParams, sessionReplayLibrary, payloadJson, globalScope, gzipped, _h, payloadSize, controller_1, headers, body, keepalive, options, serverUrl, sendTimeout, res, _j, skipCode, responseBody, responseBody, _k, e_8, isAbort;
|
|
767
|
+
return tslib_1.__generator(this, function (_l) {
|
|
768
|
+
switch (_l.label) {
|
|
628
769
|
case 0:
|
|
629
770
|
url = (0, helpers_1.getCurrentUrl)();
|
|
630
771
|
version = version_1.VERSION;
|
|
@@ -635,30 +776,31 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
635
776
|
type: "".concat(context.type),
|
|
636
777
|
});
|
|
637
778
|
sessionReplayLibrary = "".concat((_b = (_a = context.version) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : 'standalone', "/").concat((_d = (_c = context.version) === null || _c === void 0 ? void 0 : _c.version) !== null && _d !== void 0 ? _d : version);
|
|
638
|
-
|
|
779
|
+
_l.label = 1;
|
|
639
780
|
case 1:
|
|
640
|
-
|
|
781
|
+
_l.trys.push([1, 19, , 23]);
|
|
641
782
|
payloadJson = JSON.stringify(payload);
|
|
642
783
|
globalScope = (0, analytics_core_1.getGlobalScope)();
|
|
643
784
|
if (!(this.enableTransportCompression && globalScope && 'CompressionStream' in globalScope)) return [3 /*break*/, 3];
|
|
644
785
|
return [4 /*yield*/, (0, gzip_1.gzipJson)(payloadJson, globalScope)];
|
|
645
786
|
case 2:
|
|
646
|
-
_h =
|
|
787
|
+
_h = _l.sent();
|
|
647
788
|
return [3 /*break*/, 4];
|
|
648
789
|
case 3:
|
|
649
790
|
_h = null;
|
|
650
|
-
|
|
791
|
+
_l.label = 4;
|
|
651
792
|
case 4:
|
|
652
793
|
gzipped = _h;
|
|
653
794
|
payloadSize = gzipped ? gzipped.byteLength : new Blob([payloadJson]).size;
|
|
654
795
|
controller_1 = new AbortController();
|
|
796
|
+
headers = tslib_1.__assign({ 'Content-Type': 'application/json', Accept: '*/*', Authorization: "Bearer ".concat(apiKey), 'X-Client-Version': version, 'X-Client-Library': sessionReplayLibrary, 'X-Client-Url': url.substring(0, constants_1.MAX_URL_LENGTH), 'X-Client-Sample-Rate': "".concat(sampleRate), 'X-Sampling-Hash-Alg': 'xxhash32' }, (gzipped ? { 'Content-Encoding': 'gzip' } : {}));
|
|
797
|
+
body = gzipped !== null && gzipped !== void 0 ? gzipped : payloadJson;
|
|
798
|
+
keepalive = payloadSize <= constants_1.MAX_KEEPALIVE_BYTES;
|
|
655
799
|
options = {
|
|
656
|
-
headers:
|
|
657
|
-
body:
|
|
800
|
+
headers: headers,
|
|
801
|
+
body: body,
|
|
658
802
|
method: 'POST',
|
|
659
|
-
|
|
660
|
-
// Must stay under the browser's 64 KB keepalive budget; large payloads skip it.
|
|
661
|
-
keepalive: payloadSize <= constants_1.MAX_KEEPALIVE_BYTES,
|
|
803
|
+
keepalive: keepalive,
|
|
662
804
|
signal: controller_1.signal,
|
|
663
805
|
};
|
|
664
806
|
serverUrl = "".concat((0, helpers_1.getServerUrl)(context.serverZone, this.trackServerUrl), "?").concat(urlParams.toString());
|
|
@@ -677,20 +819,35 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
677
819
|
}, this.sendTimeoutMs)
|
|
678
820
|
: undefined;
|
|
679
821
|
res = void 0;
|
|
680
|
-
|
|
822
|
+
_l.label = 5;
|
|
681
823
|
case 5:
|
|
682
|
-
|
|
683
|
-
return [
|
|
824
|
+
_l.trys.push([5, , 10, 11]);
|
|
825
|
+
if (!this.handleSendEvents) return [3 /*break*/, 7];
|
|
826
|
+
return [4 /*yield*/, abortable(this.handleSendEvents({ url: serverUrl, method: 'POST', headers: headers, body: body, keepalive: keepalive }), controller_1.signal)];
|
|
684
827
|
case 6:
|
|
685
|
-
|
|
686
|
-
return [3 /*break*/,
|
|
687
|
-
case 7:
|
|
828
|
+
_j = _l.sent();
|
|
829
|
+
return [3 /*break*/, 9];
|
|
830
|
+
case 7: return [4 /*yield*/, fetch(serverUrl, options)];
|
|
831
|
+
case 8:
|
|
832
|
+
_j = _l.sent();
|
|
833
|
+
_l.label = 9;
|
|
834
|
+
case 9:
|
|
835
|
+
// When a custom transport is configured, hand it the fully-formed request and let it own
|
|
836
|
+
// the network call (e.g. to attach a JWT and route through a proxy). Otherwise use the
|
|
837
|
+
// built-in fetch. Retry/response handling below is identical for both paths. The built-in
|
|
838
|
+
// fetch cancels directly on controller.signal; the custom callback can't be cancelled, so
|
|
839
|
+
// we race it against the abort — a hung/never-settling transport then rejects with an
|
|
840
|
+
// AbortError (retryable, like the worker delegation path) instead of blocking the serial
|
|
841
|
+
// flush loop forever. The callback's own promise keeps running; we just stop awaiting it.
|
|
842
|
+
res = _j;
|
|
843
|
+
return [3 /*break*/, 11];
|
|
844
|
+
case 10:
|
|
688
845
|
// Clear on success and on error alike so a settled request never leaves an armed
|
|
689
846
|
// timer that would abort a later reused controller or fire a stray callback.
|
|
690
847
|
if (sendTimeout)
|
|
691
848
|
clearTimeout(sendTimeout);
|
|
692
849
|
return [7 /*endfinally*/];
|
|
693
|
-
case
|
|
850
|
+
case 11:
|
|
694
851
|
if (res === null) {
|
|
695
852
|
this.completeRequest({ context: context, err: messages_1.UNEXPECTED_ERROR_MESSAGE });
|
|
696
853
|
return [2 /*return*/];
|
|
@@ -699,47 +856,47 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
699
856
|
skipCode = (_g = (_f = (_e = res.headers) === null || _e === void 0 ? void 0 : _e.get) === null || _f === void 0 ? void 0 : _f.call(_e, constants_1.EVENT_SKIPPED_HEADER)) !== null && _g !== void 0 ? _g : null;
|
|
700
857
|
this.applyServerDirective(context.sessionId, skipCode);
|
|
701
858
|
}
|
|
702
|
-
if (!!useRetry) return [3 /*break*/,
|
|
859
|
+
if (!!useRetry) return [3 /*break*/, 12];
|
|
703
860
|
responseBody = '';
|
|
704
861
|
try {
|
|
705
862
|
responseBody = JSON.stringify(res.body, null, 2);
|
|
706
863
|
}
|
|
707
|
-
catch (
|
|
864
|
+
catch (_m) {
|
|
708
865
|
// to avoid crash, but don't care about the error, add comment to avoid empty block lint error
|
|
709
866
|
}
|
|
710
867
|
this.completeRequest({ context: context, success: "".concat(res.status, ": ").concat(responseBody) });
|
|
711
|
-
return [3 /*break*/,
|
|
712
|
-
case
|
|
868
|
+
return [3 /*break*/, 18];
|
|
869
|
+
case 12:
|
|
713
870
|
responseBody = '';
|
|
714
|
-
if (!(res.status === 413)) return [3 /*break*/,
|
|
715
|
-
|
|
716
|
-
case
|
|
717
|
-
|
|
871
|
+
if (!(res.status === 413)) return [3 /*break*/, 16];
|
|
872
|
+
_l.label = 13;
|
|
873
|
+
case 13:
|
|
874
|
+
_l.trys.push([13, 15, , 16]);
|
|
718
875
|
return [4 /*yield*/, res.text()];
|
|
719
|
-
case 11:
|
|
720
|
-
responseBody = _k.sent();
|
|
721
|
-
return [3 /*break*/, 13];
|
|
722
|
-
case 12:
|
|
723
|
-
_j = _k.sent();
|
|
724
|
-
return [3 /*break*/, 13];
|
|
725
|
-
case 13: return [4 /*yield*/, this.handleReponse(res.status, context, responseBody)];
|
|
726
876
|
case 14:
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
case 15:
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
if (!(isAbort && useRetry)) return [3 /*break*/, 18];
|
|
734
|
-
return [4 /*yield*/, this.handleOtherResponse(context)];
|
|
877
|
+
responseBody = _l.sent();
|
|
878
|
+
return [3 /*break*/, 16];
|
|
879
|
+
case 15:
|
|
880
|
+
_k = _l.sent();
|
|
881
|
+
return [3 /*break*/, 16];
|
|
882
|
+
case 16: return [4 /*yield*/, this.handleReponse(res.status, context, responseBody)];
|
|
735
883
|
case 17:
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
case 18:
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
884
|
+
_l.sent();
|
|
885
|
+
_l.label = 18;
|
|
886
|
+
case 18: return [3 /*break*/, 23];
|
|
887
|
+
case 19:
|
|
888
|
+
e_8 = _l.sent();
|
|
889
|
+
isAbort = !!e_8 && typeof e_8 === 'object' && e_8.name === 'AbortError';
|
|
890
|
+
if (!(isAbort && useRetry)) return [3 /*break*/, 21];
|
|
891
|
+
return [4 /*yield*/, this.handleOtherResponse(context)];
|
|
892
|
+
case 20:
|
|
893
|
+
_l.sent();
|
|
894
|
+
return [3 /*break*/, 22];
|
|
895
|
+
case 21:
|
|
896
|
+
this.completeRequest({ context: context, err: e_8 });
|
|
897
|
+
_l.label = 22;
|
|
898
|
+
case 22: return [3 /*break*/, 23];
|
|
899
|
+
case 23: return [2 /*return*/];
|
|
743
900
|
}
|
|
744
901
|
});
|
|
745
902
|
});
|
|
@@ -893,7 +1050,7 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
893
1050
|
// session for a code we don't recognize.
|
|
894
1051
|
};
|
|
895
1052
|
SessionReplayTrackDestination.prototype.killSession = function (sessionId, skipCode) {
|
|
896
|
-
var
|
|
1053
|
+
var e_9, _a, e_10, _b;
|
|
897
1054
|
if (this.killedSessions.has(sessionId))
|
|
898
1055
|
return;
|
|
899
1056
|
this.killedSessions.add(sessionId);
|
|
@@ -906,12 +1063,12 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
906
1063
|
break;
|
|
907
1064
|
}
|
|
908
1065
|
}
|
|
909
|
-
catch (
|
|
1066
|
+
catch (e_9_1) { e_9 = { error: e_9_1 }; }
|
|
910
1067
|
finally {
|
|
911
1068
|
try {
|
|
912
1069
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
913
1070
|
}
|
|
914
|
-
finally { if (
|
|
1071
|
+
finally { if (e_9) throw e_9.error; }
|
|
915
1072
|
}
|
|
916
1073
|
}
|
|
917
1074
|
this.loggerProvider.log("Session replay capture stopped for session ".concat(sessionId, " by server directive ").concat(skipCode, "; remaining events will be dropped"));
|
|
@@ -929,12 +1086,12 @@ var SessionReplayTrackDestination = /** @class */ (function () {
|
|
|
929
1086
|
}
|
|
930
1087
|
}
|
|
931
1088
|
}
|
|
932
|
-
catch (
|
|
1089
|
+
catch (e_10_1) { e_10 = { error: e_10_1 }; }
|
|
933
1090
|
finally {
|
|
934
1091
|
try {
|
|
935
1092
|
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
|
|
936
1093
|
}
|
|
937
|
-
finally { if (
|
|
1094
|
+
finally { if (e_10) throw e_10.error; }
|
|
938
1095
|
}
|
|
939
1096
|
this.queue = remaining;
|
|
940
1097
|
};
|