{"version":3,"sources":["../src/error-conditions.ts"],"names":["CONDITION_CODE","CARRIED_CODES","carriedConditionCode","error","value","defineCondition","row","ACTIVATION_ENABLE_TIMED_OUT","GRANT_WALL","CDN_DORMANT","CDN_RESTORE_PENDING","UNSUPPORTED_PLATFORM_INSTALL","MOCK_NO_ADAPTER","MOCK_NO_DEVICE_MATCH","MOCK_SERVICE_ABSENT","MOCK_CHARACTERISTIC_ABSENT","MOCK_DESCRIPTOR_ABSENT","beacioDomException","params","uuid","message","err"],"mappings":"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","file":"chunk-2B73BD5C.mjs","sourcesContent":["/**\n * The beacio ERROR-CONDITIONS table — the ONE enumeration of every first-party\n * condition surfacing to a page as a NotFoundError DOMException, keyed by\n * conditionId, NOT by message: chooser-cancelled and activation-dismissed share\n * one frozen cancel sentence (both USER_CANCELLED), and a message-keyed map is\n * structurally incapable of recording that (GH #354).\n * S5 of docs/reviews/2026-08-12-error-classification-panel/S5-DESIGN.md\n * (revisions R1-R3 applied; R3 extended to the sanitize fixed-point).\n *\n * LEAF: the only import is `import type` (erased), so the runtime closure is\n * this file alone — BeacioError/SUGGESTIONS/withRetry stay in ../errors.ts,\n * unreachable. Rows ship inside the bundles that emit them (auto.mjs budget\n * 3,072 B gzip; browser-auto 19,456 B), so each row const is its own\n * tree-shaking unit and the CONDITIONS aggregate is for TESTS/TOOLING ONLY —\n * nothing shipped may reference it (R1b, enforced by the step-E lint).\n * PURE discipline (leak RCA 2026-08-12): inside this leaf, no member access may\n * appear in a module-level initializer outside a PURE-annotated call — esbuild\n * must assume `X.y` can be a getter, which defeats `#__PURE__` and retains the\n * statement (and its row deps) in every importer.\n *\n * VERSION-SKEW INVARIANTS (§8.2 — App Store extension is slow, npm is fast; two\n * compiled copies WILL coexist): ids are APPEND-ONLY; message bytes are FROZEN\n * (edited only via reviewed adjudication); the classifier stays exact-sentence\n * rows first with the foreign fragments load-bearing FOREVER; no text-based\n * provenance detection, ever (S7's wire discriminator is the only channel).\n *\n * Adjudication prose (decision/openQuestion per row) is deliberately TEST-SIDE\n * (R1c): tests/error-conditions.test.ts `CONDITION_META`, totality-asserted.\n */\nimport type { BeacioErrorCode } from './error-taxonomy';\n\n/**\n * GH #354 — the out-of-band discriminator between the three conditions that share\n * Chromium's byte-frozen chooser-cancellation sentence. `Symbol.for` so the\n * stringified page-bootstrap (page realm) and the npm SDK resolve the SAME symbol\n * (precedent: `Symbol.for('beacio.replayGrant')`). A hostile page CAN forge this\n * symbol, so `carriedConditionCode` validates against the closed carried-code set\n * below — never trust an arbitrary string as a BeacioErrorCode.\n */\nexport const CONDITION_CODE = Symbol.for('beacio.conditionCode');\n\n/**\n * The closed set of codes a row can carry. Hardcoded LITERALS on purpose: the PURE\n * discipline forbids `ROW.code` member access in a module-level initializer. Keep in\n * sync with the rows' `code` fields (pinned by the tests' hardcoded oracle).\n */\nconst CARRIED_CODES: ReadonlySet<BeacioErrorCode> = new Set<BeacioErrorCode>([\n  'USER_CANCELLED',\n  'EXTENSION_NOT_ENABLED',\n  'EXTENSION_NOT_INSTALLED',\n  'DEVICE_NOT_FOUND',\n]);\n\n/** Read a validated carried code off a (possibly hostile) carrier; undefined → text fallback. */\nexport function carriedConditionCode(error: unknown): BeacioErrorCode | undefined {\n  if (typeof error !== 'object' || error === null) return undefined;\n  const value = (error as unknown as Record<symbol, unknown>)[CONDITION_CODE];\n  return typeof value === 'string' && CARRIED_CODES.has(value as BeacioErrorCode)\n    ? (value as BeacioErrorCode)\n    : undefined;\n}\n\n/** Every first-party NotFoundError condition. APPEND-ONLY (version skew). */\nexport type ConditionId =\n  | 'chooser-cancelled'\n  | 'activation-dismissed'\n  | 'activation-enable-timed-out'\n  | 'grant-wall'\n  | 'cdn-dormant'\n  | 'cdn-restore-pending'\n  | 'unsupported-platform-install'\n  | 'bridge-unavailable'\n  | 'mock-no-adapter'\n  | 'mock-no-device-match'\n  | 'mock-service-absent'\n  | 'mock-characteristic-absent'\n  | 'mock-descriptor-absent';\n\n/** Rows whose message carries a `{uuid}` placeholder (factory REQUIRES the uuid). */\nexport type TemplateConditionId = 'mock-service-absent' | 'mock-characteristic-absent' | 'mock-descriptor-absent';\nexport type StaticConditionId = Exclude<ConditionId, TemplateConditionId>;\n\ndeclare const conditionBrand: unique symbol;\n\n/**\n * A row. BRANDED (R1a): only the leaf-private defineCondition() mints one — a\n * forged inline row needs an `as ErrorCondition` cast, banned outside this leaf\n * by the step-E lint. `domName` is pinned for S5's scope; it widens to a name\n * union only when another DOM name onboards (append-only, no silent creep).\n */\nexport interface ErrorCondition<K extends ConditionId = ConditionId> {\n  readonly id: K;\n  readonly domName: 'NotFoundError';\n  readonly message: string;\n  readonly code: BeacioErrorCode;\n  readonly [conditionBrand]: true;\n}\n\n/** Leaf-private minting seam — the ONLY way an ErrorCondition comes to exist. */\nfunction defineCondition<K extends ConditionId>(row: {\n  readonly id: K;\n  readonly domName: 'NotFoundError';\n  readonly message: string;\n  readonly code: BeacioErrorCode;\n}): ErrorCondition<K> {\n  return Object.freeze(row) as ErrorCondition<K>;\n}\n\n/** Chromium's CHOOSER_CANCELLED sentence, emitted verbatim by the Convention-5 seam (bluetooth.ts). */\nexport const CHOOSER_CANCELLED = /*#__PURE__*/ defineCondition({\n  id: 'chooser-cancelled', domName: 'NotFoundError', code: 'USER_CANCELLED',\n  message: 'User cancelled the requestDevice() chooser.',\n});\n\n/** Activation banner dismissed (content-full → page-bootstrap listener). */\nexport const ACTIVATION_DISMISSED = /*#__PURE__*/ defineCondition({\n  id: 'activation-dismissed', domName: 'NotFoundError', code: 'USER_CANCELLED',\n  message: 'User cancelled the requestDevice() chooser.',\n});\n\n/**\n * Enable-flow timed out (or ACTIVATE_BLE send failed — same user-visible copy).\n * V7: this row now carries its OWN beacio-owned sentence (\"Beacio activation\n * timed out\") instead of reusing Chromium's byte-frozen chooser-cancellation\n * bytes — the enable timed out, the user did NOT cancel. The code stays\n * EXTENSION_NOT_ENABLED, and the honest sentence text-classifies\n * 'extension-not-enabled' on its own (see error-taxonomy.ts NOT_FOUND_FRAGMENTS),\n * so the split no longer relies on the out-of-band discriminator alone. R3's\n * message-aware \"drop the cancel-sentence lie\" branch (error-taxonomy.ts) is now\n * a VERSION-SKEW GUARD only — pre-V7 emitters still ship the cancel bytes with\n * this code; the live sentence is ECHOED, never dropped to the SUGGESTION.\n */\nexport const ACTIVATION_ENABLE_TIMED_OUT = /*#__PURE__*/ defineCondition({\n  id: 'activation-enable-timed-out', domName: 'NotFoundError', code: 'EXTENSION_NOT_ENABLED',\n  message: 'Beacio activation timed out',\n});\n\n/** Grant wall: installed, origin never enabled (G1/LESCAN-01; Chromium maps the same condition onto NotFoundError, bluetooth_error.cc:161-163). */\nexport const GRANT_WALL = /*#__PURE__*/ defineCondition({\n  id: 'grant-wall', domName: 'NotFoundError', code: 'EXTENSION_NOT_ENABLED',\n  message: 'User has not enabled Web Bluetooth for this origin.',\n});\n\n/** CDN loader while the extension is dormant — grant-wall's other surface. */\nexport const CDN_DORMANT = /*#__PURE__*/ defineCondition({\n  id: 'cdn-dormant', domName: 'NotFoundError', code: 'EXTENSION_NOT_ENABLED',\n  message: 'Beacio is installed but not active. Follow the Beacio setup prompt, then retry.',\n});\n\n/**\n * CDN loader inside Safari's POST-RESTORE window: this origin has seen the\n * extension announce before (the `beacio_seen` hint), so the tap was HELD rather\n * than funnelled — but Safari's extension-context scheduler did not deliver the\n * content script within the hold's grace window. A SIBLING of CDN_DORMANT, not a\n * reuse of it: cdn-dormant's sentence tells the user to \"follow the Beacio setup\n * prompt\", and in this condition there IS no setup prompt — nothing is wrong\n * with their install, the page simply has not been given the extension yet.\n * Deliberately NOT the install funnel: this person already has beacio.\n */\nexport const CDN_RESTORE_PENDING = /*#__PURE__*/ defineCondition({\n  id: 'cdn-restore-pending', domName: 'NotFoundError', code: 'EXTENSION_NOT_ENABLED',\n  message: 'Beacio is still starting up in this tab. Wait a moment, then retry.',\n});\n\n/**\n * auto.ts unsupported-platform stub. Its LEADING sentence is Chromium's\n * WEB_BLUETOOTH_NOT_SUPPORTED string verbatim — only the beacio tail may ever\n * classify it (the bare Chromium sentence must stay DEVICE_NOT_FOUND).\n */\nexport const UNSUPPORTED_PLATFORM_INSTALL = /*#__PURE__*/ defineCondition({\n  id: 'unsupported-platform-install', domName: 'NotFoundError', code: 'EXTENSION_NOT_INSTALLED',\n  message:\n    'Web Bluetooth is not supported on this platform. ' +\n    'On iOS Safari, install the Beacio extension. ' +\n    'See: https://beacio.com',\n});\n\n/** injected-full: the content-script bridge never answered (transport failure). */\nexport const BRIDGE_UNAVAILABLE = /*#__PURE__*/ defineCondition({\n  id: 'bridge-unavailable', domName: 'NotFoundError', code: 'DEVICE_NOT_FOUND',\n  message: 'Content script not available',\n});\n\n/** Mock adapter unavailable. PERIOD-LESS on purpose (≠ Chromium's \"…available.\"); never a classifier row. */\nexport const MOCK_NO_ADAPTER = /*#__PURE__*/ defineCondition({\n  id: 'mock-no-adapter', domName: 'NotFoundError', code: 'DEVICE_NOT_FOUND',\n  message: 'Bluetooth adapter not available',\n});\n\n/** Mock chooser: nothing matched the filters. */\nexport const MOCK_NO_DEVICE_MATCH = /*#__PURE__*/ defineCondition({\n  id: 'mock-no-device-match', domName: 'NotFoundError', code: 'DEVICE_NOT_FOUND',\n  message: 'No devices found matching the filter criteria',\n});\n\n/** Mock getPrimaryService miss ({uuid} template). SERVICE_NOT_FOUND is deliberately unreachable for DOMException carriers. */\nexport const MOCK_SERVICE_ABSENT = /*#__PURE__*/ defineCondition({\n  id: 'mock-service-absent', domName: 'NotFoundError', code: 'DEVICE_NOT_FOUND',\n  message: 'No Services matching UUID {uuid} found',\n});\n\n/** Mock getCharacteristic miss ({uuid} template; characteristics.ts:167-170 — R5a). */\nexport const MOCK_CHARACTERISTIC_ABSENT = /*#__PURE__*/ defineCondition({\n  id: 'mock-characteristic-absent', domName: 'NotFoundError', code: 'DEVICE_NOT_FOUND',\n  message: 'No Characteristics matching UUID {uuid} found',\n});\n\n/** Mock getDescriptor miss ({uuid} template). */\nexport const MOCK_DESCRIPTOR_ABSENT = /*#__PURE__*/ defineCondition({\n  id: 'mock-descriptor-absent', domName: 'NotFoundError', code: 'DEVICE_NOT_FOUND',\n  message: 'No Descriptors matching UUID {uuid} found',\n});\n\n/** TESTS/TOOLING ONLY (R1b) — referenced by nothing shipped. `satisfies` forces totality both ways. */\nexport const CONDITIONS = /*#__PURE__*/ Object.freeze({\n  'chooser-cancelled': CHOOSER_CANCELLED,\n  'activation-dismissed': ACTIVATION_DISMISSED,\n  'activation-enable-timed-out': ACTIVATION_ENABLE_TIMED_OUT,\n  'grant-wall': GRANT_WALL,\n  'cdn-dormant': CDN_DORMANT,\n  'cdn-restore-pending': CDN_RESTORE_PENDING,\n  'unsupported-platform-install': UNSUPPORTED_PLATFORM_INSTALL,\n  'bridge-unavailable': BRIDGE_UNAVAILABLE,\n  'mock-no-adapter': MOCK_NO_ADAPTER,\n  'mock-no-device-match': MOCK_NO_DEVICE_MATCH,\n  'mock-service-absent': MOCK_SERVICE_ABSENT,\n  'mock-characteristic-absent': MOCK_CHARACTERISTIC_ABSENT,\n  'mock-descriptor-absent': MOCK_DESCRIPTOR_ABSENT,\n} satisfies Record<ConditionId, ErrorCondition>);\n\n/** REQUIRED for exactly the template ids, FORBIDDEN otherwise (TS2554) — no optional arguments. */\nexport type ConditionParams<K extends ConditionId> = K extends TemplateConditionId ? [uuid: string] : [];\n\n/**\n * The factory — ROW-passing (R1): closes over nothing, so each importer carries\n * exactly the row consts it emits. The runtime guard is for un-typed JS callers\n * only: loud, never a silent undefined-message DOMException.\n */\nexport function beacioDomException<K extends ConditionId>(\n  row: ErrorCondition<K>,\n  ...params: ConditionParams<K>\n): DOMException {\n  if (!row || typeof row.message !== 'string') {\n    throw new TypeError('beacio: invalid error condition');\n  }\n  const uuid = (params as readonly string[])[0];\n  // Template rows REQUIRE a uuid (the factory is typed to enforce it, but an\n  // un-typed caller of the published @beacio/core/testing surface can omit it).\n  // Fail loud — never emit the literal `{uuid}` placeholder into a page-visible\n  // message.\n  if (row.message.includes('{uuid}') && (typeof uuid !== 'string' || uuid.length === 0)) {\n    throw new TypeError('beacio: template error condition requires a uuid');\n  }\n  // R2: FUNCTION replacement — a string replacement would interpret $&, $', $`, $$ in the uuid.\n  const message = uuid === undefined ? row.message : row.message.replace('{uuid}', () => uuid);\n  const err = new DOMException(message, row.domName);\n  // GH #354: carry row.code out-of-band so a byte-frozen shared sentence still\n  // classifies truthfully (symbol-keyed → never collides with DOMException.code).\n  Object.defineProperty(err, CONDITION_CODE, {\n    value: row.code, writable: false, enumerable: false, configurable: true,\n  });\n  return err;\n}\n\n/** The ids the stringified page-bootstrap payload carries (design §3, C1). */\nexport type PageBootstrapConditionId = 'grant-wall' | 'activation-dismissed' | 'activation-enable-timed-out';\n\n/**\n * A payload row: message + code — the bootstrap mint hardcodes the DOM name (C4)\n * and attaches `code` under the out-of-band discriminator (GH #354), so the\n * byte-frozen shared sentence still classifies truthfully in the page realm.\n */\nexport interface PageConditionRow {\n  readonly message: string;\n  readonly code: BeacioErrorCode;\n}\n\n/**\n * Payload-row projection AND the §3 static assertion in one seam: the parameter\n * constraint requires domName 'NotFoundError', so the bootstrap mint's\n * hardcoded literal (kept for the freeze's one-dynamic-site pin, C4) can never\n * drift from the table. Also the PURE-discipline fix from the header: a bare\n * `{ message: GRANT_WALL.message }` literal retained the unused payload — and\n * all three rows — in every taxonomy importer (measured +94 B gzip in\n * browser-auto); identifier-only arguments keep it droppable.\n */\nconst pageRow = (row: ErrorCondition & { readonly domName: 'NotFoundError' }): PageConditionRow => ({\n  message: row.message,\n  code: row.code,\n});\n\n/**\n * The three page-realm rows for the serialized bootstrap payload\n * (page-bootstrap.ts is STRINGIFIED for injection and cannot import the factory\n * — design §0 C1; it defines a payload-carried local mint instead).\n */\nexport const PAGE_BOOTSTRAP_CONDITIONS: Readonly<Record<PageBootstrapConditionId, PageConditionRow>> =\n  /*#__PURE__*/ Object.freeze({\n    'grant-wall': /*#__PURE__*/ pageRow(GRANT_WALL),\n    'activation-dismissed': /*#__PURE__*/ pageRow(ACTIVATION_DISMISSED),\n    'activation-enable-timed-out': /*#__PURE__*/ pageRow(ACTIVATION_ENABLE_TIMED_OUT),\n  });\n"]}