@oneuptime/react-native-replay 14.0.0 → 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.js CHANGED
@@ -20,7 +20,23 @@ import { AppState } from "react-native";
20
20
  // src/Contract.ts
21
21
  var SESSION_REPLAY_WIRE_VERSION = 1;
22
22
  var SESSION_REPLAY_SCHEMA_VERSION = 1;
23
- var SESSION_REPLAY_CONTENT_TYPE = "application/vnd.oneuptime.session-replay.v1";
23
+ var SESSION_REPLAY_CONTENT_TYPE = "application/octet-stream";
24
+ var SESSION_REPLAY_ENVELOPE_TERMINATOR = " \n";
25
+ var ESCAPED_SEQUENCES = /[%&]|(http)\//gi;
26
+ function escapeSessionReplayJson(json) {
27
+ return json.replace(
28
+ ESCAPED_SEQUENCES,
29
+ (match, http) => {
30
+ if (http !== void 0) {
31
+ return `${http}\\/`;
32
+ }
33
+ return match === "%" ? "\\u0025" : "\\u0026";
34
+ }
35
+ );
36
+ }
37
+ function encodeSessionReplayEnvelopeLine(envelope) {
38
+ return escapeSessionReplayJson(JSON.stringify(envelope)) + SESSION_REPLAY_ENVELOPE_TERMINATOR;
39
+ }
24
40
  var SESSION_REPLAY_APP_IDENTIFIER_HEADER = "x-oneuptime-app-identifier";
25
41
  var SESSION_REPLAY_RECORDER_KIND_HEADER = "x-oneuptime-replay-recorder-kind";
26
42
  var SESSION_REPLAY_MOBILE_APP_IDENTIFIER_HEADER = "x-oneuptime-mobile-app-identifier";
@@ -39,10 +55,11 @@ var SESSION_REPLAY_MAX_SESSION_MS = 4 * 60 * 6e4;
39
55
  var SESSION_REPLAY_MAX_DECOMPRESSED_FRAME_BYTES = 8 * 1024 * 1024;
40
56
  var MAX_SESSION_REPLAY_CHUNK_BYTES = 2 * 1024 * 1024;
41
57
  var MAX_SESSION_REPLAY_CHUNKS_PER_SESSION = 480;
58
+ var SESSION_REPLAY_MAX_OFFLINE_DELAY_MS = 3 * 24 * 60 * 60 * 1e3;
42
59
  var MOBILE_CAPTURE_INTERVAL_MS = 500;
43
60
  var MOBILE_RECORDER_KIND = "rn-view-tree";
44
61
  var SYNTHETIC_RRWEB_VERSION = "synthetic-1";
45
- var RECORDER_VERSION = true ? "14.0.0" : "0.0.0-dev";
62
+ var RECORDER_VERSION = true ? "14.0.2" : "0.0.0-dev";
46
63
  var SESSION_REPLAY_MOBILE_RECORDER_CAPABILITIES = [
47
64
  "mobile-view-tree",
48
65
  "mobile-touch-events",
@@ -523,6 +540,57 @@ function normalizeReplayConfig(value) {
523
540
  }
524
541
  return resolved;
525
542
  }
543
+ function replayConfigCacheKey(namespace) {
544
+ return `@oneuptime/replay/${namespace}/config`;
545
+ }
546
+ async function saveReplayConfig(storage, namespace, config, nowUnixMs) {
547
+ try {
548
+ if (!config.enabled) {
549
+ await storage.removeItem(replayConfigCacheKey(namespace));
550
+ return;
551
+ }
552
+ const cached = {
553
+ savedAtUnixMs: nowUnixMs,
554
+ config: { ...config, isTargeted: false }
555
+ };
556
+ await storage.setItem(
557
+ replayConfigCacheKey(namespace),
558
+ JSON.stringify(cached)
559
+ );
560
+ } catch {
561
+ }
562
+ }
563
+ async function forgetReplayConfig(storage, namespace) {
564
+ try {
565
+ await storage.removeItem(replayConfigCacheKey(namespace));
566
+ } catch {
567
+ }
568
+ }
569
+ async function loadCachedReplayConfig(storage, namespace, nowUnixMs) {
570
+ try {
571
+ const raw = await storage.getItem(
572
+ replayConfigCacheKey(namespace)
573
+ );
574
+ if (!raw) {
575
+ return null;
576
+ }
577
+ const cached = JSON.parse(
578
+ raw
579
+ );
580
+ const age = nowUnixMs - Number(cached.savedAtUnixMs);
581
+ if (!Number.isFinite(age) || age < 0 || age > SESSION_REPLAY_MAX_OFFLINE_DELAY_MS || !cached.config || typeof cached.config !== "object") {
582
+ return null;
583
+ }
584
+ const config = normalizeReplayConfig({
585
+ ...cached.config,
586
+ directive: cached.config.enabled === true ? "continue" : "stop",
587
+ isTargeted: false
588
+ });
589
+ return config.enabled ? config : null;
590
+ } catch {
591
+ return null;
592
+ }
593
+ }
526
594
  async function fetchReplayConfig(options, includeUserRef = false, revalidate = false) {
527
595
  const controller = typeof AbortController === "undefined" ? null : new AbortController();
528
596
  let timeout = null;
@@ -1052,878 +1120,1415 @@ function getViewport() {
1052
1120
  return viewport();
1053
1121
  }
1054
1122
 
1055
- // src/Outbox.ts
1056
- var MAX_OUTBOX_ENTRIES = 64;
1057
- var MAX_OUTBOX_BYTES = 8 * 1024 * 1024;
1058
- function isFrame(value) {
1059
- if (!value || typeof value !== "object" || Array.isArray(value)) {
1060
- return false;
1123
+ // node_modules/fflate/esm/browser.js
1124
+ var u8 = Uint8Array;
1125
+ var u16 = Uint16Array;
1126
+ var i32 = Int32Array;
1127
+ var fleb = new u8([
1128
+ 0,
1129
+ 0,
1130
+ 0,
1131
+ 0,
1132
+ 0,
1133
+ 0,
1134
+ 0,
1135
+ 0,
1136
+ 1,
1137
+ 1,
1138
+ 1,
1139
+ 1,
1140
+ 2,
1141
+ 2,
1142
+ 2,
1143
+ 2,
1144
+ 3,
1145
+ 3,
1146
+ 3,
1147
+ 3,
1148
+ 4,
1149
+ 4,
1150
+ 4,
1151
+ 4,
1152
+ 5,
1153
+ 5,
1154
+ 5,
1155
+ 5,
1156
+ 0,
1157
+ /* unused */
1158
+ 0,
1159
+ 0,
1160
+ /* impossible */
1161
+ 0
1162
+ ]);
1163
+ var fdeb = new u8([
1164
+ 0,
1165
+ 0,
1166
+ 0,
1167
+ 0,
1168
+ 1,
1169
+ 1,
1170
+ 2,
1171
+ 2,
1172
+ 3,
1173
+ 3,
1174
+ 4,
1175
+ 4,
1176
+ 5,
1177
+ 5,
1178
+ 6,
1179
+ 6,
1180
+ 7,
1181
+ 7,
1182
+ 8,
1183
+ 8,
1184
+ 9,
1185
+ 9,
1186
+ 10,
1187
+ 10,
1188
+ 11,
1189
+ 11,
1190
+ 12,
1191
+ 12,
1192
+ 13,
1193
+ 13,
1194
+ /* unused */
1195
+ 0,
1196
+ 0
1197
+ ]);
1198
+ var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
1199
+ var freb = function(eb, start) {
1200
+ var b = new u16(31);
1201
+ for (var i2 = 0; i2 < 31; ++i2) {
1202
+ b[i2] = start += 1 << eb[i2 - 1];
1061
1203
  }
1062
- const frame = value;
1063
- 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";
1064
- }
1065
- function frameId(envelope) {
1066
- return `${envelope.sessionId}:${envelope.tabId}:${envelope.chunkIndex}`;
1204
+ var r = new i32(b[30]);
1205
+ for (var i2 = 1; i2 < 30; ++i2) {
1206
+ for (var j = b[i2]; j < b[i2 + 1]; ++j) {
1207
+ r[j] = j - b[i2] << 5 | i2;
1208
+ }
1209
+ }
1210
+ return { b, r };
1211
+ };
1212
+ var _a = freb(fleb, 2);
1213
+ var fl = _a.b;
1214
+ var revfl = _a.r;
1215
+ fl[28] = 258, revfl[258] = 28;
1216
+ var _b = freb(fdeb, 0);
1217
+ var fd = _b.b;
1218
+ var revfd = _b.r;
1219
+ var rev = new u16(32768);
1220
+ for (i = 0; i < 32768; ++i) {
1221
+ x = (i & 43690) >> 1 | (i & 21845) << 1;
1222
+ x = (x & 52428) >> 2 | (x & 13107) << 2;
1223
+ x = (x & 61680) >> 4 | (x & 3855) << 4;
1224
+ rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
1067
1225
  }
1068
- var ReplayOutbox = class {
1069
- constructor(storage, namespace) {
1070
- __publicField(this, "storage");
1071
- __publicField(this, "key");
1072
- __publicField(this, "mutationQueue", Promise.resolve());
1073
- this.storage = storage;
1074
- this.key = `@oneuptime/replay/${namespace}/outbox`;
1226
+ var x;
1227
+ var i;
1228
+ var hMap = (function(cd, mb, r) {
1229
+ var s = cd.length;
1230
+ var i2 = 0;
1231
+ var l = new u16(mb);
1232
+ for (; i2 < s; ++i2) {
1233
+ if (cd[i2])
1234
+ ++l[cd[i2] - 1];
1075
1235
  }
1076
- async list() {
1077
- return await this.withLock(
1078
- async () => {
1079
- return this.readUnlocked();
1080
- }
1081
- );
1236
+ var le = new u16(mb);
1237
+ for (i2 = 1; i2 < mb; ++i2) {
1238
+ le[i2] = le[i2 - 1] + l[i2 - 1] << 1;
1082
1239
  }
1083
- async readUnlocked() {
1084
- try {
1085
- const raw = await this.storage.getItem(this.key);
1086
- if (!raw) {
1087
- return [];
1240
+ var co;
1241
+ if (r) {
1242
+ co = new u16(1 << mb);
1243
+ var rvb = 15 - mb;
1244
+ for (i2 = 0; i2 < s; ++i2) {
1245
+ if (cd[i2]) {
1246
+ var sv = i2 << 4 | cd[i2];
1247
+ var r_1 = mb - cd[i2];
1248
+ var v = le[cd[i2] - 1]++ << r_1;
1249
+ for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
1250
+ co[rev[v] >> rvb] = sv;
1251
+ }
1088
1252
  }
1089
- const parsed = JSON.parse(raw);
1090
- if (!Array.isArray(parsed) || !parsed.every(isFrame)) {
1091
- await this.removeUnlocked();
1092
- return [];
1253
+ }
1254
+ } else {
1255
+ co = new u16(s);
1256
+ for (i2 = 0; i2 < s; ++i2) {
1257
+ if (cd[i2]) {
1258
+ co[i2] = rev[le[cd[i2] - 1]++] >> 15 - cd[i2];
1093
1259
  }
1094
- return parsed.slice().sort(
1095
- (left, right) => {
1096
- return left.createdAtUnixMs - right.createdAtUnixMs;
1097
- }
1098
- );
1099
- } catch {
1100
- await this.removeUnlocked();
1101
- return [];
1102
1260
  }
1103
1261
  }
1104
- async enqueue(frame) {
1105
- return await this.withLock(async () => {
1106
- const frames = await this.readUnlocked();
1107
- if (frames.some((candidate) => {
1108
- return candidate.id === frame.id;
1109
- })) {
1110
- return { dropped: 0 };
1262
+ return co;
1263
+ });
1264
+ var flt = new u8(288);
1265
+ for (i = 0; i < 144; ++i)
1266
+ flt[i] = 8;
1267
+ var i;
1268
+ for (i = 144; i < 256; ++i)
1269
+ flt[i] = 9;
1270
+ var i;
1271
+ for (i = 256; i < 280; ++i)
1272
+ flt[i] = 7;
1273
+ var i;
1274
+ for (i = 280; i < 288; ++i)
1275
+ flt[i] = 8;
1276
+ var i;
1277
+ var fdt = new u8(32);
1278
+ for (i = 0; i < 32; ++i)
1279
+ fdt[i] = 5;
1280
+ var i;
1281
+ var flm = /* @__PURE__ */ hMap(flt, 9, 0);
1282
+ var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
1283
+ var fdm = /* @__PURE__ */ hMap(fdt, 5, 0);
1284
+ var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
1285
+ var max = function(a) {
1286
+ var m = a[0];
1287
+ for (var i2 = 1; i2 < a.length; ++i2) {
1288
+ if (a[i2] > m)
1289
+ m = a[i2];
1290
+ }
1291
+ return m;
1292
+ };
1293
+ var bits = function(d, p, m) {
1294
+ var o = p / 8 | 0;
1295
+ return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
1296
+ };
1297
+ var bits16 = function(d, p) {
1298
+ var o = p / 8 | 0;
1299
+ return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
1300
+ };
1301
+ var shft = function(p) {
1302
+ return (p + 7) / 8 | 0;
1303
+ };
1304
+ var slc = function(v, s, e) {
1305
+ if (s == null || s < 0)
1306
+ s = 0;
1307
+ if (e == null || e > v.length)
1308
+ e = v.length;
1309
+ return new u8(v.subarray(s, e));
1310
+ };
1311
+ var ec = [
1312
+ "unexpected EOF",
1313
+ "invalid block type",
1314
+ "invalid length/literal",
1315
+ "invalid distance",
1316
+ "stream finished",
1317
+ "no stream handler",
1318
+ ,
1319
+ // determined by compression function
1320
+ "no callback",
1321
+ "invalid UTF-8 data",
1322
+ "extra field too long",
1323
+ "date not in range 1980-2099",
1324
+ "filename too long",
1325
+ "stream finishing",
1326
+ "invalid zip data"
1327
+ // determined by unknown compression method
1328
+ ];
1329
+ var err = function(ind, msg, nt) {
1330
+ var e = new Error(msg || ec[ind]);
1331
+ e.code = ind;
1332
+ if (Error.captureStackTrace)
1333
+ Error.captureStackTrace(e, err);
1334
+ if (!nt)
1335
+ throw e;
1336
+ return e;
1337
+ };
1338
+ var inflt = function(dat, st, buf, dict) {
1339
+ var sl = dat.length, dl = dict ? dict.length : 0;
1340
+ if (!sl || st.f && !st.l)
1341
+ return buf || new u8(0);
1342
+ var noBuf = !buf;
1343
+ var resize = noBuf || st.i != 2;
1344
+ var noSt = st.i;
1345
+ if (noBuf)
1346
+ buf = new u8(sl * 3);
1347
+ var cbuf = function(l2) {
1348
+ var bl = buf.length;
1349
+ if (l2 > bl) {
1350
+ var nbuf = new u8(Math.max(bl * 2, l2));
1351
+ nbuf.set(buf);
1352
+ buf = nbuf;
1353
+ }
1354
+ };
1355
+ 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;
1356
+ var tbts = sl * 8;
1357
+ do {
1358
+ if (!lm) {
1359
+ final = bits(dat, pos, 1);
1360
+ var type = bits(dat, pos + 1, 3);
1361
+ pos += 3;
1362
+ if (!type) {
1363
+ var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
1364
+ if (t > sl) {
1365
+ if (noSt)
1366
+ err(0);
1367
+ break;
1368
+ }
1369
+ if (resize)
1370
+ cbuf(bt + l);
1371
+ buf.set(dat.subarray(s, t), bt);
1372
+ st.b = bt += l, st.p = pos = t * 8, st.f = final;
1373
+ continue;
1374
+ } else if (type == 1)
1375
+ lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
1376
+ else if (type == 2) {
1377
+ var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
1378
+ var tl = hLit + bits(dat, pos + 5, 31) + 1;
1379
+ pos += 14;
1380
+ var ldt = new u8(tl);
1381
+ var clt = new u8(19);
1382
+ for (var i2 = 0; i2 < hcLen; ++i2) {
1383
+ clt[clim[i2]] = bits(dat, pos + i2 * 3, 7);
1384
+ }
1385
+ pos += hcLen * 3;
1386
+ var clb = max(clt), clbmsk = (1 << clb) - 1;
1387
+ var clm = hMap(clt, clb, 1);
1388
+ for (var i2 = 0; i2 < tl; ) {
1389
+ var r = clm[bits(dat, pos, clbmsk)];
1390
+ pos += r & 15;
1391
+ var s = r >> 4;
1392
+ if (s < 16) {
1393
+ ldt[i2++] = s;
1394
+ } else {
1395
+ var c = 0, n = 0;
1396
+ if (s == 16)
1397
+ n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i2 - 1];
1398
+ else if (s == 17)
1399
+ n = 3 + bits(dat, pos, 7), pos += 3;
1400
+ else if (s == 18)
1401
+ n = 11 + bits(dat, pos, 127), pos += 7;
1402
+ while (n--)
1403
+ ldt[i2++] = c;
1404
+ }
1405
+ }
1406
+ var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
1407
+ lbt = max(lt);
1408
+ dbt = max(dt);
1409
+ lm = hMap(lt, lbt, 1);
1410
+ dm = hMap(dt, dbt, 1);
1411
+ } else
1412
+ err(1);
1413
+ if (pos > tbts) {
1414
+ if (noSt)
1415
+ err(0);
1416
+ break;
1111
1417
  }
1112
- frames.push(frame);
1113
- let dropped = 0;
1114
- while (frames.length > MAX_OUTBOX_ENTRIES || byteLength(JSON.stringify(frames)) > MAX_OUTBOX_BYTES) {
1115
- frames.shift();
1116
- dropped += 1;
1418
+ }
1419
+ if (resize)
1420
+ cbuf(bt + 131072);
1421
+ var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
1422
+ var lpos = pos;
1423
+ for (; ; lpos = pos) {
1424
+ var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
1425
+ pos += c & 15;
1426
+ if (pos > tbts) {
1427
+ if (noSt)
1428
+ err(0);
1429
+ break;
1117
1430
  }
1118
- await this.writeUnlocked(frames);
1119
- return { dropped };
1120
- });
1121
- }
1122
- async remove(id) {
1123
- await this.withLock(async () => {
1124
- const frames = (await this.readUnlocked()).filter((frame) => {
1125
- return frame.id !== id;
1126
- });
1127
- await this.writeUnlocked(frames);
1128
- });
1129
- }
1130
- async incrementAttempts(id) {
1131
- return await this.withLock(async () => {
1132
- const frames = await this.readUnlocked();
1133
- let attempts = 0;
1134
- for (const frame of frames) {
1135
- if (frame.id === id) {
1136
- frame.attempts += 1;
1137
- attempts = frame.attempts;
1431
+ if (!c)
1432
+ err(2);
1433
+ if (sym < 256)
1434
+ buf[bt++] = sym;
1435
+ else if (sym == 256) {
1436
+ lpos = pos, lm = null;
1437
+ break;
1438
+ } else {
1439
+ var add = sym - 254;
1440
+ if (sym > 264) {
1441
+ var i2 = sym - 257, b = fleb[i2];
1442
+ add = bits(dat, pos, (1 << b) - 1) + fl[i2];
1443
+ pos += b;
1444
+ }
1445
+ var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
1446
+ if (!d)
1447
+ err(3);
1448
+ pos += d & 15;
1449
+ var dt = fd[dsym];
1450
+ if (dsym > 3) {
1451
+ var b = fdeb[dsym];
1452
+ dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
1453
+ }
1454
+ if (pos > tbts) {
1455
+ if (noSt)
1456
+ err(0);
1138
1457
  break;
1139
1458
  }
1459
+ if (resize)
1460
+ cbuf(bt + 131072);
1461
+ var end = bt + add;
1462
+ if (bt < dt) {
1463
+ var shift = dl - dt, dend = Math.min(dt, end);
1464
+ if (shift + bt < 0)
1465
+ err(3);
1466
+ for (; bt < dend; ++bt)
1467
+ buf[bt] = dict[shift + bt];
1468
+ }
1469
+ for (; bt < end; ++bt)
1470
+ buf[bt] = buf[bt - dt];
1140
1471
  }
1141
- await this.writeUnlocked(frames);
1142
- return attempts;
1143
- });
1472
+ }
1473
+ st.l = lm, st.p = lpos, st.b = bt, st.f = final;
1474
+ if (lm)
1475
+ final = 1, st.m = lbt, st.d = dm, st.n = dbt;
1476
+ } while (!final);
1477
+ return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
1478
+ };
1479
+ var wbits = function(d, p, v) {
1480
+ v <<= p & 7;
1481
+ var o = p / 8 | 0;
1482
+ d[o] |= v;
1483
+ d[o + 1] |= v >> 8;
1484
+ };
1485
+ var wbits16 = function(d, p, v) {
1486
+ v <<= p & 7;
1487
+ var o = p / 8 | 0;
1488
+ d[o] |= v;
1489
+ d[o + 1] |= v >> 8;
1490
+ d[o + 2] |= v >> 16;
1491
+ };
1492
+ var hTree = function(d, mb) {
1493
+ var t = [];
1494
+ for (var i2 = 0; i2 < d.length; ++i2) {
1495
+ if (d[i2])
1496
+ t.push({ s: i2, f: d[i2] });
1144
1497
  }
1145
- async clear() {
1146
- await this.withLock(async () => {
1147
- return this.removeUnlocked();
1148
- });
1498
+ var s = t.length;
1499
+ var t2 = t.slice();
1500
+ if (!s)
1501
+ return { t: et, l: 0 };
1502
+ if (s == 1) {
1503
+ var v = new u8(t[0].s + 1);
1504
+ v[t[0].s] = 1;
1505
+ return { t: v, l: 1 };
1149
1506
  }
1150
- async removeUnlocked() {
1151
- try {
1152
- await this.storage.removeItem(this.key);
1153
- } catch {
1154
- }
1507
+ t.sort(function(a, b) {
1508
+ return a.f - b.f;
1509
+ });
1510
+ t.push({ s: -1, f: 25001 });
1511
+ var l = t[0], r = t[1], i0 = 0, i1 = 1, i22 = 2;
1512
+ t[0] = { s: -1, f: l.f + r.f, l, r };
1513
+ while (i1 != s - 1) {
1514
+ l = t[t[i0].f < t[i22].f ? i0++ : i22++];
1515
+ r = t[i0 != i1 && t[i0].f < t[i22].f ? i0++ : i22++];
1516
+ t[i1++] = { s: -1, f: l.f + r.f, l, r };
1155
1517
  }
1156
- async writeUnlocked(frames) {
1157
- try {
1158
- if (frames.length === 0) {
1159
- await this.storage.removeItem(this.key);
1160
- return;
1518
+ var maxSym = t2[0].s;
1519
+ for (var i2 = 1; i2 < s; ++i2) {
1520
+ if (t2[i2].s > maxSym)
1521
+ maxSym = t2[i2].s;
1522
+ }
1523
+ var tr = new u16(maxSym + 1);
1524
+ var mbt = ln(t[i1 - 1], tr, 0);
1525
+ if (mbt > mb) {
1526
+ var i2 = 0, dt = 0;
1527
+ var lft = mbt - mb, cst = 1 << lft;
1528
+ t2.sort(function(a, b) {
1529
+ return tr[b.s] - tr[a.s] || a.f - b.f;
1530
+ });
1531
+ for (; i2 < s; ++i2) {
1532
+ var i2_1 = t2[i2].s;
1533
+ if (tr[i2_1] > mb) {
1534
+ dt += cst - (1 << mbt - tr[i2_1]);
1535
+ tr[i2_1] = mb;
1536
+ } else
1537
+ break;
1538
+ }
1539
+ dt >>= lft;
1540
+ while (dt > 0) {
1541
+ var i2_2 = t2[i2].s;
1542
+ if (tr[i2_2] < mb)
1543
+ dt -= 1 << mb - tr[i2_2]++ - 1;
1544
+ else
1545
+ ++i2;
1546
+ }
1547
+ for (; i2 >= 0 && dt; --i2) {
1548
+ var i2_3 = t2[i2].s;
1549
+ if (tr[i2_3] == mb) {
1550
+ --tr[i2_3];
1551
+ ++dt;
1161
1552
  }
1162
- await this.storage.setItem(this.key, JSON.stringify(frames));
1163
- } catch {
1164
1553
  }
1554
+ mbt = mb;
1165
1555
  }
1166
- async withLock(operation) {
1167
- const result = this.mutationQueue.then(operation, operation);
1168
- this.mutationQueue = result.then(
1169
- () => {
1170
- return void 0;
1171
- },
1172
- () => {
1173
- return void 0;
1556
+ return { t: new u8(tr), l: mbt };
1557
+ };
1558
+ var ln = function(n, l, d) {
1559
+ return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;
1560
+ };
1561
+ var lc = function(c) {
1562
+ var s = c.length;
1563
+ while (s && !c[--s])
1564
+ ;
1565
+ var cl = new u16(++s);
1566
+ var cli = 0, cln = c[0], cls = 1;
1567
+ var w = function(v) {
1568
+ cl[cli++] = v;
1569
+ };
1570
+ for (var i2 = 1; i2 <= s; ++i2) {
1571
+ if (c[i2] == cln && i2 != s)
1572
+ ++cls;
1573
+ else {
1574
+ if (!cln && cls > 2) {
1575
+ for (; cls > 138; cls -= 138)
1576
+ w(32754);
1577
+ if (cls > 2) {
1578
+ w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);
1579
+ cls = 0;
1580
+ }
1581
+ } else if (cls > 3) {
1582
+ w(cln), --cls;
1583
+ for (; cls > 6; cls -= 6)
1584
+ w(8304);
1585
+ if (cls > 2)
1586
+ w(cls - 3 << 5 | 8208), cls = 0;
1174
1587
  }
1175
- );
1176
- return await result;
1588
+ while (cls--)
1589
+ w(cln);
1590
+ cls = 1;
1591
+ cln = c[i2];
1592
+ }
1177
1593
  }
1594
+ return { c: cl.subarray(0, cli), n: s };
1178
1595
  };
1179
-
1180
- // src/Storage.ts
1181
- import AsyncStorage from "@react-native-async-storage/async-storage";
1182
- var REPLAY_ID_PATTERN = /^[0-9a-f]{32}$/u;
1183
- var defaultReplayStorage = AsyncStorage;
1184
- function generateReplayId() {
1185
- const bytes = new Uint8Array(16);
1186
- const cryptoRef = globalThis.crypto;
1187
- if (cryptoRef && typeof cryptoRef.getRandomValues === "function") {
1188
- cryptoRef.getRandomValues(bytes);
1189
- } else {
1190
- for (let index = 0; index < bytes.length; index += 1) {
1191
- bytes[index] = Math.floor(Math.random() * 256);
1596
+ var clen = function(cf, cl) {
1597
+ var l = 0;
1598
+ for (var i2 = 0; i2 < cl.length; ++i2)
1599
+ l += cf[i2] * cl[i2];
1600
+ return l;
1601
+ };
1602
+ var wfblk = function(out, pos, dat) {
1603
+ var s = dat.length;
1604
+ var o = shft(pos + 2);
1605
+ out[o] = s & 255;
1606
+ out[o + 1] = s >> 8;
1607
+ out[o + 2] = out[o] ^ 255;
1608
+ out[o + 3] = out[o + 1] ^ 255;
1609
+ for (var i2 = 0; i2 < s; ++i2)
1610
+ out[o + i2 + 4] = dat[i2];
1611
+ return (o + 4 + s) * 8;
1612
+ };
1613
+ var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) {
1614
+ wbits(out, p++, final);
1615
+ ++lf[256];
1616
+ var _a2 = hTree(lf, 15), dlt = _a2.t, mlb = _a2.l;
1617
+ var _b2 = hTree(df, 15), ddt = _b2.t, mdb = _b2.l;
1618
+ var _c = lc(dlt), lclt = _c.c, nlc = _c.n;
1619
+ var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;
1620
+ var lcfreq = new u16(19);
1621
+ for (var i2 = 0; i2 < lclt.length; ++i2)
1622
+ ++lcfreq[lclt[i2] & 31];
1623
+ for (var i2 = 0; i2 < lcdt.length; ++i2)
1624
+ ++lcfreq[lcdt[i2] & 31];
1625
+ var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;
1626
+ var nlcc = 19;
1627
+ for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)
1628
+ ;
1629
+ var flen = bl + 5 << 3;
1630
+ var ftlen = clen(lf, flt) + clen(df, fdt) + eb;
1631
+ var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];
1632
+ if (bs >= 0 && flen <= ftlen && flen <= dtlen)
1633
+ return wfblk(out, p, dat.subarray(bs, bs + bl));
1634
+ var lm, ll, dm, dl;
1635
+ wbits(out, p, 1 + (dtlen < ftlen)), p += 2;
1636
+ if (dtlen < ftlen) {
1637
+ lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;
1638
+ var llm = hMap(lct, mlcb, 0);
1639
+ wbits(out, p, nlc - 257);
1640
+ wbits(out, p + 5, ndc - 1);
1641
+ wbits(out, p + 10, nlcc - 4);
1642
+ p += 14;
1643
+ for (var i2 = 0; i2 < nlcc; ++i2)
1644
+ wbits(out, p + 3 * i2, lct[clim[i2]]);
1645
+ p += 3 * nlcc;
1646
+ var lcts = [lclt, lcdt];
1647
+ for (var it = 0; it < 2; ++it) {
1648
+ var clct = lcts[it];
1649
+ for (var i2 = 0; i2 < clct.length; ++i2) {
1650
+ var len = clct[i2] & 31;
1651
+ wbits(out, p, llm[len]), p += lct[len];
1652
+ if (len > 15)
1653
+ wbits(out, p, clct[i2] >> 5 & 127), p += clct[i2] >> 12;
1654
+ }
1192
1655
  }
1656
+ } else {
1657
+ lm = flm, ll = flt, dm = fdm, dl = fdt;
1193
1658
  }
1194
- return Array.from(bytes).map((byte) => {
1195
- return byte.toString(16).padStart(2, "0");
1196
- }).join("");
1197
- }
1198
- function isReplayId(value) {
1199
- return typeof value === "string" && REPLAY_ID_PATTERN.test(value);
1200
- }
1201
- function parseStoredSession(value) {
1202
- if (!value) {
1203
- return null;
1204
- }
1205
- try {
1206
- const parsed = JSON.parse(value);
1207
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1208
- return null;
1209
- }
1210
- const candidate = parsed;
1211
- if (!isReplayId(candidate.sessionId) || !Number.isSafeInteger(candidate.sessionStartUnixMs) || !Number.isSafeInteger(candidate.lastActivityUnixMs) || !Number.isSafeInteger(candidate.nextChunkIndex) || (candidate.nextChunkIndex ?? -1) < 0) {
1212
- return null;
1659
+ for (var i2 = 0; i2 < li; ++i2) {
1660
+ var sym = syms[i2];
1661
+ if (sym > 255) {
1662
+ var len = sym >> 18 & 31;
1663
+ wbits16(out, p, lm[len + 257]), p += ll[len + 257];
1664
+ if (len > 7)
1665
+ wbits(out, p, sym >> 23 & 31), p += fleb[len];
1666
+ var dst = sym & 31;
1667
+ wbits16(out, p, dm[dst]), p += dl[dst];
1668
+ if (dst > 3)
1669
+ wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst];
1670
+ } else {
1671
+ wbits16(out, p, lm[sym]), p += ll[sym];
1213
1672
  }
1214
- return candidate;
1215
- } catch {
1216
- return null;
1217
1673
  }
1218
- }
1219
- var ReplaySessionStore = class {
1220
- constructor(storage, namespace) {
1221
- __publicField(this, "storage");
1222
- __publicField(this, "sessionKey");
1223
- __publicField(this, "visitorKey");
1224
- __publicField(this, "identity", null);
1225
- this.storage = storage;
1226
- this.sessionKey = `@oneuptime/replay/${namespace}/session`;
1227
- this.visitorKey = `@oneuptime/replay/${namespace}/visitor`;
1228
- }
1229
- async resolve(nowUnixMs) {
1230
- const stored = parseStoredSession(
1231
- await this.safeGet(this.sessionKey)
1232
- );
1233
- 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;
1234
- let session;
1235
- if (shouldRotate || !stored) {
1236
- session = {
1237
- sessionId: generateReplayId(),
1238
- sessionStartUnixMs: nowUnixMs,
1239
- lastActivityUnixMs: nowUnixMs,
1240
- nextChunkIndex: 0
1241
- };
1242
- } else {
1243
- session = {
1244
- sessionId: stored.sessionId,
1245
- sessionStartUnixMs: stored.sessionStartUnixMs,
1246
- lastActivityUnixMs: nowUnixMs,
1247
- nextChunkIndex: stored.nextChunkIndex
1248
- };
1674
+ wbits16(out, p, lm[256]);
1675
+ return p + ll[256];
1676
+ };
1677
+ var deo = /* @__PURE__ */ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
1678
+ var et = /* @__PURE__ */ new u8(0);
1679
+ var dflt = function(dat, lvl, plvl, pre, post, st) {
1680
+ var s = st.z || dat.length;
1681
+ var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);
1682
+ var w = o.subarray(pre, o.length - post);
1683
+ var lst = st.l;
1684
+ var pos = (st.r || 0) & 7;
1685
+ if (lvl) {
1686
+ if (pos)
1687
+ w[0] = st.r >> 3;
1688
+ var opt = deo[lvl - 1];
1689
+ var n = opt >> 13, c = opt & 8191;
1690
+ var msk_1 = (1 << plvl) - 1;
1691
+ var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);
1692
+ var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;
1693
+ var hsh = function(i3) {
1694
+ return (dat[i3] ^ dat[i3 + 1] << bs1_1 ^ dat[i3 + 2] << bs2_1) & msk_1;
1695
+ };
1696
+ var syms = new i32(25e3);
1697
+ var lf = new u16(288), df = new u16(32);
1698
+ var lc_1 = 0, eb = 0, i2 = st.i || 0, li = 0, wi = st.w || 0, bs = 0;
1699
+ for (; i2 + 2 < s; ++i2) {
1700
+ var hv = hsh(i2);
1701
+ var imod = i2 & 32767, pimod = head[hv];
1702
+ prev[imod] = pimod;
1703
+ head[hv] = imod;
1704
+ if (wi <= i2) {
1705
+ var rem = s - i2;
1706
+ if ((lc_1 > 7e3 || li > 24576) && (rem > 423 || !lst)) {
1707
+ pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i2 - bs, pos);
1708
+ li = lc_1 = eb = 0, bs = i2;
1709
+ for (var j = 0; j < 286; ++j)
1710
+ lf[j] = 0;
1711
+ for (var j = 0; j < 30; ++j)
1712
+ df[j] = 0;
1713
+ }
1714
+ var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;
1715
+ if (rem > 2 && hv == hsh(i2 - dif)) {
1716
+ var maxn = Math.min(n, rem) - 1;
1717
+ var maxd = Math.min(32767, i2);
1718
+ var ml = Math.min(258, rem);
1719
+ while (dif <= maxd && --ch_1 && imod != pimod) {
1720
+ if (dat[i2 + l] == dat[i2 + l - dif]) {
1721
+ var nl = 0;
1722
+ for (; nl < ml && dat[i2 + nl] == dat[i2 + nl - dif]; ++nl)
1723
+ ;
1724
+ if (nl > l) {
1725
+ l = nl, d = dif;
1726
+ if (nl > maxn)
1727
+ break;
1728
+ var mmd = Math.min(dif, nl - 2);
1729
+ var md = 0;
1730
+ for (var j = 0; j < mmd; ++j) {
1731
+ var ti = i2 - dif + j & 32767;
1732
+ var pti = prev[ti];
1733
+ var cd = ti - pti & 32767;
1734
+ if (cd > md)
1735
+ md = cd, pimod = ti;
1736
+ }
1737
+ }
1738
+ }
1739
+ imod = pimod, pimod = prev[imod];
1740
+ dif += imod - pimod & 32767;
1741
+ }
1742
+ }
1743
+ if (d) {
1744
+ syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];
1745
+ var lin = revfl[l] & 31, din = revfd[d] & 31;
1746
+ eb += fleb[lin] + fdeb[din];
1747
+ ++lf[257 + lin];
1748
+ ++df[din];
1749
+ wi = i2 + l;
1750
+ ++lc_1;
1751
+ } else {
1752
+ syms[li++] = dat[i2];
1753
+ ++lf[dat[i2]];
1754
+ }
1755
+ }
1249
1756
  }
1250
- let visitorId = await this.safeGet(this.visitorKey);
1251
- if (!isReplayId(visitorId)) {
1252
- visitorId = generateReplayId();
1253
- await this.safeSet(this.visitorKey, visitorId);
1757
+ for (i2 = Math.max(i2, wi); i2 < s; ++i2) {
1758
+ syms[li++] = dat[i2];
1759
+ ++lf[dat[i2]];
1254
1760
  }
1255
- await this.safeSet(this.sessionKey, JSON.stringify(session));
1256
- this.identity = {
1257
- sessionId: session.sessionId,
1258
- tabId: generateReplayId(),
1259
- visitorId,
1260
- sessionStartUnixMs: session.sessionStartUnixMs,
1261
- chunkIndex: session.nextChunkIndex
1262
- };
1263
- return { ...this.identity };
1264
- }
1265
- async takeChunkIndex(nowUnixMs) {
1266
- if (!this.identity) {
1267
- await this.resolve(nowUnixMs);
1761
+ pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i2 - bs, pos);
1762
+ if (!lst) {
1763
+ st.r = pos & 7 | w[pos / 8 | 0] << 3;
1764
+ pos -= 7;
1765
+ st.h = head, st.p = prev, st.i = i2, st.w = wi;
1268
1766
  }
1269
- const identity = this.identity;
1270
- const index = identity.chunkIndex;
1271
- identity.chunkIndex += 1;
1272
- const state = {
1273
- sessionId: identity.sessionId,
1274
- sessionStartUnixMs: identity.sessionStartUnixMs,
1275
- lastActivityUnixMs: nowUnixMs,
1276
- nextChunkIndex: identity.chunkIndex
1277
- };
1278
- await this.safeSet(this.sessionKey, JSON.stringify(state));
1279
- return index;
1280
- }
1281
- getNextChunkIndex() {
1282
- return this.identity?.chunkIndex ?? null;
1283
- }
1284
- async rotate(nowUnixMs) {
1285
- let visitorId = await this.safeGet(this.visitorKey);
1286
- if (!isReplayId(visitorId)) {
1287
- visitorId = generateReplayId();
1288
- await this.safeSet(this.visitorKey, visitorId);
1767
+ } else {
1768
+ for (var i2 = st.w || 0; i2 < s + lst; i2 += 65535) {
1769
+ var e = i2 + 65535;
1770
+ if (e >= s) {
1771
+ w[pos / 8 | 0] = lst;
1772
+ e = s;
1773
+ }
1774
+ pos = wfblk(w, pos + 1, dat.subarray(i2, e));
1289
1775
  }
1290
- const session = {
1291
- sessionId: generateReplayId(),
1292
- sessionStartUnixMs: nowUnixMs,
1293
- lastActivityUnixMs: nowUnixMs,
1294
- nextChunkIndex: 0
1295
- };
1296
- await this.safeSet(this.sessionKey, JSON.stringify(session));
1297
- this.identity = {
1298
- sessionId: session.sessionId,
1299
- tabId: generateReplayId(),
1300
- visitorId,
1301
- sessionStartUnixMs: nowUnixMs,
1302
- chunkIndex: 0
1303
- };
1304
- return { ...this.identity };
1776
+ st.i = s;
1305
1777
  }
1306
- async clear() {
1307
- this.identity = null;
1308
- await Promise.all([
1309
- this.safeRemove(this.sessionKey),
1310
- this.safeRemove(this.visitorKey)
1311
- ]);
1778
+ return slc(o, 0, pre + shft(pos) + post);
1779
+ };
1780
+ var crct = /* @__PURE__ */ (function() {
1781
+ var t = new Int32Array(256);
1782
+ for (var i2 = 0; i2 < 256; ++i2) {
1783
+ var c = i2, k = 9;
1784
+ while (--k)
1785
+ c = (c & 1 && -306674912) ^ c >>> 1;
1786
+ t[i2] = c;
1312
1787
  }
1313
- async safeGet(key) {
1314
- try {
1315
- return await this.storage.getItem(key);
1316
- } catch {
1317
- return null;
1788
+ return t;
1789
+ })();
1790
+ var crc = function() {
1791
+ var c = -1;
1792
+ return {
1793
+ p: function(d) {
1794
+ var cr = c;
1795
+ for (var i2 = 0; i2 < d.length; ++i2)
1796
+ cr = crct[cr & 255 ^ d[i2]] ^ cr >>> 8;
1797
+ c = cr;
1798
+ },
1799
+ d: function() {
1800
+ return ~c;
1318
1801
  }
1319
- }
1320
- async safeSet(key, value) {
1321
- try {
1322
- await this.storage.setItem(key, value);
1323
- } catch {
1802
+ };
1803
+ };
1804
+ var dopt = function(dat, opt, pre, post, st) {
1805
+ if (!st) {
1806
+ st = { l: 1 };
1807
+ if (opt.dictionary) {
1808
+ var dict = opt.dictionary.subarray(-32768);
1809
+ var newDat = new u8(dict.length + dat.length);
1810
+ newDat.set(dict);
1811
+ newDat.set(dat, dict.length);
1812
+ dat = newDat;
1813
+ st.w = dict.length;
1324
1814
  }
1325
1815
  }
1326
- async safeRemove(key) {
1327
- try {
1328
- await this.storage.removeItem(key);
1329
- } catch {
1330
- }
1816
+ 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);
1817
+ };
1818
+ var wbytes = function(d, b, v) {
1819
+ for (; v; ++b)
1820
+ d[b] = v, v >>>= 8;
1821
+ };
1822
+ var gzh = function(c, o) {
1823
+ var fn = o.filename;
1824
+ c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3;
1825
+ if (o.mtime != 0)
1826
+ wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1e3));
1827
+ if (fn) {
1828
+ c[3] = 8;
1829
+ for (var i2 = 0; i2 <= fn.length; ++i2)
1830
+ c[i2 + 10] = fn.charCodeAt(i2);
1331
1831
  }
1332
1832
  };
1333
-
1334
- // node_modules/fflate/esm/browser.js
1335
- var u8 = Uint8Array;
1336
- var u16 = Uint16Array;
1337
- var i32 = Int32Array;
1338
- var fleb = new u8([
1339
- 0,
1340
- 0,
1341
- 0,
1342
- 0,
1343
- 0,
1344
- 0,
1345
- 0,
1346
- 0,
1347
- 1,
1348
- 1,
1349
- 1,
1350
- 1,
1351
- 2,
1352
- 2,
1353
- 2,
1354
- 2,
1355
- 3,
1356
- 3,
1357
- 3,
1358
- 3,
1359
- 4,
1360
- 4,
1361
- 4,
1362
- 4,
1363
- 5,
1364
- 5,
1365
- 5,
1366
- 5,
1367
- 0,
1368
- /* unused */
1369
- 0,
1370
- 0,
1371
- /* impossible */
1372
- 0
1373
- ]);
1374
- var fdeb = new u8([
1375
- 0,
1376
- 0,
1377
- 0,
1378
- 0,
1379
- 1,
1380
- 1,
1381
- 2,
1382
- 2,
1383
- 3,
1384
- 3,
1385
- 4,
1386
- 4,
1387
- 5,
1388
- 5,
1389
- 6,
1390
- 6,
1391
- 7,
1392
- 7,
1393
- 8,
1394
- 8,
1395
- 9,
1396
- 9,
1397
- 10,
1398
- 10,
1399
- 11,
1400
- 11,
1401
- 12,
1402
- 12,
1403
- 13,
1404
- 13,
1405
- /* unused */
1406
- 0,
1407
- 0
1408
- ]);
1409
- var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
1410
- var freb = function(eb, start) {
1411
- var b = new u16(31);
1412
- for (var i2 = 0; i2 < 31; ++i2) {
1413
- b[i2] = start += 1 << eb[i2 - 1];
1833
+ var gzs = function(d) {
1834
+ if (d[0] != 31 || d[1] != 139 || d[2] != 8)
1835
+ err(6, "invalid gzip data");
1836
+ var flg = d[3];
1837
+ var st = 10;
1838
+ if (flg & 4)
1839
+ st += (d[10] | d[11] << 8) + 2;
1840
+ for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++])
1841
+ ;
1842
+ return st + (flg & 2);
1843
+ };
1844
+ var gzl = function(d) {
1845
+ var l = d.length;
1846
+ return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0;
1847
+ };
1848
+ var gzhl = function(o) {
1849
+ return 10 + (o.filename ? o.filename.length + 1 : 0);
1850
+ };
1851
+ function gzipSync(data, opts) {
1852
+ if (!opts)
1853
+ opts = {};
1854
+ var c = crc(), l = data.length;
1855
+ c.p(data);
1856
+ var d = dopt(data, opts, gzhl(opts), 8), s = d.length;
1857
+ return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d;
1858
+ }
1859
+ function gunzipSync(data, opts) {
1860
+ var st = gzs(data);
1861
+ if (st + 8 > data.length)
1862
+ err(6, "invalid gzip data");
1863
+ return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary);
1864
+ }
1865
+ var te = typeof TextEncoder != "undefined" && /* @__PURE__ */ new TextEncoder();
1866
+ var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
1867
+ var tds = 0;
1868
+ try {
1869
+ td.decode(et, { stream: true });
1870
+ tds = 1;
1871
+ } catch (e) {
1872
+ }
1873
+ var dutf8 = function(d) {
1874
+ for (var r = "", i2 = 0; ; ) {
1875
+ var c = d[i2++];
1876
+ var eb = (c > 127) + (c > 223) + (c > 239);
1877
+ if (i2 + eb > d.length)
1878
+ return { s: r, r: slc(d, i2 - 1) };
1879
+ if (!eb)
1880
+ r += String.fromCharCode(c);
1881
+ else if (eb == 3) {
1882
+ 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);
1883
+ } else if (eb & 1)
1884
+ r += String.fromCharCode((c & 31) << 6 | d[i2++] & 63);
1885
+ else
1886
+ r += String.fromCharCode((c & 15) << 12 | (d[i2++] & 63) << 6 | d[i2++] & 63);
1414
1887
  }
1415
- var r = new i32(b[30]);
1416
- for (var i2 = 1; i2 < 30; ++i2) {
1417
- for (var j = b[i2]; j < b[i2 + 1]; ++j) {
1418
- r[j] = j - b[i2] << 5 | i2;
1888
+ };
1889
+ function strToU8(str, latin1) {
1890
+ if (latin1) {
1891
+ var ar_1 = new u8(str.length);
1892
+ for (var i2 = 0; i2 < str.length; ++i2)
1893
+ ar_1[i2] = str.charCodeAt(i2);
1894
+ return ar_1;
1895
+ }
1896
+ if (te)
1897
+ return te.encode(str);
1898
+ var l = str.length;
1899
+ var ar = new u8(str.length + (str.length >> 1));
1900
+ var ai = 0;
1901
+ var w = function(v) {
1902
+ ar[ai++] = v;
1903
+ };
1904
+ for (var i2 = 0; i2 < l; ++i2) {
1905
+ if (ai + 5 > ar.length) {
1906
+ var n = new u8(ai + 8 + (l - i2 << 1));
1907
+ n.set(ar);
1908
+ ar = n;
1419
1909
  }
1910
+ var c = str.charCodeAt(i2);
1911
+ if (c < 128 || latin1)
1912
+ w(c);
1913
+ else if (c < 2048)
1914
+ w(192 | c >> 6), w(128 | c & 63);
1915
+ else if (c > 55295 && c < 57344)
1916
+ 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);
1917
+ else
1918
+ w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63);
1420
1919
  }
1421
- return { b, r };
1422
- };
1423
- var _a = freb(fleb, 2);
1424
- var fl = _a.b;
1425
- var revfl = _a.r;
1426
- fl[28] = 258, revfl[258] = 28;
1427
- var _b = freb(fdeb, 0);
1428
- var fd = _b.b;
1429
- var revfd = _b.r;
1430
- var rev = new u16(32768);
1431
- for (i = 0; i < 32768; ++i) {
1432
- x = (i & 43690) >> 1 | (i & 21845) << 1;
1433
- x = (x & 52428) >> 2 | (x & 13107) << 2;
1434
- x = (x & 61680) >> 4 | (x & 3855) << 4;
1435
- rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
1920
+ return slc(ar, 0, ai);
1436
1921
  }
1437
- var x;
1438
- var i;
1439
- var hMap = (function(cd, mb, r) {
1440
- var s = cd.length;
1441
- var i2 = 0;
1442
- var l = new u16(mb);
1443
- for (; i2 < s; ++i2) {
1444
- if (cd[i2])
1445
- ++l[cd[i2] - 1];
1922
+ function strFromU8(dat, latin1) {
1923
+ if (latin1) {
1924
+ var r = "";
1925
+ for (var i2 = 0; i2 < dat.length; i2 += 16384)
1926
+ r += String.fromCharCode.apply(null, dat.subarray(i2, i2 + 16384));
1927
+ return r;
1928
+ } else if (td) {
1929
+ return td.decode(dat);
1930
+ } else {
1931
+ var _a2 = dutf8(dat), s = _a2.s, r = _a2.r;
1932
+ if (r.length)
1933
+ err(8);
1934
+ return s;
1446
1935
  }
1447
- var le = new u16(mb);
1448
- for (i2 = 1; i2 < mb; ++i2) {
1449
- le[i2] = le[i2 - 1] + l[i2 - 1] << 1;
1936
+ }
1937
+
1938
+ // src/Base64.ts
1939
+ var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1940
+ var LOOKUP = (() => {
1941
+ const table = new Int16Array(128).fill(-1);
1942
+ for (let index = 0; index < ALPHABET.length; index += 1) {
1943
+ table[ALPHABET.charCodeAt(index)] = index;
1944
+ }
1945
+ return table;
1946
+ })();
1947
+ function encodeBase64(bytes) {
1948
+ const parts = [];
1949
+ for (let index = 0; index < bytes.length; index += 3) {
1950
+ const first = bytes[index];
1951
+ const second = bytes[index + 1];
1952
+ const third = bytes[index + 2];
1953
+ const triple = first << 16 | (second ?? 0) << 8 | (third ?? 0);
1954
+ parts.push(
1955
+ 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))
1956
+ );
1450
1957
  }
1451
- var co;
1452
- if (r) {
1453
- co = new u16(1 << mb);
1454
- var rvb = 15 - mb;
1455
- for (i2 = 0; i2 < s; ++i2) {
1456
- if (cd[i2]) {
1457
- var sv = i2 << 4 | cd[i2];
1458
- var r_1 = mb - cd[i2];
1459
- var v = le[cd[i2] - 1]++ << r_1;
1460
- for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
1461
- co[rev[v] >> rvb] = sv;
1462
- }
1463
- }
1958
+ return parts.join("");
1959
+ }
1960
+ function decodeBase64(text) {
1961
+ if (typeof text !== "string" || text.length % 4 !== 0) {
1962
+ return null;
1963
+ }
1964
+ const padding = text.endsWith("==") ? 2 : text.endsWith("=") ? 1 : 0;
1965
+ const bytes = new Uint8Array(text.length / 4 * 3 - padding);
1966
+ let buffer = 0;
1967
+ let bits2 = 0;
1968
+ let written = 0;
1969
+ for (let index = 0; index < text.length - padding; index += 1) {
1970
+ const code = text.charCodeAt(index);
1971
+ const value = code < 128 ? LOOKUP[code] : -1;
1972
+ if (value < 0) {
1973
+ return null;
1464
1974
  }
1465
- } else {
1466
- co = new u16(s);
1467
- for (i2 = 0; i2 < s; ++i2) {
1468
- if (cd[i2]) {
1469
- co[i2] = rev[le[cd[i2] - 1]++] >> 15 - cd[i2];
1470
- }
1975
+ buffer = (buffer << 6 | value) & 16777215;
1976
+ bits2 += 6;
1977
+ if (bits2 >= 8) {
1978
+ bits2 -= 8;
1979
+ bytes[written] = buffer >> bits2 & 255;
1980
+ written += 1;
1471
1981
  }
1472
1982
  }
1473
- return co;
1474
- });
1475
- var flt = new u8(288);
1476
- for (i = 0; i < 144; ++i)
1477
- flt[i] = 8;
1478
- var i;
1479
- for (i = 144; i < 256; ++i)
1480
- flt[i] = 9;
1481
- var i;
1482
- for (i = 256; i < 280; ++i)
1483
- flt[i] = 7;
1484
- var i;
1485
- for (i = 280; i < 288; ++i)
1486
- flt[i] = 8;
1487
- var i;
1488
- var fdt = new u8(32);
1489
- for (i = 0; i < 32; ++i)
1490
- fdt[i] = 5;
1491
- var i;
1492
- var flm = /* @__PURE__ */ hMap(flt, 9, 0);
1493
- var fdm = /* @__PURE__ */ hMap(fdt, 5, 0);
1494
- var shft = function(p) {
1495
- return (p + 7) / 8 | 0;
1496
- };
1497
- var slc = function(v, s, e) {
1498
- if (s == null || s < 0)
1499
- s = 0;
1500
- if (e == null || e > v.length)
1501
- e = v.length;
1502
- return new u8(v.subarray(s, e));
1503
- };
1504
- var wbits = function(d, p, v) {
1505
- v <<= p & 7;
1506
- var o = p / 8 | 0;
1507
- d[o] |= v;
1508
- d[o + 1] |= v >> 8;
1509
- };
1510
- var wbits16 = function(d, p, v) {
1511
- v <<= p & 7;
1512
- var o = p / 8 | 0;
1513
- d[o] |= v;
1514
- d[o + 1] |= v >> 8;
1515
- d[o + 2] |= v >> 16;
1516
- };
1517
- var hTree = function(d, mb) {
1518
- var t = [];
1519
- for (var i2 = 0; i2 < d.length; ++i2) {
1520
- if (d[i2])
1521
- t.push({ s: i2, f: d[i2] });
1983
+ return written === bytes.length ? bytes : null;
1984
+ }
1985
+
1986
+ // src/Outbox.ts
1987
+ var MAX_OUTBOX_ENTRIES = 240;
1988
+ var MAX_OUTBOX_BYTES = 3 * 1024 * 1024;
1989
+ function isEnvelope(value) {
1990
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1991
+ return false;
1522
1992
  }
1523
- var s = t.length;
1524
- var t2 = t.slice();
1525
- if (!s)
1526
- return { t: et, l: 0 };
1527
- if (s == 1) {
1528
- var v = new u8(t[0].s + 1);
1529
- v[t[0].s] = 1;
1530
- return { t: v, l: 1 };
1993
+ const envelope = value;
1994
+ return typeof envelope.sessionId === "string" && typeof envelope.tabId === "string" && typeof envelope.chunkIndex === "number";
1995
+ }
1996
+ function isEntry(value) {
1997
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1998
+ return false;
1531
1999
  }
1532
- t.sort(function(a, b) {
1533
- return a.f - b.f;
1534
- });
1535
- t.push({ s: -1, f: 25001 });
1536
- var l = t[0], r = t[1], i0 = 0, i1 = 1, i22 = 2;
1537
- t[0] = { s: -1, f: l.f + r.f, l, r };
1538
- while (i1 != s - 1) {
1539
- l = t[t[i0].f < t[i22].f ? i0++ : i22++];
1540
- r = t[i0 != i1 && t[i0].f < t[i22].f ? i0++ : i22++];
1541
- t[i1++] = { s: -1, f: l.f + r.f, l, r };
2000
+ const entry = value;
2001
+ return typeof entry.id === "string" && Number.isSafeInteger(entry.attempts) && typeof entry.createdAtUnixMs === "number" && Number.isFinite(entry.createdAtUnixMs) && Number.isSafeInteger(entry.bytes);
2002
+ }
2003
+ function isLegacyFrame(value) {
2004
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2005
+ return false;
1542
2006
  }
1543
- var maxSym = t2[0].s;
1544
- for (var i2 = 1; i2 < s; ++i2) {
1545
- if (t2[i2].s > maxSym)
1546
- maxSym = t2[i2].s;
2007
+ const frame = value;
2008
+ return typeof frame.id === "string" && typeof frame.payload === "string" && typeof frame.attempts === "number" && Number.isSafeInteger(frame.attempts) && typeof frame.createdAtUnixMs === "number" && isEnvelope(frame.envelope);
2009
+ }
2010
+ function byOldest(left, right) {
2011
+ return left.createdAtUnixMs - right.createdAtUnixMs;
2012
+ }
2013
+ function frameId(envelope) {
2014
+ return `${envelope.sessionId}:${envelope.tabId}:${envelope.chunkIndex}`;
2015
+ }
2016
+ var ReplayOutbox = class {
2017
+ constructor(storage, namespace, now = Date.now) {
2018
+ __publicField(this, "storage");
2019
+ __publicField(this, "legacyKey");
2020
+ __publicField(this, "indexKey");
2021
+ __publicField(this, "framePrefix");
2022
+ __publicField(this, "now");
2023
+ __publicField(this, "mutationQueue", Promise.resolve());
2024
+ __publicField(this, "migrated", false);
2025
+ this.storage = storage;
2026
+ this.legacyKey = `@oneuptime/replay/${namespace}/outbox`;
2027
+ this.indexKey = `@oneuptime/replay/${namespace}/outbox-v2`;
2028
+ this.framePrefix = `@oneuptime/replay/${namespace}/outbox-v2/`;
2029
+ this.now = now;
1547
2030
  }
1548
- var tr = new u16(maxSym + 1);
1549
- var mbt = ln(t[i1 - 1], tr, 0);
1550
- if (mbt > mb) {
1551
- var i2 = 0, dt = 0;
1552
- var lft = mbt - mb, cst = 1 << lft;
1553
- t2.sort(function(a, b) {
1554
- return tr[b.s] - tr[a.s] || a.f - b.f;
2031
+ /* Every queued frame's index entry, oldest first. Reads no payload. */
2032
+ async entries() {
2033
+ return await this.withLock(async () => {
2034
+ return await this.readIndexUnlocked();
1555
2035
  });
1556
- for (; i2 < s; ++i2) {
1557
- var i2_1 = t2[i2].s;
1558
- if (tr[i2_1] > mb) {
1559
- dt += cst - (1 << mbt - tr[i2_1]);
1560
- tr[i2_1] = mb;
1561
- } else
1562
- break;
2036
+ }
2037
+ /*
2038
+ * One frame, ready to post. Null when it is no longer queued, and
2039
+ * "unreadable" when its value could not be read back - it is removed, so
2040
+ * one damaged frame never blocks the ones behind it.
2041
+ */
2042
+ async load(id) {
2043
+ return await this.withLock(
2044
+ async () => {
2045
+ const entries = await this.readIndexUnlocked();
2046
+ const entry = entries.find(
2047
+ (candidate) => {
2048
+ return candidate.id === id;
2049
+ }
2050
+ );
2051
+ if (!entry) {
2052
+ return null;
2053
+ }
2054
+ const value = await this.readFrameUnlocked(id);
2055
+ if (!value) {
2056
+ await this.removeEntriesUnlocked(entries, [id]);
2057
+ return "unreadable";
2058
+ }
2059
+ return {
2060
+ id,
2061
+ envelope: value.envelope,
2062
+ compressedPayload: value.bytes,
2063
+ attempts: entry.attempts,
2064
+ createdAtUnixMs: entry.createdAtUnixMs
2065
+ };
2066
+ }
2067
+ );
2068
+ }
2069
+ /* Every frame with its payload decompressed, oldest first. */
2070
+ async list() {
2071
+ const frames = [];
2072
+ for (const entry of await this.entries()) {
2073
+ const frame = await this.load(
2074
+ entry.id
2075
+ );
2076
+ if (!frame || frame === "unreadable") {
2077
+ continue;
2078
+ }
2079
+ frames.push({
2080
+ id: frame.id,
2081
+ envelope: frame.envelope,
2082
+ payload: strFromU8(gunzipSync(frame.compressedPayload)),
2083
+ attempts: frame.attempts,
2084
+ createdAtUnixMs: frame.createdAtUnixMs
2085
+ });
1563
2086
  }
1564
- dt >>= lft;
1565
- while (dt > 0) {
1566
- var i2_2 = t2[i2].s;
1567
- if (tr[i2_2] < mb)
1568
- dt -= 1 << mb - tr[i2_2]++ - 1;
1569
- else
1570
- ++i2;
2087
+ return frames;
2088
+ }
2089
+ /*
2090
+ * Queue a frame. Past MAX_OUTBOX_ENTRIES or MAX_OUTBOX_BYTES the OLDEST
2091
+ * frames are evicted - the newest seconds are the ones closest to whatever
2092
+ * went wrong, and a later full snapshot re-anchors the player after a gap -
2093
+ * and counted in `dropped`, as is a frame the device had no room to store.
2094
+ */
2095
+ async enqueue(frame) {
2096
+ return await this.withLock(async () => {
2097
+ const entries = await this.readIndexUnlocked();
2098
+ if (entries.some((candidate) => {
2099
+ return candidate.id === frame.id;
2100
+ })) {
2101
+ return { dropped: 0 };
2102
+ }
2103
+ const bytes = await this.writeFrameUnlocked(frame);
2104
+ if (bytes === null) {
2105
+ return { dropped: 1 };
2106
+ }
2107
+ entries.push({
2108
+ id: frame.id,
2109
+ attempts: frame.attempts,
2110
+ createdAtUnixMs: frame.createdAtUnixMs,
2111
+ bytes
2112
+ });
2113
+ entries.sort(byOldest);
2114
+ let totalBytes = 0;
2115
+ for (const entry of entries) {
2116
+ totalBytes += entry.bytes;
2117
+ }
2118
+ const evicted = [];
2119
+ while (entries.length > 1 && (entries.length > MAX_OUTBOX_ENTRIES || totalBytes > MAX_OUTBOX_BYTES)) {
2120
+ const oldest = entries.shift();
2121
+ totalBytes -= oldest.bytes;
2122
+ evicted.push(oldest.id);
2123
+ }
2124
+ if (!await this.writeIndexUnlocked(entries)) {
2125
+ await this.safeRemove(this.frameKey(frame.id));
2126
+ return { dropped: 1 };
2127
+ }
2128
+ await Promise.all(
2129
+ evicted.map((id) => {
2130
+ return this.safeRemove(this.frameKey(id));
2131
+ })
2132
+ );
2133
+ return { dropped: evicted.length };
2134
+ });
2135
+ }
2136
+ async remove(id) {
2137
+ await this.withLock(async () => {
2138
+ await this.removeEntriesUnlocked(await this.readIndexUnlocked(), [id]);
2139
+ });
2140
+ }
2141
+ async incrementAttempts(id) {
2142
+ return await this.withLock(async () => {
2143
+ const entries = await this.readIndexUnlocked();
2144
+ let attempts = 0;
2145
+ for (const entry of entries) {
2146
+ if (entry.id === id) {
2147
+ entry.attempts += 1;
2148
+ attempts = entry.attempts;
2149
+ break;
2150
+ }
2151
+ }
2152
+ await this.writeIndexUnlocked(entries);
2153
+ return attempts;
2154
+ });
2155
+ }
2156
+ /*
2157
+ * Consent withdrawn, or the server refused this recorder for good: every
2158
+ * frame goes, including any a crash left untracked by the index when the
2159
+ * storage can list its keys.
2160
+ */
2161
+ async clear() {
2162
+ await this.withLock(async () => {
2163
+ const keys = /* @__PURE__ */ new Set([
2164
+ this.legacyKey,
2165
+ this.indexKey
2166
+ ]);
2167
+ for (const entry of await this.readRawIndexUnlocked()) {
2168
+ keys.add(this.frameKey(entry.id));
2169
+ }
2170
+ if (typeof this.storage.getAllKeys === "function") {
2171
+ try {
2172
+ for (const key of await this.storage.getAllKeys()) {
2173
+ if (key.startsWith(this.framePrefix)) {
2174
+ keys.add(key);
2175
+ }
2176
+ }
2177
+ } catch {
2178
+ }
2179
+ }
2180
+ this.migrated = true;
2181
+ await Promise.all(
2182
+ Array.from(keys).map((key) => {
2183
+ return this.safeRemove(key);
2184
+ })
2185
+ );
2186
+ });
2187
+ }
2188
+ frameKey(id) {
2189
+ return `${this.framePrefix}${id}`;
2190
+ }
2191
+ /*
2192
+ * The index, with the legacy layout migrated into it on first use and
2193
+ * anything older than SESSION_REPLAY_MAX_OFFLINE_DELAY_MS pruned: the
2194
+ * server would no longer place it on the recording's real timeline.
2195
+ */
2196
+ async readIndexUnlocked() {
2197
+ await this.migrateUnlocked();
2198
+ const entries = await this.readRawIndexUnlocked();
2199
+ const oldestKept = this.now() - SESSION_REPLAY_MAX_OFFLINE_DELAY_MS;
2200
+ const expired = entries.filter((entry) => {
2201
+ return entry.createdAtUnixMs < oldestKept;
2202
+ }).map((entry) => {
2203
+ return entry.id;
2204
+ });
2205
+ if (expired.length > 0) {
2206
+ await this.removeEntriesUnlocked(entries, expired);
1571
2207
  }
1572
- for (; i2 >= 0 && dt; --i2) {
1573
- var i2_3 = t2[i2].s;
1574
- if (tr[i2_3] == mb) {
1575
- --tr[i2_3];
1576
- ++dt;
2208
+ return entries.sort(byOldest);
2209
+ }
2210
+ async readRawIndexUnlocked() {
2211
+ let raw = null;
2212
+ try {
2213
+ raw = await this.storage.getItem(this.indexKey);
2214
+ } catch {
2215
+ raw = null;
2216
+ }
2217
+ if (!raw) {
2218
+ return [];
2219
+ }
2220
+ try {
2221
+ const parsed = JSON.parse(raw);
2222
+ if (Array.isArray(parsed) && parsed.every(isEntry)) {
2223
+ return parsed;
1577
2224
  }
2225
+ } catch {
1578
2226
  }
1579
- mbt = mb;
2227
+ await this.safeRemove(this.indexKey);
2228
+ return [];
1580
2229
  }
1581
- return { t: new u8(tr), l: mbt };
1582
- };
1583
- var ln = function(n, l, d) {
1584
- return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;
1585
- };
1586
- var lc = function(c) {
1587
- var s = c.length;
1588
- while (s && !c[--s])
1589
- ;
1590
- var cl = new u16(++s);
1591
- var cli = 0, cln = c[0], cls = 1;
1592
- var w = function(v) {
1593
- cl[cli++] = v;
1594
- };
1595
- for (var i2 = 1; i2 <= s; ++i2) {
1596
- if (c[i2] == cln && i2 != s)
1597
- ++cls;
1598
- else {
1599
- if (!cln && cls > 2) {
1600
- for (; cls > 138; cls -= 138)
1601
- w(32754);
1602
- if (cls > 2) {
1603
- w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);
1604
- cls = 0;
1605
- }
1606
- } else if (cls > 3) {
1607
- w(cln), --cls;
1608
- for (; cls > 6; cls -= 6)
1609
- w(8304);
1610
- if (cls > 2)
1611
- w(cls - 3 << 5 | 8208), cls = 0;
2230
+ async writeIndexUnlocked(entries) {
2231
+ if (entries.length === 0) {
2232
+ await this.safeRemove(this.indexKey);
2233
+ return true;
2234
+ }
2235
+ return await this.safeSet(this.indexKey, JSON.stringify(entries));
2236
+ }
2237
+ /* Drop entries from the index and their frames from storage. */
2238
+ async removeEntriesUnlocked(entries, ids) {
2239
+ const removing = new Set(ids);
2240
+ const kept = entries.filter(
2241
+ (entry) => {
2242
+ return !removing.has(entry.id);
1612
2243
  }
1613
- while (cls--)
1614
- w(cln);
1615
- cls = 1;
1616
- cln = c[i2];
2244
+ );
2245
+ entries.splice(0, entries.length, ...kept);
2246
+ await this.writeIndexUnlocked(entries);
2247
+ await Promise.all(
2248
+ ids.map((id) => {
2249
+ return this.safeRemove(this.frameKey(id));
2250
+ })
2251
+ );
2252
+ }
2253
+ /* Store one frame's value. Its size, or null when it could not be stored. */
2254
+ async writeFrameUnlocked(frame) {
2255
+ let value;
2256
+ try {
2257
+ const stored = {
2258
+ envelope: frame.envelope,
2259
+ gzip: encodeBase64(gzipSync(strToU8(frame.payload)))
2260
+ };
2261
+ value = JSON.stringify(stored);
2262
+ } catch {
2263
+ return null;
1617
2264
  }
2265
+ return await this.safeSet(this.frameKey(frame.id), value) ? byteLength(value) : null;
1618
2266
  }
1619
- return { c: cl.subarray(0, cli), n: s };
1620
- };
1621
- var clen = function(cf, cl) {
1622
- var l = 0;
1623
- for (var i2 = 0; i2 < cl.length; ++i2)
1624
- l += cf[i2] * cl[i2];
1625
- return l;
1626
- };
1627
- var wfblk = function(out, pos, dat) {
1628
- var s = dat.length;
1629
- var o = shft(pos + 2);
1630
- out[o] = s & 255;
1631
- out[o + 1] = s >> 8;
1632
- out[o + 2] = out[o] ^ 255;
1633
- out[o + 3] = out[o + 1] ^ 255;
1634
- for (var i2 = 0; i2 < s; ++i2)
1635
- out[o + i2 + 4] = dat[i2];
1636
- return (o + 4 + s) * 8;
1637
- };
1638
- var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) {
1639
- wbits(out, p++, final);
1640
- ++lf[256];
1641
- var _a2 = hTree(lf, 15), dlt = _a2.t, mlb = _a2.l;
1642
- var _b2 = hTree(df, 15), ddt = _b2.t, mdb = _b2.l;
1643
- var _c = lc(dlt), lclt = _c.c, nlc = _c.n;
1644
- var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;
1645
- var lcfreq = new u16(19);
1646
- for (var i2 = 0; i2 < lclt.length; ++i2)
1647
- ++lcfreq[lclt[i2] & 31];
1648
- for (var i2 = 0; i2 < lcdt.length; ++i2)
1649
- ++lcfreq[lcdt[i2] & 31];
1650
- var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;
1651
- var nlcc = 19;
1652
- for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)
1653
- ;
1654
- var flen = bl + 5 << 3;
1655
- var ftlen = clen(lf, flt) + clen(df, fdt) + eb;
1656
- var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];
1657
- if (bs >= 0 && flen <= ftlen && flen <= dtlen)
1658
- return wfblk(out, p, dat.subarray(bs, bs + bl));
1659
- var lm, ll, dm, dl;
1660
- wbits(out, p, 1 + (dtlen < ftlen)), p += 2;
1661
- if (dtlen < ftlen) {
1662
- lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;
1663
- var llm = hMap(lct, mlcb, 0);
1664
- wbits(out, p, nlc - 257);
1665
- wbits(out, p + 5, ndc - 1);
1666
- wbits(out, p + 10, nlcc - 4);
1667
- p += 14;
1668
- for (var i2 = 0; i2 < nlcc; ++i2)
1669
- wbits(out, p + 3 * i2, lct[clim[i2]]);
1670
- p += 3 * nlcc;
1671
- var lcts = [lclt, lcdt];
1672
- for (var it = 0; it < 2; ++it) {
1673
- var clct = lcts[it];
1674
- for (var i2 = 0; i2 < clct.length; ++i2) {
1675
- var len = clct[i2] & 31;
1676
- wbits(out, p, llm[len]), p += lct[len];
1677
- if (len > 15)
1678
- wbits(out, p, clct[i2] >> 5 & 127), p += clct[i2] >> 12;
2267
+ async readFrameUnlocked(id) {
2268
+ try {
2269
+ const raw = await this.storage.getItem(this.frameKey(id));
2270
+ if (!raw) {
2271
+ return null;
1679
2272
  }
2273
+ const parsed = JSON.parse(
2274
+ raw
2275
+ );
2276
+ const bytes = typeof parsed.gzip === "string" ? decodeBase64(parsed.gzip) : null;
2277
+ if (!bytes || !isEnvelope(parsed.envelope)) {
2278
+ return null;
2279
+ }
2280
+ return { envelope: parsed.envelope, bytes };
2281
+ } catch {
2282
+ return null;
1680
2283
  }
1681
- } else {
1682
- lm = flm, ll = flt, dm = fdm, dl = fdt;
1683
2284
  }
1684
- for (var i2 = 0; i2 < li; ++i2) {
1685
- var sym = syms[i2];
1686
- if (sym > 255) {
1687
- var len = sym >> 18 & 31;
1688
- wbits16(out, p, lm[len + 257]), p += ll[len + 257];
1689
- if (len > 7)
1690
- wbits(out, p, sym >> 23 & 31), p += fleb[len];
1691
- var dst = sym & 31;
1692
- wbits16(out, p, dm[dst]), p += dl[dst];
1693
- if (dst > 3)
1694
- wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst];
1695
- } else {
1696
- wbits16(out, p, lm[sym]), p += ll[sym];
2285
+ /*
2286
+ * Move a queue written by an earlier SDK version (one JSON array under the
2287
+ * legacy key) into this layout, once. A legacy queue too large to read -
2288
+ * the very failure this layout exists to fix - cannot be recovered, only
2289
+ * removed so it stops failing.
2290
+ */
2291
+ async migrateUnlocked() {
2292
+ if (this.migrated) {
2293
+ return;
2294
+ }
2295
+ this.migrated = true;
2296
+ let raw = null;
2297
+ try {
2298
+ raw = await this.storage.getItem(this.legacyKey);
2299
+ } catch {
2300
+ await this.safeRemove(this.legacyKey);
2301
+ return;
1697
2302
  }
2303
+ if (!raw) {
2304
+ return;
2305
+ }
2306
+ let legacy = [];
2307
+ try {
2308
+ const parsed = JSON.parse(raw);
2309
+ if (Array.isArray(parsed)) {
2310
+ legacy = parsed.filter(isLegacyFrame);
2311
+ }
2312
+ } catch {
2313
+ legacy = [];
2314
+ }
2315
+ const entries = await this.readRawIndexUnlocked();
2316
+ for (const frame of legacy) {
2317
+ if (entries.some((entry) => {
2318
+ return entry.id === frame.id;
2319
+ })) {
2320
+ continue;
2321
+ }
2322
+ const bytes = await this.writeFrameUnlocked(frame);
2323
+ if (bytes !== null) {
2324
+ entries.push({
2325
+ id: frame.id,
2326
+ attempts: frame.attempts,
2327
+ createdAtUnixMs: frame.createdAtUnixMs,
2328
+ bytes
2329
+ });
2330
+ }
2331
+ }
2332
+ await this.writeIndexUnlocked(entries.sort(byOldest));
2333
+ await this.safeRemove(this.legacyKey);
1698
2334
  }
1699
- wbits16(out, p, lm[256]);
1700
- return p + ll[256];
1701
- };
1702
- var deo = /* @__PURE__ */ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
1703
- var et = /* @__PURE__ */ new u8(0);
1704
- var dflt = function(dat, lvl, plvl, pre, post, st) {
1705
- var s = st.z || dat.length;
1706
- var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);
1707
- var w = o.subarray(pre, o.length - post);
1708
- var lst = st.l;
1709
- var pos = (st.r || 0) & 7;
1710
- if (lvl) {
1711
- if (pos)
1712
- w[0] = st.r >> 3;
1713
- var opt = deo[lvl - 1];
1714
- var n = opt >> 13, c = opt & 8191;
1715
- var msk_1 = (1 << plvl) - 1;
1716
- var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);
1717
- var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;
1718
- var hsh = function(i3) {
1719
- return (dat[i3] ^ dat[i3 + 1] << bs1_1 ^ dat[i3 + 2] << bs2_1) & msk_1;
1720
- };
1721
- var syms = new i32(25e3);
1722
- var lf = new u16(288), df = new u16(32);
1723
- var lc_1 = 0, eb = 0, i2 = st.i || 0, li = 0, wi = st.w || 0, bs = 0;
1724
- for (; i2 + 2 < s; ++i2) {
1725
- var hv = hsh(i2);
1726
- var imod = i2 & 32767, pimod = head[hv];
1727
- prev[imod] = pimod;
1728
- head[hv] = imod;
1729
- if (wi <= i2) {
1730
- var rem = s - i2;
1731
- if ((lc_1 > 7e3 || li > 24576) && (rem > 423 || !lst)) {
1732
- pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i2 - bs, pos);
1733
- li = lc_1 = eb = 0, bs = i2;
1734
- for (var j = 0; j < 286; ++j)
1735
- lf[j] = 0;
1736
- for (var j = 0; j < 30; ++j)
1737
- df[j] = 0;
1738
- }
1739
- var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;
1740
- if (rem > 2 && hv == hsh(i2 - dif)) {
1741
- var maxn = Math.min(n, rem) - 1;
1742
- var maxd = Math.min(32767, i2);
1743
- var ml = Math.min(258, rem);
1744
- while (dif <= maxd && --ch_1 && imod != pimod) {
1745
- if (dat[i2 + l] == dat[i2 + l - dif]) {
1746
- var nl = 0;
1747
- for (; nl < ml && dat[i2 + nl] == dat[i2 + nl - dif]; ++nl)
1748
- ;
1749
- if (nl > l) {
1750
- l = nl, d = dif;
1751
- if (nl > maxn)
1752
- break;
1753
- var mmd = Math.min(dif, nl - 2);
1754
- var md = 0;
1755
- for (var j = 0; j < mmd; ++j) {
1756
- var ti = i2 - dif + j & 32767;
1757
- var pti = prev[ti];
1758
- var cd = ti - pti & 32767;
1759
- if (cd > md)
1760
- md = cd, pimod = ti;
1761
- }
1762
- }
1763
- }
1764
- imod = pimod, pimod = prev[imod];
1765
- dif += imod - pimod & 32767;
1766
- }
1767
- }
1768
- if (d) {
1769
- syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];
1770
- var lin = revfl[l] & 31, din = revfd[d] & 31;
1771
- eb += fleb[lin] + fdeb[din];
1772
- ++lf[257 + lin];
1773
- ++df[din];
1774
- wi = i2 + l;
1775
- ++lc_1;
1776
- } else {
1777
- syms[li++] = dat[i2];
1778
- ++lf[dat[i2]];
1779
- }
2335
+ async safeSet(key, value) {
2336
+ try {
2337
+ await this.storage.setItem(key, value);
2338
+ return true;
2339
+ } catch {
2340
+ return false;
2341
+ }
2342
+ }
2343
+ async safeRemove(key) {
2344
+ try {
2345
+ await this.storage.removeItem(key);
2346
+ } catch {
2347
+ }
2348
+ }
2349
+ async withLock(operation) {
2350
+ const result = this.mutationQueue.then(operation, operation);
2351
+ this.mutationQueue = result.then(
2352
+ () => {
2353
+ return void 0;
2354
+ },
2355
+ () => {
2356
+ return void 0;
1780
2357
  }
2358
+ );
2359
+ return await result;
2360
+ }
2361
+ };
2362
+
2363
+ // src/Storage.ts
2364
+ import AsyncStorage from "@react-native-async-storage/async-storage";
2365
+ var REPLAY_ID_PATTERN = /^[0-9a-f]{32}$/u;
2366
+ var defaultReplayStorage = AsyncStorage;
2367
+ function generateReplayId() {
2368
+ const bytes = new Uint8Array(16);
2369
+ const cryptoRef = globalThis.crypto;
2370
+ if (cryptoRef && typeof cryptoRef.getRandomValues === "function") {
2371
+ cryptoRef.getRandomValues(bytes);
2372
+ } else {
2373
+ for (let index = 0; index < bytes.length; index += 1) {
2374
+ bytes[index] = Math.floor(Math.random() * 256);
1781
2375
  }
1782
- for (i2 = Math.max(i2, wi); i2 < s; ++i2) {
1783
- syms[li++] = dat[i2];
1784
- ++lf[dat[i2]];
2376
+ }
2377
+ return Array.from(bytes).map((byte) => {
2378
+ return byte.toString(16).padStart(2, "0");
2379
+ }).join("");
2380
+ }
2381
+ function isReplayId(value) {
2382
+ return typeof value === "string" && REPLAY_ID_PATTERN.test(value);
2383
+ }
2384
+ function parseStoredSession(value) {
2385
+ if (!value) {
2386
+ return null;
2387
+ }
2388
+ try {
2389
+ const parsed = JSON.parse(value);
2390
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
2391
+ return null;
2392
+ }
2393
+ const candidate = parsed;
2394
+ if (!isReplayId(candidate.sessionId) || !Number.isSafeInteger(candidate.sessionStartUnixMs) || !Number.isSafeInteger(candidate.lastActivityUnixMs) || !Number.isSafeInteger(candidate.nextChunkIndex) || (candidate.nextChunkIndex ?? -1) < 0) {
2395
+ return null;
2396
+ }
2397
+ return candidate;
2398
+ } catch {
2399
+ return null;
2400
+ }
2401
+ }
2402
+ var ReplaySessionStore = class {
2403
+ constructor(storage, namespace) {
2404
+ __publicField(this, "storage");
2405
+ __publicField(this, "sessionKey");
2406
+ __publicField(this, "visitorKey");
2407
+ __publicField(this, "identity", null);
2408
+ this.storage = storage;
2409
+ this.sessionKey = `@oneuptime/replay/${namespace}/session`;
2410
+ this.visitorKey = `@oneuptime/replay/${namespace}/visitor`;
2411
+ }
2412
+ async resolve(nowUnixMs) {
2413
+ const stored = parseStoredSession(
2414
+ await this.safeGet(this.sessionKey)
2415
+ );
2416
+ 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;
2417
+ let session;
2418
+ if (shouldRotate || !stored) {
2419
+ session = {
2420
+ sessionId: generateReplayId(),
2421
+ sessionStartUnixMs: nowUnixMs,
2422
+ lastActivityUnixMs: nowUnixMs,
2423
+ nextChunkIndex: 0
2424
+ };
2425
+ } else {
2426
+ session = {
2427
+ sessionId: stored.sessionId,
2428
+ sessionStartUnixMs: stored.sessionStartUnixMs,
2429
+ lastActivityUnixMs: nowUnixMs,
2430
+ nextChunkIndex: stored.nextChunkIndex
2431
+ };
1785
2432
  }
1786
- pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i2 - bs, pos);
1787
- if (!lst) {
1788
- st.r = pos & 7 | w[pos / 8 | 0] << 3;
1789
- pos -= 7;
1790
- st.h = head, st.p = prev, st.i = i2, st.w = wi;
2433
+ let visitorId = await this.safeGet(this.visitorKey);
2434
+ if (!isReplayId(visitorId)) {
2435
+ visitorId = generateReplayId();
2436
+ await this.safeSet(this.visitorKey, visitorId);
1791
2437
  }
1792
- } else {
1793
- for (var i2 = st.w || 0; i2 < s + lst; i2 += 65535) {
1794
- var e = i2 + 65535;
1795
- if (e >= s) {
1796
- w[pos / 8 | 0] = lst;
1797
- e = s;
1798
- }
1799
- pos = wfblk(w, pos + 1, dat.subarray(i2, e));
2438
+ await this.safeSet(this.sessionKey, JSON.stringify(session));
2439
+ this.identity = {
2440
+ sessionId: session.sessionId,
2441
+ tabId: generateReplayId(),
2442
+ visitorId,
2443
+ sessionStartUnixMs: session.sessionStartUnixMs,
2444
+ chunkIndex: session.nextChunkIndex
2445
+ };
2446
+ return { ...this.identity };
2447
+ }
2448
+ async takeChunkIndex(nowUnixMs) {
2449
+ if (!this.identity) {
2450
+ await this.resolve(nowUnixMs);
1800
2451
  }
1801
- st.i = s;
2452
+ const identity = this.identity;
2453
+ const index = identity.chunkIndex;
2454
+ identity.chunkIndex += 1;
2455
+ const state = {
2456
+ sessionId: identity.sessionId,
2457
+ sessionStartUnixMs: identity.sessionStartUnixMs,
2458
+ lastActivityUnixMs: nowUnixMs,
2459
+ nextChunkIndex: identity.chunkIndex
2460
+ };
2461
+ await this.safeSet(this.sessionKey, JSON.stringify(state));
2462
+ return index;
1802
2463
  }
1803
- return slc(o, 0, pre + shft(pos) + post);
1804
- };
1805
- var crct = /* @__PURE__ */ (function() {
1806
- var t = new Int32Array(256);
1807
- for (var i2 = 0; i2 < 256; ++i2) {
1808
- var c = i2, k = 9;
1809
- while (--k)
1810
- c = (c & 1 && -306674912) ^ c >>> 1;
1811
- t[i2] = c;
2464
+ getNextChunkIndex() {
2465
+ return this.identity?.chunkIndex ?? null;
1812
2466
  }
1813
- return t;
1814
- })();
1815
- var crc = function() {
1816
- var c = -1;
1817
- return {
1818
- p: function(d) {
1819
- var cr = c;
1820
- for (var i2 = 0; i2 < d.length; ++i2)
1821
- cr = crct[cr & 255 ^ d[i2]] ^ cr >>> 8;
1822
- c = cr;
1823
- },
1824
- d: function() {
1825
- return ~c;
1826
- }
1827
- };
1828
- };
1829
- var dopt = function(dat, opt, pre, post, st) {
1830
- if (!st) {
1831
- st = { l: 1 };
1832
- if (opt.dictionary) {
1833
- var dict = opt.dictionary.subarray(-32768);
1834
- var newDat = new u8(dict.length + dat.length);
1835
- newDat.set(dict);
1836
- newDat.set(dat, dict.length);
1837
- dat = newDat;
1838
- st.w = dict.length;
2467
+ async rotate(nowUnixMs) {
2468
+ let visitorId = await this.safeGet(this.visitorKey);
2469
+ if (!isReplayId(visitorId)) {
2470
+ visitorId = generateReplayId();
2471
+ await this.safeSet(this.visitorKey, visitorId);
1839
2472
  }
2473
+ const session = {
2474
+ sessionId: generateReplayId(),
2475
+ sessionStartUnixMs: nowUnixMs,
2476
+ lastActivityUnixMs: nowUnixMs,
2477
+ nextChunkIndex: 0
2478
+ };
2479
+ await this.safeSet(this.sessionKey, JSON.stringify(session));
2480
+ this.identity = {
2481
+ sessionId: session.sessionId,
2482
+ tabId: generateReplayId(),
2483
+ visitorId,
2484
+ sessionStartUnixMs: nowUnixMs,
2485
+ chunkIndex: 0
2486
+ };
2487
+ return { ...this.identity };
1840
2488
  }
1841
- 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);
1842
- };
1843
- var wbytes = function(d, b, v) {
1844
- for (; v; ++b)
1845
- d[b] = v, v >>>= 8;
1846
- };
1847
- var gzh = function(c, o) {
1848
- var fn = o.filename;
1849
- c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3;
1850
- if (o.mtime != 0)
1851
- wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1e3));
1852
- if (fn) {
1853
- c[3] = 8;
1854
- for (var i2 = 0; i2 <= fn.length; ++i2)
1855
- c[i2 + 10] = fn.charCodeAt(i2);
2489
+ async clear() {
2490
+ this.identity = null;
2491
+ await Promise.all([
2492
+ this.safeRemove(this.sessionKey),
2493
+ this.safeRemove(this.visitorKey)
2494
+ ]);
1856
2495
  }
1857
- };
1858
- var gzhl = function(o) {
1859
- return 10 + (o.filename ? o.filename.length + 1 : 0);
1860
- };
1861
- function gzipSync(data, opts) {
1862
- if (!opts)
1863
- opts = {};
1864
- var c = crc(), l = data.length;
1865
- c.p(data);
1866
- var d = dopt(data, opts, gzhl(opts), 8), s = d.length;
1867
- return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d;
1868
- }
1869
- var te = typeof TextEncoder != "undefined" && /* @__PURE__ */ new TextEncoder();
1870
- var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
1871
- var tds = 0;
1872
- try {
1873
- td.decode(et, { stream: true });
1874
- tds = 1;
1875
- } catch (e) {
1876
- }
1877
- function strToU8(str, latin1) {
1878
- if (latin1) {
1879
- var ar_1 = new u8(str.length);
1880
- for (var i2 = 0; i2 < str.length; ++i2)
1881
- ar_1[i2] = str.charCodeAt(i2);
1882
- return ar_1;
2496
+ async safeGet(key) {
2497
+ try {
2498
+ return await this.storage.getItem(key);
2499
+ } catch {
2500
+ return null;
2501
+ }
1883
2502
  }
1884
- if (te)
1885
- return te.encode(str);
1886
- var l = str.length;
1887
- var ar = new u8(str.length + (str.length >> 1));
1888
- var ai = 0;
1889
- var w = function(v) {
1890
- ar[ai++] = v;
1891
- };
1892
- for (var i2 = 0; i2 < l; ++i2) {
1893
- if (ai + 5 > ar.length) {
1894
- var n = new u8(ai + 8 + (l - i2 << 1));
1895
- n.set(ar);
1896
- ar = n;
2503
+ async safeSet(key, value) {
2504
+ try {
2505
+ await this.storage.setItem(key, value);
2506
+ } catch {
1897
2507
  }
1898
- var c = str.charCodeAt(i2);
1899
- if (c < 128 || latin1)
1900
- w(c);
1901
- else if (c < 2048)
1902
- w(192 | c >> 6), w(128 | c & 63);
1903
- else if (c > 55295 && c < 57344)
1904
- 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);
1905
- else
1906
- w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63);
1907
2508
  }
1908
- return slc(ar, 0, ai);
1909
- }
2509
+ async safeRemove(key) {
2510
+ try {
2511
+ await this.storage.removeItem(key);
2512
+ } catch {
2513
+ }
2514
+ }
2515
+ };
1910
2516
 
1911
2517
  // src/Transport.ts
1912
2518
  var MAX_ATTEMPTS_PER_FRAME = 3;
1913
2519
  var DEFAULT_RETRY_MS = 15e3;
1914
2520
  var MAX_RETRY_MS = 5 * 6e4;
1915
2521
  var CHUNK_POST_TIMEOUT_MS = 1e4;
2522
+ var OFFLINE_RETRY_MS = [5e3, 15e3, 3e4, 6e4];
1916
2523
  var DIRECTIVE_REASON_PATTERN = /^[A-Za-z0-9_.:-]{1,100}$/u;
1917
- function encodeReplayFrame(originalEnvelope, payload) {
1918
- const compressed = gzipSync(strToU8(payload));
2524
+ function encodeCompressedReplayFrame(originalEnvelope, compressed) {
1919
2525
  const envelope = {
1920
2526
  ...originalEnvelope,
1921
2527
  payloadEncoding: "gzip",
1922
2528
  payloadBytes: compressed.byteLength,
1923
2529
  clientSendUnixMs: Date.now()
1924
2530
  };
1925
- const prefix = strToU8(`${JSON.stringify(envelope)}
1926
- `);
2531
+ const prefix = strToU8(encodeSessionReplayEnvelopeLine(envelope));
1927
2532
  const body = new Uint8Array(
1928
2533
  prefix.byteLength + compressed.byteLength
1929
2534
  );
@@ -1988,9 +2593,47 @@ var ReplayTransport = class {
1988
2593
  __publicField(this, "retryAfterDrainMs", null);
1989
2594
  __publicField(this, "activeAbortController", null);
1990
2595
  __publicField(this, "abortCurrentRequest", null);
2596
+ /* Requests in a row that never reached the server. */
2597
+ __publicField(this, "connectivityFailures", 0);
2598
+ /* What the host app's connectivity source last said, if it has one. */
2599
+ __publicField(this, "reportedOffline", false);
1991
2600
  this.options = options;
1992
2601
  this.fetch = options.startOptions.fetch;
1993
2602
  }
2603
+ /*
2604
+ * Offline, as far as uploading goes: the host app's connectivity source
2605
+ * says so, or the last request never reached the server.
2606
+ */
2607
+ isOffline() {
2608
+ return this.reportedOffline || this.connectivityFailures > 0;
2609
+ }
2610
+ /*
2611
+ * The host app's connectivity source changed (NetInfo, typically). While
2612
+ * it says offline nothing is attempted. Coming back does NOT drain on its
2613
+ * own: whether this recorder may upload right now (consent) is the
2614
+ * recorder's decision, so it calls resume() itself. null means "unknown",
2615
+ * which blocks nothing.
2616
+ */
2617
+ setConnectivity(isConnected) {
2618
+ this.reportedOffline = isConnected === false;
2619
+ }
2620
+ /*
2621
+ * Drain now rather than on the retry timer: the app came to the
2622
+ * foreground, or the network came back. An offline wait ends; a server
2623
+ * throttle still stands.
2624
+ */
2625
+ resume() {
2626
+ if (this.stopped || this.reportedOffline) {
2627
+ return;
2628
+ }
2629
+ if (this.connectivityFailures > 0 && this.retryTimer) {
2630
+ clearTimeout(this.retryTimer);
2631
+ this.retryTimer = null;
2632
+ }
2633
+ if (!this.retryTimer) {
2634
+ void this.drain();
2635
+ }
2636
+ }
1994
2637
  async enqueue(envelope, payload) {
1995
2638
  if (this.stopped) {
1996
2639
  return;
@@ -2007,13 +2650,15 @@ var ReplayTransport = class {
2007
2650
  dropped: mutation.dropped
2008
2651
  });
2009
2652
  }
2010
- await this.drain();
2653
+ if (!this.retryTimer) {
2654
+ await this.drain();
2655
+ }
2011
2656
  }
2012
2657
  async restore() {
2013
2658
  await this.drain();
2014
2659
  }
2015
2660
  async drain() {
2016
- if (this.stopped) {
2661
+ if (this.stopped || this.reportedOffline) {
2017
2662
  return;
2018
2663
  }
2019
2664
  if (this.drainPromise) {
@@ -2042,11 +2687,19 @@ var ReplayTransport = class {
2042
2687
  return this.flushFailures;
2043
2688
  }
2044
2689
  async drainLoop() {
2045
- const frames = await this.options.outbox.list();
2046
- for (const frame of frames) {
2047
- if (this.stopped) {
2690
+ const entries = await this.options.outbox.entries();
2691
+ for (const entry of entries) {
2692
+ if (this.stopped || this.reportedOffline) {
2048
2693
  return;
2049
2694
  }
2695
+ const frame = await this.options.outbox.load(entry.id);
2696
+ if (frame === "unreadable") {
2697
+ this.options.onDiagnostic("outbox-frame-unreadable");
2698
+ continue;
2699
+ }
2700
+ if (!frame) {
2701
+ continue;
2702
+ }
2050
2703
  const outcome = await this.post(frame);
2051
2704
  if (outcome === "remove") {
2052
2705
  await this.options.outbox.remove(frame.id);
@@ -2059,10 +2712,13 @@ var ReplayTransport = class {
2059
2712
  if (outcome === "stop") {
2060
2713
  return;
2061
2714
  }
2715
+ this.flushFailures += 1;
2716
+ if (outcome === "wait") {
2717
+ return;
2718
+ }
2062
2719
  const attempts = await this.options.outbox.incrementAttempts(
2063
2720
  frame.id
2064
2721
  );
2065
- this.flushFailures += 1;
2066
2722
  if (attempts >= MAX_ATTEMPTS_PER_FRAME) {
2067
2723
  await this.options.outbox.remove(frame.id);
2068
2724
  this.options.onDiagnostic("chunk-retry-exhausted", {
@@ -2077,9 +2733,9 @@ var ReplayTransport = class {
2077
2733
  }
2078
2734
  }
2079
2735
  async post(frame) {
2080
- const encoded = encodeReplayFrame(
2736
+ const encoded = encodeCompressedReplayFrame(
2081
2737
  frame.envelope,
2082
- frame.payload
2738
+ frame.compressedPayload
2083
2739
  );
2084
2740
  if (encoded.body.byteLength > MAX_SESSION_REPLAY_CHUNK_BYTES) {
2085
2741
  this.options.onDiagnostic("chunk-too-large", {
@@ -2138,7 +2794,9 @@ var ReplayTransport = class {
2138
2794
  chunkIndex: frame.envelope.chunkIndex
2139
2795
  }
2140
2796
  );
2141
- return "retry";
2797
+ this.connectivityFailures += 1;
2798
+ this.retryAfterDrainMs = OFFLINE_RETRY_MS[Math.min(this.connectivityFailures, OFFLINE_RETRY_MS.length) - 1];
2799
+ return "wait";
2142
2800
  } finally {
2143
2801
  if (timeout) {
2144
2802
  clearTimeout(timeout);
@@ -2150,6 +2808,10 @@ var ReplayTransport = class {
2150
2808
  this.abortCurrentRequest = null;
2151
2809
  }
2152
2810
  }
2811
+ if (this.connectivityFailures > 0) {
2812
+ this.connectivityFailures = 0;
2813
+ this.options.onDiagnostic("back-online");
2814
+ }
2153
2815
  if (said.directive) {
2154
2816
  this.options.onDirective(said.directive, said.reason);
2155
2817
  }
@@ -2191,6 +2853,9 @@ var ReplayTransport = class {
2191
2853
  (said.retryAfterSeconds ?? DEFAULT_RETRY_MS / 1e3) * 1e3
2192
2854
  );
2193
2855
  this.retryAfterDrainMs = retryMs;
2856
+ if (response.status === 429 || said.directive === "throttle" || said.retryAfterSeconds !== null) {
2857
+ return "wait";
2858
+ }
2194
2859
  return "retry";
2195
2860
  }
2196
2861
  scheduleRetry(delayMs) {
@@ -2374,6 +3039,21 @@ var MobileReplayRecorder = class {
2374
3039
  __publicField(this, "captureTimer", null);
2375
3040
  __publicField(this, "flushTimer", null);
2376
3041
  __publicField(this, "appStateSubscription", null);
3042
+ /*
3043
+ * Offline mode: the host app's connectivity source (start option
3044
+ * `connectivity`), and what it last said, which a transport created later
3045
+ * - after a consent or identity change - starts from.
3046
+ */
3047
+ __publicField(this, "unsubscribeConnectivity", null);
3048
+ __publicField(this, "lastConnectivity", null);
3049
+ /*
3050
+ * The policy in force is the cached one an offline launch started with,
3051
+ * or the last refresh could not reach the server. Refreshed the moment the
3052
+ * connection is back rather than on the five-minute schedule, so a policy
3053
+ * changed while the device was offline takes effect before its backlog
3054
+ * has finished uploading.
3055
+ */
3056
+ __publicField(this, "policyStale", false);
2377
3057
  __publicField(this, "captureGeneration", null);
2378
3058
  __publicField(this, "running", false);
2379
3059
  __publicField(this, "foreground", true);
@@ -2510,11 +3190,32 @@ var MobileReplayRecorder = class {
2510
3190
  });
2511
3191
  return false;
2512
3192
  }
3193
+ const namespace = getReplayStorageNamespace(validated);
2513
3194
  let config = await fetchReplayConfig(this.options);
2514
3195
  if (!this.isCurrentGeneration(generation)) {
2515
3196
  return false;
2516
3197
  }
2517
- if (config.enabled && this.userRef && (config.consentMode === "NotRequired" /* NotRequired */ || this.consentGranted)) {
3198
+ let configFromCache = false;
3199
+ if (isRetryablePolicyFailure(config)) {
3200
+ const cached = await loadCachedReplayConfig(
3201
+ this.storage,
3202
+ namespace,
3203
+ this.now()
3204
+ );
3205
+ if (!this.isCurrentGeneration(generation)) {
3206
+ return false;
3207
+ }
3208
+ if (cached) {
3209
+ this.diagnostic("config-from-cache", {
3210
+ reason: config.disabledReason ?? "not-reported"
3211
+ });
3212
+ config = cached;
3213
+ configFromCache = true;
3214
+ }
3215
+ } else if (this.mayPersistUnder(config)) {
3216
+ await saveReplayConfig(this.storage, namespace, config, this.now());
3217
+ }
3218
+ if (!configFromCache && config.enabled && this.userRef && (config.consentMode === "NotRequired" /* NotRequired */ || this.consentGranted)) {
2518
3219
  config = await this.refreshTargetingConfig(config);
2519
3220
  if (!this.isCurrentGeneration(generation)) {
2520
3221
  return false;
@@ -2527,8 +3228,8 @@ var MobileReplayRecorder = class {
2527
3228
  });
2528
3229
  return false;
2529
3230
  }
2530
- this.lastPolicyRefreshAtUnixMs = this.now();
2531
- const namespace = getReplayStorageNamespace(validated);
3231
+ this.lastPolicyRefreshAtUnixMs = configFromCache ? 0 : this.now();
3232
+ this.policyStale = configFromCache;
2532
3233
  const sessionStore = new ReplaySessionStore(
2533
3234
  this.storage,
2534
3235
  namespace
@@ -2557,8 +3258,9 @@ var MobileReplayRecorder = class {
2557
3258
  this.disable("not-sampled");
2558
3259
  return false;
2559
3260
  }
2560
- this.outbox = new ReplayOutbox(this.storage, namespace);
3261
+ this.outbox = new ReplayOutbox(this.storage, namespace, this.now);
2561
3262
  this.transport = this.createTransport(validated, this.outbox);
3263
+ this.subscribeConnectivity(validated);
2562
3264
  try {
2563
3265
  const nativeMetadata = await this.nativeViewTree.getAppMetadata();
2564
3266
  if (!this.isCurrentGeneration(generation)) {
@@ -2708,6 +3410,7 @@ var MobileReplayRecorder = class {
2708
3410
  });
2709
3411
  await this.outbox?.clear();
2710
3412
  await this.sessionStore?.clear();
3413
+ await this.forgetCachedConfig();
2711
3414
  this.identity = null;
2712
3415
  this.userRef = null;
2713
3416
  this.traits = {};
@@ -3321,6 +4024,9 @@ var MobileReplayRecorder = class {
3321
4024
  this.startTimers();
3322
4025
  this.diagnosticsStatus = this.consentState() === "Unknown" ? "consent-required" : "recording";
3323
4026
  await this.captureTick(true);
4027
+ if (this.uploadActive && this.running) {
4028
+ this.transport?.resume();
4029
+ }
3324
4030
  }
3325
4031
  }
3326
4032
  startTimers() {
@@ -3382,7 +4088,7 @@ var MobileReplayRecorder = class {
3382
4088
  this.installedGlobalErrorHandler = null;
3383
4089
  }
3384
4090
  createTransport(startOptions, outbox) {
3385
- return new ReplayTransport({
4091
+ const transport = new ReplayTransport({
3386
4092
  startOptions,
3387
4093
  outbox,
3388
4094
  onDirective: (directive, reason) => {
@@ -3390,8 +4096,15 @@ var MobileReplayRecorder = class {
3390
4096
  },
3391
4097
  onDiagnostic: (code, details) => {
3392
4098
  this.diagnostic(code, details);
4099
+ if (code === "back-online") {
4100
+ this.onBackOnline();
4101
+ }
3393
4102
  }
3394
4103
  });
4104
+ if (this.lastConnectivity !== null) {
4105
+ transport.setConnectivity(this.lastConnectivity);
4106
+ }
4107
+ return transport;
3395
4108
  }
3396
4109
  onDirective(directive, reason) {
3397
4110
  this.diagnostic("server-directive", { directive, reason });
@@ -3430,8 +4143,76 @@ var MobileReplayRecorder = class {
3430
4143
  this.clearTimers();
3431
4144
  this.appStateSubscription?.remove();
3432
4145
  this.appStateSubscription = null;
4146
+ this.stopConnectivity();
3433
4147
  this.restoreGlobalErrorHandler();
3434
4148
  }
4149
+ /*
4150
+ * Whether this device may be written to under a policy. Nothing is stored
4151
+ * before an explicit consent the policy requires - the cached policy
4152
+ * included, even though it holds no user data - except a removal: a
4153
+ * policy that says replay is off always deletes the cached one.
4154
+ */
4155
+ /*
4156
+ * The cached policy goes with everything else when consent does: it holds
4157
+ * no user data, but "nothing of the recorder stays on the device" is the
4158
+ * promise, and the next consented policy fetch writes it again.
4159
+ */
4160
+ async forgetCachedConfig() {
4161
+ if (this.options) {
4162
+ await forgetReplayConfig(
4163
+ this.storage,
4164
+ getReplayStorageNamespace(this.options)
4165
+ );
4166
+ }
4167
+ }
4168
+ mayPersistUnder(config) {
4169
+ return !config.enabled || config.consentMode === "NotRequired" /* NotRequired */ || this.consentGranted;
4170
+ }
4171
+ subscribeConnectivity(options) {
4172
+ this.stopConnectivity();
4173
+ this.lastConnectivity = null;
4174
+ if (!options.connectivity) {
4175
+ return;
4176
+ }
4177
+ try {
4178
+ const unsubscribe = options.connectivity.subscribe(
4179
+ (isConnected) => {
4180
+ const connected = typeof isConnected === "boolean" ? isConnected : null;
4181
+ if (connected === this.lastConnectivity) {
4182
+ return;
4183
+ }
4184
+ this.lastConnectivity = connected;
4185
+ if (connected !== null) {
4186
+ this.diagnostic(connected ? "network-online" : "network-offline");
4187
+ }
4188
+ this.transport?.setConnectivity(connected);
4189
+ if (connected === true) {
4190
+ this.onBackOnline();
4191
+ if (this.uploadActive && this.running) {
4192
+ this.transport?.resume();
4193
+ }
4194
+ }
4195
+ }
4196
+ );
4197
+ this.unsubscribeConnectivity = typeof unsubscribe === "function" ? unsubscribe : null;
4198
+ } catch {
4199
+ this.diagnostic("connectivity-subscribe-failed");
4200
+ }
4201
+ }
4202
+ /* The next capture tick refreshes a stale policy (see policyStale). */
4203
+ onBackOnline() {
4204
+ if (this.policyStale) {
4205
+ this.lastPolicyRefreshAtUnixMs = 0;
4206
+ }
4207
+ }
4208
+ stopConnectivity() {
4209
+ const unsubscribe = this.unsubscribeConnectivity;
4210
+ this.unsubscribeConnectivity = null;
4211
+ try {
4212
+ unsubscribe?.();
4213
+ } catch {
4214
+ }
4215
+ }
3435
4216
  isCurrentGeneration(generation) {
3436
4217
  return generation === this.lifecycleGeneration;
3437
4218
  }
@@ -3662,11 +4443,23 @@ var MobileReplayRecorder = class {
3662
4443
  }
3663
4444
  }
3664
4445
  this.lastPolicyRefreshAtUnixMs = nowUnixMs;
4446
+ if (!isRetryablePolicyFailure(freshConfig) && this.mayPersistUnder(freshConfig)) {
4447
+ await saveReplayConfig(
4448
+ this.storage,
4449
+ getReplayStorageNamespace(currentOptions),
4450
+ freshConfig,
4451
+ nowUnixMs
4452
+ );
4453
+ if (!this.running || !this.isCurrentGeneration(generation)) {
4454
+ return false;
4455
+ }
4456
+ }
3665
4457
  if (!freshConfig.enabled) {
3666
4458
  if (reason !== "consent" && isRetryablePolicyFailure(freshConfig)) {
3667
4459
  this.diagnostic("policy-refresh-failed-using-last-config", {
3668
4460
  reason
3669
4461
  });
4462
+ this.policyStale = true;
3670
4463
  return true;
3671
4464
  }
3672
4465
  this.config = freshConfig;
@@ -3676,6 +4469,7 @@ var MobileReplayRecorder = class {
3676
4469
  );
3677
4470
  return false;
3678
4471
  }
4472
+ this.policyStale = false;
3679
4473
  return await this.applyRuntimePolicy(
3680
4474
  previousConfig,
3681
4475
  freshConfig,
@@ -3722,6 +4516,7 @@ var MobileReplayRecorder = class {
3722
4516
  });
3723
4517
  await this.outbox?.clear();
3724
4518
  await this.sessionStore?.clear();
4519
+ await this.forgetCachedConfig();
3725
4520
  if (!this.running || !this.isCurrentGeneration(generation)) {
3726
4521
  return false;
3727
4522
  }