@mushi-mushi/core 1.27.1 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/index.cjs +282 -77
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +122 -1
- package/dist/index.d.ts +122 -1
- package/dist/index.js +269 -78
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -84,7 +84,92 @@ async function hmacSha256Hex(secret, value) {
|
|
|
84
84
|
return bytesToHex(result);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// src/unload-transport.ts
|
|
88
|
+
var MUSHI_BEACON_MAX_BYTES = 60 * 1024;
|
|
89
|
+
function isMushiBeaconEnvelope(value) {
|
|
90
|
+
if (!value || typeof value !== "object") return false;
|
|
91
|
+
const rec = value;
|
|
92
|
+
return rec.mushiBeacon === true && typeof rec.path === "string" && rec.headers !== null && typeof rec.headers === "object";
|
|
93
|
+
}
|
|
94
|
+
function buildBeaconEnvelope(opts) {
|
|
95
|
+
return {
|
|
96
|
+
mushiBeacon: true,
|
|
97
|
+
path: opts.path,
|
|
98
|
+
headers: opts.headers,
|
|
99
|
+
body: opts.body
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function isSameOriginOrRelative(url, origin = typeof location !== "undefined" ? location.origin : "") {
|
|
103
|
+
if (!url) return false;
|
|
104
|
+
if (url.startsWith("/")) return true;
|
|
105
|
+
if (!origin) return false;
|
|
106
|
+
try {
|
|
107
|
+
return new URL(url, origin).origin === origin;
|
|
108
|
+
} catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function extractTunnelPath(url) {
|
|
113
|
+
try {
|
|
114
|
+
const parsed = url.startsWith("/") ? new URL(url, "https://tunnel.local") : new URL(url);
|
|
115
|
+
return `${parsed.pathname}${parsed.search}`;
|
|
116
|
+
} catch {
|
|
117
|
+
return url;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function sendOnUnload(opts) {
|
|
121
|
+
const fetchImpl = opts.fetchImpl ?? (typeof fetch === "function" ? fetch : void 0);
|
|
122
|
+
if (fetchImpl) {
|
|
123
|
+
try {
|
|
124
|
+
void fetchImpl(opts.url, {
|
|
125
|
+
method: "POST",
|
|
126
|
+
headers: {
|
|
127
|
+
"Content-Type": "application/json",
|
|
128
|
+
...opts.headers
|
|
129
|
+
},
|
|
130
|
+
body: opts.body,
|
|
131
|
+
keepalive: true
|
|
132
|
+
});
|
|
133
|
+
return true;
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const beacon = opts.sendBeacon ?? (typeof navigator !== "undefined" ? navigator.sendBeacon?.bind(navigator) : void 0);
|
|
138
|
+
if (!beacon || !isSameOriginOrRelative(opts.url)) return false;
|
|
139
|
+
let parsedBody = opts.body;
|
|
140
|
+
try {
|
|
141
|
+
parsedBody = JSON.parse(opts.body);
|
|
142
|
+
} catch {
|
|
143
|
+
parsedBody = opts.body;
|
|
144
|
+
}
|
|
145
|
+
const envelope = JSON.stringify(
|
|
146
|
+
buildBeaconEnvelope({
|
|
147
|
+
path: opts.path ?? extractTunnelPath(opts.url),
|
|
148
|
+
headers: opts.headers,
|
|
149
|
+
body: parsedBody
|
|
150
|
+
})
|
|
151
|
+
);
|
|
152
|
+
if (envelope.length > MUSHI_BEACON_MAX_BYTES) return false;
|
|
153
|
+
try {
|
|
154
|
+
return beacon(opts.url, new Blob([envelope], { type: "application/json" }));
|
|
155
|
+
} catch {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
var pageUnloading = false;
|
|
160
|
+
function markPageUnloading() {
|
|
161
|
+
pageUnloading = true;
|
|
162
|
+
}
|
|
163
|
+
function isPageUnloading() {
|
|
164
|
+
return pageUnloading;
|
|
165
|
+
}
|
|
166
|
+
|
|
87
167
|
// src/api-client.ts
|
|
168
|
+
var lastOutbound = null;
|
|
169
|
+
function flushLastOutboundOnUnload() {
|
|
170
|
+
if (!lastOutbound) return false;
|
|
171
|
+
return sendOnUnload(lastOutbound);
|
|
172
|
+
}
|
|
88
173
|
var _credWarningEmitted = false;
|
|
89
174
|
var MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
|
|
90
175
|
var MUSHI_PROJECT_HEADER = "X-Mushi-Project";
|
|
@@ -105,15 +190,22 @@ function buildSdkIngestHeaders(opts) {
|
|
|
105
190
|
var DEFAULT_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api";
|
|
106
191
|
var MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
|
|
107
192
|
var MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
|
|
193
|
+
function resolveRequestBaseUrl(apiEndpoint, tunnel) {
|
|
194
|
+
const trimmedTunnel = tunnel?.trim();
|
|
195
|
+
if (trimmedTunnel) return trimmedTunnel.replace(/\/$/, "");
|
|
196
|
+
return (apiEndpoint ?? DEFAULT_API_ENDPOINT).replace(/\/$/, "");
|
|
197
|
+
}
|
|
108
198
|
var DEFAULT_TIMEOUT = 1e4;
|
|
109
199
|
var DEFAULT_MAX_RETRIES = 2;
|
|
110
200
|
var DEFAULT_CIRCUIT_THRESHOLD = 4;
|
|
111
201
|
var DEFAULT_CIRCUIT_COOLDOWN_MS = 3e4;
|
|
202
|
+
var MAX_INLINE_RETRY_WAIT_MS = 1e4;
|
|
112
203
|
function createApiClient(options) {
|
|
113
204
|
const {
|
|
114
205
|
projectId,
|
|
115
206
|
apiKey,
|
|
116
207
|
apiEndpoint = DEFAULT_API_ENDPOINT,
|
|
208
|
+
tunnel,
|
|
117
209
|
timeout = DEFAULT_TIMEOUT,
|
|
118
210
|
maxRetries = DEFAULT_MAX_RETRIES,
|
|
119
211
|
getUserToken,
|
|
@@ -121,7 +213,7 @@ function createApiClient(options) {
|
|
|
121
213
|
sdkVersion,
|
|
122
214
|
circuitBreaker
|
|
123
215
|
} = options;
|
|
124
|
-
let baseUrl = apiEndpoint
|
|
216
|
+
let baseUrl = resolveRequestBaseUrl(apiEndpoint, tunnel);
|
|
125
217
|
const cbEnabled = circuitBreaker?.enabled !== false;
|
|
126
218
|
const cbThreshold = Math.max(1, circuitBreaker?.threshold ?? DEFAULT_CIRCUIT_THRESHOLD);
|
|
127
219
|
const cbCooldownMs = Math.max(1e3, circuitBreaker?.cooldownMs ?? DEFAULT_CIRCUIT_COOLDOWN_MS);
|
|
@@ -145,21 +237,27 @@ function createApiClient(options) {
|
|
|
145
237
|
const controller = new AbortController();
|
|
146
238
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
147
239
|
const userToken = getUserToken?.() ?? null;
|
|
240
|
+
const headers = {
|
|
241
|
+
...buildSdkIngestHeaders({
|
|
242
|
+
apiKey,
|
|
243
|
+
projectId,
|
|
244
|
+
sdkPackage,
|
|
245
|
+
sdkVersion,
|
|
246
|
+
userToken,
|
|
247
|
+
internalKind
|
|
248
|
+
}),
|
|
249
|
+
...extraHeaders
|
|
250
|
+
};
|
|
251
|
+
const serialized = body ? JSON.stringify(body) : void 0;
|
|
252
|
+
if (serialized && method !== "GET") {
|
|
253
|
+
lastOutbound = { url, headers, body: serialized, path };
|
|
254
|
+
}
|
|
148
255
|
try {
|
|
149
256
|
const response = await fetch(url, {
|
|
150
257
|
method,
|
|
151
|
-
headers
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
projectId,
|
|
155
|
-
sdkPackage,
|
|
156
|
-
sdkVersion,
|
|
157
|
-
userToken,
|
|
158
|
-
internalKind
|
|
159
|
-
}),
|
|
160
|
-
...extraHeaders
|
|
161
|
-
},
|
|
162
|
-
body: body ? JSON.stringify(body) : void 0,
|
|
258
|
+
headers,
|
|
259
|
+
body: serialized,
|
|
260
|
+
keepalive: isPageUnloading(),
|
|
163
261
|
signal: controller.signal,
|
|
164
262
|
...internalKind ? { [MUSHI_INTERNAL_INIT_MARKER]: internalKind } : {}
|
|
165
263
|
});
|
|
@@ -183,11 +281,15 @@ function createApiClient(options) {
|
|
|
183
281
|
`[Mushi] Credentials rejected (HTTP ${response.status}). Check your Project ID and API key scope (must be "report:write"). ` + where
|
|
184
282
|
);
|
|
185
283
|
}
|
|
186
|
-
|
|
187
|
-
|
|
284
|
+
const rateLimited = response.status === 429;
|
|
285
|
+
const unusable = response.status >= 500 || rateLimited;
|
|
286
|
+
const retryAfterMs = rateLimited ? parseRetryAfter(response.headers.get("Retry-After")) : null;
|
|
287
|
+
const canWaitInline = retryAfterMs === null || retryAfterMs <= MAX_INLINE_RETRY_WAIT_MS;
|
|
288
|
+
if (unusable && retries > 0 && canWaitInline) {
|
|
289
|
+
await sleep(retryAfterMs ?? getBackoffDelay(maxRetries - retries));
|
|
188
290
|
return request(method, path, body, retries - 1, internalKind, extraHeaders);
|
|
189
291
|
}
|
|
190
|
-
if (
|
|
292
|
+
if (unusable) cbRecordUnreachable();
|
|
191
293
|
else cbRecordReachable();
|
|
192
294
|
return {
|
|
193
295
|
ok: false,
|
|
@@ -205,7 +307,7 @@ function createApiClient(options) {
|
|
|
205
307
|
clearTimeout(timer);
|
|
206
308
|
if (retries > 0 && isRetryable(error)) {
|
|
207
309
|
await sleep(getBackoffDelay(maxRetries - retries));
|
|
208
|
-
return request(method, path, body, retries - 1, internalKind);
|
|
310
|
+
return request(method, path, body, retries - 1, internalKind, extraHeaders);
|
|
209
311
|
}
|
|
210
312
|
cbRecordUnreachable();
|
|
211
313
|
return {
|
|
@@ -236,6 +338,7 @@ function createApiClient(options) {
|
|
|
236
338
|
"X-Reporter-Hmac": hmac
|
|
237
339
|
},
|
|
238
340
|
body: body ? JSON.stringify(body) : void 0,
|
|
341
|
+
keepalive: isPageUnloading(),
|
|
239
342
|
[MUSHI_INTERNAL_INIT_MARKER]: "reporter-poll"
|
|
240
343
|
});
|
|
241
344
|
if (!response.ok) {
|
|
@@ -495,12 +598,48 @@ function sleep(ms) {
|
|
|
495
598
|
function getBackoffDelay(attempt) {
|
|
496
599
|
return Math.min(1e3 * 2 ** attempt + Math.random() * 500, 1e4);
|
|
497
600
|
}
|
|
601
|
+
function parseRetryAfter(value, now2 = Date.now()) {
|
|
602
|
+
if (!value) return null;
|
|
603
|
+
const raw = value.trim();
|
|
604
|
+
if (!raw) return null;
|
|
605
|
+
const seconds = Number(raw);
|
|
606
|
+
if (Number.isFinite(seconds)) return seconds < 0 ? null : seconds * 1e3;
|
|
607
|
+
const at = Date.parse(raw);
|
|
608
|
+
if (Number.isNaN(at)) return null;
|
|
609
|
+
return Math.max(at - now2, 0);
|
|
610
|
+
}
|
|
498
611
|
function isRetryable(error) {
|
|
499
612
|
if (error instanceof DOMException && error.name === "AbortError") return true;
|
|
500
613
|
if (error instanceof TypeError) return true;
|
|
501
614
|
return false;
|
|
502
615
|
}
|
|
503
616
|
|
|
617
|
+
// src/error-filters.ts
|
|
618
|
+
function matchesErrorFilter(value, filters) {
|
|
619
|
+
if (!value || !filters || filters.length === 0) return false;
|
|
620
|
+
for (const filter of filters) {
|
|
621
|
+
if (typeof filter === "string") {
|
|
622
|
+
if (value.includes(filter)) return true;
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
try {
|
|
626
|
+
if (filter.test(value)) return true;
|
|
627
|
+
} catch {
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
function shouldDropCapturedError(input) {
|
|
633
|
+
if (matchesErrorFilter(input.message, input.ignoreErrors)) return true;
|
|
634
|
+
const filename = input.filename?.trim() || "";
|
|
635
|
+
if (filename && matchesErrorFilter(filename, input.denyUrls)) return true;
|
|
636
|
+
if (input.allowUrls && input.allowUrls.length > 0) {
|
|
637
|
+
if (!filename) return true;
|
|
638
|
+
if (!matchesErrorFilter(filename, input.allowUrls)) return true;
|
|
639
|
+
}
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
|
|
504
643
|
// src/region.ts
|
|
505
644
|
var REGION_ENDPOINTS = {
|
|
506
645
|
us: DEFAULT_API_ENDPOINT,
|
|
@@ -679,6 +818,7 @@ var KNOWN_CONFIG_KEYS = [
|
|
|
679
818
|
"projectId",
|
|
680
819
|
"apiKey",
|
|
681
820
|
"apiEndpoint",
|
|
821
|
+
"tunnel",
|
|
682
822
|
"timeout",
|
|
683
823
|
"maxRetries",
|
|
684
824
|
"circuitBreaker",
|
|
@@ -698,8 +838,13 @@ var KNOWN_CONFIG_KEYS = [
|
|
|
698
838
|
"enabled",
|
|
699
839
|
"appVersion",
|
|
700
840
|
"sampleRate",
|
|
841
|
+
"replaySampleRate",
|
|
842
|
+
"replaysOnErrorSampleRate",
|
|
701
843
|
"beforeSend",
|
|
702
844
|
"beforeSendFeedback",
|
|
845
|
+
"ignoreErrors",
|
|
846
|
+
"denyUrls",
|
|
847
|
+
"allowUrls",
|
|
703
848
|
"onCrashedLastRun"
|
|
704
849
|
];
|
|
705
850
|
function presetDefaults(preset) {
|
|
@@ -1164,6 +1309,8 @@ function createOfflineQueue(config = {}) {
|
|
|
1164
1309
|
let syncCleanup = null;
|
|
1165
1310
|
let flushInterval = null;
|
|
1166
1311
|
let backendType = null;
|
|
1312
|
+
let inFlight = null;
|
|
1313
|
+
let followUp = null;
|
|
1167
1314
|
async function wrapForStorage(report) {
|
|
1168
1315
|
const queuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1169
1316
|
if (!encryptAtRest) {
|
|
@@ -1316,7 +1463,10 @@ function createOfflineQueue(config = {}) {
|
|
|
1316
1463
|
}
|
|
1317
1464
|
async function lsEnqueue(report) {
|
|
1318
1465
|
const rows = lsRead();
|
|
1319
|
-
|
|
1466
|
+
const row = await wrapForStorage(report);
|
|
1467
|
+
const idx = rows.findIndex((r) => r.id === report.id);
|
|
1468
|
+
if (idx >= 0) rows[idx] = row;
|
|
1469
|
+
else rows.push(row);
|
|
1320
1470
|
lsWrite(rows);
|
|
1321
1471
|
}
|
|
1322
1472
|
function lsDelete(id) {
|
|
@@ -1355,26 +1505,43 @@ function createOfflineQueue(config = {}) {
|
|
|
1355
1505
|
return false;
|
|
1356
1506
|
}
|
|
1357
1507
|
}
|
|
1358
|
-
async function
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
if (
|
|
1362
|
-
|
|
1363
|
-
|
|
1508
|
+
async function readRows() {
|
|
1509
|
+
const backend = detectBackend();
|
|
1510
|
+
if (backend === "none") return { backend, rows: [] };
|
|
1511
|
+
if (backend === "indexeddb") {
|
|
1512
|
+
try {
|
|
1513
|
+
return { backend, rows: await idbGetAll() };
|
|
1514
|
+
} catch {
|
|
1515
|
+
backendType = "localstorage";
|
|
1516
|
+
}
|
|
1364
1517
|
}
|
|
1518
|
+
return { backend: "localstorage", rows: lsRead() };
|
|
1519
|
+
}
|
|
1520
|
+
async function writeRow(report) {
|
|
1365
1521
|
const backend = detectBackend();
|
|
1522
|
+
if (backend === "none") {
|
|
1523
|
+
queueLog.debug("Offline queue: no storage backend, dropping report", { id: report.id });
|
|
1524
|
+
return backend;
|
|
1525
|
+
}
|
|
1366
1526
|
if (backend === "indexeddb") {
|
|
1367
1527
|
try {
|
|
1368
1528
|
await idbEnqueue(report);
|
|
1369
|
-
return;
|
|
1529
|
+
return backend;
|
|
1370
1530
|
} catch {
|
|
1371
1531
|
backendType = "localstorage";
|
|
1372
1532
|
}
|
|
1373
1533
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1534
|
+
await lsEnqueue(report);
|
|
1535
|
+
return "localstorage";
|
|
1536
|
+
}
|
|
1537
|
+
async function enqueue(report) {
|
|
1538
|
+
if (!enabled) return;
|
|
1539
|
+
const currentSize = await size();
|
|
1540
|
+
if (currentSize >= maxQueueSize) {
|
|
1541
|
+
queueLog.warn("Offline queue full \u2014 dropping report", { maxQueueSize });
|
|
1376
1542
|
return;
|
|
1377
1543
|
}
|
|
1544
|
+
await writeRow(report);
|
|
1378
1545
|
}
|
|
1379
1546
|
function getBackoffDelay2(attempt) {
|
|
1380
1547
|
return Math.min(1e3 * 2 ** attempt + Math.random() * 500, MAX_BACKOFF_MS);
|
|
@@ -1382,19 +1549,9 @@ function createOfflineQueue(config = {}) {
|
|
|
1382
1549
|
function sleep2(ms) {
|
|
1383
1550
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1384
1551
|
}
|
|
1385
|
-
async function
|
|
1386
|
-
|
|
1387
|
-
let rows;
|
|
1388
|
-
const backend = detectBackend();
|
|
1389
|
-
if (backend === "indexeddb") {
|
|
1390
|
-
try {
|
|
1391
|
-
rows = await idbGetAll();
|
|
1392
|
-
} catch {
|
|
1393
|
-
rows = lsRead();
|
|
1394
|
-
}
|
|
1395
|
-
} else {
|
|
1396
|
-
rows = lsRead();
|
|
1397
|
-
}
|
|
1552
|
+
async function runFlush(client) {
|
|
1553
|
+
const { backend, rows: storedRows } = await readRows();
|
|
1554
|
+
let rows = storedRows;
|
|
1398
1555
|
const now2 = Date.now();
|
|
1399
1556
|
const fresh = [];
|
|
1400
1557
|
for (const row of rows) {
|
|
@@ -1423,59 +1580,84 @@ function createOfflineQueue(config = {}) {
|
|
|
1423
1580
|
if (result.ok) {
|
|
1424
1581
|
await removeRow(backend, rowId);
|
|
1425
1582
|
sent++;
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
failed++;
|
|
1586
|
+
if (result.error?.code === "CIRCUIT_OPEN") {
|
|
1587
|
+
queueLog.debug("Offline queue: circuit open, deferring the rest of the batch", {
|
|
1588
|
+
id: rowId,
|
|
1589
|
+
remaining: batch.length - i
|
|
1590
|
+
});
|
|
1591
|
+
break;
|
|
1592
|
+
}
|
|
1593
|
+
const permanent = result.error?.code === "HTTP_400" || result.error?.code === "HTTP_413" || result.error?.code === "HTTP_422" || result.error?.code === "INGEST_ERROR" || result.error?.code === "VALIDATION_ERROR" || // A payload that exceeds the size guard will never shrink on its own;
|
|
1594
|
+
// retrying re-serialises the multi-MB body every sync tick and wedges
|
|
1595
|
+
// the queue (it matches neither permanent nor transient otherwise).
|
|
1596
|
+
// SERIALIZE_FAILED (circular ref) is likewise unrecoverable on retry.
|
|
1597
|
+
result.error?.code === "PAYLOAD_TOO_LARGE" || result.error?.code === "SERIALIZE_FAILED" || typeof result.error?.message === "string" && /invalid payload|description must be at least|validation/i.test(
|
|
1598
|
+
result.error.message
|
|
1599
|
+
);
|
|
1600
|
+
const transient = !permanent && (result.error?.code === "NETWORK_ERROR" || result.error?.code === "HTTP_403" || result.error?.code === "HTTP_429" || result.error?.code === "HTTP_502" || result.error?.code === "HTTP_503" || result.error?.code === "HTTP_504" || typeof result.error?.code === "string" && result.error.code.startsWith("HTTP_5"));
|
|
1601
|
+
if (permanent) {
|
|
1602
|
+
await removeRow(backend, rowId);
|
|
1426
1603
|
} else {
|
|
1427
|
-
const
|
|
1428
|
-
|
|
1429
|
-
// the queue (it matches neither permanent nor transient otherwise).
|
|
1430
|
-
// SERIALIZE_FAILED (circular ref) is likewise unrecoverable on retry.
|
|
1431
|
-
result.error?.code === "PAYLOAD_TOO_LARGE" || result.error?.code === "SERIALIZE_FAILED" || typeof result.error?.message === "string" && /invalid payload|description must be at least|validation/i.test(
|
|
1432
|
-
result.error.message
|
|
1433
|
-
);
|
|
1434
|
-
const transient = !permanent && (result.error?.code === "NETWORK_ERROR" || result.error?.code === "HTTP_403" || result.error?.code === "HTTP_429" || result.error?.code === "HTTP_502" || result.error?.code === "HTTP_503" || result.error?.code === "HTTP_504" || typeof result.error?.code === "string" && result.error.code.startsWith("HTTP_5"));
|
|
1435
|
-
if (permanent) {
|
|
1604
|
+
const nextAttempts = rowAttempts(row) + 1;
|
|
1605
|
+
if (nextAttempts >= MAX_DELIVERY_ATTEMPTS) {
|
|
1436
1606
|
await removeRow(backend, rowId);
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1607
|
+
queueLog.warn("Offline queue: giving up on report after repeated failures", {
|
|
1608
|
+
id: rowId,
|
|
1609
|
+
attempts: nextAttempts,
|
|
1610
|
+
code: result.error?.code
|
|
1611
|
+
});
|
|
1612
|
+
} else {
|
|
1613
|
+
row.attempts = nextAttempts;
|
|
1614
|
+
const persisted = await persistRow(backend, row);
|
|
1615
|
+
if (persisted) {
|
|
1616
|
+
queueLog.debug("Offline queue: delivery failed, will retry", {
|
|
1442
1617
|
id: rowId,
|
|
1443
1618
|
attempts: nextAttempts,
|
|
1444
|
-
code: result.error?.code
|
|
1619
|
+
code: result.error?.code,
|
|
1620
|
+
classified: transient ? "transient" : "unclassified"
|
|
1445
1621
|
});
|
|
1446
1622
|
} else {
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
attempts: nextAttempts,
|
|
1453
|
-
code: result.error?.code
|
|
1454
|
-
});
|
|
1455
|
-
} else {
|
|
1456
|
-
await removeRow(backend, rowId);
|
|
1457
|
-
queueLog.warn("Offline queue: dropping report (attempt counter unpersistable)", {
|
|
1458
|
-
id: rowId,
|
|
1459
|
-
code: result.error?.code
|
|
1460
|
-
});
|
|
1461
|
-
}
|
|
1623
|
+
await removeRow(backend, rowId);
|
|
1624
|
+
queueLog.warn("Offline queue: dropping report (attempt counter unpersistable)", {
|
|
1625
|
+
id: rowId,
|
|
1626
|
+
code: result.error?.code
|
|
1627
|
+
});
|
|
1462
1628
|
}
|
|
1463
1629
|
}
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
}
|
|
1630
|
+
}
|
|
1631
|
+
if (i < batch.length - 1) {
|
|
1632
|
+
await sleep2(getBackoffDelay2(i));
|
|
1468
1633
|
}
|
|
1469
1634
|
}
|
|
1470
1635
|
return { sent, failed };
|
|
1471
1636
|
}
|
|
1637
|
+
function flush(client) {
|
|
1638
|
+
if (!enabled) return Promise.resolve({ sent: 0, failed: 0 });
|
|
1639
|
+
if (inFlight) {
|
|
1640
|
+
if (!followUp) {
|
|
1641
|
+
followUp = inFlight.catch(() => void 0).then(() => {
|
|
1642
|
+
followUp = null;
|
|
1643
|
+
return flush(client);
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
return followUp;
|
|
1647
|
+
}
|
|
1648
|
+
const pass = runFlush(client).finally(() => {
|
|
1649
|
+
if (inFlight === pass) inFlight = null;
|
|
1650
|
+
});
|
|
1651
|
+
inFlight = pass;
|
|
1652
|
+
return pass;
|
|
1653
|
+
}
|
|
1472
1654
|
async function size() {
|
|
1473
1655
|
const backend = detectBackend();
|
|
1474
1656
|
if (backend === "indexeddb") {
|
|
1475
1657
|
try {
|
|
1476
1658
|
return await idbSize();
|
|
1477
1659
|
} catch {
|
|
1478
|
-
|
|
1660
|
+
backendType = "localstorage";
|
|
1479
1661
|
}
|
|
1480
1662
|
}
|
|
1481
1663
|
return lsRead().length;
|
|
@@ -2432,13 +2614,22 @@ var SLUG_DOMAIN_HINTS = {
|
|
|
2432
2614
|
"glot-it": "glot.it",
|
|
2433
2615
|
glotit: "glot.it",
|
|
2434
2616
|
"solo-boss-cloud": "solo-boss.kensaur.us",
|
|
2435
|
-
"mushi-mushi": "kensaur.us"
|
|
2617
|
+
"mushi-mushi": "kensaur.us",
|
|
2618
|
+
"how-to-talk-to-girls": "talk.kensaur.us",
|
|
2619
|
+
htttg: "talk.kensaur.us",
|
|
2620
|
+
tsumagoi: "tsumagoi.kensaur.us"
|
|
2436
2621
|
};
|
|
2437
2622
|
var SLUG_ICON_URL_HINTS = {
|
|
2438
2623
|
"mushi-mushi": "https://kensaur.us/mushi-mushi/admin/favicon.svg",
|
|
2439
2624
|
"solo-boss-cloud": "https://solo-boss.kensaur.us/favicon.svg",
|
|
2440
2625
|
"glot-it": "https://kensaur.us/glot-it/apple-touch-icon.png",
|
|
2441
|
-
glotit: "https://kensaur.us/glot-it/apple-touch-icon.png"
|
|
2626
|
+
glotit: "https://kensaur.us/glot-it/apple-touch-icon.png",
|
|
2627
|
+
"the-wanting-mind": "https://kensaur.us/the-wanting-mind/pwa-512x512.png",
|
|
2628
|
+
"how-to-talk-to-girls": "https://talk.kensaur.us/pwa-192.png",
|
|
2629
|
+
htttg: "https://talk.kensaur.us/pwa-192.png",
|
|
2630
|
+
tsumagoi: "https://tsumagoi.kensaur.us/apple-touch-icon.png",
|
|
2631
|
+
"help-her-take-photo": "https://kensaur.us/help-her-take-photo/assets/apple-touch-icon.png",
|
|
2632
|
+
"yen-yen": "https://kensaur.us/yen-yen/icon.svg"
|
|
2442
2633
|
};
|
|
2443
2634
|
var UNTRUSTED_FAVICON_HOSTS = [
|
|
2444
2635
|
"www.google.com",
|
|
@@ -2610,6 +2801,6 @@ function isSafeFaviconHref(href) {
|
|
|
2610
2801
|
}
|
|
2611
2802
|
}
|
|
2612
2803
|
|
|
2613
|
-
export { DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_BORDER, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_CONTROL_DISABLED, MUSHI_COPY, MUSHI_DURATION, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_LETTER_SPACING, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_OPACITY, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SHADOW_INK, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, REGION_ENDPOINTS, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroySessionTracker, diagnoseEnvConfig, estimateJsonBytes, expandPreset, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initSessionTracker, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, scrubUrl, sha256Hex, trackPageView, updateSessionIdentity, validateConfig };
|
|
2804
|
+
export { DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_BEACON_MAX_BYTES, MUSHI_BORDER, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_CONTROL_DISABLED, MUSHI_COPY, MUSHI_DURATION, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_LETTER_SPACING, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_OPACITY, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SHADOW_INK, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, REGION_ENDPOINTS, buildBeaconEnvelope, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroySessionTracker, diagnoseEnvConfig, estimateJsonBytes, expandPreset, extractTunnelPath, faviconUrlCandidates, flushLastOutboundOnUnload, formatBytes, getBackoffDelay, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initSessionTracker, isLikelyGenericFavicon, isMushiBeaconEnvelope, isPageUnloading, isSameOriginOrRelative, isUntrustedFaviconUrl, markPageUnloading, matchesErrorFilter, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, parseRetryAfter, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveRequestBaseUrl, resolveWidgetAccent, safeWidgetHex, scrubPii, scrubUrl, sendOnUnload, sha256Hex, shouldDropCapturedError, trackPageView, updateSessionIdentity, validateConfig };
|
|
2614
2805
|
//# sourceMappingURL=index.js.map
|
|
2615
2806
|
//# sourceMappingURL=index.js.map
|