@openreplay/tracker 18.0.10 → 18.0.12-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -171,11 +171,72 @@ export default class App {
171
171
  /** used by child iframes for crossdomain only */
172
172
  parentActive: boolean;
173
173
  checkStatus: () => boolean;
174
+ /** child-side crossdomain debug state (only meaningful when insideIframe) */
175
+ private lastTokenReceived;
176
+ private lastParentMsgAt;
177
+ private lastSentToParentAt;
178
+ private iframeDebugInterval;
179
+ /** stamp every outbound post to the parent window, for the child debug snapshot */
180
+ private markSentToParent;
181
+ /**
182
+ * Child-side counterpart of emitCrossdomainDebug: once per minute an iframe posts an
183
+ * encoded snapshot of its own tracking state up to the parent, which records it as a
184
+ * console log. Posted directly (not via this.send) so it is reported even when the
185
+ * child is NOT active — an inactive/orphaned child is exactly what we want to catch.
186
+ */
187
+ private emitIframeDebug;
174
188
  parentCrossDomainFrameListener: (event: MessageEvent) => void;
175
189
  trackedFrames: string[];
190
+ /** every context that has been enrolled at least once, to tell an orphan (re-adopt) apart
191
+ * from a brand-new child still mid-enrollment (leave alone). */
192
+ private everTrackedFrames;
176
193
  private frameLastSeen;
194
+ /** crossdomain debug diagnostics, reported once per minute as an encoded console log */
195
+ private frameOrigin;
196
+ private frameAnyLastSeen;
197
+ private frameBatchLastSeen;
198
+ private frameLastSent;
199
+ private xdomainDebugInterval;
200
+ /** last time we re-adopted a given orphaned context, to avoid restart spam */
201
+ private reAdoptCooldown;
202
+ private readonly RE_ADOPT_COOLDOWN_MS;
203
+ /**
204
+ * Stable, collision-free frame-order allocation. Node ids are partitioned by
205
+ * (frameLevel, frameOrder) via pack() — every (level, order) owns its own id block, so
206
+ * two simultaneously-live frames sharing an order at the same level corrupt each other's
207
+ * node trees and one stops rendering. The previous `trackedFrames.findIndex+1` derived
208
+ * order from a mutable array index, and pruneStaleFrames()'s .filter() shifts those
209
+ * indices, so a newly enrolled frame could be handed an order still in use by a live
210
+ * (but pruned) frame. We instead assign each context a persistent order, unique among all
211
+ * non-recycled contexts at its level, freed only when the context is GC'd (truly gone).
212
+ */
213
+ private frameAlloc;
214
+ private usedOrdersByLevel;
215
+ private allocateFrameOrder;
216
+ private freeFrameOrder;
177
217
  private readonly FRAME_STALE_MS;
178
218
  private pruneStaleFrames;
219
+ /** records the last command/signal we posted to a given child iframe context (debug) */
220
+ private recordSentToFrame;
221
+ /**
222
+ * Self-heal for the "kill-then-prune orphan" race: a live child can fall out of
223
+ * `trackedFrames` (its 250ms poll was delayed past FRAME_STALE_MS during the parent's
224
+ * stop/start NotActive gap, so pruneStaleFrames evicted it). It keeps polling but the
225
+ * only re-enrollment path is an `iframeSignal`, which a stopped/active-but-orphaned
226
+ * child never re-emits — so it would record nothing forever. When we (the parent) are
227
+ * active and see a poll from an un-tracked context, push a `startIframe` so the child
228
+ * restarts, re-runs the full handshake and re-observes with a fresh rootId. Cooldowned
229
+ * so we don't spam restarts during the child's start window.
230
+ */
231
+ private reAdoptOrphanFrame;
232
+ /**
233
+ * Once per minute: emit an encoded console log from the parent tracker describing every
234
+ * tracked child iframe and the freshness of our two-way communication with it. Lets us
235
+ * see in replay which crossdomain iframe went silent and on which leg of the handshake.
236
+ */
237
+ /** drop debug entries for contexts we have neither heard from nor messaged in this long */
238
+ private readonly XDOMAIN_DEBUG_RETENTION_MS;
239
+ private emitCrossdomainDebug;
179
240
  crossDomainIframeListener: (event: MessageEvent) => void;
180
241
  /**
181
242
  * { command : [remaining iframes] }
@@ -171,11 +171,72 @@ export default class App {
171
171
  /** used by child iframes for crossdomain only */
172
172
  parentActive: boolean;
173
173
  checkStatus: () => boolean;
174
+ /** child-side crossdomain debug state (only meaningful when insideIframe) */
175
+ private lastTokenReceived;
176
+ private lastParentMsgAt;
177
+ private lastSentToParentAt;
178
+ private iframeDebugInterval;
179
+ /** stamp every outbound post to the parent window, for the child debug snapshot */
180
+ private markSentToParent;
181
+ /**
182
+ * Child-side counterpart of emitCrossdomainDebug: once per minute an iframe posts an
183
+ * encoded snapshot of its own tracking state up to the parent, which records it as a
184
+ * console log. Posted directly (not via this.send) so it is reported even when the
185
+ * child is NOT active — an inactive/orphaned child is exactly what we want to catch.
186
+ */
187
+ private emitIframeDebug;
174
188
  parentCrossDomainFrameListener: (event: MessageEvent) => void;
175
189
  trackedFrames: string[];
190
+ /** every context that has been enrolled at least once, to tell an orphan (re-adopt) apart
191
+ * from a brand-new child still mid-enrollment (leave alone). */
192
+ private everTrackedFrames;
176
193
  private frameLastSeen;
194
+ /** crossdomain debug diagnostics, reported once per minute as an encoded console log */
195
+ private frameOrigin;
196
+ private frameAnyLastSeen;
197
+ private frameBatchLastSeen;
198
+ private frameLastSent;
199
+ private xdomainDebugInterval;
200
+ /** last time we re-adopted a given orphaned context, to avoid restart spam */
201
+ private reAdoptCooldown;
202
+ private readonly RE_ADOPT_COOLDOWN_MS;
203
+ /**
204
+ * Stable, collision-free frame-order allocation. Node ids are partitioned by
205
+ * (frameLevel, frameOrder) via pack() — every (level, order) owns its own id block, so
206
+ * two simultaneously-live frames sharing an order at the same level corrupt each other's
207
+ * node trees and one stops rendering. The previous `trackedFrames.findIndex+1` derived
208
+ * order from a mutable array index, and pruneStaleFrames()'s .filter() shifts those
209
+ * indices, so a newly enrolled frame could be handed an order still in use by a live
210
+ * (but pruned) frame. We instead assign each context a persistent order, unique among all
211
+ * non-recycled contexts at its level, freed only when the context is GC'd (truly gone).
212
+ */
213
+ private frameAlloc;
214
+ private usedOrdersByLevel;
215
+ private allocateFrameOrder;
216
+ private freeFrameOrder;
177
217
  private readonly FRAME_STALE_MS;
178
218
  private pruneStaleFrames;
219
+ /** records the last command/signal we posted to a given child iframe context (debug) */
220
+ private recordSentToFrame;
221
+ /**
222
+ * Self-heal for the "kill-then-prune orphan" race: a live child can fall out of
223
+ * `trackedFrames` (its 250ms poll was delayed past FRAME_STALE_MS during the parent's
224
+ * stop/start NotActive gap, so pruneStaleFrames evicted it). It keeps polling but the
225
+ * only re-enrollment path is an `iframeSignal`, which a stopped/active-but-orphaned
226
+ * child never re-emits — so it would record nothing forever. When we (the parent) are
227
+ * active and see a poll from an un-tracked context, push a `startIframe` so the child
228
+ * restarts, re-runs the full handshake and re-observes with a fresh rootId. Cooldowned
229
+ * so we don't spam restarts during the child's start window.
230
+ */
231
+ private reAdoptOrphanFrame;
232
+ /**
233
+ * Once per minute: emit an encoded console log from the parent tracker describing every
234
+ * tracked child iframe and the freshness of our two-way communication with it. Lets us
235
+ * see in replay which crossdomain iframe went silent and on which leg of the handshake.
236
+ */
237
+ /** drop debug entries for contexts we have neither heard from nor messaged in this long */
238
+ private readonly XDOMAIN_DEBUG_RETENTION_MS;
239
+ private emitCrossdomainDebug;
179
240
  crossDomainIframeListener: (event: MessageEvent) => void;
180
241
  /**
181
242
  * { command : [remaining iframes] }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openreplay/tracker",
3
3
  "description": "The OpenReplay tracker main package",
4
- "version": "18.0.10",
4
+ "version": "18.0.12-beta.1",
5
5
  "keywords": [
6
6
  "logging",
7
7
  "replay"