@oneuptime/react-native-replay 14.0.1 → 14.0.2

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/index.cjs CHANGED
@@ -59,7 +59,23 @@ var import_react_native2 = require("react-native");
59
59
  // src/Contract.ts
60
60
  var SESSION_REPLAY_WIRE_VERSION = 1;
61
61
  var SESSION_REPLAY_SCHEMA_VERSION = 1;
62
- var SESSION_REPLAY_CONTENT_TYPE = "application/vnd.oneuptime.session-replay.v1";
62
+ var SESSION_REPLAY_CONTENT_TYPE = "application/octet-stream";
63
+ var SESSION_REPLAY_ENVELOPE_TERMINATOR = " \n";
64
+ var ESCAPED_SEQUENCES = /[%&]|(http)\//gi;
65
+ function escapeSessionReplayJson(json) {
66
+ return json.replace(
67
+ ESCAPED_SEQUENCES,
68
+ (match, http) => {
69
+ if (http !== void 0) {
70
+ return `${http}\\/`;
71
+ }
72
+ return match === "%" ? "\\u0025" : "\\u0026";
73
+ }
74
+ );
75
+ }
76
+ function encodeSessionReplayEnvelopeLine(envelope) {
77
+ return escapeSessionReplayJson(JSON.stringify(envelope)) + SESSION_REPLAY_ENVELOPE_TERMINATOR;
78
+ }
63
79
  var SESSION_REPLAY_APP_IDENTIFIER_HEADER = "x-oneuptime-app-identifier";
64
80
  var SESSION_REPLAY_RECORDER_KIND_HEADER = "x-oneuptime-replay-recorder-kind";
65
81
  var SESSION_REPLAY_MOBILE_APP_IDENTIFIER_HEADER = "x-oneuptime-mobile-app-identifier";
@@ -78,10 +94,11 @@ var SESSION_REPLAY_MAX_SESSION_MS = 4 * 60 * 6e4;
78
94
  var SESSION_REPLAY_MAX_DECOMPRESSED_FRAME_BYTES = 8 * 1024 * 1024;
79
95
  var MAX_SESSION_REPLAY_CHUNK_BYTES = 2 * 1024 * 1024;
80
96
  var MAX_SESSION_REPLAY_CHUNKS_PER_SESSION = 480;
97
+ var SESSION_REPLAY_MAX_OFFLINE_DELAY_MS = 3 * 24 * 60 * 60 * 1e3;
81
98
  var MOBILE_CAPTURE_INTERVAL_MS = 500;
82
99
  var MOBILE_RECORDER_KIND = "rn-view-tree";
83
100
  var SYNTHETIC_RRWEB_VERSION = "synthetic-1";
84
- var RECORDER_VERSION = true ? "14.0.1" : "0.0.0-dev";
101
+ var RECORDER_VERSION = true ? "14.0.2" : "0.0.0-dev";
85
102
  var SESSION_REPLAY_MOBILE_RECORDER_CAPABILITIES = [
86
103
  "mobile-view-tree",
87
104
  "mobile-touch-events",
@@ -562,6 +579,57 @@ function normalizeReplayConfig(value) {
562
579
  }
563
580
  return resolved;
564
581
  }
582
+ function replayConfigCacheKey(namespace) {
583
+ return `@oneuptime/replay/${namespace}/config`;
584
+ }
585
+ async function saveReplayConfig(storage, namespace, config, nowUnixMs) {
586
+ try {
587
+ if (!config.enabled) {
588
+ await storage.removeItem(replayConfigCacheKey(namespace));
589
+ return;
590
+ }
591
+ const cached = {
592
+ savedAtUnixMs: nowUnixMs,
593
+ config: { ...config, isTargeted: false }
594
+ };
595
+ await storage.setItem(
596
+ replayConfigCacheKey(namespace),
597
+ JSON.stringify(cached)
598
+ );
599
+ } catch {
600
+ }
601
+ }
602
+ async function forgetReplayConfig(storage, namespace) {
603
+ try {
604
+ await storage.removeItem(replayConfigCacheKey(namespace));
605
+ } catch {
606
+ }
607
+ }
608
+ async function loadCachedReplayConfig(storage, namespace, nowUnixMs) {
609
+ try {
610
+ const raw = await storage.getItem(
611
+ replayConfigCacheKey(namespace)
612
+ );
613
+ if (!raw) {
614
+ return null;
615
+ }
616
+ const cached = JSON.parse(
617
+ raw
618
+ );
619
+ const age = nowUnixMs - Number(cached.savedAtUnixMs);
620
+ if (!Number.isFinite(age) || age < 0 || age > SESSION_REPLAY_MAX_OFFLINE_DELAY_MS || !cached.config || typeof cached.config !== "object") {
621
+ return null;
622
+ }
623
+ const config = normalizeReplayConfig({
624
+ ...cached.config,
625
+ directive: cached.config.enabled === true ? "continue" : "stop",
626
+ isTargeted: false
627
+ });
628
+ return config.enabled ? config : null;
629
+ } catch {
630
+ return null;
631
+ }
632
+ }
565
633
  async function fetchReplayConfig(options, includeUserRef = false, revalidate = false) {
566
634
  const controller = typeof AbortController === "undefined" ? null : new AbortController();
567
635
  let timeout = null;
@@ -1091,878 +1159,1415 @@ function getViewport() {
1091
1159
  return viewport();
1092
1160
  }
1093
1161
 
1094
- // src/Outbox.ts
1095
- var MAX_OUTBOX_ENTRIES = 64;
1096
- var MAX_OUTBOX_BYTES = 8 * 1024 * 1024;
1097
- function isFrame(value) {
1098
- if (!value || typeof value !== "object" || Array.isArray(value)) {
1099
- return false;
1162
+ // node_modules/fflate/esm/browser.js
1163
+ var u8 = Uint8Array;
1164
+ var u16 = Uint16Array;
1165
+ var i32 = Int32Array;
1166
+ var fleb = new u8([
1167
+ 0,
1168
+ 0,
1169
+ 0,
1170
+ 0,
1171
+ 0,
1172
+ 0,
1173
+ 0,
1174
+ 0,
1175
+ 1,
1176
+ 1,
1177
+ 1,
1178
+ 1,
1179
+ 2,
1180
+ 2,
1181
+ 2,
1182
+ 2,
1183
+ 3,
1184
+ 3,
1185
+ 3,
1186
+ 3,
1187
+ 4,
1188
+ 4,
1189
+ 4,
1190
+ 4,
1191
+ 5,
1192
+ 5,
1193
+ 5,
1194
+ 5,
1195
+ 0,
1196
+ /* unused */
1197
+ 0,
1198
+ 0,
1199
+ /* impossible */
1200
+ 0
1201
+ ]);
1202
+ var fdeb = new u8([
1203
+ 0,
1204
+ 0,
1205
+ 0,
1206
+ 0,
1207
+ 1,
1208
+ 1,
1209
+ 2,
1210
+ 2,
1211
+ 3,
1212
+ 3,
1213
+ 4,
1214
+ 4,
1215
+ 5,
1216
+ 5,
1217
+ 6,
1218
+ 6,
1219
+ 7,
1220
+ 7,
1221
+ 8,
1222
+ 8,
1223
+ 9,
1224
+ 9,
1225
+ 10,
1226
+ 10,
1227
+ 11,
1228
+ 11,
1229
+ 12,
1230
+ 12,
1231
+ 13,
1232
+ 13,
1233
+ /* unused */
1234
+ 0,
1235
+ 0
1236
+ ]);
1237
+ var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
1238
+ var freb = function(eb, start) {
1239
+ var b = new u16(31);
1240
+ for (var i2 = 0; i2 < 31; ++i2) {
1241
+ b[i2] = start += 1 << eb[i2 - 1];
1100
1242
  }
1101
- const frame = value;
1102
- return typeof frame.id === "string" && typeof frame.payload === "string" && typeof frame.attempts === "number" && Number.isSafeInteger(frame.attempts) && Boolean(frame.envelope) && typeof frame.envelope === "object" && typeof frame.envelope.sessionId === "string" && typeof frame.envelope.tabId === "string" && typeof frame.envelope.chunkIndex === "number";
1103
- }
1104
- function frameId(envelope) {
1105
- return `${envelope.sessionId}:${envelope.tabId}:${envelope.chunkIndex}`;
1243
+ var r = new i32(b[30]);
1244
+ for (var i2 = 1; i2 < 30; ++i2) {
1245
+ for (var j = b[i2]; j < b[i2 + 1]; ++j) {
1246
+ r[j] = j - b[i2] << 5 | i2;
1247
+ }
1248
+ }
1249
+ return { b, r };
1250
+ };
1251
+ var _a = freb(fleb, 2);
1252
+ var fl = _a.b;
1253
+ var revfl = _a.r;
1254
+ fl[28] = 258, revfl[258] = 28;
1255
+ var _b = freb(fdeb, 0);
1256
+ var fd = _b.b;
1257
+ var revfd = _b.r;
1258
+ var rev = new u16(32768);
1259
+ for (i = 0; i < 32768; ++i) {
1260
+ x = (i & 43690) >> 1 | (i & 21845) << 1;
1261
+ x = (x & 52428) >> 2 | (x & 13107) << 2;
1262
+ x = (x & 61680) >> 4 | (x & 3855) << 4;
1263
+ rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
1106
1264
  }
1107
- var ReplayOutbox = class {
1108
- constructor(storage, namespace) {
1109
- __publicField(this, "storage");
1110
- __publicField(this, "key");
1111
- __publicField(this, "mutationQueue", Promise.resolve());
1112
- this.storage = storage;
1113
- this.key = `@oneuptime/replay/${namespace}/outbox`;
1265
+ var x;
1266
+ var i;
1267
+ var hMap = (function(cd, mb, r) {
1268
+ var s = cd.length;
1269
+ var i2 = 0;
1270
+ var l = new u16(mb);
1271
+ for (; i2 < s; ++i2) {
1272
+ if (cd[i2])
1273
+ ++l[cd[i2] - 1];
1114
1274
  }
1115
- async list() {
1116
- return await this.withLock(
1117
- async () => {
1118
- return this.readUnlocked();
1119
- }
1120
- );
1275
+ var le = new u16(mb);
1276
+ for (i2 = 1; i2 < mb; ++i2) {
1277
+ le[i2] = le[i2 - 1] + l[i2 - 1] << 1;
1121
1278
  }
1122
- async readUnlocked() {
1123
- try {
1124
- const raw = await this.storage.getItem(this.key);
1125
- if (!raw) {
1126
- return [];
1279
+ var co;
1280
+ if (r) {
1281
+ co = new u16(1 << mb);
1282
+ var rvb = 15 - mb;
1283
+ for (i2 = 0; i2 < s; ++i2) {
1284
+ if (cd[i2]) {
1285
+ var sv = i2 << 4 | cd[i2];
1286
+ var r_1 = mb - cd[i2];
1287
+ var v = le[cd[i2] - 1]++ << r_1;
1288
+ for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
1289
+ co[rev[v] >> rvb] = sv;
1290
+ }
1127
1291
  }
1128
- const parsed = JSON.parse(raw);
1129
- if (!Array.isArray(parsed) || !parsed.every(isFrame)) {
1130
- await this.removeUnlocked();
1131
- return [];
1292
+ }
1293
+ } else {
1294
+ co = new u16(s);
1295
+ for (i2 = 0; i2 < s; ++i2) {
1296
+ if (cd[i2]) {
1297
+ co[i2] = rev[le[cd[i2] - 1]++] >> 15 - cd[i2];
1132
1298
  }
1133
- return parsed.slice().sort(
1134
- (left, right) => {
1135
- return left.createdAtUnixMs - right.createdAtUnixMs;
1136
- }
1137
- );
1138
- } catch {
1139
- await this.removeUnlocked();
1140
- return [];
1141
1299
  }
1142
1300
  }
1143
- async enqueue(frame) {
1144
- return await this.withLock(async () => {
1145
- const frames = await this.readUnlocked();
1146
- if (frames.some((candidate) => {
1147
- return candidate.id === frame.id;
1148
- })) {
1149
- return { dropped: 0 };
1301
+ return co;
1302
+ });
1303
+ var flt = new u8(288);
1304
+ for (i = 0; i < 144; ++i)
1305
+ flt[i] = 8;
1306
+ var i;
1307
+ for (i = 144; i < 256; ++i)
1308
+ flt[i] = 9;
1309
+ var i;
1310
+ for (i = 256; i < 280; ++i)
1311
+ flt[i] = 7;
1312
+ var i;
1313
+ for (i = 280; i < 288; ++i)
1314
+ flt[i] = 8;
1315
+ var i;
1316
+ var fdt = new u8(32);
1317
+ for (i = 0; i < 32; ++i)
1318
+ fdt[i] = 5;
1319
+ var i;
1320
+ var flm = /* @__PURE__ */ hMap(flt, 9, 0);
1321
+ var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
1322
+ var fdm = /* @__PURE__ */ hMap(fdt, 5, 0);
1323
+ var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
1324
+ var max = function(a) {
1325
+ var m = a[0];
1326
+ for (var i2 = 1; i2 < a.length; ++i2) {
1327
+ if (a[i2] > m)
1328
+ m = a[i2];
1329
+ }
1330
+ return m;
1331
+ };
1332
+ var bits = function(d, p, m) {
1333
+ var o = p / 8 | 0;
1334
+ return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
1335
+ };
1336
+ var bits16 = function(d, p) {
1337
+ var o = p / 8 | 0;
1338
+ return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
1339
+ };
1340
+ var shft = function(p) {
1341
+ return (p + 7) / 8 | 0;
1342
+ };
1343
+ var slc = function(v, s, e) {
1344
+ if (s == null || s < 0)
1345
+ s = 0;
1346
+ if (e == null || e > v.length)
1347
+ e = v.length;
1348
+ return new u8(v.subarray(s, e));
1349
+ };
1350
+ var ec = [
1351
+ "unexpected EOF",
1352
+ "invalid block type",
1353
+ "invalid length/literal",
1354
+ "invalid distance",
1355
+ "stream finished",
1356
+ "no stream handler",
1357
+ ,
1358
+ // determined by compression function
1359
+ "no callback",
1360
+ "invalid UTF-8 data",
1361
+ "extra field too long",
1362
+ "date not in range 1980-2099",
1363
+ "filename too long",
1364
+ "stream finishing",
1365
+ "invalid zip data"
1366
+ // determined by unknown compression method
1367
+ ];
1368
+ var err = function(ind, msg, nt) {
1369
+ var e = new Error(msg || ec[ind]);
1370
+ e.code = ind;
1371
+ if (Error.captureStackTrace)
1372
+ Error.captureStackTrace(e, err);
1373
+ if (!nt)
1374
+ throw e;
1375
+ return e;
1376
+ };
1377
+ var inflt = function(dat, st, buf, dict) {
1378
+ var sl = dat.length, dl = dict ? dict.length : 0;
1379
+ if (!sl || st.f && !st.l)
1380
+ return buf || new u8(0);
1381
+ var noBuf = !buf;
1382
+ var resize = noBuf || st.i != 2;
1383
+ var noSt = st.i;
1384
+ if (noBuf)
1385
+ buf = new u8(sl * 3);
1386
+ var cbuf = function(l2) {
1387
+ var bl = buf.length;
1388
+ if (l2 > bl) {
1389
+ var nbuf = new u8(Math.max(bl * 2, l2));
1390
+ nbuf.set(buf);
1391
+ buf = nbuf;
1392
+ }
1393
+ };
1394
+ var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
1395
+ var tbts = sl * 8;
1396
+ do {
1397
+ if (!lm) {
1398
+ final = bits(dat, pos, 1);
1399
+ var type = bits(dat, pos + 1, 3);
1400
+ pos += 3;
1401
+ if (!type) {
1402
+ var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
1403
+ if (t > sl) {
1404
+ if (noSt)
1405
+ err(0);
1406
+ break;
1407
+ }
1408
+ if (resize)
1409
+ cbuf(bt + l);
1410
+ buf.set(dat.subarray(s, t), bt);
1411
+ st.b = bt += l, st.p = pos = t * 8, st.f = final;
1412
+ continue;
1413
+ } else if (type == 1)
1414
+ lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
1415
+ else if (type == 2) {
1416
+ var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
1417
+ var tl = hLit + bits(dat, pos + 5, 31) + 1;
1418
+ pos += 14;
1419
+ var ldt = new u8(tl);
1420
+ var clt = new u8(19);
1421
+ for (var i2 = 0; i2 < hcLen; ++i2) {
1422
+ clt[clim[i2]] = bits(dat, pos + i2 * 3, 7);
1423
+ }
1424
+ pos += hcLen * 3;
1425
+ var clb = max(clt), clbmsk = (1 << clb) - 1;
1426
+ var clm = hMap(clt, clb, 1);
1427
+ for (var i2 = 0; i2 < tl; ) {
1428
+ var r = clm[bits(dat, pos, clbmsk)];
1429
+ pos += r & 15;
1430
+ var s = r >> 4;
1431
+ if (s < 16) {
1432
+ ldt[i2++] = s;
1433
+ } else {
1434
+ var c = 0, n = 0;
1435
+ if (s == 16)
1436
+ n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i2 - 1];
1437
+ else if (s == 17)
1438
+ n = 3 + bits(dat, pos, 7), pos += 3;
1439
+ else if (s == 18)
1440
+ n = 11 + bits(dat, pos, 127), pos += 7;
1441
+ while (n--)
1442
+ ldt[i2++] = c;
1443
+ }
1444
+ }
1445
+ var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
1446
+ lbt = max(lt);
1447
+ dbt = max(dt);
1448
+ lm = hMap(lt, lbt, 1);
1449
+ dm = hMap(dt, dbt, 1);
1450
+ } else
1451
+ err(1);
1452
+ if (pos > tbts) {
1453
+ if (noSt)
1454
+ err(0);
1455
+ break;
1150
1456
  }
1151
- frames.push(frame);
1152
- let dropped = 0;
1153
- while (frames.length > MAX_OUTBOX_ENTRIES || byteLength(JSON.stringify(frames)) > MAX_OUTBOX_BYTES) {
1154
- frames.shift();
1155
- dropped += 1;
1457
+ }
1458
+ if (resize)
1459
+ cbuf(bt + 131072);
1460
+ var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
1461
+ var lpos = pos;
1462
+ for (; ; lpos = pos) {
1463
+ var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
1464
+ pos += c & 15;
1465
+ if (pos > tbts) {
1466
+ if (noSt)
1467
+ err(0);
1468
+ break;
1156
1469
  }
1157
- await this.writeUnlocked(frames);
1158
- return { dropped };
1159
- });
1160
- }
1161
- async remove(id) {
1162
- await this.withLock(async () => {
1163
- const frames = (await this.readUnlocked()).filter((frame) => {
1164
- return frame.id !== id;
1165
- });
1166
- await this.writeUnlocked(frames);
1167
- });
1168
- }
1169
- async incrementAttempts(id) {
1170
- return await this.withLock(async () => {
1171
- const frames = await this.readUnlocked();
1172
- let attempts = 0;
1173
- for (const frame of frames) {
1174
- if (frame.id === id) {
1175
- frame.attempts += 1;
1176
- attempts = frame.attempts;
1470
+ if (!c)
1471
+ err(2);
1472
+ if (sym < 256)
1473
+ buf[bt++] = sym;
1474
+ else if (sym == 256) {
1475
+ lpos = pos, lm = null;
1476
+ break;
1477
+ } else {
1478
+ var add = sym - 254;
1479
+ if (sym > 264) {
1480
+ var i2 = sym - 257, b = fleb[i2];
1481
+ add = bits(dat, pos, (1 << b) - 1) + fl[i2];
1482
+ pos += b;
1483
+ }
1484
+ var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
1485
+ if (!d)
1486
+ err(3);
1487
+ pos += d & 15;
1488
+ var dt = fd[dsym];
1489
+ if (dsym > 3) {
1490
+ var b = fdeb[dsym];
1491
+ dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
1492
+ }
1493
+ if (pos > tbts) {
1494
+ if (noSt)
1495
+ err(0);
1177
1496
  break;
1178
1497
  }
1498
+ if (resize)
1499
+ cbuf(bt + 131072);
1500
+ var end = bt + add;
1501
+ if (bt < dt) {
1502
+ var shift = dl - dt, dend = Math.min(dt, end);
1503
+ if (shift + bt < 0)
1504
+ err(3);
1505
+ for (; bt < dend; ++bt)
1506
+ buf[bt] = dict[shift + bt];
1507
+ }
1508
+ for (; bt < end; ++bt)
1509
+ buf[bt] = buf[bt - dt];
1179
1510
  }
1180
- await this.writeUnlocked(frames);
1181
- return attempts;
1182
- });
1511
+ }
1512
+ st.l = lm, st.p = lpos, st.b = bt, st.f = final;
1513
+ if (lm)
1514
+ final = 1, st.m = lbt, st.d = dm, st.n = dbt;
1515
+ } while (!final);
1516
+ return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
1517
+ };
1518
+ var wbits = function(d, p, v) {
1519
+ v <<= p & 7;
1520
+ var o = p / 8 | 0;
1521
+ d[o] |= v;
1522
+ d[o + 1] |= v >> 8;
1523
+ };
1524
+ var wbits16 = function(d, p, v) {
1525
+ v <<= p & 7;
1526
+ var o = p / 8 | 0;
1527
+ d[o] |= v;
1528
+ d[o + 1] |= v >> 8;
1529
+ d[o + 2] |= v >> 16;
1530
+ };
1531
+ var hTree = function(d, mb) {
1532
+ var t = [];
1533
+ for (var i2 = 0; i2 < d.length; ++i2) {
1534
+ if (d[i2])
1535
+ t.push({ s: i2, f: d[i2] });
1183
1536
  }
1184
- async clear() {
1185
- await this.withLock(async () => {
1186
- return this.removeUnlocked();
1187
- });
1537
+ var s = t.length;
1538
+ var t2 = t.slice();
1539
+ if (!s)
1540
+ return { t: et, l: 0 };
1541
+ if (s == 1) {
1542
+ var v = new u8(t[0].s + 1);
1543
+ v[t[0].s] = 1;
1544
+ return { t: v, l: 1 };
1188
1545
  }
1189
- async removeUnlocked() {
1190
- try {
1191
- await this.storage.removeItem(this.key);
1192
- } catch {
1193
- }
1546
+ t.sort(function(a, b) {
1547
+ return a.f - b.f;
1548
+ });
1549
+ t.push({ s: -1, f: 25001 });
1550
+ var l = t[0], r = t[1], i0 = 0, i1 = 1, i22 = 2;
1551
+ t[0] = { s: -1, f: l.f + r.f, l, r };
1552
+ while (i1 != s - 1) {
1553
+ l = t[t[i0].f < t[i22].f ? i0++ : i22++];
1554
+ r = t[i0 != i1 && t[i0].f < t[i22].f ? i0++ : i22++];
1555
+ t[i1++] = { s: -1, f: l.f + r.f, l, r };
1194
1556
  }
1195
- async writeUnlocked(frames) {
1196
- try {
1197
- if (frames.length === 0) {
1198
- await this.storage.removeItem(this.key);
1199
- return;
1557
+ var maxSym = t2[0].s;
1558
+ for (var i2 = 1; i2 < s; ++i2) {
1559
+ if (t2[i2].s > maxSym)
1560
+ maxSym = t2[i2].s;
1561
+ }
1562
+ var tr = new u16(maxSym + 1);
1563
+ var mbt = ln(t[i1 - 1], tr, 0);
1564
+ if (mbt > mb) {
1565
+ var i2 = 0, dt = 0;
1566
+ var lft = mbt - mb, cst = 1 << lft;
1567
+ t2.sort(function(a, b) {
1568
+ return tr[b.s] - tr[a.s] || a.f - b.f;
1569
+ });
1570
+ for (; i2 < s; ++i2) {
1571
+ var i2_1 = t2[i2].s;
1572
+ if (tr[i2_1] > mb) {
1573
+ dt += cst - (1 << mbt - tr[i2_1]);
1574
+ tr[i2_1] = mb;
1575
+ } else
1576
+ break;
1577
+ }
1578
+ dt >>= lft;
1579
+ while (dt > 0) {
1580
+ var i2_2 = t2[i2].s;
1581
+ if (tr[i2_2] < mb)
1582
+ dt -= 1 << mb - tr[i2_2]++ - 1;
1583
+ else
1584
+ ++i2;
1585
+ }
1586
+ for (; i2 >= 0 && dt; --i2) {
1587
+ var i2_3 = t2[i2].s;
1588
+ if (tr[i2_3] == mb) {
1589
+ --tr[i2_3];
1590
+ ++dt;
1200
1591
  }
1201
- await this.storage.setItem(this.key, JSON.stringify(frames));
1202
- } catch {
1203
1592
  }
1593
+ mbt = mb;
1204
1594
  }
1205
- async withLock(operation) {
1206
- const result = this.mutationQueue.then(operation, operation);
1207
- this.mutationQueue = result.then(
1208
- () => {
1209
- return void 0;
1210
- },
1211
- () => {
1212
- return void 0;
1595
+ return { t: new u8(tr), l: mbt };
1596
+ };
1597
+ var ln = function(n, l, d) {
1598
+ return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;
1599
+ };
1600
+ var lc = function(c) {
1601
+ var s = c.length;
1602
+ while (s && !c[--s])
1603
+ ;
1604
+ var cl = new u16(++s);
1605
+ var cli = 0, cln = c[0], cls = 1;
1606
+ var w = function(v) {
1607
+ cl[cli++] = v;
1608
+ };
1609
+ for (var i2 = 1; i2 <= s; ++i2) {
1610
+ if (c[i2] == cln && i2 != s)
1611
+ ++cls;
1612
+ else {
1613
+ if (!cln && cls > 2) {
1614
+ for (; cls > 138; cls -= 138)
1615
+ w(32754);
1616
+ if (cls > 2) {
1617
+ w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);
1618
+ cls = 0;
1619
+ }
1620
+ } else if (cls > 3) {
1621
+ w(cln), --cls;
1622
+ for (; cls > 6; cls -= 6)
1623
+ w(8304);
1624
+ if (cls > 2)
1625
+ w(cls - 3 << 5 | 8208), cls = 0;
1213
1626
  }
1214
- );
1215
- return await result;
1627
+ while (cls--)
1628
+ w(cln);
1629
+ cls = 1;
1630
+ cln = c[i2];
1631
+ }
1216
1632
  }
1633
+ return { c: cl.subarray(0, cli), n: s };
1217
1634
  };
1218
-
1219
- // src/Storage.ts
1220
- var import_async_storage = __toESM(require("@react-native-async-storage/async-storage"));
1221
- var REPLAY_ID_PATTERN = /^[0-9a-f]{32}$/u;
1222
- var defaultReplayStorage = import_async_storage.default;
1223
- function generateReplayId() {
1224
- const bytes = new Uint8Array(16);
1225
- const cryptoRef = globalThis.crypto;
1226
- if (cryptoRef && typeof cryptoRef.getRandomValues === "function") {
1227
- cryptoRef.getRandomValues(bytes);
1228
- } else {
1229
- for (let index = 0; index < bytes.length; index += 1) {
1230
- bytes[index] = Math.floor(Math.random() * 256);
1635
+ var clen = function(cf, cl) {
1636
+ var l = 0;
1637
+ for (var i2 = 0; i2 < cl.length; ++i2)
1638
+ l += cf[i2] * cl[i2];
1639
+ return l;
1640
+ };
1641
+ var wfblk = function(out, pos, dat) {
1642
+ var s = dat.length;
1643
+ var o = shft(pos + 2);
1644
+ out[o] = s & 255;
1645
+ out[o + 1] = s >> 8;
1646
+ out[o + 2] = out[o] ^ 255;
1647
+ out[o + 3] = out[o + 1] ^ 255;
1648
+ for (var i2 = 0; i2 < s; ++i2)
1649
+ out[o + i2 + 4] = dat[i2];
1650
+ return (o + 4 + s) * 8;
1651
+ };
1652
+ var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) {
1653
+ wbits(out, p++, final);
1654
+ ++lf[256];
1655
+ var _a2 = hTree(lf, 15), dlt = _a2.t, mlb = _a2.l;
1656
+ var _b2 = hTree(df, 15), ddt = _b2.t, mdb = _b2.l;
1657
+ var _c = lc(dlt), lclt = _c.c, nlc = _c.n;
1658
+ var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;
1659
+ var lcfreq = new u16(19);
1660
+ for (var i2 = 0; i2 < lclt.length; ++i2)
1661
+ ++lcfreq[lclt[i2] & 31];
1662
+ for (var i2 = 0; i2 < lcdt.length; ++i2)
1663
+ ++lcfreq[lcdt[i2] & 31];
1664
+ var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;
1665
+ var nlcc = 19;
1666
+ for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)
1667
+ ;
1668
+ var flen = bl + 5 << 3;
1669
+ var ftlen = clen(lf, flt) + clen(df, fdt) + eb;
1670
+ var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];
1671
+ if (bs >= 0 && flen <= ftlen && flen <= dtlen)
1672
+ return wfblk(out, p, dat.subarray(bs, bs + bl));
1673
+ var lm, ll, dm, dl;
1674
+ wbits(out, p, 1 + (dtlen < ftlen)), p += 2;
1675
+ if (dtlen < ftlen) {
1676
+ lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;
1677
+ var llm = hMap(lct, mlcb, 0);
1678
+ wbits(out, p, nlc - 257);
1679
+ wbits(out, p + 5, ndc - 1);
1680
+ wbits(out, p + 10, nlcc - 4);
1681
+ p += 14;
1682
+ for (var i2 = 0; i2 < nlcc; ++i2)
1683
+ wbits(out, p + 3 * i2, lct[clim[i2]]);
1684
+ p += 3 * nlcc;
1685
+ var lcts = [lclt, lcdt];
1686
+ for (var it = 0; it < 2; ++it) {
1687
+ var clct = lcts[it];
1688
+ for (var i2 = 0; i2 < clct.length; ++i2) {
1689
+ var len = clct[i2] & 31;
1690
+ wbits(out, p, llm[len]), p += lct[len];
1691
+ if (len > 15)
1692
+ wbits(out, p, clct[i2] >> 5 & 127), p += clct[i2] >> 12;
1693
+ }
1231
1694
  }
1695
+ } else {
1696
+ lm = flm, ll = flt, dm = fdm, dl = fdt;
1232
1697
  }
1233
- return Array.from(bytes).map((byte) => {
1234
- return byte.toString(16).padStart(2, "0");
1235
- }).join("");
1236
- }
1237
- function isReplayId(value) {
1238
- return typeof value === "string" && REPLAY_ID_PATTERN.test(value);
1239
- }
1240
- function parseStoredSession(value) {
1241
- if (!value) {
1242
- return null;
1243
- }
1244
- try {
1245
- const parsed = JSON.parse(value);
1246
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1247
- return null;
1248
- }
1249
- const candidate = parsed;
1250
- if (!isReplayId(candidate.sessionId) || !Number.isSafeInteger(candidate.sessionStartUnixMs) || !Number.isSafeInteger(candidate.lastActivityUnixMs) || !Number.isSafeInteger(candidate.nextChunkIndex) || (candidate.nextChunkIndex ?? -1) < 0) {
1251
- return null;
1698
+ for (var i2 = 0; i2 < li; ++i2) {
1699
+ var sym = syms[i2];
1700
+ if (sym > 255) {
1701
+ var len = sym >> 18 & 31;
1702
+ wbits16(out, p, lm[len + 257]), p += ll[len + 257];
1703
+ if (len > 7)
1704
+ wbits(out, p, sym >> 23 & 31), p += fleb[len];
1705
+ var dst = sym & 31;
1706
+ wbits16(out, p, dm[dst]), p += dl[dst];
1707
+ if (dst > 3)
1708
+ wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst];
1709
+ } else {
1710
+ wbits16(out, p, lm[sym]), p += ll[sym];
1252
1711
  }
1253
- return candidate;
1254
- } catch {
1255
- return null;
1256
1712
  }
1257
- }
1258
- var ReplaySessionStore = class {
1259
- constructor(storage, namespace) {
1260
- __publicField(this, "storage");
1261
- __publicField(this, "sessionKey");
1262
- __publicField(this, "visitorKey");
1263
- __publicField(this, "identity", null);
1264
- this.storage = storage;
1265
- this.sessionKey = `@oneuptime/replay/${namespace}/session`;
1266
- this.visitorKey = `@oneuptime/replay/${namespace}/visitor`;
1267
- }
1268
- async resolve(nowUnixMs) {
1269
- const stored = parseStoredSession(
1270
- await this.safeGet(this.sessionKey)
1271
- );
1272
- const shouldRotate = !stored || stored.nextChunkIndex >= MAX_SESSION_REPLAY_CHUNKS_PER_SESSION || nowUnixMs - stored.lastActivityUnixMs >= SESSION_REPLAY_IDLE_ROLLOVER_MS || nowUnixMs - stored.sessionStartUnixMs >= SESSION_REPLAY_MAX_SESSION_MS;
1273
- let session;
1274
- if (shouldRotate || !stored) {
1275
- session = {
1276
- sessionId: generateReplayId(),
1277
- sessionStartUnixMs: nowUnixMs,
1278
- lastActivityUnixMs: nowUnixMs,
1279
- nextChunkIndex: 0
1280
- };
1281
- } else {
1282
- session = {
1283
- sessionId: stored.sessionId,
1284
- sessionStartUnixMs: stored.sessionStartUnixMs,
1285
- lastActivityUnixMs: nowUnixMs,
1286
- nextChunkIndex: stored.nextChunkIndex
1287
- };
1713
+ wbits16(out, p, lm[256]);
1714
+ return p + ll[256];
1715
+ };
1716
+ var deo = /* @__PURE__ */ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
1717
+ var et = /* @__PURE__ */ new u8(0);
1718
+ var dflt = function(dat, lvl, plvl, pre, post, st) {
1719
+ var s = st.z || dat.length;
1720
+ var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);
1721
+ var w = o.subarray(pre, o.length - post);
1722
+ var lst = st.l;
1723
+ var pos = (st.r || 0) & 7;
1724
+ if (lvl) {
1725
+ if (pos)
1726
+ w[0] = st.r >> 3;
1727
+ var opt = deo[lvl - 1];
1728
+ var n = opt >> 13, c = opt & 8191;
1729
+ var msk_1 = (1 << plvl) - 1;
1730
+ var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);
1731
+ var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;
1732
+ var hsh = function(i3) {
1733
+ return (dat[i3] ^ dat[i3 + 1] << bs1_1 ^ dat[i3 + 2] << bs2_1) & msk_1;
1734
+ };
1735
+ var syms = new i32(25e3);
1736
+ var lf = new u16(288), df = new u16(32);
1737
+ var lc_1 = 0, eb = 0, i2 = st.i || 0, li = 0, wi = st.w || 0, bs = 0;
1738
+ for (; i2 + 2 < s; ++i2) {
1739
+ var hv = hsh(i2);
1740
+ var imod = i2 & 32767, pimod = head[hv];
1741
+ prev[imod] = pimod;
1742
+ head[hv] = imod;
1743
+ if (wi <= i2) {
1744
+ var rem = s - i2;
1745
+ if ((lc_1 > 7e3 || li > 24576) && (rem > 423 || !lst)) {
1746
+ pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i2 - bs, pos);
1747
+ li = lc_1 = eb = 0, bs = i2;
1748
+ for (var j = 0; j < 286; ++j)
1749
+ lf[j] = 0;
1750
+ for (var j = 0; j < 30; ++j)
1751
+ df[j] = 0;
1752
+ }
1753
+ var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;
1754
+ if (rem > 2 && hv == hsh(i2 - dif)) {
1755
+ var maxn = Math.min(n, rem) - 1;
1756
+ var maxd = Math.min(32767, i2);
1757
+ var ml = Math.min(258, rem);
1758
+ while (dif <= maxd && --ch_1 && imod != pimod) {
1759
+ if (dat[i2 + l] == dat[i2 + l - dif]) {
1760
+ var nl = 0;
1761
+ for (; nl < ml && dat[i2 + nl] == dat[i2 + nl - dif]; ++nl)
1762
+ ;
1763
+ if (nl > l) {
1764
+ l = nl, d = dif;
1765
+ if (nl > maxn)
1766
+ break;
1767
+ var mmd = Math.min(dif, nl - 2);
1768
+ var md = 0;
1769
+ for (var j = 0; j < mmd; ++j) {
1770
+ var ti = i2 - dif + j & 32767;
1771
+ var pti = prev[ti];
1772
+ var cd = ti - pti & 32767;
1773
+ if (cd > md)
1774
+ md = cd, pimod = ti;
1775
+ }
1776
+ }
1777
+ }
1778
+ imod = pimod, pimod = prev[imod];
1779
+ dif += imod - pimod & 32767;
1780
+ }
1781
+ }
1782
+ if (d) {
1783
+ syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];
1784
+ var lin = revfl[l] & 31, din = revfd[d] & 31;
1785
+ eb += fleb[lin] + fdeb[din];
1786
+ ++lf[257 + lin];
1787
+ ++df[din];
1788
+ wi = i2 + l;
1789
+ ++lc_1;
1790
+ } else {
1791
+ syms[li++] = dat[i2];
1792
+ ++lf[dat[i2]];
1793
+ }
1794
+ }
1288
1795
  }
1289
- let visitorId = await this.safeGet(this.visitorKey);
1290
- if (!isReplayId(visitorId)) {
1291
- visitorId = generateReplayId();
1292
- await this.safeSet(this.visitorKey, visitorId);
1796
+ for (i2 = Math.max(i2, wi); i2 < s; ++i2) {
1797
+ syms[li++] = dat[i2];
1798
+ ++lf[dat[i2]];
1293
1799
  }
1294
- await this.safeSet(this.sessionKey, JSON.stringify(session));
1295
- this.identity = {
1296
- sessionId: session.sessionId,
1297
- tabId: generateReplayId(),
1298
- visitorId,
1299
- sessionStartUnixMs: session.sessionStartUnixMs,
1300
- chunkIndex: session.nextChunkIndex
1301
- };
1302
- return { ...this.identity };
1303
- }
1304
- async takeChunkIndex(nowUnixMs) {
1305
- if (!this.identity) {
1306
- await this.resolve(nowUnixMs);
1800
+ pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i2 - bs, pos);
1801
+ if (!lst) {
1802
+ st.r = pos & 7 | w[pos / 8 | 0] << 3;
1803
+ pos -= 7;
1804
+ st.h = head, st.p = prev, st.i = i2, st.w = wi;
1307
1805
  }
1308
- const identity = this.identity;
1309
- const index = identity.chunkIndex;
1310
- identity.chunkIndex += 1;
1311
- const state = {
1312
- sessionId: identity.sessionId,
1313
- sessionStartUnixMs: identity.sessionStartUnixMs,
1314
- lastActivityUnixMs: nowUnixMs,
1315
- nextChunkIndex: identity.chunkIndex
1316
- };
1317
- await this.safeSet(this.sessionKey, JSON.stringify(state));
1318
- return index;
1319
- }
1320
- getNextChunkIndex() {
1321
- return this.identity?.chunkIndex ?? null;
1322
- }
1323
- async rotate(nowUnixMs) {
1324
- let visitorId = await this.safeGet(this.visitorKey);
1325
- if (!isReplayId(visitorId)) {
1326
- visitorId = generateReplayId();
1327
- await this.safeSet(this.visitorKey, visitorId);
1806
+ } else {
1807
+ for (var i2 = st.w || 0; i2 < s + lst; i2 += 65535) {
1808
+ var e = i2 + 65535;
1809
+ if (e >= s) {
1810
+ w[pos / 8 | 0] = lst;
1811
+ e = s;
1812
+ }
1813
+ pos = wfblk(w, pos + 1, dat.subarray(i2, e));
1328
1814
  }
1329
- const session = {
1330
- sessionId: generateReplayId(),
1331
- sessionStartUnixMs: nowUnixMs,
1332
- lastActivityUnixMs: nowUnixMs,
1333
- nextChunkIndex: 0
1334
- };
1335
- await this.safeSet(this.sessionKey, JSON.stringify(session));
1336
- this.identity = {
1337
- sessionId: session.sessionId,
1338
- tabId: generateReplayId(),
1339
- visitorId,
1340
- sessionStartUnixMs: nowUnixMs,
1341
- chunkIndex: 0
1342
- };
1343
- return { ...this.identity };
1815
+ st.i = s;
1344
1816
  }
1345
- async clear() {
1346
- this.identity = null;
1347
- await Promise.all([
1348
- this.safeRemove(this.sessionKey),
1349
- this.safeRemove(this.visitorKey)
1350
- ]);
1817
+ return slc(o, 0, pre + shft(pos) + post);
1818
+ };
1819
+ var crct = /* @__PURE__ */ (function() {
1820
+ var t = new Int32Array(256);
1821
+ for (var i2 = 0; i2 < 256; ++i2) {
1822
+ var c = i2, k = 9;
1823
+ while (--k)
1824
+ c = (c & 1 && -306674912) ^ c >>> 1;
1825
+ t[i2] = c;
1351
1826
  }
1352
- async safeGet(key) {
1353
- try {
1354
- return await this.storage.getItem(key);
1355
- } catch {
1356
- return null;
1827
+ return t;
1828
+ })();
1829
+ var crc = function() {
1830
+ var c = -1;
1831
+ return {
1832
+ p: function(d) {
1833
+ var cr = c;
1834
+ for (var i2 = 0; i2 < d.length; ++i2)
1835
+ cr = crct[cr & 255 ^ d[i2]] ^ cr >>> 8;
1836
+ c = cr;
1837
+ },
1838
+ d: function() {
1839
+ return ~c;
1357
1840
  }
1358
- }
1359
- async safeSet(key, value) {
1360
- try {
1361
- await this.storage.setItem(key, value);
1362
- } catch {
1841
+ };
1842
+ };
1843
+ var dopt = function(dat, opt, pre, post, st) {
1844
+ if (!st) {
1845
+ st = { l: 1 };
1846
+ if (opt.dictionary) {
1847
+ var dict = opt.dictionary.subarray(-32768);
1848
+ var newDat = new u8(dict.length + dat.length);
1849
+ newDat.set(dict);
1850
+ newDat.set(dat, dict.length);
1851
+ dat = newDat;
1852
+ st.w = dict.length;
1363
1853
  }
1364
1854
  }
1365
- async safeRemove(key) {
1366
- try {
1367
- await this.storage.removeItem(key);
1368
- } catch {
1369
- }
1855
+ return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20 : 12 + opt.mem, pre, post, st);
1856
+ };
1857
+ var wbytes = function(d, b, v) {
1858
+ for (; v; ++b)
1859
+ d[b] = v, v >>>= 8;
1860
+ };
1861
+ var gzh = function(c, o) {
1862
+ var fn = o.filename;
1863
+ c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3;
1864
+ if (o.mtime != 0)
1865
+ wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1e3));
1866
+ if (fn) {
1867
+ c[3] = 8;
1868
+ for (var i2 = 0; i2 <= fn.length; ++i2)
1869
+ c[i2 + 10] = fn.charCodeAt(i2);
1370
1870
  }
1371
1871
  };
1372
-
1373
- // node_modules/fflate/esm/browser.js
1374
- var u8 = Uint8Array;
1375
- var u16 = Uint16Array;
1376
- var i32 = Int32Array;
1377
- var fleb = new u8([
1378
- 0,
1379
- 0,
1380
- 0,
1381
- 0,
1382
- 0,
1383
- 0,
1384
- 0,
1385
- 0,
1386
- 1,
1387
- 1,
1388
- 1,
1389
- 1,
1390
- 2,
1391
- 2,
1392
- 2,
1393
- 2,
1394
- 3,
1395
- 3,
1396
- 3,
1397
- 3,
1398
- 4,
1399
- 4,
1400
- 4,
1401
- 4,
1402
- 5,
1403
- 5,
1404
- 5,
1405
- 5,
1406
- 0,
1407
- /* unused */
1408
- 0,
1409
- 0,
1410
- /* impossible */
1411
- 0
1412
- ]);
1413
- var fdeb = new u8([
1414
- 0,
1415
- 0,
1416
- 0,
1417
- 0,
1418
- 1,
1419
- 1,
1420
- 2,
1421
- 2,
1422
- 3,
1423
- 3,
1424
- 4,
1425
- 4,
1426
- 5,
1427
- 5,
1428
- 6,
1429
- 6,
1430
- 7,
1431
- 7,
1432
- 8,
1433
- 8,
1434
- 9,
1435
- 9,
1436
- 10,
1437
- 10,
1438
- 11,
1439
- 11,
1440
- 12,
1441
- 12,
1442
- 13,
1443
- 13,
1444
- /* unused */
1445
- 0,
1446
- 0
1447
- ]);
1448
- var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
1449
- var freb = function(eb, start) {
1450
- var b = new u16(31);
1451
- for (var i2 = 0; i2 < 31; ++i2) {
1452
- b[i2] = start += 1 << eb[i2 - 1];
1872
+ var gzs = function(d) {
1873
+ if (d[0] != 31 || d[1] != 139 || d[2] != 8)
1874
+ err(6, "invalid gzip data");
1875
+ var flg = d[3];
1876
+ var st = 10;
1877
+ if (flg & 4)
1878
+ st += (d[10] | d[11] << 8) + 2;
1879
+ for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++])
1880
+ ;
1881
+ return st + (flg & 2);
1882
+ };
1883
+ var gzl = function(d) {
1884
+ var l = d.length;
1885
+ return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0;
1886
+ };
1887
+ var gzhl = function(o) {
1888
+ return 10 + (o.filename ? o.filename.length + 1 : 0);
1889
+ };
1890
+ function gzipSync(data, opts) {
1891
+ if (!opts)
1892
+ opts = {};
1893
+ var c = crc(), l = data.length;
1894
+ c.p(data);
1895
+ var d = dopt(data, opts, gzhl(opts), 8), s = d.length;
1896
+ return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d;
1897
+ }
1898
+ function gunzipSync(data, opts) {
1899
+ var st = gzs(data);
1900
+ if (st + 8 > data.length)
1901
+ err(6, "invalid gzip data");
1902
+ return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary);
1903
+ }
1904
+ var te = typeof TextEncoder != "undefined" && /* @__PURE__ */ new TextEncoder();
1905
+ var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
1906
+ var tds = 0;
1907
+ try {
1908
+ td.decode(et, { stream: true });
1909
+ tds = 1;
1910
+ } catch (e) {
1911
+ }
1912
+ var dutf8 = function(d) {
1913
+ for (var r = "", i2 = 0; ; ) {
1914
+ var c = d[i2++];
1915
+ var eb = (c > 127) + (c > 223) + (c > 239);
1916
+ if (i2 + eb > d.length)
1917
+ return { s: r, r: slc(d, i2 - 1) };
1918
+ if (!eb)
1919
+ r += String.fromCharCode(c);
1920
+ else if (eb == 3) {
1921
+ c = ((c & 15) << 18 | (d[i2++] & 63) << 12 | (d[i2++] & 63) << 6 | d[i2++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
1922
+ } else if (eb & 1)
1923
+ r += String.fromCharCode((c & 31) << 6 | d[i2++] & 63);
1924
+ else
1925
+ r += String.fromCharCode((c & 15) << 12 | (d[i2++] & 63) << 6 | d[i2++] & 63);
1453
1926
  }
1454
- var r = new i32(b[30]);
1455
- for (var i2 = 1; i2 < 30; ++i2) {
1456
- for (var j = b[i2]; j < b[i2 + 1]; ++j) {
1457
- r[j] = j - b[i2] << 5 | i2;
1927
+ };
1928
+ function strToU8(str, latin1) {
1929
+ if (latin1) {
1930
+ var ar_1 = new u8(str.length);
1931
+ for (var i2 = 0; i2 < str.length; ++i2)
1932
+ ar_1[i2] = str.charCodeAt(i2);
1933
+ return ar_1;
1934
+ }
1935
+ if (te)
1936
+ return te.encode(str);
1937
+ var l = str.length;
1938
+ var ar = new u8(str.length + (str.length >> 1));
1939
+ var ai = 0;
1940
+ var w = function(v) {
1941
+ ar[ai++] = v;
1942
+ };
1943
+ for (var i2 = 0; i2 < l; ++i2) {
1944
+ if (ai + 5 > ar.length) {
1945
+ var n = new u8(ai + 8 + (l - i2 << 1));
1946
+ n.set(ar);
1947
+ ar = n;
1458
1948
  }
1949
+ var c = str.charCodeAt(i2);
1950
+ if (c < 128 || latin1)
1951
+ w(c);
1952
+ else if (c < 2048)
1953
+ w(192 | c >> 6), w(128 | c & 63);
1954
+ else if (c > 55295 && c < 57344)
1955
+ c = 65536 + (c & 1023 << 10) | str.charCodeAt(++i2) & 1023, w(240 | c >> 18), w(128 | c >> 12 & 63), w(128 | c >> 6 & 63), w(128 | c & 63);
1956
+ else
1957
+ w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63);
1459
1958
  }
1460
- return { b, r };
1461
- };
1462
- var _a = freb(fleb, 2);
1463
- var fl = _a.b;
1464
- var revfl = _a.r;
1465
- fl[28] = 258, revfl[258] = 28;
1466
- var _b = freb(fdeb, 0);
1467
- var fd = _b.b;
1468
- var revfd = _b.r;
1469
- var rev = new u16(32768);
1470
- for (i = 0; i < 32768; ++i) {
1471
- x = (i & 43690) >> 1 | (i & 21845) << 1;
1472
- x = (x & 52428) >> 2 | (x & 13107) << 2;
1473
- x = (x & 61680) >> 4 | (x & 3855) << 4;
1474
- rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
1959
+ return slc(ar, 0, ai);
1475
1960
  }
1476
- var x;
1477
- var i;
1478
- var hMap = (function(cd, mb, r) {
1479
- var s = cd.length;
1480
- var i2 = 0;
1481
- var l = new u16(mb);
1482
- for (; i2 < s; ++i2) {
1483
- if (cd[i2])
1484
- ++l[cd[i2] - 1];
1961
+ function strFromU8(dat, latin1) {
1962
+ if (latin1) {
1963
+ var r = "";
1964
+ for (var i2 = 0; i2 < dat.length; i2 += 16384)
1965
+ r += String.fromCharCode.apply(null, dat.subarray(i2, i2 + 16384));
1966
+ return r;
1967
+ } else if (td) {
1968
+ return td.decode(dat);
1969
+ } else {
1970
+ var _a2 = dutf8(dat), s = _a2.s, r = _a2.r;
1971
+ if (r.length)
1972
+ err(8);
1973
+ return s;
1485
1974
  }
1486
- var le = new u16(mb);
1487
- for (i2 = 1; i2 < mb; ++i2) {
1488
- le[i2] = le[i2 - 1] + l[i2 - 1] << 1;
1975
+ }
1976
+
1977
+ // src/Base64.ts
1978
+ var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1979
+ var LOOKUP = (() => {
1980
+ const table = new Int16Array(128).fill(-1);
1981
+ for (let index = 0; index < ALPHABET.length; index += 1) {
1982
+ table[ALPHABET.charCodeAt(index)] = index;
1983
+ }
1984
+ return table;
1985
+ })();
1986
+ function encodeBase64(bytes) {
1987
+ const parts = [];
1988
+ for (let index = 0; index < bytes.length; index += 3) {
1989
+ const first = bytes[index];
1990
+ const second = bytes[index + 1];
1991
+ const third = bytes[index + 2];
1992
+ const triple = first << 16 | (second ?? 0) << 8 | (third ?? 0);
1993
+ parts.push(
1994
+ ALPHABET.charAt(triple >> 18 & 63) + ALPHABET.charAt(triple >> 12 & 63) + (second === void 0 ? "=" : ALPHABET.charAt(triple >> 6 & 63)) + (third === void 0 ? "=" : ALPHABET.charAt(triple & 63))
1995
+ );
1489
1996
  }
1490
- var co;
1491
- if (r) {
1492
- co = new u16(1 << mb);
1493
- var rvb = 15 - mb;
1494
- for (i2 = 0; i2 < s; ++i2) {
1495
- if (cd[i2]) {
1496
- var sv = i2 << 4 | cd[i2];
1497
- var r_1 = mb - cd[i2];
1498
- var v = le[cd[i2] - 1]++ << r_1;
1499
- for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
1500
- co[rev[v] >> rvb] = sv;
1501
- }
1502
- }
1997
+ return parts.join("");
1998
+ }
1999
+ function decodeBase64(text) {
2000
+ if (typeof text !== "string" || text.length % 4 !== 0) {
2001
+ return null;
2002
+ }
2003
+ const padding = text.endsWith("==") ? 2 : text.endsWith("=") ? 1 : 0;
2004
+ const bytes = new Uint8Array(text.length / 4 * 3 - padding);
2005
+ let buffer = 0;
2006
+ let bits2 = 0;
2007
+ let written = 0;
2008
+ for (let index = 0; index < text.length - padding; index += 1) {
2009
+ const code = text.charCodeAt(index);
2010
+ const value = code < 128 ? LOOKUP[code] : -1;
2011
+ if (value < 0) {
2012
+ return null;
1503
2013
  }
1504
- } else {
1505
- co = new u16(s);
1506
- for (i2 = 0; i2 < s; ++i2) {
1507
- if (cd[i2]) {
1508
- co[i2] = rev[le[cd[i2] - 1]++] >> 15 - cd[i2];
1509
- }
2014
+ buffer = (buffer << 6 | value) & 16777215;
2015
+ bits2 += 6;
2016
+ if (bits2 >= 8) {
2017
+ bits2 -= 8;
2018
+ bytes[written] = buffer >> bits2 & 255;
2019
+ written += 1;
1510
2020
  }
1511
2021
  }
1512
- return co;
1513
- });
1514
- var flt = new u8(288);
1515
- for (i = 0; i < 144; ++i)
1516
- flt[i] = 8;
1517
- var i;
1518
- for (i = 144; i < 256; ++i)
1519
- flt[i] = 9;
1520
- var i;
1521
- for (i = 256; i < 280; ++i)
1522
- flt[i] = 7;
1523
- var i;
1524
- for (i = 280; i < 288; ++i)
1525
- flt[i] = 8;
1526
- var i;
1527
- var fdt = new u8(32);
1528
- for (i = 0; i < 32; ++i)
1529
- fdt[i] = 5;
1530
- var i;
1531
- var flm = /* @__PURE__ */ hMap(flt, 9, 0);
1532
- var fdm = /* @__PURE__ */ hMap(fdt, 5, 0);
1533
- var shft = function(p) {
1534
- return (p + 7) / 8 | 0;
1535
- };
1536
- var slc = function(v, s, e) {
1537
- if (s == null || s < 0)
1538
- s = 0;
1539
- if (e == null || e > v.length)
1540
- e = v.length;
1541
- return new u8(v.subarray(s, e));
1542
- };
1543
- var wbits = function(d, p, v) {
1544
- v <<= p & 7;
1545
- var o = p / 8 | 0;
1546
- d[o] |= v;
1547
- d[o + 1] |= v >> 8;
1548
- };
1549
- var wbits16 = function(d, p, v) {
1550
- v <<= p & 7;
1551
- var o = p / 8 | 0;
1552
- d[o] |= v;
1553
- d[o + 1] |= v >> 8;
1554
- d[o + 2] |= v >> 16;
1555
- };
1556
- var hTree = function(d, mb) {
1557
- var t = [];
1558
- for (var i2 = 0; i2 < d.length; ++i2) {
1559
- if (d[i2])
1560
- t.push({ s: i2, f: d[i2] });
2022
+ return written === bytes.length ? bytes : null;
2023
+ }
2024
+
2025
+ // src/Outbox.ts
2026
+ var MAX_OUTBOX_ENTRIES = 240;
2027
+ var MAX_OUTBOX_BYTES = 3 * 1024 * 1024;
2028
+ function isEnvelope(value) {
2029
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2030
+ return false;
1561
2031
  }
1562
- var s = t.length;
1563
- var t2 = t.slice();
1564
- if (!s)
1565
- return { t: et, l: 0 };
1566
- if (s == 1) {
1567
- var v = new u8(t[0].s + 1);
1568
- v[t[0].s] = 1;
1569
- return { t: v, l: 1 };
2032
+ const envelope = value;
2033
+ return typeof envelope.sessionId === "string" && typeof envelope.tabId === "string" && typeof envelope.chunkIndex === "number";
2034
+ }
2035
+ function isEntry(value) {
2036
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2037
+ return false;
1570
2038
  }
1571
- t.sort(function(a, b) {
1572
- return a.f - b.f;
1573
- });
1574
- t.push({ s: -1, f: 25001 });
1575
- var l = t[0], r = t[1], i0 = 0, i1 = 1, i22 = 2;
1576
- t[0] = { s: -1, f: l.f + r.f, l, r };
1577
- while (i1 != s - 1) {
1578
- l = t[t[i0].f < t[i22].f ? i0++ : i22++];
1579
- r = t[i0 != i1 && t[i0].f < t[i22].f ? i0++ : i22++];
1580
- t[i1++] = { s: -1, f: l.f + r.f, l, r };
2039
+ const entry = value;
2040
+ return typeof entry.id === "string" && Number.isSafeInteger(entry.attempts) && typeof entry.createdAtUnixMs === "number" && Number.isFinite(entry.createdAtUnixMs) && Number.isSafeInteger(entry.bytes);
2041
+ }
2042
+ function isLegacyFrame(value) {
2043
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2044
+ return false;
1581
2045
  }
1582
- var maxSym = t2[0].s;
1583
- for (var i2 = 1; i2 < s; ++i2) {
1584
- if (t2[i2].s > maxSym)
1585
- maxSym = t2[i2].s;
2046
+ const frame = value;
2047
+ return typeof frame.id === "string" && typeof frame.payload === "string" && typeof frame.attempts === "number" && Number.isSafeInteger(frame.attempts) && typeof frame.createdAtUnixMs === "number" && isEnvelope(frame.envelope);
2048
+ }
2049
+ function byOldest(left, right) {
2050
+ return left.createdAtUnixMs - right.createdAtUnixMs;
2051
+ }
2052
+ function frameId(envelope) {
2053
+ return `${envelope.sessionId}:${envelope.tabId}:${envelope.chunkIndex}`;
2054
+ }
2055
+ var ReplayOutbox = class {
2056
+ constructor(storage, namespace, now = Date.now) {
2057
+ __publicField(this, "storage");
2058
+ __publicField(this, "legacyKey");
2059
+ __publicField(this, "indexKey");
2060
+ __publicField(this, "framePrefix");
2061
+ __publicField(this, "now");
2062
+ __publicField(this, "mutationQueue", Promise.resolve());
2063
+ __publicField(this, "migrated", false);
2064
+ this.storage = storage;
2065
+ this.legacyKey = `@oneuptime/replay/${namespace}/outbox`;
2066
+ this.indexKey = `@oneuptime/replay/${namespace}/outbox-v2`;
2067
+ this.framePrefix = `@oneuptime/replay/${namespace}/outbox-v2/`;
2068
+ this.now = now;
1586
2069
  }
1587
- var tr = new u16(maxSym + 1);
1588
- var mbt = ln(t[i1 - 1], tr, 0);
1589
- if (mbt > mb) {
1590
- var i2 = 0, dt = 0;
1591
- var lft = mbt - mb, cst = 1 << lft;
1592
- t2.sort(function(a, b) {
1593
- return tr[b.s] - tr[a.s] || a.f - b.f;
2070
+ /* Every queued frame's index entry, oldest first. Reads no payload. */
2071
+ async entries() {
2072
+ return await this.withLock(async () => {
2073
+ return await this.readIndexUnlocked();
1594
2074
  });
1595
- for (; i2 < s; ++i2) {
1596
- var i2_1 = t2[i2].s;
1597
- if (tr[i2_1] > mb) {
1598
- dt += cst - (1 << mbt - tr[i2_1]);
1599
- tr[i2_1] = mb;
1600
- } else
1601
- break;
2075
+ }
2076
+ /*
2077
+ * One frame, ready to post. Null when it is no longer queued, and
2078
+ * "unreadable" when its value could not be read back - it is removed, so
2079
+ * one damaged frame never blocks the ones behind it.
2080
+ */
2081
+ async load(id) {
2082
+ return await this.withLock(
2083
+ async () => {
2084
+ const entries = await this.readIndexUnlocked();
2085
+ const entry = entries.find(
2086
+ (candidate) => {
2087
+ return candidate.id === id;
2088
+ }
2089
+ );
2090
+ if (!entry) {
2091
+ return null;
2092
+ }
2093
+ const value = await this.readFrameUnlocked(id);
2094
+ if (!value) {
2095
+ await this.removeEntriesUnlocked(entries, [id]);
2096
+ return "unreadable";
2097
+ }
2098
+ return {
2099
+ id,
2100
+ envelope: value.envelope,
2101
+ compressedPayload: value.bytes,
2102
+ attempts: entry.attempts,
2103
+ createdAtUnixMs: entry.createdAtUnixMs
2104
+ };
2105
+ }
2106
+ );
2107
+ }
2108
+ /* Every frame with its payload decompressed, oldest first. */
2109
+ async list() {
2110
+ const frames = [];
2111
+ for (const entry of await this.entries()) {
2112
+ const frame = await this.load(
2113
+ entry.id
2114
+ );
2115
+ if (!frame || frame === "unreadable") {
2116
+ continue;
2117
+ }
2118
+ frames.push({
2119
+ id: frame.id,
2120
+ envelope: frame.envelope,
2121
+ payload: strFromU8(gunzipSync(frame.compressedPayload)),
2122
+ attempts: frame.attempts,
2123
+ createdAtUnixMs: frame.createdAtUnixMs
2124
+ });
1602
2125
  }
1603
- dt >>= lft;
1604
- while (dt > 0) {
1605
- var i2_2 = t2[i2].s;
1606
- if (tr[i2_2] < mb)
1607
- dt -= 1 << mb - tr[i2_2]++ - 1;
1608
- else
1609
- ++i2;
2126
+ return frames;
2127
+ }
2128
+ /*
2129
+ * Queue a frame. Past MAX_OUTBOX_ENTRIES or MAX_OUTBOX_BYTES the OLDEST
2130
+ * frames are evicted - the newest seconds are the ones closest to whatever
2131
+ * went wrong, and a later full snapshot re-anchors the player after a gap -
2132
+ * and counted in `dropped`, as is a frame the device had no room to store.
2133
+ */
2134
+ async enqueue(frame) {
2135
+ return await this.withLock(async () => {
2136
+ const entries = await this.readIndexUnlocked();
2137
+ if (entries.some((candidate) => {
2138
+ return candidate.id === frame.id;
2139
+ })) {
2140
+ return { dropped: 0 };
2141
+ }
2142
+ const bytes = await this.writeFrameUnlocked(frame);
2143
+ if (bytes === null) {
2144
+ return { dropped: 1 };
2145
+ }
2146
+ entries.push({
2147
+ id: frame.id,
2148
+ attempts: frame.attempts,
2149
+ createdAtUnixMs: frame.createdAtUnixMs,
2150
+ bytes
2151
+ });
2152
+ entries.sort(byOldest);
2153
+ let totalBytes = 0;
2154
+ for (const entry of entries) {
2155
+ totalBytes += entry.bytes;
2156
+ }
2157
+ const evicted = [];
2158
+ while (entries.length > 1 && (entries.length > MAX_OUTBOX_ENTRIES || totalBytes > MAX_OUTBOX_BYTES)) {
2159
+ const oldest = entries.shift();
2160
+ totalBytes -= oldest.bytes;
2161
+ evicted.push(oldest.id);
2162
+ }
2163
+ if (!await this.writeIndexUnlocked(entries)) {
2164
+ await this.safeRemove(this.frameKey(frame.id));
2165
+ return { dropped: 1 };
2166
+ }
2167
+ await Promise.all(
2168
+ evicted.map((id) => {
2169
+ return this.safeRemove(this.frameKey(id));
2170
+ })
2171
+ );
2172
+ return { dropped: evicted.length };
2173
+ });
2174
+ }
2175
+ async remove(id) {
2176
+ await this.withLock(async () => {
2177
+ await this.removeEntriesUnlocked(await this.readIndexUnlocked(), [id]);
2178
+ });
2179
+ }
2180
+ async incrementAttempts(id) {
2181
+ return await this.withLock(async () => {
2182
+ const entries = await this.readIndexUnlocked();
2183
+ let attempts = 0;
2184
+ for (const entry of entries) {
2185
+ if (entry.id === id) {
2186
+ entry.attempts += 1;
2187
+ attempts = entry.attempts;
2188
+ break;
2189
+ }
2190
+ }
2191
+ await this.writeIndexUnlocked(entries);
2192
+ return attempts;
2193
+ });
2194
+ }
2195
+ /*
2196
+ * Consent withdrawn, or the server refused this recorder for good: every
2197
+ * frame goes, including any a crash left untracked by the index when the
2198
+ * storage can list its keys.
2199
+ */
2200
+ async clear() {
2201
+ await this.withLock(async () => {
2202
+ const keys = /* @__PURE__ */ new Set([
2203
+ this.legacyKey,
2204
+ this.indexKey
2205
+ ]);
2206
+ for (const entry of await this.readRawIndexUnlocked()) {
2207
+ keys.add(this.frameKey(entry.id));
2208
+ }
2209
+ if (typeof this.storage.getAllKeys === "function") {
2210
+ try {
2211
+ for (const key of await this.storage.getAllKeys()) {
2212
+ if (key.startsWith(this.framePrefix)) {
2213
+ keys.add(key);
2214
+ }
2215
+ }
2216
+ } catch {
2217
+ }
2218
+ }
2219
+ this.migrated = true;
2220
+ await Promise.all(
2221
+ Array.from(keys).map((key) => {
2222
+ return this.safeRemove(key);
2223
+ })
2224
+ );
2225
+ });
2226
+ }
2227
+ frameKey(id) {
2228
+ return `${this.framePrefix}${id}`;
2229
+ }
2230
+ /*
2231
+ * The index, with the legacy layout migrated into it on first use and
2232
+ * anything older than SESSION_REPLAY_MAX_OFFLINE_DELAY_MS pruned: the
2233
+ * server would no longer place it on the recording's real timeline.
2234
+ */
2235
+ async readIndexUnlocked() {
2236
+ await this.migrateUnlocked();
2237
+ const entries = await this.readRawIndexUnlocked();
2238
+ const oldestKept = this.now() - SESSION_REPLAY_MAX_OFFLINE_DELAY_MS;
2239
+ const expired = entries.filter((entry) => {
2240
+ return entry.createdAtUnixMs < oldestKept;
2241
+ }).map((entry) => {
2242
+ return entry.id;
2243
+ });
2244
+ if (expired.length > 0) {
2245
+ await this.removeEntriesUnlocked(entries, expired);
1610
2246
  }
1611
- for (; i2 >= 0 && dt; --i2) {
1612
- var i2_3 = t2[i2].s;
1613
- if (tr[i2_3] == mb) {
1614
- --tr[i2_3];
1615
- ++dt;
2247
+ return entries.sort(byOldest);
2248
+ }
2249
+ async readRawIndexUnlocked() {
2250
+ let raw = null;
2251
+ try {
2252
+ raw = await this.storage.getItem(this.indexKey);
2253
+ } catch {
2254
+ raw = null;
2255
+ }
2256
+ if (!raw) {
2257
+ return [];
2258
+ }
2259
+ try {
2260
+ const parsed = JSON.parse(raw);
2261
+ if (Array.isArray(parsed) && parsed.every(isEntry)) {
2262
+ return parsed;
1616
2263
  }
2264
+ } catch {
1617
2265
  }
1618
- mbt = mb;
2266
+ await this.safeRemove(this.indexKey);
2267
+ return [];
1619
2268
  }
1620
- return { t: new u8(tr), l: mbt };
1621
- };
1622
- var ln = function(n, l, d) {
1623
- return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;
1624
- };
1625
- var lc = function(c) {
1626
- var s = c.length;
1627
- while (s && !c[--s])
1628
- ;
1629
- var cl = new u16(++s);
1630
- var cli = 0, cln = c[0], cls = 1;
1631
- var w = function(v) {
1632
- cl[cli++] = v;
1633
- };
1634
- for (var i2 = 1; i2 <= s; ++i2) {
1635
- if (c[i2] == cln && i2 != s)
1636
- ++cls;
1637
- else {
1638
- if (!cln && cls > 2) {
1639
- for (; cls > 138; cls -= 138)
1640
- w(32754);
1641
- if (cls > 2) {
1642
- w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);
1643
- cls = 0;
1644
- }
1645
- } else if (cls > 3) {
1646
- w(cln), --cls;
1647
- for (; cls > 6; cls -= 6)
1648
- w(8304);
1649
- if (cls > 2)
1650
- w(cls - 3 << 5 | 8208), cls = 0;
2269
+ async writeIndexUnlocked(entries) {
2270
+ if (entries.length === 0) {
2271
+ await this.safeRemove(this.indexKey);
2272
+ return true;
2273
+ }
2274
+ return await this.safeSet(this.indexKey, JSON.stringify(entries));
2275
+ }
2276
+ /* Drop entries from the index and their frames from storage. */
2277
+ async removeEntriesUnlocked(entries, ids) {
2278
+ const removing = new Set(ids);
2279
+ const kept = entries.filter(
2280
+ (entry) => {
2281
+ return !removing.has(entry.id);
1651
2282
  }
1652
- while (cls--)
1653
- w(cln);
1654
- cls = 1;
1655
- cln = c[i2];
2283
+ );
2284
+ entries.splice(0, entries.length, ...kept);
2285
+ await this.writeIndexUnlocked(entries);
2286
+ await Promise.all(
2287
+ ids.map((id) => {
2288
+ return this.safeRemove(this.frameKey(id));
2289
+ })
2290
+ );
2291
+ }
2292
+ /* Store one frame's value. Its size, or null when it could not be stored. */
2293
+ async writeFrameUnlocked(frame) {
2294
+ let value;
2295
+ try {
2296
+ const stored = {
2297
+ envelope: frame.envelope,
2298
+ gzip: encodeBase64(gzipSync(strToU8(frame.payload)))
2299
+ };
2300
+ value = JSON.stringify(stored);
2301
+ } catch {
2302
+ return null;
1656
2303
  }
2304
+ return await this.safeSet(this.frameKey(frame.id), value) ? byteLength(value) : null;
1657
2305
  }
1658
- return { c: cl.subarray(0, cli), n: s };
1659
- };
1660
- var clen = function(cf, cl) {
1661
- var l = 0;
1662
- for (var i2 = 0; i2 < cl.length; ++i2)
1663
- l += cf[i2] * cl[i2];
1664
- return l;
1665
- };
1666
- var wfblk = function(out, pos, dat) {
1667
- var s = dat.length;
1668
- var o = shft(pos + 2);
1669
- out[o] = s & 255;
1670
- out[o + 1] = s >> 8;
1671
- out[o + 2] = out[o] ^ 255;
1672
- out[o + 3] = out[o + 1] ^ 255;
1673
- for (var i2 = 0; i2 < s; ++i2)
1674
- out[o + i2 + 4] = dat[i2];
1675
- return (o + 4 + s) * 8;
1676
- };
1677
- var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) {
1678
- wbits(out, p++, final);
1679
- ++lf[256];
1680
- var _a2 = hTree(lf, 15), dlt = _a2.t, mlb = _a2.l;
1681
- var _b2 = hTree(df, 15), ddt = _b2.t, mdb = _b2.l;
1682
- var _c = lc(dlt), lclt = _c.c, nlc = _c.n;
1683
- var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;
1684
- var lcfreq = new u16(19);
1685
- for (var i2 = 0; i2 < lclt.length; ++i2)
1686
- ++lcfreq[lclt[i2] & 31];
1687
- for (var i2 = 0; i2 < lcdt.length; ++i2)
1688
- ++lcfreq[lcdt[i2] & 31];
1689
- var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;
1690
- var nlcc = 19;
1691
- for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)
1692
- ;
1693
- var flen = bl + 5 << 3;
1694
- var ftlen = clen(lf, flt) + clen(df, fdt) + eb;
1695
- var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];
1696
- if (bs >= 0 && flen <= ftlen && flen <= dtlen)
1697
- return wfblk(out, p, dat.subarray(bs, bs + bl));
1698
- var lm, ll, dm, dl;
1699
- wbits(out, p, 1 + (dtlen < ftlen)), p += 2;
1700
- if (dtlen < ftlen) {
1701
- lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;
1702
- var llm = hMap(lct, mlcb, 0);
1703
- wbits(out, p, nlc - 257);
1704
- wbits(out, p + 5, ndc - 1);
1705
- wbits(out, p + 10, nlcc - 4);
1706
- p += 14;
1707
- for (var i2 = 0; i2 < nlcc; ++i2)
1708
- wbits(out, p + 3 * i2, lct[clim[i2]]);
1709
- p += 3 * nlcc;
1710
- var lcts = [lclt, lcdt];
1711
- for (var it = 0; it < 2; ++it) {
1712
- var clct = lcts[it];
1713
- for (var i2 = 0; i2 < clct.length; ++i2) {
1714
- var len = clct[i2] & 31;
1715
- wbits(out, p, llm[len]), p += lct[len];
1716
- if (len > 15)
1717
- wbits(out, p, clct[i2] >> 5 & 127), p += clct[i2] >> 12;
2306
+ async readFrameUnlocked(id) {
2307
+ try {
2308
+ const raw = await this.storage.getItem(this.frameKey(id));
2309
+ if (!raw) {
2310
+ return null;
1718
2311
  }
2312
+ const parsed = JSON.parse(
2313
+ raw
2314
+ );
2315
+ const bytes = typeof parsed.gzip === "string" ? decodeBase64(parsed.gzip) : null;
2316
+ if (!bytes || !isEnvelope(parsed.envelope)) {
2317
+ return null;
2318
+ }
2319
+ return { envelope: parsed.envelope, bytes };
2320
+ } catch {
2321
+ return null;
1719
2322
  }
1720
- } else {
1721
- lm = flm, ll = flt, dm = fdm, dl = fdt;
1722
2323
  }
1723
- for (var i2 = 0; i2 < li; ++i2) {
1724
- var sym = syms[i2];
1725
- if (sym > 255) {
1726
- var len = sym >> 18 & 31;
1727
- wbits16(out, p, lm[len + 257]), p += ll[len + 257];
1728
- if (len > 7)
1729
- wbits(out, p, sym >> 23 & 31), p += fleb[len];
1730
- var dst = sym & 31;
1731
- wbits16(out, p, dm[dst]), p += dl[dst];
1732
- if (dst > 3)
1733
- wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst];
1734
- } else {
1735
- wbits16(out, p, lm[sym]), p += ll[sym];
2324
+ /*
2325
+ * Move a queue written by an earlier SDK version (one JSON array under the
2326
+ * legacy key) into this layout, once. A legacy queue too large to read -
2327
+ * the very failure this layout exists to fix - cannot be recovered, only
2328
+ * removed so it stops failing.
2329
+ */
2330
+ async migrateUnlocked() {
2331
+ if (this.migrated) {
2332
+ return;
2333
+ }
2334
+ this.migrated = true;
2335
+ let raw = null;
2336
+ try {
2337
+ raw = await this.storage.getItem(this.legacyKey);
2338
+ } catch {
2339
+ await this.safeRemove(this.legacyKey);
2340
+ return;
1736
2341
  }
2342
+ if (!raw) {
2343
+ return;
2344
+ }
2345
+ let legacy = [];
2346
+ try {
2347
+ const parsed = JSON.parse(raw);
2348
+ if (Array.isArray(parsed)) {
2349
+ legacy = parsed.filter(isLegacyFrame);
2350
+ }
2351
+ } catch {
2352
+ legacy = [];
2353
+ }
2354
+ const entries = await this.readRawIndexUnlocked();
2355
+ for (const frame of legacy) {
2356
+ if (entries.some((entry) => {
2357
+ return entry.id === frame.id;
2358
+ })) {
2359
+ continue;
2360
+ }
2361
+ const bytes = await this.writeFrameUnlocked(frame);
2362
+ if (bytes !== null) {
2363
+ entries.push({
2364
+ id: frame.id,
2365
+ attempts: frame.attempts,
2366
+ createdAtUnixMs: frame.createdAtUnixMs,
2367
+ bytes
2368
+ });
2369
+ }
2370
+ }
2371
+ await this.writeIndexUnlocked(entries.sort(byOldest));
2372
+ await this.safeRemove(this.legacyKey);
1737
2373
  }
1738
- wbits16(out, p, lm[256]);
1739
- return p + ll[256];
1740
- };
1741
- var deo = /* @__PURE__ */ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
1742
- var et = /* @__PURE__ */ new u8(0);
1743
- var dflt = function(dat, lvl, plvl, pre, post, st) {
1744
- var s = st.z || dat.length;
1745
- var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);
1746
- var w = o.subarray(pre, o.length - post);
1747
- var lst = st.l;
1748
- var pos = (st.r || 0) & 7;
1749
- if (lvl) {
1750
- if (pos)
1751
- w[0] = st.r >> 3;
1752
- var opt = deo[lvl - 1];
1753
- var n = opt >> 13, c = opt & 8191;
1754
- var msk_1 = (1 << plvl) - 1;
1755
- var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);
1756
- var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;
1757
- var hsh = function(i3) {
1758
- return (dat[i3] ^ dat[i3 + 1] << bs1_1 ^ dat[i3 + 2] << bs2_1) & msk_1;
1759
- };
1760
- var syms = new i32(25e3);
1761
- var lf = new u16(288), df = new u16(32);
1762
- var lc_1 = 0, eb = 0, i2 = st.i || 0, li = 0, wi = st.w || 0, bs = 0;
1763
- for (; i2 + 2 < s; ++i2) {
1764
- var hv = hsh(i2);
1765
- var imod = i2 & 32767, pimod = head[hv];
1766
- prev[imod] = pimod;
1767
- head[hv] = imod;
1768
- if (wi <= i2) {
1769
- var rem = s - i2;
1770
- if ((lc_1 > 7e3 || li > 24576) && (rem > 423 || !lst)) {
1771
- pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i2 - bs, pos);
1772
- li = lc_1 = eb = 0, bs = i2;
1773
- for (var j = 0; j < 286; ++j)
1774
- lf[j] = 0;
1775
- for (var j = 0; j < 30; ++j)
1776
- df[j] = 0;
1777
- }
1778
- var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;
1779
- if (rem > 2 && hv == hsh(i2 - dif)) {
1780
- var maxn = Math.min(n, rem) - 1;
1781
- var maxd = Math.min(32767, i2);
1782
- var ml = Math.min(258, rem);
1783
- while (dif <= maxd && --ch_1 && imod != pimod) {
1784
- if (dat[i2 + l] == dat[i2 + l - dif]) {
1785
- var nl = 0;
1786
- for (; nl < ml && dat[i2 + nl] == dat[i2 + nl - dif]; ++nl)
1787
- ;
1788
- if (nl > l) {
1789
- l = nl, d = dif;
1790
- if (nl > maxn)
1791
- break;
1792
- var mmd = Math.min(dif, nl - 2);
1793
- var md = 0;
1794
- for (var j = 0; j < mmd; ++j) {
1795
- var ti = i2 - dif + j & 32767;
1796
- var pti = prev[ti];
1797
- var cd = ti - pti & 32767;
1798
- if (cd > md)
1799
- md = cd, pimod = ti;
1800
- }
1801
- }
1802
- }
1803
- imod = pimod, pimod = prev[imod];
1804
- dif += imod - pimod & 32767;
1805
- }
1806
- }
1807
- if (d) {
1808
- syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];
1809
- var lin = revfl[l] & 31, din = revfd[d] & 31;
1810
- eb += fleb[lin] + fdeb[din];
1811
- ++lf[257 + lin];
1812
- ++df[din];
1813
- wi = i2 + l;
1814
- ++lc_1;
1815
- } else {
1816
- syms[li++] = dat[i2];
1817
- ++lf[dat[i2]];
1818
- }
2374
+ async safeSet(key, value) {
2375
+ try {
2376
+ await this.storage.setItem(key, value);
2377
+ return true;
2378
+ } catch {
2379
+ return false;
2380
+ }
2381
+ }
2382
+ async safeRemove(key) {
2383
+ try {
2384
+ await this.storage.removeItem(key);
2385
+ } catch {
2386
+ }
2387
+ }
2388
+ async withLock(operation) {
2389
+ const result = this.mutationQueue.then(operation, operation);
2390
+ this.mutationQueue = result.then(
2391
+ () => {
2392
+ return void 0;
2393
+ },
2394
+ () => {
2395
+ return void 0;
1819
2396
  }
2397
+ );
2398
+ return await result;
2399
+ }
2400
+ };
2401
+
2402
+ // src/Storage.ts
2403
+ var import_async_storage = __toESM(require("@react-native-async-storage/async-storage"));
2404
+ var REPLAY_ID_PATTERN = /^[0-9a-f]{32}$/u;
2405
+ var defaultReplayStorage = import_async_storage.default;
2406
+ function generateReplayId() {
2407
+ const bytes = new Uint8Array(16);
2408
+ const cryptoRef = globalThis.crypto;
2409
+ if (cryptoRef && typeof cryptoRef.getRandomValues === "function") {
2410
+ cryptoRef.getRandomValues(bytes);
2411
+ } else {
2412
+ for (let index = 0; index < bytes.length; index += 1) {
2413
+ bytes[index] = Math.floor(Math.random() * 256);
1820
2414
  }
1821
- for (i2 = Math.max(i2, wi); i2 < s; ++i2) {
1822
- syms[li++] = dat[i2];
1823
- ++lf[dat[i2]];
2415
+ }
2416
+ return Array.from(bytes).map((byte) => {
2417
+ return byte.toString(16).padStart(2, "0");
2418
+ }).join("");
2419
+ }
2420
+ function isReplayId(value) {
2421
+ return typeof value === "string" && REPLAY_ID_PATTERN.test(value);
2422
+ }
2423
+ function parseStoredSession(value) {
2424
+ if (!value) {
2425
+ return null;
2426
+ }
2427
+ try {
2428
+ const parsed = JSON.parse(value);
2429
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
2430
+ return null;
2431
+ }
2432
+ const candidate = parsed;
2433
+ if (!isReplayId(candidate.sessionId) || !Number.isSafeInteger(candidate.sessionStartUnixMs) || !Number.isSafeInteger(candidate.lastActivityUnixMs) || !Number.isSafeInteger(candidate.nextChunkIndex) || (candidate.nextChunkIndex ?? -1) < 0) {
2434
+ return null;
2435
+ }
2436
+ return candidate;
2437
+ } catch {
2438
+ return null;
2439
+ }
2440
+ }
2441
+ var ReplaySessionStore = class {
2442
+ constructor(storage, namespace) {
2443
+ __publicField(this, "storage");
2444
+ __publicField(this, "sessionKey");
2445
+ __publicField(this, "visitorKey");
2446
+ __publicField(this, "identity", null);
2447
+ this.storage = storage;
2448
+ this.sessionKey = `@oneuptime/replay/${namespace}/session`;
2449
+ this.visitorKey = `@oneuptime/replay/${namespace}/visitor`;
2450
+ }
2451
+ async resolve(nowUnixMs) {
2452
+ const stored = parseStoredSession(
2453
+ await this.safeGet(this.sessionKey)
2454
+ );
2455
+ const shouldRotate = !stored || stored.nextChunkIndex >= MAX_SESSION_REPLAY_CHUNKS_PER_SESSION || nowUnixMs - stored.lastActivityUnixMs >= SESSION_REPLAY_IDLE_ROLLOVER_MS || nowUnixMs - stored.sessionStartUnixMs >= SESSION_REPLAY_MAX_SESSION_MS;
2456
+ let session;
2457
+ if (shouldRotate || !stored) {
2458
+ session = {
2459
+ sessionId: generateReplayId(),
2460
+ sessionStartUnixMs: nowUnixMs,
2461
+ lastActivityUnixMs: nowUnixMs,
2462
+ nextChunkIndex: 0
2463
+ };
2464
+ } else {
2465
+ session = {
2466
+ sessionId: stored.sessionId,
2467
+ sessionStartUnixMs: stored.sessionStartUnixMs,
2468
+ lastActivityUnixMs: nowUnixMs,
2469
+ nextChunkIndex: stored.nextChunkIndex
2470
+ };
1824
2471
  }
1825
- pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i2 - bs, pos);
1826
- if (!lst) {
1827
- st.r = pos & 7 | w[pos / 8 | 0] << 3;
1828
- pos -= 7;
1829
- st.h = head, st.p = prev, st.i = i2, st.w = wi;
2472
+ let visitorId = await this.safeGet(this.visitorKey);
2473
+ if (!isReplayId(visitorId)) {
2474
+ visitorId = generateReplayId();
2475
+ await this.safeSet(this.visitorKey, visitorId);
1830
2476
  }
1831
- } else {
1832
- for (var i2 = st.w || 0; i2 < s + lst; i2 += 65535) {
1833
- var e = i2 + 65535;
1834
- if (e >= s) {
1835
- w[pos / 8 | 0] = lst;
1836
- e = s;
1837
- }
1838
- pos = wfblk(w, pos + 1, dat.subarray(i2, e));
2477
+ await this.safeSet(this.sessionKey, JSON.stringify(session));
2478
+ this.identity = {
2479
+ sessionId: session.sessionId,
2480
+ tabId: generateReplayId(),
2481
+ visitorId,
2482
+ sessionStartUnixMs: session.sessionStartUnixMs,
2483
+ chunkIndex: session.nextChunkIndex
2484
+ };
2485
+ return { ...this.identity };
2486
+ }
2487
+ async takeChunkIndex(nowUnixMs) {
2488
+ if (!this.identity) {
2489
+ await this.resolve(nowUnixMs);
1839
2490
  }
1840
- st.i = s;
2491
+ const identity = this.identity;
2492
+ const index = identity.chunkIndex;
2493
+ identity.chunkIndex += 1;
2494
+ const state = {
2495
+ sessionId: identity.sessionId,
2496
+ sessionStartUnixMs: identity.sessionStartUnixMs,
2497
+ lastActivityUnixMs: nowUnixMs,
2498
+ nextChunkIndex: identity.chunkIndex
2499
+ };
2500
+ await this.safeSet(this.sessionKey, JSON.stringify(state));
2501
+ return index;
1841
2502
  }
1842
- return slc(o, 0, pre + shft(pos) + post);
1843
- };
1844
- var crct = /* @__PURE__ */ (function() {
1845
- var t = new Int32Array(256);
1846
- for (var i2 = 0; i2 < 256; ++i2) {
1847
- var c = i2, k = 9;
1848
- while (--k)
1849
- c = (c & 1 && -306674912) ^ c >>> 1;
1850
- t[i2] = c;
2503
+ getNextChunkIndex() {
2504
+ return this.identity?.chunkIndex ?? null;
1851
2505
  }
1852
- return t;
1853
- })();
1854
- var crc = function() {
1855
- var c = -1;
1856
- return {
1857
- p: function(d) {
1858
- var cr = c;
1859
- for (var i2 = 0; i2 < d.length; ++i2)
1860
- cr = crct[cr & 255 ^ d[i2]] ^ cr >>> 8;
1861
- c = cr;
1862
- },
1863
- d: function() {
1864
- return ~c;
1865
- }
1866
- };
1867
- };
1868
- var dopt = function(dat, opt, pre, post, st) {
1869
- if (!st) {
1870
- st = { l: 1 };
1871
- if (opt.dictionary) {
1872
- var dict = opt.dictionary.subarray(-32768);
1873
- var newDat = new u8(dict.length + dat.length);
1874
- newDat.set(dict);
1875
- newDat.set(dat, dict.length);
1876
- dat = newDat;
1877
- st.w = dict.length;
2506
+ async rotate(nowUnixMs) {
2507
+ let visitorId = await this.safeGet(this.visitorKey);
2508
+ if (!isReplayId(visitorId)) {
2509
+ visitorId = generateReplayId();
2510
+ await this.safeSet(this.visitorKey, visitorId);
1878
2511
  }
2512
+ const session = {
2513
+ sessionId: generateReplayId(),
2514
+ sessionStartUnixMs: nowUnixMs,
2515
+ lastActivityUnixMs: nowUnixMs,
2516
+ nextChunkIndex: 0
2517
+ };
2518
+ await this.safeSet(this.sessionKey, JSON.stringify(session));
2519
+ this.identity = {
2520
+ sessionId: session.sessionId,
2521
+ tabId: generateReplayId(),
2522
+ visitorId,
2523
+ sessionStartUnixMs: nowUnixMs,
2524
+ chunkIndex: 0
2525
+ };
2526
+ return { ...this.identity };
1879
2527
  }
1880
- return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20 : 12 + opt.mem, pre, post, st);
1881
- };
1882
- var wbytes = function(d, b, v) {
1883
- for (; v; ++b)
1884
- d[b] = v, v >>>= 8;
1885
- };
1886
- var gzh = function(c, o) {
1887
- var fn = o.filename;
1888
- c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3;
1889
- if (o.mtime != 0)
1890
- wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1e3));
1891
- if (fn) {
1892
- c[3] = 8;
1893
- for (var i2 = 0; i2 <= fn.length; ++i2)
1894
- c[i2 + 10] = fn.charCodeAt(i2);
2528
+ async clear() {
2529
+ this.identity = null;
2530
+ await Promise.all([
2531
+ this.safeRemove(this.sessionKey),
2532
+ this.safeRemove(this.visitorKey)
2533
+ ]);
1895
2534
  }
1896
- };
1897
- var gzhl = function(o) {
1898
- return 10 + (o.filename ? o.filename.length + 1 : 0);
1899
- };
1900
- function gzipSync(data, opts) {
1901
- if (!opts)
1902
- opts = {};
1903
- var c = crc(), l = data.length;
1904
- c.p(data);
1905
- var d = dopt(data, opts, gzhl(opts), 8), s = d.length;
1906
- return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d;
1907
- }
1908
- var te = typeof TextEncoder != "undefined" && /* @__PURE__ */ new TextEncoder();
1909
- var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
1910
- var tds = 0;
1911
- try {
1912
- td.decode(et, { stream: true });
1913
- tds = 1;
1914
- } catch (e) {
1915
- }
1916
- function strToU8(str, latin1) {
1917
- if (latin1) {
1918
- var ar_1 = new u8(str.length);
1919
- for (var i2 = 0; i2 < str.length; ++i2)
1920
- ar_1[i2] = str.charCodeAt(i2);
1921
- return ar_1;
2535
+ async safeGet(key) {
2536
+ try {
2537
+ return await this.storage.getItem(key);
2538
+ } catch {
2539
+ return null;
2540
+ }
1922
2541
  }
1923
- if (te)
1924
- return te.encode(str);
1925
- var l = str.length;
1926
- var ar = new u8(str.length + (str.length >> 1));
1927
- var ai = 0;
1928
- var w = function(v) {
1929
- ar[ai++] = v;
1930
- };
1931
- for (var i2 = 0; i2 < l; ++i2) {
1932
- if (ai + 5 > ar.length) {
1933
- var n = new u8(ai + 8 + (l - i2 << 1));
1934
- n.set(ar);
1935
- ar = n;
2542
+ async safeSet(key, value) {
2543
+ try {
2544
+ await this.storage.setItem(key, value);
2545
+ } catch {
1936
2546
  }
1937
- var c = str.charCodeAt(i2);
1938
- if (c < 128 || latin1)
1939
- w(c);
1940
- else if (c < 2048)
1941
- w(192 | c >> 6), w(128 | c & 63);
1942
- else if (c > 55295 && c < 57344)
1943
- c = 65536 + (c & 1023 << 10) | str.charCodeAt(++i2) & 1023, w(240 | c >> 18), w(128 | c >> 12 & 63), w(128 | c >> 6 & 63), w(128 | c & 63);
1944
- else
1945
- w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63);
1946
2547
  }
1947
- return slc(ar, 0, ai);
1948
- }
2548
+ async safeRemove(key) {
2549
+ try {
2550
+ await this.storage.removeItem(key);
2551
+ } catch {
2552
+ }
2553
+ }
2554
+ };
1949
2555
 
1950
2556
  // src/Transport.ts
1951
2557
  var MAX_ATTEMPTS_PER_FRAME = 3;
1952
2558
  var DEFAULT_RETRY_MS = 15e3;
1953
2559
  var MAX_RETRY_MS = 5 * 6e4;
1954
2560
  var CHUNK_POST_TIMEOUT_MS = 1e4;
2561
+ var OFFLINE_RETRY_MS = [5e3, 15e3, 3e4, 6e4];
1955
2562
  var DIRECTIVE_REASON_PATTERN = /^[A-Za-z0-9_.:-]{1,100}$/u;
1956
- function encodeReplayFrame(originalEnvelope, payload) {
1957
- const compressed = gzipSync(strToU8(payload));
2563
+ function encodeCompressedReplayFrame(originalEnvelope, compressed) {
1958
2564
  const envelope = {
1959
2565
  ...originalEnvelope,
1960
2566
  payloadEncoding: "gzip",
1961
2567
  payloadBytes: compressed.byteLength,
1962
2568
  clientSendUnixMs: Date.now()
1963
2569
  };
1964
- const prefix = strToU8(`${JSON.stringify(envelope)}
1965
- `);
2570
+ const prefix = strToU8(encodeSessionReplayEnvelopeLine(envelope));
1966
2571
  const body = new Uint8Array(
1967
2572
  prefix.byteLength + compressed.byteLength
1968
2573
  );
@@ -2027,9 +2632,47 @@ var ReplayTransport = class {
2027
2632
  __publicField(this, "retryAfterDrainMs", null);
2028
2633
  __publicField(this, "activeAbortController", null);
2029
2634
  __publicField(this, "abortCurrentRequest", null);
2635
+ /* Requests in a row that never reached the server. */
2636
+ __publicField(this, "connectivityFailures", 0);
2637
+ /* What the host app's connectivity source last said, if it has one. */
2638
+ __publicField(this, "reportedOffline", false);
2030
2639
  this.options = options;
2031
2640
  this.fetch = options.startOptions.fetch;
2032
2641
  }
2642
+ /*
2643
+ * Offline, as far as uploading goes: the host app's connectivity source
2644
+ * says so, or the last request never reached the server.
2645
+ */
2646
+ isOffline() {
2647
+ return this.reportedOffline || this.connectivityFailures > 0;
2648
+ }
2649
+ /*
2650
+ * The host app's connectivity source changed (NetInfo, typically). While
2651
+ * it says offline nothing is attempted. Coming back does NOT drain on its
2652
+ * own: whether this recorder may upload right now (consent) is the
2653
+ * recorder's decision, so it calls resume() itself. null means "unknown",
2654
+ * which blocks nothing.
2655
+ */
2656
+ setConnectivity(isConnected) {
2657
+ this.reportedOffline = isConnected === false;
2658
+ }
2659
+ /*
2660
+ * Drain now rather than on the retry timer: the app came to the
2661
+ * foreground, or the network came back. An offline wait ends; a server
2662
+ * throttle still stands.
2663
+ */
2664
+ resume() {
2665
+ if (this.stopped || this.reportedOffline) {
2666
+ return;
2667
+ }
2668
+ if (this.connectivityFailures > 0 && this.retryTimer) {
2669
+ clearTimeout(this.retryTimer);
2670
+ this.retryTimer = null;
2671
+ }
2672
+ if (!this.retryTimer) {
2673
+ void this.drain();
2674
+ }
2675
+ }
2033
2676
  async enqueue(envelope, payload) {
2034
2677
  if (this.stopped) {
2035
2678
  return;
@@ -2046,13 +2689,15 @@ var ReplayTransport = class {
2046
2689
  dropped: mutation.dropped
2047
2690
  });
2048
2691
  }
2049
- await this.drain();
2692
+ if (!this.retryTimer) {
2693
+ await this.drain();
2694
+ }
2050
2695
  }
2051
2696
  async restore() {
2052
2697
  await this.drain();
2053
2698
  }
2054
2699
  async drain() {
2055
- if (this.stopped) {
2700
+ if (this.stopped || this.reportedOffline) {
2056
2701
  return;
2057
2702
  }
2058
2703
  if (this.drainPromise) {
@@ -2081,11 +2726,19 @@ var ReplayTransport = class {
2081
2726
  return this.flushFailures;
2082
2727
  }
2083
2728
  async drainLoop() {
2084
- const frames = await this.options.outbox.list();
2085
- for (const frame of frames) {
2086
- if (this.stopped) {
2729
+ const entries = await this.options.outbox.entries();
2730
+ for (const entry of entries) {
2731
+ if (this.stopped || this.reportedOffline) {
2087
2732
  return;
2088
2733
  }
2734
+ const frame = await this.options.outbox.load(entry.id);
2735
+ if (frame === "unreadable") {
2736
+ this.options.onDiagnostic("outbox-frame-unreadable");
2737
+ continue;
2738
+ }
2739
+ if (!frame) {
2740
+ continue;
2741
+ }
2089
2742
  const outcome = await this.post(frame);
2090
2743
  if (outcome === "remove") {
2091
2744
  await this.options.outbox.remove(frame.id);
@@ -2098,10 +2751,13 @@ var ReplayTransport = class {
2098
2751
  if (outcome === "stop") {
2099
2752
  return;
2100
2753
  }
2754
+ this.flushFailures += 1;
2755
+ if (outcome === "wait") {
2756
+ return;
2757
+ }
2101
2758
  const attempts = await this.options.outbox.incrementAttempts(
2102
2759
  frame.id
2103
2760
  );
2104
- this.flushFailures += 1;
2105
2761
  if (attempts >= MAX_ATTEMPTS_PER_FRAME) {
2106
2762
  await this.options.outbox.remove(frame.id);
2107
2763
  this.options.onDiagnostic("chunk-retry-exhausted", {
@@ -2116,9 +2772,9 @@ var ReplayTransport = class {
2116
2772
  }
2117
2773
  }
2118
2774
  async post(frame) {
2119
- const encoded = encodeReplayFrame(
2775
+ const encoded = encodeCompressedReplayFrame(
2120
2776
  frame.envelope,
2121
- frame.payload
2777
+ frame.compressedPayload
2122
2778
  );
2123
2779
  if (encoded.body.byteLength > MAX_SESSION_REPLAY_CHUNK_BYTES) {
2124
2780
  this.options.onDiagnostic("chunk-too-large", {
@@ -2177,7 +2833,9 @@ var ReplayTransport = class {
2177
2833
  chunkIndex: frame.envelope.chunkIndex
2178
2834
  }
2179
2835
  );
2180
- return "retry";
2836
+ this.connectivityFailures += 1;
2837
+ this.retryAfterDrainMs = OFFLINE_RETRY_MS[Math.min(this.connectivityFailures, OFFLINE_RETRY_MS.length) - 1];
2838
+ return "wait";
2181
2839
  } finally {
2182
2840
  if (timeout) {
2183
2841
  clearTimeout(timeout);
@@ -2189,6 +2847,10 @@ var ReplayTransport = class {
2189
2847
  this.abortCurrentRequest = null;
2190
2848
  }
2191
2849
  }
2850
+ if (this.connectivityFailures > 0) {
2851
+ this.connectivityFailures = 0;
2852
+ this.options.onDiagnostic("back-online");
2853
+ }
2192
2854
  if (said.directive) {
2193
2855
  this.options.onDirective(said.directive, said.reason);
2194
2856
  }
@@ -2230,6 +2892,9 @@ var ReplayTransport = class {
2230
2892
  (said.retryAfterSeconds ?? DEFAULT_RETRY_MS / 1e3) * 1e3
2231
2893
  );
2232
2894
  this.retryAfterDrainMs = retryMs;
2895
+ if (response.status === 429 || said.directive === "throttle" || said.retryAfterSeconds !== null) {
2896
+ return "wait";
2897
+ }
2233
2898
  return "retry";
2234
2899
  }
2235
2900
  scheduleRetry(delayMs) {
@@ -2413,6 +3078,21 @@ var MobileReplayRecorder = class {
2413
3078
  __publicField(this, "captureTimer", null);
2414
3079
  __publicField(this, "flushTimer", null);
2415
3080
  __publicField(this, "appStateSubscription", null);
3081
+ /*
3082
+ * Offline mode: the host app's connectivity source (start option
3083
+ * `connectivity`), and what it last said, which a transport created later
3084
+ * - after a consent or identity change - starts from.
3085
+ */
3086
+ __publicField(this, "unsubscribeConnectivity", null);
3087
+ __publicField(this, "lastConnectivity", null);
3088
+ /*
3089
+ * The policy in force is the cached one an offline launch started with,
3090
+ * or the last refresh could not reach the server. Refreshed the moment the
3091
+ * connection is back rather than on the five-minute schedule, so a policy
3092
+ * changed while the device was offline takes effect before its backlog
3093
+ * has finished uploading.
3094
+ */
3095
+ __publicField(this, "policyStale", false);
2416
3096
  __publicField(this, "captureGeneration", null);
2417
3097
  __publicField(this, "running", false);
2418
3098
  __publicField(this, "foreground", true);
@@ -2549,11 +3229,32 @@ var MobileReplayRecorder = class {
2549
3229
  });
2550
3230
  return false;
2551
3231
  }
3232
+ const namespace = getReplayStorageNamespace(validated);
2552
3233
  let config = await fetchReplayConfig(this.options);
2553
3234
  if (!this.isCurrentGeneration(generation)) {
2554
3235
  return false;
2555
3236
  }
2556
- if (config.enabled && this.userRef && (config.consentMode === "NotRequired" /* NotRequired */ || this.consentGranted)) {
3237
+ let configFromCache = false;
3238
+ if (isRetryablePolicyFailure(config)) {
3239
+ const cached = await loadCachedReplayConfig(
3240
+ this.storage,
3241
+ namespace,
3242
+ this.now()
3243
+ );
3244
+ if (!this.isCurrentGeneration(generation)) {
3245
+ return false;
3246
+ }
3247
+ if (cached) {
3248
+ this.diagnostic("config-from-cache", {
3249
+ reason: config.disabledReason ?? "not-reported"
3250
+ });
3251
+ config = cached;
3252
+ configFromCache = true;
3253
+ }
3254
+ } else if (this.mayPersistUnder(config)) {
3255
+ await saveReplayConfig(this.storage, namespace, config, this.now());
3256
+ }
3257
+ if (!configFromCache && config.enabled && this.userRef && (config.consentMode === "NotRequired" /* NotRequired */ || this.consentGranted)) {
2557
3258
  config = await this.refreshTargetingConfig(config);
2558
3259
  if (!this.isCurrentGeneration(generation)) {
2559
3260
  return false;
@@ -2566,8 +3267,8 @@ var MobileReplayRecorder = class {
2566
3267
  });
2567
3268
  return false;
2568
3269
  }
2569
- this.lastPolicyRefreshAtUnixMs = this.now();
2570
- const namespace = getReplayStorageNamespace(validated);
3270
+ this.lastPolicyRefreshAtUnixMs = configFromCache ? 0 : this.now();
3271
+ this.policyStale = configFromCache;
2571
3272
  const sessionStore = new ReplaySessionStore(
2572
3273
  this.storage,
2573
3274
  namespace
@@ -2596,8 +3297,9 @@ var MobileReplayRecorder = class {
2596
3297
  this.disable("not-sampled");
2597
3298
  return false;
2598
3299
  }
2599
- this.outbox = new ReplayOutbox(this.storage, namespace);
3300
+ this.outbox = new ReplayOutbox(this.storage, namespace, this.now);
2600
3301
  this.transport = this.createTransport(validated, this.outbox);
3302
+ this.subscribeConnectivity(validated);
2601
3303
  try {
2602
3304
  const nativeMetadata = await this.nativeViewTree.getAppMetadata();
2603
3305
  if (!this.isCurrentGeneration(generation)) {
@@ -2747,6 +3449,7 @@ var MobileReplayRecorder = class {
2747
3449
  });
2748
3450
  await this.outbox?.clear();
2749
3451
  await this.sessionStore?.clear();
3452
+ await this.forgetCachedConfig();
2750
3453
  this.identity = null;
2751
3454
  this.userRef = null;
2752
3455
  this.traits = {};
@@ -3360,6 +4063,9 @@ var MobileReplayRecorder = class {
3360
4063
  this.startTimers();
3361
4064
  this.diagnosticsStatus = this.consentState() === "Unknown" ? "consent-required" : "recording";
3362
4065
  await this.captureTick(true);
4066
+ if (this.uploadActive && this.running) {
4067
+ this.transport?.resume();
4068
+ }
3363
4069
  }
3364
4070
  }
3365
4071
  startTimers() {
@@ -3421,7 +4127,7 @@ var MobileReplayRecorder = class {
3421
4127
  this.installedGlobalErrorHandler = null;
3422
4128
  }
3423
4129
  createTransport(startOptions, outbox) {
3424
- return new ReplayTransport({
4130
+ const transport = new ReplayTransport({
3425
4131
  startOptions,
3426
4132
  outbox,
3427
4133
  onDirective: (directive, reason) => {
@@ -3429,8 +4135,15 @@ var MobileReplayRecorder = class {
3429
4135
  },
3430
4136
  onDiagnostic: (code, details) => {
3431
4137
  this.diagnostic(code, details);
4138
+ if (code === "back-online") {
4139
+ this.onBackOnline();
4140
+ }
3432
4141
  }
3433
4142
  });
4143
+ if (this.lastConnectivity !== null) {
4144
+ transport.setConnectivity(this.lastConnectivity);
4145
+ }
4146
+ return transport;
3434
4147
  }
3435
4148
  onDirective(directive, reason) {
3436
4149
  this.diagnostic("server-directive", { directive, reason });
@@ -3469,8 +4182,76 @@ var MobileReplayRecorder = class {
3469
4182
  this.clearTimers();
3470
4183
  this.appStateSubscription?.remove();
3471
4184
  this.appStateSubscription = null;
4185
+ this.stopConnectivity();
3472
4186
  this.restoreGlobalErrorHandler();
3473
4187
  }
4188
+ /*
4189
+ * Whether this device may be written to under a policy. Nothing is stored
4190
+ * before an explicit consent the policy requires - the cached policy
4191
+ * included, even though it holds no user data - except a removal: a
4192
+ * policy that says replay is off always deletes the cached one.
4193
+ */
4194
+ /*
4195
+ * The cached policy goes with everything else when consent does: it holds
4196
+ * no user data, but "nothing of the recorder stays on the device" is the
4197
+ * promise, and the next consented policy fetch writes it again.
4198
+ */
4199
+ async forgetCachedConfig() {
4200
+ if (this.options) {
4201
+ await forgetReplayConfig(
4202
+ this.storage,
4203
+ getReplayStorageNamespace(this.options)
4204
+ );
4205
+ }
4206
+ }
4207
+ mayPersistUnder(config) {
4208
+ return !config.enabled || config.consentMode === "NotRequired" /* NotRequired */ || this.consentGranted;
4209
+ }
4210
+ subscribeConnectivity(options) {
4211
+ this.stopConnectivity();
4212
+ this.lastConnectivity = null;
4213
+ if (!options.connectivity) {
4214
+ return;
4215
+ }
4216
+ try {
4217
+ const unsubscribe = options.connectivity.subscribe(
4218
+ (isConnected) => {
4219
+ const connected = typeof isConnected === "boolean" ? isConnected : null;
4220
+ if (connected === this.lastConnectivity) {
4221
+ return;
4222
+ }
4223
+ this.lastConnectivity = connected;
4224
+ if (connected !== null) {
4225
+ this.diagnostic(connected ? "network-online" : "network-offline");
4226
+ }
4227
+ this.transport?.setConnectivity(connected);
4228
+ if (connected === true) {
4229
+ this.onBackOnline();
4230
+ if (this.uploadActive && this.running) {
4231
+ this.transport?.resume();
4232
+ }
4233
+ }
4234
+ }
4235
+ );
4236
+ this.unsubscribeConnectivity = typeof unsubscribe === "function" ? unsubscribe : null;
4237
+ } catch {
4238
+ this.diagnostic("connectivity-subscribe-failed");
4239
+ }
4240
+ }
4241
+ /* The next capture tick refreshes a stale policy (see policyStale). */
4242
+ onBackOnline() {
4243
+ if (this.policyStale) {
4244
+ this.lastPolicyRefreshAtUnixMs = 0;
4245
+ }
4246
+ }
4247
+ stopConnectivity() {
4248
+ const unsubscribe = this.unsubscribeConnectivity;
4249
+ this.unsubscribeConnectivity = null;
4250
+ try {
4251
+ unsubscribe?.();
4252
+ } catch {
4253
+ }
4254
+ }
3474
4255
  isCurrentGeneration(generation) {
3475
4256
  return generation === this.lifecycleGeneration;
3476
4257
  }
@@ -3701,11 +4482,23 @@ var MobileReplayRecorder = class {
3701
4482
  }
3702
4483
  }
3703
4484
  this.lastPolicyRefreshAtUnixMs = nowUnixMs;
4485
+ if (!isRetryablePolicyFailure(freshConfig) && this.mayPersistUnder(freshConfig)) {
4486
+ await saveReplayConfig(
4487
+ this.storage,
4488
+ getReplayStorageNamespace(currentOptions),
4489
+ freshConfig,
4490
+ nowUnixMs
4491
+ );
4492
+ if (!this.running || !this.isCurrentGeneration(generation)) {
4493
+ return false;
4494
+ }
4495
+ }
3704
4496
  if (!freshConfig.enabled) {
3705
4497
  if (reason !== "consent" && isRetryablePolicyFailure(freshConfig)) {
3706
4498
  this.diagnostic("policy-refresh-failed-using-last-config", {
3707
4499
  reason
3708
4500
  });
4501
+ this.policyStale = true;
3709
4502
  return true;
3710
4503
  }
3711
4504
  this.config = freshConfig;
@@ -3715,6 +4508,7 @@ var MobileReplayRecorder = class {
3715
4508
  );
3716
4509
  return false;
3717
4510
  }
4511
+ this.policyStale = false;
3718
4512
  return await this.applyRuntimePolicy(
3719
4513
  previousConfig,
3720
4514
  freshConfig,
@@ -3761,6 +4555,7 @@ var MobileReplayRecorder = class {
3761
4555
  });
3762
4556
  await this.outbox?.clear();
3763
4557
  await this.sessionStore?.clear();
4558
+ await this.forgetCachedConfig();
3764
4559
  if (!this.running || !this.isCurrentGeneration(generation)) {
3765
4560
  return false;
3766
4561
  }