@mushi-mushi/core 0.2.0 → 0.2.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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Core types, API client, and utilities for the Mushi Mushi SDK.
4
4
 
5
+ > **You almost certainly don't need to install this directly.** Run `npx mushi-mushi` and the wizard will pick the right framework SDK ([`@mushi-mushi/react`](https://npmjs.com/package/@mushi-mushi/react), [`@mushi-mushi/vue`](https://npmjs.com/package/@mushi-mushi/vue), [`@mushi-mushi/svelte`](https://npmjs.com/package/@mushi-mushi/svelte), [`@mushi-mushi/angular`](https://npmjs.com/package/@mushi-mushi/angular), [`@mushi-mushi/react-native`](https://npmjs.com/package/@mushi-mushi/react-native), [`@mushi-mushi/capacitor`](https://npmjs.com/package/@mushi-mushi/capacitor), or [`@mushi-mushi/web`](https://npmjs.com/package/@mushi-mushi/web)) which depends on this package.
6
+
5
7
  ## What's Inside
6
8
 
7
9
  - **Types**: `MushiConfig`, `MushiReport`, `MushiEnvironment`, and all shared interfaces
package/dist/index.cjs CHANGED
@@ -622,6 +622,54 @@ function generateToken() {
622
622
  return `mushi_${hex}`;
623
623
  }
624
624
 
625
+ // src/fingerprint.ts
626
+ var CACHE_KEY = "mushi_fingerprint_hash";
627
+ function collectInputs() {
628
+ const nav = typeof navigator !== "undefined" ? navigator : void 0;
629
+ const scr = typeof screen !== "undefined" ? screen : void 0;
630
+ const win = typeof window !== "undefined" ? window : void 0;
631
+ return {
632
+ userAgent: nav?.userAgent ?? "unknown",
633
+ platform: nav?.platform ?? "unknown",
634
+ language: nav?.language ?? "en",
635
+ timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone ?? "UTC",
636
+ screenWidth: scr?.width ?? 0,
637
+ screenHeight: scr?.height ?? 0,
638
+ pixelRatio: win?.devicePixelRatio ?? 1,
639
+ deviceMemory: nav?.deviceMemory,
640
+ hardwareConcurrency: nav?.hardwareConcurrency
641
+ };
642
+ }
643
+ async function sha256Hex(input) {
644
+ if (typeof crypto !== "undefined" && crypto.subtle) {
645
+ const buf = new TextEncoder().encode(input);
646
+ const digest = await crypto.subtle.digest("SHA-256", buf);
647
+ return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
648
+ }
649
+ let hash = 0;
650
+ for (let i = 0; i < input.length; i++) {
651
+ hash = (hash << 5) - hash + input.charCodeAt(i);
652
+ hash |= 0;
653
+ }
654
+ return `fbk_${(hash >>> 0).toString(16).padStart(8, "0")}`;
655
+ }
656
+ async function getDeviceFingerprintHash() {
657
+ if (typeof localStorage !== "undefined") {
658
+ const cached = localStorage.getItem(CACHE_KEY);
659
+ if (cached) return cached;
660
+ }
661
+ const inputs = collectInputs();
662
+ const serialised = JSON.stringify(inputs);
663
+ const hash = await sha256Hex(serialised);
664
+ if (typeof localStorage !== "undefined") {
665
+ try {
666
+ localStorage.setItem(CACHE_KEY, hash);
667
+ } catch {
668
+ }
669
+ }
670
+ return hash;
671
+ }
672
+
625
673
  // src/session.ts
626
674
  var SESSION_KEY = "mushi_session_id";
627
675
  var cachedSessionId = null;
@@ -740,6 +788,7 @@ exports.createOfflineQueue = createOfflineQueue;
740
788
  exports.createPiiScrubber = createPiiScrubber;
741
789
  exports.createPreFilter = createPreFilter;
742
790
  exports.createRateLimiter = createRateLimiter;
791
+ exports.getDeviceFingerprintHash = getDeviceFingerprintHash;
743
792
  exports.getReporterToken = getReporterToken;
744
793
  exports.getSessionId = getSessionId;
745
794
  exports.noopLogger = noopLogger;
@@ -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/session.ts","../src/rate-limiter.ts","../src/pii-scrubber.ts"],"names":["getBackoffDelay","sleep"],"mappings":"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","file":"index.cjs","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","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.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":";;;AAgBO,IAAM,oBAAA,GAAuB;AACpC,IAAM,eAAA,GAAkB,GAAA;AACxB,IAAM,mBAAA,GAAsB,CAAA;AAErB,SAAS,gBAAgB,OAAA,EAA2C;AACzE,EAAA,MAAM;AAAA,IACJ,SAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA,GAAc,oBAAA;AAAA,IACd,OAAA,GAAU,eAAA;AAAA,IACV,UAAA,GAAa;AAAA,GACf,GAAI,OAAA;AAEJ,EAAA,IAAI,OAAA,GAAU,WAAA,CAAY,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAE3C,EAAA,eAAe,OAAA,CACb,MAAA,EACA,IAAA,EACA,IAAA,EACA,UAAU,UAAA,EACoB;AAC9B,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA;AAC7B,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE1D,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,QAChC,MAAA;AAAA,QACA,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,kBAAA;AAAA,UAChB,iBAAA,EAAmB,MAAA;AAAA,UACnB,iBAAA,EAAmB;AAAA,SACrB;AAAA,QACA,IAAA,EAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,GAAI,KAAA,CAAA;AAAA,QACpC,QAAQ,UAAA,CAAW;AAAA,OACpB,CAAA;AAED,MAAA,YAAA,CAAa,KAAK,CAAA;AAKlB,MAAA,IAAI,QAAA,CAAS,MAAA,KAAW,GAAA,IAAO,QAAA,CAAS,WAAW,GAAA,EAAK;AACtD,QAAA,MAAM,MAAA,GAAS,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA;AAC9C,QAAA,IAAI,MAAA,IAAU,UAAU,CAAA,EAAG;AACzB,UAAA,MAAM,UAAA,GAAa,OAAO,OAAA,CAAQ,WAAA,EAAa,EAAE,CAAA,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AACpE,UAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,YAAA,OAAA,GAAU,UAAA;AACV,YAAA,OAAO,OAAA,CAAW,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,UAAU,CAAC,CAAA;AAAA,UACnD;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AACxD,QAAA,IAAI,QAAA,CAAS,MAAA,IAAU,GAAA,IAAO,OAAA,GAAU,CAAA,EAAG;AACzC,UAAA,MAAM,KAAA,CAAM,eAAA,CAAgB,UAAA,GAAa,OAAO,CAAC,CAAA;AACjD,UAAA,OAAO,OAAA,CAAW,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,UAAU,CAAC,CAAA;AAAA,QACnD;AACA,QAAA,OAAO;AAAA,UACL,EAAA,EAAI,KAAA;AAAA,UACJ,KAAA,EAAO;AAAA,YACL,IAAA,EAAM,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA;AAAA,YAC7B,OAAA,EACG,SAAA,CAAmC,OAAA,IAAW,CAAA,KAAA,EAAQ,SAAS,MAAM,CAAA,MAAA;AAAA;AAC1E,SACF;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,IAAA,EAAK;AAAA,IAC1B,SAAS,KAAA,EAAO;AACd,MAAA,YAAA,CAAa,KAAK,CAAA;AAElB,MAAA,IAAI,OAAA,GAAU,CAAA,IAAK,WAAA,CAAY,KAAK,CAAA,EAAG;AACrC,QAAA,MAAM,KAAA,CAAM,eAAA,CAAgB,UAAA,GAAa,OAAO,CAAC,CAAA;AACjD,QAAA,OAAO,OAAA,CAAW,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,UAAU,CAAC,CAAA;AAAA,MACnD;AAEA,MAAA,OAAO;AAAA,QACL,EAAA,EAAI,KAAA;AAAA,QACJ,KAAA,EAAO;AAAA,UACL,IAAA,EAAM,eAAA;AAAA,UACN,OAAA,EAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA;AACpD,OACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,aAAa,MAAA,EAAqB;AACtC,MAAA,OAAO,OAAA,CAA8B,MAAA,EAAQ,aAAA,EAAe,MAAM,CAAA;AAAA,IACpE,CAAA;AAAA,IAEA,MAAM,gBAAgB,QAAA,EAAkB;AACtC,MAAA,OAAO,OAAA,CAAuC,KAAA,EAAO,CAAA,YAAA,EAAe,QAAQ,CAAA,OAAA,CAAS,CAAA;AAAA,IACvF;AAAA,GACF;AACF;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAEA,SAAS,gBAAgB,OAAA,EAAyB;AAChD,EAAA,OAAO,IAAA,CAAK,IAAI,GAAA,GAAO,CAAA,IAAK,UAAU,IAAA,CAAK,MAAA,EAAO,GAAI,GAAA,EAAK,GAAM,CAAA;AACnE;AAEA,SAAS,YAAY,KAAA,EAAyB;AAC5C,EAAA,IAAI,KAAA,YAAiB,YAAA,IAAgB,KAAA,CAAM,IAAA,KAAS,cAAc,OAAO,IAAA;AACzE,EAAA,IAAI,KAAA,YAAiB,WAAW,OAAO,IAAA;AACvC,EAAA,OAAO,KAAA;AACT;;;AC/GO,IAAM,gBAAA,GAAiE;AAAA,EAC5E,EAAA,EAAI,gDAAA;AAAA,EACJ,EAAA,EAAI,gDAAA;AAAA,EACJ,EAAA,EAAI;AACN;AAEA,IAAM,iBAAA,GAAoB,iBAAA;AAC1B,IAAM,oBAAA,GAAuB,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAA;AAgB5C,eAAsB,sBAAsB,IAAA,EAMxB;AAClB,EAAA,MAAM,WAAW,IAAA,CAAK,MAAA;AACtB,EAAA,IAAI,QAAA,IAAY,QAAA,KAAa,MAAA,IAAU,gBAAA,CAAiB,QAAQ,CAAA,EAAG;AACjE,IAAA,OAAO,iBAAiB,QAAQ,CAAA;AAAA,EAClC;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,IAAW,gBAAA,EAAiB;AACjD,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,OAAA,EAAS,IAAA,CAAK,SAAS,CAAA;AAChD,EAAA,IAAI,QAAQ,OAAO,MAAA;AAEnB,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,KAAA;AAChC,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAA,CAAK,WAAA,CAAY,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,8BAAA,EAAiC,kBAAA,CAAmB,IAAA,CAAK,SAAS,CAAC,CAAA,CAAA;AACrH,IAAA,MAAM,MAAM,MAAM,OAAA,CAAQ,KAAK,EAAE,MAAA,EAAQ,OAAO,CAAA;AAChD,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,EAAI,OAAO,IAAA,CAAK,WAAA;AACzB,IAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAC7B,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,IAAU,CAAC,IAAA,CAAK,QAAA,SAAiB,IAAA,CAAK,WAAA;AAChD,IAAA,UAAA,CAAW,OAAA,EAAS,IAAA,CAAK,SAAA,EAAW,EAAE,QAAQ,IAAA,CAAK,MAAA,EAAQ,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,EAAA,EAAI,IAAA,CAAK,GAAA,IAAO,CAAA;AACpG,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EACd;AACF;AAEA,SAAS,gBAAA,GAAwC;AAC/C,EAAA,IAAI;AACF,IAAA,OAAO,OAAO,UAAA,KAAe,WAAA,IAAe,cAAA,IAAkB,UAAA,GACzD,WAAyC,YAAA,GAC1C,KAAA,CAAA;AAAA,EACN,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,SAAS,SAAA,CAAU,SAA8B,SAAA,EAAkC;AACjF,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,IAAI;AACF,IAAA,MAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,GAAG,iBAAiB,CAAA,CAAA,EAAI,SAAS,CAAA,CAAE,CAAA;AAC/D,IAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,IAAI,KAAK,GAAA,EAAI,GAAI,MAAA,CAAO,EAAA,GAAK,sBAAsB,OAAO,IAAA;AAC1D,IAAA,OAAO,MAAA,CAAO,QAAA;AAAA,EAChB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,UAAA,CAAW,OAAA,EAA8B,SAAA,EAAmB,KAAA,EAA+B;AAClG,EAAA,IAAI,CAAC,OAAA,EAAS;AACd,EAAA,IAAI;AACF,IAAA,OAAA,CAAQ,OAAA,CAAQ,GAAG,iBAAiB,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,EAC5E,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;;;AC7FA,IAAM,kBAAA,GAAqB,EAAA;AAC3B,IAAM,kBAAA,GAAqB,GAAA;AAE3B,IAAM,aAAA,GAA0B;AAAA,EAC9B,cAAA;AAAA;AAAA,EACA,kBAAA;AAAA;AAAA,EACA,WAAA;AAAA;AAAA,EACA,sEAAA;AAAA;AAAA,EACA;AAAA;AACF,CAAA;AAEA,IAAM,iBAAA,GAAoB,8BAAA;AAEnB,SAAS,eAAA,CAAgB,MAAA,GAA+B,EAAC,EAAG;AACjE,EAAA,MAAM;AAAA,IACJ,OAAA,GAAU,IAAA;AAAA,IACV,gBAAA,GAAmB,IAAA;AAAA,IACnB,oBAAA,GAAuB,kBAAA;AAAA,IACvB,oBAAA,GAAuB;AAAA,GACzB,GAAI,MAAA;AAEJ,EAAA,SAAS,MAAM,WAAA,EAAsC;AACnD,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,EAAE,QAAQ,IAAA,EAAK;AAAA,IACxB;AAEA,IAAA,MAAM,OAAA,GAAU,YAAY,IAAA,EAAK;AAEjC,IAAA,IAAI,OAAA,CAAQ,SAAS,oBAAA,EAAsB;AACzC,MAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,CAAA,eAAA,EAAkB,oBAAoB,CAAA,YAAA,CAAA,EAAe;AAAA,IACvF;AAEA,IAAA,IAAI,OAAA,CAAQ,SAAS,oBAAA,EAAsB;AACzC,MAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,CAAA,cAAA,EAAiB,oBAAoB,CAAA,YAAA,CAAA,EAAe;AAAA,IACtF;AAEA,IAAA,IAAI,gBAAA,EAAkB;AACpB,MAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACnC,QAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAA,EAAG;AACzB,UAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,kBAAA,EAAmB;AAAA,QACrD;AAAA,MACF;AAEA,MAAA,IAAI,iBAAA,CAAkB,IAAA,CAAK,OAAO,CAAA,EAAG;AACnC,QAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,uBAAA,EAAwB;AAAA,MAC1D;AAEA,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,CAAE,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS,CAAC,CAAA;AAC7D,MAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,QAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,oCAAA,EAAqC;AAAA,MACvE;AAAA,IACF;AAEA,IAAA,OAAO,EAAE,QAAQ,IAAA,EAAK;AAAA,EACxB;AAEA,EAAA,SAAS,SAAS,WAAA,EAA6B;AAC7C,IAAA,MAAM,OAAA,GAAU,YAAY,IAAA,EAAK;AACjC,IAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,oBAAA,EAAsB,OAAO,OAAA;AACnD,IAAA,OAAO,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,oBAAoB,CAAA,GAAI,KAAA;AAAA,EAClD;AAEA,EAAA,OAAO,EAAE,OAAO,QAAA,EAAS;AAC3B;;;ACfA,IAAM,WAAA,GAAwC;AAAA,EAC5C,KAAA,EAAO,EAAA;AAAA,EACP,IAAA,EAAM,EAAA;AAAA,EACN,IAAA,EAAM,EAAA;AAAA,EACN,KAAA,EAAO,EAAA;AAAA,EACP,KAAA,EAAO,EAAA;AAAA,EACP,MAAA,EAAQ;AACV,CAAA;AAEA,IAAM,WAAA,GAAsC;AAAA,EAC1C,KAAA,EAAO,KAAA;AAAA,EACP,IAAA,EAAM,KAAA;AAAA,EACN,IAAA,EAAM,KAAA;AAAA,EACN,KAAA,EAAO,KAAA;AAAA,EACP,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,IAAA,GAAO;AAAA,EACX,KAAA,EAAO,SAAA;AAAA,EACP,GAAA,EAAK,SAAA;AAAA,EACL,IAAA,EAAM,SAAA;AAAA,EACN,IAAA,EAAM,UAAA;AAAA,EACN,KAAA,EAAO,UAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,GAAA,EAAK,UAAA;AAAA,EAEL,KAAA,EAAO,UAAA;AAAA,EACP,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,WAAA,GAAsC;AAAA,EAC1C,OAAO,IAAA,CAAK,GAAA;AAAA,EACZ,MAAM,IAAA,CAAK,KAAA;AAAA,EACX,MAAM,IAAA,CAAK,MAAA;AAAA,EACX,OAAO,IAAA,CAAK,GAAA;AAAA,EACZ,KAAA,EAAO,GAAG,IAAA,CAAK,KAAK,GAAG,IAAA,CAAK,KAAK,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA;AAC/C,CAAA;AAGA,SAAS,YAAA,GAAkC;AACzC,EAAA,IAAI;AACF,IAAA,IAAI,OAAQ,UAAA,CAAmB,IAAA,KAAS,WAAA,EAAa,OAAO,MAAA;AAAA,EAC9D,CAAA,CAAA,MAAQ;AAAA,EAAiB;AAEzB,EAAA,MAAM,OAAO,OAAQ,UAAA,CAAmB,OAAA,KAAY,WAAA,GAC/C,WAAmB,OAAA,GACpB,MAAA;AAEJ,EAAA,IAAI,MAAM,GAAA,EAAK;AACb,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,QAAA,KAAa,YAAA,EAAc,OAAO,MAAA;AAC/C,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,UAAA,KAAe,MAAA,EAAQ,OAAO,MAAA;AAC3C,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,UAAA,KAAe,QAAA,EAAU,OAAO,QAAA;AAC7C,IAAA,IAAI,IAAA,CAAK,MAAA,EAAQ,KAAA,EAAO,OAAO,QAAA;AAAA,EACjC;AAEA,EAAA,IAAI,OAAQ,UAAA,CAAmB,MAAA,KAAW,WAAA,EAAa,OAAO,QAAA;AAE9D,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,YAAY,IAAA,EAAuC;AAC1D,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA,EAAG;AACzC,IAAA,IAAI,CAAA,KAAM,MAAA,IAAa,CAAA,KAAM,IAAA,EAAM;AACnC,IAAA,IAAI,OAAO,MAAM,QAAA,EAAU;AACzB,MAAA,KAAA,CAAM,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,EAAI,KAAK,SAAA,CAAU,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,IACxC,CAAA,MAAO;AACL,MAAA,KAAA,CAAM,KAAK,CAAA,EAAG,CAAC,IAAI,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,IAChC;AAAA,EACF;AACA,EAAA,OAAO,KAAA,CAAM,KAAK,GAAG,CAAA;AACvB;AAEA,SAAS,aAAa,KAAA,EAAyB;AAC7C,EAAA,MAAM,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,GAAA,EAAK,GAAG,MAAK,GAAI,KAAA;AAC3C,EAAA,MAAM,IAAA,GAAO,EAAA,CAAG,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AAC5B,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,KAAK,CAAA,IAAK,EAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,KAAK,CAAA,IAAK,MAAM,WAAA,EAAY;AACtD,EAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,SAAS,CAAA,GAAI,CAAA,CAAA,EAAI,IAAA,CAAK,GAAG,GAAG,WAAA,CAAY,IAAI,CAAC,CAAA,EAAG,IAAA,CAAK,KAAK,CAAA,CAAA,GAAK,EAAA;AAEjG,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,GAAG,CAAA,EAAG,IAAI,CAAA,EAAG,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,EAAG,KAAK,CAAA,EAAG,KAAK,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA,EAAG,OAAO,CAAA,CAAA;AAC3H;AAEA,SAAS,WAAW,KAAA,EAAyB;AAC3C,EAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAC7B;AAEA,SAAS,IAAA,CAAK,OAAiB,SAAA,EAAyB;AACtD,EAAA,QAAQ,KAAA;AAAO,IACb,KAAK,OAAA;AAAA,IACL,KAAK,OAAA;AACH,MAAA,OAAA,CAAQ,MAAM,SAAS,CAAA;AACvB,MAAA;AAAA,IACF,KAAK,MAAA;AACH,MAAA,OAAA,CAAQ,KAAK,SAAS,CAAA;AACtB,MAAA;AAAA,IACF;AACE,MAAA,OAAA,CAAQ,IAAI,SAAS,CAAA;AAAA;AAE3B;AAEA,SAAS,WAAA,CACP,KAAA,EACA,QAAA,EACA,QAAA,EACA,SAAA,EACQ;AACR,EAAA,IAAI,YAAA,GAAe,QAAA;AAEnB,EAAA,SAAS,GAAA,CAAI,KAAA,EAAiB,GAAA,EAAa,IAAA,EAAsC;AAC/E,IAAA,IAAI,WAAA,CAAY,KAAK,CAAA,GAAI,WAAA,CAAY,YAAY,CAAA,EAAG;AAEpD,IAAA,MAAM,KAAA,GAAkB;AAAA,MACtB,EAAA,EAAA,iBAAI,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAC3B,KAAA;AAAA,MACA,KAAA;AAAA,MACA,GAAA;AAAA,MACA,GAAG,QAAA;AAAA,MACH,GAAG;AAAA,KACL;AAEA,IAAA,IAAA,CAAK,KAAA,EAAO,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,EAC9B;AAEA,EAAA,OAAO;AAAA,IACL,OAAO,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,OAAA,EAAS,KAAK,IAAI,CAAA;AAAA,IAC7C,MAAM,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAI,CAAA;AAAA,IAC3C,MAAM,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAI,CAAA;AAAA,IAC3C,OAAO,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,OAAA,EAAS,KAAK,IAAI,CAAA;AAAA,IAC7C,OAAO,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,OAAA,EAAS,KAAK,IAAI,CAAA;AAAA,IAE7C,KAAA,CAAM,YAAoB,SAAA,EAA6C;AACrE,MAAA,OAAO,WAAA;AAAA,QACL,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AAAA,QACtB,YAAA;AAAA,QACA,EAAE,GAAG,QAAA,EAAU,GAAG,SAAA,EAAU;AAAA,QAC5B;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IAEA,SAAS,KAAA,EAAiB;AACxB,MAAA,YAAA,GAAe,KAAA;AAAA,IACjB;AAAA,GACF;AACF;AAYO,SAAS,aAAa,OAAA,EAAgC;AAC3D,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,KAAA,GAAQ,MAAA;AAAA,IACR,OAAO,EAAC;AAAA,IACR,MAAA,GAAS;AAAA,GACX,GAAI,OAAA;AAEJ,EAAA,MAAM,cAAA,GAAiB,MAAA,KAAW,MAAA,GAAS,YAAA,EAAa,GAAI,MAAA;AAC5D,EAAA,MAAM,SAAA,GAAY,cAAA,KAAmB,MAAA,GAAS,UAAA,GAAa,YAAA;AAE3D,EAAA,OAAO,WAAA,CAAY,KAAA,EAAO,KAAA,EAAO,IAAA,EAAM,SAAS,CAAA;AAClD;AAMO,IAAM,UAAA,GAAqB;AAAA,EAChC,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,MAAM,MAAM;AAAA,EAAC,CAAA;AAAA,EACb,MAAM,MAAM;AAAA,EAAC,CAAA;AAAA,EACb,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,OAAO,MAAM,UAAA;AAAA,EACb,UAAU,MAAM;AAAA,EAAC;AACnB;;;AC3OA,IAAM,WAAW,YAAA,CAAa,EAAE,OAAO,aAAA,EAAe,KAAA,EAAO,QAAQ,CAAA;AAErE,IAAM,OAAA,GAAU,aAAA;AAChB,IAAM,UAAA,GAAa,iBAAA;AACnB,IAAM,UAAA,GAAa,CAAA;AACnB,IAAM,MAAA,GAAS,qBAAA;AACf,IAAM,UAAA,GAAa,EAAA;AACnB,IAAM,cAAA,GAAiB,GAAA;AAahB,SAAS,kBAAA,CAAmB,MAAA,GAA6B,EAAC,EAAiB;AAChF,EAAA,MAAM,EAAE,OAAA,GAAU,IAAA,EAAM,eAAe,EAAA,EAAI,eAAA,GAAkB,MAAK,GAAI,MAAA;AAEtE,EAAA,IAAI,WAAA,GAAmC,IAAA;AACvC,EAAA,IAAI,WAAA,GAAqC,IAAA;AAEzC,EAAA,SAAS,aAAA,GAAgC;AACvC,IAAA,IAAI,aAAa,OAAO,WAAA;AACxB,IAAA,IAAI,OAAO,cAAc,WAAA,EAAa;AACpC,MAAA,WAAA,GAAc,WAAA;AAAA,IAChB,CAAA,MAAA,IAAW,OAAO,YAAA,KAAiB,WAAA,EAAa;AAC9C,MAAA,WAAA,GAAc,cAAA;AAAA,IAChB,CAAA,MAAO;AACL,MAAA,WAAA,GAAc,MAAA;AAAA,IAChB;AACA,IAAA,OAAO,WAAA;AAAA,EACT;AAIA,EAAA,SAAS,MAAA,GAA+B;AACtC,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,OAAA,GAAU,SAAA,CAAU,IAAA,CAAK,OAAA,EAAS,UAAU,CAAA;AAClD,MAAA,OAAA,CAAQ,kBAAkB,MAAM;AAC9B,QAAA,MAAM,KAAK,OAAA,CAAQ,MAAA;AACnB,QAAA,IAAI,CAAC,EAAA,CAAG,gBAAA,CAAiB,QAAA,CAAS,UAAU,CAAA,EAAG;AAC7C,UAAA,EAAA,CAAG,iBAAA,CAAkB,UAAA,EAAY,EAAE,OAAA,EAAS,MAAM,CAAA;AAAA,QACpD;AAAA,MACF,CAAA;AACA,MAAA,OAAA,CAAQ,SAAA,GAAY,MAAM,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AAChD,MAAA,OAAA,CAAQ,UAAU,MAAM;AACtB,QAAA,WAAA,GAAc,cAAA;AACd,QAAA,MAAA,CAAO,QAAQ,KAAK,CAAA;AAAA,MACtB,CAAA;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,WAAW,MAAA,EAAoC;AAC5D,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,WAAW,CAAA;AACjD,MAAA,EAAA,CAAG,WAAA,CAAY,UAAU,CAAA,CAAE,GAAA,CAAI,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAA,iBAAU,IAAI,IAAA,EAAK,EAAE,WAAA,IAAe,CAAA;AAChF,MAAA,EAAA,CAAG,UAAA,GAAa,MAAM,OAAA,EAAQ;AAC9B,MAAA,EAAA,CAAG,OAAA,GAAU,MAAM,MAAA,CAAO,EAAA,CAAG,KAAK,CAAA;AAAA,IACpC,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,SAAA,GAAoC;AACjD,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,UAAU,CAAA;AAChD,MAAA,MAAM,OAAA,GAAU,EAAA,CAAG,WAAA,CAAY,UAAU,EAAE,MAAA,EAAO;AAClD,MAAA,OAAA,CAAQ,SAAA,GAAY,MAAM,OAAA,CAAQ,OAAA,CAAQ,MAAuB,CAAA;AACjE,MAAA,OAAA,CAAQ,OAAA,GAAU,MAAM,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAAA,IAC9C,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,UAAU,EAAA,EAA2B;AAClD,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,WAAW,CAAA;AACjD,MAAA,EAAA,CAAG,WAAA,CAAY,UAAU,CAAA,CAAE,MAAA,CAAO,EAAE,CAAA;AACpC,MAAA,EAAA,CAAG,UAAA,GAAa,MAAM,OAAA,EAAQ;AAC9B,MAAA,EAAA,CAAG,OAAA,GAAU,MAAM,MAAA,CAAO,EAAA,CAAG,KAAK,CAAA;AAAA,IACpC,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,OAAA,GAA2B;AACxC,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,UAAU,CAAA;AAChD,MAAA,MAAM,OAAA,GAAU,EAAA,CAAG,WAAA,CAAY,UAAU,EAAE,KAAA,EAAM;AACjD,MAAA,OAAA,CAAQ,SAAA,GAAY,MAAM,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AAChD,MAAA,OAAA,CAAQ,OAAA,GAAU,MAAM,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAAA,IAC9C,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,QAAA,GAA0B;AACvC,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,WAAW,CAAA;AACjD,MAAA,EAAA,CAAG,WAAA,CAAY,UAAU,CAAA,CAAE,KAAA,EAAM;AACjC,MAAA,EAAA,CAAG,UAAA,GAAa,MAAM,OAAA,EAAQ;AAC9B,MAAA,EAAA,CAAG,OAAA,GAAU,MAAM,MAAA,CAAO,EAAA,CAAG,KAAK,CAAA;AAAA,IACpC,CAAC,CAAA;AAAA,EACH;AAIA,EAAA,SAAS,MAAA,GAAwB;AAC/B,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,YAAA,CAAa,OAAA,CAAQ,MAAM,CAAA;AACvC,MAAA,OAAO,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAG,IAAI,EAAC;AAAA,IAClC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAC;AAAA,IACV;AAAA,EACF;AAEA,EAAA,SAAS,QAAQ,OAAA,EAA8B;AAC7C,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,OAAA,CAAQ,MAAA,EAAQ,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,IACtD,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,SAAS,UAAU,MAAA,EAA2B;AAC5C,IAAA,MAAM,UAAU,MAAA,EAAO;AACvB,IAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAA,qBAAc,IAAA,EAAK,EAAE,WAAA,EAAY,EAAkB,CAAA;AAC7E,IAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,EACjB;AAEA,EAAA,SAAS,SAAS,EAAA,EAAkB;AAClC,IAAA,MAAM,OAAA,GAAU,QAAO,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,EAAE,CAAA;AAClD,IAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,EACjB;AAIA,EAAA,eAAe,QAAQ,MAAA,EAAoC;AACzD,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,MAAM,WAAA,GAAc,MAAM,IAAA,EAAK;AAC/B,IAAA,IAAI,eAAe,YAAA,EAAc;AAC/B,MAAA,QAAA,CAAS,IAAA,CAAK,2CAAA,EAAwC,EAAE,YAAA,EAAc,CAAA;AACtE,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAU,aAAA,EAAc;AAC9B,IAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,MAAM,CAAA;AACvB,QAAA;AAAA,MACF,CAAA,CAAA,MAAQ;AAEN,QAAA,WAAA,GAAc,cAAA;AAAA,MAChB;AAAA,IACF;AAEA,IAAA,IAAI,OAAA,KAAY,cAAA,IAAkB,WAAA,KAAgB,cAAA,EAAgB;AAChE,MAAA,SAAA,CAAU,MAAM,CAAA;AAChB,MAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,SAASA,iBAAgB,OAAA,EAAyB;AAChD,IAAA,OAAO,IAAA,CAAK,IAAI,GAAA,GAAO,CAAA,IAAK,UAAU,IAAA,CAAK,MAAA,EAAO,GAAI,GAAA,EAAK,cAAc,CAAA;AAAA,EAC3E;AAEA,EAAA,SAASC,OAAM,EAAA,EAA2B;AACxC,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AAAA,EACzD;AAEA,EAAA,eAAe,MAAM,MAAA,EAAmE;AACtF,IAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAE,IAAA,EAAM,CAAA,EAAG,QAAQ,CAAA,EAAE;AAE1C,IAAA,IAAI,OAAA;AACJ,IAAA,MAAM,UAAU,aAAA,EAAc;AAE9B,IAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,MAAA,IAAI;AACF,QAAA,OAAA,GAAU,MAAM,SAAA,EAAU;AAAA,MAC5B,CAAA,CAAA,MAAQ;AACN,QAAA,OAAA,GAAU,MAAA,EAAO;AAAA,MACnB;AAAA,IACF,CAAA,MAAO;AACL,MAAA,OAAA,GAAU,MAAA,EAAO;AAAA,IACnB;AAEA,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,UAAU,CAAA;AACzC,IAAA,IAAI,IAAA,GAAO,CAAA;AACX,IAAA,IAAI,MAAA,GAAS,CAAA;AAEb,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,MAAA,MAAM,MAAA,GAAS,MAAM,CAAC,CAAA;AACtB,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,YAAA,CAAa,MAAM,CAAA;AAE/C,MAAA,IAAI,OAAO,EAAA,EAAI;AACb,QAAA,IAAI;AACF,UAAA,IAAI,OAAA,KAAY,WAAA,EAAa,MAAM,SAAA,CAAU,OAAO,EAAE,CAAA;AAAA,eACjD,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,QACzB,CAAA,CAAA,MAAQ;AACN,UAAA,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,QACpB;AACA,QAAA,IAAA,EAAA;AAAA,MACF,CAAA,MAAO;AACL,QAAA,MAAA,EAAA;AACA,QAAA,IAAI,CAAA,GAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AACxB,UAAA,MAAMA,MAAAA,CAAMD,gBAAAA,CAAgB,CAAC,CAAC,CAAA;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,EAAE,MAAM,MAAA,EAAO;AAAA,EACxB;AAEA,EAAA,eAAe,IAAA,GAAwB;AACrC,IAAA,MAAM,UAAU,aAAA,EAAc;AAC9B,IAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,OAAA,EAAQ;AAAA,MACvB,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,QAAO,CAAE,MAAA;AAAA,MAClB;AAAA,IACF;AACA,IAAA,OAAO,QAAO,CAAE,MAAA;AAAA,EAClB;AAEA,EAAA,eAAe,KAAA,GAAuB;AACpC,IAAA,MAAM,UAAU,aAAA,EAAc;AAC9B,IAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,EAAS;AAAA,MACjB,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AACA,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,WAAW,MAAM,CAAA;AAAA,IAChC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,SAAS,cAAc,MAAA,EAA8B;AACnD,IAAA,IAAI,CAAC,OAAA,IAAW,CAAC,eAAA,IAAmB,OAAO,WAAW,WAAA,EAAa;AAEnE,IAAA,MAAM,UAAU,MAAM;AACpB,MAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,QAAA,KAAA,CAAM,MAAM,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAAA,MAC9B;AAAA,IACF,CAAA;AAEA,IAAA,MAAA,CAAO,gBAAA,CAAiB,UAAU,OAAO,CAAA;AACzC,IAAA,WAAA,GAAc,MAAM,MAAA,CAAO,mBAAA,CAAoB,QAAA,EAAU,OAAO,CAAA;AAAA,EAClE;AAEA,EAAA,SAAS,YAAA,GAAqB;AAC5B,IAAA,WAAA,IAAc;AACd,IAAA,WAAA,GAAc,IAAA;AAAA,EAChB;AAEA,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,eAAe,YAAA,EAAa;AACpE;;;ACxQO,SAAS,kBAAA,GAAuC;AACrD,EAAA,MAAM,GAAA,GAAM,OAAO,SAAA,KAAc,WAAA,GAAc,SAAA,GAAY,MAAA;AAC3D,EAAA,MAAM,GAAA,GAAM,OAAO,MAAA,KAAW,WAAA,GAAc,MAAA,GAAS,MAAA;AACrD,EAAA,MAAM,GAAA,GAAM,OAAO,QAAA,KAAa,WAAA,GAAc,QAAA,GAAW,MAAA;AAEzD,EAAA,MAAM,UAAA,GAAa,GAAA,IAAO,YAAA,IAAgB,GAAA,GAAO,IAAgC,UAAA,GAAa,MAAA;AAE9F,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,KAAK,SAAA,IAAa,SAAA;AAAA,IAC7B,QAAA,EAAU,KAAK,QAAA,IAAY,SAAA;AAAA,IAC3B,QAAA,EAAU,KAAK,QAAA,IAAY,IAAA;AAAA,IAC3B,QAAA,EAAU;AAAA,MACR,KAAA,EAAO,KAAK,UAAA,IAAc,CAAA;AAAA,MAC1B,MAAA,EAAQ,KAAK,WAAA,IAAe;AAAA,KAC9B;AAAA,IACA,GAAA,EAAK,GAAA,EAAK,QAAA,EAAU,IAAA,IAAQ,EAAA;AAAA,IAC5B,QAAA,EAAU,KAAK,QAAA,IAAY,EAAA;AAAA,IAC3B,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IAClC,UAAU,IAAA,EAAM,cAAA,IAAiB,EAAG,eAAA,MAAqB,QAAA,IAAY,KAAA;AAAA,IACrE,YAAY,UAAA,GACR;AAAA,MACE,eAAe,UAAA,CAAW,aAAA;AAAA,MAC1B,UAAU,UAAA,CAAW,QAAA;AAAA,MACrB,KAAK,UAAA,CAAW;AAAA,KAClB,GACA,MAAA;AAAA,IACJ,cAAe,GAAA,EAAmC,YAAA;AAAA,IAClD,qBAAqB,GAAA,EAAK;AAAA,GAC5B;AACF;;;AC/BA,IAAM,WAAA,GAAc,sBAAA;AAEb,SAAS,gBAAA,GAA2B;AACzC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,MAAM,QAAA,GAAW,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAA;AACjD,IAAA,IAAI,UAAU,OAAO,QAAA;AAAA,EACvB;AAEA,EAAA,MAAM,QAAQ,aAAA,EAAc;AAE5B,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,OAAA,CAAQ,aAAa,KAAK,CAAA;AAAA,IACzC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,aAAA,GAAwB;AAC/B,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,UAAA,EAAY;AACtD,IAAA,OAAO,CAAA,MAAA,EAAS,MAAA,CAAO,UAAA,EAAY,CAAA,CAAA;AAAA,EACrC;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,EAAE,CAAA;AAC/B,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,IAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAAA,EAC9B,CAAA,MAAO;AACL,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,MAAA,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,CAAK,MAAM,IAAA,CAAK,MAAA,KAAW,GAAG,CAAA;AAAA,IAC3C;AAAA,EACF;AAEA,EAAA,MAAM,MAAM,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA,CACzB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAC1C,KAAK,EAAE,CAAA;AACV,EAAA,OAAO,SAAS,GAAG,CAAA,CAAA;AACrB;;;ACtBA,IAAM,SAAA,GAAY,wBAAA;AAclB,SAAS,aAAA,GAAmC;AAC1C,EAAA,MAAM,GAAA,GAAM,OAAO,SAAA,KAAc,WAAA,GAAc,SAAA,GAAY,MAAA;AAC3D,EAAA,MAAM,GAAA,GAAM,OAAO,MAAA,KAAW,WAAA,GAAc,MAAA,GAAS,MAAA;AACrD,EAAA,MAAM,GAAA,GAAM,OAAO,MAAA,KAAW,WAAA,GAAc,MAAA,GAAS,MAAA;AACrD,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,KAAK,SAAA,IAAa,SAAA;AAAA,IAC7B,QAAA,EAAU,KAAK,QAAA,IAAY,SAAA;AAAA,IAC3B,QAAA,EAAU,KAAK,QAAA,IAAY,IAAA;AAAA,IAC3B,UAAU,IAAA,EAAM,cAAA,IAAiB,EAAG,eAAA,MAAqB,QAAA,IAAY,KAAA;AAAA,IACrE,WAAA,EAAa,KAAK,KAAA,IAAS,CAAA;AAAA,IAC3B,YAAA,EAAc,KAAK,MAAA,IAAU,CAAA;AAAA,IAC7B,UAAA,EAAY,KAAK,gBAAA,IAAoB,CAAA;AAAA,IACrC,cAAe,GAAA,EAA+C,YAAA;AAAA,IAC9D,qBAAqB,GAAA,EAAK;AAAA,GAC5B;AACF;AAMA,eAAe,UAAU,KAAA,EAAgC;AACvD,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,MAAA,EAAQ;AAClD,IAAA,MAAM,GAAA,GAAM,IAAI,WAAA,EAAY,CAAE,OAAO,KAAK,CAAA;AAC1C,IAAA,MAAM,SAAS,MAAM,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,WAAW,GAAG,CAAA;AACxD,IAAA,OAAO,KAAA,CAAM,KAAK,IAAI,UAAA,CAAW,MAAM,CAAC,CAAA,CACrC,IAAI,CAAC,CAAA,KAAM,EAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAC1C,KAAK,EAAE,CAAA;AAAA,EACZ;AAIA,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,IAAA,GAAA,CAAQ,IAAA,IAAQ,CAAA,IAAK,IAAA,GAAO,KAAA,CAAM,WAAW,CAAC,CAAA;AAC9C,IAAA,IAAA,IAAQ,CAAA;AAAA,EACV;AACA,EAAA,OAAO,CAAA,IAAA,EAAA,CAAQ,SAAS,CAAA,EAAG,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAC1D;AASA,eAAsB,wBAAA,GAAmD;AACvE,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,OAAA,CAAQ,SAAS,CAAA;AAC7C,IAAA,IAAI,QAAQ,OAAO,MAAA;AAAA,EACrB;AAEA,EAAA,MAAM,SAAS,aAAA,EAAc;AAC7B,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,SAAA,CAAU,MAAM,CAAA;AACxC,EAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,UAAU,CAAA;AAEvC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,OAAA,CAAQ,WAAW,IAAI,CAAA;AAAA,IACtC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;;;AChGA,IAAM,WAAA,GAAc,kBAAA;AAEpB,IAAI,eAAA,GAAiC,IAAA;AAE9B,SAAS,YAAA,GAAuB;AACrC,EAAA,IAAI,iBAAiB,OAAO,eAAA;AAE5B,EAAA,IAAI,OAAO,mBAAmB,WAAA,EAAa;AACzC,IAAA,MAAM,QAAA,GAAW,cAAA,CAAe,OAAA,CAAQ,WAAW,CAAA;AACnD,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,eAAA,GAAkB,QAAA;AAClB,MAAA,OAAO,QAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,MAAM,KAAK,iBAAA,EAAkB;AAC7B,EAAA,eAAA,GAAkB,EAAA;AAElB,EAAA,IAAI,OAAO,mBAAmB,WAAA,EAAa;AACzC,IAAA,IAAI;AACF,MAAA,cAAA,CAAe,OAAA,CAAQ,aAAa,EAAE,CAAA;AAAA,IACxC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,OAAO,EAAA;AACT;AAEA,SAAS,iBAAA,GAA4B;AACnC,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,CAAE,SAAS,EAAE,CAAA;AACxC,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AACpD,EAAA,OAAO,CAAA,GAAA,EAAM,SAAS,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AAClC;;;ACrBA,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,0BAAA,GAA6B,GAAA;AAE5B,SAAS,iBAAA,CAAkB,MAAA,GAA4B,EAAC,EAAgB;AAC7E,EAAA,MAAM;AAAA,IACJ,QAAA,GAAW,iBAAA;AAAA,IACX,UAAA,GAAa,mBAAA;AAAA,IACb,gBAAA,GAAmB;AAAA,GACrB,GAAI,MAAA;AAEJ,EAAA,IAAI,MAAA,GAAS,QAAA;AACb,EAAA,IAAI,UAAA,GAAa,KAAK,GAAA,EAAI;AAE1B,EAAA,SAAS,MAAA,GAAS;AAChB,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,MAAM,UAAU,GAAA,GAAM,UAAA;AACtB,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,gBAAgB,CAAA;AACrD,IAAA,IAAI,UAAU,CAAA,EAAG;AACf,MAAA,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,QAAA,EAAU,MAAA,GAAS,UAAU,UAAU,CAAA;AACzD,MAAA,UAAA,GAAa,GAAA;AAAA,IACf;AAAA,EACF;AAEA,EAAA,SAAS,UAAA,GAAsB;AAC7B,IAAA,MAAA,EAAO;AACP,IAAA,IAAI,SAAS,CAAA,EAAG;AACd,MAAA,MAAA,EAAA;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,SAAS,KAAA,GAAc;AACrB,IAAA,MAAA,GAAS,QAAA;AACT,IAAA,UAAA,GAAa,KAAK,GAAA,EAAI;AAAA,EACxB;AAEA,EAAA,SAAS,eAAA,GAA0B;AACjC,IAAA,MAAA,EAAO;AACP,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAE,UAAA,EAAY,KAAA,EAAO,eAAA,EAAgB;AAC9C;;;ACxCA,IAAM,gBAAA,GAAiC;AAAA,EACrC,EAAE,GAAA,EAAK,MAAA,EAAQ,KAAA,EAAO,wBAAA,EAA0B,aAAa,gBAAA,EAAiB;AAAA,EAC9E,EAAE,GAAA,EAAK,aAAA,EAAe,KAAA,EAAO,2BAAA,EAA6B,aAAa,eAAA,EAAgB;AAAA,EACvF,EAAE,GAAA,EAAK,QAAA,EAAU,KAAA,EAAO,uDAAA,EAAyD,aAAa,kBAAA,EAAmB;AAAA,EACjH,EAAE,GAAA,EAAK,QAAA,EAAU,KAAA,EAAO,gEAAA,EAAkE,aAAa,kBAAA,EAAmB;AAAA,EAC1H,EAAE,GAAA,EAAK,aAAA,EAAe,KAAA,EAAO,8BAAA,EAAgC,aAAa,eAAA;AAC5E,CAAA;AAEA,IAAM,cAAA,GAAoC;AAAA,EACxC,MAAA,EAAQ,IAAA;AAAA,EACR,MAAA,EAAQ,IAAA;AAAA,EACR,WAAA,EAAa,IAAA;AAAA,EACb,IAAA,EAAM,IAAA;AAAA,EACN,WAAA,EAAa;AACf,CAAA;AAEO,SAAS,iBAAA,CAAkB,MAAA,GAA4B,EAAC,EAAG;AAChE,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,cAAA,EAAgB,GAAG,MAAA,EAAO;AAE9C,EAAA,MAAM,cAAA,GAAiB,iBAAiB,MAAA,CAAO,CAAC,MAAM,MAAA,CAAO,CAAA,CAAE,GAAG,CAAC,CAAA;AAEnE,EAAA,SAAS,MAAM,IAAA,EAAsB;AACnC,IAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,IAAA,IAAI,MAAA,GAAS,IAAA;AACb,IAAA,KAAA,MAAW,EAAE,KAAA,EAAO,WAAA,EAAY,IAAK,cAAA,EAAgB;AACnD,MAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,IAAI,MAAA,CAAO,MAAM,MAAA,EAAQ,KAAA,CAAM,KAAK,CAAA,EAAG,WAAW,CAAA;AAAA,IAC5E;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,SAAS,WAAA,CAA+C,KAAQ,IAAA,EAAmB;AACjF,IAAA,MAAM,IAAA,GAAO,EAAE,GAAG,GAAA,EAAI;AACtB,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,IAAI,OAAO,IAAA,CAAK,GAAG,CAAA,KAAM,QAAA,EAAU;AACjC,QAAC,KAAiC,GAAG,CAAA,GAAI,KAAA,CAAM,IAAA,CAAK,GAAG,CAAW,CAAA;AAAA,MACpE;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAE,OAAO,WAAA,EAAY;AAC9B;AAEO,SAAS,QAAA,CAAS,MAAc,MAAA,EAAoC;AACzE,EAAA,OAAO,iBAAA,CAAkB,MAAM,CAAA,CAAE,KAAA,CAAM,IAAI,CAAA;AAC7C","file":"index.cjs","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"]}
package/dist/index.d.cts CHANGED
@@ -119,6 +119,12 @@ interface MushiReport {
119
119
  metadata?: Record<string, unknown>;
120
120
  sessionId?: string;
121
121
  reporterToken: string;
122
+ /**
123
+ * Wave E §3c — stable per-device hash from `getDeviceFingerprintHash()`.
124
+ * Sent so the server can run the cross-account anti-gaming check; falls
125
+ * back to IP+UA fingerprinting when omitted.
126
+ */
127
+ fingerprintHash?: string;
122
128
  appVersion?: string;
123
129
  proactiveTrigger?: string;
124
130
  sentryEventId?: string;
@@ -299,6 +305,31 @@ declare function captureEnvironment(): MushiEnvironment;
299
305
 
300
306
  declare function getReporterToken(): string;
301
307
 
308
+ /**
309
+ * Wave E §3c — stable device fingerprint hash.
310
+ *
311
+ * Hashes a deliberately small set of long-lived device characteristics so
312
+ * the same browser keeps the same hash across sessions, but moving to a
313
+ * new browser/device produces a different one. This lets the server
314
+ * detect cross-account abuse (same hash → many reporter accounts) without
315
+ * needing fingerprint.js or any other entropy-heavy library.
316
+ *
317
+ * Privacy notes:
318
+ * - We never send the raw inputs, only the SHA-256 hex digest.
319
+ * - The set is intentionally low-entropy on purpose; this is "is this the
320
+ * same device" not "who is this user". For high-stakes anti-fraud you
321
+ * should still combine with server-side IP/geo signals.
322
+ * - Cached in localStorage so subsequent calls are zero-cost.
323
+ */
324
+ /**
325
+ * Returns a stable per-device hash. Cached in localStorage; first call is
326
+ * one SHA-256, subsequent calls are a localStorage read.
327
+ *
328
+ * Returns `null` outside browser-like environments (SSR, web workers
329
+ * without crypto.subtle) so callers can omit the field gracefully.
330
+ */
331
+ declare function getDeviceFingerprintHash(): Promise<string | null>;
332
+
302
333
  declare function getSessionId(): string;
303
334
 
304
335
  interface RateLimiterConfig {
@@ -392,4 +423,4 @@ declare function createLogger(options: LoggerOptions): Logger;
392
423
  */
393
424
  declare const noopLogger: Logger;
394
425
 
395
- export { type ApiClientOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, type MushiApiClient, type MushiApiResponse, type MushiCaptureConfig, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiIntegrationsConfig, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiRewardsConfig, type MushiSDKInstance, type MushiSelectedElement, type MushiSentryConfig, type MushiWidgetConfig, type OfflineQueue, type PiiScrubberConfig, type PreFilterResult, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, captureEnvironment, createApiClient, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, getReporterToken, getSessionId, noopLogger, resolveRegionEndpoint, scrubPii };
426
+ export { type ApiClientOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, type MushiApiClient, type MushiApiResponse, type MushiCaptureConfig, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiIntegrationsConfig, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiRewardsConfig, type MushiSDKInstance, type MushiSelectedElement, type MushiSentryConfig, type MushiWidgetConfig, type OfflineQueue, type PiiScrubberConfig, type PreFilterResult, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, captureEnvironment, createApiClient, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, getDeviceFingerprintHash, getReporterToken, getSessionId, noopLogger, resolveRegionEndpoint, scrubPii };
package/dist/index.d.ts CHANGED
@@ -119,6 +119,12 @@ interface MushiReport {
119
119
  metadata?: Record<string, unknown>;
120
120
  sessionId?: string;
121
121
  reporterToken: string;
122
+ /**
123
+ * Wave E §3c — stable per-device hash from `getDeviceFingerprintHash()`.
124
+ * Sent so the server can run the cross-account anti-gaming check; falls
125
+ * back to IP+UA fingerprinting when omitted.
126
+ */
127
+ fingerprintHash?: string;
122
128
  appVersion?: string;
123
129
  proactiveTrigger?: string;
124
130
  sentryEventId?: string;
@@ -299,6 +305,31 @@ declare function captureEnvironment(): MushiEnvironment;
299
305
 
300
306
  declare function getReporterToken(): string;
301
307
 
308
+ /**
309
+ * Wave E §3c — stable device fingerprint hash.
310
+ *
311
+ * Hashes a deliberately small set of long-lived device characteristics so
312
+ * the same browser keeps the same hash across sessions, but moving to a
313
+ * new browser/device produces a different one. This lets the server
314
+ * detect cross-account abuse (same hash → many reporter accounts) without
315
+ * needing fingerprint.js or any other entropy-heavy library.
316
+ *
317
+ * Privacy notes:
318
+ * - We never send the raw inputs, only the SHA-256 hex digest.
319
+ * - The set is intentionally low-entropy on purpose; this is "is this the
320
+ * same device" not "who is this user". For high-stakes anti-fraud you
321
+ * should still combine with server-side IP/geo signals.
322
+ * - Cached in localStorage so subsequent calls are zero-cost.
323
+ */
324
+ /**
325
+ * Returns a stable per-device hash. Cached in localStorage; first call is
326
+ * one SHA-256, subsequent calls are a localStorage read.
327
+ *
328
+ * Returns `null` outside browser-like environments (SSR, web workers
329
+ * without crypto.subtle) so callers can omit the field gracefully.
330
+ */
331
+ declare function getDeviceFingerprintHash(): Promise<string | null>;
332
+
302
333
  declare function getSessionId(): string;
303
334
 
304
335
  interface RateLimiterConfig {
@@ -392,4 +423,4 @@ declare function createLogger(options: LoggerOptions): Logger;
392
423
  */
393
424
  declare const noopLogger: Logger;
394
425
 
395
- export { type ApiClientOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, type MushiApiClient, type MushiApiResponse, type MushiCaptureConfig, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiIntegrationsConfig, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiRewardsConfig, type MushiSDKInstance, type MushiSelectedElement, type MushiSentryConfig, type MushiWidgetConfig, type OfflineQueue, type PiiScrubberConfig, type PreFilterResult, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, captureEnvironment, createApiClient, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, getReporterToken, getSessionId, noopLogger, resolveRegionEndpoint, scrubPii };
426
+ export { type ApiClientOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, type MushiApiClient, type MushiApiResponse, type MushiCaptureConfig, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiIntegrationsConfig, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiRewardsConfig, type MushiSDKInstance, type MushiSelectedElement, type MushiSentryConfig, type MushiWidgetConfig, type OfflineQueue, type PiiScrubberConfig, type PreFilterResult, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, captureEnvironment, createApiClient, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, getDeviceFingerprintHash, getReporterToken, getSessionId, noopLogger, resolveRegionEndpoint, scrubPii };
package/dist/index.js CHANGED
@@ -620,6 +620,54 @@ function generateToken() {
620
620
  return `mushi_${hex}`;
621
621
  }
622
622
 
623
+ // src/fingerprint.ts
624
+ var CACHE_KEY = "mushi_fingerprint_hash";
625
+ function collectInputs() {
626
+ const nav = typeof navigator !== "undefined" ? navigator : void 0;
627
+ const scr = typeof screen !== "undefined" ? screen : void 0;
628
+ const win = typeof window !== "undefined" ? window : void 0;
629
+ return {
630
+ userAgent: nav?.userAgent ?? "unknown",
631
+ platform: nav?.platform ?? "unknown",
632
+ language: nav?.language ?? "en",
633
+ timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone ?? "UTC",
634
+ screenWidth: scr?.width ?? 0,
635
+ screenHeight: scr?.height ?? 0,
636
+ pixelRatio: win?.devicePixelRatio ?? 1,
637
+ deviceMemory: nav?.deviceMemory,
638
+ hardwareConcurrency: nav?.hardwareConcurrency
639
+ };
640
+ }
641
+ async function sha256Hex(input) {
642
+ if (typeof crypto !== "undefined" && crypto.subtle) {
643
+ const buf = new TextEncoder().encode(input);
644
+ const digest = await crypto.subtle.digest("SHA-256", buf);
645
+ return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
646
+ }
647
+ let hash = 0;
648
+ for (let i = 0; i < input.length; i++) {
649
+ hash = (hash << 5) - hash + input.charCodeAt(i);
650
+ hash |= 0;
651
+ }
652
+ return `fbk_${(hash >>> 0).toString(16).padStart(8, "0")}`;
653
+ }
654
+ async function getDeviceFingerprintHash() {
655
+ if (typeof localStorage !== "undefined") {
656
+ const cached = localStorage.getItem(CACHE_KEY);
657
+ if (cached) return cached;
658
+ }
659
+ const inputs = collectInputs();
660
+ const serialised = JSON.stringify(inputs);
661
+ const hash = await sha256Hex(serialised);
662
+ if (typeof localStorage !== "undefined") {
663
+ try {
664
+ localStorage.setItem(CACHE_KEY, hash);
665
+ } catch {
666
+ }
667
+ }
668
+ return hash;
669
+ }
670
+
623
671
  // src/session.ts
624
672
  var SESSION_KEY = "mushi_session_id";
625
673
  var cachedSessionId = null;
@@ -729,6 +777,6 @@ function scrubPii(text, config) {
729
777
  return createPiiScrubber(config).scrub(text);
730
778
  }
731
779
 
732
- export { DEFAULT_API_ENDPOINT, REGION_ENDPOINTS, captureEnvironment, createApiClient, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, getReporterToken, getSessionId, noopLogger, resolveRegionEndpoint, scrubPii };
780
+ export { DEFAULT_API_ENDPOINT, REGION_ENDPOINTS, captureEnvironment, createApiClient, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, getDeviceFingerprintHash, getReporterToken, getSessionId, noopLogger, resolveRegionEndpoint, scrubPii };
733
781
  //# sourceMappingURL=index.js.map
734
782
  //# sourceMappingURL=index.js.map
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/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","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.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":";AAgBO,IAAM,oBAAA,GAAuB;AACpC,IAAM,eAAA,GAAkB,GAAA;AACxB,IAAM,mBAAA,GAAsB,CAAA;AAErB,SAAS,gBAAgB,OAAA,EAA2C;AACzE,EAAA,MAAM;AAAA,IACJ,SAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA,GAAc,oBAAA;AAAA,IACd,OAAA,GAAU,eAAA;AAAA,IACV,UAAA,GAAa;AAAA,GACf,GAAI,OAAA;AAEJ,EAAA,IAAI,OAAA,GAAU,WAAA,CAAY,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAE3C,EAAA,eAAe,OAAA,CACb,MAAA,EACA,IAAA,EACA,IAAA,EACA,UAAU,UAAA,EACoB;AAC9B,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA;AAC7B,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE1D,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,QAChC,MAAA;AAAA,QACA,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,kBAAA;AAAA,UAChB,iBAAA,EAAmB,MAAA;AAAA,UACnB,iBAAA,EAAmB;AAAA,SACrB;AAAA,QACA,IAAA,EAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,GAAI,KAAA,CAAA;AAAA,QACpC,QAAQ,UAAA,CAAW;AAAA,OACpB,CAAA;AAED,MAAA,YAAA,CAAa,KAAK,CAAA;AAKlB,MAAA,IAAI,QAAA,CAAS,MAAA,KAAW,GAAA,IAAO,QAAA,CAAS,WAAW,GAAA,EAAK;AACtD,QAAA,MAAM,MAAA,GAAS,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA;AAC9C,QAAA,IAAI,MAAA,IAAU,UAAU,CAAA,EAAG;AACzB,UAAA,MAAM,UAAA,GAAa,OAAO,OAAA,CAAQ,WAAA,EAAa,EAAE,CAAA,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AACpE,UAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,YAAA,OAAA,GAAU,UAAA;AACV,YAAA,OAAO,OAAA,CAAW,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,UAAU,CAAC,CAAA;AAAA,UACnD;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AACxD,QAAA,IAAI,QAAA,CAAS,MAAA,IAAU,GAAA,IAAO,OAAA,GAAU,CAAA,EAAG;AACzC,UAAA,MAAM,KAAA,CAAM,eAAA,CAAgB,UAAA,GAAa,OAAO,CAAC,CAAA;AACjD,UAAA,OAAO,OAAA,CAAW,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,UAAU,CAAC,CAAA;AAAA,QACnD;AACA,QAAA,OAAO;AAAA,UACL,EAAA,EAAI,KAAA;AAAA,UACJ,KAAA,EAAO;AAAA,YACL,IAAA,EAAM,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA;AAAA,YAC7B,OAAA,EACG,SAAA,CAAmC,OAAA,IAAW,CAAA,KAAA,EAAQ,SAAS,MAAM,CAAA,MAAA;AAAA;AAC1E,SACF;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,IAAA,EAAK;AAAA,IAC1B,SAAS,KAAA,EAAO;AACd,MAAA,YAAA,CAAa,KAAK,CAAA;AAElB,MAAA,IAAI,OAAA,GAAU,CAAA,IAAK,WAAA,CAAY,KAAK,CAAA,EAAG;AACrC,QAAA,MAAM,KAAA,CAAM,eAAA,CAAgB,UAAA,GAAa,OAAO,CAAC,CAAA;AACjD,QAAA,OAAO,OAAA,CAAW,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,UAAU,CAAC,CAAA;AAAA,MACnD;AAEA,MAAA,OAAO;AAAA,QACL,EAAA,EAAI,KAAA;AAAA,QACJ,KAAA,EAAO;AAAA,UACL,IAAA,EAAM,eAAA;AAAA,UACN,OAAA,EAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA;AACpD,OACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,aAAa,MAAA,EAAqB;AACtC,MAAA,OAAO,OAAA,CAA8B,MAAA,EAAQ,aAAA,EAAe,MAAM,CAAA;AAAA,IACpE,CAAA;AAAA,IAEA,MAAM,gBAAgB,QAAA,EAAkB;AACtC,MAAA,OAAO,OAAA,CAAuC,KAAA,EAAO,CAAA,YAAA,EAAe,QAAQ,CAAA,OAAA,CAAS,CAAA;AAAA,IACvF;AAAA,GACF;AACF;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAEA,SAAS,gBAAgB,OAAA,EAAyB;AAChD,EAAA,OAAO,IAAA,CAAK,IAAI,GAAA,GAAO,CAAA,IAAK,UAAU,IAAA,CAAK,MAAA,EAAO,GAAI,GAAA,EAAK,GAAM,CAAA;AACnE;AAEA,SAAS,YAAY,KAAA,EAAyB;AAC5C,EAAA,IAAI,KAAA,YAAiB,YAAA,IAAgB,KAAA,CAAM,IAAA,KAAS,cAAc,OAAO,IAAA;AACzE,EAAA,IAAI,KAAA,YAAiB,WAAW,OAAO,IAAA;AACvC,EAAA,OAAO,KAAA;AACT;;;AC/GO,IAAM,gBAAA,GAAiE;AAAA,EAC5E,EAAA,EAAI,gDAAA;AAAA,EACJ,EAAA,EAAI,gDAAA;AAAA,EACJ,EAAA,EAAI;AACN;AAEA,IAAM,iBAAA,GAAoB,iBAAA;AAC1B,IAAM,oBAAA,GAAuB,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAA;AAgB5C,eAAsB,sBAAsB,IAAA,EAMxB;AAClB,EAAA,MAAM,WAAW,IAAA,CAAK,MAAA;AACtB,EAAA,IAAI,QAAA,IAAY,QAAA,KAAa,MAAA,IAAU,gBAAA,CAAiB,QAAQ,CAAA,EAAG;AACjE,IAAA,OAAO,iBAAiB,QAAQ,CAAA;AAAA,EAClC;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,IAAW,gBAAA,EAAiB;AACjD,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,OAAA,EAAS,IAAA,CAAK,SAAS,CAAA;AAChD,EAAA,IAAI,QAAQ,OAAO,MAAA;AAEnB,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,KAAA;AAChC,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAA,CAAK,WAAA,CAAY,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,8BAAA,EAAiC,kBAAA,CAAmB,IAAA,CAAK,SAAS,CAAC,CAAA,CAAA;AACrH,IAAA,MAAM,MAAM,MAAM,OAAA,CAAQ,KAAK,EAAE,MAAA,EAAQ,OAAO,CAAA;AAChD,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,EAAI,OAAO,IAAA,CAAK,WAAA;AACzB,IAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAC7B,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,IAAU,CAAC,IAAA,CAAK,QAAA,SAAiB,IAAA,CAAK,WAAA;AAChD,IAAA,UAAA,CAAW,OAAA,EAAS,IAAA,CAAK,SAAA,EAAW,EAAE,QAAQ,IAAA,CAAK,MAAA,EAAQ,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,EAAA,EAAI,IAAA,CAAK,GAAA,IAAO,CAAA;AACpG,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EACd;AACF;AAEA,SAAS,gBAAA,GAAwC;AAC/C,EAAA,IAAI;AACF,IAAA,OAAO,OAAO,UAAA,KAAe,WAAA,IAAe,cAAA,IAAkB,UAAA,GACzD,WAAyC,YAAA,GAC1C,KAAA,CAAA;AAAA,EACN,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,SAAS,SAAA,CAAU,SAA8B,SAAA,EAAkC;AACjF,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,IAAI;AACF,IAAA,MAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,GAAG,iBAAiB,CAAA,CAAA,EAAI,SAAS,CAAA,CAAE,CAAA;AAC/D,IAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,IAAI,KAAK,GAAA,EAAI,GAAI,MAAA,CAAO,EAAA,GAAK,sBAAsB,OAAO,IAAA;AAC1D,IAAA,OAAO,MAAA,CAAO,QAAA;AAAA,EAChB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,UAAA,CAAW,OAAA,EAA8B,SAAA,EAAmB,KAAA,EAA+B;AAClG,EAAA,IAAI,CAAC,OAAA,EAAS;AACd,EAAA,IAAI;AACF,IAAA,OAAA,CAAQ,OAAA,CAAQ,GAAG,iBAAiB,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,EAC5E,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;;;AC7FA,IAAM,kBAAA,GAAqB,EAAA;AAC3B,IAAM,kBAAA,GAAqB,GAAA;AAE3B,IAAM,aAAA,GAA0B;AAAA,EAC9B,cAAA;AAAA;AAAA,EACA,kBAAA;AAAA;AAAA,EACA,WAAA;AAAA;AAAA,EACA,sEAAA;AAAA;AAAA,EACA;AAAA;AACF,CAAA;AAEA,IAAM,iBAAA,GAAoB,8BAAA;AAEnB,SAAS,eAAA,CAAgB,MAAA,GAA+B,EAAC,EAAG;AACjE,EAAA,MAAM;AAAA,IACJ,OAAA,GAAU,IAAA;AAAA,IACV,gBAAA,GAAmB,IAAA;AAAA,IACnB,oBAAA,GAAuB,kBAAA;AAAA,IACvB,oBAAA,GAAuB;AAAA,GACzB,GAAI,MAAA;AAEJ,EAAA,SAAS,MAAM,WAAA,EAAsC;AACnD,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,EAAE,QAAQ,IAAA,EAAK;AAAA,IACxB;AAEA,IAAA,MAAM,OAAA,GAAU,YAAY,IAAA,EAAK;AAEjC,IAAA,IAAI,OAAA,CAAQ,SAAS,oBAAA,EAAsB;AACzC,MAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,CAAA,eAAA,EAAkB,oBAAoB,CAAA,YAAA,CAAA,EAAe;AAAA,IACvF;AAEA,IAAA,IAAI,OAAA,CAAQ,SAAS,oBAAA,EAAsB;AACzC,MAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,CAAA,cAAA,EAAiB,oBAAoB,CAAA,YAAA,CAAA,EAAe;AAAA,IACtF;AAEA,IAAA,IAAI,gBAAA,EAAkB;AACpB,MAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACnC,QAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAA,EAAG;AACzB,UAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,kBAAA,EAAmB;AAAA,QACrD;AAAA,MACF;AAEA,MAAA,IAAI,iBAAA,CAAkB,IAAA,CAAK,OAAO,CAAA,EAAG;AACnC,QAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,uBAAA,EAAwB;AAAA,MAC1D;AAEA,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,CAAE,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS,CAAC,CAAA;AAC7D,MAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,QAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,oCAAA,EAAqC;AAAA,MACvE;AAAA,IACF;AAEA,IAAA,OAAO,EAAE,QAAQ,IAAA,EAAK;AAAA,EACxB;AAEA,EAAA,SAAS,SAAS,WAAA,EAA6B;AAC7C,IAAA,MAAM,OAAA,GAAU,YAAY,IAAA,EAAK;AACjC,IAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,oBAAA,EAAsB,OAAO,OAAA;AACnD,IAAA,OAAO,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,oBAAoB,CAAA,GAAI,KAAA;AAAA,EAClD;AAEA,EAAA,OAAO,EAAE,OAAO,QAAA,EAAS;AAC3B;;;ACfA,IAAM,WAAA,GAAwC;AAAA,EAC5C,KAAA,EAAO,EAAA;AAAA,EACP,IAAA,EAAM,EAAA;AAAA,EACN,IAAA,EAAM,EAAA;AAAA,EACN,KAAA,EAAO,EAAA;AAAA,EACP,KAAA,EAAO,EAAA;AAAA,EACP,MAAA,EAAQ;AACV,CAAA;AAEA,IAAM,WAAA,GAAsC;AAAA,EAC1C,KAAA,EAAO,KAAA;AAAA,EACP,IAAA,EAAM,KAAA;AAAA,EACN,IAAA,EAAM,KAAA;AAAA,EACN,KAAA,EAAO,KAAA;AAAA,EACP,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,IAAA,GAAO;AAAA,EACX,KAAA,EAAO,SAAA;AAAA,EACP,GAAA,EAAK,SAAA;AAAA,EACL,IAAA,EAAM,SAAA;AAAA,EACN,IAAA,EAAM,UAAA;AAAA,EACN,KAAA,EAAO,UAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,GAAA,EAAK,UAAA;AAAA,EAEL,KAAA,EAAO,UAAA;AAAA,EACP,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,WAAA,GAAsC;AAAA,EAC1C,OAAO,IAAA,CAAK,GAAA;AAAA,EACZ,MAAM,IAAA,CAAK,KAAA;AAAA,EACX,MAAM,IAAA,CAAK,MAAA;AAAA,EACX,OAAO,IAAA,CAAK,GAAA;AAAA,EACZ,KAAA,EAAO,GAAG,IAAA,CAAK,KAAK,GAAG,IAAA,CAAK,KAAK,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA;AAC/C,CAAA;AAGA,SAAS,YAAA,GAAkC;AACzC,EAAA,IAAI;AACF,IAAA,IAAI,OAAQ,UAAA,CAAmB,IAAA,KAAS,WAAA,EAAa,OAAO,MAAA;AAAA,EAC9D,CAAA,CAAA,MAAQ;AAAA,EAAiB;AAEzB,EAAA,MAAM,OAAO,OAAQ,UAAA,CAAmB,OAAA,KAAY,WAAA,GAC/C,WAAmB,OAAA,GACpB,MAAA;AAEJ,EAAA,IAAI,MAAM,GAAA,EAAK;AACb,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,QAAA,KAAa,YAAA,EAAc,OAAO,MAAA;AAC/C,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,UAAA,KAAe,MAAA,EAAQ,OAAO,MAAA;AAC3C,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,UAAA,KAAe,QAAA,EAAU,OAAO,QAAA;AAC7C,IAAA,IAAI,IAAA,CAAK,MAAA,EAAQ,KAAA,EAAO,OAAO,QAAA;AAAA,EACjC;AAEA,EAAA,IAAI,OAAQ,UAAA,CAAmB,MAAA,KAAW,WAAA,EAAa,OAAO,QAAA;AAE9D,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,YAAY,IAAA,EAAuC;AAC1D,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA,EAAG;AACzC,IAAA,IAAI,CAAA,KAAM,MAAA,IAAa,CAAA,KAAM,IAAA,EAAM;AACnC,IAAA,IAAI,OAAO,MAAM,QAAA,EAAU;AACzB,MAAA,KAAA,CAAM,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,EAAI,KAAK,SAAA,CAAU,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,IACxC,CAAA,MAAO;AACL,MAAA,KAAA,CAAM,KAAK,CAAA,EAAG,CAAC,IAAI,MAAA,CAAO,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,IAChC;AAAA,EACF;AACA,EAAA,OAAO,KAAA,CAAM,KAAK,GAAG,CAAA;AACvB;AAEA,SAAS,aAAa,KAAA,EAAyB;AAC7C,EAAA,MAAM,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,GAAA,EAAK,GAAG,MAAK,GAAI,KAAA;AAC3C,EAAA,MAAM,IAAA,GAAO,EAAA,CAAG,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AAC5B,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,KAAK,CAAA,IAAK,EAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,KAAK,CAAA,IAAK,MAAM,WAAA,EAAY;AACtD,EAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,SAAS,CAAA,GAAI,CAAA,CAAA,EAAI,IAAA,CAAK,GAAG,GAAG,WAAA,CAAY,IAAI,CAAC,CAAA,EAAG,IAAA,CAAK,KAAK,CAAA,CAAA,GAAK,EAAA;AAEjG,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,GAAG,CAAA,EAAG,IAAI,CAAA,EAAG,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,EAAG,KAAK,CAAA,EAAG,KAAK,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA,EAAG,OAAO,CAAA,CAAA;AAC3H;AAEA,SAAS,WAAW,KAAA,EAAyB;AAC3C,EAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAC7B;AAEA,SAAS,IAAA,CAAK,OAAiB,SAAA,EAAyB;AACtD,EAAA,QAAQ,KAAA;AAAO,IACb,KAAK,OAAA;AAAA,IACL,KAAK,OAAA;AACH,MAAA,OAAA,CAAQ,MAAM,SAAS,CAAA;AACvB,MAAA;AAAA,IACF,KAAK,MAAA;AACH,MAAA,OAAA,CAAQ,KAAK,SAAS,CAAA;AACtB,MAAA;AAAA,IACF;AACE,MAAA,OAAA,CAAQ,IAAI,SAAS,CAAA;AAAA;AAE3B;AAEA,SAAS,WAAA,CACP,KAAA,EACA,QAAA,EACA,QAAA,EACA,SAAA,EACQ;AACR,EAAA,IAAI,YAAA,GAAe,QAAA;AAEnB,EAAA,SAAS,GAAA,CAAI,KAAA,EAAiB,GAAA,EAAa,IAAA,EAAsC;AAC/E,IAAA,IAAI,WAAA,CAAY,KAAK,CAAA,GAAI,WAAA,CAAY,YAAY,CAAA,EAAG;AAEpD,IAAA,MAAM,KAAA,GAAkB;AAAA,MACtB,EAAA,EAAA,iBAAI,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAC3B,KAAA;AAAA,MACA,KAAA;AAAA,MACA,GAAA;AAAA,MACA,GAAG,QAAA;AAAA,MACH,GAAG;AAAA,KACL;AAEA,IAAA,IAAA,CAAK,KAAA,EAAO,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,EAC9B;AAEA,EAAA,OAAO;AAAA,IACL,OAAO,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,OAAA,EAAS,KAAK,IAAI,CAAA;AAAA,IAC7C,MAAM,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAI,CAAA;AAAA,IAC3C,MAAM,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAI,CAAA;AAAA,IAC3C,OAAO,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,OAAA,EAAS,KAAK,IAAI,CAAA;AAAA,IAC7C,OAAO,CAAC,GAAA,EAAK,SAAU,GAAA,CAAI,OAAA,EAAS,KAAK,IAAI,CAAA;AAAA,IAE7C,KAAA,CAAM,YAAoB,SAAA,EAA6C;AACrE,MAAA,OAAO,WAAA;AAAA,QACL,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AAAA,QACtB,YAAA;AAAA,QACA,EAAE,GAAG,QAAA,EAAU,GAAG,SAAA,EAAU;AAAA,QAC5B;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IAEA,SAAS,KAAA,EAAiB;AACxB,MAAA,YAAA,GAAe,KAAA;AAAA,IACjB;AAAA,GACF;AACF;AAYO,SAAS,aAAa,OAAA,EAAgC;AAC3D,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,KAAA,GAAQ,MAAA;AAAA,IACR,OAAO,EAAC;AAAA,IACR,MAAA,GAAS;AAAA,GACX,GAAI,OAAA;AAEJ,EAAA,MAAM,cAAA,GAAiB,MAAA,KAAW,MAAA,GAAS,YAAA,EAAa,GAAI,MAAA;AAC5D,EAAA,MAAM,SAAA,GAAY,cAAA,KAAmB,MAAA,GAAS,UAAA,GAAa,YAAA;AAE3D,EAAA,OAAO,WAAA,CAAY,KAAA,EAAO,KAAA,EAAO,IAAA,EAAM,SAAS,CAAA;AAClD;AAMO,IAAM,UAAA,GAAqB;AAAA,EAChC,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,MAAM,MAAM;AAAA,EAAC,CAAA;AAAA,EACb,MAAM,MAAM;AAAA,EAAC,CAAA;AAAA,EACb,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,OAAO,MAAM,UAAA;AAAA,EACb,UAAU,MAAM;AAAA,EAAC;AACnB;;;AC3OA,IAAM,WAAW,YAAA,CAAa,EAAE,OAAO,aAAA,EAAe,KAAA,EAAO,QAAQ,CAAA;AAErE,IAAM,OAAA,GAAU,aAAA;AAChB,IAAM,UAAA,GAAa,iBAAA;AACnB,IAAM,UAAA,GAAa,CAAA;AACnB,IAAM,MAAA,GAAS,qBAAA;AACf,IAAM,UAAA,GAAa,EAAA;AACnB,IAAM,cAAA,GAAiB,GAAA;AAahB,SAAS,kBAAA,CAAmB,MAAA,GAA6B,EAAC,EAAiB;AAChF,EAAA,MAAM,EAAE,OAAA,GAAU,IAAA,EAAM,eAAe,EAAA,EAAI,eAAA,GAAkB,MAAK,GAAI,MAAA;AAEtE,EAAA,IAAI,WAAA,GAAmC,IAAA;AACvC,EAAA,IAAI,WAAA,GAAqC,IAAA;AAEzC,EAAA,SAAS,aAAA,GAAgC;AACvC,IAAA,IAAI,aAAa,OAAO,WAAA;AACxB,IAAA,IAAI,OAAO,cAAc,WAAA,EAAa;AACpC,MAAA,WAAA,GAAc,WAAA;AAAA,IAChB,CAAA,MAAA,IAAW,OAAO,YAAA,KAAiB,WAAA,EAAa;AAC9C,MAAA,WAAA,GAAc,cAAA;AAAA,IAChB,CAAA,MAAO;AACL,MAAA,WAAA,GAAc,MAAA;AAAA,IAChB;AACA,IAAA,OAAO,WAAA;AAAA,EACT;AAIA,EAAA,SAAS,MAAA,GAA+B;AACtC,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,OAAA,GAAU,SAAA,CAAU,IAAA,CAAK,OAAA,EAAS,UAAU,CAAA;AAClD,MAAA,OAAA,CAAQ,kBAAkB,MAAM;AAC9B,QAAA,MAAM,KAAK,OAAA,CAAQ,MAAA;AACnB,QAAA,IAAI,CAAC,EAAA,CAAG,gBAAA,CAAiB,QAAA,CAAS,UAAU,CAAA,EAAG;AAC7C,UAAA,EAAA,CAAG,iBAAA,CAAkB,UAAA,EAAY,EAAE,OAAA,EAAS,MAAM,CAAA;AAAA,QACpD;AAAA,MACF,CAAA;AACA,MAAA,OAAA,CAAQ,SAAA,GAAY,MAAM,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AAChD,MAAA,OAAA,CAAQ,UAAU,MAAM;AACtB,QAAA,WAAA,GAAc,cAAA;AACd,QAAA,MAAA,CAAO,QAAQ,KAAK,CAAA;AAAA,MACtB,CAAA;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,WAAW,MAAA,EAAoC;AAC5D,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,WAAW,CAAA;AACjD,MAAA,EAAA,CAAG,WAAA,CAAY,UAAU,CAAA,CAAE,GAAA,CAAI,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAA,iBAAU,IAAI,IAAA,EAAK,EAAE,WAAA,IAAe,CAAA;AAChF,MAAA,EAAA,CAAG,UAAA,GAAa,MAAM,OAAA,EAAQ;AAC9B,MAAA,EAAA,CAAG,OAAA,GAAU,MAAM,MAAA,CAAO,EAAA,CAAG,KAAK,CAAA;AAAA,IACpC,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,SAAA,GAAoC;AACjD,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,UAAU,CAAA;AAChD,MAAA,MAAM,OAAA,GAAU,EAAA,CAAG,WAAA,CAAY,UAAU,EAAE,MAAA,EAAO;AAClD,MAAA,OAAA,CAAQ,SAAA,GAAY,MAAM,OAAA,CAAQ,OAAA,CAAQ,MAAuB,CAAA;AACjE,MAAA,OAAA,CAAQ,OAAA,GAAU,MAAM,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAAA,IAC9C,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,UAAU,EAAA,EAA2B;AAClD,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,WAAW,CAAA;AACjD,MAAA,EAAA,CAAG,WAAA,CAAY,UAAU,CAAA,CAAE,MAAA,CAAO,EAAE,CAAA;AACpC,MAAA,EAAA,CAAG,UAAA,GAAa,MAAM,OAAA,EAAQ;AAC9B,MAAA,EAAA,CAAG,OAAA,GAAU,MAAM,MAAA,CAAO,EAAA,CAAG,KAAK,CAAA;AAAA,IACpC,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,OAAA,GAA2B;AACxC,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,UAAU,CAAA;AAChD,MAAA,MAAM,OAAA,GAAU,EAAA,CAAG,WAAA,CAAY,UAAU,EAAE,KAAA,EAAM;AACjD,MAAA,OAAA,CAAQ,SAAA,GAAY,MAAM,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AAChD,MAAA,OAAA,CAAQ,OAAA,GAAU,MAAM,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAAA,IAC9C,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,QAAA,GAA0B;AACvC,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,EAAO;AACxB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,UAAA,EAAY,WAAW,CAAA;AACjD,MAAA,EAAA,CAAG,WAAA,CAAY,UAAU,CAAA,CAAE,KAAA,EAAM;AACjC,MAAA,EAAA,CAAG,UAAA,GAAa,MAAM,OAAA,EAAQ;AAC9B,MAAA,EAAA,CAAG,OAAA,GAAU,MAAM,MAAA,CAAO,EAAA,CAAG,KAAK,CAAA;AAAA,IACpC,CAAC,CAAA;AAAA,EACH;AAIA,EAAA,SAAS,MAAA,GAAwB;AAC/B,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,YAAA,CAAa,OAAA,CAAQ,MAAM,CAAA;AACvC,MAAA,OAAO,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAG,IAAI,EAAC;AAAA,IAClC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAC;AAAA,IACV;AAAA,EACF;AAEA,EAAA,SAAS,QAAQ,OAAA,EAA8B;AAC7C,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,OAAA,CAAQ,MAAA,EAAQ,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,IACtD,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,SAAS,UAAU,MAAA,EAA2B;AAC5C,IAAA,MAAM,UAAU,MAAA,EAAO;AACvB,IAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAA,qBAAc,IAAA,EAAK,EAAE,WAAA,EAAY,EAAkB,CAAA;AAC7E,IAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,EACjB;AAEA,EAAA,SAAS,SAAS,EAAA,EAAkB;AAClC,IAAA,MAAM,OAAA,GAAU,QAAO,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,EAAE,CAAA;AAClD,IAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,EACjB;AAIA,EAAA,eAAe,QAAQ,MAAA,EAAoC;AACzD,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,MAAM,WAAA,GAAc,MAAM,IAAA,EAAK;AAC/B,IAAA,IAAI,eAAe,YAAA,EAAc;AAC/B,MAAA,QAAA,CAAS,IAAA,CAAK,2CAAA,EAAwC,EAAE,YAAA,EAAc,CAAA;AACtE,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAU,aAAA,EAAc;AAC9B,IAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,MAAM,CAAA;AACvB,QAAA;AAAA,MACF,CAAA,CAAA,MAAQ;AAEN,QAAA,WAAA,GAAc,cAAA;AAAA,MAChB;AAAA,IACF;AAEA,IAAA,IAAI,OAAA,KAAY,cAAA,IAAkB,WAAA,KAAgB,cAAA,EAAgB;AAChE,MAAA,SAAA,CAAU,MAAM,CAAA;AAChB,MAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,SAASA,iBAAgB,OAAA,EAAyB;AAChD,IAAA,OAAO,IAAA,CAAK,IAAI,GAAA,GAAO,CAAA,IAAK,UAAU,IAAA,CAAK,MAAA,EAAO,GAAI,GAAA,EAAK,cAAc,CAAA;AAAA,EAC3E;AAEA,EAAA,SAASC,OAAM,EAAA,EAA2B;AACxC,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AAAA,EACzD;AAEA,EAAA,eAAe,MAAM,MAAA,EAAmE;AACtF,IAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAE,IAAA,EAAM,CAAA,EAAG,QAAQ,CAAA,EAAE;AAE1C,IAAA,IAAI,OAAA;AACJ,IAAA,MAAM,UAAU,aAAA,EAAc;AAE9B,IAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,MAAA,IAAI;AACF,QAAA,OAAA,GAAU,MAAM,SAAA,EAAU;AAAA,MAC5B,CAAA,CAAA,MAAQ;AACN,QAAA,OAAA,GAAU,MAAA,EAAO;AAAA,MACnB;AAAA,IACF,CAAA,MAAO;AACL,MAAA,OAAA,GAAU,MAAA,EAAO;AAAA,IACnB;AAEA,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,UAAU,CAAA;AACzC,IAAA,IAAI,IAAA,GAAO,CAAA;AACX,IAAA,IAAI,MAAA,GAAS,CAAA;AAEb,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,MAAA,MAAM,MAAA,GAAS,MAAM,CAAC,CAAA;AACtB,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,YAAA,CAAa,MAAM,CAAA;AAE/C,MAAA,IAAI,OAAO,EAAA,EAAI;AACb,QAAA,IAAI;AACF,UAAA,IAAI,OAAA,KAAY,WAAA,EAAa,MAAM,SAAA,CAAU,OAAO,EAAE,CAAA;AAAA,eACjD,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,QACzB,CAAA,CAAA,MAAQ;AACN,UAAA,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,QACpB;AACA,QAAA,IAAA,EAAA;AAAA,MACF,CAAA,MAAO;AACL,QAAA,MAAA,EAAA;AACA,QAAA,IAAI,CAAA,GAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AACxB,UAAA,MAAMA,MAAAA,CAAMD,gBAAAA,CAAgB,CAAC,CAAC,CAAA;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,EAAE,MAAM,MAAA,EAAO;AAAA,EACxB;AAEA,EAAA,eAAe,IAAA,GAAwB;AACrC,IAAA,MAAM,UAAU,aAAA,EAAc;AAC9B,IAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,OAAA,EAAQ;AAAA,MACvB,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,QAAO,CAAE,MAAA;AAAA,MAClB;AAAA,IACF;AACA,IAAA,OAAO,QAAO,CAAE,MAAA;AAAA,EAClB;AAEA,EAAA,eAAe,KAAA,GAAuB;AACpC,IAAA,MAAM,UAAU,aAAA,EAAc;AAC9B,IAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,EAAS;AAAA,MACjB,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AACA,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,WAAW,MAAM,CAAA;AAAA,IAChC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,SAAS,cAAc,MAAA,EAA8B;AACnD,IAAA,IAAI,CAAC,OAAA,IAAW,CAAC,eAAA,IAAmB,OAAO,WAAW,WAAA,EAAa;AAEnE,IAAA,MAAM,UAAU,MAAM;AACpB,MAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,QAAA,KAAA,CAAM,MAAM,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAAA,MAC9B;AAAA,IACF,CAAA;AAEA,IAAA,MAAA,CAAO,gBAAA,CAAiB,UAAU,OAAO,CAAA;AACzC,IAAA,WAAA,GAAc,MAAM,MAAA,CAAO,mBAAA,CAAoB,QAAA,EAAU,OAAO,CAAA;AAAA,EAClE;AAEA,EAAA,SAAS,YAAA,GAAqB;AAC5B,IAAA,WAAA,IAAc;AACd,IAAA,WAAA,GAAc,IAAA;AAAA,EAChB;AAEA,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,eAAe,YAAA,EAAa;AACpE;;;ACxQO,SAAS,kBAAA,GAAuC;AACrD,EAAA,MAAM,GAAA,GAAM,OAAO,SAAA,KAAc,WAAA,GAAc,SAAA,GAAY,MAAA;AAC3D,EAAA,MAAM,GAAA,GAAM,OAAO,MAAA,KAAW,WAAA,GAAc,MAAA,GAAS,MAAA;AACrD,EAAA,MAAM,GAAA,GAAM,OAAO,QAAA,KAAa,WAAA,GAAc,QAAA,GAAW,MAAA;AAEzD,EAAA,MAAM,UAAA,GAAa,GAAA,IAAO,YAAA,IAAgB,GAAA,GAAO,IAAgC,UAAA,GAAa,MAAA;AAE9F,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,KAAK,SAAA,IAAa,SAAA;AAAA,IAC7B,QAAA,EAAU,KAAK,QAAA,IAAY,SAAA;AAAA,IAC3B,QAAA,EAAU,KAAK,QAAA,IAAY,IAAA;AAAA,IAC3B,QAAA,EAAU;AAAA,MACR,KAAA,EAAO,KAAK,UAAA,IAAc,CAAA;AAAA,MAC1B,MAAA,EAAQ,KAAK,WAAA,IAAe;AAAA,KAC9B;AAAA,IACA,GAAA,EAAK,GAAA,EAAK,QAAA,EAAU,IAAA,IAAQ,EAAA;AAAA,IAC5B,QAAA,EAAU,KAAK,QAAA,IAAY,EAAA;AAAA,IAC3B,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IAClC,UAAU,IAAA,EAAM,cAAA,IAAiB,EAAG,eAAA,MAAqB,QAAA,IAAY,KAAA;AAAA,IACrE,YAAY,UAAA,GACR;AAAA,MACE,eAAe,UAAA,CAAW,aAAA;AAAA,MAC1B,UAAU,UAAA,CAAW,QAAA;AAAA,MACrB,KAAK,UAAA,CAAW;AAAA,KAClB,GACA,MAAA;AAAA,IACJ,cAAe,GAAA,EAAmC,YAAA;AAAA,IAClD,qBAAqB,GAAA,EAAK;AAAA,GAC5B;AACF;;;AC/BA,IAAM,WAAA,GAAc,sBAAA;AAEb,SAAS,gBAAA,GAA2B;AACzC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,MAAM,QAAA,GAAW,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAA;AACjD,IAAA,IAAI,UAAU,OAAO,QAAA;AAAA,EACvB;AAEA,EAAA,MAAM,QAAQ,aAAA,EAAc;AAE5B,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,OAAA,CAAQ,aAAa,KAAK,CAAA;AAAA,IACzC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,aAAA,GAAwB;AAC/B,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,UAAA,EAAY;AACtD,IAAA,OAAO,CAAA,MAAA,EAAS,MAAA,CAAO,UAAA,EAAY,CAAA,CAAA;AAAA,EACrC;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,EAAE,CAAA;AAC/B,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,IAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAAA,EAC9B,CAAA,MAAO;AACL,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,MAAA,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,CAAK,MAAM,IAAA,CAAK,MAAA,KAAW,GAAG,CAAA;AAAA,IAC3C;AAAA,EACF;AAEA,EAAA,MAAM,MAAM,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA,CACzB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAC1C,KAAK,EAAE,CAAA;AACV,EAAA,OAAO,SAAS,GAAG,CAAA,CAAA;AACrB;;;ACtBA,IAAM,SAAA,GAAY,wBAAA;AAclB,SAAS,aAAA,GAAmC;AAC1C,EAAA,MAAM,GAAA,GAAM,OAAO,SAAA,KAAc,WAAA,GAAc,SAAA,GAAY,MAAA;AAC3D,EAAA,MAAM,GAAA,GAAM,OAAO,MAAA,KAAW,WAAA,GAAc,MAAA,GAAS,MAAA;AACrD,EAAA,MAAM,GAAA,GAAM,OAAO,MAAA,KAAW,WAAA,GAAc,MAAA,GAAS,MAAA;AACrD,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,KAAK,SAAA,IAAa,SAAA;AAAA,IAC7B,QAAA,EAAU,KAAK,QAAA,IAAY,SAAA;AAAA,IAC3B,QAAA,EAAU,KAAK,QAAA,IAAY,IAAA;AAAA,IAC3B,UAAU,IAAA,EAAM,cAAA,IAAiB,EAAG,eAAA,MAAqB,QAAA,IAAY,KAAA;AAAA,IACrE,WAAA,EAAa,KAAK,KAAA,IAAS,CAAA;AAAA,IAC3B,YAAA,EAAc,KAAK,MAAA,IAAU,CAAA;AAAA,IAC7B,UAAA,EAAY,KAAK,gBAAA,IAAoB,CAAA;AAAA,IACrC,cAAe,GAAA,EAA+C,YAAA;AAAA,IAC9D,qBAAqB,GAAA,EAAK;AAAA,GAC5B;AACF;AAMA,eAAe,UAAU,KAAA,EAAgC;AACvD,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,MAAA,EAAQ;AAClD,IAAA,MAAM,GAAA,GAAM,IAAI,WAAA,EAAY,CAAE,OAAO,KAAK,CAAA;AAC1C,IAAA,MAAM,SAAS,MAAM,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,WAAW,GAAG,CAAA;AACxD,IAAA,OAAO,KAAA,CAAM,KAAK,IAAI,UAAA,CAAW,MAAM,CAAC,CAAA,CACrC,IAAI,CAAC,CAAA,KAAM,EAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAC1C,KAAK,EAAE,CAAA;AAAA,EACZ;AAIA,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,IAAA,GAAA,CAAQ,IAAA,IAAQ,CAAA,IAAK,IAAA,GAAO,KAAA,CAAM,WAAW,CAAC,CAAA;AAC9C,IAAA,IAAA,IAAQ,CAAA;AAAA,EACV;AACA,EAAA,OAAO,CAAA,IAAA,EAAA,CAAQ,SAAS,CAAA,EAAG,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAC1D;AASA,eAAsB,wBAAA,GAAmD;AACvE,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,OAAA,CAAQ,SAAS,CAAA;AAC7C,IAAA,IAAI,QAAQ,OAAO,MAAA;AAAA,EACrB;AAEA,EAAA,MAAM,SAAS,aAAA,EAAc;AAC7B,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,SAAA,CAAU,MAAM,CAAA;AACxC,EAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,UAAU,CAAA;AAEvC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,OAAA,CAAQ,WAAW,IAAI,CAAA;AAAA,IACtC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;;;AChGA,IAAM,WAAA,GAAc,kBAAA;AAEpB,IAAI,eAAA,GAAiC,IAAA;AAE9B,SAAS,YAAA,GAAuB;AACrC,EAAA,IAAI,iBAAiB,OAAO,eAAA;AAE5B,EAAA,IAAI,OAAO,mBAAmB,WAAA,EAAa;AACzC,IAAA,MAAM,QAAA,GAAW,cAAA,CAAe,OAAA,CAAQ,WAAW,CAAA;AACnD,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,eAAA,GAAkB,QAAA;AAClB,MAAA,OAAO,QAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,MAAM,KAAK,iBAAA,EAAkB;AAC7B,EAAA,eAAA,GAAkB,EAAA;AAElB,EAAA,IAAI,OAAO,mBAAmB,WAAA,EAAa;AACzC,IAAA,IAAI;AACF,MAAA,cAAA,CAAe,OAAA,CAAQ,aAAa,EAAE,CAAA;AAAA,IACxC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,OAAO,EAAA;AACT;AAEA,SAAS,iBAAA,GAA4B;AACnC,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,CAAE,SAAS,EAAE,CAAA;AACxC,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AACpD,EAAA,OAAO,CAAA,GAAA,EAAM,SAAS,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AAClC;;;ACrBA,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,0BAAA,GAA6B,GAAA;AAE5B,SAAS,iBAAA,CAAkB,MAAA,GAA4B,EAAC,EAAgB;AAC7E,EAAA,MAAM;AAAA,IACJ,QAAA,GAAW,iBAAA;AAAA,IACX,UAAA,GAAa,mBAAA;AAAA,IACb,gBAAA,GAAmB;AAAA,GACrB,GAAI,MAAA;AAEJ,EAAA,IAAI,MAAA,GAAS,QAAA;AACb,EAAA,IAAI,UAAA,GAAa,KAAK,GAAA,EAAI;AAE1B,EAAA,SAAS,MAAA,GAAS;AAChB,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,MAAM,UAAU,GAAA,GAAM,UAAA;AACtB,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,gBAAgB,CAAA;AACrD,IAAA,IAAI,UAAU,CAAA,EAAG;AACf,MAAA,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,QAAA,EAAU,MAAA,GAAS,UAAU,UAAU,CAAA;AACzD,MAAA,UAAA,GAAa,GAAA;AAAA,IACf;AAAA,EACF;AAEA,EAAA,SAAS,UAAA,GAAsB;AAC7B,IAAA,MAAA,EAAO;AACP,IAAA,IAAI,SAAS,CAAA,EAAG;AACd,MAAA,MAAA,EAAA;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,SAAS,KAAA,GAAc;AACrB,IAAA,MAAA,GAAS,QAAA;AACT,IAAA,UAAA,GAAa,KAAK,GAAA,EAAI;AAAA,EACxB;AAEA,EAAA,SAAS,eAAA,GAA0B;AACjC,IAAA,MAAA,EAAO;AACP,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAE,UAAA,EAAY,KAAA,EAAO,eAAA,EAAgB;AAC9C;;;ACxCA,IAAM,gBAAA,GAAiC;AAAA,EACrC,EAAE,GAAA,EAAK,MAAA,EAAQ,KAAA,EAAO,wBAAA,EAA0B,aAAa,gBAAA,EAAiB;AAAA,EAC9E,EAAE,GAAA,EAAK,aAAA,EAAe,KAAA,EAAO,2BAAA,EAA6B,aAAa,eAAA,EAAgB;AAAA,EACvF,EAAE,GAAA,EAAK,QAAA,EAAU,KAAA,EAAO,uDAAA,EAAyD,aAAa,kBAAA,EAAmB;AAAA,EACjH,EAAE,GAAA,EAAK,QAAA,EAAU,KAAA,EAAO,gEAAA,EAAkE,aAAa,kBAAA,EAAmB;AAAA,EAC1H,EAAE,GAAA,EAAK,aAAA,EAAe,KAAA,EAAO,8BAAA,EAAgC,aAAa,eAAA;AAC5E,CAAA;AAEA,IAAM,cAAA,GAAoC;AAAA,EACxC,MAAA,EAAQ,IAAA;AAAA,EACR,MAAA,EAAQ,IAAA;AAAA,EACR,WAAA,EAAa,IAAA;AAAA,EACb,IAAA,EAAM,IAAA;AAAA,EACN,WAAA,EAAa;AACf,CAAA;AAEO,SAAS,iBAAA,CAAkB,MAAA,GAA4B,EAAC,EAAG;AAChE,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,cAAA,EAAgB,GAAG,MAAA,EAAO;AAE9C,EAAA,MAAM,cAAA,GAAiB,iBAAiB,MAAA,CAAO,CAAC,MAAM,MAAA,CAAO,CAAA,CAAE,GAAG,CAAC,CAAA;AAEnE,EAAA,SAAS,MAAM,IAAA,EAAsB;AACnC,IAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,IAAA,IAAI,MAAA,GAAS,IAAA;AACb,IAAA,KAAA,MAAW,EAAE,KAAA,EAAO,WAAA,EAAY,IAAK,cAAA,EAAgB;AACnD,MAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,IAAI,MAAA,CAAO,MAAM,MAAA,EAAQ,KAAA,CAAM,KAAK,CAAA,EAAG,WAAW,CAAA;AAAA,IAC5E;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,SAAS,WAAA,CAA+C,KAAQ,IAAA,EAAmB;AACjF,IAAA,MAAM,IAAA,GAAO,EAAE,GAAG,GAAA,EAAI;AACtB,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,IAAI,OAAO,IAAA,CAAK,GAAG,CAAA,KAAM,QAAA,EAAU;AACjC,QAAC,KAAiC,GAAG,CAAA,GAAI,KAAA,CAAM,IAAA,CAAK,GAAG,CAAW,CAAA;AAAA,MACpE;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAE,OAAO,WAAA,EAAY;AAC9B;AAEO,SAAS,QAAA,CAAS,MAAc,MAAA,EAAoC;AACzE,EAAA,OAAO,iBAAA,CAAkB,MAAM,CAAA,CAAE,KAAA,CAAM,IAAI,CAAA;AAC7C","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mushi-mushi/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Core types, API client, and pre-filter for Mushi Mushi SDK",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -34,12 +34,19 @@
34
34
  "url": "https://github.com/kensaurus/mushi-mushi/issues"
35
35
  },
36
36
  "keywords": [
37
+ "mushi-mushi",
37
38
  "bug-reporting",
38
- "sdk",
39
39
  "user-feedback",
40
- "friction",
40
+ "sdk",
41
+ "core",
41
42
  "types",
42
- "api-client"
43
+ "api-client",
44
+ "session-replay",
45
+ "screenshot",
46
+ "shake-to-report",
47
+ "sentry-companion",
48
+ "error-tracking",
49
+ "ai-triage"
43
50
  ],
44
51
  "publishConfig": {
45
52
  "access": "public"