@amplitude/session-replay-browser 1.47.0-sr-trc-debug-log.2 → 1.47.0-sr-trc-debug-log.3
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/lib/cjs/diagnostics.d.ts +2 -0
- package/lib/cjs/diagnostics.d.ts.map +1 -1
- package/lib/cjs/diagnostics.js +4 -1
- package/lib/cjs/diagnostics.js.map +1 -1
- package/lib/cjs/plugins/url-tracking-plugin.d.ts +7 -0
- package/lib/cjs/plugins/url-tracking-plugin.d.ts.map +1 -1
- package/lib/cjs/plugins/url-tracking-plugin.js +5 -3
- package/lib/cjs/plugins/url-tracking-plugin.js.map +1 -1
- package/lib/cjs/session-replay.d.ts +1 -0
- package/lib/cjs/session-replay.d.ts.map +1 -1
- package/lib/cjs/session-replay.js +15 -0
- package/lib/cjs/session-replay.js.map +1 -1
- package/lib/cjs/version.d.ts +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/cjs/version.js.map +1 -1
- package/lib/esm/diagnostics.d.ts +2 -0
- package/lib/esm/diagnostics.d.ts.map +1 -1
- package/lib/esm/diagnostics.js +4 -1
- package/lib/esm/diagnostics.js.map +1 -1
- package/lib/esm/plugins/url-tracking-plugin.d.ts +7 -0
- package/lib/esm/plugins/url-tracking-plugin.d.ts.map +1 -1
- package/lib/esm/plugins/url-tracking-plugin.js +5 -3
- package/lib/esm/plugins/url-tracking-plugin.js.map +1 -1
- package/lib/esm/session-replay.d.ts +1 -0
- package/lib/esm/session-replay.d.ts.map +1 -1
- package/lib/esm/session-replay.js +15 -0
- package/lib/esm/session-replay.js.map +1 -1
- package/lib/esm/version.d.ts +1 -1
- package/lib/esm/version.js +1 -1
- package/lib/esm/version.js.map +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/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/package.json +3 -3
package/lib/cjs/diagnostics.d.ts
CHANGED
|
@@ -44,5 +44,7 @@ export declare const SrDiagnostic: {
|
|
|
44
44
|
readonly urlListenerSetup: "sr.trc.url_listener.setup";
|
|
45
45
|
readonly urlListenerAttached: "sr.trc.url_listener.attached";
|
|
46
46
|
readonly urlListenerSkipped: "sr.trc.url_listener.skipped";
|
|
47
|
+
readonly urlPollTick: "sr.trc.url_poll.tick";
|
|
48
|
+
readonly urlPollFirstTick: "sr.trc.url_poll.first_tick";
|
|
47
49
|
};
|
|
48
50
|
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAI7C,eAAO,MAAM,YAAY;;;oCAUA,MAAM;;;;;;oCAUN,MAAM
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAI7C,eAAO,MAAM,YAAY;;;oCAUA,MAAM;;;;;;oCAUN,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCrB,CAAC"}
|
package/lib/cjs/diagnostics.js
CHANGED
|
@@ -59,6 +59,9 @@ exports.SrDiagnostic = {
|
|
|
59
59
|
// because the listener was never attached — e.g. no targeting config, or no global scope.)
|
|
60
60
|
urlListenerSetup: "".concat(p, ".url_listener.setup"),
|
|
61
61
|
urlListenerAttached: "".concat(p, ".url_listener.attached"),
|
|
62
|
-
urlListenerSkipped: "".concat(p, ".url_listener.skipped"),
|
|
62
|
+
urlListenerSkipped: "".concat(p, ".url_listener.skipped"),
|
|
63
|
+
// Proof the polling loop actually FIRES (not just that it was scheduled by url_listener.attached).
|
|
64
|
+
urlPollTick: "".concat(p, ".url_poll.tick"),
|
|
65
|
+
urlPollFirstTick: "".concat(p, ".url_poll.first_tick"), // event: once per session on the first tick (carries href)
|
|
63
66
|
};
|
|
64
67
|
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/diagnostics.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;GAQG;AACU,QAAA,oBAAoB,GAAG,QAAQ,CAAC;AAE7C,IAAM,CAAC,GAAG,4BAAoB,CAAC;AAElB,QAAA,YAAY,GAAG;IAC1B,4EAA4E;IAC5E,IAAI,EAAE,UAAG,CAAC,UAAO;IAEjB,4EAA4E;IAC5E,4FAA4F;IAC5F,sFAAsF;IACtF,cAAc,EAAE,UAAG,CAAC,qBAAkB;IAEtC,4EAA4E;IAC5E,YAAY,EAAE,UAAC,MAAc,IAAK,OAAA,UAAG,CAAC,4BAAkB,MAAM,CAAE,EAA9B,CAA8B;IAChE,kBAAkB,EAAE,UAAG,CAAC,0BAAuB;IAC/C,iBAAiB,EAAE,UAAG,CAAC,yBAAsB;IAC7C,iBAAiB,EAAE,UAAG,CAAC,yBAAsB;IAC7C,cAAc,EAAE,UAAG,CAAC,qBAAkB;IAEtC,gBAAgB,EAAE,UAAG,CAAC,uBAAoB;IAE1C,6EAA6E;IAC7E,kFAAkF;IAClF,WAAW,EAAE,UAAC,OAAe,IAAK,OAAA,UAAG,CAAC,mBAAS,OAAO,CAAE,EAAtB,CAAsB;IACxD,YAAY,EAAE,UAAG,CAAC,oBAAiB;IACnC,iBAAiB,EAAE,UAAG,CAAC,yBAAsB;IAC7C,SAAS,EAAE,UAAG,CAAC,gBAAa;IAC5B,WAAW,EAAE,UAAG,CAAC,mBAAgB;IACjC,SAAS,EAAE,UAAG,CAAC,gBAAa;IAC5B,kBAAkB,EAAE,UAAG,CAAC,0BAAuB;IAC/C,yBAAyB,EAAE,UAAG,CAAC,kCAA+B;IAC9D,cAAc,EAAE,UAAG,CAAC,sBAAmB;IACvC,SAAS,EAAE,UAAG,CAAC,UAAO;IACtB,UAAU,EAAE,UAAG,CAAC,iBAAc;IAE9B,mFAAmF;IACnF,aAAa,EAAE,UAAG,CAAC,oBAAiB;IACpC,gBAAgB,EAAE,UAAG,CAAC,yBAAsB;IAC5C,yBAAyB,EAAE,UAAG,CAAC,kCAA+B;IAE9D,4EAA4E;IAC5E,iBAAiB,EAAE,UAAG,CAAC,yBAAsB;IAC7C,mBAAmB,EAAE,UAAG,CAAC,2BAAwB;IACjD,UAAU,EAAE,UAAG,CAAC,iBAAc;IAC9B,YAAY,EAAE,UAAG,CAAC,oBAAiB;IACnC,cAAc,EAAE,UAAG,CAAC,uBAAoB;IACxC,YAAY,EAAE,UAAG,CAAC,oBAAiB;IACnC,aAAa,EAAE,UAAG,CAAC,qBAAkB;IACrC,QAAQ,EAAE,UAAG,CAAC,cAAW;IAEzB,4EAA4E;IAC5E,SAAS,EAAE,UAAG,CAAC,gBAAa;IAC5B,cAAc,EAAE,UAAG,CAAC,gBAAa;IACjC,wFAAwF;IACxF,2FAA2F;IAC3F,gBAAgB,EAAE,UAAG,CAAC,wBAAqB;IAC3C,mBAAmB,EAAE,UAAG,CAAC,2BAAwB;IACjD,kBAAkB,EAAE,UAAG,CAAC,0BAAuB,EAAE,
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/diagnostics.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;GAQG;AACU,QAAA,oBAAoB,GAAG,QAAQ,CAAC;AAE7C,IAAM,CAAC,GAAG,4BAAoB,CAAC;AAElB,QAAA,YAAY,GAAG;IAC1B,4EAA4E;IAC5E,IAAI,EAAE,UAAG,CAAC,UAAO;IAEjB,4EAA4E;IAC5E,4FAA4F;IAC5F,sFAAsF;IACtF,cAAc,EAAE,UAAG,CAAC,qBAAkB;IAEtC,4EAA4E;IAC5E,YAAY,EAAE,UAAC,MAAc,IAAK,OAAA,UAAG,CAAC,4BAAkB,MAAM,CAAE,EAA9B,CAA8B;IAChE,kBAAkB,EAAE,UAAG,CAAC,0BAAuB;IAC/C,iBAAiB,EAAE,UAAG,CAAC,yBAAsB;IAC7C,iBAAiB,EAAE,UAAG,CAAC,yBAAsB;IAC7C,cAAc,EAAE,UAAG,CAAC,qBAAkB;IAEtC,gBAAgB,EAAE,UAAG,CAAC,uBAAoB;IAE1C,6EAA6E;IAC7E,kFAAkF;IAClF,WAAW,EAAE,UAAC,OAAe,IAAK,OAAA,UAAG,CAAC,mBAAS,OAAO,CAAE,EAAtB,CAAsB;IACxD,YAAY,EAAE,UAAG,CAAC,oBAAiB;IACnC,iBAAiB,EAAE,UAAG,CAAC,yBAAsB;IAC7C,SAAS,EAAE,UAAG,CAAC,gBAAa;IAC5B,WAAW,EAAE,UAAG,CAAC,mBAAgB;IACjC,SAAS,EAAE,UAAG,CAAC,gBAAa;IAC5B,kBAAkB,EAAE,UAAG,CAAC,0BAAuB;IAC/C,yBAAyB,EAAE,UAAG,CAAC,kCAA+B;IAC9D,cAAc,EAAE,UAAG,CAAC,sBAAmB;IACvC,SAAS,EAAE,UAAG,CAAC,UAAO;IACtB,UAAU,EAAE,UAAG,CAAC,iBAAc;IAE9B,mFAAmF;IACnF,aAAa,EAAE,UAAG,CAAC,oBAAiB;IACpC,gBAAgB,EAAE,UAAG,CAAC,yBAAsB;IAC5C,yBAAyB,EAAE,UAAG,CAAC,kCAA+B;IAE9D,4EAA4E;IAC5E,iBAAiB,EAAE,UAAG,CAAC,yBAAsB;IAC7C,mBAAmB,EAAE,UAAG,CAAC,2BAAwB;IACjD,UAAU,EAAE,UAAG,CAAC,iBAAc;IAC9B,YAAY,EAAE,UAAG,CAAC,oBAAiB;IACnC,cAAc,EAAE,UAAG,CAAC,uBAAoB;IACxC,YAAY,EAAE,UAAG,CAAC,oBAAiB;IACnC,aAAa,EAAE,UAAG,CAAC,qBAAkB;IACrC,QAAQ,EAAE,UAAG,CAAC,cAAW;IAEzB,4EAA4E;IAC5E,SAAS,EAAE,UAAG,CAAC,gBAAa;IAC5B,cAAc,EAAE,UAAG,CAAC,gBAAa;IACjC,wFAAwF;IACxF,2FAA2F;IAC3F,gBAAgB,EAAE,UAAG,CAAC,wBAAqB;IAC3C,mBAAmB,EAAE,UAAG,CAAC,2BAAwB;IACjD,kBAAkB,EAAE,UAAG,CAAC,0BAAuB;IAC/C,mGAAmG;IACnG,WAAW,EAAE,UAAG,CAAC,mBAAgB;IACjC,gBAAgB,EAAE,UAAG,CAAC,yBAAsB,EAAE,2DAA2D;CACjG,CAAC","sourcesContent":["/**\n * Centralized names for Session Replay diagnostics shipped via the analytics DiagnosticsClient.\n *\n * Every name shares SR_DIAGNOSTIC_PREFIX so they group together in DataDog as\n * `sdk.diagnostics.sr.trc.*`. The diagnostics pipeline prepends `sdk.diagnostics.` and appends\n * `.count` to counters / `.{min,max,avg,count}` to histograms; events are forwarded to DataDog\n * Logs keyed by `event_name`. Keep ALL SR diagnostic names here so the prefix stays unified —\n * changing the namespace is then a one-line edit.\n */\nexport const SR_DIAGNOSTIC_PREFIX = 'sr.trc';\n\nconst p = SR_DIAGNOSTIC_PREFIX;\n\nexport const SrDiagnostic = {\n // ── Init (Q1: did init even happen?) ─────────────────────────────────────\n init: `${p}.init`, // counter + event(with props): fires once per init()\n\n // ── Session lifecycle ────────────────────────────────────────────────────\n // SR session id changed (timeout / explicit setSessionId / custom session id). New tabs and\n // page refreshes do NOT change the session id, so this is distinct from a fresh init.\n sessionChanged: `${p}.session.changed`, // event (with from/to)\n\n // ── Remote config fetch (joined-config) ──────────────────────────────────\n configSource: (source: string) => `${p}.config.source.${source}`,\n configHasTargeting: `${p}.config.has_targeting`,\n configNoTargeting: `${p}.config.no_targeting`,\n configFetchFailed: `${p}.config.fetch_failed`,\n configReceived: `${p}.config.received`, // event (with props)\n\n targetingTrigger: `${p}.targeting.trigger`, // event: targeting evaluation triggered\n\n // ── Targeting evaluation (evaluateTargetingAndCapture) ────────────────────\n // Q2 (did eval run?), Q3 (working/failed?), Q4 (missing value?), Q5 (all params).\n evalTrigger: (trigger: string) => `${p}.eval.${trigger}`, // init | urlchange | event\n evalNoConfig: `${p}.eval.no_config`,\n evalMissingPrereq: `${p}.eval.missing_prereq`, // Q4: sessionId/config/deviceId missing\n evalMatch: `${p}.eval.match`,\n evalNoMatch: `${p}.eval.no_match`,\n evalError: `${p}.eval.error`, // Q3: targeting engine threw\n evalStaleDiscarded: `${p}.eval.stale_discarded`,\n evalSkippedAlreadyMatched: `${p}.eval.skipped_already_matched`,\n evalDurationMs: `${p}.eval.duration_ms`, // histogram\n evalEvent: `${p}.eval`, // event (with ALL eval params — Q5)\n evalResult: `${p}.eval.result`, // event: raw engine verdict (variantKey) — why match/no-match\n\n // ── Recording execution (getShouldRecord said yes — did rrweb actually start?) ──\n recordStarted: `${p}.record.started`, // event: capture began (carries the srId the replay uploads under)\n recordNoRecordFn: `${p}.record.no_record_fn`, // counter + event: rrweb import returned nothing\n sendSuppressedMinDuration: `${p}.send.suppressed_min_duration`, // counter: events held back by min_session_duration\n\n // ── Record / no-record gate (getShouldRecord) ────────────────────────────\n gateNoIdentifiers: `${p}.gate.no_identifiers`, // Q4: no config/sessionId at gate time\n gateCaptureDisabled: `${p}.gate.capture_disabled`,\n gateOptOut: `${p}.gate.optout`,\n gateTrcMatch: `${p}.gate.trc_match`,\n gateTrcNoMatch: `${p}.gate.trc_no_match`,\n gateSampleIn: `${p}.gate.sample_in`,\n gateSampleOut: `${p}.gate.sample_out`,\n decision: `${p}.decision`, // event (with props)\n\n // ── SPA URL change (setupUrlChangeListener) ──────────────────────────────\n urlChange: `${p}.url_change`,\n urlChangeEvent: `${p}.url_change`, // event (with props); same name, logs vs metric\n // Was the URL-change listener even wired up? (covers \"the SDK never saw any navigation\"\n // because the listener was never attached — e.g. no targeting config, or no global scope.)\n urlListenerSetup: `${p}.url_listener.setup`, // event: the needsUrlTracking decision + its inputs\n urlListenerAttached: `${p}.url_listener.attached`, // event: subscribeToUrlChanges succeeded (with polling opts)\n urlListenerSkipped: `${p}.url_listener.skipped`, // counter + event: listener NOT attached (with reason)\n // Proof the polling loop actually FIRES (not just that it was scheduled by url_listener.attached).\n urlPollTick: `${p}.url_poll.tick`, // counter: incremented every poll tick (aggregated metric, cheap)\n urlPollFirstTick: `${p}.url_poll.first_tick`, // event: once per session on the first tick (carries href)\n} as const;\n"]}
|
|
@@ -41,6 +41,13 @@ export interface SubscribeToUrlChangesOptions {
|
|
|
41
41
|
* that enableUrlChangePolling took effect for an SPA that bypasses the History API.
|
|
42
42
|
*/
|
|
43
43
|
log?: (message: string) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Optional per-tick hook (polling path only), called every interval with the current href and
|
|
46
|
+
* whether it changed since the last tick. The SDK uses this to emit a diagnostics signal proving
|
|
47
|
+
* the polling loop actually fired (vs only being scheduled). Kept separate from `log` so the SDK
|
|
48
|
+
* can throttle/aggregate what it ships.
|
|
49
|
+
*/
|
|
50
|
+
onPoll?: (href: string, changed: boolean) => void;
|
|
44
51
|
}
|
|
45
52
|
/**
|
|
46
53
|
* Single helper for URL change detection. Supports:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-tracking-plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/url-tracking-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,kEAAkE;IAClE,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,oEAAoE;AACpE,MAAM,WAAW,4BAA4B;IAC3C,2FAA2F;IAC3F,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"url-tracking-plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/url-tracking-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,kEAAkE;IAClE,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,oEAAoE;AACpE,MAAM,WAAW,4BAA4B;IAC3C,2FAA2F;IAC3F,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AAiBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EACnC,OAAO,GAAE,4BAAiC,GACzC,MAAM,IAAI,CAyGZ;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,wBAA6B,GACrC,YAAY,CAAC,wBAAwB,CAAC,CAqFxC;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,wCAA4B,CAAC"}
|
|
@@ -28,15 +28,17 @@ function subscribeToUrlChanges(globalScope, onUrlChange, options) {
|
|
|
28
28
|
return;
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
var _a = options.enablePolling, enablePolling = _a === void 0 ? false : _a, _b = options.pollingInterval, pollingInterval = _b === void 0 ? constants_1.DEFAULT_URL_CHANGE_POLLING_INTERVAL : _b, log = options.log;
|
|
31
|
+
var _a = options.enablePolling, enablePolling = _a === void 0 ? false : _a, _b = options.pollingInterval, pollingInterval = _b === void 0 ? constants_1.DEFAULT_URL_CHANGE_POLLING_INTERVAL : _b, log = options.log, onPoll = options.onPoll;
|
|
32
32
|
if (enablePolling) {
|
|
33
33
|
var getHref_1 = function () { var _a; return (_a = globalScope.location.href) !== null && _a !== void 0 ? _a : ''; };
|
|
34
34
|
var lastHref_1 = getHref_1();
|
|
35
35
|
var id_1 = globalScope.setInterval(function () {
|
|
36
36
|
var href = getHref_1();
|
|
37
|
+
var changed = href !== lastHref_1;
|
|
37
38
|
// Logged every tick (not just on change) so we can confirm the polling loop is alive.
|
|
38
|
-
log === null || log === void 0 ? void 0 : log("URL polling tick (href=".concat(href, ", changed=").concat(String(
|
|
39
|
-
|
|
39
|
+
log === null || log === void 0 ? void 0 : log("URL polling tick (href=".concat(href, ", changed=").concat(String(changed), ")."));
|
|
40
|
+
onPoll === null || onPoll === void 0 ? void 0 : onPoll(href, changed);
|
|
41
|
+
if (!changed) {
|
|
40
42
|
return;
|
|
41
43
|
}
|
|
42
44
|
lastHref_1 = href;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-tracking-plugin.js","sourceRoot":"","sources":["../../../src/plugins/url-tracking-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { getPageUrl } from '../helpers';\nimport { UGCFilterRule } from '../config/types';\nimport { DEFAULT_URL_CHANGE_POLLING_INTERVAL } from '../constants';\nimport { RecordPlugin } from '@amplitude/rrweb-types';\n\n/**\n * Event emitted when URL changes are detected by the plugin\n * Contains the current page URL, title, and viewport dimensions\n */\nexport interface URLChangeEvent {\n /** The current page URL (may be filtered if UGC rules are applied) */\n href: string;\n /** The current page title */\n title: string;\n /** Viewport height in pixels */\n viewportHeight: number;\n /** Viewport width in pixels */\n viewportWidth: number;\n /** The type of URL change event */\n type: string;\n}\n\n/**\n * Configuration options for the URL tracking plugin\n */\nexport interface URLTrackingPluginOptions {\n /** Rules for filtering sensitive URLs (User Generated Content) */\n ugcFilterRules?: UGCFilterRule[];\n /** Whether to use polling instead of history API events for URL detection */\n enablePolling?: boolean;\n /** Interval in milliseconds for polling URL changes (default: 1000ms) */\n pollingInterval?: number;\n /** Whether to capture document title in URL change events (default: false) */\n captureDocumentTitle?: boolean;\n}\n\n/** Options for subscribeToUrlChanges (polling vs history + hash) */\nexport interface SubscribeToUrlChangesOptions {\n /** Use polling instead of history/popstate/hashchange (e.g. when history is unreliable) */\n enablePolling?: boolean;\n /** Polling interval in ms when enablePolling is true (default: 1000) */\n pollingInterval?: number;\n /**\n * Optional debug logger, called once per poll tick (only on the polling path). Lets the SDK\n * confirm in the browser console that the interval is actually firing — useful when verifying\n * that enableUrlChangePolling took effect for an SPA that bypasses the History API.\n */\n log?: (message: string) => void;\n}\n\n/** Patch detection marker to prevent double-patching */\nconst PATCH_MARKER = '__amplitude_url_tracking_patched__';\n\ntype PatchableHistoryMethod<T extends (...args: any[]) => any> = T & { [PATCH_MARKER]?: boolean };\n\ninterface UrlChangeSubscriptionState {\n callbacks: Set<(href: string) => void>;\n onPopStateOrHashChange: () => void;\n notify: () => void;\n listenersAttached: boolean;\n}\n\n/** Per-globalScope subscription state; persists to avoid wrapper stacking across re-subscribe cycles */\nconst urlChangeSubscriptionsByScope = new WeakMap<Window, UrlChangeSubscriptionState>();\n\n/**\n * Single helper for URL change detection. Supports:\n * - History API (pushState/replaceState) + popstate + hashchange (shared patch per scope)\n * - Optional polling (setInterval on location.href)\n *\n * Used by session-replay targeting (re-evaluate on URL change) and the URL tracking plugin\n * (emit rrweb events). Call the returned function to unsubscribe.\n *\n * @param globalScope - window (or equivalent); no-op if undefined\n * @param onUrlChange - called when the URL changes, with the new href\n * @param options - optional polling (default: event-based only)\n * @returns cleanup function to remove this subscription\n */\nexport function subscribeToUrlChanges(\n globalScope: Window | undefined,\n onUrlChange: (href: string) => void,\n options: SubscribeToUrlChangesOptions = {},\n): () => void {\n if (!globalScope?.location) {\n return (): void => {\n return;\n };\n }\n\n const { enablePolling = false, pollingInterval = DEFAULT_URL_CHANGE_POLLING_INTERVAL, log } = options;\n\n if (enablePolling) {\n const getHref = (): string => globalScope.location.href ?? '';\n let lastHref = getHref();\n const id = globalScope.setInterval(() => {\n const href = getHref();\n // Logged every tick (not just on change) so we can confirm the polling loop is alive.\n log?.(`URL polling tick (href=${href}, changed=${String(href !== lastHref)}).`);\n if (href === lastHref) {\n return;\n }\n lastHref = href;\n onUrlChange(href);\n }, pollingInterval);\n return (): void => {\n if (id != null) {\n globalScope.clearInterval(id);\n }\n };\n }\n\n let subscriptionState = urlChangeSubscriptionsByScope.get(globalScope);\n if (!subscriptionState) {\n let lastHref: string | undefined = undefined;\n const callbacks = new Set<(href: string) => void>();\n\n const getHref = (): string => globalScope.location.href ?? '';\n\n const notify = (): void => {\n const href = getHref();\n if (lastHref !== undefined && href === lastHref) return;\n lastHref = href;\n callbacks.forEach((c) => c(href));\n };\n\n /**\n * Creates a patched version of history methods (pushState/replaceState)\n * that calls the original method and then emits a URL change event.\n */\n const createHistoryMethodPatch = <T extends typeof history.pushState | typeof history.replaceState>(\n originalMethod: T,\n ) => {\n const patchedMethod = function (this: History, ...args: Parameters<T>) {\n const result = originalMethod.apply(this, args);\n // Read from location.href after history call so we always notify with resolved absolute URL.\n notify();\n return result;\n } as PatchableHistoryMethod<T>;\n\n patchedMethod[PATCH_MARKER] = true;\n return patchedMethod;\n };\n\n const history = globalScope.history;\n if (history?.pushState) {\n const pushState = Reflect.get(history, 'pushState') as PatchableHistoryMethod<History['pushState']>;\n if (!pushState[PATCH_MARKER]) {\n history.pushState = createHistoryMethodPatch(pushState);\n }\n }\n if (history?.replaceState) {\n const replaceState = Reflect.get(history, 'replaceState') as PatchableHistoryMethod<History['replaceState']>;\n if (!replaceState[PATCH_MARKER]) {\n history.replaceState = createHistoryMethodPatch(replaceState);\n }\n }\n\n subscriptionState = {\n callbacks,\n notify,\n onPopStateOrHashChange: () => notify(),\n listenersAttached: false,\n };\n urlChangeSubscriptionsByScope.set(globalScope, subscriptionState);\n }\n\n const state = subscriptionState;\n if (!state.listenersAttached) {\n globalScope.addEventListener('popstate', state.onPopStateOrHashChange);\n globalScope.addEventListener('hashchange', state.onPopStateOrHashChange);\n state.listenersAttached = true;\n }\n\n state.callbacks.add(onUrlChange);\n return (): void => {\n state.callbacks.delete(onUrlChange);\n if (state.callbacks.size === 0) {\n // Do not restore history methods: we are not aware of patches applied by other scripts.\n if (state.listenersAttached) {\n globalScope.removeEventListener('popstate', state.onPopStateOrHashChange);\n globalScope.removeEventListener('hashchange', state.onPopStateOrHashChange);\n state.listenersAttached = false;\n }\n }\n };\n}\n\n/**\n * Creates a URL tracking plugin for rrweb record function\n *\n * This plugin monitors URL changes in the browser and emits events when the URL changes.\n * It supports three tracking modes:\n * 1. Polling (if explicitly enabled) - periodically checks for URL changes\n * 2. History API + Hash routing (default) - patches pushState/replaceState, listens to popstate and hashchange\n * 3. Hash routing only (fallback) - listens to hashchange events when History API is unavailable\n *\n * The plugin handles edge cases gracefully:\n * - Missing or null location objects\n * - Undefined, null, or empty location.href values\n * - Temporal dead zone issues with variable declarations\n * - Consistent URL normalization across all code paths\n *\n * @param options Configuration options for URL tracking\n * @returns RecordPlugin instance that can be used with rrweb\n */\nexport function createUrlTrackingPlugin(\n options: URLTrackingPluginOptions = {},\n): RecordPlugin<URLTrackingPluginOptions> {\n return {\n name: 'amplitude/url-tracking@1',\n observer(cb, globalScope, pluginOptions?: URLTrackingPluginOptions) {\n // Merge options with plugin-level options taking precedence over constructor options\n const config = { ...options, ...pluginOptions };\n const ugcFilterRules = config.ugcFilterRules || [];\n const enablePolling = config.enablePolling ?? false;\n const pollingInterval = config.pollingInterval ?? DEFAULT_URL_CHANGE_POLLING_INTERVAL;\n const captureDocumentTitle = config.captureDocumentTitle ?? false;\n\n // Early return if no global scope is available\n if (!globalScope) {\n return () => {\n // No cleanup needed if no global scope available\n };\n }\n\n // Track the last URL to prevent duplicate events\n // Initialize to undefined to ensure first call always emits an event\n let lastTrackedUrl: string | undefined = undefined;\n\n // Helper functions\n /**\n * Gets the current URL with proper normalization\n * Handles edge cases where location.href might be undefined, null, or empty\n * Ensures consistent behavior across all code paths\n * @returns Normalized URL string (empty string if location unavailable)\n */\n const getCurrentUrl = (): string => {\n if (!globalScope.location) return '';\n return globalScope.location.href || '';\n };\n\n /**\n * Creates a URL change event with current page information\n * Applies UGC filtering if rules are configured\n * Uses getCurrentUrl() for consistent URL normalization\n * @returns URLChangeEvent with current page state\n */\n const createUrlChangeEvent = (): URLChangeEvent => {\n const { innerHeight, innerWidth, document } = globalScope;\n const currentUrl = getCurrentUrl();\n let currentTitle = '';\n if (captureDocumentTitle) {\n currentTitle = document?.title || '';\n }\n\n // Apply UGC filtering if rules are provided, otherwise use original URL\n const filteredUrl = ugcFilterRules.length > 0 ? getPageUrl(currentUrl, ugcFilterRules) : currentUrl;\n\n return {\n href: filteredUrl,\n title: currentTitle,\n viewportHeight: innerHeight,\n viewportWidth: innerWidth,\n type: 'url-change-event',\n };\n };\n\n /**\n * Emits a URL change event if the URL has actually changed\n * Always emits on first call (when lastTrackedUrl is undefined)\n */\n const emitUrlChange = (): void => {\n const currentUrl = getCurrentUrl();\n if (lastTrackedUrl === undefined || currentUrl !== lastTrackedUrl) {\n lastTrackedUrl = currentUrl;\n const event = createUrlChangeEvent();\n cb(event);\n }\n };\n\n // Single helper: history + popstate + hashchange, or polling when enabled\n const unsubscribe = subscribeToUrlChanges(\n globalScope as Window,\n () => emitUrlChange(),\n enablePolling ? { enablePolling: true, pollingInterval } : {},\n );\n emitUrlChange();\n\n return (): void => unsubscribe();\n },\n options,\n };\n}\n\n/**\n * Default URL tracking plugin instance with default options\n * Can be used directly without custom configuration\n */\nexport const urlTrackingPlugin = createUrlTrackingPlugin();\n"]}
|
|
1
|
+
{"version":3,"file":"url-tracking-plugin.js","sourceRoot":"","sources":["../../../src/plugins/url-tracking-plugin.ts"],"names":[],"mappings":";;;;AAAA,sCAAwC;AAExC,0CAAmE;AAuDnE,wDAAwD;AACxD,IAAM,YAAY,GAAG,oCAAoC,CAAC;AAW1D,wGAAwG;AACxG,IAAM,6BAA6B,GAAG,IAAI,OAAO,EAAsC,CAAC;AAExF;;;;;;;;;;;;GAYG;AACH,SAAgB,qBAAqB,CACnC,WAA+B,EAC/B,WAAmC,EACnC,OAA0C;IAA1C,wBAAA,EAAA,YAA0C;IAE1C,IAAI,CAAC,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,QAAQ,CAAA,EAAE;QAC1B,OAAO;YACL,OAAO;QACT,CAAC,CAAC;KACH;IAEO,IAAA,KAA8F,OAAO,cAAhF,EAArB,aAAa,mBAAG,KAAK,KAAA,EAAE,KAAuE,OAAO,gBAAzB,EAArD,eAAe,mBAAG,+CAAmC,KAAA,EAAE,GAAG,GAAa,OAAO,IAApB,EAAE,MAAM,GAAK,OAAO,OAAZ,CAAa;IAE9G,IAAI,aAAa,EAAE;QACjB,IAAM,SAAO,GAAG,sBAAc,OAAA,MAAA,WAAW,CAAC,QAAQ,CAAC,IAAI,mCAAI,EAAE,CAAA,EAAA,CAAC;QAC9D,IAAI,UAAQ,GAAG,SAAO,EAAE,CAAC;QACzB,IAAM,IAAE,GAAG,WAAW,CAAC,WAAW,CAAC;YACjC,IAAM,IAAI,GAAG,SAAO,EAAE,CAAC;YACvB,IAAM,OAAO,GAAG,IAAI,KAAK,UAAQ,CAAC;YAClC,sFAAsF;YACtF,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAG,iCAA0B,IAAI,uBAAa,MAAM,CAAC,OAAO,CAAC,OAAI,CAAC,CAAC;YACtE,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAG,IAAI,EAAE,OAAO,CAAC,CAAC;YACxB,IAAI,CAAC,OAAO,EAAE;gBACZ,OAAO;aACR;YACD,UAAQ,GAAG,IAAI,CAAC;YAChB,WAAW,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,EAAE,eAAe,CAAC,CAAC;QACpB,OAAO;YACL,IAAI,IAAE,IAAI,IAAI,EAAE;gBACd,WAAW,CAAC,aAAa,CAAC,IAAE,CAAC,CAAC;aAC/B;QACH,CAAC,CAAC;KACH;IAED,IAAI,iBAAiB,GAAG,6BAA6B,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACvE,IAAI,CAAC,iBAAiB,EAAE;QACtB,IAAI,UAAQ,GAAuB,SAAS,CAAC;QAC7C,IAAM,WAAS,GAAG,IAAI,GAAG,EAA0B,CAAC;QAEpD,IAAM,SAAO,GAAG,sBAAc,OAAA,MAAA,WAAW,CAAC,QAAQ,CAAC,IAAI,mCAAI,EAAE,CAAA,EAAA,CAAC;QAE9D,IAAM,QAAM,GAAG;YACb,IAAM,IAAI,GAAG,SAAO,EAAE,CAAC;YACvB,IAAI,UAAQ,KAAK,SAAS,IAAI,IAAI,KAAK,UAAQ;gBAAE,OAAO;YACxD,UAAQ,GAAG,IAAI,CAAC;YAChB,WAAS,CAAC,OAAO,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,CAAC,IAAI,CAAC,EAAP,CAAO,CAAC,CAAC;QACpC,CAAC,CAAC;QAEF;;;WAGG;QACH,IAAM,wBAAwB,GAAG,UAC/B,cAAiB;YAEjB,IAAM,aAAa,GAAG;gBAAyB,cAAsB;qBAAtB,UAAsB,EAAtB,qBAAsB,EAAtB,IAAsB;oBAAtB,yBAAsB;;gBACnE,IAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAChD,6FAA6F;gBAC7F,QAAM,EAAE,CAAC;gBACT,OAAO,MAAM,CAAC;YAChB,CAA8B,CAAC;YAE/B,aAAa,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;YACnC,OAAO,aAAa,CAAC;QACvB,CAAC,CAAC;QAEF,IAAM,SAAO,GAAG,WAAW,CAAC,OAAO,CAAC;QACpC,IAAI,SAAO,aAAP,SAAO,uBAAP,SAAO,CAAE,SAAS,EAAE;YACtB,IAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,SAAO,EAAE,WAAW,CAAiD,CAAC;YACpG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE;gBAC5B,SAAO,CAAC,SAAS,GAAG,wBAAwB,CAAC,SAAS,CAAC,CAAC;aACzD;SACF;QACD,IAAI,SAAO,aAAP,SAAO,uBAAP,SAAO,CAAE,YAAY,EAAE;YACzB,IAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,SAAO,EAAE,cAAc,CAAoD,CAAC;YAC7G,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE;gBAC/B,SAAO,CAAC,YAAY,GAAG,wBAAwB,CAAC,YAAY,CAAC,CAAC;aAC/D;SACF;QAED,iBAAiB,GAAG;YAClB,SAAS,aAAA;YACT,MAAM,UAAA;YACN,sBAAsB,EAAE,cAAM,OAAA,QAAM,EAAE,EAAR,CAAQ;YACtC,iBAAiB,EAAE,KAAK;SACzB,CAAC;QACF,6BAA6B,CAAC,GAAG,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;KACnE;IAED,IAAM,KAAK,GAAG,iBAAiB,CAAC;IAChC,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE;QAC5B,WAAW,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACvE,WAAW,CAAC,gBAAgB,CAAC,YAAY,EAAE,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACzE,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC;KAChC;IAED,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACjC,OAAO;QACL,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE;YAC9B,wFAAwF;YACxF,IAAI,KAAK,CAAC,iBAAiB,EAAE;gBAC3B,WAAW,CAAC,mBAAmB,CAAC,UAAU,EAAE,KAAK,CAAC,sBAAsB,CAAC,CAAC;gBAC1E,WAAW,CAAC,mBAAmB,CAAC,YAAY,EAAE,KAAK,CAAC,sBAAsB,CAAC,CAAC;gBAC5E,KAAK,CAAC,iBAAiB,GAAG,KAAK,CAAC;aACjC;SACF;IACH,CAAC,CAAC;AACJ,CAAC;AA7GD,sDA6GC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,uBAAuB,CACrC,OAAsC;IAAtC,wBAAA,EAAA,YAAsC;IAEtC,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,QAAQ,YAAC,EAAE,EAAE,WAAW,EAAE,aAAwC;;YAChE,qFAAqF;YACrF,IAAM,MAAM,yCAAQ,OAAO,GAAK,aAAa,CAAE,CAAC;YAChD,IAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC;YACnD,IAAM,aAAa,GAAG,MAAA,MAAM,CAAC,aAAa,mCAAI,KAAK,CAAC;YACpD,IAAM,eAAe,GAAG,MAAA,MAAM,CAAC,eAAe,mCAAI,+CAAmC,CAAC;YACtF,IAAM,oBAAoB,GAAG,MAAA,MAAM,CAAC,oBAAoB,mCAAI,KAAK,CAAC;YAElE,+CAA+C;YAC/C,IAAI,CAAC,WAAW,EAAE;gBAChB,OAAO;oBACL,iDAAiD;gBACnD,CAAC,CAAC;aACH;YAED,iDAAiD;YACjD,qEAAqE;YACrE,IAAI,cAAc,GAAuB,SAAS,CAAC;YAEnD,mBAAmB;YACnB;;;;;eAKG;YACH,IAAM,aAAa,GAAG;gBACpB,IAAI,CAAC,WAAW,CAAC,QAAQ;oBAAE,OAAO,EAAE,CAAC;gBACrC,OAAO,WAAW,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;YACzC,CAAC,CAAC;YAEF;;;;;eAKG;YACH,IAAM,oBAAoB,GAAG;gBACnB,IAAA,WAAW,GAA2B,WAAW,YAAtC,EAAE,UAAU,GAAe,WAAW,WAA1B,EAAE,QAAQ,GAAK,WAAW,SAAhB,CAAiB;gBAC1D,IAAM,UAAU,GAAG,aAAa,EAAE,CAAC;gBACnC,IAAI,YAAY,GAAG,EAAE,CAAC;gBACtB,IAAI,oBAAoB,EAAE;oBACxB,YAAY,GAAG,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,KAAK,KAAI,EAAE,CAAC;iBACtC;gBAED,wEAAwE;gBACxE,IAAM,WAAW,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAA,oBAAU,EAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;gBAEpG,OAAO;oBACL,IAAI,EAAE,WAAW;oBACjB,KAAK,EAAE,YAAY;oBACnB,cAAc,EAAE,WAAW;oBAC3B,aAAa,EAAE,UAAU;oBACzB,IAAI,EAAE,kBAAkB;iBACzB,CAAC;YACJ,CAAC,CAAC;YAEF;;;eAGG;YACH,IAAM,aAAa,GAAG;gBACpB,IAAM,UAAU,GAAG,aAAa,EAAE,CAAC;gBACnC,IAAI,cAAc,KAAK,SAAS,IAAI,UAAU,KAAK,cAAc,EAAE;oBACjE,cAAc,GAAG,UAAU,CAAC;oBAC5B,IAAM,OAAK,GAAG,oBAAoB,EAAE,CAAC;oBACrC,EAAE,CAAC,OAAK,CAAC,CAAC;iBACX;YACH,CAAC,CAAC;YAEF,0EAA0E;YAC1E,IAAM,WAAW,GAAG,qBAAqB,CACvC,WAAqB,EACrB,cAAM,OAAA,aAAa,EAAE,EAAf,CAAe,EACrB,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,iBAAA,EAAE,CAAC,CAAC,CAAC,EAAE,CAC9D,CAAC;YACF,aAAa,EAAE,CAAC;YAEhB,OAAO,cAAY,OAAA,WAAW,EAAE,EAAb,CAAa,CAAC;QACnC,CAAC;QACD,OAAO,SAAA;KACR,CAAC;AACJ,CAAC;AAvFD,0DAuFC;AAED;;;GAGG;AACU,QAAA,iBAAiB,GAAG,uBAAuB,EAAE,CAAC","sourcesContent":["import { getPageUrl } from '../helpers';\nimport { UGCFilterRule } from '../config/types';\nimport { DEFAULT_URL_CHANGE_POLLING_INTERVAL } from '../constants';\nimport { RecordPlugin } from '@amplitude/rrweb-types';\n\n/**\n * Event emitted when URL changes are detected by the plugin\n * Contains the current page URL, title, and viewport dimensions\n */\nexport interface URLChangeEvent {\n /** The current page URL (may be filtered if UGC rules are applied) */\n href: string;\n /** The current page title */\n title: string;\n /** Viewport height in pixels */\n viewportHeight: number;\n /** Viewport width in pixels */\n viewportWidth: number;\n /** The type of URL change event */\n type: string;\n}\n\n/**\n * Configuration options for the URL tracking plugin\n */\nexport interface URLTrackingPluginOptions {\n /** Rules for filtering sensitive URLs (User Generated Content) */\n ugcFilterRules?: UGCFilterRule[];\n /** Whether to use polling instead of history API events for URL detection */\n enablePolling?: boolean;\n /** Interval in milliseconds for polling URL changes (default: 1000ms) */\n pollingInterval?: number;\n /** Whether to capture document title in URL change events (default: false) */\n captureDocumentTitle?: boolean;\n}\n\n/** Options for subscribeToUrlChanges (polling vs history + hash) */\nexport interface SubscribeToUrlChangesOptions {\n /** Use polling instead of history/popstate/hashchange (e.g. when history is unreliable) */\n enablePolling?: boolean;\n /** Polling interval in ms when enablePolling is true (default: 1000) */\n pollingInterval?: number;\n /**\n * Optional debug logger, called once per poll tick (only on the polling path). Lets the SDK\n * confirm in the browser console that the interval is actually firing — useful when verifying\n * that enableUrlChangePolling took effect for an SPA that bypasses the History API.\n */\n log?: (message: string) => void;\n /**\n * Optional per-tick hook (polling path only), called every interval with the current href and\n * whether it changed since the last tick. The SDK uses this to emit a diagnostics signal proving\n * the polling loop actually fired (vs only being scheduled). Kept separate from `log` so the SDK\n * can throttle/aggregate what it ships.\n */\n onPoll?: (href: string, changed: boolean) => void;\n}\n\n/** Patch detection marker to prevent double-patching */\nconst PATCH_MARKER = '__amplitude_url_tracking_patched__';\n\ntype PatchableHistoryMethod<T extends (...args: any[]) => any> = T & { [PATCH_MARKER]?: boolean };\n\ninterface UrlChangeSubscriptionState {\n callbacks: Set<(href: string) => void>;\n onPopStateOrHashChange: () => void;\n notify: () => void;\n listenersAttached: boolean;\n}\n\n/** Per-globalScope subscription state; persists to avoid wrapper stacking across re-subscribe cycles */\nconst urlChangeSubscriptionsByScope = new WeakMap<Window, UrlChangeSubscriptionState>();\n\n/**\n * Single helper for URL change detection. Supports:\n * - History API (pushState/replaceState) + popstate + hashchange (shared patch per scope)\n * - Optional polling (setInterval on location.href)\n *\n * Used by session-replay targeting (re-evaluate on URL change) and the URL tracking plugin\n * (emit rrweb events). Call the returned function to unsubscribe.\n *\n * @param globalScope - window (or equivalent); no-op if undefined\n * @param onUrlChange - called when the URL changes, with the new href\n * @param options - optional polling (default: event-based only)\n * @returns cleanup function to remove this subscription\n */\nexport function subscribeToUrlChanges(\n globalScope: Window | undefined,\n onUrlChange: (href: string) => void,\n options: SubscribeToUrlChangesOptions = {},\n): () => void {\n if (!globalScope?.location) {\n return (): void => {\n return;\n };\n }\n\n const { enablePolling = false, pollingInterval = DEFAULT_URL_CHANGE_POLLING_INTERVAL, log, onPoll } = options;\n\n if (enablePolling) {\n const getHref = (): string => globalScope.location.href ?? '';\n let lastHref = getHref();\n const id = globalScope.setInterval(() => {\n const href = getHref();\n const changed = href !== lastHref;\n // Logged every tick (not just on change) so we can confirm the polling loop is alive.\n log?.(`URL polling tick (href=${href}, changed=${String(changed)}).`);\n onPoll?.(href, changed);\n if (!changed) {\n return;\n }\n lastHref = href;\n onUrlChange(href);\n }, pollingInterval);\n return (): void => {\n if (id != null) {\n globalScope.clearInterval(id);\n }\n };\n }\n\n let subscriptionState = urlChangeSubscriptionsByScope.get(globalScope);\n if (!subscriptionState) {\n let lastHref: string | undefined = undefined;\n const callbacks = new Set<(href: string) => void>();\n\n const getHref = (): string => globalScope.location.href ?? '';\n\n const notify = (): void => {\n const href = getHref();\n if (lastHref !== undefined && href === lastHref) return;\n lastHref = href;\n callbacks.forEach((c) => c(href));\n };\n\n /**\n * Creates a patched version of history methods (pushState/replaceState)\n * that calls the original method and then emits a URL change event.\n */\n const createHistoryMethodPatch = <T extends typeof history.pushState | typeof history.replaceState>(\n originalMethod: T,\n ) => {\n const patchedMethod = function (this: History, ...args: Parameters<T>) {\n const result = originalMethod.apply(this, args);\n // Read from location.href after history call so we always notify with resolved absolute URL.\n notify();\n return result;\n } as PatchableHistoryMethod<T>;\n\n patchedMethod[PATCH_MARKER] = true;\n return patchedMethod;\n };\n\n const history = globalScope.history;\n if (history?.pushState) {\n const pushState = Reflect.get(history, 'pushState') as PatchableHistoryMethod<History['pushState']>;\n if (!pushState[PATCH_MARKER]) {\n history.pushState = createHistoryMethodPatch(pushState);\n }\n }\n if (history?.replaceState) {\n const replaceState = Reflect.get(history, 'replaceState') as PatchableHistoryMethod<History['replaceState']>;\n if (!replaceState[PATCH_MARKER]) {\n history.replaceState = createHistoryMethodPatch(replaceState);\n }\n }\n\n subscriptionState = {\n callbacks,\n notify,\n onPopStateOrHashChange: () => notify(),\n listenersAttached: false,\n };\n urlChangeSubscriptionsByScope.set(globalScope, subscriptionState);\n }\n\n const state = subscriptionState;\n if (!state.listenersAttached) {\n globalScope.addEventListener('popstate', state.onPopStateOrHashChange);\n globalScope.addEventListener('hashchange', state.onPopStateOrHashChange);\n state.listenersAttached = true;\n }\n\n state.callbacks.add(onUrlChange);\n return (): void => {\n state.callbacks.delete(onUrlChange);\n if (state.callbacks.size === 0) {\n // Do not restore history methods: we are not aware of patches applied by other scripts.\n if (state.listenersAttached) {\n globalScope.removeEventListener('popstate', state.onPopStateOrHashChange);\n globalScope.removeEventListener('hashchange', state.onPopStateOrHashChange);\n state.listenersAttached = false;\n }\n }\n };\n}\n\n/**\n * Creates a URL tracking plugin for rrweb record function\n *\n * This plugin monitors URL changes in the browser and emits events when the URL changes.\n * It supports three tracking modes:\n * 1. Polling (if explicitly enabled) - periodically checks for URL changes\n * 2. History API + Hash routing (default) - patches pushState/replaceState, listens to popstate and hashchange\n * 3. Hash routing only (fallback) - listens to hashchange events when History API is unavailable\n *\n * The plugin handles edge cases gracefully:\n * - Missing or null location objects\n * - Undefined, null, or empty location.href values\n * - Temporal dead zone issues with variable declarations\n * - Consistent URL normalization across all code paths\n *\n * @param options Configuration options for URL tracking\n * @returns RecordPlugin instance that can be used with rrweb\n */\nexport function createUrlTrackingPlugin(\n options: URLTrackingPluginOptions = {},\n): RecordPlugin<URLTrackingPluginOptions> {\n return {\n name: 'amplitude/url-tracking@1',\n observer(cb, globalScope, pluginOptions?: URLTrackingPluginOptions) {\n // Merge options with plugin-level options taking precedence over constructor options\n const config = { ...options, ...pluginOptions };\n const ugcFilterRules = config.ugcFilterRules || [];\n const enablePolling = config.enablePolling ?? false;\n const pollingInterval = config.pollingInterval ?? DEFAULT_URL_CHANGE_POLLING_INTERVAL;\n const captureDocumentTitle = config.captureDocumentTitle ?? false;\n\n // Early return if no global scope is available\n if (!globalScope) {\n return () => {\n // No cleanup needed if no global scope available\n };\n }\n\n // Track the last URL to prevent duplicate events\n // Initialize to undefined to ensure first call always emits an event\n let lastTrackedUrl: string | undefined = undefined;\n\n // Helper functions\n /**\n * Gets the current URL with proper normalization\n * Handles edge cases where location.href might be undefined, null, or empty\n * Ensures consistent behavior across all code paths\n * @returns Normalized URL string (empty string if location unavailable)\n */\n const getCurrentUrl = (): string => {\n if (!globalScope.location) return '';\n return globalScope.location.href || '';\n };\n\n /**\n * Creates a URL change event with current page information\n * Applies UGC filtering if rules are configured\n * Uses getCurrentUrl() for consistent URL normalization\n * @returns URLChangeEvent with current page state\n */\n const createUrlChangeEvent = (): URLChangeEvent => {\n const { innerHeight, innerWidth, document } = globalScope;\n const currentUrl = getCurrentUrl();\n let currentTitle = '';\n if (captureDocumentTitle) {\n currentTitle = document?.title || '';\n }\n\n // Apply UGC filtering if rules are provided, otherwise use original URL\n const filteredUrl = ugcFilterRules.length > 0 ? getPageUrl(currentUrl, ugcFilterRules) : currentUrl;\n\n return {\n href: filteredUrl,\n title: currentTitle,\n viewportHeight: innerHeight,\n viewportWidth: innerWidth,\n type: 'url-change-event',\n };\n };\n\n /**\n * Emits a URL change event if the URL has actually changed\n * Always emits on first call (when lastTrackedUrl is undefined)\n */\n const emitUrlChange = (): void => {\n const currentUrl = getCurrentUrl();\n if (lastTrackedUrl === undefined || currentUrl !== lastTrackedUrl) {\n lastTrackedUrl = currentUrl;\n const event = createUrlChangeEvent();\n cb(event);\n }\n };\n\n // Single helper: history + popstate + hashchange, or polling when enabled\n const unsubscribe = subscribeToUrlChanges(\n globalScope as Window,\n () => emitUrlChange(),\n enablePolling ? { enablePolling: true, pollingInterval } : {},\n );\n emitUrlChange();\n\n return (): void => unsubscribe();\n },\n options,\n };\n}\n\n/**\n * Default URL tracking plugin instance with default options\n * Can be used directly without custom configuration\n */\nexport const urlTrackingPlugin = createUrlTrackingPlugin();\n"]}
|
|
@@ -42,6 +42,7 @@ export declare class SessionReplay implements AmplitudeSessionReplay {
|
|
|
42
42
|
private recordEventsPendingShouldLogMetadata;
|
|
43
43
|
/** Cleanup for URL change listener used to re-evaluate targeting on SPA route changes */
|
|
44
44
|
private urlChangeCleanup;
|
|
45
|
+
private urlPollFirstTickRecorded;
|
|
45
46
|
private crossOriginIframeCoordinator;
|
|
46
47
|
private crossOriginParentSignalCleanup;
|
|
47
48
|
/** Monotonic counter to ignore stale URL-change targeting results */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,OAAO,EASR,MAAM,2BAA2B,CAAC;AAKnC,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,kCAAkC,EAInC,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEL,gBAAgB,EASjB,MAAM,aAAa,CAAC;AAWrB,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAuB,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAcvF,OAAO,EACL,sBAAsB,EACtB,0BAA0B,IAAI,mCAAmC,EAIjE,kBAAkB,IAAI,mBAAmB,EACzC,oBAAoB,EACpB,2BAA2B,EAC5B,MAAM,0BAA0B,CAAC;AAOlC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,KAAK,WAAW,GAAG,CAAC,CAAC,EAAE,mBAAmB,GAAG,KAAK,KAAK,IAAI,CAAC;AAE5D,qBAAa,aAAc,YAAW,sBAAsB;IAC1D,IAAI,SAAuC;IAC3C,MAAM,EAAE,yBAAyB,GAAG,SAAS,CAAC;IAC9C,qBAAqB,EAAE,kCAAkC,GAAG,SAAS,CAAC;IACtE,WAAW,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC7C,aAAa,CAAC,EAAE,mCAAmC,CAAC,QAAQ,GAAG,aAAa,EAAE,MAAM,CAAC,CAAC;IACtF,cAAc,EAAE,OAAO,CAAC;IACxB,oBAAoB,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,IAAI,CAAQ;IAC/D,UAAU,SAAK;IACf,eAAe,EAAE,eAAe,GAAG,SAAS,CAAC;IAC7C,qBAAqB,UAAS;IAC9B,OAAO,CAAC,mBAAmB,CAAC,CAA8B;IAC1D,OAAO,CAAC,wBAAwB,CAAC,CAAU;IAI3C,OAAO,CAAC,sBAAsB,CAA0C;IAOxE,YAAY,EAAE,WAAW,EAAE,CAAM;IACjC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,iBAAiB,EAAE,uBAAuB,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IACjE;;;OAGG;IACH,OAAO,CAAC,mBAAmB,CAAK;IAChC,+EAA+E;IAC/E,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,UAAU,CAAC,CAAiB;IACpC,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,QAAQ,CAAoC;IAGpD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,iBAAiB,CAAmE;IAE5F,gFAAgF;IAChF,OAAO,CAAC,cAAc,CAAM;IAE5B,OAAO,CAAC,oCAAoC,CAAwB;IAEpE,yFAAyF;IACzF,OAAO,CAAC,gBAAgB,CAA6B;
|
|
1
|
+
{"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/session-replay.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,6 +55,9 @@ var SessionReplay = /** @class */ (function () {
|
|
|
55
55
|
this.recordEventsPendingShouldLogMetadata = null;
|
|
56
56
|
/** Cleanup for URL change listener used to re-evaluate targeting on SPA route changes */
|
|
57
57
|
this.urlChangeCleanup = null;
|
|
58
|
+
// Ensures the url_poll.first_tick diagnostic event is emitted at most once per listener setup
|
|
59
|
+
// (the per-tick counter still increments every tick; only the rich event is one-shot).
|
|
60
|
+
this.urlPollFirstTickRecorded = false;
|
|
58
61
|
this.crossOriginIframeCoordinator = null;
|
|
59
62
|
this.crossOriginParentSignalCleanup = null;
|
|
60
63
|
/** Monotonic counter to ignore stale URL-change targeting results */
|
|
@@ -381,11 +384,23 @@ var SessionReplay = /** @class */ (function () {
|
|
|
381
384
|
// recording never starts on the new URL (enableUrlChangePolling previously only affected the
|
|
382
385
|
// rrweb URL-tracking plugin, which runs only once recording is already active).
|
|
383
386
|
var enablePolling = (_d = (_c = this.config) === null || _c === void 0 ? void 0 : _c.enableUrlChangePolling) !== null && _d !== void 0 ? _d : false;
|
|
387
|
+
this.urlPollFirstTickRecorded = false;
|
|
384
388
|
var unsubscribe = (0, url_tracking_plugin_1.subscribeToUrlChanges)(globalScope, onUrlChange, {
|
|
385
389
|
enablePolling: enablePolling,
|
|
386
390
|
pollingInterval: (_e = this.config) === null || _e === void 0 ? void 0 : _e.urlChangePollingInterval,
|
|
387
391
|
// Mirror each poll tick to the console (Debug level) so we can confirm polling is firing.
|
|
388
392
|
log: this.loggerProvider.debug.bind(this.loggerProvider),
|
|
393
|
+
// Prove in DataDog that polling actually FIRES (not just that it was scheduled). Per-tick is a
|
|
394
|
+
// cheap aggregated counter; the rich event is emitted once (with href) to avoid flooding the
|
|
395
|
+
// diagnostics endpoint with one capture POST per second.
|
|
396
|
+
onPoll: function (href, changed) {
|
|
397
|
+
_this.incrementDiagnostic(diagnostics_1.SrDiagnostic.urlPollTick);
|
|
398
|
+
if (!_this.urlPollFirstTickRecorded) {
|
|
399
|
+
_this.urlPollFirstTickRecorded = true;
|
|
400
|
+
// pollingInterval is already on url_listener.attached, so it's omitted here.
|
|
401
|
+
_this.recordDiagnosticEvent(diagnostics_1.SrDiagnostic.urlPollFirstTick, { href: href, changed: changed });
|
|
402
|
+
}
|
|
403
|
+
},
|
|
389
404
|
});
|
|
390
405
|
// Confirm the listener is actually live, and under what settings — if recording never starts on
|
|
391
406
|
// navigation, this tells us whether the listener existed and whether polling (the fallback for
|