@ghostlytools/cli 1.3.4 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{api-BCwaCbKh.js → api-Br3msjtR.js} +2 -2
- package/dist/assets/{api-Bp_hWAiU.js → api-z9mlywrn.js} +9 -9
- package/dist/assets/{api-Bp_hWAiU.js.map → api-z9mlywrn.js.map} +1 -1
- package/dist/assets/{apiKit-3MLUyuhL.js → apiKit-lX3Xx_hY.js} +2 -2
- package/dist/assets/{apiKit-3MLUyuhL.js.map → apiKit-lX3Xx_hY.js.map} +1 -1
- package/dist/assets/{apps-BXw3Ui_3.js → apps-BUK6bEKW.js} +2 -2
- package/dist/assets/{apps-BXw3Ui_3.js.map → apps-BUK6bEKW.js.map} +1 -1
- package/dist/assets/{apps-B6gqk4GD.js → apps-Dn7rCafG.js} +1 -1
- package/dist/assets/{arkade-CyplNY_v.js → arkade-uqAXA5BT.js} +2 -2
- package/dist/assets/{arkade-CyplNY_v.js.map → arkade-uqAXA5BT.js.map} +1 -1
- package/dist/assets/{backup-BGE4BDzf.js → backup-CJQK5Miu.js} +4 -4
- package/dist/assets/{backup-BGE4BDzf.js.map → backup-CJQK5Miu.js.map} +1 -1
- package/dist/assets/{backup-Cm8ptQQA.js → backup-_JnqeFZb.js} +1 -1
- package/dist/assets/buttons-DDB9Xdha.js +2 -0
- package/dist/assets/{buttons-52NT4sA_.js → buttons-DDvTuViY.js} +3 -3
- package/dist/assets/{buttons-52NT4sA_.js.map → buttons-DDvTuViY.js.map} +1 -1
- package/dist/assets/{envelope-CsRRCrL3.js → envelope-BqvBb6hC.js} +2 -2
- package/dist/assets/{envelope-CsRRCrL3.js.map → envelope-BqvBb6hC.js.map} +1 -1
- package/dist/assets/{groupFiles-BurezP4Z.js → groupFiles-B1lL6wch.js} +31 -4
- package/dist/assets/{groupFiles-BurezP4Z.js.map → groupFiles-B1lL6wch.js.map} +1 -1
- package/dist/assets/{host-C74Sy5jT.js → host-DFzlKU3P.js} +8 -8
- package/dist/assets/{host-C74Sy5jT.js.map → host-DFzlKU3P.js.map} +1 -1
- package/dist/assets/{hyperdhtRelay-D0MvfMzX.js → hyperdhtRelay-DwlOY6aD.js} +2 -2
- package/dist/assets/{hyperdhtRelay-D0MvfMzX.js.map → hyperdhtRelay-DwlOY6aD.js.map} +1 -1
- package/dist/assets/{irohWeb-DynqwRwl.js → irohWeb-DZDCyL9b.js} +2 -2
- package/dist/assets/{irohWeb-DynqwRwl.js.map → irohWeb-DZDCyL9b.js.map} +1 -1
- package/dist/assets/{main-DNzQOdNG.js → main-DgbdDDif.js} +15 -15
- package/dist/assets/main-DgbdDDif.js.map +1 -0
- package/dist/assets/{mainline-COqCHn1R.js → mainline-BHE5-R3A.js} +2 -2
- package/dist/assets/{mainline-COqCHn1R.js.map → mainline-BHE5-R3A.js.map} +1 -1
- package/dist/assets/{networkReason-WikfjkIw.js → networkReason-Btv4b2C4.js} +2 -2
- package/dist/assets/{networkReason-WikfjkIw.js.map → networkReason-Btv4b2C4.js.map} +1 -1
- package/dist/assets/{nwc-ClsjYuyP.js → nwc-z0pa5zql.js} +3 -3
- package/dist/assets/{nwc-ClsjYuyP.js.map → nwc-z0pa5zql.js.map} +1 -1
- package/dist/assets/{nwcProvider-ksMYZra9.js → nwcProvider-C1AhPoFW.js} +2 -2
- package/dist/assets/{nwcProvider-ksMYZra9.js.map → nwcProvider-C1AhPoFW.js.map} +1 -1
- package/dist/assets/{registry-S7SFF_JB.js → registry-C09xXyx-.js} +1 -1
- package/dist/assets/{registry-CJh9L_kF.js → registry-JrnwUWmh.js} +3 -3
- package/dist/assets/{registry-CJh9L_kF.js.map → registry-JrnwUWmh.js.map} +1 -1
- package/dist/assets/{resolve-BJxBhU5j.js → resolve-Ssq1nDy4.js} +2 -2
- package/dist/assets/{resolve-BJxBhU5j.js.map → resolve-Ssq1nDy4.js.map} +1 -1
- package/dist/assets/{server-C05N9q4G.js → server-D6FSznK5.js} +97 -33
- package/dist/assets/server-D6FSznK5.js.map +1 -0
- package/dist/assets/{src-RQ6OJOUO.js → src-XhjSWnp-.js} +14 -3
- package/dist/assets/{src-RQ6OJOUO.js.map → src-XhjSWnp-.js.map} +1 -1
- package/dist/assets/{turnRefs-u-U75DFx.js → turnRefs-Cle33IoV.js} +2 -2
- package/dist/assets/{turnRefs-u-U75DFx.js.map → turnRefs-Cle33IoV.js.map} +1 -1
- package/dist/assets/{usdt-A1B3r3Mq.js → usdt-DO86yko2.js} +3 -3
- package/dist/assets/{usdt-A1B3r3Mq.js.map → usdt-DO86yko2.js.map} +1 -1
- package/dist/ghostly.mjs +1 -1
- package/package.json +1 -1
- package/dist/assets/buttons-PCvHRlkS.js +0 -2
- package/dist/assets/main-DNzQOdNG.js.map +0 -1
- package/dist/assets/server-C05N9q4G.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-
|
|
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-XhjSWnp-.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-
|
|
606
|
+
//# sourceMappingURL=resolve-Ssq1nDy4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-BJxBhU5j.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-Ssq1nDy4.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,16 +1,16 @@
|
|
|
1
1
|
import { n as traceJoin } from "./joinTrace-CjRDFy85.js";
|
|
2
|
-
import { $c as currentRelays, $i as revokesIdentity, $n as GROUP_FILE_LIMITS, $r as WAKE_CALL_INTERVAL_MS, $t as didDhtFromPublicKey, A as CommunitySession, Aa as forwardedAgain, Ac as devicePingFrame, Ao as rosterAdmin, Ar as newerHead, As as handoffOfferFrame, B as knockRecords, Ba as readReaction, Bc as TURN_MAX, Bi as capsDescriptors, Bn as findEndpoint, Bo as GhostlyHttpError, Br as transferStalled, Bs as readHandoffHave, C as sha256Paced, Ca as parseImageMeta, Cc as DEVICES_CAPABILITY, Ci as readManifest, Cl as randomBytes, Cn as isBitcoinAddress, Cr as beaconRecords, Cs as handoffContext, D as openGroupTyping, Da as RateWindow, Dc as deviceEchoNonce, Dl as utf8Encode, Do as MEMBER_KEY, Dr as lobbyRecords, Ds as handoffEphemeral, E as groupTypingEpoch, Ea as EDIT_RATE_WINDOW_MS, Ec as deviceEchoFrame, El as utf8Decode, Er as lobbyKeys, Es as handoffDigest, Et as normalizeAtprotoHandle, Fa as ReactionWindow, Fc as TURN_RAISE_READ_TIMEOUT_MS, Fr as readLobby, Fs as handoffVersions, G as groupWakeFrame, Ga as replySnippet, Gc as signTurnRelease, Gn as INVITE_TAKEN, Go as decodeControl, Gr as typingActivity, Gs as sealHandoffPiece, H as readKnocks, Ha as wireReaction, Hc as nextTurnPosition, Hn as parseCashuRequestPayload, Ho as parseLocalTarget, Hs as readHandoffPake, I as decodeGroupEntryLink, Ia as nextReactionNumber, Ic as TURN_SETTLE_MS, In as decodeBolt11, Io as DHT_POLL_INTERVALS, Ir as shouldBeHub, Is as newHandoffId, J as GROUP_LIMITS, Jc as turnName, Ji as emptyIdentityLedger, Jn as pairedMessageFits, Jo as RTC_CONFIG, Jr as mayPin, Js as readSetUpdate, K as groupWakes, Ka as BUTTON_ID, Kc as turnInstance, Ki as IdentityExchange, Kn as LIVENESS_PING_MS, Ko as encodeControl, L as encodeGroupEntryLink, La as queueReaction, Lc as classifyTurnRead, Ln as ENDPOINT, Lr as ChatFiles, Ls as readHandoffAck, M as communityHasFrame, Ma as COMMUNITY_REACTION_FRAME, Mc as seedSigner, Mo as verifyCommitSignature, Mr as rankHubs, Ms as handoffReleaseFrame, N as decodeCommunityLink, Na as GROUP_REACTION_FRAME, Nc as webCryptoSigner, No as edgeParams, Nr as readBeacon, Ns as handoffRetryAfter, O as sealGroupTyping, Oa as dhtEditId, Oc as deviceKeyZ32, Oo as commitHash, Or as mergeBeacon, Os as handoffHelloFrame, P as encodeCommunityLink, Pa as REACTION_LIMITS, Po as DirectPathWatch, Pr as readBeaconHead, Ps as handoffStreamKey, Q as frameBytes, Qc as RelayTransport, Qi as receivedIdentityStatus, Qn as parseEngineError, Qr as readPin, Qs as verifySetUpdate, Qt as didDhtDocument, R as entryParams, Ra as reactionEmoji, Rc as turnPutSummary, Ri as CapsExchange, Rn as cashuRequestPayload, Ro as RELAY_POLL_INTERVALS, Rr as FILE_LIMITS, Rs as readHandoffCancel, S as readAppBundleAsync, Sa as parseVideoMeta, Si as newMailbox, Sn as sparkInvoiceDetails, So as canonicalJson, Sr as beaconKeys, Ss as handoffCancelFrame, T as GroupTypingBoard, Ta as EDIT_BUFFER_MS, Tc as HANDOFF_CAPABILITY, Tl as toZ32, Tn as isPubkyKey, To as GROUP_MEMBER_CAP, Tr as freshHubs, Ts as handoffDataFrame, Tt as isAtprotoDid, Ua as pairedReplyAuthor, Uc as readTurnPacket, Un as parseFedimintRequestPayload, Uo as webLocalFetch, Ur as TypingSender, Us as readHandoffTurnFrame, V as mergeKnocks, Va as validReactionNumber, Vc as firstDeviceSetSecret, Vi as dialDescriptors, Vn as isFederationId, Vo as formatLocalTarget, Vs as readHandoffHello, W as GroupWakeLimiter, Wa as readReply, Wc as signTurnPacket, Wi as IDENTITY_REVOCATION_LABEL, Wn as GhostLink, Wo as LIMITS, Ws as readHandoffVerified, X as GROUP_READ_NOTE, Xc as turnVerifierMark, Xi as identityStatement, Xn as engineError, Xr as pinIsNewer, Xs as setUpdateFrame, Yc as turnStatedVerifier, Yi as identityRevocationValue, Yn as pairedMessageFrame, Yr as nextPinNumber, Ys as setAckFrame, Z as GroupSession, Za as STATUS_CARD_LIMITS, Zc as DEFAULT_RELAYS, Zi as newIdentityBinding, Zn as engineText, Zr as pinNumberHolds, Zs as signTombstone, _c as createChatInvite, _i as HOLD_DATED_BACK_MS, _n as validatePaymentTarget, _o as isAppRef, _r as MESH_HUBS, _s as filePartName, a as planAppUpdate, aa as automaticTransport, ac as enrollDigits, ai as wakeRequest, al as withRequestOptions, an as EVM_TEST_CHAINS, ao as arrivalKey, as as serviceIdFromName, at as groupName, b as pacer, ba as parseVoiceMeta, bi as HoldRefusedError, bl as bytesEqual, bn as SPARK_PROVIDER, br as pickMeshHubs, bs as handoffAttemptSucceeded, cc as enrollHelloFrame, cl as createRelayPayload, cn as SEPOLIA_TEST_USDT, co as receivedTimestamp, cs as HANDOFF_DONE, d as APP_BUNDLE_LIMITS, da as DHT_FILE_CAPABILITY, dc as readEnrollHello, di as APPS_CAPABILITY, dn as USDT_PUBLIC_RPC, do as APP_STATEMENT_LIMITS, ds as HANDOFF_OFFER, ea as lastSharedWithMe, ei as WakeLimiter, el as normalizeRelayUrl, en as encodeDidDhtDeactivated, es as parseCallSignal, f as APP_BUNDLE_MAGIC, fa as dhtFileId, fc as verifyEnrollProof, fi as BUTTONS_CAPABILITY, fl as createIdentity, fn as WALLET_NETWORKS, fo as appFingerprint, fs as HANDOFF_PAKE, g as appViewOf, gc as OwnInviteError, gi as HOLD_CAPABILITY, gl as verify, gn as formatPaymentAmount, go as isAppKey, gr as readGroupSignal, gs as HANDOFF_VERIFIED, h as appDigest, ha as sanitizeMime, hc as readDeviceInvite, hi as UPGRADE_CAPABILITY, hl as publicKeyFromZ32, hn as assertWholeSats, ho as isAppHash, hr as groupSignalFrame, hs as HANDOFF_TIMINGS, i as checkAppBeforeRun, ia as TRANSPORTS, ic as enrollCancelReason, ii as relayRequest, il as isDiscoveryBudgetError, in as ETHEREUM_USDT, io as statusCardText, ir as groupFileFallback, is as LEGACY_SERVICES, it as mentionsMember, j as GROUP_READ_NOTE_COMMUNITY, ja as readForwarded, jc as newDeviceSetSecret, jo as rosterHas, jr as pickHubs, js as handoffPakeFrame, k as COMMUNITY_LIMITS, ka as parseLinkPreview, kc as deviceLinkPairing, ko as parseGroupCommit, kr as mergeLobby, ks as handoffManifestFrames, l as readAppStoreSteps, la as DHT_MESSAGE_TTL, lc as enrollProofFrame, li as chatAppId, lo as shownTime, ls as HANDOFF_HAVE, ma as sanitizeFileName, mc as deviceInviteJoinerParams, mi as STATUS_CARD_CAPABILITY, ml as identityFromSeedB64, mn as assertTokenUnits, ms as HANDOFF_REQUEST, n as appStoreDecision, na as emptyProofLedger, ni as newWakeToken, nl as traceLink, no as checkStatusCard, ns as emptyLinkRecords, nt as carryMentions, o as APP_STORE_LIMITS, oc as enrollDoneFrame, oi as checkPushEndpoint, ol as PacketTooLargeError, on as ONCHAIN_PROVIDER, oo as claimedTime, or as readGroupFileMeta, os as HANDOFF_ACK, p as APP_ICON_PATH, pa as formatFileSize, pc as createDeviceInvite, pi as EDIT_CAPABILITY, pl as identityFromSeed, pn as arkAddressPrefix, po as appRef, ps as HANDOFF_PIECE_BYTES, q as parseGroupWakeFrame, qc as turnKeys, qn as PAIRED_FRAME_TOO_LARGE, qr as PIN_LIMITS, r as appUpdateDecision, ra as validExternalKey, rc as enrollCancelFrame, ri as parseWakeFrame, rl as budgetRetryMs, rn as signDidDhtPacket, ro as sameButtonText, rs as HTTP_SERVICE_PROTO, rt as parseCommunityEdit, sc as enrollGrantFrame, si as vapidKeysMatch, sn as PaymentPreflightError, so as heardTime, ss as HANDOFF_CANCEL, t as appRevocationFor, ta as PeerProofs, ti as deviceWakeRequest, tn as encodeDidDhtPacket, tt as GROUP_EDIT_TEXT_BYTES, ua as peekDhtMailbox, uc as readEnrollGrant, ui as isAppVersion, un as TEST_USDT_FAUCET_AMOUNT, ur as CarriedTransport, us as HANDOFF_HELLO, vc as decodeInviteCode, vi as HOLD_LIMITS, vl as sanitizeAvatar, vn as walletNetworkOf, vo as readAppRevocation, vr as mayBeHub, vs as handoffAttemptAllowed, wc as ENROLL_CAPABILITY, wl as toBase64Url, wo as readCanonicalJson, wr as doorHubs, ws as handoffContextProof, xc as inviteOwnership, xi as isHoldUrl, xl as fromBase64Url, xn as sparkAddressKind, xr as COMMUNITY_TOPOLOGY, xs as handoffBusyFrame, y as isAppUrl, ya as fileMessageText, yc as encodeInviteCode, yi as HoldKeys, yl as sanitizeDisplayText, yn as SPARK_NETWORKS, yr as meshHubs, ys as handoffAttemptFailed, z as knockIdentity, za as reactionIsNewer, zc as TURN_LAST_SEQUENCE, zi as DHT_TEXT_CAPABILITY, zn as fedimintRequestPayload, zo as presenceSeenAt, zr as transferEnded, zs as readHandoffDone } from "./src-
|
|
2
|
+
import { $c as currentRelays, $i as revokesIdentity, $n as GROUP_FILE_LIMITS, $r as WAKE_CALL_INTERVAL_MS, $t as didDhtFromPublicKey, A as CommunitySession, Aa as forwardedAgain, Ac as devicePingFrame, Ao as rosterAdmin, Ar as newerHead, As as handoffOfferFrame, B as knockRecords, Ba as readReaction, Bc as TURN_MAX, Bi as capsDescriptors, Bn as findEndpoint, Bo as GhostlyHttpError, Br as transferStalled, Bs as readHandoffHave, C as sha256Paced, Ca as parseImageMeta, Cc as DEVICES_CAPABILITY, Ci as readManifest, Cl as randomBytes, Cn as isBitcoinAddress, Cr as beaconRecords, Cs as handoffContext, D as openGroupTyping, Da as RateWindow, Dc as deviceEchoNonce, Dl as utf8Encode, Do as MEMBER_KEY, Dr as lobbyRecords, Ds as handoffEphemeral, E as groupTypingEpoch, Ea as EDIT_RATE_WINDOW_MS, Ec as deviceEchoFrame, El as utf8Decode, Er as lobbyKeys, Es as handoffDigest, Et as normalizeAtprotoHandle, Fa as ReactionWindow, Fc as TURN_RAISE_READ_TIMEOUT_MS, Fr as readLobby, Fs as handoffVersions, G as groupWakeFrame, Ga as replySnippet, Gc as signTurnRelease, Gn as INVITE_TAKEN, Go as decodeControl, Gr as typingActivity, Gs as sealHandoffPiece, H as readKnocks, Ha as wireReaction, Hc as nextTurnPosition, Hn as parseCashuRequestPayload, Ho as parseLocalTarget, Hs as readHandoffPake, I as decodeGroupEntryLink, Ia as nextReactionNumber, Ic as TURN_SETTLE_MS, In as decodeBolt11, Io as DHT_POLL_INTERVALS, Ir as shouldBeHub, Is as newHandoffId, J as GROUP_LIMITS, Jc as turnName, Ji as emptyIdentityLedger, Jn as pairedMessageFits, Jo as RTC_CONFIG, Jr as mayPin, Js as readSetUpdate, K as groupWakes, Ka as BUTTON_ID, Kc as turnInstance, Ki as IdentityExchange, Kn as LIVENESS_PING_MS, Ko as encodeControl, L as encodeGroupEntryLink, La as queueReaction, Lc as classifyTurnRead, Ln as ENDPOINT, Lr as ChatFiles, Ls as readHandoffAck, M as communityHasFrame, Ma as COMMUNITY_REACTION_FRAME, Mc as seedSigner, Mo as verifyCommitSignature, Mr as rankHubs, Ms as handoffReleaseFrame, N as decodeCommunityLink, Na as GROUP_REACTION_FRAME, Nc as webCryptoSigner, No as edgeParams, Nr as readBeacon, Ns as handoffRetryAfter, O as sealGroupTyping, Oa as dhtEditId, Oc as deviceKeyZ32, Oo as commitHash, Or as mergeBeacon, Os as handoffHelloFrame, P as encodeCommunityLink, Pa as REACTION_LIMITS, Po as DirectPathWatch, Pr as readBeaconHead, Ps as handoffStreamKey, Q as frameBytes, Qc as RelayTransport, Qi as receivedIdentityStatus, Qn as parseEngineError, Qr as readPin, Qs as verifySetUpdate, Qt as didDhtDocument, R as entryParams, Ra as reactionEmoji, Rc as turnPutSummary, Ri as CapsExchange, Rn as cashuRequestPayload, Ro as RELAY_POLL_INTERVALS, Rr as FILE_LIMITS, Rs as readHandoffCancel, S as readAppBundleAsync, Sa as parseVideoMeta, Si as newMailbox, Sn as sparkInvoiceDetails, So as canonicalJson, Sr as beaconKeys, Ss as handoffCancelFrame, T as GroupTypingBoard, Ta as EDIT_BUFFER_MS, Tc as HANDOFF_CAPABILITY, Tl as toZ32, Tn as isPubkyKey, To as GROUP_MEMBER_CAP, Tr as freshHubs, Ts as handoffDataFrame, Tt as isAtprotoDid, Ua as pairedReplyAuthor, Uc as readTurnPacket, Un as parseFedimintRequestPayload, Uo as webLocalFetch, Ur as TypingSender, Us as readHandoffTurnFrame, V as mergeKnocks, Va as validReactionNumber, Vc as firstDeviceSetSecret, Vi as dialDescriptors, Vn as isFederationId, Vo as formatLocalTarget, Vs as readHandoffHello, W as GroupWakeLimiter, Wa as readReply, Wc as signTurnPacket, Wi as IDENTITY_REVOCATION_LABEL, Wn as GhostLink, Wo as LIMITS, Ws as readHandoffVerified, X as GROUP_READ_NOTE, Xc as turnVerifierMark, Xi as identityStatement, Xn as engineError, Xr as pinIsNewer, Xs as setUpdateFrame, Yc as turnStatedVerifier, Yi as identityRevocationValue, Yn as pairedMessageFrame, Yr as nextPinNumber, Ys as setAckFrame, Z as GroupSession, Za as STATUS_CARD_LIMITS, Zc as DEFAULT_RELAYS, Zi as newIdentityBinding, Zn as engineText, Zr as pinNumberHolds, Zs as signTombstone, _c as createChatInvite, _i as HOLD_DATED_BACK_MS, _n as validatePaymentTarget, _o as isAppRef, _r as MESH_HUBS, _s as filePartName, a as planAppUpdate, aa as automaticTransport, ac as enrollDigits, ai as wakeRequest, al as withRequestOptions, an as EVM_TEST_CHAINS, ao as arrivalKey, as as serviceIdFromName, at as groupName, b as pacer, ba as parseVoiceMeta, bi as HoldRefusedError, bl as bytesEqual, bn as SPARK_PROVIDER, br as pickMeshHubs, bs as handoffAttemptSucceeded, cc as enrollHelloFrame, cl as createRelayPayload, cn as SEPOLIA_TEST_USDT, co as receivedTimestamp, cs as HANDOFF_DONE, d as APP_BUNDLE_LIMITS, da as DHT_FILE_CAPABILITY, dc as readEnrollHello, di as APPS_CAPABILITY, dn as USDT_PUBLIC_RPC, do as APP_STATEMENT_LIMITS, ds as HANDOFF_OFFER, ea as lastSharedWithMe, ei as WakeLimiter, el as normalizeRelayUrl, en as encodeDidDhtDeactivated, es as parseCallSignal, f as APP_BUNDLE_MAGIC, fa as dhtFileId, fc as verifyEnrollProof, fi as BUTTONS_CAPABILITY, fl as createIdentity, fn as WALLET_NETWORKS, fo as appFingerprint, fs as HANDOFF_PAKE, g as appViewOf, gc as OwnInviteError, gi as HOLD_CAPABILITY, gl as verify, gn as formatPaymentAmount, go as isAppKey, gr as readGroupSignal, gs as HANDOFF_VERIFIED, h as appDigest, ha as sanitizeMime, hc as readDeviceInvite, hi as UPGRADE_CAPABILITY, hl as publicKeyFromZ32, hn as assertWholeSats, ho as isAppHash, hr as groupSignalFrame, hs as HANDOFF_TIMINGS, i as checkAppBeforeRun, ia as TRANSPORTS, ic as enrollCancelReason, ii as relayRequest, il as isDiscoveryBudgetError, in as ETHEREUM_USDT, io as statusCardText, ir as groupFileFallback, is as LEGACY_SERVICES, it as mentionsMember, j as GROUP_READ_NOTE_COMMUNITY, ja as readForwarded, jc as newDeviceSetSecret, jo as rosterHas, jr as pickHubs, js as handoffPakeFrame, k as COMMUNITY_LIMITS, ka as parseLinkPreview, kc as deviceLinkPairing, ko as parseGroupCommit, kr as mergeLobby, ks as handoffManifestFrames, l as readAppStoreSteps, la as DHT_MESSAGE_TTL, lc as enrollProofFrame, li as chatAppId, lo as shownTime, ls as HANDOFF_HAVE, ma as sanitizeFileName, mc as deviceInviteJoinerParams, mi as STATUS_CARD_CAPABILITY, ml as identityFromSeedB64, mn as assertTokenUnits, ms as HANDOFF_REQUEST, n as appStoreDecision, na as emptyProofLedger, ni as newWakeToken, nl as traceLink, no as checkStatusCard, ns as emptyLinkRecords, nt as carryMentions, o as APP_STORE_LIMITS, oc as enrollDoneFrame, oi as checkPushEndpoint, ol as PacketTooLargeError, on as ONCHAIN_PROVIDER, oo as claimedTime, or as readGroupFileMeta, os as HANDOFF_ACK, p as APP_ICON_PATH, pa as formatFileSize, pc as createDeviceInvite, pi as EDIT_CAPABILITY, pl as identityFromSeed, pn as arkAddressPrefix, po as appRef, ps as HANDOFF_PIECE_BYTES, q as parseGroupWakeFrame, qc as turnKeys, qn as PAIRED_FRAME_TOO_LARGE, qr as PIN_LIMITS, r as appUpdateDecision, ra as validExternalKey, rc as enrollCancelFrame, ri as parseWakeFrame, rl as budgetRetryMs, rn as signDidDhtPacket, ro as sameButtonText, rs as HTTP_SERVICE_PROTO, rt as parseCommunityEdit, sc as enrollGrantFrame, si as vapidKeysMatch, sn as PaymentPreflightError, so as heardTime, ss as HANDOFF_CANCEL, t as appRevocationFor, ta as PeerProofs, ti as deviceWakeRequest, tn as encodeDidDhtPacket, tt as GROUP_EDIT_TEXT_BYTES, ua as peekDhtMailbox, uc as readEnrollGrant, ui as isAppVersion, un as TEST_USDT_FAUCET_AMOUNT, ur as CarriedTransport, us as HANDOFF_HELLO, vc as decodeInviteCode, vi as HOLD_LIMITS, vl as sanitizeAvatar, vn as walletNetworkOf, vo as readAppRevocation, vr as mayBeHub, vs as handoffAttemptAllowed, wc as ENROLL_CAPABILITY, wl as toBase64Url, wo as readCanonicalJson, wr as doorHubs, ws as handoffContextProof, xc as inviteOwnership, xi as isHoldUrl, xl as fromBase64Url, xn as sparkAddressKind, xr as COMMUNITY_TOPOLOGY, xs as handoffBusyFrame, y as isAppUrl, ya as fileMessageText, yc as encodeInviteCode, yi as HoldKeys, yl as sanitizeDisplayText, yn as SPARK_NETWORKS, yr as meshHubs, ys as handoffAttemptFailed, z as knockIdentity, za as reactionIsNewer, zc as TURN_LAST_SEQUENCE, zi as DHT_TEXT_CAPABILITY, zn as fedimintRequestPayload, zo as presenceSeenAt, zr as transferEnded, zs as readHandoffDone } from "./src-XhjSWnp-.js";
|
|
3
3
|
import { i as SourceUnreachableError, n as PROVIDER_PLATFORMS, o as isNothingSpentError, r as SourceConfigError, t as NothingSpentError, u as redact } from "./types-C4_KafL_.js";
|
|
4
4
|
import { t as bitcoindRpc } from "./bitcoindProvider-DGw3xBSa.js";
|
|
5
|
-
import { t as nwc } from "./nwcProvider-
|
|
5
|
+
import { t as nwc } from "./nwcProvider-C1AhPoFW.js";
|
|
6
6
|
import { a as clearProfileStores, c as fileStore, d as profileOpenFailure, f as store, i as STORES$1, l as newestWalletTx, m as wrap, n as APP_STORAGE_SCOPE_INDEX, o as databaseName, p as transact, r as CARD_INDEX, s as deleteDatabase, t as APP_STORAGE_CHAT_INDEX, u as openDb } from "./idb-B5L8wuOm.js";
|
|
7
|
-
import { a as sealSeed, i as newDeviceKey, o as unsealSeed, r as intentRepository } from "./networkReason-
|
|
8
|
-
import { $ as setSingleWriterGate, A as LightningCards, B as breezDatabaseInUse, C as FileAppender, D as streamStored, E as storedSize, F as ProviderSources, G as ModeChanged, H as dropBreezDatabase, I as sourceKey, J as networkLabel, K as ModeGate, L as CASHU_MINT_SOURCE, M as isRecoveryPhrase, N as normalizePhrase, P as lightningPaying, Q as setAwayWallets, R as cashuMint, S as WALLET_TYPES, T as removeStored, U as iceServerProblem, V as breezDatabasesFor, W as iceServerSetting, X as refuseAway, Y as awayFrom, Z as requireTurn, _ as crossNetwork, a as storedGroupFiles, b as walletInstances, c as receivedPairedReply, d as paymentAlias, f as paymentWireId, g as createTiming, h as createFailure, i as groupOfFile, j as cardsKey, k as CASHU_CARD, l as replyRef, m as assertConfirmedReal, n as groupFileId, o as groupReply, p as WALLET_NAMES, q as WrongNetworkError, r as groupFileText, s as pairedWireReply, t as GroupFileDesk, u as replyTo, v as paymentNetwork, w as readStored$1, y as paymentNetworksOf, z as breezDatabase } from "./groupFiles-
|
|
9
|
-
import { i as fedimintDatabase, n as createIrohWebEndpoint, o as loadFedimintSdk, r as irohRelayProblem, t as DEFAULT_IROH_RELAYS } from "./irohWeb-
|
|
7
|
+
import { a as sealSeed, i as newDeviceKey, o as unsealSeed, r as intentRepository } from "./networkReason-Btv4b2C4.js";
|
|
8
|
+
import { $ as setSingleWriterGate, A as LightningCards, B as breezDatabaseInUse, C as FileAppender, D as streamStored, E as storedSize, F as ProviderSources, G as ModeChanged, H as dropBreezDatabase, I as sourceKey, J as networkLabel, K as ModeGate, L as CASHU_MINT_SOURCE, M as isRecoveryPhrase, N as normalizePhrase, P as lightningPaying, Q as setAwayWallets, R as cashuMint, S as WALLET_TYPES, T as removeStored, U as iceServerProblem, V as breezDatabasesFor, W as iceServerSetting, X as refuseAway, Y as awayFrom, Z as requireTurn, _ as crossNetwork, a as storedGroupFiles, b as walletInstances, c as receivedPairedReply, d as paymentAlias, f as paymentWireId, g as createTiming, h as createFailure, i as groupOfFile, j as cardsKey, k as CASHU_CARD, l as replyRef, m as assertConfirmedReal, n as groupFileId, o as groupReply, p as WALLET_NAMES, q as WrongNetworkError, r as groupFileText, s as pairedWireReply, t as GroupFileDesk, u as replyTo, v as paymentNetwork, w as readStored$1, y as paymentNetworksOf, z as breezDatabase } from "./groupFiles-B1lL6wch.js";
|
|
9
|
+
import { i as fedimintDatabase, n as createIrohWebEndpoint, o as loadFedimintSdk, r as irohRelayProblem, t as DEFAULT_IROH_RELAYS } from "./irohWeb-DZDCyL9b.js";
|
|
10
10
|
import { c as isTestMint, d as paysItsOwnInvoices, l as isWorthlessMint, n as DEFAULT_MINTS, o as fakesLightning, r as TEST_MINT, t as BITCOIN_INVOICE_ON_TESTNET, u as mintNetwork } from "./mints-BrlY773j.js";
|
|
11
|
-
import { _ as reserveAdapterIds, b as testBuild, f as setOwnDidSource, g as registeredOnchainProviders, h as registeredLightningProviders, l as chosenResolver, n as resolveAtprotoDid, p as onAdaptersChanged, t as assertPublicServer, v as boundedIdentityFetch, y as verifyIdentity } from "./resolve-
|
|
11
|
+
import { _ as reserveAdapterIds, b as testBuild, f as setOwnDidSource, g as registeredOnchainProviders, h as registeredLightningProviders, l as chosenResolver, n as resolveAtprotoDid, p as onAdaptersChanged, t as assertPublicServer, v as boundedIdentityFetch, y as verifyIdentity } from "./resolve-Ssq1nDy4.js";
|
|
12
12
|
import { c as fileSpace, f as FILE_BYTES_STEP, o as fileBytes, r as blobDigest, s as fileBytesOf, u as removeFileBytes } from "./fileBytes-Di7VZtmU.js";
|
|
13
|
-
import { n as MAX_BACKUP_BYTES, t as BACKUP_MEDIA_TYPE } from "./envelope-
|
|
13
|
+
import { n as MAX_BACKUP_BYTES, t as BACKUP_MEDIA_TYPE } from "./envelope-BqvBb6hC.js";
|
|
14
14
|
import { t as hyperdhtRelayProblem } from "./hyperdhtRelay-BT_wRxab.js";
|
|
15
15
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
16
16
|
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
@@ -199,7 +199,7 @@ function viewNews(before, after) {
|
|
|
199
199
|
//#endregion
|
|
200
200
|
//#region ../browser/src/engine/paymentAdapters/usdtWallet.ts
|
|
201
201
|
/** The Ethereum libraries, a large part of the app: loaded once a USDT wallet is made, opened or restored, not with the engine. */
|
|
202
|
-
var loadUsdt = () => import("./usdt-
|
|
202
|
+
var loadUsdt = () => import("./usdt-DO86yko2.js");
|
|
203
203
|
/** Every new profile starts with this wallet: an address to receive on, nothing to set up. */
|
|
204
204
|
var DEFAULT_USDT = {
|
|
205
205
|
network: "ethereum",
|
|
@@ -648,7 +648,7 @@ async function restoreArkDatabase(walletId, snapshot) {
|
|
|
648
648
|
//#endregion
|
|
649
649
|
//#region ../browser/src/engine/paymentAdapters/arkWallet.ts
|
|
650
650
|
/** The Ark SDK, a large part of the app: loaded once an Ark wallet is made, opened or restored, not with the engine. */
|
|
651
|
-
var loadArkade = () => import("./arkade-
|
|
651
|
+
var loadArkade = () => import("./arkade-uqAXA5BT.js");
|
|
652
652
|
/** How long a Testnet wallet about to make way for another waits for its server to say what it holds. */
|
|
653
653
|
var RETIRE_READ_MS = 1e4;
|
|
654
654
|
/** Every new profile starts with this wallet: nothing to set up before receiving. */
|
|
@@ -6703,7 +6703,7 @@ var registry;
|
|
|
6703
6703
|
var loading$1;
|
|
6704
6704
|
var listeners = /* @__PURE__ */ new Set();
|
|
6705
6705
|
function loadIdentityProviders() {
|
|
6706
|
-
return loading$1 ??= import("./registry-
|
|
6706
|
+
return loading$1 ??= import("./registry-C09xXyx-.js").then((m) => {
|
|
6707
6707
|
registry = m;
|
|
6708
6708
|
for (const listener of listeners) listener();
|
|
6709
6709
|
return m;
|
|
@@ -9998,21 +9998,26 @@ var AppFetchError = class extends Error {
|
|
|
9998
9998
|
}
|
|
9999
9999
|
};
|
|
10000
10000
|
function boundedAppFetch(options = {}) {
|
|
10001
|
-
return async (url, { maxBytes, peek = false }) => {
|
|
10001
|
+
return async (url, { maxBytes, peek = false, revalidate = false, signal: stopped }) => {
|
|
10002
10002
|
if (!isAppFetchUrl(url)) throw new AppFetchError("host", "Apps are read only from raw.githubusercontent.com, or from cdn.jsdelivr.net at a commit, over HTTPS");
|
|
10003
10003
|
if (options.online && !options.online()) throw new AppFetchError("offline", "Offline");
|
|
10004
|
+
if (stopped?.aborted) throw new AppFetchError("network", "The read was stopped");
|
|
10004
10005
|
const fetcher = options.fetcher ?? globalThis.fetch.bind(globalThis);
|
|
10005
10006
|
const controller = new AbortController();
|
|
10006
10007
|
const cut = () => {
|
|
10007
10008
|
controller.abort(new DOMException("The read took too long", "TimeoutError"));
|
|
10008
10009
|
};
|
|
10010
|
+
const stop = () => {
|
|
10011
|
+
controller.abort(new DOMException("The read was stopped", "AbortError"));
|
|
10012
|
+
};
|
|
10013
|
+
stopped?.addEventListener("abort", stop);
|
|
10009
10014
|
const total = setTimeout(cut, options.totalMs ?? APP_FETCH_LIMITS.totalMs);
|
|
10010
10015
|
let idle = setTimeout(cut, options.timeoutMs ?? APP_FETCH_LIMITS.timeoutMs);
|
|
10011
10016
|
const heard = () => {
|
|
10012
10017
|
clearTimeout(idle);
|
|
10013
10018
|
idle = setTimeout(cut, options.idleMs ?? APP_FETCH_LIMITS.idleMs);
|
|
10014
10019
|
};
|
|
10015
|
-
const failure = (error) => controller.signal.aborted ? new AppFetchError("slow", "That took too long on this connection") : new AppFetchError("network", error instanceof Error ? error.message : String(error));
|
|
10020
|
+
const failure = (error) => stopped?.aborted ? new AppFetchError("network", "The read was stopped") : controller.signal.aborted ? new AppFetchError("slow", "That took too long on this connection") : new AppFetchError("network", error instanceof Error ? error.message : String(error));
|
|
10016
10021
|
const { signal } = controller;
|
|
10017
10022
|
let response;
|
|
10018
10023
|
try {
|
|
@@ -10020,13 +10025,14 @@ function boundedAppFetch(options = {}) {
|
|
|
10020
10025
|
signal,
|
|
10021
10026
|
credentials: "omit",
|
|
10022
10027
|
referrerPolicy: "no-referrer",
|
|
10023
|
-
cache: "no-store",
|
|
10028
|
+
cache: revalidate && !peek ? "no-cache" : "no-store",
|
|
10024
10029
|
redirect: "error",
|
|
10025
10030
|
...peek && { headers: { range: `bytes=0-${maxBytes - 1}` } }
|
|
10026
10031
|
});
|
|
10027
10032
|
} catch (error) {
|
|
10028
10033
|
clearTimeout(total);
|
|
10029
10034
|
clearTimeout(idle);
|
|
10035
|
+
stopped?.removeEventListener("abort", stop);
|
|
10030
10036
|
throw failure(error);
|
|
10031
10037
|
}
|
|
10032
10038
|
heard();
|
|
@@ -10044,10 +10050,10 @@ function boundedAppFetch(options = {}) {
|
|
|
10044
10050
|
}
|
|
10045
10051
|
const reader = response.body?.getReader();
|
|
10046
10052
|
if (reader) {
|
|
10047
|
-
const
|
|
10053
|
+
const letGo = () => {
|
|
10048
10054
|
reader.cancel().catch(() => {});
|
|
10049
10055
|
};
|
|
10050
|
-
signal.addEventListener("abort",
|
|
10056
|
+
signal.addEventListener("abort", letGo);
|
|
10051
10057
|
try {
|
|
10052
10058
|
for (;;) {
|
|
10053
10059
|
const { done, value } = await reader.read();
|
|
@@ -10067,13 +10073,14 @@ function boundedAppFetch(options = {}) {
|
|
|
10067
10073
|
if (error instanceof AppFetchError) throw error;
|
|
10068
10074
|
throw failure(error);
|
|
10069
10075
|
} finally {
|
|
10070
|
-
signal.removeEventListener("abort",
|
|
10076
|
+
signal.removeEventListener("abort", letGo);
|
|
10071
10077
|
await reader.cancel().catch(() => {});
|
|
10072
10078
|
}
|
|
10073
10079
|
}
|
|
10074
10080
|
} finally {
|
|
10075
10081
|
clearTimeout(total);
|
|
10076
10082
|
clearTimeout(idle);
|
|
10083
|
+
stopped?.removeEventListener("abort", stop);
|
|
10077
10084
|
}
|
|
10078
10085
|
const bytes = new Uint8Array(length);
|
|
10079
10086
|
let at = 0;
|
|
@@ -10400,6 +10407,8 @@ var Apps = class {
|
|
|
10400
10407
|
runUsed = /* @__PURE__ */ new Map();
|
|
10401
10408
|
/** Reads of a bundle under way, by digest: icons drawn at once share one read. */
|
|
10402
10409
|
verifying = /* @__PURE__ */ new Map();
|
|
10410
|
+
/** Reads of a bundle's URL under way: an install screen opened again waits on the read the closed one began, not on a second. */
|
|
10411
|
+
bundleReads = /* @__PURE__ */ new Map();
|
|
10403
10412
|
/**
|
|
10404
10413
|
* The `icon.png` of each checked bundle, by digest (at most 256 KiB and 1024 × 1024 pixels, or null for none): every icon shown on the Apps
|
|
10405
10414
|
* page, in a chat's cards and in the composer's Apps is read without the whole bundle again.
|
|
@@ -10415,6 +10424,10 @@ var Apps = class {
|
|
|
10415
10424
|
timer = null;
|
|
10416
10425
|
/** Drops what `staged` holds past `STAGED.ms`, set while it holds anything: a closed install screen sends no call. */
|
|
10417
10426
|
sweep = null;
|
|
10427
|
+
/** The store `previewStore` last read and checked, for Add to take within `STAGED.ms` without reading it again. */
|
|
10428
|
+
previewed = null;
|
|
10429
|
+
/** Drops `previewed` past `STAGED.ms`: an index is up to 4 MiB, and a closed Add screen sends no call. */
|
|
10430
|
+
previewedSweep = null;
|
|
10418
10431
|
checking = null;
|
|
10419
10432
|
/** Runs the person started with Run anyway (`<ref> <digest>`), for this engine's life: a removal does not cut them off. */
|
|
10420
10433
|
anyway = /* @__PURE__ */ new Set();
|
|
@@ -10471,6 +10484,7 @@ var Apps = class {
|
|
|
10471
10484
|
if (this.sweep) clearTimeout(this.sweep);
|
|
10472
10485
|
this.sweep = null;
|
|
10473
10486
|
this.staged.clear();
|
|
10487
|
+
this.keepPreviewed(null);
|
|
10474
10488
|
this.held.clear();
|
|
10475
10489
|
this.heldStores = null;
|
|
10476
10490
|
this.views = null;
|
|
@@ -10824,14 +10838,22 @@ var Apps = class {
|
|
|
10824
10838
|
this.runUsed.delete(digest);
|
|
10825
10839
|
}
|
|
10826
10840
|
}
|
|
10827
|
-
|
|
10828
|
-
const
|
|
10829
|
-
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
|
|
10841
|
+
fetchBundle(url) {
|
|
10842
|
+
const running = this.bundleReads.get(url);
|
|
10843
|
+
if (running) return running;
|
|
10844
|
+
const read = (async () => {
|
|
10845
|
+
const bytes = await this.host.fetch(url, { maxBytes: APP_BUNDLE_LIMITS.bundleBytes });
|
|
10846
|
+
const read = await readAppBundleAsync(bytes);
|
|
10847
|
+
if (!read.ok) fail(read.reason, `This is not an app Ghostly can install${read.detail ? ` (${read.detail})` : ""}`);
|
|
10848
|
+
return {
|
|
10849
|
+
bundle: read.bundle,
|
|
10850
|
+
bytes
|
|
10851
|
+
};
|
|
10852
|
+
})().finally(() => {
|
|
10853
|
+
this.bundleReads.delete(url);
|
|
10854
|
+
});
|
|
10855
|
+
this.bundleReads.set(url, read);
|
|
10856
|
+
return read;
|
|
10835
10857
|
}
|
|
10836
10858
|
/**
|
|
10837
10859
|
* Reads the index at `url`. With the index held for this store, bytes equal to it (by digest) are the held index: its
|
|
@@ -10841,7 +10863,16 @@ var Apps = class {
|
|
|
10841
10863
|
* this store or another, a preview included, is not checked again.
|
|
10842
10864
|
*/
|
|
10843
10865
|
async readStoreAt(url, heldKey, held) {
|
|
10844
|
-
const
|
|
10866
|
+
const stop = new AbortController();
|
|
10867
|
+
const read = (at, maxBytes) => this.host.fetch(at, {
|
|
10868
|
+
maxBytes,
|
|
10869
|
+
revalidate: true,
|
|
10870
|
+
signal: stop.signal
|
|
10871
|
+
}).catch((error) => {
|
|
10872
|
+
stop.abort();
|
|
10873
|
+
throw error;
|
|
10874
|
+
});
|
|
10875
|
+
const [indexBytes, sigBytes] = await Promise.all([read(url, APP_FETCH_LIMITS.storeIndexBytes), read(besideUrl(url, "ghostly-store.sig"), APP_FETCH_LIMITS.sigBytes)]);
|
|
10845
10876
|
if (held?.index && held.digest !== void 0 && toBase64Url(await sha256Paced(indexBytes)) === held.digest) return {
|
|
10846
10877
|
ok: true,
|
|
10847
10878
|
store: {
|
|
@@ -10868,7 +10899,10 @@ var Apps = class {
|
|
|
10868
10899
|
if (read.has(url)) continue;
|
|
10869
10900
|
read.add(url);
|
|
10870
10901
|
try {
|
|
10871
|
-
const file = await this.readRevocationsFile(await this.host.fetch(url, {
|
|
10902
|
+
const file = await this.readRevocationsFile(await this.host.fetch(url, {
|
|
10903
|
+
maxBytes: APP_FETCH_LIMITS.revocationsBytes,
|
|
10904
|
+
revalidate: true
|
|
10905
|
+
}));
|
|
10872
10906
|
if (file) (out ??= []).push(...file.filter((r) => r.statement.app === ref));
|
|
10873
10907
|
} catch {}
|
|
10874
10908
|
}
|
|
@@ -10942,12 +10976,24 @@ var Apps = class {
|
|
|
10942
10976
|
storeUrl(url) {
|
|
10943
10977
|
return typeof url === "string" && appPasteUrl(url, "ghostly-store.json") || notReadable(url, "Stores are read only from raw.githubusercontent.com, or from cdn.jsdelivr.net at a commit, over HTTPS");
|
|
10944
10978
|
}
|
|
10945
|
-
|
|
10979
|
+
keepPreviewed(previewed) {
|
|
10980
|
+
if (this.previewedSweep) clearTimeout(this.previewedSweep);
|
|
10981
|
+
this.previewedSweep = previewed ? setTimeout(() => this.keepPreviewed(null), STAGED.ms) : null;
|
|
10982
|
+
this.previewed = previewed;
|
|
10983
|
+
}
|
|
10984
|
+
/** Reads a store at a URL for the person to see before adding it. Nothing is stored: the checked index waits in memory for `addStore`. */
|
|
10946
10985
|
async previewStore({ url }) {
|
|
10947
10986
|
const at = this.storeUrl(url);
|
|
10987
|
+
this.keepPreviewed(null);
|
|
10948
10988
|
const read = await this.readStoreAt(at);
|
|
10949
10989
|
if (!read.ok) fail(read.reason, "This is not a store Ghostly can read");
|
|
10950
|
-
const { index } = read.store;
|
|
10990
|
+
const { index, digest } = read.store;
|
|
10991
|
+
this.keepPreviewed({
|
|
10992
|
+
url: at,
|
|
10993
|
+
index,
|
|
10994
|
+
digest,
|
|
10995
|
+
at: this.now()
|
|
10996
|
+
});
|
|
10951
10997
|
return {
|
|
10952
10998
|
url: at,
|
|
10953
10999
|
key: index.key,
|
|
@@ -10963,12 +11009,22 @@ var Apps = class {
|
|
|
10963
11009
|
}
|
|
10964
11010
|
/**
|
|
10965
11011
|
* Adds a store the person chose: read at its URL and pinned to its key (`key`, when given, is the key the person saw,
|
|
10966
|
-
* and another one is refused). A store already added under that key takes the URL and the newer index.
|
|
11012
|
+
* and another one is refused). A store already added under that key takes the URL and the newer index. The index the
|
|
11013
|
+
* preview just read at that URL, under that key, is taken as it is (only its expiry again), not downloaded again.
|
|
10967
11014
|
*/
|
|
10968
11015
|
async addStore({ url, key }) {
|
|
10969
11016
|
if (key !== void 0 && !isAppKey(key)) fail("store-key", "Not a store key");
|
|
10970
11017
|
const at = this.storeUrl(url);
|
|
10971
|
-
const
|
|
11018
|
+
const kept = this.previewed;
|
|
11019
|
+
this.keepPreviewed(null);
|
|
11020
|
+
const read = kept && kept.url === at && (key === void 0 || key === kept.index.key) && this.now() - kept.at <= STAGED.ms ? {
|
|
11021
|
+
ok: true,
|
|
11022
|
+
store: {
|
|
11023
|
+
index: kept.index,
|
|
11024
|
+
digest: kept.digest,
|
|
11025
|
+
expired: kept.index.expires < this.nowS()
|
|
11026
|
+
}
|
|
11027
|
+
} : await this.readStoreAt(at, key);
|
|
10972
11028
|
if (!read.ok) fail(read.reason, "This is not a store Ghostly can read");
|
|
10973
11029
|
const { index, digest } = read.store;
|
|
10974
11030
|
const held = await this.storeRecord(index.key);
|
|
@@ -16270,6 +16326,7 @@ var DeviceLinks = class {
|
|
|
16270
16326
|
packetTransports: true,
|
|
16271
16327
|
transport: this.options.transport,
|
|
16272
16328
|
pollIntervals: this.options.pollIntervals,
|
|
16329
|
+
madeAt: 0,
|
|
16273
16330
|
autoConnect: true,
|
|
16274
16331
|
createPeerConnection: () => {
|
|
16275
16332
|
if (!this.createPeerConnection) throw new ReferenceError("RTCPeerConnection is not defined");
|
|
@@ -37923,7 +37980,8 @@ var GhostlyNode = class GhostlyNode {
|
|
|
37923
37980
|
...reply.button && { button: reply.button }
|
|
37924
37981
|
}
|
|
37925
37982
|
};
|
|
37926
|
-
const
|
|
37983
|
+
const pressed = buttonPress(resolved, original, []);
|
|
37984
|
+
const press = pressed && messageButtons(original)?.buttons.some((b) => b.once) ? buttonPress(resolved, original, history ?? await db.getMessages(message.linkId)) : pressed;
|
|
37927
37985
|
return press ? {
|
|
37928
37986
|
...resolved,
|
|
37929
37987
|
press
|
|
@@ -39062,6 +39120,8 @@ var GhostlyNode = class GhostlyNode {
|
|
|
39062
39120
|
if (!files) return "refused";
|
|
39063
39121
|
if (files.wireIds.has(wire.id)) return "duplicate file id";
|
|
39064
39122
|
if (files.receivedBytes + wire.size > LIMITS.maxStoredIncomingBytesPerPeer) return "no room for more files";
|
|
39123
|
+
if (wire.size > FILE_LIMITS.askAboveBytes) return "file too large without files/3";
|
|
39124
|
+
if (files.receivedBytes + this.fileDesk.autoTaken(linkId) + wire.size > FILE_LIMITS.autoAcceptBytesPerPeer) return "no more files without asking";
|
|
39065
39125
|
const said = this.fileDesk.takeAnnounced(linkId, wire.id);
|
|
39066
39126
|
if (said) db.deleteMessage(linkId, `peer_${wire.id}`).then(() => fileStore.delete(said)).then(() => this.messagesChanged(linkId, [`peer_${wire.id}`])).catch(() => {});
|
|
39067
39127
|
const { reply: _reply, ...announced } = wire;
|
|
@@ -42272,6 +42332,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
42272
42332
|
transport: live.carried ?? this.groupTransport,
|
|
42273
42333
|
nick: !entry && this.quietEdge(stored) ? void 0 : this.sharedNick,
|
|
42274
42334
|
pollIntervals: entry || this.groups.isCommunityGroup(group) ? this.pollIntervals : meshEdgeIntervals(this.pollIntervals, () => this.groups.meshSize(group)),
|
|
42335
|
+
madeAt: stored.createdAt,
|
|
42275
42336
|
autoConnect: true,
|
|
42276
42337
|
...entry ? {
|
|
42277
42338
|
oneShot: true,
|
|
@@ -42367,6 +42428,9 @@ var GhostlyNode = class GhostlyNode {
|
|
|
42367
42428
|
onAnswersRefused: () => {
|
|
42368
42429
|
this.edgeWithoutRtc(linkId);
|
|
42369
42430
|
},
|
|
42431
|
+
onRtcStalled: () => {
|
|
42432
|
+
this.edgeWithoutRtc(linkId);
|
|
42433
|
+
},
|
|
42370
42434
|
onDataLinkState: (state) => {
|
|
42371
42435
|
traceJoin(group, `link.${state}`, { role });
|
|
42372
42436
|
if (state === "open" || live.dataLink === "open") live.lastSyncAt = Date.now();
|
|
@@ -42980,7 +43044,7 @@ var GhostlyNode = class GhostlyNode {
|
|
|
42980
43044
|
get nativeFactories() {
|
|
42981
43045
|
const relay = this.relaysHyperdht ? this.hyperdhtRelay : "";
|
|
42982
43046
|
return {
|
|
42983
|
-
...relay ? { "hyperdht/1": async (seedB64) => (await import("./hyperdhtRelay-
|
|
43047
|
+
...relay ? { "hyperdht/1": async (seedB64) => (await import("./hyperdhtRelay-DwlOY6aD.js")).createRelayedHyperEndpoint(seedB64, relay) } : {},
|
|
42984
43048
|
...this.options.nativeTransports,
|
|
42985
43049
|
...this.ownIrohRelays ? { "iroh/1": (seedB64) => this.options.nativeTransports["iroh/1"](seedB64, this.settings.irohRelays?.length ? { relays: [...this.settings.irohRelays] } : {}) } : {},
|
|
42986
43050
|
...this.options.irohWeb ? { "iroh/1": (seedB64) => createIrohWebEndpoint(seedB64, { relays: this.irohRelays }) } : {}
|
|
@@ -43829,4 +43893,4 @@ function signalKind(signal) {
|
|
|
43829
43893
|
//#endregion
|
|
43830
43894
|
export { EngineServer };
|
|
43831
43895
|
|
|
43832
|
-
//# sourceMappingURL=server-
|
|
43896
|
+
//# sourceMappingURL=server-D6FSznK5.js.map
|