@mushi-mushi/core 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CODE_OF_CONDUCT.md +51 -0
- package/CONTRIBUTING.md +122 -0
- package/SECURITY.md +50 -0
- package/dist/index.cjs +171 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -4
- package/dist/index.d.ts +69 -4
- package/dist/index.js +171 -22
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -348,6 +348,98 @@ var noopLogger = {
|
|
|
348
348
|
}
|
|
349
349
|
};
|
|
350
350
|
|
|
351
|
+
// src/queue-crypto.ts
|
|
352
|
+
var KEY_DB = "mushi-mushi-keyring";
|
|
353
|
+
var KEY_STORE = "keys";
|
|
354
|
+
var KEY_RECORD_ID = "offline-queue/v1";
|
|
355
|
+
var cachedKey = null;
|
|
356
|
+
var cachedKeyPromise = null;
|
|
357
|
+
function hasWebCrypto() {
|
|
358
|
+
return typeof globalThis !== "undefined" && typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.subtle !== "undefined" && typeof indexedDB !== "undefined";
|
|
359
|
+
}
|
|
360
|
+
function openKeyDb() {
|
|
361
|
+
return new Promise((resolve, reject) => {
|
|
362
|
+
const req = indexedDB.open(KEY_DB, 1);
|
|
363
|
+
req.onupgradeneeded = () => {
|
|
364
|
+
const db = req.result;
|
|
365
|
+
if (!db.objectStoreNames.contains(KEY_STORE)) {
|
|
366
|
+
db.createObjectStore(KEY_STORE);
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
req.onsuccess = () => resolve(req.result);
|
|
370
|
+
req.onerror = () => reject(req.error);
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
async function loadKey() {
|
|
374
|
+
const db = await openKeyDb();
|
|
375
|
+
return new Promise((resolve, reject) => {
|
|
376
|
+
const tx = db.transaction(KEY_STORE, "readonly");
|
|
377
|
+
const req = tx.objectStore(KEY_STORE).get(KEY_RECORD_ID);
|
|
378
|
+
req.onsuccess = () => resolve(req.result ?? null);
|
|
379
|
+
req.onerror = () => reject(req.error);
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
async function storeKey(key) {
|
|
383
|
+
const db = await openKeyDb();
|
|
384
|
+
return new Promise((resolve, reject) => {
|
|
385
|
+
const tx = db.transaction(KEY_STORE, "readwrite");
|
|
386
|
+
tx.objectStore(KEY_STORE).put(key, KEY_RECORD_ID);
|
|
387
|
+
tx.oncomplete = () => resolve();
|
|
388
|
+
tx.onerror = () => reject(tx.error);
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
async function getOfflineQueueKey() {
|
|
392
|
+
if (cachedKey) return cachedKey;
|
|
393
|
+
if (cachedKeyPromise) return cachedKeyPromise;
|
|
394
|
+
if (!hasWebCrypto()) {
|
|
395
|
+
throw new Error("Web Crypto + IndexedDB required for offline queue encryption");
|
|
396
|
+
}
|
|
397
|
+
cachedKeyPromise = (async () => {
|
|
398
|
+
const existing = await loadKey();
|
|
399
|
+
if (existing) {
|
|
400
|
+
cachedKey = existing;
|
|
401
|
+
return existing;
|
|
402
|
+
}
|
|
403
|
+
const key = await crypto.subtle.generateKey(
|
|
404
|
+
{ name: "AES-GCM", length: 256 },
|
|
405
|
+
false,
|
|
406
|
+
["encrypt", "decrypt"]
|
|
407
|
+
);
|
|
408
|
+
await storeKey(key);
|
|
409
|
+
cachedKey = key;
|
|
410
|
+
return key;
|
|
411
|
+
})();
|
|
412
|
+
return cachedKeyPromise;
|
|
413
|
+
}
|
|
414
|
+
function bytesToB64(bytes) {
|
|
415
|
+
let s = "";
|
|
416
|
+
for (const b of bytes) s += String.fromCharCode(b);
|
|
417
|
+
return btoa(s);
|
|
418
|
+
}
|
|
419
|
+
function b64ToBytes(s) {
|
|
420
|
+
const bin = atob(s);
|
|
421
|
+
const out = new Uint8Array(new ArrayBuffer(bin.length));
|
|
422
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
423
|
+
return out;
|
|
424
|
+
}
|
|
425
|
+
async function encryptJson(plain) {
|
|
426
|
+
const key = await getOfflineQueueKey();
|
|
427
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
428
|
+
const data = new TextEncoder().encode(JSON.stringify(plain));
|
|
429
|
+
const cipher = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, data));
|
|
430
|
+
return { _mme: 1, iv: bytesToB64(iv), ct: bytesToB64(cipher) };
|
|
431
|
+
}
|
|
432
|
+
function isEncryptedPayload(v) {
|
|
433
|
+
return !!v && typeof v === "object" && v._mme === 1 && typeof v.iv === "string" && typeof v.ct === "string";
|
|
434
|
+
}
|
|
435
|
+
async function decryptJson(payload) {
|
|
436
|
+
const key = await getOfflineQueueKey();
|
|
437
|
+
const iv = b64ToBytes(payload.iv);
|
|
438
|
+
const ct = b64ToBytes(payload.ct);
|
|
439
|
+
const plain = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ct);
|
|
440
|
+
return JSON.parse(new TextDecoder().decode(plain));
|
|
441
|
+
}
|
|
442
|
+
|
|
351
443
|
// src/queue.ts
|
|
352
444
|
var queueLog = createLogger({ scope: "mushi:queue", level: "warn" });
|
|
353
445
|
var DB_NAME = "mushi-mushi";
|
|
@@ -357,9 +449,36 @@ var LS_KEY = "mushi_offline_queue";
|
|
|
357
449
|
var BATCH_SIZE = 10;
|
|
358
450
|
var MAX_BACKOFF_MS = 6e4;
|
|
359
451
|
function createOfflineQueue(config = {}) {
|
|
360
|
-
const { enabled = true, maxQueueSize = 50, syncOnReconnect = true } = config;
|
|
452
|
+
const { enabled = true, maxQueueSize = 50, syncOnReconnect = true, encryptAtRest = true } = config;
|
|
361
453
|
let syncCleanup = null;
|
|
362
454
|
let backendType = null;
|
|
455
|
+
async function wrapForStorage(report) {
|
|
456
|
+
const queuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
457
|
+
if (!encryptAtRest) {
|
|
458
|
+
return { ...report, queuedAt };
|
|
459
|
+
}
|
|
460
|
+
try {
|
|
461
|
+
const payload = await encryptJson(report);
|
|
462
|
+
return { id: report.id, queuedAt, payload };
|
|
463
|
+
} catch (err) {
|
|
464
|
+
queueLog.warn("Offline queue: encryption failed, storing plaintext", { err: String(err) });
|
|
465
|
+
return { ...report, queuedAt };
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
async function unwrapForSend(row) {
|
|
469
|
+
if (isEncryptedRecord(row)) {
|
|
470
|
+
try {
|
|
471
|
+
return await decryptJson(row.payload);
|
|
472
|
+
} catch (err) {
|
|
473
|
+
queueLog.warn("Offline queue: decrypt failed, dropping row", { err: String(err), id: row.id });
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return row;
|
|
478
|
+
}
|
|
479
|
+
function isEncryptedRecord(row) {
|
|
480
|
+
return !!row.payload && isEncryptedPayload(row.payload);
|
|
481
|
+
}
|
|
363
482
|
function detectBackend() {
|
|
364
483
|
if (backendType) return backendType;
|
|
365
484
|
if (typeof indexedDB !== "undefined") {
|
|
@@ -389,9 +508,10 @@ function createOfflineQueue(config = {}) {
|
|
|
389
508
|
}
|
|
390
509
|
async function idbEnqueue(report) {
|
|
391
510
|
const db = await openDb();
|
|
511
|
+
const row = await wrapForStorage(report);
|
|
392
512
|
return new Promise((resolve, reject) => {
|
|
393
513
|
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
394
|
-
tx.objectStore(STORE_NAME).put(
|
|
514
|
+
tx.objectStore(STORE_NAME).put(row);
|
|
395
515
|
tx.oncomplete = () => resolve();
|
|
396
516
|
tx.onerror = () => reject(tx.error);
|
|
397
517
|
});
|
|
@@ -440,20 +560,20 @@ function createOfflineQueue(config = {}) {
|
|
|
440
560
|
return [];
|
|
441
561
|
}
|
|
442
562
|
}
|
|
443
|
-
function lsWrite(
|
|
563
|
+
function lsWrite(rows) {
|
|
444
564
|
try {
|
|
445
|
-
localStorage.setItem(LS_KEY, JSON.stringify(
|
|
565
|
+
localStorage.setItem(LS_KEY, JSON.stringify(rows));
|
|
446
566
|
} catch {
|
|
447
567
|
}
|
|
448
568
|
}
|
|
449
|
-
function lsEnqueue(report) {
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
lsWrite(
|
|
569
|
+
async function lsEnqueue(report) {
|
|
570
|
+
const rows = lsRead();
|
|
571
|
+
rows.push(await wrapForStorage(report));
|
|
572
|
+
lsWrite(rows);
|
|
453
573
|
}
|
|
454
574
|
function lsDelete(id) {
|
|
455
|
-
const
|
|
456
|
-
lsWrite(
|
|
575
|
+
const rows = lsRead().filter((r) => r.id !== id);
|
|
576
|
+
lsWrite(rows);
|
|
457
577
|
}
|
|
458
578
|
async function enqueue(report) {
|
|
459
579
|
if (!enabled) return;
|
|
@@ -472,7 +592,7 @@ function createOfflineQueue(config = {}) {
|
|
|
472
592
|
}
|
|
473
593
|
}
|
|
474
594
|
if (backend === "localstorage" || backendType === "localstorage") {
|
|
475
|
-
lsEnqueue(report);
|
|
595
|
+
await lsEnqueue(report);
|
|
476
596
|
return;
|
|
477
597
|
}
|
|
478
598
|
}
|
|
@@ -484,29 +604,41 @@ function createOfflineQueue(config = {}) {
|
|
|
484
604
|
}
|
|
485
605
|
async function flush(client) {
|
|
486
606
|
if (!enabled) return { sent: 0, failed: 0 };
|
|
487
|
-
let
|
|
607
|
+
let rows;
|
|
488
608
|
const backend = detectBackend();
|
|
489
609
|
if (backend === "indexeddb") {
|
|
490
610
|
try {
|
|
491
|
-
|
|
611
|
+
rows = await idbGetAll();
|
|
492
612
|
} catch {
|
|
493
|
-
|
|
613
|
+
rows = lsRead();
|
|
494
614
|
}
|
|
495
615
|
} else {
|
|
496
|
-
|
|
616
|
+
rows = lsRead();
|
|
497
617
|
}
|
|
498
|
-
const batch =
|
|
618
|
+
const batch = rows.slice(0, BATCH_SIZE);
|
|
499
619
|
let sent = 0;
|
|
500
620
|
let failed = 0;
|
|
501
621
|
for (let i = 0; i < batch.length; i++) {
|
|
502
|
-
const
|
|
622
|
+
const row = batch[i];
|
|
623
|
+
const rowId = row.id;
|
|
624
|
+
const report = await unwrapForSend(row);
|
|
625
|
+
if (!report) {
|
|
626
|
+
try {
|
|
627
|
+
if (backend === "indexeddb") await idbDelete(rowId);
|
|
628
|
+
else lsDelete(rowId);
|
|
629
|
+
} catch {
|
|
630
|
+
lsDelete(rowId);
|
|
631
|
+
}
|
|
632
|
+
failed++;
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
503
635
|
const result = await client.submitReport(report);
|
|
504
636
|
if (result.ok) {
|
|
505
637
|
try {
|
|
506
|
-
if (backend === "indexeddb") await idbDelete(
|
|
507
|
-
else lsDelete(
|
|
638
|
+
if (backend === "indexeddb") await idbDelete(rowId);
|
|
639
|
+
else lsDelete(rowId);
|
|
508
640
|
} catch {
|
|
509
|
-
lsDelete(
|
|
641
|
+
lsDelete(rowId);
|
|
510
642
|
}
|
|
511
643
|
sent++;
|
|
512
644
|
} else {
|
|
@@ -740,16 +872,33 @@ function createRateLimiter(config = {}) {
|
|
|
740
872
|
var ORDERED_PATTERNS = [
|
|
741
873
|
{ key: "ssns", regex: /\b\d{3}-\d{2}-\d{4}\b/g, replacement: "[REDACTED_SSN]" },
|
|
742
874
|
{ key: "creditCards", regex: /\b(?:\d[ -]*){12,18}\d\b/g, replacement: "[REDACTED_CC]" },
|
|
875
|
+
// Vendor secret tokens — mirrors packages/server/.../pii-scrubber.ts exactly.
|
|
876
|
+
{ key: "secretTokens", regex: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g, replacement: "[REDACTED_AWS_KEY]" },
|
|
877
|
+
{ key: "secretTokens", regex: /(?:aws_secret_access_key|secret_access_key)["'\s:=]+[A-Za-z0-9/+=]{40}\b/gi, replacement: "aws_secret_access_key=[REDACTED_AWS_SECRET]" },
|
|
878
|
+
{ key: "secretTokens", regex: /\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\b/g, replacement: "[REDACTED_STRIPE_KEY]" },
|
|
879
|
+
{ key: "secretTokens", regex: /\bpk_(?:live|test)_[A-Za-z0-9]{24,}\b/g, replacement: "[REDACTED_STRIPE_PK]" },
|
|
880
|
+
{ key: "secretTokens", regex: /\bxox[abpor]-[A-Za-z0-9-]{10,}\b/g, replacement: "[REDACTED_SLACK_TOKEN]" },
|
|
881
|
+
{ key: "secretTokens", regex: /\bghp_[A-Za-z0-9]{36}\b/g, replacement: "[REDACTED_GITHUB_PAT]" },
|
|
882
|
+
{ key: "secretTokens", regex: /\bgithub_pat_[A-Za-z0-9_]{80,}\b/g, replacement: "[REDACTED_GITHUB_PAT]" },
|
|
883
|
+
{ key: "secretTokens", regex: /\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b/g, replacement: "[REDACTED_OPENAI_KEY]" },
|
|
884
|
+
{ key: "secretTokens", regex: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g, replacement: "[REDACTED_ANTHROPIC_KEY]" },
|
|
885
|
+
{ key: "secretTokens", regex: /\bAIza[0-9A-Za-z_-]{35}\b/g, replacement: "[REDACTED_GOOGLE_KEY]" },
|
|
886
|
+
{ key: "secretTokens", regex: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, replacement: "[REDACTED_JWT]" },
|
|
743
887
|
{ key: "emails", regex: /\b[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}\b/g, replacement: "[REDACTED_EMAIL]" },
|
|
744
888
|
{ key: "phones", regex: /(?:\+\d{1,3}[\s.-])?\(?\d{2,4}\)?[\s.-]\d{3,4}[\s.-]\d{3,4}\b/g, replacement: "[REDACTED_PHONE]" },
|
|
745
|
-
{ key: "ipAddresses", regex: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g, replacement: "[REDACTED_IP]" }
|
|
889
|
+
{ key: "ipAddresses", regex: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g, replacement: "[REDACTED_IP]" },
|
|
890
|
+
{ key: "ipv6", regex: /\b(?:[A-Fa-f0-9]{1,4}:){2,7}[A-Fa-f0-9]{0,4}\b/g, replacement: "[REDACTED_IPV6]" }
|
|
746
891
|
];
|
|
747
892
|
var DEFAULT_CONFIG = {
|
|
748
893
|
emails: true,
|
|
749
894
|
phones: true,
|
|
750
895
|
creditCards: true,
|
|
751
896
|
ssns: true,
|
|
752
|
-
ipAddresses: false
|
|
897
|
+
ipAddresses: false,
|
|
898
|
+
// Secret tokens default ON — if they leak into a bug report there's no
|
|
899
|
+
// good reason to ship them to our servers. Cheaper to scrub client-side.
|
|
900
|
+
secretTokens: true,
|
|
901
|
+
ipv6: false
|
|
753
902
|
};
|
|
754
903
|
function createPiiScrubber(config = {}) {
|
|
755
904
|
const merged = { ...DEFAULT_CONFIG, ...config };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api-client.ts","../src/region.ts","../src/pre-filter.ts","../src/logger.ts","../src/queue.ts","../src/environment.ts","../src/reporter-token.ts","../src/fingerprint.ts","../src/session.ts","../src/rate-limiter.ts","../src/pii-scrubber.ts"],"names":["getBackoffDelay","sleep"],"mappings":"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","file":"index.js","sourcesContent":["import type { MushiApiClient, MushiApiResponse, MushiReport, MushiReportStatus } from './types';\n\nexport interface ApiClientOptions {\n projectId: string;\n apiKey: string;\n /**\n * Override the API endpoint. Defaults to the canonical Cloud URL\n * (DEFAULT_API_ENDPOINT). Self-hosted users MUST set this.\n */\n apiEndpoint?: string;\n timeout?: number;\n maxRetries?: number;\n}\n\n// V5.3 (M-cross-cutting): canonical Cloud URL — the older `api.mushimushi.dev`\n// hostname was never wired up. Self-hosted users MUST override `apiEndpoint`.\nexport const DEFAULT_API_ENDPOINT = 'https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api';\nconst DEFAULT_TIMEOUT = 10_000;\nconst DEFAULT_MAX_RETRIES = 2;\n\nexport function createApiClient(options: ApiClientOptions): MushiApiClient {\n const {\n projectId,\n apiKey,\n apiEndpoint = DEFAULT_API_ENDPOINT,\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = options;\n\n let baseUrl = apiEndpoint.replace(/\\/$/, '');\n\n async function request<T>(\n method: string,\n path: string,\n body?: unknown,\n retries = maxRetries,\n ): Promise<MushiApiResponse<T>> {\n const url = `${baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'X-Mushi-Api-Key': apiKey,\n 'X-Mushi-Project': projectId,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n // Wave C C7: data residency — follow a one-shot redirect when the\n // gateway tells us the project lives in a different region. Cache the\n // new base URL so subsequent calls go straight to the right cluster.\n if (response.status === 307 || response.status === 308) {\n const target = response.headers.get('Location');\n if (target && retries > 0) {\n const targetBase = target.replace(/\\/v1\\/.*$/, '').replace(/\\/$/, '');\n if (targetBase !== baseUrl) {\n baseUrl = targetBase;\n return request<T>(method, path, body, retries - 1);\n }\n }\n }\n\n if (!response.ok) {\n const errorBody = await response.json().catch(() => ({}));\n if (response.status >= 500 && retries > 0) {\n await sleep(getBackoffDelay(maxRetries - retries));\n return request<T>(method, path, body, retries - 1);\n }\n return {\n ok: false,\n error: {\n code: `HTTP_${response.status}`,\n message:\n (errorBody as { message?: string }).message || `HTTP ${response.status} error`,\n },\n };\n }\n\n const data = (await response.json()) as T;\n return { ok: true, data };\n } catch (error) {\n clearTimeout(timer);\n\n if (retries > 0 && isRetryable(error)) {\n await sleep(getBackoffDelay(maxRetries - retries));\n return request<T>(method, path, body, retries - 1);\n }\n\n return {\n ok: false,\n error: {\n code: 'NETWORK_ERROR',\n message: error instanceof Error ? error.message : 'Unknown network error',\n },\n };\n }\n }\n\n return {\n async submitReport(report: MushiReport) {\n return request<{ reportId: string }>('POST', '/v1/reports', report);\n },\n\n async getReportStatus(reportId: string) {\n return request<{ status: MushiReportStatus }>('GET', `/v1/reports/${reportId}/status`);\n },\n };\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return Math.min(1000 * 2 ** attempt + Math.random() * 500, 10_000);\n}\n\nfunction isRetryable(error: unknown): boolean {\n if (error instanceof DOMException && error.name === 'AbortError') return true;\n if (error instanceof TypeError) return true; // network failures\n return false;\n}\n","/**\n * Wave C C7: Data residency region resolution.\n *\n * The SDK supports four regional clouds:\n * - 'us' → United States (default; legacy `dxptnwrhwsqckaftyymj`)\n * - 'eu' → European Union (Frankfurt)\n * - 'jp' → Japan (Tokyo)\n * - 'self' → self-hosted / BYO Supabase\n *\n * Customers choose a region at project creation time, and the gateway will\n * 307-redirect any cross-region calls to the correct host. The SDK caches\n * the resolved hostname in `localStorage` (browser) so that subsequent\n * sessions skip the redirect.\n */\n\nexport type MushiRegion = 'us' | 'eu' | 'jp' | 'self';\n\nexport const REGION_ENDPOINTS: Record<Exclude<MushiRegion, 'self'>, string> = {\n us: 'https://api.us.mushimushi.dev/functions/v1/api',\n eu: 'https://api.eu.mushimushi.dev/functions/v1/api',\n jp: 'https://api.jp.mushimushi.dev/functions/v1/api',\n};\n\nconst ROUTING_CACHE_KEY = 'mushi_region_v1';\nconst ROUTING_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\ninterface RegionCacheEntry {\n region: MushiRegion;\n endpoint: string;\n ts: number;\n}\n\n/**\n * Resolve the regional endpoint for a project. Looks up the public\n * `region_routing` table on the legacy US gateway (the catalog of record),\n * then caches the result.\n *\n * Falls back to the explicit `apiEndpoint` if anything goes wrong — failure\n * here must never block report submission.\n */\nexport async function resolveRegionEndpoint(opts: {\n projectId: string;\n apiEndpoint: string;\n region?: MushiRegion;\n storage?: Storage;\n fetcher?: typeof fetch;\n}): Promise<string> {\n const explicit = opts.region;\n if (explicit && explicit !== 'self' && REGION_ENDPOINTS[explicit]) {\n return REGION_ENDPOINTS[explicit];\n }\n\n const storage = opts.storage ?? safeLocalStorage();\n const cached = readCache(storage, opts.projectId);\n if (cached) return cached;\n\n try {\n const fetcher = opts.fetcher ?? fetch;\n const url = `${opts.apiEndpoint.replace(/\\/$/, '')}/v1/region/resolve?project_id=${encodeURIComponent(opts.projectId)}`;\n const res = await fetcher(url, { method: 'GET' });\n if (!res.ok) return opts.apiEndpoint;\n const body = (await res.json()) as { region?: MushiRegion; endpoint?: string };\n if (!body.region || !body.endpoint) return opts.apiEndpoint;\n writeCache(storage, opts.projectId, { region: body.region, endpoint: body.endpoint, ts: Date.now() });\n return body.endpoint;\n } catch {\n return opts.apiEndpoint;\n }\n}\n\nfunction safeLocalStorage(): Storage | undefined {\n try {\n return typeof globalThis !== 'undefined' && 'localStorage' in globalThis\n ? (globalThis as { localStorage: Storage }).localStorage\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readCache(storage: Storage | undefined, projectId: string): string | null {\n if (!storage) return null;\n try {\n const raw = storage.getItem(`${ROUTING_CACHE_KEY}:${projectId}`);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as RegionCacheEntry;\n if (Date.now() - parsed.ts > ROUTING_CACHE_TTL_MS) return null;\n return parsed.endpoint;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(storage: Storage | undefined, projectId: string, entry: RegionCacheEntry): void {\n if (!storage) return;\n try {\n storage.setItem(`${ROUTING_CACHE_KEY}:${projectId}`, JSON.stringify(entry));\n } catch {\n /* no-op: quota exceeded etc. */\n }\n}\n","import type { MushiPreFilterConfig } from './types';\n\nexport interface PreFilterResult {\n passed: boolean;\n reason?: string;\n}\n\nconst DEFAULT_MIN_LENGTH = 10;\nconst DEFAULT_MAX_LENGTH = 2000;\n\nconst SPAM_PATTERNS: RegExp[] = [\n /^(.)\\1{10,}$/, // repeated single character\n /^[A-Z\\s!?]{20,}$/, // all caps shouting\n /^[\\d\\s]+$/, // numbers only\n /^[^a-zA-Z\\u00C0-\\u024F\\u4E00-\\u9FFF\\u3040-\\u309F\\u30A0-\\u30FF]{10,}$/, // no real letters\n /\\b(test|asdf|qwerty|lorem ipsum)\\b/i, // common test strings\n];\n\nconst GIBBERISH_PATTERN = /^[bcdfghjklmnpqrstvwxz]{6,}/i; // consonant-only strings\n\nexport function createPreFilter(config: MushiPreFilterConfig = {}) {\n const {\n enabled = true,\n blockObviousSpam = true,\n minDescriptionLength = DEFAULT_MIN_LENGTH,\n maxDescriptionLength = DEFAULT_MAX_LENGTH,\n } = config;\n\n function check(description: string): PreFilterResult {\n if (!enabled) {\n return { passed: true };\n }\n\n const trimmed = description.trim();\n\n if (trimmed.length < minDescriptionLength) {\n return { passed: false, reason: `Too short (min ${minDescriptionLength} characters)` };\n }\n\n if (trimmed.length > maxDescriptionLength) {\n return { passed: false, reason: `Too long (max ${maxDescriptionLength} characters)` };\n }\n\n if (blockObviousSpam) {\n for (const pattern of SPAM_PATTERNS) {\n if (pattern.test(trimmed)) {\n return { passed: false, reason: 'Detected as spam' };\n }\n }\n\n if (GIBBERISH_PATTERN.test(trimmed)) {\n return { passed: false, reason: 'Detected as gibberish' };\n }\n\n const words = trimmed.split(/\\s+/).filter((w) => w.length > 1);\n if (words.length < 2) {\n return { passed: false, reason: 'Description needs at least 2 words' };\n }\n }\n\n return { passed: true };\n }\n\n function truncate(description: string): string {\n const trimmed = description.trim();\n if (trimmed.length <= maxDescriptionLength) return trimmed;\n return trimmed.slice(0, maxDescriptionLength) + '...';\n }\n\n return { check, truncate };\n}\n","/**\n * FILE: logger.ts\n * PURPOSE: Zero-dependency structured logger for the mushi-mushi SDK ecosystem.\n *\n * OVERVIEW:\n * - Production-grade logging with levels, scoped namespaces, and child loggers\n * - JSON output for server/production, pretty-formatted output for development\n * - Automatic environment detection (browser vs Node vs Deno)\n * - Structured metadata on every log entry\n * - No external dependencies — safe to ship in any SDK bundle\n *\n * USAGE:\n * import { createLogger } from '@mushi-mushi/core'\n * const log = createLogger({ scope: 'mushi:api' })\n * log.info('Request received', { method: 'POST', path: '/v1/reports' })\n * const child = log.child('ingest', { reportId: 'abc' })\n * child.warn('Slow query', { latencyMs: 420 })\n *\n * TECHNICAL DETAILS:\n * - Log levels: debug(10) < info(20) < warn(30) < error(40) < fatal(50) < silent(99)\n * - Format auto-detected: JSON in production/server, pretty in development\n * - Pretty format uses ANSI colors when supported (Node/Deno TTY)\n * - Child loggers inherit parent scope + metadata, can override level\n * - Timestamps are ISO 8601 with millisecond precision\n */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'silent'\n\nexport type LogFormat = 'json' | 'pretty' | 'auto'\n\nexport interface LoggerOptions {\n scope: string\n level?: LogLevel\n meta?: Record<string, unknown>\n format?: LogFormat\n}\n\nexport interface Logger {\n debug(msg: string, meta?: Record<string, unknown>): void\n info(msg: string, meta?: Record<string, unknown>): void\n warn(msg: string, meta?: Record<string, unknown>): void\n error(msg: string, meta?: Record<string, unknown>): void\n fatal(msg: string, meta?: Record<string, unknown>): void\n child(scope: string, meta?: Record<string, unknown>): Logger\n setLevel(level: LogLevel): void\n}\n\nexport interface LogEntry {\n ts: string\n level: LogLevel\n scope: string\n msg: string\n [key: string]: unknown\n}\n\nconst LEVEL_VALUE: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n fatal: 50,\n silent: 99,\n}\n\nconst LEVEL_LABEL: Record<string, string> = {\n debug: 'DBG',\n info: 'INF',\n warn: 'WRN',\n error: 'ERR',\n fatal: 'FTL',\n}\n\nconst ANSI = {\n reset: '\\x1b[0m',\n dim: '\\x1b[2m',\n bold: '\\x1b[1m',\n cyan: '\\x1b[36m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n red: '\\x1b[31m',\n magenta: '\\x1b[35m',\n white: '\\x1b[37m',\n bgRed: '\\x1b[41m',\n} as const\n\nconst LEVEL_COLOR: Record<string, string> = {\n debug: ANSI.dim,\n info: ANSI.green,\n warn: ANSI.yellow,\n error: ANSI.red,\n fatal: `${ANSI.bgRed}${ANSI.white}${ANSI.bold}`,\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nfunction detectFormat(): 'json' | 'pretty' {\n try {\n if (typeof (globalThis as any).Deno !== 'undefined') return 'json'\n } catch { /* not Deno */ }\n\n const proc = typeof (globalThis as any).process !== 'undefined'\n ? (globalThis as any).process\n : undefined\n\n if (proc?.env) {\n if (proc.env.NODE_ENV === 'production') return 'json'\n if (proc.env.LOG_FORMAT === 'json') return 'json'\n if (proc.env.LOG_FORMAT === 'pretty') return 'pretty'\n if (proc.stdout?.isTTY) return 'pretty'\n }\n\n if (typeof (globalThis as any).window !== 'undefined') return 'pretty'\n\n return 'json'\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nfunction flattenMeta(meta: Record<string, unknown>): string {\n const parts: string[] = []\n for (const [k, v] of Object.entries(meta)) {\n if (v === undefined || v === null) continue\n if (typeof v === 'object') {\n parts.push(`${k}=${JSON.stringify(v)}`)\n } else {\n parts.push(`${k}=${String(v)}`)\n }\n }\n return parts.join(' ')\n}\n\nfunction formatPretty(entry: LogEntry): string {\n const { ts, level, scope, msg, ...rest } = entry\n const time = ts.slice(11, 23)\n const color = LEVEL_COLOR[level] ?? ''\n const label = LEVEL_LABEL[level] ?? level.toUpperCase()\n const metaStr = Object.keys(rest).length > 0 ? ` ${ANSI.dim}${flattenMeta(rest)}${ANSI.reset}` : ''\n\n return `${ANSI.dim}${time}${ANSI.reset} ${color}${label}${ANSI.reset} ${ANSI.cyan}[${scope}]${ANSI.reset} ${msg}${metaStr}`\n}\n\nfunction formatJson(entry: LogEntry): string {\n return JSON.stringify(entry)\n}\n\nfunction emit(level: LogLevel, formatted: string): void {\n switch (level) {\n case 'error':\n case 'fatal':\n console.error(formatted)\n break\n case 'warn':\n console.warn(formatted)\n break\n default:\n console.log(formatted)\n }\n}\n\nfunction buildLogger(\n scope: string,\n minLevel: LogLevel,\n baseMeta: Record<string, unknown>,\n formatter: (entry: LogEntry) => string,\n): Logger {\n let currentLevel = minLevel\n\n function log(level: LogLevel, msg: string, meta?: Record<string, unknown>): void {\n if (LEVEL_VALUE[level] < LEVEL_VALUE[currentLevel]) return\n\n const entry: LogEntry = {\n ts: new Date().toISOString(),\n level,\n scope,\n msg,\n ...baseMeta,\n ...meta,\n }\n\n emit(level, formatter(entry))\n }\n\n return {\n debug: (msg, meta?) => log('debug', msg, meta),\n info: (msg, meta?) => log('info', msg, meta),\n warn: (msg, meta?) => log('warn', msg, meta),\n error: (msg, meta?) => log('error', msg, meta),\n fatal: (msg, meta?) => log('fatal', msg, meta),\n\n child(childScope: string, childMeta?: Record<string, unknown>): Logger {\n return buildLogger(\n `${scope}:${childScope}`,\n currentLevel,\n { ...baseMeta, ...childMeta },\n formatter,\n )\n },\n\n setLevel(level: LogLevel) {\n currentLevel = level\n },\n }\n}\n\n/**\n * Create a structured logger instance.\n *\n * @example\n * const log = createLogger({ scope: 'mushi:api', level: 'info' })\n * log.info('Server started', { port: 3000 })\n *\n * const child = log.child('auth', { userId: 'u-123' })\n * child.warn('Token expired')\n */\nexport function createLogger(options: LoggerOptions): Logger {\n const {\n scope,\n level = 'info',\n meta = {},\n format = 'auto',\n } = options\n\n const resolvedFormat = format === 'auto' ? detectFormat() : format\n const formatter = resolvedFormat === 'json' ? formatJson : formatPretty\n\n return buildLogger(scope, level, meta, formatter)\n}\n\n/**\n * Noop logger that discards all output.\n * Useful when logging should be completely disabled.\n */\nexport const noopLogger: Logger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n fatal: () => {},\n child: () => noopLogger,\n setLevel: () => {},\n}\n","import type { MushiApiClient, MushiOfflineConfig, MushiReport } from './types';\nimport { createLogger } from './logger';\n\nconst queueLog = createLogger({ scope: 'mushi:queue', level: 'warn' });\n\nconst DB_NAME = 'mushi-mushi';\nconst STORE_NAME = 'offline-reports';\nconst DB_VERSION = 1;\nconst LS_KEY = 'mushi_offline_queue';\nconst BATCH_SIZE = 10;\nconst MAX_BACKOFF_MS = 60_000;\n\nexport interface OfflineQueue {\n enqueue(report: MushiReport): Promise<void>;\n flush(client: MushiApiClient): Promise<{ sent: number; failed: number }>;\n size(): Promise<number>;\n clear(): Promise<void>;\n startAutoSync(client: MushiApiClient): void;\n stopAutoSync(): void;\n}\n\ntype StorageBackend = 'indexeddb' | 'localstorage' | 'none';\n\nexport function createOfflineQueue(config: MushiOfflineConfig = {}): OfflineQueue {\n const { enabled = true, maxQueueSize = 50, syncOnReconnect = true } = config;\n\n let syncCleanup: (() => void) | null = null;\n let backendType: StorageBackend | null = null;\n\n function detectBackend(): StorageBackend {\n if (backendType) return backendType;\n if (typeof indexedDB !== 'undefined') {\n backendType = 'indexeddb';\n } else if (typeof localStorage !== 'undefined') {\n backendType = 'localstorage';\n } else {\n backendType = 'none';\n }\n return backendType;\n }\n\n // --- IndexedDB backend ---\n\n function openDb(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { keyPath: 'id' });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => {\n backendType = 'localstorage';\n reject(request.error);\n };\n });\n }\n\n async function idbEnqueue(report: MushiReport): Promise<void> {\n const db = await openDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).put({ ...report, queuedAt: new Date().toISOString() });\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n async function idbGetAll(): Promise<MushiReport[]> {\n const db = await openDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).getAll();\n request.onsuccess = () => resolve(request.result as MushiReport[]);\n request.onerror = () => reject(request.error);\n });\n }\n\n async function idbDelete(id: string): Promise<void> {\n const db = await openDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).delete(id);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n async function idbSize(): Promise<number> {\n const db = await openDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).count();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async function idbClear(): Promise<void> {\n const db = await openDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).clear();\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n // --- localStorage fallback ---\n\n function lsRead(): MushiReport[] {\n try {\n const raw = localStorage.getItem(LS_KEY);\n return raw ? JSON.parse(raw) : [];\n } catch {\n return [];\n }\n }\n\n function lsWrite(reports: MushiReport[]): void {\n try {\n localStorage.setItem(LS_KEY, JSON.stringify(reports));\n } catch {\n // localStorage full or unavailable\n }\n }\n\n function lsEnqueue(report: MushiReport): void {\n const reports = lsRead();\n reports.push({ ...report, queuedAt: new Date().toISOString() } as MushiReport);\n lsWrite(reports);\n }\n\n function lsDelete(id: string): void {\n const reports = lsRead().filter((r) => r.id !== id);\n lsWrite(reports);\n }\n\n // --- Unified interface ---\n\n async function enqueue(report: MushiReport): Promise<void> {\n if (!enabled) return;\n\n const currentSize = await size();\n if (currentSize >= maxQueueSize) {\n queueLog.warn('Offline queue full — dropping report', { maxQueueSize });\n return;\n }\n\n const backend = detectBackend();\n if (backend === 'indexeddb') {\n try {\n await idbEnqueue(report);\n return;\n } catch {\n // IndexedDB failed, fall through to localStorage\n backendType = 'localstorage';\n }\n }\n\n if (backend === 'localstorage' || backendType === 'localstorage') {\n lsEnqueue(report);\n return;\n }\n }\n\n function getBackoffDelay(attempt: number): number {\n return Math.min(1000 * 2 ** attempt + Math.random() * 500, MAX_BACKOFF_MS);\n }\n\n function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n async function flush(client: MushiApiClient): Promise<{ sent: number; failed: number }> {\n if (!enabled) return { sent: 0, failed: 0 };\n\n let reports: MushiReport[];\n const backend = detectBackend();\n\n if (backend === 'indexeddb') {\n try {\n reports = await idbGetAll();\n } catch {\n reports = lsRead();\n }\n } else {\n reports = lsRead();\n }\n\n const batch = reports.slice(0, BATCH_SIZE);\n let sent = 0;\n let failed = 0;\n\n for (let i = 0; i < batch.length; i++) {\n const report = batch[i];\n const result = await client.submitReport(report);\n\n if (result.ok) {\n try {\n if (backend === 'indexeddb') await idbDelete(report.id);\n else lsDelete(report.id);\n } catch {\n lsDelete(report.id);\n }\n sent++;\n } else {\n failed++;\n if (i < batch.length - 1) {\n await sleep(getBackoffDelay(i));\n }\n }\n }\n\n return { sent, failed };\n }\n\n async function size(): Promise<number> {\n const backend = detectBackend();\n if (backend === 'indexeddb') {\n try {\n return await idbSize();\n } catch {\n return lsRead().length;\n }\n }\n return lsRead().length;\n }\n\n async function clear(): Promise<void> {\n const backend = detectBackend();\n if (backend === 'indexeddb') {\n try {\n await idbClear();\n } catch {\n // fall through\n }\n }\n try {\n localStorage.removeItem(LS_KEY);\n } catch {\n // unavailable\n }\n }\n\n function startAutoSync(client: MushiApiClient): void {\n if (!enabled || !syncOnReconnect || typeof window === 'undefined') return;\n\n const handler = () => {\n if (navigator.onLine) {\n flush(client).catch(() => {});\n }\n };\n\n window.addEventListener('online', handler);\n syncCleanup = () => window.removeEventListener('online', handler);\n }\n\n function stopAutoSync(): void {\n syncCleanup?.();\n syncCleanup = null;\n }\n\n return { enqueue, flush, size, clear, startAutoSync, stopAutoSync };\n}\n","import type { MushiEnvironment } from './types';\n\nexport function captureEnvironment(): MushiEnvironment {\n const nav = typeof navigator !== 'undefined' ? navigator : undefined;\n const win = typeof window !== 'undefined' ? window : undefined;\n const doc = typeof document !== 'undefined' ? document : undefined;\n\n const connection = nav && 'connection' in nav ? (nav as NavigatorWithConnection).connection : undefined;\n\n return {\n userAgent: nav?.userAgent ?? 'unknown',\n platform: nav?.platform ?? 'unknown',\n language: nav?.language ?? 'en',\n viewport: {\n width: win?.innerWidth ?? 0,\n height: win?.innerHeight ?? 0,\n },\n url: win?.location?.href ?? '',\n referrer: doc?.referrer ?? '',\n timestamp: new Date().toISOString(),\n timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone ?? 'UTC',\n connection: connection\n ? {\n effectiveType: connection.effectiveType,\n downlink: connection.downlink,\n rtt: connection.rtt,\n }\n : undefined,\n deviceMemory: (nav as NavigatorWithDeviceMemory)?.deviceMemory,\n hardwareConcurrency: nav?.hardwareConcurrency,\n };\n}\n\ninterface NetworkInformation {\n effectiveType?: string;\n downlink?: number;\n rtt?: number;\n}\n\ninterface NavigatorWithConnection extends Navigator {\n connection?: NetworkInformation;\n}\n\ninterface NavigatorWithDeviceMemory extends Navigator {\n deviceMemory?: number;\n}\n","const STORAGE_KEY = 'mushi_reporter_token';\n\nexport function getReporterToken(): string {\n if (typeof localStorage !== 'undefined') {\n const existing = localStorage.getItem(STORAGE_KEY);\n if (existing) return existing;\n }\n\n const token = generateToken();\n\n if (typeof localStorage !== 'undefined') {\n try {\n localStorage.setItem(STORAGE_KEY, token);\n } catch {\n // localStorage full or unavailable — token is ephemeral\n }\n }\n\n return token;\n}\n\nfunction generateToken(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return `mushi_${crypto.randomUUID()}`;\n }\n\n const bytes = new Uint8Array(16);\n if (typeof crypto !== 'undefined') {\n crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n\n const hex = Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return `mushi_${hex}`;\n}\n","/**\n * Wave E §3c — stable device fingerprint hash.\n *\n * Hashes a deliberately small set of long-lived device characteristics so\n * the same browser keeps the same hash across sessions, but moving to a\n * new browser/device produces a different one. This lets the server\n * detect cross-account abuse (same hash → many reporter accounts) without\n * needing fingerprint.js or any other entropy-heavy library.\n *\n * Privacy notes:\n * - We never send the raw inputs, only the SHA-256 hex digest.\n * - The set is intentionally low-entropy on purpose; this is \"is this the\n * same device\" not \"who is this user\". For high-stakes anti-fraud you\n * should still combine with server-side IP/geo signals.\n * - Cached in localStorage so subsequent calls are zero-cost.\n */\n\nconst CACHE_KEY = 'mushi_fingerprint_hash';\n\ninterface FingerprintInputs {\n userAgent: string;\n platform: string;\n language: string;\n timezone: string;\n screenWidth: number;\n screenHeight: number;\n pixelRatio: number;\n deviceMemory: number | undefined;\n hardwareConcurrency: number | undefined;\n}\n\nfunction collectInputs(): FingerprintInputs {\n const nav = typeof navigator !== 'undefined' ? navigator : undefined;\n const scr = typeof screen !== 'undefined' ? screen : undefined;\n const win = typeof window !== 'undefined' ? window : undefined;\n return {\n userAgent: nav?.userAgent ?? 'unknown',\n platform: nav?.platform ?? 'unknown',\n language: nav?.language ?? 'en',\n timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone ?? 'UTC',\n screenWidth: scr?.width ?? 0,\n screenHeight: scr?.height ?? 0,\n pixelRatio: win?.devicePixelRatio ?? 1,\n deviceMemory: (nav as NavigatorWithDeviceMemory | undefined)?.deviceMemory,\n hardwareConcurrency: nav?.hardwareConcurrency,\n };\n}\n\ninterface NavigatorWithDeviceMemory extends Navigator {\n deviceMemory?: number;\n}\n\nasync function sha256Hex(input: string): Promise<string> {\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n const buf = new TextEncoder().encode(input);\n const digest = await crypto.subtle.digest('SHA-256', buf);\n return Array.from(new Uint8Array(digest))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n }\n // Fallback (Node 18+ test envs, very old browsers): non-cryptographic but\n // good enough for the \"are these two requests from the same device\" use\n // case the server makes of this value.\n let hash = 0;\n for (let i = 0; i < input.length; i++) {\n hash = (hash << 5) - hash + input.charCodeAt(i);\n hash |= 0;\n }\n return `fbk_${(hash >>> 0).toString(16).padStart(8, '0')}`;\n}\n\n/**\n * Returns a stable per-device hash. Cached in localStorage; first call is\n * one SHA-256, subsequent calls are a localStorage read.\n *\n * Returns `null` outside browser-like environments (SSR, web workers\n * without crypto.subtle) so callers can omit the field gracefully.\n */\nexport async function getDeviceFingerprintHash(): Promise<string | null> {\n if (typeof localStorage !== 'undefined') {\n const cached = localStorage.getItem(CACHE_KEY);\n if (cached) return cached;\n }\n\n const inputs = collectInputs();\n const serialised = JSON.stringify(inputs);\n const hash = await sha256Hex(serialised);\n\n if (typeof localStorage !== 'undefined') {\n try {\n localStorage.setItem(CACHE_KEY, hash);\n } catch {\n // localStorage quota / private mode — caller still gets the hash.\n }\n }\n return hash;\n}\n\n/** Test/diagnostic helper — never include in shipped reports. */\nexport function _resetFingerprintCacheForTests(): void {\n if (typeof localStorage !== 'undefined') {\n try {\n localStorage.removeItem(CACHE_KEY);\n } catch {\n // ignore\n }\n }\n}\n","const SESSION_KEY = 'mushi_session_id';\n\nlet cachedSessionId: string | null = null;\n\nexport function getSessionId(): string {\n if (cachedSessionId) return cachedSessionId;\n\n if (typeof sessionStorage !== 'undefined') {\n const existing = sessionStorage.getItem(SESSION_KEY);\n if (existing) {\n cachedSessionId = existing;\n return existing;\n }\n }\n\n const id = generateSessionId();\n cachedSessionId = id;\n\n if (typeof sessionStorage !== 'undefined') {\n try {\n sessionStorage.setItem(SESSION_KEY, id);\n } catch {\n // sessionStorage unavailable\n }\n }\n\n return id;\n}\n\nfunction generateSessionId(): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).slice(2, 8);\n return `ms_${timestamp}_${random}`;\n}\n","export interface RateLimiterConfig {\n maxBurst?: number;\n refillRate?: number;\n refillIntervalMs?: number;\n}\n\nexport interface RateLimiter {\n tryConsume(): boolean;\n reset(): void;\n availableTokens(): number;\n}\n\nconst DEFAULT_MAX_BURST = 10;\nconst DEFAULT_REFILL_RATE = 1;\nconst DEFAULT_REFILL_INTERVAL_MS = 5_000;\n\nexport function createRateLimiter(config: RateLimiterConfig = {}): RateLimiter {\n const {\n maxBurst = DEFAULT_MAX_BURST,\n refillRate = DEFAULT_REFILL_RATE,\n refillIntervalMs = DEFAULT_REFILL_INTERVAL_MS,\n } = config;\n\n let tokens = maxBurst;\n let lastRefill = Date.now();\n\n function refill() {\n const now = Date.now();\n const elapsed = now - lastRefill;\n const refills = Math.floor(elapsed / refillIntervalMs);\n if (refills > 0) {\n tokens = Math.min(maxBurst, tokens + refills * refillRate);\n lastRefill = now;\n }\n }\n\n function tryConsume(): boolean {\n refill();\n if (tokens > 0) {\n tokens--;\n return true;\n }\n return false;\n }\n\n function reset(): void {\n tokens = maxBurst;\n lastRefill = Date.now();\n }\n\n function availableTokens(): number {\n refill();\n return tokens;\n }\n\n return { tryConsume, reset, availableTokens };\n}\n","export interface PiiScrubberConfig {\n emails?: boolean;\n phones?: boolean;\n creditCards?: boolean;\n ssns?: boolean;\n ipAddresses?: boolean;\n}\n\ninterface PiiPattern {\n key: keyof PiiScrubberConfig;\n regex: RegExp;\n replacement: string;\n}\n\n// Order matters: SSN → CC → email → phone → IP\n// CC must run before phone to prevent phone regex from partially matching CC sequences\nconst ORDERED_PATTERNS: PiiPattern[] = [\n { key: 'ssns', regex: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g, replacement: '[REDACTED_SSN]' },\n { key: 'creditCards', regex: /\\b(?:\\d[ -]*){12,18}\\d\\b/g, replacement: '[REDACTED_CC]' },\n { key: 'emails', regex: /\\b[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}\\b/g, replacement: '[REDACTED_EMAIL]' },\n { key: 'phones', regex: /(?:\\+\\d{1,3}[\\s.-])?\\(?\\d{2,4}\\)?[\\s.-]\\d{3,4}[\\s.-]\\d{3,4}\\b/g, replacement: '[REDACTED_PHONE]' },\n { key: 'ipAddresses', regex: /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g, replacement: '[REDACTED_IP]' },\n];\n\nconst DEFAULT_CONFIG: PiiScrubberConfig = {\n emails: true,\n phones: true,\n creditCards: true,\n ssns: true,\n ipAddresses: false,\n};\n\nexport function createPiiScrubber(config: PiiScrubberConfig = {}) {\n const merged = { ...DEFAULT_CONFIG, ...config };\n\n const activePatterns = ORDERED_PATTERNS.filter((p) => merged[p.key]);\n\n function scrub(text: string): string {\n if (!text) return text;\n let result = text;\n for (const { regex, replacement } of activePatterns) {\n result = result.replace(new RegExp(regex.source, regex.flags), replacement);\n }\n return result;\n }\n\n function scrubObject<T extends Record<string, unknown>>(obj: T, keys: string[]): T {\n const copy = { ...obj };\n for (const key of keys) {\n if (typeof copy[key] === 'string') {\n (copy as Record<string, unknown>)[key] = scrub(copy[key] as string);\n }\n }\n return copy;\n }\n\n return { scrub, scrubObject };\n}\n\nexport function scrubPii(text: string, config?: PiiScrubberConfig): string {\n return createPiiScrubber(config).scrub(text);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/api-client.ts","../src/region.ts","../src/pre-filter.ts","../src/logger.ts","../src/queue-crypto.ts","../src/queue.ts","../src/environment.ts","../src/reporter-token.ts","../src/fingerprint.ts","../src/session.ts","../src/rate-limiter.ts","../src/pii-scrubber.ts"],"names":["getBackoffDelay","sleep"],"mappings":"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","file":"index.js","sourcesContent":["import type { MushiApiClient, MushiApiResponse, MushiReport, MushiReportStatus } from './types';\n\nexport interface ApiClientOptions {\n projectId: string;\n apiKey: string;\n /**\n * Override the API endpoint. Defaults to the canonical Cloud URL\n * (DEFAULT_API_ENDPOINT). Self-hosted users MUST set this.\n */\n apiEndpoint?: string;\n timeout?: number;\n maxRetries?: number;\n}\n\n// V5.3 (M-cross-cutting): canonical Cloud URL — the older `api.mushimushi.dev`\n// hostname was never wired up. Self-hosted users MUST override `apiEndpoint`.\nexport const DEFAULT_API_ENDPOINT = 'https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api';\nconst DEFAULT_TIMEOUT = 10_000;\nconst DEFAULT_MAX_RETRIES = 2;\n\nexport function createApiClient(options: ApiClientOptions): MushiApiClient {\n const {\n projectId,\n apiKey,\n apiEndpoint = DEFAULT_API_ENDPOINT,\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = options;\n\n let baseUrl = apiEndpoint.replace(/\\/$/, '');\n\n async function request<T>(\n method: string,\n path: string,\n body?: unknown,\n retries = maxRetries,\n ): Promise<MushiApiResponse<T>> {\n const url = `${baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'X-Mushi-Api-Key': apiKey,\n 'X-Mushi-Project': projectId,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n // C7: data residency — follow a one-shot redirect when the\n // gateway tells us the project lives in a different region. Cache the\n // new base URL so subsequent calls go straight to the right cluster.\n if (response.status === 307 || response.status === 308) {\n const target = response.headers.get('Location');\n if (target && retries > 0) {\n const targetBase = target.replace(/\\/v1\\/.*$/, '').replace(/\\/$/, '');\n if (targetBase !== baseUrl) {\n baseUrl = targetBase;\n return request<T>(method, path, body, retries - 1);\n }\n }\n }\n\n if (!response.ok) {\n const errorBody = await response.json().catch(() => ({}));\n if (response.status >= 500 && retries > 0) {\n await sleep(getBackoffDelay(maxRetries - retries));\n return request<T>(method, path, body, retries - 1);\n }\n return {\n ok: false,\n error: {\n code: `HTTP_${response.status}`,\n message:\n (errorBody as { message?: string }).message || `HTTP ${response.status} error`,\n },\n };\n }\n\n const data = (await response.json()) as T;\n return { ok: true, data };\n } catch (error) {\n clearTimeout(timer);\n\n if (retries > 0 && isRetryable(error)) {\n await sleep(getBackoffDelay(maxRetries - retries));\n return request<T>(method, path, body, retries - 1);\n }\n\n return {\n ok: false,\n error: {\n code: 'NETWORK_ERROR',\n message: error instanceof Error ? error.message : 'Unknown network error',\n },\n };\n }\n }\n\n return {\n async submitReport(report: MushiReport) {\n return request<{ reportId: string }>('POST', '/v1/reports', report);\n },\n\n async getReportStatus(reportId: string) {\n return request<{ status: MushiReportStatus }>('GET', `/v1/reports/${reportId}/status`);\n },\n };\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return Math.min(1000 * 2 ** attempt + Math.random() * 500, 10_000);\n}\n\nfunction isRetryable(error: unknown): boolean {\n if (error instanceof DOMException && error.name === 'AbortError') return true;\n if (error instanceof TypeError) return true; // network failures\n return false;\n}\n","/**\n * C7: Data residency region resolution.\n *\n * The SDK supports four regional clouds:\n * - 'us' → United States (default; legacy `dxptnwrhwsqckaftyymj`)\n * - 'eu' → European Union (Frankfurt)\n * - 'jp' → Japan (Tokyo)\n * - 'self' → self-hosted / BYO Supabase\n *\n * Customers choose a region at project creation time, and the gateway will\n * 307-redirect any cross-region calls to the correct host. The SDK caches\n * the resolved hostname in `localStorage` (browser) so that subsequent\n * sessions skip the redirect.\n */\n\nexport type MushiRegion = 'us' | 'eu' | 'jp' | 'self';\n\nexport const REGION_ENDPOINTS: Record<Exclude<MushiRegion, 'self'>, string> = {\n us: 'https://api.us.mushimushi.dev/functions/v1/api',\n eu: 'https://api.eu.mushimushi.dev/functions/v1/api',\n jp: 'https://api.jp.mushimushi.dev/functions/v1/api',\n};\n\nconst ROUTING_CACHE_KEY = 'mushi_region_v1';\nconst ROUTING_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\ninterface RegionCacheEntry {\n region: MushiRegion;\n endpoint: string;\n ts: number;\n}\n\n/**\n * Resolve the regional endpoint for a project. Looks up the public\n * `region_routing` table on the legacy US gateway (the catalog of record),\n * then caches the result.\n *\n * Falls back to the explicit `apiEndpoint` if anything goes wrong — failure\n * here must never block report submission.\n */\nexport async function resolveRegionEndpoint(opts: {\n projectId: string;\n apiEndpoint: string;\n region?: MushiRegion;\n storage?: Storage;\n fetcher?: typeof fetch;\n}): Promise<string> {\n const explicit = opts.region;\n if (explicit && explicit !== 'self' && REGION_ENDPOINTS[explicit]) {\n return REGION_ENDPOINTS[explicit];\n }\n\n const storage = opts.storage ?? safeLocalStorage();\n const cached = readCache(storage, opts.projectId);\n if (cached) return cached;\n\n try {\n const fetcher = opts.fetcher ?? fetch;\n const url = `${opts.apiEndpoint.replace(/\\/$/, '')}/v1/region/resolve?project_id=${encodeURIComponent(opts.projectId)}`;\n const res = await fetcher(url, { method: 'GET' });\n if (!res.ok) return opts.apiEndpoint;\n const body = (await res.json()) as { region?: MushiRegion; endpoint?: string };\n if (!body.region || !body.endpoint) return opts.apiEndpoint;\n writeCache(storage, opts.projectId, { region: body.region, endpoint: body.endpoint, ts: Date.now() });\n return body.endpoint;\n } catch {\n return opts.apiEndpoint;\n }\n}\n\nfunction safeLocalStorage(): Storage | undefined {\n try {\n return typeof globalThis !== 'undefined' && 'localStorage' in globalThis\n ? (globalThis as { localStorage: Storage }).localStorage\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readCache(storage: Storage | undefined, projectId: string): string | null {\n if (!storage) return null;\n try {\n const raw = storage.getItem(`${ROUTING_CACHE_KEY}:${projectId}`);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as RegionCacheEntry;\n if (Date.now() - parsed.ts > ROUTING_CACHE_TTL_MS) return null;\n return parsed.endpoint;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(storage: Storage | undefined, projectId: string, entry: RegionCacheEntry): void {\n if (!storage) return;\n try {\n storage.setItem(`${ROUTING_CACHE_KEY}:${projectId}`, JSON.stringify(entry));\n } catch {\n /* no-op: quota exceeded etc. */\n }\n}\n","import type { MushiPreFilterConfig } from './types';\n\nexport interface PreFilterResult {\n passed: boolean;\n reason?: string;\n}\n\nconst DEFAULT_MIN_LENGTH = 10;\nconst DEFAULT_MAX_LENGTH = 2000;\n\nconst SPAM_PATTERNS: RegExp[] = [\n /^(.)\\1{10,}$/, // repeated single character\n /^[A-Z\\s!?]{20,}$/, // all caps shouting\n /^[\\d\\s]+$/, // numbers only\n /^[^a-zA-Z\\u00C0-\\u024F\\u4E00-\\u9FFF\\u3040-\\u309F\\u30A0-\\u30FF]{10,}$/, // no real letters\n /\\b(test|asdf|qwerty|lorem ipsum)\\b/i, // common test strings\n];\n\nconst GIBBERISH_PATTERN = /^[bcdfghjklmnpqrstvwxz]{6,}/i; // consonant-only strings\n\nexport function createPreFilter(config: MushiPreFilterConfig = {}) {\n const {\n enabled = true,\n blockObviousSpam = true,\n minDescriptionLength = DEFAULT_MIN_LENGTH,\n maxDescriptionLength = DEFAULT_MAX_LENGTH,\n } = config;\n\n function check(description: string): PreFilterResult {\n if (!enabled) {\n return { passed: true };\n }\n\n const trimmed = description.trim();\n\n if (trimmed.length < minDescriptionLength) {\n return { passed: false, reason: `Too short (min ${minDescriptionLength} characters)` };\n }\n\n if (trimmed.length > maxDescriptionLength) {\n return { passed: false, reason: `Too long (max ${maxDescriptionLength} characters)` };\n }\n\n if (blockObviousSpam) {\n for (const pattern of SPAM_PATTERNS) {\n if (pattern.test(trimmed)) {\n return { passed: false, reason: 'Detected as spam' };\n }\n }\n\n if (GIBBERISH_PATTERN.test(trimmed)) {\n return { passed: false, reason: 'Detected as gibberish' };\n }\n\n const words = trimmed.split(/\\s+/).filter((w) => w.length > 1);\n if (words.length < 2) {\n return { passed: false, reason: 'Description needs at least 2 words' };\n }\n }\n\n return { passed: true };\n }\n\n function truncate(description: string): string {\n const trimmed = description.trim();\n if (trimmed.length <= maxDescriptionLength) return trimmed;\n return trimmed.slice(0, maxDescriptionLength) + '...';\n }\n\n return { check, truncate };\n}\n","/**\n * FILE: logger.ts\n * PURPOSE: Zero-dependency structured logger for the mushi-mushi SDK ecosystem.\n *\n * OVERVIEW:\n * - Production-grade logging with levels, scoped namespaces, and child loggers\n * - JSON output for server/production, pretty-formatted output for development\n * - Automatic environment detection (browser vs Node vs Deno)\n * - Structured metadata on every log entry\n * - No external dependencies — safe to ship in any SDK bundle\n *\n * USAGE:\n * import { createLogger } from '@mushi-mushi/core'\n * const log = createLogger({ scope: 'mushi:api' })\n * log.info('Request received', { method: 'POST', path: '/v1/reports' })\n * const child = log.child('ingest', { reportId: 'abc' })\n * child.warn('Slow query', { latencyMs: 420 })\n *\n * TECHNICAL DETAILS:\n * - Log levels: debug(10) < info(20) < warn(30) < error(40) < fatal(50) < silent(99)\n * - Format auto-detected: JSON in production/server, pretty in development\n * - Pretty format uses ANSI colors when supported (Node/Deno TTY)\n * - Child loggers inherit parent scope + metadata, can override level\n * - Timestamps are ISO 8601 with millisecond precision\n */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'silent'\n\nexport type LogFormat = 'json' | 'pretty' | 'auto'\n\nexport interface LoggerOptions {\n scope: string\n level?: LogLevel\n meta?: Record<string, unknown>\n format?: LogFormat\n}\n\nexport interface Logger {\n debug(msg: string, meta?: Record<string, unknown>): void\n info(msg: string, meta?: Record<string, unknown>): void\n warn(msg: string, meta?: Record<string, unknown>): void\n error(msg: string, meta?: Record<string, unknown>): void\n fatal(msg: string, meta?: Record<string, unknown>): void\n child(scope: string, meta?: Record<string, unknown>): Logger\n setLevel(level: LogLevel): void\n}\n\nexport interface LogEntry {\n ts: string\n level: LogLevel\n scope: string\n msg: string\n [key: string]: unknown\n}\n\nconst LEVEL_VALUE: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n fatal: 50,\n silent: 99,\n}\n\nconst LEVEL_LABEL: Record<string, string> = {\n debug: 'DBG',\n info: 'INF',\n warn: 'WRN',\n error: 'ERR',\n fatal: 'FTL',\n}\n\nconst ANSI = {\n reset: '\\x1b[0m',\n dim: '\\x1b[2m',\n bold: '\\x1b[1m',\n cyan: '\\x1b[36m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n red: '\\x1b[31m',\n magenta: '\\x1b[35m',\n white: '\\x1b[37m',\n bgRed: '\\x1b[41m',\n} as const\n\nconst LEVEL_COLOR: Record<string, string> = {\n debug: ANSI.dim,\n info: ANSI.green,\n warn: ANSI.yellow,\n error: ANSI.red,\n fatal: `${ANSI.bgRed}${ANSI.white}${ANSI.bold}`,\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nfunction detectFormat(): 'json' | 'pretty' {\n try {\n if (typeof (globalThis as any).Deno !== 'undefined') return 'json'\n } catch { /* not Deno */ }\n\n const proc = typeof (globalThis as any).process !== 'undefined'\n ? (globalThis as any).process\n : undefined\n\n if (proc?.env) {\n if (proc.env.NODE_ENV === 'production') return 'json'\n if (proc.env.LOG_FORMAT === 'json') return 'json'\n if (proc.env.LOG_FORMAT === 'pretty') return 'pretty'\n if (proc.stdout?.isTTY) return 'pretty'\n }\n\n if (typeof (globalThis as any).window !== 'undefined') return 'pretty'\n\n return 'json'\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nfunction flattenMeta(meta: Record<string, unknown>): string {\n const parts: string[] = []\n for (const [k, v] of Object.entries(meta)) {\n if (v === undefined || v === null) continue\n if (typeof v === 'object') {\n parts.push(`${k}=${JSON.stringify(v)}`)\n } else {\n parts.push(`${k}=${String(v)}`)\n }\n }\n return parts.join(' ')\n}\n\nfunction formatPretty(entry: LogEntry): string {\n const { ts, level, scope, msg, ...rest } = entry\n const time = ts.slice(11, 23)\n const color = LEVEL_COLOR[level] ?? ''\n const label = LEVEL_LABEL[level] ?? level.toUpperCase()\n const metaStr = Object.keys(rest).length > 0 ? ` ${ANSI.dim}${flattenMeta(rest)}${ANSI.reset}` : ''\n\n return `${ANSI.dim}${time}${ANSI.reset} ${color}${label}${ANSI.reset} ${ANSI.cyan}[${scope}]${ANSI.reset} ${msg}${metaStr}`\n}\n\nfunction formatJson(entry: LogEntry): string {\n return JSON.stringify(entry)\n}\n\nfunction emit(level: LogLevel, formatted: string): void {\n switch (level) {\n case 'error':\n case 'fatal':\n console.error(formatted)\n break\n case 'warn':\n console.warn(formatted)\n break\n default:\n console.log(formatted)\n }\n}\n\nfunction buildLogger(\n scope: string,\n minLevel: LogLevel,\n baseMeta: Record<string, unknown>,\n formatter: (entry: LogEntry) => string,\n): Logger {\n let currentLevel = minLevel\n\n function log(level: LogLevel, msg: string, meta?: Record<string, unknown>): void {\n if (LEVEL_VALUE[level] < LEVEL_VALUE[currentLevel]) return\n\n const entry: LogEntry = {\n ts: new Date().toISOString(),\n level,\n scope,\n msg,\n ...baseMeta,\n ...meta,\n }\n\n emit(level, formatter(entry))\n }\n\n return {\n debug: (msg, meta?) => log('debug', msg, meta),\n info: (msg, meta?) => log('info', msg, meta),\n warn: (msg, meta?) => log('warn', msg, meta),\n error: (msg, meta?) => log('error', msg, meta),\n fatal: (msg, meta?) => log('fatal', msg, meta),\n\n child(childScope: string, childMeta?: Record<string, unknown>): Logger {\n return buildLogger(\n `${scope}:${childScope}`,\n currentLevel,\n { ...baseMeta, ...childMeta },\n formatter,\n )\n },\n\n setLevel(level: LogLevel) {\n currentLevel = level\n },\n }\n}\n\n/**\n * Create a structured logger instance.\n *\n * @example\n * const log = createLogger({ scope: 'mushi:api', level: 'info' })\n * log.info('Server started', { port: 3000 })\n *\n * const child = log.child('auth', { userId: 'u-123' })\n * child.warn('Token expired')\n */\nexport function createLogger(options: LoggerOptions): Logger {\n const {\n scope,\n level = 'info',\n meta = {},\n format = 'auto',\n } = options\n\n const resolvedFormat = format === 'auto' ? detectFormat() : format\n const formatter = resolvedFormat === 'json' ? formatJson : formatPretty\n\n return buildLogger(scope, level, meta, formatter)\n}\n\n/**\n * Noop logger that discards all output.\n * Useful when logging should be completely disabled.\n */\nexport const noopLogger: Logger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n fatal: () => {},\n child: () => noopLogger,\n setLevel: () => {},\n}\n","/**\n * AES-GCM at-rest encryption for the offline queue (Wave S1 / D-16).\n *\n * Why this exists: on shared devices (kiosks, support-agent laptops) a\n * queued bug report sits in plaintext IndexedDB until the next flush.\n * Browser extensions, other tabs on the same origin, and forensic tools\n * with disk access can all read it. For a QA/bug-reporting SDK that\n * encourages users to paste sensitive data into descriptions, that's\n * unacceptable.\n *\n * Design:\n * - Generate a non-extractable AES-GCM key on first call (256-bit).\n * - Persist the `CryptoKey` object itself (Web Crypto allows IDB round-\n * trip of `CryptoKey` without ever serialising the raw bytes).\n * - Use a 12-byte random IV per payload; prepend it to ciphertext so\n * decrypt() needs no out-of-band state.\n * - Never block the caller — all errors bubble up so the queue can fall\n * back to plaintext storage with a debug log (see queue.ts).\n *\n * The key is tied to the browser origin (same-origin IDB). It does NOT\n * protect against an attacker with admin shell on the device: the browser\n * WILL decrypt on demand for anyone with origin access. That's the same\n * guarantee every origin-bound browser secret has and is the correct\n * threat model for offline bug reports.\n */\n\nconst KEY_DB = 'mushi-mushi-keyring';\nconst KEY_STORE = 'keys';\nconst KEY_RECORD_ID = 'offline-queue/v1';\n\nlet cachedKey: CryptoKey | null = null;\nlet cachedKeyPromise: Promise<CryptoKey> | null = null;\n\nfunction hasWebCrypto(): boolean {\n return (\n typeof globalThis !== 'undefined' &&\n typeof (globalThis as unknown as { crypto?: Crypto }).crypto !== 'undefined' &&\n typeof (globalThis as unknown as { crypto: Crypto }).crypto.subtle !== 'undefined' &&\n typeof indexedDB !== 'undefined'\n );\n}\n\nfunction openKeyDb(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(KEY_DB, 1);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(KEY_STORE)) {\n db.createObjectStore(KEY_STORE);\n }\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n}\n\nasync function loadKey(): Promise<CryptoKey | null> {\n const db = await openKeyDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(KEY_STORE, 'readonly');\n const req = tx.objectStore(KEY_STORE).get(KEY_RECORD_ID);\n req.onsuccess = () => resolve((req.result as CryptoKey) ?? null);\n req.onerror = () => reject(req.error);\n });\n}\n\nasync function storeKey(key: CryptoKey): Promise<void> {\n const db = await openKeyDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(KEY_STORE, 'readwrite');\n tx.objectStore(KEY_STORE).put(key, KEY_RECORD_ID);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/**\n * Lazily get (or generate once + persist) the AES-GCM key for this origin.\n * `extractable: false` — so a script-level attacker can't `exportKey()` and\n * ship the raw bytes to their server, only use it via `encrypt`/`decrypt`.\n */\nexport async function getOfflineQueueKey(): Promise<CryptoKey> {\n if (cachedKey) return cachedKey;\n if (cachedKeyPromise) return cachedKeyPromise;\n if (!hasWebCrypto()) {\n throw new Error('Web Crypto + IndexedDB required for offline queue encryption');\n }\n cachedKeyPromise = (async () => {\n const existing = await loadKey();\n if (existing) {\n cachedKey = existing;\n return existing;\n }\n const key = await crypto.subtle.generateKey(\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt'],\n );\n await storeKey(key);\n cachedKey = key;\n return key;\n })();\n return cachedKeyPromise;\n}\n\nexport interface EncryptedPayload {\n /** Magic marker so decrypt() can tell encrypted vs legacy plaintext rows. */\n readonly _mme: 1;\n readonly iv: string;\n readonly ct: string;\n}\n\nfunction bytesToB64(bytes: Uint8Array): string {\n let s = '';\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s);\n}\n\nfunction b64ToBytes(s: string): Uint8Array<ArrayBuffer> {\n const bin = atob(s);\n const out = new Uint8Array(new ArrayBuffer(bin.length));\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\nexport async function encryptJson(plain: unknown): Promise<EncryptedPayload> {\n const key = await getOfflineQueueKey();\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const data = new TextEncoder().encode(JSON.stringify(plain));\n const cipher = new Uint8Array(await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, data));\n return { _mme: 1, iv: bytesToB64(iv), ct: bytesToB64(cipher) };\n}\n\nexport function isEncryptedPayload(v: unknown): v is EncryptedPayload {\n return (\n !!v &&\n typeof v === 'object' &&\n (v as EncryptedPayload)._mme === 1 &&\n typeof (v as EncryptedPayload).iv === 'string' &&\n typeof (v as EncryptedPayload).ct === 'string'\n );\n}\n\nexport async function decryptJson<T = unknown>(payload: EncryptedPayload): Promise<T> {\n const key = await getOfflineQueueKey();\n const iv = b64ToBytes(payload.iv);\n const ct = b64ToBytes(payload.ct);\n const plain = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ct);\n return JSON.parse(new TextDecoder().decode(plain)) as T;\n}\n","import type { MushiApiClient, MushiOfflineConfig, MushiReport } from './types';\nimport { createLogger } from './logger';\nimport {\n encryptJson,\n decryptJson,\n isEncryptedPayload,\n type EncryptedPayload,\n} from './queue-crypto';\n\nconst queueLog = createLogger({ scope: 'mushi:queue', level: 'warn' });\n\n// Wave S1 / D-16: opaque at-rest wrapper. Each queue row is either:\n// - a legacy plaintext `MushiReport` (pre-encryption; still readable)\n// - an `EncryptedRecord` with a bare `id` (so count / delete can operate\n// without decrypting every row) plus the encrypted payload blob.\ninterface EncryptedRecord {\n id: string;\n queuedAt: string;\n payload: EncryptedPayload;\n}\n\ntype StoredRow = MushiReport | EncryptedRecord;\n\nconst DB_NAME = 'mushi-mushi';\nconst STORE_NAME = 'offline-reports';\nconst DB_VERSION = 1;\nconst LS_KEY = 'mushi_offline_queue';\nconst BATCH_SIZE = 10;\nconst MAX_BACKOFF_MS = 60_000;\n\nexport interface OfflineQueue {\n enqueue(report: MushiReport): Promise<void>;\n flush(client: MushiApiClient): Promise<{ sent: number; failed: number }>;\n size(): Promise<number>;\n clear(): Promise<void>;\n startAutoSync(client: MushiApiClient): void;\n stopAutoSync(): void;\n}\n\ntype StorageBackend = 'indexeddb' | 'localstorage' | 'none';\n\nexport function createOfflineQueue(config: MushiOfflineConfig = {}): OfflineQueue {\n const { enabled = true, maxQueueSize = 50, syncOnReconnect = true, encryptAtRest = true } = config;\n\n let syncCleanup: (() => void) | null = null;\n let backendType: StorageBackend | null = null;\n\n async function wrapForStorage(report: MushiReport): Promise<StoredRow> {\n const queuedAt = new Date().toISOString();\n if (!encryptAtRest) {\n return { ...report, queuedAt } as MushiReport;\n }\n try {\n const payload = await encryptJson(report);\n return { id: report.id, queuedAt, payload } satisfies EncryptedRecord;\n } catch (err) {\n // Encryption failure is non-fatal — queue integrity matters more than\n // at-rest confidentiality. We fall back to plaintext and warn.\n queueLog.warn('Offline queue: encryption failed, storing plaintext', { err: String(err) });\n return { ...report, queuedAt } as MushiReport;\n }\n }\n\n async function unwrapForSend(row: StoredRow): Promise<MushiReport | null> {\n if (isEncryptedRecord(row)) {\n try {\n return await decryptJson<MushiReport>(row.payload);\n } catch (err) {\n queueLog.warn('Offline queue: decrypt failed, dropping row', { err: String(err), id: row.id });\n return null;\n }\n }\n return row;\n }\n\n function isEncryptedRecord(row: StoredRow): row is EncryptedRecord {\n return !!(row as EncryptedRecord).payload && isEncryptedPayload((row as EncryptedRecord).payload);\n }\n\n function detectBackend(): StorageBackend {\n if (backendType) return backendType;\n if (typeof indexedDB !== 'undefined') {\n backendType = 'indexeddb';\n } else if (typeof localStorage !== 'undefined') {\n backendType = 'localstorage';\n } else {\n backendType = 'none';\n }\n return backendType;\n }\n\n // --- IndexedDB backend ---\n\n function openDb(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { keyPath: 'id' });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => {\n backendType = 'localstorage';\n reject(request.error);\n };\n });\n }\n\n async function idbEnqueue(report: MushiReport): Promise<void> {\n const db = await openDb();\n const row = await wrapForStorage(report);\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).put(row);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n async function idbGetAll(): Promise<StoredRow[]> {\n const db = await openDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).getAll();\n request.onsuccess = () => resolve(request.result as StoredRow[]);\n request.onerror = () => reject(request.error);\n });\n }\n\n async function idbDelete(id: string): Promise<void> {\n const db = await openDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).delete(id);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n async function idbSize(): Promise<number> {\n const db = await openDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).count();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async function idbClear(): Promise<void> {\n const db = await openDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).clear();\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n // --- localStorage fallback ---\n\n function lsRead(): StoredRow[] {\n try {\n const raw = localStorage.getItem(LS_KEY);\n return raw ? (JSON.parse(raw) as StoredRow[]) : [];\n } catch {\n return [];\n }\n }\n\n function lsWrite(rows: StoredRow[]): void {\n try {\n localStorage.setItem(LS_KEY, JSON.stringify(rows));\n } catch {\n // localStorage full or unavailable\n }\n }\n\n async function lsEnqueue(report: MushiReport): Promise<void> {\n const rows = lsRead();\n rows.push(await wrapForStorage(report));\n lsWrite(rows);\n }\n\n function lsDelete(id: string): void {\n const rows = lsRead().filter((r) => r.id !== id);\n lsWrite(rows);\n }\n\n // --- Unified interface ---\n\n async function enqueue(report: MushiReport): Promise<void> {\n if (!enabled) return;\n\n const currentSize = await size();\n if (currentSize >= maxQueueSize) {\n queueLog.warn('Offline queue full — dropping report', { maxQueueSize });\n return;\n }\n\n const backend = detectBackend();\n if (backend === 'indexeddb') {\n try {\n await idbEnqueue(report);\n return;\n } catch {\n // IndexedDB failed, fall through to localStorage\n backendType = 'localstorage';\n }\n }\n\n if (backend === 'localstorage' || backendType === 'localstorage') {\n await lsEnqueue(report);\n return;\n }\n }\n\n function getBackoffDelay(attempt: number): number {\n return Math.min(1000 * 2 ** attempt + Math.random() * 500, MAX_BACKOFF_MS);\n }\n\n function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n async function flush(client: MushiApiClient): Promise<{ sent: number; failed: number }> {\n if (!enabled) return { sent: 0, failed: 0 };\n\n let rows: StoredRow[];\n const backend = detectBackend();\n\n if (backend === 'indexeddb') {\n try {\n rows = await idbGetAll();\n } catch {\n rows = lsRead();\n }\n } else {\n rows = lsRead();\n }\n\n const batch = rows.slice(0, BATCH_SIZE);\n let sent = 0;\n let failed = 0;\n\n for (let i = 0; i < batch.length; i++) {\n const row = batch[i];\n const rowId = (row as { id: string }).id;\n const report = await unwrapForSend(row);\n\n if (!report) {\n // Undecryptable row — drop so it doesn't re-poison the queue forever.\n try {\n if (backend === 'indexeddb') await idbDelete(rowId);\n else lsDelete(rowId);\n } catch {\n lsDelete(rowId);\n }\n failed++;\n continue;\n }\n\n const result = await client.submitReport(report);\n\n if (result.ok) {\n try {\n if (backend === 'indexeddb') await idbDelete(rowId);\n else lsDelete(rowId);\n } catch {\n lsDelete(rowId);\n }\n sent++;\n } else {\n failed++;\n if (i < batch.length - 1) {\n await sleep(getBackoffDelay(i));\n }\n }\n }\n\n return { sent, failed };\n }\n\n async function size(): Promise<number> {\n const backend = detectBackend();\n if (backend === 'indexeddb') {\n try {\n return await idbSize();\n } catch {\n return lsRead().length;\n }\n }\n return lsRead().length;\n }\n\n async function clear(): Promise<void> {\n const backend = detectBackend();\n if (backend === 'indexeddb') {\n try {\n await idbClear();\n } catch {\n // fall through\n }\n }\n try {\n localStorage.removeItem(LS_KEY);\n } catch {\n // unavailable\n }\n }\n\n function startAutoSync(client: MushiApiClient): void {\n if (!enabled || !syncOnReconnect || typeof window === 'undefined') return;\n\n const handler = () => {\n if (navigator.onLine) {\n flush(client).catch(() => {});\n }\n };\n\n window.addEventListener('online', handler);\n syncCleanup = () => window.removeEventListener('online', handler);\n }\n\n function stopAutoSync(): void {\n syncCleanup?.();\n syncCleanup = null;\n }\n\n return { enqueue, flush, size, clear, startAutoSync, stopAutoSync };\n}\n","import type { MushiEnvironment } from './types';\n\nexport function captureEnvironment(): MushiEnvironment {\n const nav = typeof navigator !== 'undefined' ? navigator : undefined;\n const win = typeof window !== 'undefined' ? window : undefined;\n const doc = typeof document !== 'undefined' ? document : undefined;\n\n const connection = nav && 'connection' in nav ? (nav as NavigatorWithConnection).connection : undefined;\n\n return {\n userAgent: nav?.userAgent ?? 'unknown',\n platform: nav?.platform ?? 'unknown',\n language: nav?.language ?? 'en',\n viewport: {\n width: win?.innerWidth ?? 0,\n height: win?.innerHeight ?? 0,\n },\n url: win?.location?.href ?? '',\n referrer: doc?.referrer ?? '',\n timestamp: new Date().toISOString(),\n timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone ?? 'UTC',\n connection: connection\n ? {\n effectiveType: connection.effectiveType,\n downlink: connection.downlink,\n rtt: connection.rtt,\n }\n : undefined,\n deviceMemory: (nav as NavigatorWithDeviceMemory)?.deviceMemory,\n hardwareConcurrency: nav?.hardwareConcurrency,\n };\n}\n\ninterface NetworkInformation {\n effectiveType?: string;\n downlink?: number;\n rtt?: number;\n}\n\ninterface NavigatorWithConnection extends Navigator {\n connection?: NetworkInformation;\n}\n\ninterface NavigatorWithDeviceMemory extends Navigator {\n deviceMemory?: number;\n}\n","const STORAGE_KEY = 'mushi_reporter_token';\n\nexport function getReporterToken(): string {\n if (typeof localStorage !== 'undefined') {\n const existing = localStorage.getItem(STORAGE_KEY);\n if (existing) return existing;\n }\n\n const token = generateToken();\n\n if (typeof localStorage !== 'undefined') {\n try {\n localStorage.setItem(STORAGE_KEY, token);\n } catch {\n // localStorage full or unavailable — token is ephemeral\n }\n }\n\n return token;\n}\n\nfunction generateToken(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return `mushi_${crypto.randomUUID()}`;\n }\n\n const bytes = new Uint8Array(16);\n if (typeof crypto !== 'undefined') {\n crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n\n const hex = Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return `mushi_${hex}`;\n}\n","/**\n * §3c — stable device fingerprint hash.\n *\n * Hashes a deliberately small set of long-lived device characteristics so\n * the same browser keeps the same hash across sessions, but moving to a\n * new browser/device produces a different one. This lets the server\n * detect cross-account abuse (same hash → many reporter accounts) without\n * needing fingerprint.js or any other entropy-heavy library.\n *\n * Privacy notes:\n * - We never send the raw inputs, only the SHA-256 hex digest.\n * - The set is intentionally low-entropy on purpose; this is \"is this the\n * same device\" not \"who is this user\". For high-stakes anti-fraud you\n * should still combine with server-side IP/geo signals.\n * - Cached in localStorage so subsequent calls are zero-cost.\n */\n\nconst CACHE_KEY = 'mushi_fingerprint_hash';\n\ninterface FingerprintInputs {\n userAgent: string;\n platform: string;\n language: string;\n timezone: string;\n screenWidth: number;\n screenHeight: number;\n pixelRatio: number;\n deviceMemory: number | undefined;\n hardwareConcurrency: number | undefined;\n}\n\nfunction collectInputs(): FingerprintInputs {\n const nav = typeof navigator !== 'undefined' ? navigator : undefined;\n const scr = typeof screen !== 'undefined' ? screen : undefined;\n const win = typeof window !== 'undefined' ? window : undefined;\n return {\n userAgent: nav?.userAgent ?? 'unknown',\n platform: nav?.platform ?? 'unknown',\n language: nav?.language ?? 'en',\n timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone ?? 'UTC',\n screenWidth: scr?.width ?? 0,\n screenHeight: scr?.height ?? 0,\n pixelRatio: win?.devicePixelRatio ?? 1,\n deviceMemory: (nav as NavigatorWithDeviceMemory | undefined)?.deviceMemory,\n hardwareConcurrency: nav?.hardwareConcurrency,\n };\n}\n\ninterface NavigatorWithDeviceMemory extends Navigator {\n deviceMemory?: number;\n}\n\nasync function sha256Hex(input: string): Promise<string> {\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n const buf = new TextEncoder().encode(input);\n const digest = await crypto.subtle.digest('SHA-256', buf);\n return Array.from(new Uint8Array(digest))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n }\n // Fallback (Node 18+ test envs, very old browsers): non-cryptographic but\n // good enough for the \"are these two requests from the same device\" use\n // case the server makes of this value.\n let hash = 0;\n for (let i = 0; i < input.length; i++) {\n hash = (hash << 5) - hash + input.charCodeAt(i);\n hash |= 0;\n }\n return `fbk_${(hash >>> 0).toString(16).padStart(8, '0')}`;\n}\n\n/**\n * Returns a stable per-device hash. Cached in localStorage; first call is\n * one SHA-256, subsequent calls are a localStorage read.\n *\n * Returns `null` outside browser-like environments (SSR, web workers\n * without crypto.subtle) so callers can omit the field gracefully.\n */\nexport async function getDeviceFingerprintHash(): Promise<string | null> {\n if (typeof localStorage !== 'undefined') {\n const cached = localStorage.getItem(CACHE_KEY);\n if (cached) return cached;\n }\n\n const inputs = collectInputs();\n const serialised = JSON.stringify(inputs);\n const hash = await sha256Hex(serialised);\n\n if (typeof localStorage !== 'undefined') {\n try {\n localStorage.setItem(CACHE_KEY, hash);\n } catch {\n // localStorage quota / private mode — caller still gets the hash.\n }\n }\n return hash;\n}\n\n/** Test/diagnostic helper — never include in shipped reports. */\nexport function _resetFingerprintCacheForTests(): void {\n if (typeof localStorage !== 'undefined') {\n try {\n localStorage.removeItem(CACHE_KEY);\n } catch {\n // ignore\n }\n }\n}\n","const SESSION_KEY = 'mushi_session_id';\n\nlet cachedSessionId: string | null = null;\n\nexport function getSessionId(): string {\n if (cachedSessionId) return cachedSessionId;\n\n if (typeof sessionStorage !== 'undefined') {\n const existing = sessionStorage.getItem(SESSION_KEY);\n if (existing) {\n cachedSessionId = existing;\n return existing;\n }\n }\n\n const id = generateSessionId();\n cachedSessionId = id;\n\n if (typeof sessionStorage !== 'undefined') {\n try {\n sessionStorage.setItem(SESSION_KEY, id);\n } catch {\n // sessionStorage unavailable\n }\n }\n\n return id;\n}\n\nfunction generateSessionId(): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).slice(2, 8);\n return `ms_${timestamp}_${random}`;\n}\n","export interface RateLimiterConfig {\n maxBurst?: number;\n refillRate?: number;\n refillIntervalMs?: number;\n}\n\nexport interface RateLimiter {\n tryConsume(): boolean;\n reset(): void;\n availableTokens(): number;\n}\n\nconst DEFAULT_MAX_BURST = 10;\nconst DEFAULT_REFILL_RATE = 1;\nconst DEFAULT_REFILL_INTERVAL_MS = 5_000;\n\nexport function createRateLimiter(config: RateLimiterConfig = {}): RateLimiter {\n const {\n maxBurst = DEFAULT_MAX_BURST,\n refillRate = DEFAULT_REFILL_RATE,\n refillIntervalMs = DEFAULT_REFILL_INTERVAL_MS,\n } = config;\n\n let tokens = maxBurst;\n let lastRefill = Date.now();\n\n function refill() {\n const now = Date.now();\n const elapsed = now - lastRefill;\n const refills = Math.floor(elapsed / refillIntervalMs);\n if (refills > 0) {\n tokens = Math.min(maxBurst, tokens + refills * refillRate);\n lastRefill = now;\n }\n }\n\n function tryConsume(): boolean {\n refill();\n if (tokens > 0) {\n tokens--;\n return true;\n }\n return false;\n }\n\n function reset(): void {\n tokens = maxBurst;\n lastRefill = Date.now();\n }\n\n function availableTokens(): number {\n refill();\n return tokens;\n }\n\n return { tryConsume, reset, availableTokens };\n}\n","export interface PiiScrubberConfig {\n emails?: boolean;\n phones?: boolean;\n creditCards?: boolean;\n ssns?: boolean;\n ipAddresses?: boolean;\n /**\n * Scrub vendor-shaped secret tokens (AWS access keys, Stripe keys,\n * Slack/GitHub PATs, OpenAI/Anthropic/Google keys, JWTs).\n *\n * Wave S1 / D-15: SDK parity with the server-side scrubber. The server\n * scrubs these on every LLM invocation; the SDK now scrubs them at\n * capture so they never hit the wire in the first place — important for\n * users who `console.log(stripeKey)` during dev and later ship bug\n * reports with the error text attached.\n */\n secretTokens?: boolean;\n /** IPv6 addresses. Defaults off for the same reason IPv4 does. */\n ipv6?: boolean;\n}\n\ninterface PiiPattern {\n key: keyof PiiScrubberConfig;\n regex: RegExp;\n replacement: string;\n}\n\n// Order matters: SSN → CC → vendor secrets → email → phone → IP. Secret\n// tokens are matched *before* the generic email/phone regex because some JWT\n// payloads contain `.` that could be mis-parsed as `xyz.abc.com`.\nconst ORDERED_PATTERNS: PiiPattern[] = [\n { key: 'ssns', regex: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g, replacement: '[REDACTED_SSN]' },\n { key: 'creditCards', regex: /\\b(?:\\d[ -]*){12,18}\\d\\b/g, replacement: '[REDACTED_CC]' },\n\n // Vendor secret tokens — mirrors packages/server/.../pii-scrubber.ts exactly.\n { key: 'secretTokens', regex: /\\b(?:AKIA|ASIA)[0-9A-Z]{16}\\b/g, replacement: '[REDACTED_AWS_KEY]' },\n { key: 'secretTokens', regex: /(?:aws_secret_access_key|secret_access_key)[\"'\\s:=]+[A-Za-z0-9/+=]{40}\\b/gi, replacement: 'aws_secret_access_key=[REDACTED_AWS_SECRET]' },\n { key: 'secretTokens', regex: /\\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\\b/g, replacement: '[REDACTED_STRIPE_KEY]' },\n { key: 'secretTokens', regex: /\\bpk_(?:live|test)_[A-Za-z0-9]{24,}\\b/g, replacement: '[REDACTED_STRIPE_PK]' },\n { key: 'secretTokens', regex: /\\bxox[abpor]-[A-Za-z0-9-]{10,}\\b/g, replacement: '[REDACTED_SLACK_TOKEN]' },\n { key: 'secretTokens', regex: /\\bghp_[A-Za-z0-9]{36}\\b/g, replacement: '[REDACTED_GITHUB_PAT]' },\n { key: 'secretTokens', regex: /\\bgithub_pat_[A-Za-z0-9_]{80,}\\b/g, replacement: '[REDACTED_GITHUB_PAT]' },\n { key: 'secretTokens', regex: /\\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\\b/g, replacement: '[REDACTED_OPENAI_KEY]' },\n { key: 'secretTokens', regex: /\\bsk-ant-[A-Za-z0-9_-]{20,}\\b/g, replacement: '[REDACTED_ANTHROPIC_KEY]' },\n { key: 'secretTokens', regex: /\\bAIza[0-9A-Za-z_-]{35}\\b/g, replacement: '[REDACTED_GOOGLE_KEY]' },\n { key: 'secretTokens', regex: /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/g, replacement: '[REDACTED_JWT]' },\n\n { key: 'emails', regex: /\\b[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}\\b/g, replacement: '[REDACTED_EMAIL]' },\n { key: 'phones', regex: /(?:\\+\\d{1,3}[\\s.-])?\\(?\\d{2,4}\\)?[\\s.-]\\d{3,4}[\\s.-]\\d{3,4}\\b/g, replacement: '[REDACTED_PHONE]' },\n { key: 'ipAddresses', regex: /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g, replacement: '[REDACTED_IP]' },\n { key: 'ipv6', regex: /\\b(?:[A-Fa-f0-9]{1,4}:){2,7}[A-Fa-f0-9]{0,4}\\b/g, replacement: '[REDACTED_IPV6]' },\n];\n\nconst DEFAULT_CONFIG: PiiScrubberConfig = {\n emails: true,\n phones: true,\n creditCards: true,\n ssns: true,\n ipAddresses: false,\n // Secret tokens default ON — if they leak into a bug report there's no\n // good reason to ship them to our servers. Cheaper to scrub client-side.\n secretTokens: true,\n ipv6: false,\n};\n\nexport function createPiiScrubber(config: PiiScrubberConfig = {}) {\n const merged = { ...DEFAULT_CONFIG, ...config };\n\n const activePatterns = ORDERED_PATTERNS.filter((p) => merged[p.key]);\n\n function scrub(text: string): string {\n if (!text) return text;\n let result = text;\n for (const { regex, replacement } of activePatterns) {\n result = result.replace(new RegExp(regex.source, regex.flags), replacement);\n }\n return result;\n }\n\n function scrubObject<T extends Record<string, unknown>>(obj: T, keys: string[]): T {\n const copy = { ...obj };\n for (const key of keys) {\n if (typeof copy[key] === 'string') {\n (copy as Record<string, unknown>)[key] = scrub(copy[key] as string);\n }\n }\n return copy;\n }\n\n return { scrub, scrubObject };\n}\n\nexport function scrubPii(text: string, config?: PiiScrubberConfig): string {\n return createPiiScrubber(config).scrub(text);\n}\n"]}
|