@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.
Files changed (100) hide show
  1. package/README.md +203 -0
  2. package/lib/cjs/beacon-transport.d.ts +2 -0
  3. package/lib/cjs/beacon-transport.d.ts.map +1 -1
  4. package/lib/cjs/beacon-transport.js +39 -1
  5. package/lib/cjs/beacon-transport.js.map +1 -1
  6. package/lib/cjs/config/joined-config.d.ts +1 -6
  7. package/lib/cjs/config/joined-config.d.ts.map +1 -1
  8. package/lib/cjs/config/joined-config.js +23 -64
  9. package/lib/cjs/config/joined-config.js.map +1 -1
  10. package/lib/cjs/config/local-config.d.ts +4 -6
  11. package/lib/cjs/config/local-config.d.ts.map +1 -1
  12. package/lib/cjs/config/local-config.js +3 -19
  13. package/lib/cjs/config/local-config.js.map +1 -1
  14. package/lib/cjs/config/types.d.ts +74 -19
  15. package/lib/cjs/config/types.d.ts.map +1 -1
  16. package/lib/cjs/config/types.js.map +1 -1
  17. package/lib/cjs/index.d.ts +1 -0
  18. package/lib/cjs/index.d.ts.map +1 -1
  19. package/lib/cjs/index.js.map +1 -1
  20. package/lib/cjs/plugins/url-tracking-plugin.d.ts +0 -13
  21. package/lib/cjs/plugins/url-tracking-plugin.d.ts.map +1 -1
  22. package/lib/cjs/plugins/url-tracking-plugin.js +2 -6
  23. package/lib/cjs/plugins/url-tracking-plugin.js.map +1 -1
  24. package/lib/cjs/session-replay.d.ts +0 -33
  25. package/lib/cjs/session-replay.d.ts.map +1 -1
  26. package/lib/cjs/session-replay.js +40 -339
  27. package/lib/cjs/session-replay.js.map +1 -1
  28. package/lib/cjs/targeting/targeting-manager.d.ts +1 -4
  29. package/lib/cjs/targeting/targeting-manager.d.ts.map +1 -1
  30. package/lib/cjs/targeting/targeting-manager.js +10 -56
  31. package/lib/cjs/targeting/targeting-manager.js.map +1 -1
  32. package/lib/cjs/track-destination.d.ts +5 -1
  33. package/lib/cjs/track-destination.d.ts.map +1 -1
  34. package/lib/cjs/track-destination.js +212 -55
  35. package/lib/cjs/track-destination.js.map +1 -1
  36. package/lib/cjs/version.d.ts +1 -1
  37. package/lib/cjs/version.d.ts.map +1 -1
  38. package/lib/cjs/version.js +1 -1
  39. package/lib/cjs/version.js.map +1 -1
  40. package/lib/cjs/worker/index.js +1 -1
  41. package/lib/esm/beacon-transport.d.ts +2 -0
  42. package/lib/esm/beacon-transport.d.ts.map +1 -1
  43. package/lib/esm/beacon-transport.js +39 -1
  44. package/lib/esm/beacon-transport.js.map +1 -1
  45. package/lib/esm/config/joined-config.d.ts +1 -6
  46. package/lib/esm/config/joined-config.d.ts.map +1 -1
  47. package/lib/esm/config/joined-config.js +23 -64
  48. package/lib/esm/config/joined-config.js.map +1 -1
  49. package/lib/esm/config/local-config.d.ts +4 -6
  50. package/lib/esm/config/local-config.d.ts.map +1 -1
  51. package/lib/esm/config/local-config.js +4 -20
  52. package/lib/esm/config/local-config.js.map +1 -1
  53. package/lib/esm/config/types.d.ts +74 -19
  54. package/lib/esm/config/types.d.ts.map +1 -1
  55. package/lib/esm/config/types.js.map +1 -1
  56. package/lib/esm/index.d.ts +1 -0
  57. package/lib/esm/index.d.ts.map +1 -1
  58. package/lib/esm/index.js.map +1 -1
  59. package/lib/esm/plugins/url-tracking-plugin.d.ts +0 -13
  60. package/lib/esm/plugins/url-tracking-plugin.d.ts.map +1 -1
  61. package/lib/esm/plugins/url-tracking-plugin.js +2 -6
  62. package/lib/esm/plugins/url-tracking-plugin.js.map +1 -1
  63. package/lib/esm/session-replay.d.ts +0 -33
  64. package/lib/esm/session-replay.d.ts.map +1 -1
  65. package/lib/esm/session-replay.js +40 -339
  66. package/lib/esm/session-replay.js.map +1 -1
  67. package/lib/esm/targeting/targeting-manager.d.ts +1 -4
  68. package/lib/esm/targeting/targeting-manager.d.ts.map +1 -1
  69. package/lib/esm/targeting/targeting-manager.js +10 -56
  70. package/lib/esm/targeting/targeting-manager.js.map +1 -1
  71. package/lib/esm/track-destination.d.ts +5 -1
  72. package/lib/esm/track-destination.d.ts.map +1 -1
  73. package/lib/esm/track-destination.js +212 -55
  74. package/lib/esm/track-destination.js.map +1 -1
  75. package/lib/esm/version.d.ts +1 -1
  76. package/lib/esm/version.d.ts.map +1 -1
  77. package/lib/esm/version.js +1 -1
  78. package/lib/esm/version.js.map +1 -1
  79. package/lib/esm/worker/index.js +1 -1
  80. package/lib/scripts/index-min.js +1 -1
  81. package/lib/scripts/index-min.js.gz +0 -0
  82. package/lib/scripts/index-min.js.map +1 -1
  83. package/lib/scripts/observers-min.js +1 -1
  84. package/lib/scripts/observers-min.js.gz +0 -0
  85. package/lib/scripts/session-replay-browser-min.js +1 -1
  86. package/lib/scripts/session-replay-browser-min.js.gz +0 -0
  87. package/lib/scripts/session-replay-browser-min.js.map +1 -1
  88. package/lib/scripts/targeting-min.js +1 -1
  89. package/lib/scripts/targeting-min.js.gz +0 -0
  90. package/lib/scripts/worker-min.js +1 -1
  91. package/lib/scripts/worker-min.js.gz +0 -0
  92. package/package.json +4 -4
  93. package/lib/cjs/diagnostics.d.ts +0 -50
  94. package/lib/cjs/diagnostics.d.ts.map +0 -1
  95. package/lib/cjs/diagnostics.js +0 -67
  96. package/lib/cjs/diagnostics.js.map +0 -1
  97. package/lib/esm/diagnostics.d.ts +0 -50
  98. package/lib/esm/diagnostics.d.ts.map +0 -1
  99. package/lib/esm/diagnostics.js +0 -64
  100. 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":"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","sourcesContent":["import type { TargetingParameters } from '@amplitude/targeting';\nimport { TargetingConfig } from '../config/types';\nimport { Logger } from '@amplitude/analytics-types';\nimport { IDiagnosticsClient } from '@amplitude/analytics-core';\nimport { SessionReplayTargetingInput } from '../typings/session-replay';\nimport { targetingIDBStore } from './targeting-idb-store';\nimport { SrDiagnostic } from '../diagnostics';\n\nexport const evaluateTargetingAndStore = async ({\n sessionId,\n targetingConfig,\n loggerProvider,\n apiKey,\n targetingParams,\n urlChange = false,\n diagnosticsClient,\n deviceId,\n}: {\n sessionId: string | number;\n targetingConfig: TargetingConfig;\n loggerProvider: Logger;\n apiKey: string;\n targetingParams?: SessionReplayTargetingInput;\n urlChange?: boolean;\n diagnosticsClient?: IDiagnosticsClient;\n deviceId?: string;\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\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 diagnosticsClient?.recordEvent(SrDiagnostic.targetingTrigger, {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n pageUrl: targetingParams?.page?.url,\n matched: sessionTargetingMatch,\n targetingConfig: targetingConfig,\n });\n const targetingResult = await evaluateTargetingPackage(params);\n if (targetingResult && targetingResult.sr_targeting_config) {\n sessionTargetingMatch = targetingResult.sr_targeting_config.key === 'on';\n }\n // gap #2: the raw engine verdict. variantKey 'on' => matched; 'off'/undefined => not.\n // Pair with the eval event's pageUrl to tell \"URL condition didn't match\" from \"URL matched\n // but the segment bucket (capture %) didn't allocate this session\".\n try {\n diagnosticsClient?.recordEvent(SrDiagnostic.evalResult, {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n pageUrl: targetingParams?.page?.url,\n variantKey: targetingResult?.sr_targeting_config?.key ?? null,\n matched: sessionTargetingMatch,\n targetingConfig: targetingConfig,\n });\n // Flush now so the verdict ships immediately (vs the client's ~5-min timer). One capture\n // POST per event — higher volume; revisit/gate before production.\n void diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\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 // Q3 \"is the TRC failing?\": the targeting engine threw — record it so the team sees TRC\n // errors in DataDog (this exception is otherwise swallowed). Best-effort, never re-throws.\n try {\n diagnosticsClient?.increment(SrDiagnostic.evalError);\n diagnosticsClient?.recordEvent(SrDiagnostic.evalError, {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n pageUrl: targetingParams?.page?.url,\n message: knownError.message,\n });\n void diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\n }\n loggerProvider.warn(knownError.message);\n }\n return sessionTargetingMatch;\n};\n"]}
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
- constructor({ trackServerUrl, loggerProvider, payloadBatcher, workerScript, enableTransportCompression, sendTimeoutMs, }: {
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":"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"}
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, _j, e_7, isAbort;
626
- return tslib_1.__generator(this, function (_k) {
627
- switch (_k.label) {
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
- _k.label = 1;
779
+ _l.label = 1;
639
780
  case 1:
640
- _k.trys.push([1, 16, , 20]);
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 = _k.sent();
787
+ _h = _l.sent();
647
788
  return [3 /*break*/, 4];
648
789
  case 3:
649
790
  _h = null;
650
- _k.label = 4;
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: 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' } : {})),
657
- body: (gzipped !== null && gzipped !== void 0 ? gzipped : payloadJson),
800
+ headers: headers,
801
+ body: body,
658
802
  method: 'POST',
659
- // keepalive lets the request survive page navigation, preventing 499 (client-closed) errors.
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
- _k.label = 5;
822
+ _l.label = 5;
681
823
  case 5:
682
- _k.trys.push([5, , 7, 8]);
683
- return [4 /*yield*/, fetch(serverUrl, options)];
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
- res = _k.sent();
686
- return [3 /*break*/, 8];
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 8:
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*/, 9];
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 (_l) {
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*/, 15];
712
- case 9:
868
+ return [3 /*break*/, 18];
869
+ case 12:
713
870
  responseBody = '';
714
- if (!(res.status === 413)) return [3 /*break*/, 13];
715
- _k.label = 10;
716
- case 10:
717
- _k.trys.push([10, 12, , 13]);
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
- _k.sent();
728
- _k.label = 15;
729
- case 15: return [3 /*break*/, 20];
730
- case 16:
731
- e_7 = _k.sent();
732
- isAbort = !!e_7 && typeof e_7 === 'object' && e_7.name === 'AbortError';
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
- _k.sent();
737
- return [3 /*break*/, 19];
738
- case 18:
739
- this.completeRequest({ context: context, err: e_7 });
740
- _k.label = 19;
741
- case 19: return [3 /*break*/, 20];
742
- case 20: return [2 /*return*/];
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 e_8, _a, e_9, _b;
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 (e_8_1) { e_8 = { error: e_8_1 }; }
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 (e_8) throw e_8.error; }
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 (e_9_1) { e_9 = { error: e_9_1 }; }
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 (e_9) throw e_9.error; }
1094
+ finally { if (e_10) throw e_10.error; }
938
1095
  }
939
1096
  this.queue = remaining;
940
1097
  };