@openreplay/tracker 18.0.1 → 18.0.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/dist/cjs/entry.js +117 -18
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +117 -18
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/main/app/index.d.ts +4 -4
- package/dist/cjs/main/app/observer/observer.d.ts +6 -0
- package/dist/lib/entry.js +117 -18
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +117 -18
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/main/app/index.d.ts +4 -4
- package/dist/lib/main/app/observer/observer.d.ts +6 -0
- package/dist/types/main/app/index.d.ts +4 -4
- package/dist/types/main/app/observer/observer.d.ts +6 -0
- package/package.json +2 -2
|
@@ -172,11 +172,10 @@ export default class App {
|
|
|
172
172
|
parentActive: boolean;
|
|
173
173
|
checkStatus: () => boolean;
|
|
174
174
|
parentCrossDomainFrameListener: (event: MessageEvent) => void;
|
|
175
|
-
/**
|
|
176
|
-
* context ids for iframes,
|
|
177
|
-
* order is not so important as long as its consistent
|
|
178
|
-
* */
|
|
179
175
|
trackedFrames: string[];
|
|
176
|
+
private frameLastSeen;
|
|
177
|
+
private readonly FRAME_STALE_MS;
|
|
178
|
+
private pruneStaleFrames;
|
|
180
179
|
crossDomainIframeListener: (event: MessageEvent) => void;
|
|
181
180
|
/**
|
|
182
181
|
* { command : [remaining iframes] }
|
|
@@ -291,6 +290,7 @@ export default class App {
|
|
|
291
290
|
* */
|
|
292
291
|
uploadOfflineRecording(): Promise<void>;
|
|
293
292
|
prevOpts: StartOptions;
|
|
293
|
+
private userStartCallback?;
|
|
294
294
|
private _start;
|
|
295
295
|
restartCanvasTracking: () => void;
|
|
296
296
|
flushBuffer: (buffer: Message[]) => Promise<unknown>;
|
|
@@ -28,6 +28,12 @@ export default abstract class Observer {
|
|
|
28
28
|
private readonly inlineRemoteCss;
|
|
29
29
|
private readonly inlinerOptions;
|
|
30
30
|
private readonly domParser;
|
|
31
|
+
/**
|
|
32
|
+
* Bumped on every disconnect(). Stale async CSS-inlining callbacks from a
|
|
33
|
+
* previous session (e.g. agent reload → tracker restart) compare against
|
|
34
|
+
* this and bail instead of sending messages that reference vanished node ids.
|
|
35
|
+
*/
|
|
36
|
+
private generation;
|
|
31
37
|
constructor(app: App, isTopContext?: boolean, options?: Options);
|
|
32
38
|
private clear;
|
|
33
39
|
/**
|
package/dist/lib/entry.js
CHANGED
|
@@ -2386,8 +2386,44 @@ function inlineRemoteCss(node, id, baseHref, getNextID, insertRule, addOwner, fo
|
|
|
2386
2386
|
})
|
|
2387
2387
|
.catch(error => {
|
|
2388
2388
|
console.error(`OpenReplay: Failed to fetch CSS from ${node.href}:`, error);
|
|
2389
|
+
// Fetch failed (likely CORS) — retry via load event + sheet access
|
|
2390
|
+
retryViaLoadEvent();
|
|
2389
2391
|
});
|
|
2390
2392
|
}
|
|
2393
|
+
else {
|
|
2394
|
+
retryViaLoadEvent();
|
|
2395
|
+
}
|
|
2396
|
+
function retryViaLoadEvent() {
|
|
2397
|
+
const trySheet = () => {
|
|
2398
|
+
const loadedSheet = node.sheet;
|
|
2399
|
+
if (loadedSheet) {
|
|
2400
|
+
try {
|
|
2401
|
+
const cssText = stringifyStylesheet(loadedSheet);
|
|
2402
|
+
if (cssText) {
|
|
2403
|
+
if (sendPlain && onPlain) {
|
|
2404
|
+
onPlain(cssText, fakeIdHolder++);
|
|
2405
|
+
}
|
|
2406
|
+
else {
|
|
2407
|
+
processCssText(cssText);
|
|
2408
|
+
}
|
|
2409
|
+
return;
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
catch (e) {
|
|
2413
|
+
// cross-origin sheet — nothing more we can do
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
if (node.sheet) {
|
|
2418
|
+
trySheet();
|
|
2419
|
+
}
|
|
2420
|
+
else {
|
|
2421
|
+
node.addEventListener('load', function onLoad() {
|
|
2422
|
+
node.removeEventListener('load', onLoad);
|
|
2423
|
+
trySheet();
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2391
2427
|
function processCssText(cssText) {
|
|
2392
2428
|
// Remove comments
|
|
2393
2429
|
cssText = cssText.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
@@ -2609,7 +2645,6 @@ function ConstructedStyleSheets (app) {
|
|
|
2609
2645
|
if (!hasAdoptedSS(document)) {
|
|
2610
2646
|
return;
|
|
2611
2647
|
}
|
|
2612
|
-
const styleSheetIDMap = new Map();
|
|
2613
2648
|
const adoptedStyleSheetsOwnings = new Map();
|
|
2614
2649
|
const sendAdoptedStyleSheetsUpdate = (root) => setTimeout(() => {
|
|
2615
2650
|
let nodeID = app.nodes.getID(root);
|
|
@@ -2874,6 +2909,12 @@ class Observer {
|
|
|
2874
2909
|
this.inlineRemoteCss = false;
|
|
2875
2910
|
this.inlinerOptions = undefined;
|
|
2876
2911
|
this.domParser = new DOMParser();
|
|
2912
|
+
/**
|
|
2913
|
+
* Bumped on every disconnect(). Stale async CSS-inlining callbacks from a
|
|
2914
|
+
* previous session (e.g. agent reload → tracker restart) compare against
|
|
2915
|
+
* this and bail instead of sending messages that reference vanished node ids.
|
|
2916
|
+
*/
|
|
2917
|
+
this.generation = 0;
|
|
2877
2918
|
this.throttling = true;
|
|
2878
2919
|
this.throttledSetNodeData = throttleWithTrailing((id, parentElement, data) => this.sendNodeData(id, parentElement, data), 30);
|
|
2879
2920
|
this.throttling = !Boolean(options.disableThrottling);
|
|
@@ -3020,18 +3061,23 @@ class Observer {
|
|
|
3020
3061
|
}
|
|
3021
3062
|
if (name === 'style' || (name === 'href' && hasTag(node, 'link'))) {
|
|
3022
3063
|
if ('rel' in node && node.rel === 'stylesheet' && this.inlineRemoteCss) {
|
|
3064
|
+
const gen = this.generation;
|
|
3023
3065
|
setTimeout(() => {
|
|
3024
3066
|
inlineRemoteCss(
|
|
3025
3067
|
// @ts-ignore
|
|
3026
3068
|
node, id, this.app.getBaseHref(), nextID, (id, cssText, index, baseHref) => {
|
|
3069
|
+
if (this.generation !== gen)
|
|
3070
|
+
return;
|
|
3027
3071
|
this.app.send(AdoptedSSInsertRuleURLBased(id, cssText, index, baseHref));
|
|
3028
3072
|
}, (sheetId, ownerId) => {
|
|
3073
|
+
if (this.generation !== gen)
|
|
3074
|
+
return;
|
|
3029
3075
|
this.app.send(AdoptedSSAddOwner(sheetId, ownerId));
|
|
3030
3076
|
}, this.inlinerOptions?.forceFetch, this.inlinerOptions?.forcePlain, (cssText, fakeTextId) => {
|
|
3077
|
+
if (this.generation !== gen)
|
|
3078
|
+
return;
|
|
3031
3079
|
this.app.send(CreateTextNode(fakeTextId, id, 0));
|
|
3032
|
-
|
|
3033
|
-
this.app.send(SetCSSDataURLBased(fakeTextId, cssText, this.app.getBaseHref()));
|
|
3034
|
-
}, 10);
|
|
3080
|
+
this.app.send(SetCSSDataURLBased(fakeTextId, cssText, this.app.getBaseHref()));
|
|
3035
3081
|
});
|
|
3036
3082
|
}, 0);
|
|
3037
3083
|
return;
|
|
@@ -3295,6 +3341,7 @@ class Observer {
|
|
|
3295
3341
|
this.observer.disconnect();
|
|
3296
3342
|
this.clear();
|
|
3297
3343
|
this.throttledSetNodeData.clear();
|
|
3344
|
+
this.generation++;
|
|
3298
3345
|
}
|
|
3299
3346
|
}
|
|
3300
3347
|
|
|
@@ -3958,7 +4005,7 @@ class App {
|
|
|
3958
4005
|
this.stopCallbacks = [];
|
|
3959
4006
|
this.commitCallbacks = [];
|
|
3960
4007
|
this.activityState = ActivityState.NotActive;
|
|
3961
|
-
this.version = '18.0.
|
|
4008
|
+
this.version = '18.0.3'; // TODO: version compatability check inside each plugin.
|
|
3962
4009
|
this.socketMode = false;
|
|
3963
4010
|
this.compressionThreshold = 24 * 1000;
|
|
3964
4011
|
this.bc = null;
|
|
@@ -3980,12 +4027,19 @@ class App {
|
|
|
3980
4027
|
if (!data || event.source === window)
|
|
3981
4028
|
return;
|
|
3982
4029
|
if (data.line === proto.startIframe) {
|
|
3983
|
-
|
|
4030
|
+
// Avoid corrupting an in-flight start; let it complete.
|
|
4031
|
+
if (this.activityState === ActivityState.Starting)
|
|
3984
4032
|
return;
|
|
3985
4033
|
try {
|
|
4034
|
+
if (this.active()) {
|
|
4035
|
+
this.stop();
|
|
4036
|
+
}
|
|
3986
4037
|
if (data.token) {
|
|
3987
4038
|
this.session.setSessionToken(data.token, this.projectKey);
|
|
3988
4039
|
}
|
|
4040
|
+
if (data.id !== undefined) {
|
|
4041
|
+
this.rootId = data.id;
|
|
4042
|
+
}
|
|
3989
4043
|
this.allowAppStart();
|
|
3990
4044
|
void this.start();
|
|
3991
4045
|
}
|
|
@@ -4011,17 +4065,22 @@ class App {
|
|
|
4011
4065
|
}
|
|
4012
4066
|
}
|
|
4013
4067
|
};
|
|
4014
|
-
/**
|
|
4015
|
-
* context ids for iframes,
|
|
4016
|
-
* order is not so important as long as its consistent
|
|
4017
|
-
* */
|
|
4018
4068
|
this.trackedFrames = [];
|
|
4069
|
+
this.frameLastSeen = new Map();
|
|
4070
|
+
this.FRAME_STALE_MS = 1500;
|
|
4019
4071
|
this.crossDomainIframeListener = (event) => {
|
|
4020
|
-
if (
|
|
4072
|
+
if (event.source === window)
|
|
4021
4073
|
return;
|
|
4022
4074
|
const { data } = event;
|
|
4023
4075
|
if (!data)
|
|
4024
4076
|
return;
|
|
4077
|
+
// Record liveness regardless of our own active state so the queue can prune
|
|
4078
|
+
// stale contexts reliably once we resume dispatching commands after a cycle.
|
|
4079
|
+
if ((data.line === proto.polling || data.line === proto.iframeSignal) && data.context) {
|
|
4080
|
+
this.frameLastSeen.set(data.context, Date.now());
|
|
4081
|
+
}
|
|
4082
|
+
if (!this.active())
|
|
4083
|
+
return;
|
|
4025
4084
|
if (data.line === proto.iframeSignal) {
|
|
4026
4085
|
// @ts-ignore
|
|
4027
4086
|
event.source?.postMessage({ ping: true, line: proto.parentAlive }, '*');
|
|
@@ -4119,20 +4178,41 @@ class App {
|
|
|
4119
4178
|
if (!this.pollingQueue.order.length) {
|
|
4120
4179
|
return;
|
|
4121
4180
|
}
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4181
|
+
this.pruneStaleFrames();
|
|
4182
|
+
const liveSet = new Set(this.trackedFrames);
|
|
4183
|
+
while (this.pollingQueue.order.length > 0) {
|
|
4184
|
+
const head = this.pollingQueue.order[0];
|
|
4185
|
+
this.pollingQueue[head] = this.pollingQueue[head].filter((ctx) => liveSet.has(ctx));
|
|
4186
|
+
if (this.pollingQueue[head].length === 0) {
|
|
4187
|
+
delete this.pollingQueue[head];
|
|
4188
|
+
this.pollingQueue.order.shift();
|
|
4189
|
+
}
|
|
4190
|
+
else {
|
|
4191
|
+
break;
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
if (!this.pollingQueue.order.length) {
|
|
4125
4195
|
return;
|
|
4126
4196
|
}
|
|
4197
|
+
const nextCommand = this.pollingQueue.order[0];
|
|
4127
4198
|
if (this.pollingQueue[nextCommand].includes(data.context)) {
|
|
4128
4199
|
this.pollingQueue[nextCommand] = this.pollingQueue[nextCommand].filter((c) => c !== data.context);
|
|
4129
4200
|
const message = { line: nextCommand };
|
|
4130
4201
|
if (nextCommand === proto.startIframe) {
|
|
4131
4202
|
message.token = this.session.getSessionToken(this.projectKey);
|
|
4203
|
+
const targetFrame = this.pageFrames.find((f) => f.contentWindow === event.source)
|
|
4204
|
+
|| Array.from(document.querySelectorAll('iframe')).find((f) => f.contentWindow === event.source);
|
|
4205
|
+
if (targetFrame) {
|
|
4206
|
+
const nodeId = targetFrame[this.options.node_id];
|
|
4207
|
+
if (nodeId !== undefined) {
|
|
4208
|
+
message.id = nodeId;
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4132
4211
|
}
|
|
4133
4212
|
// @ts-ignore
|
|
4134
4213
|
event.source?.postMessage(message, '*');
|
|
4135
4214
|
if (this.pollingQueue[nextCommand].length === 0) {
|
|
4215
|
+
delete this.pollingQueue[nextCommand];
|
|
4136
4216
|
this.pollingQueue.order.shift();
|
|
4137
4217
|
}
|
|
4138
4218
|
}
|
|
@@ -4146,6 +4226,11 @@ class App {
|
|
|
4146
4226
|
order: [],
|
|
4147
4227
|
};
|
|
4148
4228
|
this.addCommand = (cmd) => {
|
|
4229
|
+
this.pruneStaleFrames();
|
|
4230
|
+
if (this.pollingQueue[cmd]) {
|
|
4231
|
+
this.pollingQueue[cmd] = Array.from(new Set([...this.pollingQueue[cmd], ...this.trackedFrames]));
|
|
4232
|
+
return;
|
|
4233
|
+
}
|
|
4149
4234
|
this.pollingQueue.order.push(cmd);
|
|
4150
4235
|
this.pollingQueue[cmd] = [...this.trackedFrames];
|
|
4151
4236
|
};
|
|
@@ -4458,6 +4543,16 @@ class App {
|
|
|
4458
4543
|
};
|
|
4459
4544
|
}
|
|
4460
4545
|
}
|
|
4546
|
+
pruneStaleFrames() {
|
|
4547
|
+
const staleAfter = Date.now() - this.FRAME_STALE_MS;
|
|
4548
|
+
this.trackedFrames = this.trackedFrames.filter((ctx) => {
|
|
4549
|
+
const last = this.frameLastSeen.get(ctx);
|
|
4550
|
+
if (last !== undefined && last >= staleAfter)
|
|
4551
|
+
return true;
|
|
4552
|
+
this.frameLastSeen.delete(ctx);
|
|
4553
|
+
return false;
|
|
4554
|
+
});
|
|
4555
|
+
}
|
|
4461
4556
|
allowAppStart() {
|
|
4462
4557
|
this.canStart = true;
|
|
4463
4558
|
if (this.startTimeout) {
|
|
@@ -5039,6 +5134,9 @@ class App {
|
|
|
5039
5134
|
if (Object.keys(startOpts).length !== 0) {
|
|
5040
5135
|
this.prevOpts = startOpts;
|
|
5041
5136
|
}
|
|
5137
|
+
if (startOpts.startCallback) {
|
|
5138
|
+
this.userStartCallback = startOpts.startCallback;
|
|
5139
|
+
}
|
|
5042
5140
|
const isColdStart = this.activityState === ActivityState.ColdStart;
|
|
5043
5141
|
if (isColdStart && this.coldInterval) {
|
|
5044
5142
|
clearInterval(this.coldInterval);
|
|
@@ -5180,8 +5278,8 @@ class App {
|
|
|
5180
5278
|
// TODO: start as early as possible (before receiving the token)
|
|
5181
5279
|
/** after start */
|
|
5182
5280
|
this.startCallbacks.forEach((cb) => cb(onStartInfo)); // MBTODO: callbacks after DOM "mounted" (observed)
|
|
5183
|
-
if (
|
|
5184
|
-
|
|
5281
|
+
if (this.userStartCallback) {
|
|
5282
|
+
this.userStartCallback(SuccessfulStart(onStartInfo));
|
|
5185
5283
|
}
|
|
5186
5284
|
this.activityState = ActivityState.Active;
|
|
5187
5285
|
if (this.options.crossdomain?.enabled) {
|
|
@@ -5344,6 +5442,7 @@ class App {
|
|
|
5344
5442
|
this.canvasRecorder?.clear();
|
|
5345
5443
|
this.messages.length = 0;
|
|
5346
5444
|
this.parentActive = false;
|
|
5445
|
+
this.pageFrames = [];
|
|
5347
5446
|
}
|
|
5348
5447
|
finally {
|
|
5349
5448
|
this.activityState = ActivityState.NotActive;
|
|
@@ -8873,7 +8972,7 @@ class ConstantProperties {
|
|
|
8873
8972
|
user_id: this.user_id,
|
|
8874
8973
|
distinct_id: this.deviceId,
|
|
8875
8974
|
sdk_edition: 'web',
|
|
8876
|
-
sdk_version: '18.0.
|
|
8975
|
+
sdk_version: '18.0.3',
|
|
8877
8976
|
timezone: getUTCOffsetString(),
|
|
8878
8977
|
search_engine: this.searchEngine,
|
|
8879
8978
|
};
|
|
@@ -9575,7 +9674,7 @@ class API {
|
|
|
9575
9674
|
this.signalStartIssue = (reason, missingApi) => {
|
|
9576
9675
|
const doNotTrack = this.checkDoNotTrack();
|
|
9577
9676
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
9578
|
-
trackerVersion: '18.0.
|
|
9677
|
+
trackerVersion: '18.0.3',
|
|
9579
9678
|
projectKey: this.options.projectKey,
|
|
9580
9679
|
doNotTrack,
|
|
9581
9680
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|