@newtalaria/browser 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/client.d.ts +4 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/index.js +162 -29
- package/dist/index.js.map +3 -3
- package/dist/replay/fit_segment.d.ts +9 -1
- package/dist/replay/fit_segment.d.ts.map +1 -1
- package/dist/replay/paint_base_size.d.ts +19 -0
- package/dist/replay/paint_base_size.d.ts.map +1 -0
- package/dist/replay/segment_buffer.d.ts +17 -3
- package/dist/replay/segment_buffer.d.ts.map +1 -1
- package/dist/talaria.browser.iife.js +162 -29
- package/dist/talaria.browser.iife.js.map +3 -3
- package/package.json +1 -1
|
@@ -23,11 +23,19 @@ export declare function planOversizedRetry(events: RrwebEvent[]): {
|
|
|
23
23
|
left: RrwebEvent[];
|
|
24
24
|
right: RrwebEvent[];
|
|
25
25
|
};
|
|
26
|
+
/** Leading Meta+FullSnapshot (2) or FullSnapshot alone (1); else 0. */
|
|
27
|
+
export declare function paintBaseEventCount(events: RrwebEvent[]): number;
|
|
26
28
|
/**
|
|
27
29
|
* Binary-search the largest prefix that gzips under the pack target.
|
|
28
30
|
* Remainder is returned for re-queue; null means every event was dropped.
|
|
31
|
+
*
|
|
32
|
+
* When `atomicMinCount` is set (segment-0 paint base), never return a prefix
|
|
33
|
+
* shorter than that count unless the atomic unit itself exceeds `hardCap`
|
|
34
|
+
* (then null — caller should abort as oversized, not ship Meta-only).
|
|
29
35
|
*/
|
|
30
|
-
export declare function fitCompressedPrefix(events: RrwebEvent[], compress: CompressEvents, targetBytes?: number, hardCap?: number
|
|
36
|
+
export declare function fitCompressedPrefix(events: RrwebEvent[], compress: CompressEvents, targetBytes?: number, hardCap?: number, opts?: {
|
|
37
|
+
atomicMinCount?: number;
|
|
38
|
+
}): Promise<{
|
|
31
39
|
events: RrwebEvent[];
|
|
32
40
|
gzip: Uint8Array;
|
|
33
41
|
remainder: RrwebEvent[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fit_segment.d.ts","sourceRoot":"","sources":["../../src/replay/fit_segment.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"fit_segment.d.ts","sourceRoot":"","sources":["../../src/replay/fit_segment.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3E;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,iBAAiB,EAAE,MAAM,EACzB,OAAO,EAAE,MAAM,EACf,OAAO,SAA4B,GAClC,MAAM,CAER;AAED,2EAA2E;AAC3E,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,MAAM,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAOV;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAAE,GACnB;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,CAUpF;AAED,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAYhE;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,UAAU,EAAE,EACpB,QAAQ,EAAE,cAAc,EACxB,WAAW,SAAkC,EAC7C,OAAO,SAA+B,EACtC,IAAI,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GACjC,OAAO,CAAC;IACT,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,UAAU,EAAE,CAAC;CACzB,GAAG,IAAI,CAAC,CA2ER"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type RrwebEvent } from './segment_buffer.js';
|
|
2
|
+
/** Size diagnostics when segment 0 cannot ship a paint base. */
|
|
3
|
+
export type PaintBaseSizeDetails = {
|
|
4
|
+
segmentEventTypes: number[];
|
|
5
|
+
/** Estimated JSON bytes of the Meta event, if present. */
|
|
6
|
+
metaEstimatedBytes?: number;
|
|
7
|
+
/** Estimated JSON bytes of the FullSnapshot, if present. */
|
|
8
|
+
fullSnapshotEstimatedBytes?: number;
|
|
9
|
+
/** Actual gzip size of FullSnapshot alone, when measured. */
|
|
10
|
+
fullSnapshotCompressedBytes?: number;
|
|
11
|
+
/** Soft estimated take window (not the server uncompressed hard cap). */
|
|
12
|
+
softTakeEstimatedBytes: number;
|
|
13
|
+
targetCompressedSegmentBytes: number;
|
|
14
|
+
maxCompressedSegmentBytes: number;
|
|
15
|
+
} & Record<string, unknown>;
|
|
16
|
+
export declare function paintBaseSizeDetails(events: RrwebEvent[], opts?: {
|
|
17
|
+
fullSnapshotCompressedBytes?: number;
|
|
18
|
+
}): PaintBaseSizeDetails;
|
|
19
|
+
//# sourceMappingURL=paint_base_size.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paint_base_size.d.ts","sourceRoot":"","sources":["../../src/replay/paint_base_size.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAE7B,gEAAgE;AAChE,MAAM,MAAM,oBAAoB,GAAG;IACjC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,0DAA0D;IAC1D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,6DAA6D;IAC7D,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,yEAAyE;IACzE,sBAAsB,EAAE,MAAM,CAAC;IAC/B,4BAA4B,EAAE,MAAM,CAAC;IACrC,yBAAyB,EAAE,MAAM,CAAC;CACnC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5B,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,UAAU,EAAE,EACpB,IAAI,CAAC,EAAE;IAAE,2BAA2B,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,oBAAoB,CAsBtB"}
|
|
@@ -5,8 +5,9 @@ export interface RrwebEvent {
|
|
|
5
5
|
timestamp: number;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Soft
|
|
9
|
-
*
|
|
8
|
+
* Soft estimated-JSON take size before gzip fitting.
|
|
9
|
+
* Not a hard server limit — packing uses MAX_COMPRESSED_SEGMENT_BYTES.
|
|
10
|
+
* Paint base (Meta+FullSnapshot) is taken atomically and may exceed this.
|
|
10
11
|
*/
|
|
11
12
|
export declare const SEGMENT_SIZE_BYTES = 800000;
|
|
12
13
|
/**
|
|
@@ -53,6 +54,8 @@ export declare class SegmentBuffer {
|
|
|
53
54
|
get estimatedBytes(): number;
|
|
54
55
|
push(event: RrwebEvent): void;
|
|
55
56
|
hasFullSnapshot(): boolean;
|
|
57
|
+
/** First FullSnapshot still queued (does not remove it). */
|
|
58
|
+
peekFullSnapshot(): RrwebEvent | undefined;
|
|
56
59
|
/**
|
|
57
60
|
* Drop leading events until Meta+FullSnapshot (or FullSnapshot alone).
|
|
58
61
|
* Returns false if no FullSnapshot is present (replay would paint blank).
|
|
@@ -64,12 +67,23 @@ export declare class SegmentBuffer {
|
|
|
64
67
|
*/
|
|
65
68
|
trimRing(now?: number, maxBytes?: number): void;
|
|
66
69
|
shouldFlushBySize(): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* How many leading events form the rrweb paint base (Meta+FullSnapshot or
|
|
72
|
+
* FullSnapshot alone). Returns 0 if the buffer does not start with a paint base.
|
|
73
|
+
*/
|
|
74
|
+
paintBaseLength(): number;
|
|
67
75
|
/**
|
|
68
76
|
* Take a prefix of events whose estimated JSON size is ~maxBytes.
|
|
69
77
|
* Always returns at least one event when the buffer is non-empty (caller
|
|
70
78
|
* must handle a single oversized event).
|
|
79
|
+
*
|
|
80
|
+
* When `keepPaintBaseTogether` is true (segment 0), Meta immediately followed
|
|
81
|
+
* by FullSnapshot is taken as one unit even if estimated size exceeds
|
|
82
|
+
* maxBytes — gzip fitting / hard caps decide whether it can ship.
|
|
71
83
|
*/
|
|
72
|
-
takeByEstimatedBytes(maxBytes: number
|
|
84
|
+
takeByEstimatedBytes(maxBytes: number, opts?: {
|
|
85
|
+
keepPaintBaseTogether?: boolean;
|
|
86
|
+
}): RrwebEvent[];
|
|
73
87
|
takeAll(): RrwebEvent[];
|
|
74
88
|
/** Re-queue events at the front (failed upload retry / bisect remainder). */
|
|
75
89
|
prepend(events: RrwebEvent[]): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"segment_buffer.d.ts","sourceRoot":"","sources":["../../src/replay/segment_buffer.ts"],"names":[],"mappings":"AAEA,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED
|
|
1
|
+
{"version":3,"file":"segment_buffer.d.ts","sourceRoot":"","sources":["../../src/replay/segment_buffer.ts"],"names":[],"mappings":"AAEA,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,SAAU,CAAC;AAC1C;;;GAGG;AACH,eAAO,MAAM,4BAA4B,QAAc,CAAC;AACxD,iFAAiF;AACjF,eAAO,MAAM,+BAA+B,QACF,CAAC;AAC3C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C;;GAEG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,uEAAuE;AACvE,eAAO,MAAM,+BAA+B,QAAkB,CAAC;AAC/D,8DAA8D;AAC9D,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAC/C,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,OAAQ,CAAC;AACtC,oEAAoE;AACpE,eAAO,MAAM,cAAc,QAAS,CAAC;AACrC,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,UAAY,CAAC;AAC/C,2DAA2D;AAC3D,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C;;;GAGG;AACH,eAAO,MAAM,sBAAsB,QAAgB,CAAC;AAEpD,mCAAmC;AACnC,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,2BAA2B;AAC3B,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAK;IAEzB,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAK7B,eAAe,IAAI,OAAO;IAI1B,4DAA4D;IAC5D,gBAAgB,IAAI,UAAU,GAAG,SAAS;IAI1C;;;OAGG;IACH,kBAAkB,IAAI,OAAO;IAc7B;;;OAGG;IACH,QAAQ,CAAC,GAAG,SAAa,EAAE,QAAQ,SAAwB,GAAG,IAAI;IAiBlE,iBAAiB,IAAI,OAAO;IAI5B;;;OAGG;IACH,eAAe,IAAI,MAAM;IAczB;;;;;;;;OAQG;IACH,oBAAoB,CAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;KAAE,GACzC,UAAU,EAAE;IAqCf,OAAO,IAAI,UAAU,EAAE;IAOvB,6EAA6E;IAC7E,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI;IAMnC,KAAK,IAAI,IAAI;IAKb,SAAS,IAAI;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI;IAUtD,OAAO,CAAC,cAAc;CAGvB"}
|
|
@@ -163,6 +163,10 @@
|
|
|
163
163
|
hasFullSnapshot() {
|
|
164
164
|
return this.events.some((e) => e.type === RRWEB_FULL_SNAPSHOT);
|
|
165
165
|
}
|
|
166
|
+
/** First FullSnapshot still queued (does not remove it). */
|
|
167
|
+
peekFullSnapshot() {
|
|
168
|
+
return this.events.find((e) => e.type === RRWEB_FULL_SNAPSHOT);
|
|
169
|
+
}
|
|
166
170
|
/**
|
|
167
171
|
* Drop leading events until Meta+FullSnapshot (or FullSnapshot alone).
|
|
168
172
|
* Returns false if no FullSnapshot is present (replay would paint blank).
|
|
@@ -202,15 +206,44 @@
|
|
|
202
206
|
shouldFlushBySize() {
|
|
203
207
|
return this.pendingBytes >= SEGMENT_SIZE_BYTES;
|
|
204
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* How many leading events form the rrweb paint base (Meta+FullSnapshot or
|
|
211
|
+
* FullSnapshot alone). Returns 0 if the buffer does not start with a paint base.
|
|
212
|
+
*/
|
|
213
|
+
paintBaseLength() {
|
|
214
|
+
if (this.events.length === 0) return 0;
|
|
215
|
+
if (this.events[0].type === RRWEB_META && this.events[1]?.type === RRWEB_FULL_SNAPSHOT) {
|
|
216
|
+
return 2;
|
|
217
|
+
}
|
|
218
|
+
if (this.events[0].type === RRWEB_FULL_SNAPSHOT) {
|
|
219
|
+
return 1;
|
|
220
|
+
}
|
|
221
|
+
return 0;
|
|
222
|
+
}
|
|
205
223
|
/**
|
|
206
224
|
* Take a prefix of events whose estimated JSON size is ~maxBytes.
|
|
207
225
|
* Always returns at least one event when the buffer is non-empty (caller
|
|
208
226
|
* must handle a single oversized event).
|
|
227
|
+
*
|
|
228
|
+
* When `keepPaintBaseTogether` is true (segment 0), Meta immediately followed
|
|
229
|
+
* by FullSnapshot is taken as one unit even if estimated size exceeds
|
|
230
|
+
* maxBytes — gzip fitting / hard caps decide whether it can ship.
|
|
209
231
|
*/
|
|
210
|
-
takeByEstimatedBytes(maxBytes) {
|
|
232
|
+
takeByEstimatedBytes(maxBytes, opts) {
|
|
211
233
|
if (this.events.length === 0) return [];
|
|
212
234
|
const batch = [];
|
|
213
235
|
let batchBytes = 0;
|
|
236
|
+
if (opts?.keepPaintBaseTogether) {
|
|
237
|
+
const paintLen = this.paintBaseLength();
|
|
238
|
+
if (paintLen > 0) {
|
|
239
|
+
for (let i = 0; i < paintLen; i++) {
|
|
240
|
+
const ev = this.events.shift();
|
|
241
|
+
batch.push(ev);
|
|
242
|
+
batchBytes += estimateJsonBytes(ev);
|
|
243
|
+
}
|
|
244
|
+
this.recomputeBytes();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
214
247
|
while (this.events.length > 0) {
|
|
215
248
|
const next = this.events[0];
|
|
216
249
|
const nextBytes = estimateJsonBytes(next);
|
|
@@ -335,8 +368,53 @@
|
|
|
335
368
|
right: events.slice(mid)
|
|
336
369
|
};
|
|
337
370
|
}
|
|
338
|
-
|
|
371
|
+
function paintBaseEventCount(events) {
|
|
372
|
+
if (events.length === 0) return 0;
|
|
373
|
+
if (events[0].type === RRWEB_META && events[1]?.type === RRWEB_FULL_SNAPSHOT) {
|
|
374
|
+
return 2;
|
|
375
|
+
}
|
|
376
|
+
if (events[0].type === RRWEB_FULL_SNAPSHOT) {
|
|
377
|
+
return 1;
|
|
378
|
+
}
|
|
379
|
+
return 0;
|
|
380
|
+
}
|
|
381
|
+
async function fitCompressedPrefix(events, compress, targetBytes = TARGET_COMPRESSED_SEGMENT_BYTES, hardCap = MAX_COMPRESSED_SEGMENT_BYTES, opts) {
|
|
339
382
|
if (events.length === 0) return null;
|
|
383
|
+
const atomicMin = opts?.atomicMinCount ?? 0;
|
|
384
|
+
if (atomicMin > 0) {
|
|
385
|
+
if (events.length < atomicMin) return null;
|
|
386
|
+
const paint = events.slice(0, atomicMin);
|
|
387
|
+
const paintGzip = await compress(paint);
|
|
388
|
+
if (paintGzip.length > hardCap) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
let lo = atomicMin;
|
|
392
|
+
let hi = events.length;
|
|
393
|
+
let best = {
|
|
394
|
+
events: paint,
|
|
395
|
+
gzip: paintGzip
|
|
396
|
+
};
|
|
397
|
+
while (lo <= hi) {
|
|
398
|
+
const mid = Math.floor((lo + hi) / 2);
|
|
399
|
+
if (mid < atomicMin) {
|
|
400
|
+
lo = atomicMin;
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
const prefix = events.slice(0, mid);
|
|
404
|
+
const gzip = await compress(prefix);
|
|
405
|
+
if (gzip.length <= targetBytes && gzip.length <= hardCap) {
|
|
406
|
+
best = { events: prefix, gzip };
|
|
407
|
+
lo = mid + 1;
|
|
408
|
+
} else {
|
|
409
|
+
hi = mid - 1;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return {
|
|
413
|
+
events: best.events,
|
|
414
|
+
gzip: best.gzip,
|
|
415
|
+
remainder: events.slice(best.events.length)
|
|
416
|
+
};
|
|
417
|
+
}
|
|
340
418
|
let remaining = events;
|
|
341
419
|
while (remaining.length > 0) {
|
|
342
420
|
let lo = 1;
|
|
@@ -392,6 +470,28 @@
|
|
|
392
470
|
};
|
|
393
471
|
}
|
|
394
472
|
|
|
473
|
+
// src/replay/paint_base_size.ts
|
|
474
|
+
function paintBaseSizeDetails(events, opts) {
|
|
475
|
+
const meta = events.find((e) => e.type === RRWEB_META);
|
|
476
|
+
const full = events.find((e) => e.type === RRWEB_FULL_SNAPSHOT);
|
|
477
|
+
const details = {
|
|
478
|
+
segmentEventTypes: events.map((e) => e.type),
|
|
479
|
+
softTakeEstimatedBytes: SEGMENT_SIZE_BYTES,
|
|
480
|
+
targetCompressedSegmentBytes: TARGET_COMPRESSED_SEGMENT_BYTES,
|
|
481
|
+
maxCompressedSegmentBytes: MAX_COMPRESSED_SEGMENT_BYTES
|
|
482
|
+
};
|
|
483
|
+
if (meta) {
|
|
484
|
+
details.metaEstimatedBytes = estimateJsonBytes(meta);
|
|
485
|
+
}
|
|
486
|
+
if (full) {
|
|
487
|
+
details.fullSnapshotEstimatedBytes = estimateJsonBytes(full);
|
|
488
|
+
}
|
|
489
|
+
if (opts?.fullSnapshotCompressedBytes !== void 0) {
|
|
490
|
+
details.fullSnapshotCompressedBytes = opts.fullSnapshotCompressedBytes;
|
|
491
|
+
}
|
|
492
|
+
return details;
|
|
493
|
+
}
|
|
494
|
+
|
|
395
495
|
// ../../node_modules/rrweb/dist/rrweb.js
|
|
396
496
|
var __defProp = Object.defineProperty;
|
|
397
497
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -13977,7 +14077,11 @@
|
|
|
13977
14077
|
if (!this.options || !this.transport || !this.replayId) return;
|
|
13978
14078
|
if (!this.startedOnServer || this.finishedOnServer) return;
|
|
13979
14079
|
if (!this.prepareBufferForNewReplay()) {
|
|
13980
|
-
|
|
14080
|
+
const leftover = this.buffer.peekFullSnapshot();
|
|
14081
|
+
await this.abortUnusableClip(
|
|
14082
|
+
"no_full_snapshot",
|
|
14083
|
+
paintBaseSizeDetails(leftover ? [leftover] : [])
|
|
14084
|
+
);
|
|
13981
14085
|
return;
|
|
13982
14086
|
}
|
|
13983
14087
|
while (this.buffer.length > 0) {
|
|
@@ -14025,9 +14129,10 @@
|
|
|
14025
14129
|
}
|
|
14026
14130
|
const { events, gzip } = fitted;
|
|
14027
14131
|
if (this.segmentIndex === 0 && !events.some((e) => e.type === RRWEB_FULL_SNAPSHOT)) {
|
|
14028
|
-
await this.abortUnusableClip(
|
|
14029
|
-
|
|
14030
|
-
|
|
14132
|
+
await this.abortUnusableClip(
|
|
14133
|
+
"no_full_snapshot",
|
|
14134
|
+
paintBaseSizeDetails(events)
|
|
14135
|
+
);
|
|
14031
14136
|
return;
|
|
14032
14137
|
}
|
|
14033
14138
|
if (this.isErrorClipMode() && this.uploadedCompressedBytes + gzip.length > MAX_ERROR_CLIP_COMPRESSED_BYTES && this.segmentIndex > 0) {
|
|
@@ -14071,6 +14176,14 @@
|
|
|
14071
14176
|
break;
|
|
14072
14177
|
}
|
|
14073
14178
|
if (isOversizedSegmentError(error)) {
|
|
14179
|
+
if (this.segmentIndex === 0 && paintBaseEventCount(events) > 0) {
|
|
14180
|
+
await this.abortUnusableClip("oversized_full_snapshot", {
|
|
14181
|
+
source: "server_reject_paint_base",
|
|
14182
|
+
...paintBaseSizeDetails(events),
|
|
14183
|
+
rejectedCompressedBytes: gzip.length
|
|
14184
|
+
});
|
|
14185
|
+
return;
|
|
14186
|
+
}
|
|
14074
14187
|
const plan = planOversizedRetry(events);
|
|
14075
14188
|
if (plan.action === "drop") {
|
|
14076
14189
|
const droppedType = events[0]?.type;
|
|
@@ -14078,10 +14191,15 @@
|
|
|
14078
14191
|
"@newtalaria/browser: dropping rrweb event rejected as oversized",
|
|
14079
14192
|
{ type: droppedType }
|
|
14080
14193
|
);
|
|
14081
|
-
if (
|
|
14082
|
-
await this.abortUnusableClip(
|
|
14083
|
-
|
|
14084
|
-
|
|
14194
|
+
if (droppedType === RRWEB_FULL_SNAPSHOT) {
|
|
14195
|
+
await this.abortUnusableClip(
|
|
14196
|
+
"oversized_full_snapshot",
|
|
14197
|
+
{
|
|
14198
|
+
source: "server_reject",
|
|
14199
|
+
...paintBaseSizeDetails(events),
|
|
14200
|
+
rejectedCompressedBytes: gzip.length
|
|
14201
|
+
}
|
|
14202
|
+
);
|
|
14085
14203
|
return;
|
|
14086
14204
|
}
|
|
14087
14205
|
continue;
|
|
@@ -14111,45 +14229,60 @@
|
|
|
14111
14229
|
}
|
|
14112
14230
|
/**
|
|
14113
14231
|
* Pull the largest event prefix that gzips under the target compressed size.
|
|
14114
|
-
*
|
|
14115
|
-
*
|
|
14232
|
+
*
|
|
14233
|
+
* Segment 0 keeps Meta+FullSnapshot (paint base) atomic through take + fit so
|
|
14234
|
+
* a soft estimated-byte window cannot orphan the FullSnapshot.
|
|
14116
14235
|
*/
|
|
14117
14236
|
async takeFittedSegment() {
|
|
14118
|
-
const
|
|
14237
|
+
const isPaintBaseSegment = this.segmentIndex === 0;
|
|
14238
|
+
const chunk = this.buffer.takeByEstimatedBytes(SEGMENT_SIZE_BYTES, {
|
|
14239
|
+
keepPaintBaseTogether: isPaintBaseSegment
|
|
14240
|
+
});
|
|
14119
14241
|
if (chunk.length === 0) return null;
|
|
14242
|
+
const atomicMin = isPaintBaseSegment ? paintBaseEventCount(chunk) : 0;
|
|
14120
14243
|
const fitted = await fitCompressedPrefix(
|
|
14121
14244
|
chunk,
|
|
14122
14245
|
compressReplayEvents,
|
|
14123
14246
|
TARGET_COMPRESSED_SEGMENT_BYTES,
|
|
14124
|
-
MAX_COMPRESSED_SEGMENT_BYTES
|
|
14247
|
+
MAX_COMPRESSED_SEGMENT_BYTES,
|
|
14248
|
+
atomicMin > 0 ? { atomicMinCount: atomicMin } : void 0
|
|
14125
14249
|
);
|
|
14126
14250
|
if (!fitted) {
|
|
14127
|
-
|
|
14128
|
-
|
|
14129
|
-
|
|
14130
|
-
|
|
14131
|
-
|
|
14132
|
-
|
|
14251
|
+
if (isPaintBaseSegment && atomicMin > 0) {
|
|
14252
|
+
const paint = chunk.slice(0, atomicMin);
|
|
14253
|
+
let compressedBytes;
|
|
14254
|
+
const full = paint.find((e) => e.type === RRWEB_FULL_SNAPSHOT);
|
|
14255
|
+
if (full) {
|
|
14256
|
+
try {
|
|
14257
|
+
compressedBytes = (await compressReplayEvents([full])).length;
|
|
14258
|
+
} catch {
|
|
14259
|
+
}
|
|
14260
|
+
}
|
|
14261
|
+
if (chunk.length > atomicMin) {
|
|
14262
|
+
this.buffer.prepend(chunk.slice(atomicMin));
|
|
14263
|
+
}
|
|
14133
14264
|
return {
|
|
14134
14265
|
events: [],
|
|
14135
14266
|
gzip: new Uint8Array(),
|
|
14136
14267
|
abortReason: "oversized_full_snapshot",
|
|
14137
|
-
abortDetails: {
|
|
14268
|
+
abortDetails: {
|
|
14269
|
+
source: "paint_base_exceeds_hard_cap",
|
|
14270
|
+
...paintBaseSizeDetails(paint, {
|
|
14271
|
+
fullSnapshotCompressedBytes: compressedBytes
|
|
14272
|
+
})
|
|
14273
|
+
}
|
|
14138
14274
|
};
|
|
14139
14275
|
}
|
|
14276
|
+
const dropped = chunk[0];
|
|
14277
|
+
console.warn(
|
|
14278
|
+
"@newtalaria/browser: dropping rrweb event that exceeds max segment size",
|
|
14279
|
+
{ type: dropped?.type }
|
|
14280
|
+
);
|
|
14140
14281
|
if (chunk.length > 1) {
|
|
14141
14282
|
this.buffer.prepend(chunk.slice(1));
|
|
14142
14283
|
}
|
|
14143
14284
|
return this.takeFittedSegment();
|
|
14144
14285
|
}
|
|
14145
|
-
if (this.segmentIndex === 0 && chunk.some((e) => e.type === RRWEB_FULL_SNAPSHOT) && !fitted.events.some((e) => e.type === RRWEB_FULL_SNAPSHOT)) {
|
|
14146
|
-
return {
|
|
14147
|
-
events: [],
|
|
14148
|
-
gzip: new Uint8Array(),
|
|
14149
|
-
abortReason: "oversized_full_snapshot",
|
|
14150
|
-
abortDetails: { source: "fit_dropped_full_snapshot" }
|
|
14151
|
-
};
|
|
14152
|
-
}
|
|
14153
14286
|
if (fitted.remainder.length > 0) {
|
|
14154
14287
|
this.buffer.prepend(fitted.remainder);
|
|
14155
14288
|
}
|