@ghostlytools/cli 1.3.9 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +13 -4
  2. package/SKILL.md +7 -4
  3. package/dist/assets/{api-Cp9GxjUO.js → api-BqLfti32.js} +2 -2
  4. package/dist/assets/{api-BCrwJ57L.js → api-JMkEO0RR.js} +130 -50
  5. package/dist/assets/api-JMkEO0RR.js.map +1 -0
  6. package/dist/assets/{apiKit-B4qhnLQT.js → apiKit-BpIUCwa-.js} +3 -3
  7. package/dist/assets/{apiKit-B4qhnLQT.js.map → apiKit-BpIUCwa-.js.map} +1 -1
  8. package/dist/assets/{apps-CpxENMgl.js → apps-BdfyGVZ1.js} +1 -1
  9. package/dist/assets/{apps-DOH1P_S0.js → apps-Bettj7WQ.js} +6 -6
  10. package/dist/assets/apps-Bettj7WQ.js.map +1 -0
  11. package/dist/assets/{arkade-Cyf5MGxG.js → arkade-CP4HvKaa.js} +2 -2
  12. package/dist/assets/{arkade-Cyf5MGxG.js.map → arkade-CP4HvKaa.js.map} +1 -1
  13. package/dist/assets/{backup-CqM-0-2v.js → backup-BbO2zLjx.js} +1 -1
  14. package/dist/assets/{backup-CTpFFQ-4.js → backup-BmBtta66.js} +7 -7
  15. package/dist/assets/{backup-CTpFFQ-4.js.map → backup-BmBtta66.js.map} +1 -1
  16. package/dist/assets/blobFiles-B0rNnHlO.js +35 -0
  17. package/dist/assets/blobFiles-B0rNnHlO.js.map +1 -0
  18. package/dist/assets/{buttons-BtxwyM2l.js → buttons-YgijrprJ.js} +4 -4
  19. package/dist/assets/{buttons-BtxwyM2l.js.map → buttons-YgijrprJ.js.map} +1 -1
  20. package/dist/assets/buttons-_GBlxAti.js +2 -0
  21. package/dist/assets/{endpoint-BOTFMpfS.js → endpoint-Cl3cgAYl.js} +3 -2
  22. package/dist/assets/endpoint-Cl3cgAYl.js.map +1 -0
  23. package/dist/assets/{envelope-DW8TWKPD.js → envelope-C7vnmsJN.js} +2 -2
  24. package/dist/assets/{envelope-DW8TWKPD.js.map → envelope-C7vnmsJN.js.map} +1 -1
  25. package/dist/assets/{errors-B-zMxbcd.js → errors-BLSPp0tK.js} +3 -1
  26. package/dist/assets/errors-BLSPp0tK.js.map +1 -0
  27. package/dist/assets/{fileBytes-Di7VZtmU.js → fileBytes-B-fqGdEd.js} +3 -3
  28. package/dist/assets/{fileBytes-Di7VZtmU.js.map → fileBytes-B-fqGdEd.js.map} +1 -1
  29. package/dist/assets/{fileBytes-CgbibpbV.js → fileBytes-C2jycN_7.js} +1 -1
  30. package/dist/assets/{fileBytes-CfSXjTFa.js → fileBytes-D6fqFQEX.js} +6 -3
  31. package/dist/assets/fileBytes-D6fqFQEX.js.map +1 -0
  32. package/dist/assets/fileBytesIdb-DOxm_BKt.js +2 -0
  33. package/dist/assets/{fileBytesIdb-D5u6H8X_.js → fileBytesIdb-_HnxdacI.js} +3 -3
  34. package/dist/assets/{fileBytesIdb-D5u6H8X_.js.map → fileBytesIdb-_HnxdacI.js.map} +1 -1
  35. package/dist/assets/{fileBytesOpfs-Dd1N4ERH.js → fileBytesOpfs-p_CANncD.js} +3 -3
  36. package/dist/assets/{fileBytesOpfs-Dd1N4ERH.js.map → fileBytesOpfs-p_CANncD.js.map} +1 -1
  37. package/dist/assets/{groupFiles-uxa0U9_n.js → groupFiles-sIdGq4AV.js} +5 -5
  38. package/dist/assets/groupFiles-sIdGq4AV.js.map +1 -0
  39. package/dist/assets/{host-DPy0eaH9.js → host-Drd-c4VO.js} +147 -25
  40. package/dist/assets/host-Drd-c4VO.js.map +1 -0
  41. package/dist/assets/{hyperdhtRelay-De5FT7Am.js → hyperdhtRelay-13aQ4KOf.js} +2 -2
  42. package/dist/assets/{hyperdhtRelay-De5FT7Am.js.map → hyperdhtRelay-13aQ4KOf.js.map} +1 -1
  43. package/dist/assets/{idb-B5L8wuOm.js → idb-CMVgtn2k.js} +59 -6
  44. package/dist/assets/idb-CMVgtn2k.js.map +1 -0
  45. package/dist/assets/{irohWeb-z5QDDWa-.js → irohWeb-DHCxSvHF.js} +2 -2
  46. package/dist/assets/{irohWeb-z5QDDWa-.js.map → irohWeb-DHCxSvHF.js.map} +1 -1
  47. package/dist/assets/{main-Dt7xrqtb.js → main-BWAwKY4f.js} +476 -141
  48. package/dist/assets/main-BWAwKY4f.js.map +1 -0
  49. package/dist/assets/{mainline-Cld-bKeC.js → mainline-CsG-DdJ5.js} +2 -2
  50. package/dist/assets/{mainline-Cld-bKeC.js.map → mainline-CsG-DdJ5.js.map} +1 -1
  51. package/dist/assets/{networkReason-vUHo6A_C.js → networkReason-B91upMCb.js} +3 -3
  52. package/dist/assets/{networkReason-vUHo6A_C.js.map → networkReason-B91upMCb.js.map} +1 -1
  53. package/dist/assets/{nwc-zXpmd2FN.js → nwc-BFv67iSz.js} +3 -3
  54. package/dist/assets/{nwc-zXpmd2FN.js.map → nwc-BFv67iSz.js.map} +1 -1
  55. package/dist/assets/{nwcProvider-D482SQ1a.js → nwcProvider-BKNFdH9v.js} +2 -2
  56. package/dist/assets/{nwcProvider-D482SQ1a.js.map → nwcProvider-BKNFdH9v.js.map} +1 -1
  57. package/dist/assets/{profiles-gPCjLOQq.js → profiles-DSxPYdlU.js} +13 -3
  58. package/dist/assets/profiles-DSxPYdlU.js.map +1 -0
  59. package/dist/assets/{registry-CxsDR3c6.js → registry-CHPd_hf7.js} +1 -1
  60. package/dist/assets/{registry-OVx2kY3d.js → registry-qbnWmwCE.js} +3 -3
  61. package/dist/assets/registry-qbnWmwCE.js.map +1 -0
  62. package/dist/assets/{resolve-CPTAnu-9.js → resolve-B63_uSu7.js} +2 -2
  63. package/dist/assets/{resolve-CPTAnu-9.js.map → resolve-B63_uSu7.js.map} +1 -1
  64. package/dist/assets/{restoredRows-Db3oUTko.js → restoredRows-DeBImGRd.js} +2 -2
  65. package/dist/assets/{restoredRows-Db3oUTko.js.map → restoredRows-DeBImGRd.js.map} +1 -1
  66. package/dist/assets/{server-p5DJnN7T.js → server-Cd1dLOB8.js} +1485 -240
  67. package/dist/assets/server-Cd1dLOB8.js.map +1 -0
  68. package/dist/assets/{src-Dg1bvMNv.js → src-DzXL-GYu.js} +7277 -5975
  69. package/dist/assets/src-DzXL-GYu.js.map +1 -0
  70. package/dist/assets/turnRefs-BCtM10d3.js +357 -0
  71. package/dist/assets/turnRefs-BCtM10d3.js.map +1 -0
  72. package/dist/assets/{usdt-BY5OIIvG.js → usdt-B7JWDhQV.js} +3 -3
  73. package/dist/assets/{usdt-BY5OIIvG.js.map → usdt-B7JWDhQV.js.map} +1 -1
  74. package/dist/ghostly.mjs +1 -1
  75. package/package.json +7 -6
  76. package/skills/ghostly/README.md +41 -0
  77. package/skills/ghostly/SKILL.md +79 -0
  78. package/skills/ghostly/scripts/listen +67 -0
  79. package/skills/ghostly/scripts/react +25 -0
  80. package/skills/ghostly/scripts/say +44 -0
  81. package/skills/ghostly/scripts/status +27 -0
  82. package/dist/assets/api-BCrwJ57L.js.map +0 -1
  83. package/dist/assets/apps-DOH1P_S0.js.map +0 -1
  84. package/dist/assets/buttons-CJqNkG-Q.js +0 -2
  85. package/dist/assets/endpoint-BOTFMpfS.js.map +0 -1
  86. package/dist/assets/errors-B-zMxbcd.js.map +0 -1
  87. package/dist/assets/fileBytes-CfSXjTFa.js.map +0 -1
  88. package/dist/assets/fileBytesIdb-CFP-DSkZ.js +0 -2
  89. package/dist/assets/groupFiles-uxa0U9_n.js.map +0 -1
  90. package/dist/assets/host-DPy0eaH9.js.map +0 -1
  91. package/dist/assets/idb-B5L8wuOm.js.map +0 -1
  92. package/dist/assets/main-Dt7xrqtb.js.map +0 -1
  93. package/dist/assets/profiles-gPCjLOQq.js.map +0 -1
  94. package/dist/assets/registry-OVx2kY3d.js.map +0 -1
  95. package/dist/assets/server-p5DJnN7T.js.map +0 -1
  96. package/dist/assets/src-Dg1bvMNv.js.map +0 -1
  97. package/dist/assets/turnRefs-WnggXm2T.js +0 -323
  98. package/dist/assets/turnRefs-WnggXm2T.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { Ai as isPublicAddress, Dt as parseAtprotoDidDocument, Ei as dnsProofName, Fi as recordsName, Ii as txtValue, Li as wellKnownUrl, Mi as normalizeDomain, Ni as recordsFromTxt, Pi as recordsFromWellKnown, Ti as decodeDnsResponse, Tt as isAtprotoDid, ji as nip05RootKey, ki as encodeDnsQuery, qi as boundVerifiedIdentity, wi as DOMAIN_FILE_MAX_BYTES, wl as toBase64Url, xt as atprotoDidMethod } from "./src-Dg1bvMNv.js";
1
+ import { Ci as recordsFromTxt, Di as wellKnownUrl, Ei as txtValue, Li as boundVerifiedIdentity, Si as normalizeDomain, Ti as recordsName, _t as parseAtprotoDidDocument, bi as isPublicAddress, dt as atprotoDidMethod, eu as toBase64Url, gi as dnsProofName, hi as decodeDnsResponse, ht as isAtprotoDid, mi as DOMAIN_FILE_MAX_BYTES, wi as recordsFromWellKnown, xi as nip05RootKey, yi as encodeDnsQuery } from "./src-DzXL-GYu.js";
2
2
  import { l as providerDescriptorProblems } from "./types-C4_KafL_.js";
3
3
  //#region ../browser/src/shared/features.ts
4
4
  /**
@@ -603,4 +603,4 @@ async function verifiedAtprotoHandle(doc, options) {
603
603
  //#endregion
604
604
  export { reserveAdapterIds as _, DomainCheckError as a, testBuild as b, assertPublicHost as c, ownDid as d, setOwnDidSource as f, registeredOnchainProviders as g, registeredLightningProviders as h, verifiedAtprotoHandle as i, chosenResolver as l, registeredIdentityProviders as m, resolveAtprotoDid as n, assertDomainRecord as o, onAdaptersChanged as p, resolveAtprotoHandle as r, assertNip05 as s, assertPublicServer as t, resolverById as u, boundedIdentityFetch as v, verifyIdentity as y };
605
605
 
606
- //# sourceMappingURL=resolve-CPTAnu-9.js.map
606
+ //# sourceMappingURL=resolve-B63_uSu7.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-CPTAnu-9.js","names":[],"sources":["../../../browser/src/shared/features.ts","../../../browser/src/proofs/verify.ts","../../../browser/src/plugins/bundled.ts","../../../browser/src/plugins/registry.ts","../../../browser/src/proofs/ownDid.ts","../../../browser/src/proofs/domain.ts","../../../browser/src/proofs/atproto/resolve.ts"],"sourcesContent":["/** Release policy: external identity experiments are retained for future work,\n * but must not advertise capabilities, start network lookups, or expose cached\n * external profiles. This does not gate Ghostly participation authentication. */\nexport const EXTERNAL_IDENTITIES_ENABLED: boolean = false;\n\n/** Mini-apps (WISP 1200): `apps/1` on paired sessions and the engine's `app*` calls. On from release 1.2 (a version\n * before 1.2.0 is never cut with it on: `RELEASE_GUARDS` in tools/scripts/changes.mjs). Off, nothing is offered to\n * contacts and every call is refused; a host that runs no apps pins its engine off (`NodeOptions.apps`). */\nexport const APPS_ENABLED: boolean = true;\n\n/**\n * A build that may be put into test mode: a development build (`import.meta.env.DEV`, which vitest also sets) or the\n * e2e suite's build (`VITE_APPS_TEST`, fixed when the build is made, as the mini-app switch is). A release build is\n * neither: Vite folds this to `false` there, so the storage flags the test fakes answer to are ignored. The fakes\n * themselves are still in the bundle (the registries import them); plugins may still pass fakes to the registry.\n */\nexport const testBuild = (): boolean => { try { return !!import.meta.env?.DEV || import.meta.env?.VITE_APPS_TEST === \"1\"; } catch { return false; } };\n","import { boundVerifiedIdentity, IDENTITY_MAX_EVIDENCE, IDENTITY_MAX_VALIDITY, type IdentityStatement, type VerifiedIdentity } from \"@ghostly/core\";\nimport type { IdentityFetch, IdentityProofProvider, IdentitySigner, VerifyContext } from \"./contract\";\n\nconst DAY = 86_400;\n\n/**\n * The checks every proof goes through, whatever its provider: known provider, validity within the\n * provider's limit, bounded evidence, strict parsing, the provider's own check, and the category rule\n * (a self-custodied proof proves exactly the subject it names; an attested one says who attests it).\n * The engine verifies a contact's proof, and the person's own proof before saving it, only through this.\n */\nexport async function verifyIdentity(providers: readonly IdentityProofProvider[], statement: IdentityStatement, evidence: unknown, ctx: VerifyContext): Promise<VerifiedIdentity> {\n const { binding } = statement;\n const provider = providers.find(p => p.id === binding.provider);\n if (!provider) throw new Error(\"This app cannot verify this kind of identity\");\n if (binding.expiresAt - binding.issuedAt > Math.min(provider.validity.maxDays * DAY, IDENTITY_MAX_VALIDITY)) throw new Error(\"The proof lasts longer than this kind of identity allows\");\n if (JSON.stringify(evidence ?? null).length > IDENTITY_MAX_EVIDENCE) throw new Error(\"Evidence too large\");\n const parsed = provider.parseEvidence(evidence);\n const verified = boundVerifiedIdentity(await provider.verify(statement, parsed, ctx));\n if (provider.category === \"self-custodied\" && verified.subject !== binding.subject) throw new Error(\"The evidence is for another identity\");\n if (provider.category === \"provider-attested\" && !verified.attester) throw new Error(\"The evidence does not say who attests it\");\n return verified;\n}\n\n/** Problems with a provider's descriptor, empty when it is well-formed. The registry and the contract suite use it. */\nexport function descriptorProblems(p: IdentityProofProvider): string[] {\n const problems: string[] = [];\n if (!/^[a-z][a-z0-9-]{0,31}$/.test(p.id)) problems.push(\"id must match ^[a-z][a-z0-9-]{0,31}$\");\n if (!p.label?.trim()) problems.push(\"label is empty\");\n if (!p.description?.trim()) problems.push(\"description is empty\");\n if (!p.privacy?.trim()) problems.push(\"privacy is empty: say what verify contacts\");\n if (p.category !== \"self-custodied\" && p.category !== \"provider-attested\") problems.push(\"category is unknown\");\n if (!p.platforms.length) problems.push(\"no platforms\");\n const { defaultDays, maxDays } = p.validity;\n if (!(Number.isInteger(defaultDays) && Number.isInteger(maxDays) && defaultDays >= 1 && defaultDays <= maxDays && maxDays * DAY <= IDENTITY_MAX_VALIDITY)) problems.push(\"validity must be whole days, 1 ≤ default ≤ max ≤ 400\");\n if (p.recheck && !(Number.isInteger(p.recheck.afterSeconds) && p.recheck.afterSeconds >= 60)) problems.push(\"recheck.afterSeconds must be at least 60\");\n if (!p.signers.length) problems.push(\"no signers\");\n const ids = p.signers.map(s => s.id);\n if (new Set(ids).size !== ids.length) problems.push(\"signer ids are not unique\");\n for (const s of p.signers as readonly IdentitySigner<unknown>[]) {\n if (![\"in-app\", \"external-tool\", \"redirect\", \"publish\"].includes(s.kind)) problems.push(`signer ${s.id} has an unknown kind`);\n if (s.kind === \"in-app\" && typeof s.run !== \"function\") problems.push(`signer ${s.id} has no run()`);\n if (s.kind === \"external-tool\" && (typeof s.instructions !== \"function\" || typeof s.parse !== \"function\")) problems.push(`signer ${s.id} needs instructions() and parse()`);\n if (s.kind === \"redirect\" && typeof s.start !== \"function\") problems.push(`signer ${s.id} has no start()`);\n if (s.kind === \"publish\" && (typeof s.instructions !== \"function\" || typeof s.evidence !== \"function\")) problems.push(`signer ${s.id} needs instructions() and evidence()`);\n }\n return problems;\n}\n\n/** Signers of a provider that run on this platform and are available in this window. */\nexport function availableSigners<E>(p: IdentityProofProvider<E>, platform: IdentityProofProvider[\"platforms\"][number]): IdentitySigner<E>[] {\n return p.signers.filter(s => (s.platforms ?? p.platforms).includes(platform) && (s.available?.() ?? true));\n}\n\n/**\n * The engine's `ctx.fetch`: HTTPS GET only, no credentials or referrer, a time-out, a size cap,\n * redirects refused unless asked for.\n * `online` false refuses everything (the person turned the network off).\n */\nexport function boundedIdentityFetch(options: { online: () => boolean; timeoutMs?: number; fetcher?: typeof fetch } = { online: () => true }): IdentityFetch {\n return async (url, { headers, maxBytes = 64 * 1024, signal, redirect = \"error\" } = {}) => {\n if (!options.online()) throw new Error(\"Offline: this identity cannot be checked now\");\n const target = new URL(url);\n if (target.protocol !== \"https:\" || target.username || target.password) throw new Error(\"Identity checks use HTTPS only\");\n const timeout = AbortSignal.timeout(options.timeoutMs ?? 10_000);\n const response = await (options.fetcher ?? fetch)(target.href, {\n headers, signal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n credentials: \"omit\", referrerPolicy: \"no-referrer\", cache: \"no-store\", redirect,\n });\n if (Number(response.headers.get(\"content-length\")) > maxBytes) throw new Error(\"Identity check response too large\");\n const reader = response.body?.getReader();\n const parts: Uint8Array[] = [];\n let length = 0;\n if (reader) {\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n length += value.length;\n if (length > maxBytes) throw new Error(\"Identity check response too large\");\n parts.push(value);\n }\n } finally { await reader.cancel().catch(() => {}); }\n }\n const bytes = new Uint8Array(length);\n let offset = 0;\n for (const part of parts) { bytes.set(part, offset); offset += part.length; }\n return { status: response.status, contentType: response.headers.get(\"content-type\") ?? \"\", text: new TextDecoder().decode(bytes), bytes };\n };\n}\n","import type { GhostlyAdapterPlugin } from \"./registry\";\n\n/**\n * The adapter plugins compiled into this build. Empty unless the build lists some: `GHOSTLY_PLUGINS`\n * names their modules (comma-separated paths from the repository root, each default-exporting a\n * `GhostlyAdapterPlugin`), and the Vite plugin in `packages/browser/vite-plugin.ts` swaps this module\n * for one that imports them. Release builds never set it; the e2e build carries the SDK example.\n */\nexport const BUNDLED_PLUGINS: readonly GhostlyAdapterPlugin[] = [];\n","import type { LightningProviderDescriptor } from \"../engine/paymentAdapters/providers/lightning\";\nimport type { OnchainProviderDescriptor } from \"../engine/paymentAdapters/providers/onchain\";\nimport { providerDescriptorProblems, type ProviderDescriptor, type ProviderKind } from \"../engine/paymentAdapters/providers/types\";\nimport type { IdentityProofProvider } from \"../proofs/contract\";\nimport { descriptorProblems } from \"../proofs/verify\";\nimport { BUNDLED_PLUGINS } from \"./bundled\";\n\n/**\n * Adapters written outside the app: wallet sources (Lightning, on-chain) and identity-proof providers\n * that register here instead of being added to the built-in lists. A plugin is a plain object naming\n * its adapters; the registries (`providers/registry.ts`, `proofs/registry.ts`) list what is registered\n * after the built-ins and before the test fakes, and the same platform and mode rules apply to all.\n *\n * Two ways in:\n * - at build time: `GHOSTLY_PLUGINS` lists the modules and `bundled.ts` is swapped for them;\n * - at run time: code already running in the engine's realm calls `registerAdapters` before the\n * pickers are shown (or after: the engine re-reads the lists when something registers).\n *\n * Trust: a plugin runs with the app's privileges, in the app's own JavaScript realm. There is no\n * sandbox, no permission prompt and no store; whoever builds a plugin in, or loads one, trusts its\n * author with everything the app can do, keys and sats included. A manifest with permissions and an\n * isolated runtime are a later phase (docs/wisps/ADAPTER-ROADMAP.md, \"Plugins, apps, catalogs\").\n *\n * The state lives on `globalThis` under a well-known symbol, so a plugin bundled with its own copy of\n * the SDK (a second copy of this module) still registers into the same lists the app reads.\n */\n\n/** The generation of the adapter contracts. A plugin says which one it was written against. */\nexport const SDK_API = 1;\nexport const PLUGIN_ID = /^[a-z][a-z0-9-]{0,63}$/;\n\nexport interface GhostlyAdapterPlugin {\n /** Stable, unique among plugins: `^[a-z][a-z0-9-]{0,63}$`. */\n id: string;\n /** The plugin's own version, for people. */\n version?: string;\n /** The contract generation it was written against: `SDK_API`. Another one is refused. */\n sdk: number;\n lightning?: readonly LightningProviderDescriptor[];\n onchain?: readonly OnchainProviderDescriptor[];\n identities?: readonly IdentityProofProvider[];\n}\n\nexport type AdapterKind = ProviderKind | \"identity\";\n\ninterface Store {\n plugins: Map<string, GhostlyAdapterPlugin>;\n /** Ids the built-in registries own, per kind: a plugin cannot take one. */\n reserved: Record<AdapterKind, Set<string>>;\n listeners: Set<() => void>;\n seeded: boolean;\n}\n\nconst KEY = Symbol.for(\"ghostly.adapters/1\");\nfunction store(): Store {\n const g = globalThis as unknown as Record<symbol, Store | undefined>;\n return (g[KEY] ??= { plugins: new Map(), reserved: { lightning: new Set(), onchain: new Set(), identity: new Set() }, listeners: new Set(), seeded: false });\n}\n\nconst ids = (kind: AdapterKind, plugin: GhostlyAdapterPlugin): string[] => {\n // Not trusted to be well formed: pluginProblems reads it before saying what is wrong with it.\n const list: unknown = kind === \"identity\" ? plugin.identities : kind === \"lightning\" ? plugin.lightning : plugin.onchain;\n return Array.isArray(list) ? list.map((a: { id?: string } | null) => a?.id as string) : [];\n};\nconst KINDS: readonly AdapterKind[] = [\"lightning\", \"onchain\", \"identity\"];\n\n/** Problems with a plugin, empty when it can be registered. Does not look at what is already registered. */\nexport function pluginProblems(plugin: GhostlyAdapterPlugin): string[] {\n const problems: string[] = [];\n if (!plugin || typeof plugin !== \"object\") return [\"not a plugin object\"];\n if (!PLUGIN_ID.test(plugin.id ?? \"\")) problems.push(\"plugin id must match ^[a-z][a-z0-9-]{0,63}$\");\n if (plugin.sdk !== SDK_API) problems.push(`plugin was written for SDK API ${String(plugin.sdk)}; this app speaks ${SDK_API}`);\n if (plugin.version !== undefined && (typeof plugin.version !== \"string\" || plugin.version.length > 64)) problems.push(\"version must be a short string\");\n for (const kind of [\"lightning\", \"onchain\"] as const) {\n const list = plugin[kind];\n if (list === undefined) continue;\n if (!Array.isArray(list)) { problems.push(`${kind} must be a list of descriptors`); continue; }\n for (const d of list as ProviderDescriptor<unknown>[]) {\n if (!d || typeof d !== \"object\") { problems.push(`${kind} ${String(d)}: not a descriptor`); continue; }\n const own = providerDescriptorProblems(d);\n if (d?.kind && d.kind !== kind) own.push(`is listed under ${kind} but says kind ${String(d.kind)}`);\n problems.push(...own.map((p) => `${kind} ${String(d?.id)}: ${p}`));\n }\n }\n if (plugin.identities !== undefined) {\n if (!Array.isArray(plugin.identities)) problems.push(\"identities must be a list of providers\");\n else for (const p of plugin.identities) {\n if (!p || typeof p !== \"object\") problems.push(`identity ${String(p)}: not a provider`);\n else problems.push(...descriptorProblems(p).map((m) => `identity ${String(p.id)}: ${m}`));\n }\n }\n for (const kind of KINDS) {\n const list = ids(kind, plugin);\n if (new Set(list).size !== list.length) problems.push(`${kind} ids are not unique within the plugin`);\n }\n if (!KINDS.some((kind) => ids(kind, plugin).length)) problems.push(\"the plugin brings no adapter\");\n return problems;\n}\n\n/** The built-in registries say which ids are theirs. A plugin using one is refused. */\nexport function reserveAdapterIds(kind: AdapterKind, list: readonly string[]): void {\n const s = store();\n for (const id of list) s.reserved[kind].add(id);\n}\n\n/**\n * Registers a plugin's adapters. Throws, registering nothing, when the plugin is malformed, its id or\n * one of its adapters' ids is taken (by a built-in or by another plugin), or its contract generation\n * is another one. Returns the function that unregisters it.\n */\nexport function registerAdapters(plugin: GhostlyAdapterPlugin): () => void {\n const problems = pluginProblems(plugin);\n const s = store();\n if (!problems.length) {\n if (s.plugins.has(plugin.id)) problems.push(`a plugin with id ${plugin.id} is already registered`);\n for (const kind of KINDS) for (const id of ids(kind, plugin)) {\n if (s.reserved[kind].has(id)) problems.push(`${kind} ${id} is a built-in of this app`);\n for (const other of s.plugins.values()) if (ids(kind, other).includes(id)) problems.push(`${kind} ${id} is already registered by plugin ${other.id}`);\n }\n }\n if (problems.length) throw new Error(`Cannot register plugin ${String(plugin?.id)}: ${problems.join(\"; \")}`);\n s.plugins.set(plugin.id, plugin);\n notify(s);\n return () => { if (s.plugins.get(plugin.id) === plugin) { s.plugins.delete(plugin.id); notify(s); } };\n}\n\nfunction notify(s: Store) { for (const listener of s.listeners) { try { listener(); } catch { /* a listener's problem */ } } }\n\n/** Called when a plugin registers or unregisters: the engine re-reads the lists. */\nexport function onAdaptersChanged(listener: () => void): () => void {\n const s = store();\n s.listeners.add(listener);\n return () => { s.listeners.delete(listener); };\n}\n\n/** Every registered plugin, in registration order (bundled ones first). */\nexport function registeredPlugins(): readonly GhostlyAdapterPlugin[] { seed(); return [...store().plugins.values()]; }\nexport function registeredLightningProviders(): readonly LightningProviderDescriptor[] { return registeredPlugins().flatMap((p) => p.lightning ?? []); }\nexport function registeredOnchainProviders(): readonly OnchainProviderDescriptor[] { return registeredPlugins().flatMap((p) => p.onchain ?? []); }\nexport function registeredIdentityProviders(): readonly IdentityProofProvider[] { return registeredPlugins().flatMap((p) => p.identities ?? []); }\n\n/**\n * The plugins compiled into this build register once, when they are first asked for. A broken one is\n * reported and skipped rather than taking the app down with it; the e2e that expects it fails instead.\n */\nfunction seed() {\n const s = store();\n if (s.seeded) return;\n s.seeded = true;\n for (const plugin of BUNDLED_PLUGINS) {\n try { registerAdapters(plugin); }\n catch (error) { console.error(`[ghostly] a bundled adapter plugin was not loaded: ${error instanceof Error ? error.message : String(error)}`); }\n }\n}\n\n/** Tests only: forget every registration, including the bundled ones. */\nexport function resetAdapterRegistry(): void {\n const s = store();\n s.plugins.clear(); s.seeded = false;\n for (const kind of KINDS) s.reserved[kind].clear();\n notify(s);\n}\n","/**\n * The profile's own Ghostly did:dht, which the DID provider refuses as an external identity. The UI and the engine each\n * set where to read it. Here, not in the provider, so setting it does not load the providers.\n */\nlet source: () => string | undefined = () => undefined;\nexport function setOwnDidSource(read: () => string | undefined): void { source = read; }\nexport const ownDid = (): string | undefined => source();\n","import {\n DOMAIN_FILE_MAX_BYTES, decodeDnsResponse, dnsProofName, encodeDnsQuery, isPublicAddress, nip05RootKey, normalizeDomain,\n recordsFromTxt, recordsFromWellKnown, recordsName, toBase64Url, txtValue, wellKnownUrl,\n type DnsResponse, type DnsType, type DomainMethod, type DomainRecord,\n} from '@ghostly/core';\nimport type { IdentityFetch } from './contract';\n\n/**\n * Network side of domain proofs: DNS TXT through DNS over HTTPS and the\n * `/.well-known/` files, under strict limits. Nothing here trusts the prover:\n * the domain comes from the signed binding, the URLs are built here, every\n * answer is bounded and parsed strictly, and lookups are cached only briefly.\n *\n * What a check reveals, and to whom:\n * - DNS: the chosen resolver learns that this device looked up `_ghostly.<domain>`\n * (the next one in DOH_RESOLVERS too, when the chosen one gives no answer).\n * The domain's own servers see only the resolver.\n * - HTTPS / NIP-05: the resolver learns the domain (its addresses are looked up\n * first, to refuse private networks), and the domain's web server — run by\n * the person being checked — sees this device's IP address and when.\n */\n\nexport type DohResolverId = 'quad9' | 'cloudflare' | 'google';\nexport interface DohResolver { id: DohResolverId; name: string; url: string }\n/** Public resolvers that answer RFC 8484 wire-format GETs with CORS (checked 2026-09-23). */\nexport const DOH_RESOLVERS: readonly DohResolver[] = [\n { id: 'quad9', name: 'Quad9', url: 'https://dns.quad9.net/dns-query' },\n { id: 'cloudflare', name: 'Cloudflare', url: 'https://cloudflare-dns.com/dns-query' },\n { id: 'google', name: 'Google', url: 'https://dns.google/dns-query' },\n];\nexport const DEFAULT_RESOLVER: DohResolverId = 'quad9';\nexport const resolverById = (id: string | null | undefined): DohResolver =>\n DOH_RESOLVERS.find(r => r.id === id) ?? DOH_RESOLVERS.find(r => r.id === DEFAULT_RESOLVER)!;\n\n/** The person's resolver choice, per browser profile (UI and engine share the origin). */\nexport const RESOLVER_SETTING = 'ghostly-doh-resolver';\nexport function chosenResolver(): DohResolver {\n try { return resolverById(globalThis.localStorage?.getItem(RESOLVER_SETTING)); } catch { return resolverById(undefined); }\n}\nexport function chooseResolver(id: DohResolverId): void {\n try { globalThis.localStorage?.setItem(RESOLVER_SETTING, resolverById(id).id); } catch { /* not persisted: the default stays */ }\n}\n\nexport const DNS_MAX_BYTES = 16 * 1024;\n/**\n * Lookups are shared between checks for the DNS TTL, capped: never staler than the resolver itself would\n * be, so a re-check sees a removal as soon as DNS does. Files have no TTL and are only shared in flight.\n */\nconst CACHE_MAX_MS = 30_000, CACHE_FILE_MS = 0;\n\n/** The contract's `ctx.fetch`: HTTPS GET, no credentials, bounded, redirects refused unless asked, with raw bytes. */\nexport type DomainFetch = IdentityFetch;\n\nexport interface DomainLookupOptions {\n fetch: DomainFetch;\n resolver?: DohResolverId;\n signal?: AbortSignal;\n /** Milliseconds. */\n now?: () => number;\n}\n\n/** A check that did not confirm the record, with a message for people. */\nexport class DomainCheckError extends Error {}\n\n/** A resolver that gave no DNS answer at all: not reached, or it refused the request. The next one may answer. */\nclass ResolverUnavailable extends DomainCheckError {}\n\n/** One RFC 8484 GET to one resolver. The query has ID 0 and no client subnet, so it carries only the name. */\nasync function askResolver(resolver: DohResolver, name: string, type: DnsType, options: DomainLookupOptions): Promise<DnsResponse> {\n let response: Awaited<ReturnType<DomainFetch>>;\n try {\n response = await options.fetch(`${resolver.url}?dns=${toBase64Url(encodeDnsQuery(name, type))}`, {\n headers: { accept: 'application/dns-message' }, maxBytes: DNS_MAX_BYTES, signal: options.signal, redirect: 'error' });\n } catch (e) {\n throw /too large/i.test(String(e))\n ? new DomainCheckError(`${resolver.name} sent an answer that is too large`)\n : new ResolverUnavailable(`${resolver.name} could not be reached`);\n }\n if (response.status !== 200 || !/^application\\/dns-message\\b/i.test(response.contentType))\n throw new ResolverUnavailable(`${resolver.name} refused the lookup`);\n let answer: DnsResponse;\n try { answer = decodeDnsResponse(response.bytes, name, type); } catch { throw new DomainCheckError(`${resolver.name} sent an unusable answer`); }\n if (answer.rcode !== 0 && answer.rcode !== 3) throw new DomainCheckError(`${resolver.name} could not resolve ${name}`);\n return answer;\n}\n\n/**\n * A lookup through the chosen resolver, and through the others in turn (in list order) only when it gives no DNS\n * answer at all. Quad9, for one, cannot be read from WebKit (the Mac desktop app, Safari): its HTTP/3 answers carry\n * no CORS header. An answer, even \"no such name\" or a failure, is never asked again elsewhere. `resolver`: who answered.\n */\nexport async function dohQuery(name: string, type: DnsType, options: DomainLookupOptions): Promise<DnsResponse & { resolver: DohResolverId }> {\n const chosen = resolverById(options.resolver);\n let first: DomainCheckError | undefined;\n for (const resolver of [chosen, ...DOH_RESOLVERS.filter(r => r !== chosen)]) {\n try { return { ...await askResolver(resolver, name, type, options), resolver: resolver.id }; }\n catch (e) {\n if (!(e instanceof ResolverUnavailable) || options.signal?.aborted) throw e;\n first ??= e;\n }\n }\n throw first!;\n}\n\n/**\n * Refuses a domain whose addresses are not all public before its web server is\n * contacted, so a proof cannot make a contact's app probe their own network.\n * The browser resolves again when it fetches; a name that changes its answer in\n * between (rebinding) is not fully excluded by this check — see the draft.\n */\nexport async function assertPublicHost(domain: string, options: DomainLookupOptions): Promise<void> {\n const [v4, v6] = await Promise.all([dohQuery(domain, 'A', options), dohQuery(domain, 'AAAA', options)]);\n const addresses = [...v4.answers, ...v6.answers].map(a => a.data);\n if (!addresses.length) throw new DomainCheckError(`${domain} has no address`);\n if (!addresses.every(isPublicAddress)) throw new DomainCheckError(`${domain} points to a private network address, so it was not contacted`);\n}\n\n/** A well-known file: https only, no redirects, bounded. `undefined` when the server says it is not there. */\nexport async function fetchWellKnown(domain: string, method: 'https' | 'nip05', options: DomainLookupOptions): Promise<string | undefined> {\n await assertPublicHost(domain, options);\n const url = wellKnownUrl(domain, method);\n let response: Awaited<ReturnType<DomainFetch>>;\n try {\n response = await options.fetch(url, { headers: { accept: 'application/json' }, maxBytes: DOMAIN_FILE_MAX_BYTES, signal: options.signal, redirect: 'error' });\n } catch (e) {\n throw new DomainCheckError(/too large/i.test(String(e)) ? `${url} is too large`\n : `${domain} could not be reached. The file must be served at exactly this address, without a redirect, with the header Access-Control-Allow-Origin: *`);\n }\n if (response.status === 404 || response.status === 410) return;\n if (response.status >= 300 && response.status < 400) throw new DomainCheckError(`${domain} answered with a redirect; the file must be served at exactly ${url}`);\n if (response.status !== 200) throw new DomainCheckError(`${domain} answered ${response.status}`);\n try { return new TextDecoder('utf-8', { fatal: true }).decode(response.bytes); } catch { throw new DomainCheckError(`${url} is not text`); }\n}\n\nexport interface DomainLookup {\n domain: string;\n method: DomainMethod;\n /** DNS / HTTPS: the Ghostly records found. */\n records: DomainRecord[];\n /** NIP-05: the Nostr key named for the domain itself. */\n nostrKey?: string;\n /** A record or file exists at all (as opposed to nothing there). */\n found: boolean;\n /** The resolver reported DNSSEC validation of the TXT answer. */\n dnssec: boolean;\n resolver: DohResolverId;\n}\n\nasync function lookup(domain: string, method: DomainMethod, options: DomainLookupOptions): Promise<DomainLookup & { ttlMs: number }> {\n const resolver = resolverById(options.resolver).id;\n if (method === 'dns') {\n const answer = await dohQuery(dnsProofName(domain), 'TXT', options);\n const values: string[] = [];\n for (const record of answer.answers.slice(0, 32)) { try { values.push(txtValue(record.data)); } catch { /* not text: not ours */ } }\n const ttlMs = answer.answers.length ? Math.min(...answer.answers.map(a => a.ttl)) * 1000 : 0;\n return { domain, method, resolver: answer.resolver, records: recordsFromTxt(values), found: answer.answers.length > 0, dnssec: answer.authenticated, ttlMs };\n }\n const text = await fetchWellKnown(domain, method, options);\n const base = { domain, method, resolver, dnssec: false, records: [] as DomainRecord[], ttlMs: CACHE_FILE_MS };\n if (text === undefined) return { ...base, found: false };\n try {\n return method === 'nip05' ? { ...base, found: true, nostrKey: nip05RootKey(text) } : { ...base, found: true, records: recordsFromWellKnown(text) };\n } catch { throw new DomainCheckError(`${wellKnownUrl(domain, method)} is not a valid ${method === 'nip05' ? 'NIP-05' : 'Ghostly'} file`); }\n}\n\nconst cache = new Map<string, { until: number; result: Promise<DomainLookup & { ttlMs: number }> }>();\n/** Tests only. */\nexport function clearDomainCache(): void { cache.clear(); }\n\n/** What a domain publishes by one method. Concurrent and back-to-back checks share one lookup. */\nexport async function lookupDomain(domainInput: string, method: DomainMethod, options: DomainLookupOptions): Promise<DomainLookup> {\n const domain = normalizeDomain(domainInput), now = options.now ?? Date.now, resolver = resolverById(options.resolver).id;\n const id = `${resolver}|${method}|${domain}`;\n const hit = cache.get(id);\n if (hit && hit.until > now()) { const { ttlMs: _ttl, ...result } = await hit.result; return result; }\n const started = now();\n const entry = { until: started + CACHE_MAX_MS, result: lookup(domain, method, { ...options, resolver }) };\n cache.set(id, entry);\n if (cache.size > 128) cache.delete(cache.keys().next().value!);\n try {\n const { ttlMs, ...result } = await entry.result;\n entry.until = started + Math.min(CACHE_MAX_MS, ttlMs);\n return result;\n } catch (e) {\n if (cache.get(id) === entry) cache.delete(id);\n throw e;\n }\n}\n\n/** Throws unless `domain` publishes `record` by `method` (DNS or HTTPS). Returns what was found. */\nexport async function assertDomainRecord(domain: string, method: 'dns' | 'https', record: DomainRecord, options: DomainLookupOptions): Promise<DomainLookup> {\n const found = await lookupDomain(domain, method, options);\n if (recordsName(found.records, record)) return found;\n const where = method === 'dns' ? `The TXT record at ${dnsProofName(domain)}` : wellKnownUrl(domain);\n if (found.records.some(r => r.key === record.key)) throw new DomainCheckError(`${where} is for another proof of this key`);\n if (found.records.length) throw new DomainCheckError(`${where} names another Ghostly key: this proof was replaced or removed`);\n throw new DomainCheckError(method === 'dns'\n ? `No Ghostly TXT record at ${dnsProofName(domain)}${found.found ? '' : ' (DNS changes can take a few minutes)'}`\n : found.found ? `${wellKnownUrl(domain)} names no Ghostly proof` : `${wellKnownUrl(domain)} was not found`);\n}\n\n/** Throws unless the domain's NIP-05 root name is `nostrKey`. */\nexport async function assertNip05(domain: string, nostrKey: string, options: DomainLookupOptions): Promise<DomainLookup> {\n const found = await lookupDomain(domain, 'nip05', options);\n if (found.nostrKey === nostrKey) return found;\n const url = wellKnownUrl(domain, 'nip05');\n throw new DomainCheckError(!found.found ? `${url} was not found` : found.nostrKey\n ? `${url} names another Nostr key for ${domain}` : `${url} has no root name \"_\" for ${domain}`);\n}\n","import { atprotoDidMethod, isAtprotoDid, parseAtprotoDidDocument, txtValue, type AtprotoDidDocument } from \"@ghostly/core\";\nimport type { IdentityFetch } from \"../contract\";\nimport { assertPublicHost, dohQuery, type DohResolverId } from \"../domain\";\n\n/**\n * AT Protocol identity resolution, the network half: a DID to its document (the PLC directory for\n * did:plc, the host's `/.well-known/did.json` for did:web), and a handle to a DID (DNS TXT\n * `_atproto.<handle>` through the person's DNS-over-HTTPS resolver, then\n * `https://<handle>/.well-known/atproto-did`). Every request goes through the contract's bounded\n * fetch: HTTPS only, no redirects, a size cap, a time-out. URLs are built here from the DID or the\n * handle, never taken from a proof.\n */\n\nexport const PLC_DIRECTORY = \"https://plc.directory\";\nconst TEST_HOST = /^https:\\/\\/[a-z0-9-]+(\\.[a-z0-9-]+)*\\.test$/;\n/** DID documents are small; a large answer is not one. */\nexport const DID_DOCUMENT_MAX_BYTES = 32 * 1024;\nconst HANDLE_DID_MAX_BYTES = 2048;\n\n/**\n * The PLC directory. A build made for the e2e suite with VITE_ATPROTO_TEST_PLC may point it at a\n * `.test` host (a name reserved for testing); a release build always uses plc.directory.\n */\nexport function plcDirectory(): string {\n try {\n const value = import.meta.env?.VITE_ATPROTO_TEST_PLC as string | undefined;\n return value && TEST_HOST.test(value) ? value : PLC_DIRECTORY;\n } catch { return PLC_DIRECTORY; }\n}\n\nexport interface AtprotoResolveOptions {\n fetch: IdentityFetch;\n signal?: AbortSignal;\n /** The DoH resolver for handles (the person's choice, as for domains). */\n resolver?: DohResolverId;\n /** The PLC directory; plcDirectory() by default. */\n plc?: string;\n}\n\n/** Where a DID's document lives. */\nexport function didDocumentUrl(did: string, plc = plcDirectory()): string {\n const method = atprotoDidMethod(did);\n if (method === \"plc\") return `${plc}/${did}`;\n if (method === \"web\") return `https://${did.slice(\"did:web:\".length)}/.well-known/did.json`;\n throw new Error(\"Not an AT Protocol DID\");\n}\n\n/**\n * Refuses a host the account chose (a did:web host, the PDS its document names) that points to a private\n * network address: a contact's app never knocks on its own local network for someone else's proof.\n */\nexport async function assertPublicServer(host: string, options: AtprotoResolveOptions): Promise<void> {\n try { await assertPublicHost(host, { fetch: options.fetch, signal: options.signal, resolver: options.resolver }); }\n catch (e) { throw new Error(`The account's server ${host} was not contacted: ${e instanceof Error ? e.message : String(e)}`); } // eslint-disable-line preserve-caught-error -- The domain check's message says why; ES2020 has no Error.cause.\n}\n\n/** A DID's document, checked (parseAtprotoDidDocument). Throws a message people can read. */\nexport async function resolveAtprotoDid(did: string, options: AtprotoResolveOptions): Promise<AtprotoDidDocument> {\n const url = didDocumentUrl(did, options.plc);\n if (atprotoDidMethod(did) === \"web\") await assertPublicServer(did.slice(\"did:web:\".length), options);\n let response: Awaited<ReturnType<IdentityFetch>>;\n try {\n response = await options.fetch(url, { headers: { accept: \"application/did+ld+json, application/json\" }, maxBytes: DID_DOCUMENT_MAX_BYTES, signal: options.signal, redirect: \"error\" });\n } catch (e) {\n // eslint-disable-next-line preserve-caught-error -- A message people can act on; the library's error stays out of the UI (ES2020 has no Error.cause).\n throw new Error(/too large/i.test(String(e)) ? \"The account's DID document is too large\" : \"The account's DID could not be resolved\");\n }\n if (response.status === 404 || response.status === 410) throw new Error(\"The account's DID is not registered, or was deactivated\");\n if (response.status !== 200) throw new Error(\"The account's DID could not be resolved\");\n let doc: unknown;\n try { doc = JSON.parse(response.text); } catch { throw new Error(\"The account's DID document is malformed\"); }\n return parseAtprotoDidDocument(doc, did);\n}\n\n/**\n * The DID a handle points to, or null when it points nowhere (or to two different DIDs). DNS first,\n * then HTTPS, as the handle spec says. The HTTPS lookup first checks the handle's addresses are public,\n * so a handle cannot make a contact's app knock on its local network.\n */\nexport async function resolveAtprotoHandle(handle: string, options: AtprotoResolveOptions): Promise<string | null> {\n const lookup = { fetch: options.fetch, signal: options.signal, resolver: options.resolver };\n try {\n const answer = await dohQuery(`_atproto.${handle}`, \"TXT\", lookup);\n const dids = new Set<string>();\n for (const a of answer.answers) {\n if (a.type !== 16) continue;\n let text: string;\n try { text = txtValue(a.data); } catch { continue; }\n if (text.startsWith(\"did=\")) dids.add(text.slice(4));\n }\n if (dids.size > 1) return null;\n const [did] = dids;\n if (did) return isAtprotoDid(did) ? did : null;\n } catch { /* The resolver failed: try HTTPS. */ }\n try {\n await assertPublicHost(handle, lookup);\n const response = await options.fetch(`https://${handle}/.well-known/atproto-did`, { headers: { accept: \"text/plain\" }, maxBytes: HANDLE_DID_MAX_BYTES, signal: options.signal, redirect: \"error\" });\n if (response.status !== 200) return null;\n const did = response.text.trim();\n return isAtprotoDid(did) ? did : null;\n } catch { return null; }\n}\n\n/**\n * The handle to show for a DID: the one its document claims, and only if that handle resolves back to\n * the same DID. Otherwise nothing: the card shows the DID. Never throws.\n */\nexport async function verifiedAtprotoHandle(doc: AtprotoDidDocument, options: AtprotoResolveOptions): Promise<string | undefined> {\n if (!doc.handle) return undefined;\n try { return (await resolveAtprotoHandle(doc.handle, options)) === doc.did ? doc.handle : undefined; } catch { return undefined; }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"resolve-B63_uSu7.js","names":[],"sources":["../../../browser/src/shared/features.ts","../../../browser/src/proofs/verify.ts","../../../browser/src/plugins/bundled.ts","../../../browser/src/plugins/registry.ts","../../../browser/src/proofs/ownDid.ts","../../../browser/src/proofs/domain.ts","../../../browser/src/proofs/atproto/resolve.ts"],"sourcesContent":["/** Release policy: external identity experiments are retained for future work,\n * but must not advertise capabilities, start network lookups, or expose cached\n * external profiles. This does not gate Ghostly participation authentication. */\nexport const EXTERNAL_IDENTITIES_ENABLED: boolean = false;\n\n/** Mini-apps (WISP 1200): `apps/1` on paired sessions and the engine's `app*` calls. On from release 1.2 (a version\n * before 1.2.0 is never cut with it on: `RELEASE_GUARDS` in tools/scripts/changes.mjs). Off, nothing is offered to\n * contacts and every call is refused; a host that runs no apps pins its engine off (`NodeOptions.apps`). */\nexport const APPS_ENABLED: boolean = true;\n\n/**\n * A build that may be put into test mode: a development build (`import.meta.env.DEV`, which vitest also sets) or the\n * e2e suite's build (`VITE_APPS_TEST`, fixed when the build is made, as the mini-app switch is). A release build is\n * neither: Vite folds this to `false` there, so the storage flags the test fakes answer to are ignored. The fakes\n * themselves are still in the bundle (the registries import them); plugins may still pass fakes to the registry.\n */\nexport const testBuild = (): boolean => { try { return !!import.meta.env?.DEV || import.meta.env?.VITE_APPS_TEST === \"1\"; } catch { return false; } };\n","import { boundVerifiedIdentity, IDENTITY_MAX_EVIDENCE, IDENTITY_MAX_VALIDITY, type IdentityStatement, type VerifiedIdentity } from \"@ghostly/core\";\nimport type { IdentityFetch, IdentityProofProvider, IdentitySigner, VerifyContext } from \"./contract\";\n\nconst DAY = 86_400;\n\n/**\n * The checks every proof goes through, whatever its provider: known provider, validity within the\n * provider's limit, bounded evidence, strict parsing, the provider's own check, and the category rule\n * (a self-custodied proof proves exactly the subject it names; an attested one says who attests it).\n * The engine verifies a contact's proof, and the person's own proof before saving it, only through this.\n */\nexport async function verifyIdentity(providers: readonly IdentityProofProvider[], statement: IdentityStatement, evidence: unknown, ctx: VerifyContext): Promise<VerifiedIdentity> {\n const { binding } = statement;\n const provider = providers.find(p => p.id === binding.provider);\n if (!provider) throw new Error(\"This app cannot verify this kind of identity\");\n if (binding.expiresAt - binding.issuedAt > Math.min(provider.validity.maxDays * DAY, IDENTITY_MAX_VALIDITY)) throw new Error(\"The proof lasts longer than this kind of identity allows\");\n if (JSON.stringify(evidence ?? null).length > IDENTITY_MAX_EVIDENCE) throw new Error(\"Evidence too large\");\n const parsed = provider.parseEvidence(evidence);\n const verified = boundVerifiedIdentity(await provider.verify(statement, parsed, ctx));\n if (provider.category === \"self-custodied\" && verified.subject !== binding.subject) throw new Error(\"The evidence is for another identity\");\n if (provider.category === \"provider-attested\" && !verified.attester) throw new Error(\"The evidence does not say who attests it\");\n return verified;\n}\n\n/** Problems with a provider's descriptor, empty when it is well-formed. The registry and the contract suite use it. */\nexport function descriptorProblems(p: IdentityProofProvider): string[] {\n const problems: string[] = [];\n if (!/^[a-z][a-z0-9-]{0,31}$/.test(p.id)) problems.push(\"id must match ^[a-z][a-z0-9-]{0,31}$\");\n if (!p.label?.trim()) problems.push(\"label is empty\");\n if (!p.description?.trim()) problems.push(\"description is empty\");\n if (!p.privacy?.trim()) problems.push(\"privacy is empty: say what verify contacts\");\n if (p.category !== \"self-custodied\" && p.category !== \"provider-attested\") problems.push(\"category is unknown\");\n if (!p.platforms.length) problems.push(\"no platforms\");\n const { defaultDays, maxDays } = p.validity;\n if (!(Number.isInteger(defaultDays) && Number.isInteger(maxDays) && defaultDays >= 1 && defaultDays <= maxDays && maxDays * DAY <= IDENTITY_MAX_VALIDITY)) problems.push(\"validity must be whole days, 1 ≤ default ≤ max ≤ 400\");\n if (p.recheck && !(Number.isInteger(p.recheck.afterSeconds) && p.recheck.afterSeconds >= 60)) problems.push(\"recheck.afterSeconds must be at least 60\");\n if (!p.signers.length) problems.push(\"no signers\");\n const ids = p.signers.map(s => s.id);\n if (new Set(ids).size !== ids.length) problems.push(\"signer ids are not unique\");\n for (const s of p.signers as readonly IdentitySigner<unknown>[]) {\n if (![\"in-app\", \"external-tool\", \"redirect\", \"publish\"].includes(s.kind)) problems.push(`signer ${s.id} has an unknown kind`);\n if (s.kind === \"in-app\" && typeof s.run !== \"function\") problems.push(`signer ${s.id} has no run()`);\n if (s.kind === \"external-tool\" && (typeof s.instructions !== \"function\" || typeof s.parse !== \"function\")) problems.push(`signer ${s.id} needs instructions() and parse()`);\n if (s.kind === \"redirect\" && typeof s.start !== \"function\") problems.push(`signer ${s.id} has no start()`);\n if (s.kind === \"publish\" && (typeof s.instructions !== \"function\" || typeof s.evidence !== \"function\")) problems.push(`signer ${s.id} needs instructions() and evidence()`);\n }\n return problems;\n}\n\n/** Signers of a provider that run on this platform and are available in this window. */\nexport function availableSigners<E>(p: IdentityProofProvider<E>, platform: IdentityProofProvider[\"platforms\"][number]): IdentitySigner<E>[] {\n return p.signers.filter(s => (s.platforms ?? p.platforms).includes(platform) && (s.available?.() ?? true));\n}\n\n/**\n * The engine's `ctx.fetch`: HTTPS GET only, no credentials or referrer, a time-out, a size cap,\n * redirects refused unless asked for.\n * `online` false refuses everything (the person turned the network off).\n */\nexport function boundedIdentityFetch(options: { online: () => boolean; timeoutMs?: number; fetcher?: typeof fetch } = { online: () => true }): IdentityFetch {\n return async (url, { headers, maxBytes = 64 * 1024, signal, redirect = \"error\" } = {}) => {\n if (!options.online()) throw new Error(\"Offline: this identity cannot be checked now\");\n const target = new URL(url);\n if (target.protocol !== \"https:\" || target.username || target.password) throw new Error(\"Identity checks use HTTPS only\");\n const timeout = AbortSignal.timeout(options.timeoutMs ?? 10_000);\n const response = await (options.fetcher ?? fetch)(target.href, {\n headers, signal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n credentials: \"omit\", referrerPolicy: \"no-referrer\", cache: \"no-store\", redirect,\n });\n if (Number(response.headers.get(\"content-length\")) > maxBytes) throw new Error(\"Identity check response too large\");\n const reader = response.body?.getReader();\n const parts: Uint8Array[] = [];\n let length = 0;\n if (reader) {\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n length += value.length;\n if (length > maxBytes) throw new Error(\"Identity check response too large\");\n parts.push(value);\n }\n } finally { await reader.cancel().catch(() => {}); }\n }\n const bytes = new Uint8Array(length);\n let offset = 0;\n for (const part of parts) { bytes.set(part, offset); offset += part.length; }\n return { status: response.status, contentType: response.headers.get(\"content-type\") ?? \"\", text: new TextDecoder().decode(bytes), bytes };\n };\n}\n","import type { GhostlyAdapterPlugin } from \"./registry\";\n\n/**\n * The adapter plugins compiled into this build. Empty unless the build lists some: `GHOSTLY_PLUGINS`\n * names their modules (comma-separated paths from the repository root, each default-exporting a\n * `GhostlyAdapterPlugin`), and the Vite plugin in `packages/browser/vite-plugin.ts` swaps this module\n * for one that imports them. Release builds never set it; the e2e build carries the SDK example.\n */\nexport const BUNDLED_PLUGINS: readonly GhostlyAdapterPlugin[] = [];\n","import type { LightningProviderDescriptor } from \"../engine/paymentAdapters/providers/lightning\";\nimport type { OnchainProviderDescriptor } from \"../engine/paymentAdapters/providers/onchain\";\nimport { providerDescriptorProblems, type ProviderDescriptor, type ProviderKind } from \"../engine/paymentAdapters/providers/types\";\nimport type { IdentityProofProvider } from \"../proofs/contract\";\nimport { descriptorProblems } from \"../proofs/verify\";\nimport { BUNDLED_PLUGINS } from \"./bundled\";\n\n/**\n * Adapters written outside the app: wallet sources (Lightning, on-chain) and identity-proof providers\n * that register here instead of being added to the built-in lists. A plugin is a plain object naming\n * its adapters; the registries (`providers/registry.ts`, `proofs/registry.ts`) list what is registered\n * after the built-ins and before the test fakes, and the same platform and mode rules apply to all.\n *\n * Two ways in:\n * - at build time: `GHOSTLY_PLUGINS` lists the modules and `bundled.ts` is swapped for them;\n * - at run time: code already running in the engine's realm calls `registerAdapters` before the\n * pickers are shown (or after: the engine re-reads the lists when something registers).\n *\n * Trust: a plugin runs with the app's privileges, in the app's own JavaScript realm. There is no\n * sandbox, no permission prompt and no store; whoever builds a plugin in, or loads one, trusts its\n * author with everything the app can do, keys and sats included. A manifest with permissions and an\n * isolated runtime are a later phase (docs/wisps/ADAPTER-ROADMAP.md, \"Plugins, apps, catalogs\").\n *\n * The state lives on `globalThis` under a well-known symbol, so a plugin bundled with its own copy of\n * the SDK (a second copy of this module) still registers into the same lists the app reads.\n */\n\n/** The generation of the adapter contracts. A plugin says which one it was written against. */\nexport const SDK_API = 1;\nexport const PLUGIN_ID = /^[a-z][a-z0-9-]{0,63}$/;\n\nexport interface GhostlyAdapterPlugin {\n /** Stable, unique among plugins: `^[a-z][a-z0-9-]{0,63}$`. */\n id: string;\n /** The plugin's own version, for people. */\n version?: string;\n /** The contract generation it was written against: `SDK_API`. Another one is refused. */\n sdk: number;\n lightning?: readonly LightningProviderDescriptor[];\n onchain?: readonly OnchainProviderDescriptor[];\n identities?: readonly IdentityProofProvider[];\n}\n\nexport type AdapterKind = ProviderKind | \"identity\";\n\ninterface Store {\n plugins: Map<string, GhostlyAdapterPlugin>;\n /** Ids the built-in registries own, per kind: a plugin cannot take one. */\n reserved: Record<AdapterKind, Set<string>>;\n listeners: Set<() => void>;\n seeded: boolean;\n}\n\nconst KEY = Symbol.for(\"ghostly.adapters/1\");\nfunction store(): Store {\n const g = globalThis as unknown as Record<symbol, Store | undefined>;\n return (g[KEY] ??= { plugins: new Map(), reserved: { lightning: new Set(), onchain: new Set(), identity: new Set() }, listeners: new Set(), seeded: false });\n}\n\nconst ids = (kind: AdapterKind, plugin: GhostlyAdapterPlugin): string[] => {\n // Not trusted to be well formed: pluginProblems reads it before saying what is wrong with it.\n const list: unknown = kind === \"identity\" ? plugin.identities : kind === \"lightning\" ? plugin.lightning : plugin.onchain;\n return Array.isArray(list) ? list.map((a: { id?: string } | null) => a?.id as string) : [];\n};\nconst KINDS: readonly AdapterKind[] = [\"lightning\", \"onchain\", \"identity\"];\n\n/** Problems with a plugin, empty when it can be registered. Does not look at what is already registered. */\nexport function pluginProblems(plugin: GhostlyAdapterPlugin): string[] {\n const problems: string[] = [];\n if (!plugin || typeof plugin !== \"object\") return [\"not a plugin object\"];\n if (!PLUGIN_ID.test(plugin.id ?? \"\")) problems.push(\"plugin id must match ^[a-z][a-z0-9-]{0,63}$\");\n if (plugin.sdk !== SDK_API) problems.push(`plugin was written for SDK API ${String(plugin.sdk)}; this app speaks ${SDK_API}`);\n if (plugin.version !== undefined && (typeof plugin.version !== \"string\" || plugin.version.length > 64)) problems.push(\"version must be a short string\");\n for (const kind of [\"lightning\", \"onchain\"] as const) {\n const list = plugin[kind];\n if (list === undefined) continue;\n if (!Array.isArray(list)) { problems.push(`${kind} must be a list of descriptors`); continue; }\n for (const d of list as ProviderDescriptor<unknown>[]) {\n if (!d || typeof d !== \"object\") { problems.push(`${kind} ${String(d)}: not a descriptor`); continue; }\n const own = providerDescriptorProblems(d);\n if (d?.kind && d.kind !== kind) own.push(`is listed under ${kind} but says kind ${String(d.kind)}`);\n problems.push(...own.map((p) => `${kind} ${String(d?.id)}: ${p}`));\n }\n }\n if (plugin.identities !== undefined) {\n if (!Array.isArray(plugin.identities)) problems.push(\"identities must be a list of providers\");\n else for (const p of plugin.identities) {\n if (!p || typeof p !== \"object\") problems.push(`identity ${String(p)}: not a provider`);\n else problems.push(...descriptorProblems(p).map((m) => `identity ${String(p.id)}: ${m}`));\n }\n }\n for (const kind of KINDS) {\n const list = ids(kind, plugin);\n if (new Set(list).size !== list.length) problems.push(`${kind} ids are not unique within the plugin`);\n }\n if (!KINDS.some((kind) => ids(kind, plugin).length)) problems.push(\"the plugin brings no adapter\");\n return problems;\n}\n\n/** The built-in registries say which ids are theirs. A plugin using one is refused. */\nexport function reserveAdapterIds(kind: AdapterKind, list: readonly string[]): void {\n const s = store();\n for (const id of list) s.reserved[kind].add(id);\n}\n\n/**\n * Registers a plugin's adapters. Throws, registering nothing, when the plugin is malformed, its id or\n * one of its adapters' ids is taken (by a built-in or by another plugin), or its contract generation\n * is another one. Returns the function that unregisters it.\n */\nexport function registerAdapters(plugin: GhostlyAdapterPlugin): () => void {\n const problems = pluginProblems(plugin);\n const s = store();\n if (!problems.length) {\n if (s.plugins.has(plugin.id)) problems.push(`a plugin with id ${plugin.id} is already registered`);\n for (const kind of KINDS) for (const id of ids(kind, plugin)) {\n if (s.reserved[kind].has(id)) problems.push(`${kind} ${id} is a built-in of this app`);\n for (const other of s.plugins.values()) if (ids(kind, other).includes(id)) problems.push(`${kind} ${id} is already registered by plugin ${other.id}`);\n }\n }\n if (problems.length) throw new Error(`Cannot register plugin ${String(plugin?.id)}: ${problems.join(\"; \")}`);\n s.plugins.set(plugin.id, plugin);\n notify(s);\n return () => { if (s.plugins.get(plugin.id) === plugin) { s.plugins.delete(plugin.id); notify(s); } };\n}\n\nfunction notify(s: Store) { for (const listener of s.listeners) { try { listener(); } catch { /* a listener's problem */ } } }\n\n/** Called when a plugin registers or unregisters: the engine re-reads the lists. */\nexport function onAdaptersChanged(listener: () => void): () => void {\n const s = store();\n s.listeners.add(listener);\n return () => { s.listeners.delete(listener); };\n}\n\n/** Every registered plugin, in registration order (bundled ones first). */\nexport function registeredPlugins(): readonly GhostlyAdapterPlugin[] { seed(); return [...store().plugins.values()]; }\nexport function registeredLightningProviders(): readonly LightningProviderDescriptor[] { return registeredPlugins().flatMap((p) => p.lightning ?? []); }\nexport function registeredOnchainProviders(): readonly OnchainProviderDescriptor[] { return registeredPlugins().flatMap((p) => p.onchain ?? []); }\nexport function registeredIdentityProviders(): readonly IdentityProofProvider[] { return registeredPlugins().flatMap((p) => p.identities ?? []); }\n\n/**\n * The plugins compiled into this build register once, when they are first asked for. A broken one is\n * reported and skipped rather than taking the app down with it; the e2e that expects it fails instead.\n */\nfunction seed() {\n const s = store();\n if (s.seeded) return;\n s.seeded = true;\n for (const plugin of BUNDLED_PLUGINS) {\n try { registerAdapters(plugin); }\n catch (error) { console.error(`[ghostly] a bundled adapter plugin was not loaded: ${error instanceof Error ? error.message : String(error)}`); }\n }\n}\n\n/** Tests only: forget every registration, including the bundled ones. */\nexport function resetAdapterRegistry(): void {\n const s = store();\n s.plugins.clear(); s.seeded = false;\n for (const kind of KINDS) s.reserved[kind].clear();\n notify(s);\n}\n","/**\n * The profile's own Ghostly did:dht, which the DID provider refuses as an external identity. The UI and the engine each\n * set where to read it. Here, not in the provider, so setting it does not load the providers.\n */\nlet source: () => string | undefined = () => undefined;\nexport function setOwnDidSource(read: () => string | undefined): void { source = read; }\nexport const ownDid = (): string | undefined => source();\n","import {\n DOMAIN_FILE_MAX_BYTES, decodeDnsResponse, dnsProofName, encodeDnsQuery, isPublicAddress, nip05RootKey, normalizeDomain,\n recordsFromTxt, recordsFromWellKnown, recordsName, toBase64Url, txtValue, wellKnownUrl,\n type DnsResponse, type DnsType, type DomainMethod, type DomainRecord,\n} from '@ghostly/core';\nimport type { IdentityFetch } from './contract';\n\n/**\n * Network side of domain proofs: DNS TXT through DNS over HTTPS and the\n * `/.well-known/` files, under strict limits. Nothing here trusts the prover:\n * the domain comes from the signed binding, the URLs are built here, every\n * answer is bounded and parsed strictly, and lookups are cached only briefly.\n *\n * What a check reveals, and to whom:\n * - DNS: the chosen resolver learns that this device looked up `_ghostly.<domain>`\n * (the next one in DOH_RESOLVERS too, when the chosen one gives no answer).\n * The domain's own servers see only the resolver.\n * - HTTPS / NIP-05: the resolver learns the domain (its addresses are looked up\n * first, to refuse private networks), and the domain's web server — run by\n * the person being checked — sees this device's IP address and when.\n */\n\nexport type DohResolverId = 'quad9' | 'cloudflare' | 'google';\nexport interface DohResolver { id: DohResolverId; name: string; url: string }\n/** Public resolvers that answer RFC 8484 wire-format GETs with CORS (checked 2026-09-23). */\nexport const DOH_RESOLVERS: readonly DohResolver[] = [\n { id: 'quad9', name: 'Quad9', url: 'https://dns.quad9.net/dns-query' },\n { id: 'cloudflare', name: 'Cloudflare', url: 'https://cloudflare-dns.com/dns-query' },\n { id: 'google', name: 'Google', url: 'https://dns.google/dns-query' },\n];\nexport const DEFAULT_RESOLVER: DohResolverId = 'quad9';\nexport const resolverById = (id: string | null | undefined): DohResolver =>\n DOH_RESOLVERS.find(r => r.id === id) ?? DOH_RESOLVERS.find(r => r.id === DEFAULT_RESOLVER)!;\n\n/** The person's resolver choice, per browser profile (UI and engine share the origin). */\nexport const RESOLVER_SETTING = 'ghostly-doh-resolver';\nexport function chosenResolver(): DohResolver {\n try { return resolverById(globalThis.localStorage?.getItem(RESOLVER_SETTING)); } catch { return resolverById(undefined); }\n}\nexport function chooseResolver(id: DohResolverId): void {\n try { globalThis.localStorage?.setItem(RESOLVER_SETTING, resolverById(id).id); } catch { /* not persisted: the default stays */ }\n}\n\nexport const DNS_MAX_BYTES = 16 * 1024;\n/**\n * Lookups are shared between checks for the DNS TTL, capped: never staler than the resolver itself would\n * be, so a re-check sees a removal as soon as DNS does. Files have no TTL and are only shared in flight.\n */\nconst CACHE_MAX_MS = 30_000, CACHE_FILE_MS = 0;\n\n/** The contract's `ctx.fetch`: HTTPS GET, no credentials, bounded, redirects refused unless asked, with raw bytes. */\nexport type DomainFetch = IdentityFetch;\n\nexport interface DomainLookupOptions {\n fetch: DomainFetch;\n resolver?: DohResolverId;\n signal?: AbortSignal;\n /** Milliseconds. */\n now?: () => number;\n}\n\n/** A check that did not confirm the record, with a message for people. */\nexport class DomainCheckError extends Error {}\n\n/** A resolver that gave no DNS answer at all: not reached, or it refused the request. The next one may answer. */\nclass ResolverUnavailable extends DomainCheckError {}\n\n/** One RFC 8484 GET to one resolver. The query has ID 0 and no client subnet, so it carries only the name. */\nasync function askResolver(resolver: DohResolver, name: string, type: DnsType, options: DomainLookupOptions): Promise<DnsResponse> {\n let response: Awaited<ReturnType<DomainFetch>>;\n try {\n response = await options.fetch(`${resolver.url}?dns=${toBase64Url(encodeDnsQuery(name, type))}`, {\n headers: { accept: 'application/dns-message' }, maxBytes: DNS_MAX_BYTES, signal: options.signal, redirect: 'error' });\n } catch (e) {\n throw /too large/i.test(String(e))\n ? new DomainCheckError(`${resolver.name} sent an answer that is too large`)\n : new ResolverUnavailable(`${resolver.name} could not be reached`);\n }\n if (response.status !== 200 || !/^application\\/dns-message\\b/i.test(response.contentType))\n throw new ResolverUnavailable(`${resolver.name} refused the lookup`);\n let answer: DnsResponse;\n try { answer = decodeDnsResponse(response.bytes, name, type); } catch { throw new DomainCheckError(`${resolver.name} sent an unusable answer`); }\n if (answer.rcode !== 0 && answer.rcode !== 3) throw new DomainCheckError(`${resolver.name} could not resolve ${name}`);\n return answer;\n}\n\n/**\n * A lookup through the chosen resolver, and through the others in turn (in list order) only when it gives no DNS\n * answer at all. Quad9, for one, cannot be read from WebKit (the Mac desktop app, Safari): its HTTP/3 answers carry\n * no CORS header. An answer, even \"no such name\" or a failure, is never asked again elsewhere. `resolver`: who answered.\n */\nexport async function dohQuery(name: string, type: DnsType, options: DomainLookupOptions): Promise<DnsResponse & { resolver: DohResolverId }> {\n const chosen = resolverById(options.resolver);\n let first: DomainCheckError | undefined;\n for (const resolver of [chosen, ...DOH_RESOLVERS.filter(r => r !== chosen)]) {\n try { return { ...await askResolver(resolver, name, type, options), resolver: resolver.id }; }\n catch (e) {\n if (!(e instanceof ResolverUnavailable) || options.signal?.aborted) throw e;\n first ??= e;\n }\n }\n throw first!;\n}\n\n/**\n * Refuses a domain whose addresses are not all public before its web server is\n * contacted, so a proof cannot make a contact's app probe their own network.\n * The browser resolves again when it fetches; a name that changes its answer in\n * between (rebinding) is not fully excluded by this check — see the draft.\n */\nexport async function assertPublicHost(domain: string, options: DomainLookupOptions): Promise<void> {\n const [v4, v6] = await Promise.all([dohQuery(domain, 'A', options), dohQuery(domain, 'AAAA', options)]);\n const addresses = [...v4.answers, ...v6.answers].map(a => a.data);\n if (!addresses.length) throw new DomainCheckError(`${domain} has no address`);\n if (!addresses.every(isPublicAddress)) throw new DomainCheckError(`${domain} points to a private network address, so it was not contacted`);\n}\n\n/** A well-known file: https only, no redirects, bounded. `undefined` when the server says it is not there. */\nexport async function fetchWellKnown(domain: string, method: 'https' | 'nip05', options: DomainLookupOptions): Promise<string | undefined> {\n await assertPublicHost(domain, options);\n const url = wellKnownUrl(domain, method);\n let response: Awaited<ReturnType<DomainFetch>>;\n try {\n response = await options.fetch(url, { headers: { accept: 'application/json' }, maxBytes: DOMAIN_FILE_MAX_BYTES, signal: options.signal, redirect: 'error' });\n } catch (e) {\n throw new DomainCheckError(/too large/i.test(String(e)) ? `${url} is too large`\n : `${domain} could not be reached. The file must be served at exactly this address, without a redirect, with the header Access-Control-Allow-Origin: *`);\n }\n if (response.status === 404 || response.status === 410) return;\n if (response.status >= 300 && response.status < 400) throw new DomainCheckError(`${domain} answered with a redirect; the file must be served at exactly ${url}`);\n if (response.status !== 200) throw new DomainCheckError(`${domain} answered ${response.status}`);\n try { return new TextDecoder('utf-8', { fatal: true }).decode(response.bytes); } catch { throw new DomainCheckError(`${url} is not text`); }\n}\n\nexport interface DomainLookup {\n domain: string;\n method: DomainMethod;\n /** DNS / HTTPS: the Ghostly records found. */\n records: DomainRecord[];\n /** NIP-05: the Nostr key named for the domain itself. */\n nostrKey?: string;\n /** A record or file exists at all (as opposed to nothing there). */\n found: boolean;\n /** The resolver reported DNSSEC validation of the TXT answer. */\n dnssec: boolean;\n resolver: DohResolverId;\n}\n\nasync function lookup(domain: string, method: DomainMethod, options: DomainLookupOptions): Promise<DomainLookup & { ttlMs: number }> {\n const resolver = resolverById(options.resolver).id;\n if (method === 'dns') {\n const answer = await dohQuery(dnsProofName(domain), 'TXT', options);\n const values: string[] = [];\n for (const record of answer.answers.slice(0, 32)) { try { values.push(txtValue(record.data)); } catch { /* not text: not ours */ } }\n const ttlMs = answer.answers.length ? Math.min(...answer.answers.map(a => a.ttl)) * 1000 : 0;\n return { domain, method, resolver: answer.resolver, records: recordsFromTxt(values), found: answer.answers.length > 0, dnssec: answer.authenticated, ttlMs };\n }\n const text = await fetchWellKnown(domain, method, options);\n const base = { domain, method, resolver, dnssec: false, records: [] as DomainRecord[], ttlMs: CACHE_FILE_MS };\n if (text === undefined) return { ...base, found: false };\n try {\n return method === 'nip05' ? { ...base, found: true, nostrKey: nip05RootKey(text) } : { ...base, found: true, records: recordsFromWellKnown(text) };\n } catch { throw new DomainCheckError(`${wellKnownUrl(domain, method)} is not a valid ${method === 'nip05' ? 'NIP-05' : 'Ghostly'} file`); }\n}\n\nconst cache = new Map<string, { until: number; result: Promise<DomainLookup & { ttlMs: number }> }>();\n/** Tests only. */\nexport function clearDomainCache(): void { cache.clear(); }\n\n/** What a domain publishes by one method. Concurrent and back-to-back checks share one lookup. */\nexport async function lookupDomain(domainInput: string, method: DomainMethod, options: DomainLookupOptions): Promise<DomainLookup> {\n const domain = normalizeDomain(domainInput), now = options.now ?? Date.now, resolver = resolverById(options.resolver).id;\n const id = `${resolver}|${method}|${domain}`;\n const hit = cache.get(id);\n if (hit && hit.until > now()) { const { ttlMs: _ttl, ...result } = await hit.result; return result; }\n const started = now();\n const entry = { until: started + CACHE_MAX_MS, result: lookup(domain, method, { ...options, resolver }) };\n cache.set(id, entry);\n if (cache.size > 128) cache.delete(cache.keys().next().value!);\n try {\n const { ttlMs, ...result } = await entry.result;\n entry.until = started + Math.min(CACHE_MAX_MS, ttlMs);\n return result;\n } catch (e) {\n if (cache.get(id) === entry) cache.delete(id);\n throw e;\n }\n}\n\n/** Throws unless `domain` publishes `record` by `method` (DNS or HTTPS). Returns what was found. */\nexport async function assertDomainRecord(domain: string, method: 'dns' | 'https', record: DomainRecord, options: DomainLookupOptions): Promise<DomainLookup> {\n const found = await lookupDomain(domain, method, options);\n if (recordsName(found.records, record)) return found;\n const where = method === 'dns' ? `The TXT record at ${dnsProofName(domain)}` : wellKnownUrl(domain);\n if (found.records.some(r => r.key === record.key)) throw new DomainCheckError(`${where} is for another proof of this key`);\n if (found.records.length) throw new DomainCheckError(`${where} names another Ghostly key: this proof was replaced or removed`);\n throw new DomainCheckError(method === 'dns'\n ? `No Ghostly TXT record at ${dnsProofName(domain)}${found.found ? '' : ' (DNS changes can take a few minutes)'}`\n : found.found ? `${wellKnownUrl(domain)} names no Ghostly proof` : `${wellKnownUrl(domain)} was not found`);\n}\n\n/** Throws unless the domain's NIP-05 root name is `nostrKey`. */\nexport async function assertNip05(domain: string, nostrKey: string, options: DomainLookupOptions): Promise<DomainLookup> {\n const found = await lookupDomain(domain, 'nip05', options);\n if (found.nostrKey === nostrKey) return found;\n const url = wellKnownUrl(domain, 'nip05');\n throw new DomainCheckError(!found.found ? `${url} was not found` : found.nostrKey\n ? `${url} names another Nostr key for ${domain}` : `${url} has no root name \"_\" for ${domain}`);\n}\n","import { atprotoDidMethod, isAtprotoDid, parseAtprotoDidDocument, txtValue, type AtprotoDidDocument } from \"@ghostly/core\";\nimport type { IdentityFetch } from \"../contract\";\nimport { assertPublicHost, dohQuery, type DohResolverId } from \"../domain\";\n\n/**\n * AT Protocol identity resolution, the network half: a DID to its document (the PLC directory for\n * did:plc, the host's `/.well-known/did.json` for did:web), and a handle to a DID (DNS TXT\n * `_atproto.<handle>` through the person's DNS-over-HTTPS resolver, then\n * `https://<handle>/.well-known/atproto-did`). Every request goes through the contract's bounded\n * fetch: HTTPS only, no redirects, a size cap, a time-out. URLs are built here from the DID or the\n * handle, never taken from a proof.\n */\n\nexport const PLC_DIRECTORY = \"https://plc.directory\";\nconst TEST_HOST = /^https:\\/\\/[a-z0-9-]+(\\.[a-z0-9-]+)*\\.test$/;\n/** DID documents are small; a large answer is not one. */\nexport const DID_DOCUMENT_MAX_BYTES = 32 * 1024;\nconst HANDLE_DID_MAX_BYTES = 2048;\n\n/**\n * The PLC directory. A build made for the e2e suite with VITE_ATPROTO_TEST_PLC may point it at a\n * `.test` host (a name reserved for testing); a release build always uses plc.directory.\n */\nexport function plcDirectory(): string {\n try {\n const value = import.meta.env?.VITE_ATPROTO_TEST_PLC as string | undefined;\n return value && TEST_HOST.test(value) ? value : PLC_DIRECTORY;\n } catch { return PLC_DIRECTORY; }\n}\n\nexport interface AtprotoResolveOptions {\n fetch: IdentityFetch;\n signal?: AbortSignal;\n /** The DoH resolver for handles (the person's choice, as for domains). */\n resolver?: DohResolverId;\n /** The PLC directory; plcDirectory() by default. */\n plc?: string;\n}\n\n/** Where a DID's document lives. */\nexport function didDocumentUrl(did: string, plc = plcDirectory()): string {\n const method = atprotoDidMethod(did);\n if (method === \"plc\") return `${plc}/${did}`;\n if (method === \"web\") return `https://${did.slice(\"did:web:\".length)}/.well-known/did.json`;\n throw new Error(\"Not an AT Protocol DID\");\n}\n\n/**\n * Refuses a host the account chose (a did:web host, the PDS its document names) that points to a private\n * network address: a contact's app never knocks on its own local network for someone else's proof.\n */\nexport async function assertPublicServer(host: string, options: AtprotoResolveOptions): Promise<void> {\n try { await assertPublicHost(host, { fetch: options.fetch, signal: options.signal, resolver: options.resolver }); }\n catch (e) { throw new Error(`The account's server ${host} was not contacted: ${e instanceof Error ? e.message : String(e)}`); } // eslint-disable-line preserve-caught-error -- The domain check's message says why; ES2020 has no Error.cause.\n}\n\n/** A DID's document, checked (parseAtprotoDidDocument). Throws a message people can read. */\nexport async function resolveAtprotoDid(did: string, options: AtprotoResolveOptions): Promise<AtprotoDidDocument> {\n const url = didDocumentUrl(did, options.plc);\n if (atprotoDidMethod(did) === \"web\") await assertPublicServer(did.slice(\"did:web:\".length), options);\n let response: Awaited<ReturnType<IdentityFetch>>;\n try {\n response = await options.fetch(url, { headers: { accept: \"application/did+ld+json, application/json\" }, maxBytes: DID_DOCUMENT_MAX_BYTES, signal: options.signal, redirect: \"error\" });\n } catch (e) {\n // eslint-disable-next-line preserve-caught-error -- A message people can act on; the library's error stays out of the UI (ES2020 has no Error.cause).\n throw new Error(/too large/i.test(String(e)) ? \"The account's DID document is too large\" : \"The account's DID could not be resolved\");\n }\n if (response.status === 404 || response.status === 410) throw new Error(\"The account's DID is not registered, or was deactivated\");\n if (response.status !== 200) throw new Error(\"The account's DID could not be resolved\");\n let doc: unknown;\n try { doc = JSON.parse(response.text); } catch { throw new Error(\"The account's DID document is malformed\"); }\n return parseAtprotoDidDocument(doc, did);\n}\n\n/**\n * The DID a handle points to, or null when it points nowhere (or to two different DIDs). DNS first,\n * then HTTPS, as the handle spec says. The HTTPS lookup first checks the handle's addresses are public,\n * so a handle cannot make a contact's app knock on its local network.\n */\nexport async function resolveAtprotoHandle(handle: string, options: AtprotoResolveOptions): Promise<string | null> {\n const lookup = { fetch: options.fetch, signal: options.signal, resolver: options.resolver };\n try {\n const answer = await dohQuery(`_atproto.${handle}`, \"TXT\", lookup);\n const dids = new Set<string>();\n for (const a of answer.answers) {\n if (a.type !== 16) continue;\n let text: string;\n try { text = txtValue(a.data); } catch { continue; }\n if (text.startsWith(\"did=\")) dids.add(text.slice(4));\n }\n if (dids.size > 1) return null;\n const [did] = dids;\n if (did) return isAtprotoDid(did) ? did : null;\n } catch { /* The resolver failed: try HTTPS. */ }\n try {\n await assertPublicHost(handle, lookup);\n const response = await options.fetch(`https://${handle}/.well-known/atproto-did`, { headers: { accept: \"text/plain\" }, maxBytes: HANDLE_DID_MAX_BYTES, signal: options.signal, redirect: \"error\" });\n if (response.status !== 200) return null;\n const did = response.text.trim();\n return isAtprotoDid(did) ? did : null;\n } catch { return null; }\n}\n\n/**\n * The handle to show for a DID: the one its document claims, and only if that handle resolves back to\n * the same DID. Otherwise nothing: the card shows the DID. Never throws.\n */\nexport async function verifiedAtprotoHandle(doc: AtprotoDidDocument, options: AtprotoResolveOptions): Promise<string | undefined> {\n if (!doc.handle) return undefined;\n try { return (await resolveAtprotoHandle(doc.handle, options)) === doc.did ? doc.handle : undefined; } catch { return undefined; }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { i as STORES, u as openDb } from "./idb-B5L8wuOm.js";
1
+ import { d as openDb, i as STORES } from "./idb-CMVgtn2k.js";
2
2
  //#region ../browser/src/shared/restoredRows.ts
3
3
  /**
4
4
  * What a restore changes in the money a backup carries (WISP 05 § Restoring). A bundle holds the wallet as it stood
@@ -111,4 +111,4 @@ async function markLeftOutFiles(ids) {
111
111
  //#endregion
112
112
  export { markLeftOutFiles, markRestoredWallet };
113
113
 
114
- //# sourceMappingURL=restoredRows-Db3oUTko.js.map
114
+ //# sourceMappingURL=restoredRows-DeBImGRd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"restoredRows-Db3oUTko.js","names":[],"sources":["../../../browser/src/shared/restoredRows.ts"],"sourcesContent":["import { STORES, openDb } from \"./idb\";\n\n/**\n * What a restore changes in the money a backup carries (WISP 05 § Restoring). A bundle holds the wallet as it stood\n * when the backup was made, and the profile it came from may have gone on since: none of it is taken at its word.\n */\nexport const RESTORED_WALLET_STORES: readonly string[] = [STORES.proofs, STORES.swaps, STORES.intents];\n\n/** One row of `store` as a restore writes it. A row of any other store, or one that is not what it should be, is kept as it is. */\nexport function restoredWalletRow(store: string, value: unknown): unknown {\n if (!value || typeof value !== \"object\") return value;\n if (store === STORES.proofs) {\n // Ecash as it was when the backup was made: what was spent since is found by asking the mint, once the wallet runs.\n const proof = value as { secret?: unknown; reserved?: boolean };\n return typeof proof.secret === \"string\" && !proof.reserved ? { ...proof, unchecked: true } : value;\n }\n // A swap as it stood when the backup was made: what it brings is checked like the copy's ecash.\n if (store === STORES.swaps) return { ...value, restored: true };\n if (store === STORES.intents) {\n // An older copy cannot prove an unfinished attempt was never sent; it may not authorize a new one.\n const intent = value as { review?: { state?: string; method?: string } };\n // An on-chain review never approved stays unapproved: only Approve on this profile could send it, and a copy has none.\n if (intent.review?.method === \"bitcoin\" && intent.review.state === \"pending\") return { ...intent, review: { ...intent.review, state: \"cancelled\" } };\n return intent.review && [\"pending\", \"submitted\", \"unknown\"].includes(intent.review.state ?? \"\") ? { ...intent, review: { ...intent.review, state: \"unknown\" } } : value;\n }\n return value;\n}\n\n/**\n * The same, for a restore that brought the profile's database back whole (the headless CLI's): every wallet row of\n * this profile's database is rewritten as `restoredWalletRow` says, in one transaction, before the engine reads any.\n * Doing it twice changes nothing more.\n */\nexport async function markRestoredWallet(): Promise<void> {\n const db = await openDb();\n const names = RESTORED_WALLET_STORES.filter((name) => db.objectStoreNames.contains(name));\n if (!names.length) return;\n const tx = db.transaction(names, \"readwrite\");\n const done = new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onabort = () => reject(tx.error ?? new Error(\"The restored wallet could not be marked\"));\n tx.onerror = () => reject(tx.error ?? new Error(\"The restored wallet could not be marked\"));\n });\n for (const name of names) {\n const walk = tx.objectStore(name).openCursor();\n walk.onsuccess = () => {\n const cursor = walk.result;\n if (!cursor) return;\n const next = restoredWalletRow(name, cursor.value);\n if (next !== cursor.value) cursor.update(next);\n cursor.continue();\n };\n }\n return done;\n}\n\n/**\n * Files a light backup left out (WISP 05 § Light backups), for a restore that brought the database back whole (the\n * headless CLI's): each record is marked `leftOut`, and nothing of it says any longer where its bytes were. A file\n * not in the database is passed over. Doing it twice changes nothing more.\n */\nexport async function markLeftOutFiles(ids: readonly string[]): Promise<void> {\n if (!ids.length) return;\n const db = await openDb();\n const tx = db.transaction([STORES.files, STORES.fileState], \"readwrite\");\n const done = new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onabort = () => reject(tx.error ?? new Error(\"The files left out could not be marked\"));\n tx.onerror = () => reject(tx.error ?? new Error(\"The files left out could not be marked\"));\n });\n const files = tx.objectStore(STORES.files), states = tx.objectStore(STORES.fileState);\n for (const id of ids) {\n const read = files.get(id);\n read.onsuccess = () => {\n const record = read.result as { blob?: unknown; bytes?: unknown } | undefined;\n if (!record) return;\n const { blob: _blob, bytes: _bytes, ...rest } = record;\n files.put({ ...rest, leftOut: true });\n };\n const state = states.get(id);\n state.onsuccess = () => {\n const value = state.result as { bytes?: unknown } | undefined;\n if (!value || !(\"bytes\" in value)) return;\n const { bytes: _bytes, ...rest } = value;\n states.put(rest);\n };\n }\n return done;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"restoredRows-DeBImGRd.js","names":[],"sources":["../../../browser/src/shared/restoredRows.ts"],"sourcesContent":["import { STORES, openDb } from \"./idb\";\n\n/**\n * What a restore changes in the money a backup carries (WISP 05 § Restoring). A bundle holds the wallet as it stood\n * when the backup was made, and the profile it came from may have gone on since: none of it is taken at its word.\n */\nexport const RESTORED_WALLET_STORES: readonly string[] = [STORES.proofs, STORES.swaps, STORES.intents];\n\n/** One row of `store` as a restore writes it. A row of any other store, or one that is not what it should be, is kept as it is. */\nexport function restoredWalletRow(store: string, value: unknown): unknown {\n if (!value || typeof value !== \"object\") return value;\n if (store === STORES.proofs) {\n // Ecash as it was when the backup was made: what was spent since is found by asking the mint, once the wallet runs.\n const proof = value as { secret?: unknown; reserved?: boolean };\n return typeof proof.secret === \"string\" && !proof.reserved ? { ...proof, unchecked: true } : value;\n }\n // A swap as it stood when the backup was made: what it brings is checked like the copy's ecash.\n if (store === STORES.swaps) return { ...value, restored: true };\n if (store === STORES.intents) {\n // An older copy cannot prove an unfinished attempt was never sent; it may not authorize a new one.\n const intent = value as { review?: { state?: string; method?: string } };\n // An on-chain review never approved stays unapproved: only Approve on this profile could send it, and a copy has none.\n if (intent.review?.method === \"bitcoin\" && intent.review.state === \"pending\") return { ...intent, review: { ...intent.review, state: \"cancelled\" } };\n return intent.review && [\"pending\", \"submitted\", \"unknown\"].includes(intent.review.state ?? \"\") ? { ...intent, review: { ...intent.review, state: \"unknown\" } } : value;\n }\n return value;\n}\n\n/**\n * The same, for a restore that brought the profile's database back whole (the headless CLI's): every wallet row of\n * this profile's database is rewritten as `restoredWalletRow` says, in one transaction, before the engine reads any.\n * Doing it twice changes nothing more.\n */\nexport async function markRestoredWallet(): Promise<void> {\n const db = await openDb();\n const names = RESTORED_WALLET_STORES.filter((name) => db.objectStoreNames.contains(name));\n if (!names.length) return;\n const tx = db.transaction(names, \"readwrite\");\n const done = new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onabort = () => reject(tx.error ?? new Error(\"The restored wallet could not be marked\"));\n tx.onerror = () => reject(tx.error ?? new Error(\"The restored wallet could not be marked\"));\n });\n for (const name of names) {\n const walk = tx.objectStore(name).openCursor();\n walk.onsuccess = () => {\n const cursor = walk.result;\n if (!cursor) return;\n const next = restoredWalletRow(name, cursor.value);\n if (next !== cursor.value) cursor.update(next);\n cursor.continue();\n };\n }\n return done;\n}\n\n/**\n * Files a light backup left out (WISP 05 § Light backups), for a restore that brought the database back whole (the\n * headless CLI's): each record is marked `leftOut`, and nothing of it says any longer where its bytes were. A file\n * not in the database is passed over. Doing it twice changes nothing more.\n */\nexport async function markLeftOutFiles(ids: readonly string[]): Promise<void> {\n if (!ids.length) return;\n const db = await openDb();\n const tx = db.transaction([STORES.files, STORES.fileState], \"readwrite\");\n const done = new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onabort = () => reject(tx.error ?? new Error(\"The files left out could not be marked\"));\n tx.onerror = () => reject(tx.error ?? new Error(\"The files left out could not be marked\"));\n });\n const files = tx.objectStore(STORES.files), states = tx.objectStore(STORES.fileState);\n for (const id of ids) {\n const read = files.get(id);\n read.onsuccess = () => {\n const record = read.result as { blob?: unknown; bytes?: unknown } | undefined;\n if (!record) return;\n const { blob: _blob, bytes: _bytes, ...rest } = record;\n files.put({ ...rest, leftOut: true });\n };\n const state = states.get(id);\n state.onsuccess = () => {\n const value = state.result as { bytes?: unknown } | undefined;\n if (!value || !(\"bytes\" in value)) return;\n const { bytes: _bytes, ...rest } = value;\n states.put(rest);\n };\n }\n return done;\n}\n"],"mappings":"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"}