@orangecheck/chat-core 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{channel-D8aOo4eI.d.mts → channel-ChK3AAvd.d.mts} +8 -3
- package/dist/{channel-D8aOo4eI.d.ts → channel-ChK3AAvd.d.ts} +8 -3
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +23 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +23 -6
- package/dist/index.mjs.map +1 -1
- package/dist/io.d.mts +13 -14
- package/dist/io.d.ts +13 -14
- package/dist/io.js +45 -23
- package/dist/io.js.map +1 -1
- package/dist/io.mjs +45 -24
- package/dist/io.mjs.map +1 -1
- package/package.json +2 -2
- package/src/channel.test.ts +121 -7
- package/src/channel.ts +48 -12
- package/src/io.test.ts +97 -51
- package/src/io.ts +95 -50
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/attachment.ts","../src/canonical.ts","../src/event.ts","../src/session.ts","../src/version-binding.ts","../src/channel.ts","../src/directory-legacy.json","../src/directory.ts","../src/records.ts"],"names":["utf8Encode","p","key","curId","best","c","keys","authorizedDevices"],"mappings":"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","file":"index.mjs","sourcesContent":["// An inline file attachment (SPEC §5.1, §8.3.2). Its bytes are attacker-influenced,\n// and on a public channel post they are fully attacker-chosen.\n\nexport interface Attachment {\n /** Original file name. */\n name: string;\n /** MIME type, untrusted off the wire. */\n type: string;\n /** Raw byte size (before base64). */\n size: number;\n /** base64 of the raw file bytes. */\n data: string;\n}\n\n/** Hard ceiling for an inline attachment (~100KB, ~135KB base64), whatever its source. */\nexport const MAX_ATTACHMENT_BYTES = 100 * 1024;\n\n/** Is a parsed attachment the §5.1 shape, real base64 and within the byte cap?\n * A post whose attachment fails is malformed and never renders. */\nexport function isValidAttachment(a: unknown): a is Attachment {\n if (!a || typeof a !== 'object') return false;\n const o = a as Record<string, unknown>;\n if (typeof o.name !== 'string' || typeof o.type !== 'string') return false;\n if (typeof o.size !== 'number' || !(o.size >= 0 && o.size <= MAX_ATTACHMENT_BYTES)) return false;\n if (typeof o.data !== 'string') return false;\n if (o.data.length > Math.ceil((MAX_ATTACHMENT_BYTES * 4) / 3) + 8) return false;\n // atob throws on a string that is not base64, which would crash a feed at render time.\n try {\n if (atob(o.data).length > MAX_ATTACHMENT_BYTES) return false;\n } catch {\n return false;\n }\n return true;\n}\n","// The canonical bytes OC Chat hashes for channel descriptors and posts (SPEC §0):\n// keys sorted at every depth, compact, LF-terminated. Arrays keep their order.\n\nimport { b64urlEncode, utf8Encode } from '@orangecheck/lock-crypto';\n\nexport function canonicalBytes(value: unknown): Uint8Array {\n const sort = (v: unknown): unknown => {\n if (Array.isArray(v)) return v.map(sort);\n if (v && typeof v === 'object') {\n const out: Record<string, unknown> = {};\n for (const k of Object.keys(v as Record<string, unknown>).sort()) {\n out[k] = sort((v as Record<string, unknown>)[k]);\n }\n return out;\n }\n return v;\n };\n return utf8Encode(JSON.stringify(sort(value)) + '\\n');\n}\n\n/** base64url without padding, the d-tag suffix encoding. */\nexport function b64urlNoPad(bytes: Uint8Array): string {\n return b64urlEncode(bytes).replace(/=+$/, '');\n}\n","import { verifyNostrEvent, type NostrEvent } from '@orangecheck/lock-device';\n\nexport type { NostrEvent };\nexport { verifyNostrEvent };\n\n/** NIP-01 holds and the event is signed by `pubkey`. */\nexport function signedBy(ev: NostrEvent, pubkey: string): boolean {\n return ev.pubkey === pubkey && verifyNostrEvent(ev);\n}\n","// did:oc session devices (SPEC §8.6): the auth host's vouch that binds a device\n// key to a did:oc, the host's signed revocations, and which keys stand.\n//\n// A session record has no BIP-322 signature, and its Nostr self-signature\n// proves only that SOME key published it. What binds it to a did:oc is the\n// auth host (ochk.io), the named trust anchor, signing the exact (did_oc,\n// device_pk, nostr_pk, device_id) after the device proved it holds the Nostr\n// key. This tier is not offline-verifiable and not Bitcoin-load-bearing.\n// The caller supplies the host's published keys.\n\nimport { ed25519 } from '@noble/curves/ed25519';\nimport { utf8Encode } from '@orangecheck/lock-crypto';\nimport { DEVICE_KIND, type NostrEvent } from '@orangecheck/lock-device';\n\nimport { verifyNostrEvent } from './event';\n\nexport const AUTH_HOST_JWKS_URL = 'https://ochk.io/.well-known/jwks.json';\nexport const VOUCH_JWS_TYP = 'oc-chat-device-vouch';\nexport const REVOCATION_JWS_TYP = 'oc-chat-device-revoke';\n\n/** The d-tag a did:oc's session device records are published under. */\nexport function sessionDeviceDtag(didOc: string): string {\n return `oc-chat:device:${didOc}`;\n}\n\nexport interface VouchSubject {\n didOc: string;\n device_pk: string;\n nostr_pk: string;\n device_id: string;\n}\n\nexport interface AuthHostKey {\n kid?: string;\n kty?: string;\n crv?: string;\n x?: string;\n /** A key rotated out: it verifies only what it signed before `retired_at`. */\n status?: string;\n retired_at?: number;\n}\n\nfunction fields(ns: string, s: VouchSubject): string[] {\n return [\n ns,\n `did_oc: ${s.didOc}`,\n `device_pk: ${s.device_pk}`,\n `nostr_pk: ${s.nostr_pk}`,\n `device_id: ${s.device_id}`,\n ];\n}\n\n/** The request the device's Nostr key signs (proof of possession). */\nexport function vouchRequestStatement(s: VouchSubject): string {\n return fields('oc-chat:device-vouch-request:v1', s).join('\\n') + '\\n';\n}\n\nfunction b64urlDecode(s: string): Uint8Array {\n const b64 = s.replace(/-/g, '+').replace(/_/g, '/');\n const pad = b64.length % 4 === 0 ? '' : '='.repeat(4 - (b64.length % 4));\n const bin = atob(b64 + pad);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n/**\n * The plain-text statement of a host JWS of type `typ`, signed by a published\n * key, or null. A retired key counts only for a statement whose signed time\n * (`timeField`) is before its `retired_at` (SPEC §8.6).\n */\nfunction hostStatement(\n jws: string,\n typ: string,\n timeField: string,\n keys: readonly AuthHostKey[]\n): string[] | null {\n try {\n const parts = jws.split('.');\n if (parts.length !== 3) return null;\n const [h, p, sig] = parts as [string, string, string];\n const header = JSON.parse(new TextDecoder().decode(b64urlDecode(h))) as Record<\n string,\n unknown\n >;\n if (header.alg !== 'EdDSA' || header.typ !== typ) return null;\n const key = keys.find(\n (k) => k.kty === 'OKP' && k.crv === 'Ed25519' && k.x && k.kid === header.kid\n );\n if (!key?.x) return null;\n if (!ed25519.verify(b64urlDecode(sig), utf8Encode(`${h}.${p}`), b64urlDecode(key.x))) {\n return null;\n }\n const lines = new TextDecoder().decode(b64urlDecode(p)).split('\\n');\n const at = lines.find((l) => l.startsWith(`${timeField}: `));\n const t = at ? Number(at.slice(timeField.length + 2)) : NaN;\n if (!/^\\d+$/.test(at?.slice(timeField.length + 2) ?? '')) return null;\n if (\n key.status === 'retired' &&\n !(typeof key.retired_at === 'number' && t < key.retired_at)\n ) {\n return null;\n }\n return lines;\n } catch {\n return null;\n }\n}\n\n/**\n * Does `vouch` — a compact JWS from the auth host — vouch for exactly this\n * subject? Checks the header, the Ed25519 signature against a published key\n * (a retired one only for a vouch issued before it retired), and every\n * statement field. Pure; the caller supplies the keys.\n */\nexport function verifySessionVouch(\n vouch: string,\n subject: VouchSubject,\n keys: readonly AuthHostKey[]\n): boolean {\n const lines = hostStatement(vouch, VOUCH_JWS_TYP, 'issued_at', keys);\n if (!lines) return false;\n const expected = fields('oc-chat:device-vouch:v1', subject);\n // The statement is the expected fields, an issued_at line, and the final LF.\n if (lines.length !== expected.length + 2) return false;\n for (let i = 0; i < expected.length; i++) if (lines[i] !== expected[i]) return false;\n return /^issued_at: \\d+$/.test(lines[expected.length]!) && lines.at(-1) === '';\n}\n\n/** Who a host-signed device revocation names (SPEC §8.6), or null if it does not verify. */\nexport function verifyHostRevocation(\n jws: string,\n keys: readonly AuthHostKey[]\n): {\n didOc: string;\n device_id: string;\n nostr_pk: string;\n revoked_at: number;\n statement: string;\n} | null {\n const lines = hostStatement(jws, REVOCATION_JWS_TYP, 'revoked_at', keys);\n if (!lines || lines[0] !== 'oc-chat:device-revoke:v1' || lines.at(-1) !== '') return null;\n // The signature covers every line. The named ones are read by name, once\n // each, and a line the host adds later is kept in the statement but not read.\n const field = (name: string) => {\n const found = lines.filter((l) => l.startsWith(`${name}: `));\n return found.length === 1 ? found[0]!.slice(name.length + 2) : null;\n };\n const didOc = field('did_oc');\n const device_id = field('device_id');\n const nostr_pk = field('nostr_pk');\n const at = field('revoked_at');\n const revoked_at = at === null ? NaN : Number(at);\n if (!didOc || !device_id || !nostr_pk || !Number.isFinite(revoked_at)) return null;\n return { didOc, device_id, nostr_pk, revoked_at, statement: lines.join('\\n') };\n}\n\n/** The signed issued_at of a vouch, read without verifying it (callers verify first). */\nexport function vouchIssuedAt(vouch: string): number | null {\n try {\n const p = vouch.split('.')[1] ?? '';\n const line = new TextDecoder()\n .decode(b64urlDecode(p))\n .split('\\n')\n .find((l) => l.startsWith('issued_at: '));\n const t = line ? Number(line.slice('issued_at: '.length)) : NaN;\n return Number.isFinite(t) ? t : null;\n } catch {\n return null;\n }\n}\n\n\nexport interface ParsedSessionDeviceEvent {\n /** The did:oc this device is published under. */\n didOc: string;\n device_id: string;\n device_pk: string;\n bindingStatement: string;\n revoked: boolean;\n createdAtUnix: number;\n nostrPubkey: string;\n eventId: string;\n /** The auth host's vouch, or null when the record carries none. */\n vouch: string | null;\n}\n\n/**\n * Parse a session device event. Unlike lock-device's parseDeviceEvent, this does\n * NOT require a non-empty binding_sig (session devices have none) and asserts\n * the `auth=session` tag so a lock-namespace record can never be parsed here.\n */\nexport function parseSessionDeviceEvent(event: NostrEvent): ParsedSessionDeviceEvent {\n if (event.kind !== DEVICE_KIND) {\n throw new Error('not a device event (kind mismatch)');\n }\n const tag = (name: string): string | null => {\n for (const t of event.tags) {\n if (t[0] === name && t.length > 1) return t[1] ?? null;\n }\n return null;\n };\n const didOc = tag('addr');\n const device_id = tag('device_id');\n const device_pk = tag('device_pk');\n if (!didOc || !device_id || !device_pk) {\n throw new Error('session device event missing required tags');\n }\n if (tag('auth') !== 'session') {\n throw new Error('not a session device event (auth tag mismatch)');\n }\n return {\n didOc,\n device_id,\n device_pk,\n bindingStatement: event.content,\n revoked: device_pk === 'revoked',\n createdAtUnix: event.created_at,\n nostrPubkey: event.pubkey,\n eventId: event.id,\n vouch: tag('vouch'),\n };\n}\n\n/** Every revocation of `didOc`'s session devices seen on any relay (SPEC §8.6). */\nexport interface SessionRevocations {\n /** \"nostr_pk:device_id\" of devices whose own key signed a revocation. */\n self: Set<string>;\n /** device_id → the latest host-signed revoked_at for it. */\n host: Map<string, number>;\n /** The nostr_pk each host revocation names. */\n hostNamed: Set<string>;\n}\n\nexport function sessionRevocations(\n events: readonly NostrEvent[],\n didOc: string,\n hostKeys: readonly AuthHostKey[]\n): SessionRevocations {\n const out: SessionRevocations = { self: new Set(), host: new Map(), hostNamed: new Set() };\n for (const e of events) {\n if (!verifyNostrEvent(e)) continue;\n const tag = (name: string) => e.tags.find((t) => t[0] === name)?.[1];\n const jws = tag('revocation');\n if (jws) {\n // Whatever key carried it: the host's signature is the authority. The\n // device is the one the statement names, whatever the other tags say;\n // only the d tag and addr must name this did:oc (SPEC §8.6).\n const r = verifyHostRevocation(jws, hostKeys);\n if (\n r &&\n r.statement === e.content &&\n r.didOc === didOc &&\n tag('d') === `oc-chat:device:${didOc}` &&\n tag('addr') === didOc\n ) {\n out.host.set(r.device_id, Math.max(out.host.get(r.device_id) ?? -1, r.revoked_at));\n out.hostNamed.add(r.nostr_pk);\n }\n continue;\n }\n try {\n const p = parseSessionDeviceEvent(e);\n if (p.revoked && p.didOc === didOc) out.self.add(`${e.pubkey}:${p.device_id}`);\n } catch {\n // not a session record\n }\n }\n return out;\n}\n\n/** Is this bind retired: by its own key, or by a host revocation dated at or\n * after its vouch was issued (both times the host's own)? */\nexport function sessionDeviceRevoked(\n d: { nostrPubkey: string; device_id: string; issuedAt: number | null },\n revs: SessionRevocations\n): boolean {\n if (revs.self.has(`${d.nostrPubkey}:${d.device_id}`)) return true;\n const at = revs.host.get(d.device_id);\n return at !== undefined && (d.issuedAt === null || d.issuedAt <= at);\n}\n\n/** The session records for `didOc` whose own signature and host vouch verify, revoked or not. */\nexport function vouchedSessionDevices(\n events: readonly NostrEvent[],\n didOc: string,\n hostKeys: readonly AuthHostKey[]\n): ParsedSessionDeviceEvent[] {\n const out: ParsedSessionDeviceEvent[] = [];\n for (const e of events) {\n try {\n const p = parseSessionDeviceEvent(e);\n if (p.revoked) continue;\n if (p.didOc !== didOc) continue; // namespace must match the queried did:oc\n if (!verifyNostrEvent(e)) continue; // integrity gate\n // The binding itself: the auth host vouched for this did:oc + keys.\n if (\n !p.vouch ||\n !verifySessionVouch(\n p.vouch,\n {\n didOc,\n device_pk: p.device_pk,\n nostr_pk: p.nostrPubkey,\n device_id: p.device_id,\n },\n hostKeys\n )\n ) {\n continue;\n }\n out.push(p);\n } catch {\n // skip malformed / non-session records\n }\n }\n return out;\n}\n\n/** The session devices that bind for `didOc` now: vouched, and retired by no revocation seen (§8.6). */\nexport function liveSessionDevices(\n events: readonly NostrEvent[],\n didOc: string,\n hostKeys: readonly AuthHostKey[]\n): ParsedSessionDeviceEvent[] {\n const revoked = sessionRevocations(events, didOc, hostKeys);\n return vouchedSessionDevices(events, didOc, hostKeys).filter(\n (p) =>\n !sessionDeviceRevoked(\n { ...p, issuedAt: p.vouch ? vouchIssuedAt(p.vouch) : null },\n revoked\n )\n );\n}\n\n/**\n * Every inbox key the auth host has vouched for `didOc`, revoked ones too. An\n * earlier channel version stands on its binding whatever became of the key\n * since (§8.3.1), so a version reader asks each. A device's own revocation\n * replaces its record at the relay, so for a device no record of which remains,\n * the key that carried it counts; a host revocation names its key.\n */\nexport function sessionKeysEverBound(\n events: readonly NostrEvent[],\n didOc: string,\n hostKeys: readonly AuthHostKey[]\n): string[] {\n const bound = vouchedSessionDevices(events, didOc, hostKeys);\n const boundIds = new Set(bound.map((p) => p.device_id));\n const revs = sessionRevocations(events, didOc, hostKeys);\n const replaced = [...revs.self]\n .map((s) => s.split(':') as [string, string])\n .filter(([, id]) => !boundIds.has(id))\n .map(([pk]) => pk);\n return [...new Set([...bound.map((p) => p.nostrPubkey), ...replaced, ...revs.hostNamed])];\n}\n","// A channel version's own proof of who signed it (SPEC §8.3.1, 0.3.0): the\n// kind-30078 device record carried in the version event's `binding` tag. An\n// earlier version stands on this proof alone; the last version of a chain also\n// needs it to be live, which is the one read that goes to the relays.\n\nimport {\n authorizedDevices,\n liveDevices,\n parseDeviceEvent,\n type NostrEvent,\n type ParsedDeviceEvent,\n} from '@orangecheck/lock-device';\n\nimport { verifyNostrEvent } from './event';\nimport { UnansweredReadError, type VerifyBip322 } from './read';\nimport {\n parseSessionDeviceEvent,\n sessionDeviceRevoked,\n sessionRevocations,\n verifySessionVouch,\n vouchIssuedAt,\n type AuthHostKey,\n} from './session';\n\n/** Who a version event's key is bound to, by the record in its `binding` tag. */\nexport type VersionBinding =\n | { kind: 'btc'; principal: string; pubkey: string; record: ParsedDeviceEvent }\n | {\n kind: 'session';\n principal: string;\n pubkey: string;\n deviceId: string;\n /** The vouch's signed issued_at (the host's clock). */\n issuedAt: number | null;\n };\n\nexport type Liveness = 'live' | 'revoked' | 'unknown';\n\n/** What reading a `binding` record needs: the host's keys (retired ones included) and a BIP-322 verifier. */\nexport interface BindingVerifiers {\n /** Throw UnansweredReadError when they could not be read; an empty list binds nothing. */\n hostKeys: () => Promise<readonly AuthHostKey[]>;\n verifyBip322: VerifyBip322;\n}\n\nconst bindingTag = (ev: NostrEvent): string | null =>\n ev.tags.find((t) => t[0] === 'binding')?.[1] ?? null;\n\n/** True when the version carries a `binding` tag, valid or not (0.3.0 and later). */\nexport function hasBindingTag(ev: NostrEvent): boolean {\n return bindingTag(ev) !== null;\n}\n\n/**\n * The principal the event's `binding` record binds its key to, or null when the\n * tag is absent or does not bind this key.\n */\nexport async function readVersionBinding(\n ev: NostrEvent,\n v: BindingVerifiers\n): Promise<VersionBinding | null> {\n const raw = bindingTag(ev);\n if (!raw) return null;\n let rec: NostrEvent;\n try {\n rec = JSON.parse(raw) as NostrEvent;\n } catch {\n return null;\n }\n return recordBinding(rec, ev.pubkey, v);\n}\n\n/** The principal a kind-30078 record binds `pubkey` to, or null. Throws\n * UnansweredReadError when the host's keys could not be read. */\nexport async function recordBinding(\n rec: NostrEvent,\n pubkey: string,\n v: BindingVerifiers\n): Promise<VersionBinding | null> {\n try {\n if (!rec || rec.kind !== 30078 || rec.pubkey !== pubkey || !verifyNostrEvent(rec)) return null;\n const auth = rec.tags.find((t) => t[0] === 'auth')?.[1];\n if (auth === 'session') {\n const p = parseSessionDeviceEvent(rec);\n if (p.revoked || !p.vouch) return null;\n const subject = {\n didOc: p.didOc,\n device_pk: p.device_pk,\n nostr_pk: rec.pubkey,\n device_id: p.device_id,\n };\n if (!verifySessionVouch(p.vouch, subject, await v.hostKeys())) return null;\n return {\n kind: 'session',\n principal: p.didOc,\n pubkey: rec.pubkey,\n deviceId: p.device_id,\n issuedAt: vouchIssuedAt(p.vouch),\n };\n }\n const p = parseDeviceEvent(rec);\n // Only a v3 statement signs the key that carries it (OC Lock SPEC §3.4).\n if (p.revoked || p.bindingVersion !== 'v3') return null;\n if (!authorizedDevices([p]).some((d) => d.nostrPubkey === pubkey)) return null;\n const ok = await v.verifyBip322({\n address: p.address,\n message: p.bindingStatement,\n signature: p.bindingSigBase64,\n });\n return ok === true ? { kind: 'btc', principal: p.address, pubkey, record: p } : null;\n } catch (e) {\n // A read with no answer (the host's keys) proves nothing: the caller hears it.\n if (e instanceof UnansweredReadError) throw e;\n return null;\n }\n}\n\n/** Is an address binding live, given every verified record seen for that address:\n * OC Lock's own rule, with the version's bind included so a relay dropping it\n * does not count as a revocation. */\nexport function btcBindingLive(\n b: Extract<VersionBinding, { kind: 'btc' }>,\n verified: readonly ParsedDeviceEvent[],\n now: Date\n): boolean {\n const live = authorizedDevices(liveDevices([...verified, b.record], { now }), { now });\n return live.some((d) => d.nostrPubkey === b.pubkey);\n}\n\n/** Is a session device revoked on any relay, by its own key or by the auth host (§8.6)? */\nexport function sessionBindingRevoked(\n b: Extract<VersionBinding, { kind: 'session' }>,\n events: readonly NostrEvent[],\n hostKeys: readonly AuthHostKey[]\n): boolean {\n return sessionDeviceRevoked(\n { nostrPubkey: b.pubkey, device_id: b.deviceId, issuedAt: b.issuedAt },\n sessionRevocations(events, b.principal, hostKeys)\n );\n}\n","// Channels (oc-chat-protocol SPEC §8.3) — the pure, offline-verifiable core.\n//\n// v1 = PUBLIC channels: a kind-30110 founder-rooted governance descriptor +\n// kind-30111 `chat-channel` posts + a Bitcoin-priced write gate. Private\n// channels (read:\"members\" + an encryption block + kind-30113 group keys) are\n// reserved behind the SAME descriptor (§8.3.7) and are NOT implemented here —\n// the v1 verifier rejects them as unsupported, never silently downgrades.\n//\n// A public channel makes NO E2EE claim (S-CH-4): it uses OC Lock *identity\n// binding* (BIP-322 device signatures via the kind-30078 record) + OC Chat's\n// *Bitcoin-priced access control*, not confidentiality. Posts are plaintext,\n// recipient-less (`recipients=[]` → E_CHANNEL_RECIPIENTS otherwise), and\n// content-addressed.\n//\n// Bitcoin-load-bearing axis (§8.3.3): ONLY `utxo-floor` (rooted:true) carries\n// the Bitcoin claim — a funded, aged UTXO has no Ed25519 analog, so spam is\n// priced in Bitcoin maturity. allowlist / founder / open are rooted:false (NOT\n// Bitcoin-load-bearing; rendered the muted \"via ochk.io\" tier). The\n// `write.rooted` flag MUST match the policy (E_CH_POLICY_INVALID), making the\n// Bitcoin claim a property of the artifact, not a UI label.\n//\n\n// Every read a verdict needs (bindings, liveness, the chain, BIP-322) is passed\n// in, so the same rules run in a browser, a relay's write gate or a terminal.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport { hexEncode, utf8Encode } from '@orangecheck/lock-crypto';\n\nimport { isValidAttachment, type Attachment } from './attachment';\nimport { b64urlNoPad, canonicalBytes } from './canonical';\nimport { signedBy, verifyNostrEvent, type NostrEvent } from './event';\nimport { answeredEvents, meetsReadFloor, UnansweredReadError, type Query, type VerifyBip322 } from './read';\nimport type { AuthHostKey } from './session';\nimport {\n hasBindingTag,\n readVersionBinding,\n type Liveness,\n type VersionBinding,\n} from './version-binding';\n\nexport const CHANNEL_DESCRIPTOR_KIND = 30110;\nexport const CHANNEL_POST_KIND = 30111;\n\nconst CH_DTAG_PREFIX = 'oc-lock-chat-ch:';\nconst POST_DTAG_PREFIX = 'oc-lock-chat-msg:';\nconst CH_SALT_LABEL = 'oc-lock-chat-ch/v1:';\n\n/** Slug: a NON-authoritative display label (S17). The trust root is the founder\n * address, never the slug. */\nconst SLUG_RE = /^[a-z0-9-]{3,48}$/;\n\n/** Wire-error + client-capability codes (§8.3 / §9). The first six are normative\n * protocol errors; `E_CH_UNSUPPORTED` is a v1-client capability signal (a\n * private-channel descriptor a public-only client can't render). */\nexport type ChannelError =\n | 'E_CHANNEL_RECIPIENTS'\n | 'E_CH_POLICY_INVALID'\n | 'E_CH_UNAUTHORIZED'\n | 'E_CH_WRITE_DENIED'\n | 'E_CH_NOT_WRITER'\n | 'E_CHAN_FLOOR'\n | 'E_CH_CLOSED'\n | 'E_CH_UNSUPPORTED';\n\n// ───────────────────────── types ─────────────────────────\n\n/** Is this inbox key bound to this principal (a Bitcoin address or a did:oc) by a\n * kind-30078 record? A reader that could not tell should throw, not answer false. */\nexport type IsBound = (pubkey: string, principal: string) => Promise<boolean>;\n\n/** Does this utxo-floor write proof match current chain state: an unspent output\n * of `address` with exactly the proof's value, height and block hash (§8.3.3)? */\nexport type VerifyOnChain = (proof: WriteProof, address: string) => Promise<boolean>;\n\nexport type WritePolicy = 'utxo-floor' | 'allowlist' | 'founder' | 'open';\n\nexport interface ChannelWrite {\n policy: WritePolicy;\n /** utxo-floor: minimum UTXO age (blocks) the write-proof must clear. */\n utxo_floor_confs: number;\n /** utxo-floor: minimum UTXO value (sats) counting toward the age test. */\n utxo_floor_sats: number;\n /** allowlist: hex SHA-256 of the canonical sorted writer-address list. */\n allowlist_root: string | null;\n /** MUST be true iff policy === 'utxo-floor' (§8.3.3). */\n rooted: boolean;\n}\n\n/** kind-30110 descriptor content (the hashed bytes; the binding sig + signer\n * ride in the event tags, NOT in here). */\nexport interface DescriptorContent {\n v: 1;\n channel_id: string;\n slug: string;\n founder_address: string;\n founder_inbox_pubkey: string;\n read: 'public'; // v1 (private \"members\" reserved, §8.3.7)\n encryption: null; // v1 (reserved private block)\n write: ChannelWrite;\n admins: string[];\n moderators: string[];\n title: string;\n description: string;\n avatar: string | null;\n rules: string | null;\n directory_opt_in: boolean;\n created_at: number;\n supersedes: string | null;\n /** §8.3.8 lifecycle. OMITTED when active (byte-compat with pre-close\n * descriptors + vc14/vc15); present as \"closed\" when the founder retires the\n * channel. A closed channel is read-only (only removal tombstones land);\n * re-openable via a later status:\"active\" founder revision. Only the FOUNDER\n * may change status (verifyDescriptor), so an admin cannot close via a coup. */\n status?: 'active' | 'closed';\n /** §8.3.8 optional pointer to a replacement channel a closed channel succeeds\n * to. A user-confirmed link, never an auto-redirect. */\n successor_channel_id?: string | null;\n}\n\n/** Self-contained, height-anchored UTXO write-proof (§8.3.3). Verified OFFLINE\n * against the reader's own tip — no per-post live point-query. `control_sig`\n * (BIP-322 over post_id) is NOT in this hashed struct; it rides the event. */\nexport interface WriteProof {\n outpoint: string;\n value_sats: number;\n anchor_block_height: number;\n anchor_block_hash: string;\n}\n\n/** kind-30111 `chat-channel` post content (the hashed bytes). A removal\n * tombstone (§8.3.5) is a post with `removes` = target post_id, written with `body:\"\"`. */\nexport interface PostContent {\n v: 1;\n kind: 'chat-channel';\n channel_id: string;\n author_address: string;\n author_inbox_pubkey: string;\n body: string;\n seq: number;\n parent_id: string | null;\n /** REQUIRED iff the channel's write.policy === 'utxo-floor'. */\n write_proof?: WriteProof;\n /** Moderation tombstone: the target post_id this removes (§8.3.5). */\n removes?: string;\n /** Optional PUBLIC inline file attachment (§8.3.2). UNLIKE a DM attachment it\n * is NOT encrypted — a public channel post is plaintext, so the file is\n * public too. It rides base64 in the content and is committed to post_id\n * (tamper-evident), size-bounded to MAX_ATTACHMENT_BYTES. */\n attachment?: Attachment;\n}\n\nexport type Role = 'founder' | 'admin' | 'moderator' | 'member';\n\n/** channel_id = SHA-256('oc-lock-chat-ch/v1:' ‖ founder_address ‖ ':' ‖ slug)\n * — identity binds to the founder address, the trust root (vc14, §8.3.1). */\nexport function channelId(founderAddress: string, slug: string): string {\n return hexEncode(sha256(utf8Encode(CH_SALT_LABEL + founderAddress + ':' + slug.toLowerCase())));\n}\n\n/** The pre-0.3.0 descriptor d-tag, \"oc-lock-chat-ch:\" ‖ b64url(SHA-256(salt ‖ channel_id)).\n * Readers still fetch it; nothing is published at it any more (§8.3.1). */\nexport function descriptorDtag(cid: string): string {\n return CH_DTAG_PREFIX + b64urlNoPad(sha256(utf8Encode(CH_SALT_LABEL + cid)));\n}\n\n/** A descriptor version's own d-tag, \"oc-lock-chat-ch:\" ‖ descriptor_id (0.3.0). */\nexport function versionDtag(did: string): string {\n return CH_DTAG_PREFIX + did;\n}\n\n/** Post d-tag = \"oc-lock-chat-msg:\" ‖ b64url(SHA-256(channel_id ‖ \":\" ‖ post_id)). */\nexport function postDtag(cid: string, pid: string): string {\n return POST_DTAG_PREFIX + b64urlNoPad(sha256(utf8Encode(cid + ':' + pid)));\n}\n\nexport function isValidSlug(slug: string): boolean {\n return SLUG_RE.test(slug);\n}\n\n/** descriptor_id = SHA-256(canonical(content)), hex (content-addressed, vc14). */\nexport function descriptorId(content: DescriptorContent): string {\n return hexEncode(sha256(canonicalBytes(content)));\n}\n\n/** post_id = SHA-256(canonical(content)), hex (content-addressed, vc16). */\nexport function postId(content: PostContent): string {\n return hexEncode(sha256(canonicalBytes(content)));\n}\n\n/** allowlist_root = hex SHA-256(canonical(sorted unique writer-address list)). */\nexport function allowlistRoot(addresses: string[]): string {\n const sorted = [...new Set(addresses)].sort();\n return hexEncode(sha256(canonicalBytes(sorted)));\n}\n\n// ─────────────────────── policy / roles ───────────────────────\n\n/** §8.3.3: utxo-floor ⇒ rooted:true; allowlist/founder/open ⇒ rooted:false.\n * A mismatch is E_CH_POLICY_INVALID — the Bitcoin claim is a property of the\n * artifact, not a UI label. */\nexport function policyRootedMatches(write: ChannelWrite): boolean {\n return write.rooted === (write.policy === 'utxo-floor');\n}\n\n/** Is a write policy Bitcoin-load-bearing (passes the Ed25519 substitution\n * test)? Only utxo-floor in v1 (pay-to-post is the deferred kind-30115 one). */\nexport function isRootedPolicy(policy: WritePolicy): boolean {\n return policy === 'utxo-floor';\n}\n\nexport function roleOf(address: string, d: DescriptorContent): Role {\n if (address === d.founder_address) return 'founder';\n if (d.admins.includes(address)) return 'admin';\n if (d.moderators.includes(address)) return 'moderator';\n return 'member';\n}\n\n/**\n * The badge the roster shows. A founder lists admins and moderators without\n * their say, so one who has never posted here reads as named by the founder,\n/** Rough address-shape guard: a utxo-floor author MUST post under a Bitcoin\n * address (a did:oc can't own a UTXO). The BIP-322 control_sig is the real\n * check; this only rejects an obviously non-Bitcoin principal early. */\nexport function isBitcoinAddress(addr: string): boolean {\n if (/^(bc1|tb1|bcrt1)[02-9ac-hj-np-z]{6,}$/i.test(addr)) return true; // bech32(m)\n if (/^[13][a-km-zA-HJ-NP-Z1-9]{25,39}$/.test(addr)) return true; // base58 p2pkh/p2sh\n return false;\n}\n\n// ─────────────────── write-proof arithmetic (vc17) ───────────────────\n\nexport interface WriteProofVerdict {\n /** Age of the anchored UTXO at the reader's tip: tip − anchor + 1. */\n ageConfs: number;\n meetsAge: boolean;\n meetsValue: boolean;\n verdict: 'accept' | 'E_CHAN_FLOOR';\n}\n\n/**\n * Evaluate a height-anchored UTXO write-proof OFFLINE against the reader's own\n * current tip (one tip read per render batch, never per post). Pure arithmetic\n * — reproduces vc17. The control_sig (BIP-322 over post_id) is verified\n * separately in checkWritePermission; this only gates value + age.\n */\nexport function evaluateWriteProof(\n proof: Pick<WriteProof, 'value_sats' | 'anchor_block_height'>,\n policy: Pick<ChannelWrite, 'utxo_floor_confs' | 'utxo_floor_sats'>,\n tipHeight: number\n): WriteProofVerdict {\n const ageConfs = tipHeight - proof.anchor_block_height + 1;\n const meetsAge = ageConfs >= policy.utxo_floor_confs;\n const meetsValue = proof.value_sats >= policy.utxo_floor_sats;\n return {\n ageConfs,\n meetsAge,\n meetsValue,\n verdict: meetsAge && meetsValue ? 'accept' : 'E_CHAN_FLOOR',\n };\n}\n\n\nexport function parseDescriptor(ev: NostrEvent): DescriptorContent | null {\n try {\n const c = JSON.parse(ev.content) as Record<string, unknown>;\n if (c.v !== 1) return null;\n if (typeof c.channel_id !== 'string' || typeof c.slug !== 'string') return null;\n if (typeof c.founder_address !== 'string') return null;\n if (typeof c.founder_inbox_pubkey !== 'string') return null;\n if (!c.write || typeof c.write !== 'object') return null;\n if (typeof c.created_at !== 'number') return null;\n // Text every reader shows; not text is not a descriptor (§8.3.1).\n if (typeof c.title !== 'string' || typeof c.description !== 'string') return null;\n return c as unknown as DescriptorContent;\n } catch {\n return null;\n }\n}\n\nexport function parsePost(ev: NostrEvent): PostContent | null {\n try {\n const c = JSON.parse(ev.content) as Record<string, unknown>;\n if (c.v !== 1 || c.kind !== 'chat-channel') return null;\n if (typeof c.channel_id !== 'string' || typeof c.author_address !== 'string') return null;\n if (typeof c.author_inbox_pubkey !== 'string' || typeof c.body !== 'string') return null;\n // A malformed/oversized attachment is a render-DoS — drop the whole post\n // (the attachment is committed to post_id, so it can't be stripped).\n if (c.attachment !== undefined && !isValidAttachment(c.attachment)) return null;\n return c as unknown as PostContent;\n } catch {\n return null;\n }\n}\n\n\n// ───────────────────────── verify ─────────────────────────\n\nexport type DescriptorVerify =\n | { ok: true; channelId: string; descriptorId: string; signerAddress: string }\n | { ok: false; error: ChannelError };\n\n/**\n * Verify a channel descriptor (§8.3.1) OFFLINE given the descriptor content + its\n * kind-30110 event. Authorship = the event's schnorr signature by an inbox key\n * that is bound (kind-30078) to the founder (genesis) or a PRIOR-epoch admin\n * (supersede) — the governance hash-chain, the §5 parent_id trick applied to\n * governance (vc15). No per-edit wallet ceremony: the device record IS the\n * binding, established once. The Bitcoin claim is in the write policy, not here.\n *\n * v1 rejects private descriptors (read != \"public\" or encryption != null) as\n * E_CH_UNSUPPORTED — a public-only client never silently downgrades them.\n */\nexport async function verifyDescriptor(\n content: DescriptorContent,\n event: NostrEvent,\n opts: {\n priorEpoch?: DescriptorContent;\n /** Is this inbox key bound to this principal (an address or a did:oc)? */\n isBound: IsBound;\n }\n): Promise<DescriptorVerify> {\n const isBound = opts.isBound;\n\n // Phase guard: v1 is public-only.\n if (content.read !== 'public' || content.encryption !== null) {\n return { ok: false, error: 'E_CH_UNSUPPORTED' };\n }\n // Capability guard: the public-only v1 client does not implement allowlist\n // membership proofs (§8.3.3), so it cannot resolve the writer set on read —\n // every post would then fail-closed and silently vanish. Reject the descriptor\n // as unsupported instead, so the unsupported state is honest rather than a\n // channel that renders permanently empty with no error.\n if (content.write.policy === 'allowlist') {\n return { ok: false, error: 'E_CH_UNSUPPORTED' };\n }\n // Identity integrity: channel_id MUST bind to founder_address ‖ slug.\n if (channelId(content.founder_address, content.slug) !== content.channel_id) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n // Policy/rooted match (the Bitcoin claim is a property of the artifact).\n if (!policyRootedMatches(content.write)) {\n return { ok: false, error: 'E_CH_POLICY_INVALID' };\n }\n // The event must be self-consistent + schnorr-signed by its own pubkey, and\n // actually carry this content (its content hashes to descriptor_id).\n if (!signedBy(event, event.pubkey)) return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n if (event.content !== JSON.stringify(content)) {\n // Allow a re-serialization match (key order may differ on the wire); the\n // content-addressed id is canonical, so compare on descriptorId instead.\n if (descriptorId(parseDescriptor(event) ?? content) !== descriptorId(content)) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n }\n\n const did = descriptorId(content);\n\n if (!opts.priorEpoch) {\n // Genesis: supersedes MUST be null; the signing inbox key IS the founder's\n // and is bound to founder_address via the kind-30078 record.\n if (content.supersedes !== null) return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n if (event.pubkey !== content.founder_inbox_pubkey) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n if (!(await isBound(event.pubkey, content.founder_address))) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n return {\n ok: true,\n channelId: content.channel_id,\n descriptorId: did,\n signerAddress: content.founder_address,\n };\n }\n\n const prior = opts.priorEpoch;\n // Same channel, and the chain links to the prior descriptor_id.\n if (content.channel_id !== prior.channel_id) return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n if (content.supersedes !== descriptorId(prior)) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n // The inbox TRUST-ROOT key is immutable across epochs (founder_address is\n // already pinned by channel_id at line 465). A supersede that mutates\n // founder_inbox_pubkey — e.g. an admin redirecting the channel's trust root to\n // their own device key — is unauthorized.\n if (content.founder_inbox_pubkey !== prior.founder_inbox_pubkey) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n // The FOUNDER is the trust root (§8.3.4: \"may do anything, including replace the\n // descriptor\") — a founder-signed supersede may make any change.\n if (await isBound(event.pubkey, prior.founder_address)) {\n return {\n ok: true,\n channelId: content.channel_id,\n descriptorId: did,\n signerAddress: prior.founder_address,\n };\n }\n // An ADMIN-signed supersede may edit metadata/policy but MUST NOT stage a\n // governance coup: it cannot remove the founder or any prior admin (require\n // prior.admins ⊆ next.admins), and it cannot CLOSE or RE-OPEN the channel\n // (§8.3.8 status change is founder-only — an admin nuking a channel others\n // rely on is exactly the coup we forbid). Only the founder may do either, and\n // only the founder may set or change successor_channel_id, at any status.\n for (const addr of prior.admins) {\n if (await isBound(event.pubkey, addr)) {\n const nextAdmins = new Set(content.admins);\n if (!prior.admins.every((a) => nextAdmins.has(a))) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n if ((prior.status ?? 'active') !== (content.status ?? 'active')) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n if ((prior.successor_channel_id ?? null) !== (content.successor_channel_id ?? null)) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n return {\n ok: true,\n channelId: content.channel_id,\n descriptorId: did,\n signerAddress: addr,\n };\n }\n }\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n}\n\nexport interface VerifyPostOpts {\n /** Reader's current tip height (one read per render batch). */\n tipHeight: number;\n /** BIP-322 by author_address over post_id — REQUIRED for utxo-floor. */\n controlSig?: string;\n /** The full writer-address list for an allowlist channel (membership proof). */\n allowlist?: string[];\n /** The Nostr event (to verify the author device signature). verifyPost\n * rejects a post without it; checkWritePolicy does not read it. */\n event?: NostrEvent;\n /** Is this inbox key bound to this principal? verifyPost needs it. */\n isBound?: IsBound;\n /** BIP-322, for a utxo-floor post's control_sig. */\n verifyBip322: VerifyBip322;\n /** A non-empty recipients[] on a chat-channel envelope is E_CHANNEL_RECIPIENTS. */\n recipients?: unknown[];\n /** utxo-floor: binds the write_proof to real chain state (io.ts has one\n * over an esplora API). Fail-closed: false drops the post. */\n verifyOnChain: VerifyOnChain;\n}\n\nexport type PostVerify =\n | { ok: true; postId: string; role: Role; isTombstone: boolean }\n | { ok: false; error: ChannelError };\n\n/**\n * NON-AUTHORITATIVE policy check (§8.3.2/§8.3.3): recipient-exclusion, channel\n * match, writer role, and the write-policy gate — ASSUMING the author is already\n * authenticated. It does NOT verify the author device signature or the kind-30078\n * binding. `verifyPost` wraps this with that authentication; this is exposed only\n * so the write-gate arithmetic (vc17) can be unit-tested without minting a real\n * device record. Never call it as an authorization decision on its own.\n */\nexport async function checkWritePolicy(\n content: PostContent,\n descriptor: DescriptorContent,\n opts: VerifyPostOpts\n): Promise<PostVerify> {\n const verify = opts.verifyBip322;\n\n // (0) recipient-exclusion: a chat-channel post is public + recipient-less.\n if (opts.recipients && opts.recipients.length > 0) {\n return { ok: false, error: 'E_CHANNEL_RECIPIENTS' };\n }\n // A non-channel envelope kind is not a valid channel post (distinct from the\n // recipient-exclusion condition — they are different defects).\n if (content.kind !== 'chat-channel') return { ok: false, error: 'E_CH_WRITE_DENIED' };\n if (content.channel_id !== descriptor.channel_id) {\n return { ok: false, error: 'E_CH_WRITE_DENIED' };\n }\n\n const pid = postId(content);\n const role = roleOf(content.author_address, descriptor);\n // A removal names its target in `removes`; its body grants nothing (§8.3.5).\n const isTombstone = typeof content.removes === 'string';\n\n // Moderation tombstone: roster moderator/admin/founder only (§8.3.5).\n if (isTombstone) {\n if (role === 'member') return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n return { ok: true, postId: pid, role, isTombstone: true };\n }\n\n // §8.3.8: a CLOSED channel is read-only. Removal tombstones (above) still land\n // so moderation works after close; every other post is denied. Forward-\n // effective only — posts already propagated are unaffected.\n if ((descriptor.status ?? 'active') === 'closed') {\n return { ok: false, error: 'E_CH_CLOSED' };\n }\n\n const denied = await checkWritePermission(content, descriptor, role, pid, opts, verify);\n if (denied) return { ok: false, error: denied };\n return { ok: true, postId: pid, role, isTombstone: false };\n}\n\n/**\n * AUTHORITATIVE verify of a public channel post (§8.3.2). REQUIRES the kind-30111\n * event so it can prove authorship — there is no unauthenticated accept path:\n * (0) recipient-exclusion; (1) the event schnorr-signed by author_inbox_pubkey\n * AND that inbox key bound to author_address via the kind-30078 record; (2)/(3)\n * the §8.3.3 write-policy gate + writer role (via checkWritePolicy). A post with\n * no event cannot be authenticated and is rejected E_CH_UNAUTHORIZED.\n */\nexport async function verifyPost(\n content: PostContent,\n descriptor: DescriptorContent,\n opts: VerifyPostOpts\n): Promise<PostVerify> {\n const isBound = opts.isBound;\n\n // (0) recipient-exclusion is structural — check before authentication so a\n // recipient-bearing post returns the precise code, not E_CH_UNAUTHORIZED.\n if (opts.recipients && opts.recipients.length > 0) {\n return { ok: false, error: 'E_CHANNEL_RECIPIENTS' };\n }\n // (1) authorship is MANDATORY: no event ⇒ unauthenticated ⇒ reject.\n if (!opts.event || !isBound) return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n if (!signedBy(opts.event, content.author_inbox_pubkey)) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n if (!(await isBound(content.author_inbox_pubkey, content.author_address))) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n return checkWritePolicy(content, descriptor, opts);\n}\n\n/** The §8.3.3 write gate. founder/admin bypass all policies (the trust root). */\nasync function checkWritePermission(\n content: PostContent,\n descriptor: DescriptorContent,\n role: Role,\n pid: string,\n opts: VerifyPostOpts,\n verify: VerifyBip322\n): Promise<ChannelError | null> {\n if (role === 'founder' || role === 'admin') return null;\n const w = descriptor.write;\n switch (w.policy) {\n case 'founder':\n return 'E_CH_NOT_WRITER'; // only founder/admin (handled above)\n case 'open':\n return null; // any valid device may post\n case 'allowlist': {\n if (!opts.allowlist) return 'E_CH_WRITE_DENIED';\n if (allowlistRoot(opts.allowlist) !== w.allowlist_root) {\n return 'E_CH_WRITE_DENIED';\n }\n return opts.allowlist.includes(content.author_address) ? null : 'E_CH_WRITE_DENIED';\n }\n case 'utxo-floor': {\n if (!content.write_proof) return 'E_CHAN_FLOOR';\n if (!opts.controlSig) return 'E_CHAN_FLOOR';\n if (!isBitcoinAddress(content.author_address)) return 'E_CHAN_FLOOR';\n // Cheap offline gates first (no network): the floor arithmetic + the\n // control_sig (author controls the address, over post_id).\n const v = evaluateWriteProof(content.write_proof, w, opts.tipHeight);\n if (v.verdict !== 'accept') return 'E_CHAN_FLOOR';\n const sigOk = await verify({\n address: content.author_address,\n message: pid,\n signature: opts.controlSig,\n });\n if (sigOk !== true) return 'E_CHAN_FLOOR';\n // THE Bitcoin-load-bearing leg: bind the proof to real chain state — the\n // claimed coin must actually exist, be unspent, be owned by the author's\n // address, and carry the asserted value/height/hash. Without this the\n // value/age are unverified author claims (the §8.3.3 forgery). Fail-closed.\n if ((await opts.verifyOnChain(content.write_proof, content.author_address)) !== true) {\n return 'E_CHAN_FLOOR';\n }\n return null;\n }\n }\n}\n\n// ───────────────────── the governance chain ─────────────────────\n\n/** A version of a channel the resolution authorized (§8.3.1). */\nexport interface ResolvedVersion {\n descriptorId: string;\n descriptor: DescriptorContent;\n /** The keys of its authorized copies, the founder's first. */\n signers: string[];\n /** The event ids of its authorized copies. A copy of the same content under any\n * other key or event is not one: the id covers the content, not the signer. */\n copies: string[];\n}\n\nexport interface ResolvedChannel {\n descriptor: DescriptorContent;\n descriptorId: string;\n /** How many governance epochs validated back to genesis (1 = genesis only). */\n epochs: number;\n /** The key that signed the copy of the tip the channel resolved by. */\n tipPubkey: string;\n /** The resolved chain from the genesis to the tip, with every key that signed\n * an authorized copy of each version, and those copies' event ids. */\n chain: ResolvedVersion[];\n /** Every authorized version, on any branch, with every key that signed a copy. */\n versions: ResolvedVersion[];\n /** Every closed tip, overruled ones included: a re-open supersedes each (§8.3.8). */\n closedTips: { descriptorId: string; descriptor: DescriptorContent }[];\n}\n\n/** What a resolver needs beyond the events themselves. */\nexport interface ChainReads {\n /** A pre-0.3.0 version (no `binding` tag): is its key bound to the principal now? */\n isBound: IsBound;\n /** Every key the auth host publishes, retired ones included (§8.6). Read once, when a session record needs them. */\n hostKeys: () => Promise<readonly AuthHostKey[]>;\n /** Is a version's binding still live: no revocation of it seen on any relay,\n * and an address bind not dated ahead of the reader's clock? 'unknown' (no\n * relay answered) stops the resolution with UnansweredReadError; a liveness\n * read may also throw its own error. */\n liveness: (b: VersionBinding) => Promise<Liveness>;\n verifyBip322: VerifyBip322;\n}\n\n/** An authorized copy of a version: whether the founder signed it, and its binding\n * (null for a pre-0.3.0 copy, authorized by a binding read from the relays). */\ninterface AuthorizedCopy {\n ev: NostrEvent;\n founder: boolean;\n binding: VersionBinding | null;\n}\n\n/**\n * Walk the governance hash-chain over every version of a channel and return the\n * tip that resolves (§8.3.1). A version with a later version after it stands on\n * the binding its event carries; the last version of a chain also needs that\n * binding to be live, else the chain ends at the version before it. Competing\n * tips: a founder-signed branch at a fork wins, then a closed tip, then the\n * longest chain, then the freshest signed created_at, then the lowest\n * descriptor_id. Null if nothing resolves; UnansweredReadError if a liveness\n * read could not be answered.\n */\nexport async function resolveChannelChain(\n events: NostrEvent[],\n cid: string,\n opts: ChainReads\n): Promise<ResolvedChannel | null> {\n // Index descriptors by their own descriptor_id, keeping EVERY event that\n // carries it. Authorship is the event's key, which sits outside the id, so\n // anyone can re-sign a descriptor under their own key: keeping one copy let\n // a stranger's unauthorized copy replace the founder's and roll the channel\n // back. A descriptor stands if any copy is authorized (§8.3.1).\n const nodes = new Map<string, { content: DescriptorContent; events: NostrEvent[] }>();\n for (const ev of events) {\n const content = parseDescriptor(ev);\n if (!content) continue;\n // The d-tag is a relay-side lookup key, not a trust boundary: another\n // founder's valid channel published under this d-tag must not compete.\n if (content.channel_id !== cid) continue;\n if (!signedBy(ev, ev.pubkey)) continue;\n const id = descriptorId(content);\n const node = nodes.get(id);\n if (!node) nodes.set(id, { content, events: [ev] });\n else if (!node.events.some((e) => e.id === ev.id)) node.events.push(ev);\n }\n if (nodes.size === 0) return null;\n\n let keys: Promise<readonly AuthHostKey[]> | null = null;\n const hostKeys = () => (keys ??= opts.hostKeys());\n const bindings = new Map<string, Promise<VersionBinding | null>>();\n const bindingOf = (ev: NostrEvent) => {\n if (!bindings.has(ev.id))\n bindings.set(ev.id, readVersionBinding(ev, { hostKeys, verifyBip322: opts.verifyBip322 }));\n return bindings.get(ev.id)!;\n };\n\n // Every authorized copy of a version, the founder's first. A version with a\n // `binding` tag is signed by the principal its record names; one without\n // (pre-0.3.0) only by a key a record on the relays binds now.\n const authorize = async (\n node: { content: DescriptorContent; events: NostrEvent[] },\n priorEpoch?: DescriptorContent\n ): Promise<AuthorizedCopy[]> => {\n const out: AuthorizedCopy[] = [];\n for (const ev of node.events) {\n const binding = await bindingOf(ev);\n const isBound = hasBindingTag(ev)\n ? async (pk: string, principal: string) =>\n binding !== null && pk === binding.pubkey && principal === binding.principal\n : opts.isBound;\n const v = await verifyDescriptor(node.content, ev, {\n ...(priorEpoch ? { priorEpoch } : {}),\n isBound,\n });\n if (!v.ok) continue;\n const founder = !priorEpoch || v.signerAddress === priorEpoch.founder_address;\n out.push({ ev, founder, binding });\n }\n return out.sort((a, b) => Number(b.founder) - Number(a.founder));\n };\n\n // Validate each version's chain back to a genesis; memoize its depth.\n const copies = new Map<string, AuthorizedCopy[]>();\n const depthCache = new Map<string, number | null>();\n const validateChain = async (id: string, seen: Set<string>): Promise<number | null> => {\n if (depthCache.has(id)) return depthCache.get(id)!;\n const node = nodes.get(id);\n if (!node || seen.has(id)) {\n depthCache.set(id, null);\n return null;\n }\n seen.add(id);\n const prevId = node.content.supersedes;\n let priorDepth = 0;\n let prior: DescriptorContent | undefined;\n if (prevId !== null) {\n const p = nodes.get(prevId);\n const d = p ? await validateChain(prevId, seen) : null;\n if (!p || d === null) {\n depthCache.set(id, null);\n return null;\n }\n priorDepth = d;\n prior = p.content;\n }\n const a = await authorize(node, prior);\n if (a.length) copies.set(id, a);\n const depth = a.length ? priorDepth + 1 : null;\n depthCache.set(id, depth);\n return depth;\n };\n for (const id of nodes.keys()) await validateChain(id, new Set());\n\n // The copy a version counts by as the last of its chain: an authorized copy\n // whose binding is live, the founder's first. A pre-0.3.0 copy was authorized\n // by a binding read just now, so it is live by that read.\n const liveness = opts.liveness;\n const liveCache = new Map<string, Promise<Liveness>>();\n const isLive = async (c: AuthorizedCopy): Promise<boolean> => {\n if (!c.binding) return true;\n // Per binding, not per key: the same key under a later vouch can be live\n // while its earlier one is revoked.\n const b = c.binding;\n const key = `${b.principal}:${b.pubkey}:${b.kind === 'session' ? b.issuedAt : b.record.eventId}`;\n if (!liveCache.has(key)) liveCache.set(key, liveness(c.binding));\n const l = await liveCache.get(key)!;\n if (l === 'unknown') throw new UnansweredReadError();\n return l === 'live';\n };\n const tipCopy = async (id: string): Promise<AuthorizedCopy | null> => {\n for (const c of copies.get(id) ?? []) if (await isLive(c)) return c;\n return null;\n };\n const tips = new Map<string, AuthorizedCopy>();\n for (const id of copies.keys()) {\n const c = await tipCopy(id);\n if (c) tips.set(id, c);\n }\n\n // Only versions on a chain that resolves count at a fork: a revoked key's\n // dead branch must not overrule a live one.\n const resolving = new Set<string>();\n for (const tip of tips.keys()) {\n let cur: string | null = tip;\n while (cur && !resolving.has(cur)) {\n resolving.add(cur);\n cur = nodes.get(cur)?.content.supersedes ?? null;\n }\n }\n // A version's rank at a fork: 1 the founder signed it with a live binding,\n // 2 the founder signed it with a binding since revoked, 3 anything else.\n const rank = new Map<string, number>();\n for (const id of resolving) {\n const founderCopies = (copies.get(id) ?? []).filter((c) => c.founder);\n let r = founderCopies.length ? 2 : 3;\n for (const c of founderCopies) if (await isLive(c)) r = 1;\n rank.set(id, r);\n }\n\n // Longest chain alone would let an admin fork from a version before the\n // founder's latest decision (e.g. before being removed) and outgrow it, and\n // a stolen founder key, once revoked, outgrow the founder's live device, by\n // a fork or by a genesis of its own. So at a fork, and among geneses, every\n // branch through a version ranked below the best is overruled, however long\n // it grows.\n const overruled = (id: string): boolean => {\n // Siblings at a fork share a parent; the geneses of one channel are\n // siblings under a virtual root (null).\n const beaten = (curId: string, parentId: string | null): boolean => {\n let best = 3;\n for (const [otherId, other] of nodes) {\n if (other.content.supersedes === parentId && resolving.has(otherId)) {\n best = Math.min(best, rank.get(otherId)!);\n }\n }\n return rank.get(curId)! > best;\n };\n let curId = id;\n for (let cur = nodes.get(id); cur; cur = nodes.get(curId)) {\n const parentId = cur.content.supersedes;\n if (beaten(curId, parentId)) return true;\n if (parentId === null) return false;\n curId = parentId;\n }\n return false;\n };\n\n const chainTo = (id: string): ResolvedChannel['chain'] => {\n const out: ResolvedChannel['chain'] = [];\n for (let cur: string | null = id; cur; cur = nodes.get(cur)!.content.supersedes) {\n const cs = copies.get(cur) ?? [];\n out.unshift({\n descriptorId: cur,\n descriptor: nodes.get(cur)!.content,\n signers: cs.map((c) => c.ev.pubkey),\n copies: cs.map((c) => c.ev.id),\n });\n }\n return out;\n };\n\n // Among the tips left (versions nothing supersedes): a closed one, then the\n // longest chain, then the freshest signed created_at, then the lowest\n // descriptor_id, so every reader picks the same tip (§8.3.1, 0.3.2).\n const key = (id: string) => {\n const d = nodes.get(id)!.content;\n return [d.status === 'closed' ? 1 : 0, depthCache.get(id)!, d.created_at] as const;\n };\n const beats = (a: string, b: string): boolean => {\n const ka = key(a);\n const kb = key(b);\n for (let i = 0; i < ka.length; i++) if (ka[i] !== kb[i]) return ka[i]! > kb[i]!;\n return a < b;\n };\n // A tip is a version no resolving version supersedes: a close that a re-open\n // superseded is no longer one.\n const superseded = new Set<string>();\n for (const id of resolving) {\n const parent = nodes.get(id)?.content.supersedes;\n if (parent) superseded.add(parent);\n }\n const closedTips = [...tips.keys()]\n .filter((id) => !superseded.has(id) && nodes.get(id)!.content.status === 'closed')\n .map((id) => ({ descriptorId: id, descriptor: nodes.get(id)!.content }));\n let best: ResolvedChannel | null = null;\n let bestId: string | null = null;\n for (const [id, c] of tips) {\n if (superseded.has(id) || overruled(id)) continue;\n const depth = depthCache.get(id)!;\n if (bestId === null || beats(id, bestId)) {\n best = {\n descriptor: nodes.get(id)!.content,\n descriptorId: id,\n epochs: depth,\n tipPubkey: c.ev.pubkey,\n chain: chainTo(id),\n versions: [...copies].map(([vid, cs]) => ({\n descriptorId: vid,\n descriptor: nodes.get(vid)!.content,\n signers: cs.map((c) => c.ev.pubkey),\n copies: cs.map((c) => c.ev.id),\n })),\n closedTips,\n };\n bestId = id;\n }\n }\n return best;\n}\n\n/** Where one version event stands in a resolved channel. */\nexport interface CopyStanding {\n descriptorId: string;\n /** Its version is on the chain from the genesis to the tip. */\n onChain: boolean;\n /** Its version is the tip the channel resolved to. */\n isTip: boolean;\n}\n\n/**\n * Is this event an authorized copy of a version of `resolved` (§8.3.1)? A version\n * stands when any copy of it is authorized, but an event is authorized only when\n * it is one of those copies: the same content signed by another key, or carried\n * by another event, is not, though its descriptor_id is the same. Null when the\n * event is not an authorized copy, or does not verify (NIP-01).\n */\nexport function authorizedCopy(resolved: ResolvedChannel | null, ev: NostrEvent): CopyStanding | null {\n if (!resolved || !verifyNostrEvent(ev)) return null;\n const v = resolved.versions.find((x) => x.copies.includes(ev.id));\n if (!v) return null;\n return {\n descriptorId: v.descriptorId,\n onChain: resolved.chain.some((c) => c.descriptorId === v.descriptorId),\n isTip: resolved.descriptorId === v.descriptorId,\n };\n}\n\n/** The reads readChannelVersions makes: one relay query, and every inbox key a principal's records have ever bound. */\nexport interface VersionReads {\n /** One REQ to the reader's relays. */\n query: Query;\n /** Every key a principal's device records have bound, revoked ones too (§8.3.1); whether a\n * relay answered; and whether the read met the floor (§8.7), so that no key is missing. */\n everBoundKeys: (principal: string) => Promise<{ keys: string[]; answered: boolean; floor: boolean }>;\n}\n\n/** Events asked for per page: relays commonly cap one REQ at 500. */\nconst VERSION_PAGE_LIMIT = 500;\n/** Pages read for one channel's `t` tag: up to 2,000 events, as attest reads a subject. */\nconst VERSION_MAX_PAGES = 4;\n/** Rounds of walking forward by `s` or back by exact d-tag past what the pages read. */\nconst VERSION_WALK_ROUNDS = 64;\n/** Exact d-tags asked for per round of the walk back, so a REQ stays small. */\nconst VERSION_BACK_IDS = 100;\n/** Keys read per principal: past this, one principal's rotations cannot fan the reader out. */\nconst VERSION_MAX_KEYS = 32;\n/** REQs the founder's-keys read and the walk by `s` make in all. */\nconst VERSION_MAX_ROLE_REQS = 256;\n\n/** The founder a version names, when its founder and slug derive `cid`. */\nfunction founderFrom(e: NostrEvent, cid: string): string | null {\n const c = parseDescriptor(e);\n return c && c.channel_id === cid && channelId(c.founder_address, c.slug) === cid\n ? c.founder_address\n : null;\n}\n\n/**\n * Every version of a channel a reader can find (§8.3.1, 0.3.0), whether the open\n * read under its `t` tag stopped at the page bound, and whether the reads by\n * role holders' keys stopped short (an unanswered key lookup, or a bound).\n * Anyone can publish under that tag, so besides the paged open read and the\n * legacy d-tag it reads where a flood cannot reach: the versions the founder's\n * keys signed, then forward by `s` from each of those, by the keys of the role\n * holders that version names. Then back by exact d-tag to any version a\n * `supersedes` names, the parents role holders named first. Every copy is\n * kept. Throws UnansweredReadError when no read was answered. `floorMet` is\n * false when any read, of versions or of a role holder's keys, fell below the\n * read floor (§8.7), so a newer version may exist.\n */\nexport async function readChannelVersions(\n cid: string,\n reads: VersionReads,\n founderHint?: string\n): Promise<{ events: NostrEvent[]; truncated: boolean; incomplete: boolean; floorMet: boolean }> {\n const queryEvents = reads.query;\n const merged = new Map<string, NostrEvent>();\n const status: { eose: boolean }[] = [];\n // A read without relay statuses is taken as it is, as answeredEvents takes it.\n let floorMet = true;\n // Versions a role holder's key signed: the only ones the walk goes forward from.\n const walkable = new Set<string>();\n const roleKeys = new Set<string>();\n const add = (\n res: { events?: NostrEvent[]; relayStatus?: readonly { eose: boolean }[] },\n byRole = false\n ) => {\n status.push(...(res.relayStatus ?? []));\n if (res.relayStatus && !meetsReadFloor(res.relayStatus)) floorMet = false;\n let fresh = 0;\n for (const e of res.events ?? []) {\n if (byRole) walkable.add(e.id);\n if (merged.has(e.id)) continue;\n merged.set(e.id, e);\n fresh++;\n }\n return fresh;\n };\n const legacy = queryEvents({ kinds: [CHANNEL_DESCRIPTOR_KIND], '#d': [descriptorDtag(cid)] });\n\n // The open read, paged with `until` (inclusive; events already read are skipped).\n let until: number | undefined;\n let truncated = false;\n for (let page = 0; page < VERSION_MAX_PAGES; page++) {\n const res = await queryEvents({\n kinds: [CHANNEL_DESCRIPTOR_KIND],\n '#t': [cid],\n limit: VERSION_PAGE_LIMIT,\n ...(until !== undefined ? { until } : {}),\n });\n const fresh = add(res);\n for (const e of res.events ?? []) until = Math.min(until ?? Infinity, e.created_at);\n // A full page may have more behind it. One that brought nothing new is\n // stuck on a second it cannot page past: the read stops there, cut off.\n if ((res.events ?? []).length < VERSION_PAGE_LIMIT) break;\n if (fresh === 0 || page === VERSION_MAX_PAGES - 1) {\n truncated = true;\n break;\n }\n }\n add(await legacy);\n\n // The founder's keys first, then forward from each version by `s`, from the\n // keys of the founder and the admins that version names. Every key their\n // records have bound counts, revoked ones too: an earlier version stands on\n // its binding whatever became of the key since. One REQ per key, so what one\n // key floods its own reads with hides only that key's own versions.\n let incomplete = false;\n let reqs = 0;\n const founder =\n founderHint ?? [...merged.values()].map((e) => founderFrom(e, cid)).find(Boolean) ?? null;\n if (!founder) incomplete = true;\n else {\n const keysCache = new Map<string, Promise<string[]>>();\n const keysOf = (p: string) => {\n if (!keysCache.has(p))\n keysCache.set(\n p,\n reads\n .everBoundKeys(p)\n .catch(() => ({ keys: [] as string[], answered: false, floor: false }))\n .then(({ keys, answered, floor }) => {\n if (!answered || keys.length > VERSION_MAX_KEYS) incomplete = true;\n if (!floor) floorMet = false;\n const used = keys.slice(0, VERSION_MAX_KEYS);\n for (const k of used) roleKeys.add(k);\n return used;\n })\n );\n return keysCache.get(p)!;\n };\n const read = async (filter: Record<string, unknown>, keys: readonly string[]) => {\n const fresh = keys.slice(0, Math.max(0, VERSION_MAX_ROLE_REQS - reqs));\n if (fresh.length < keys.length) incomplete = true;\n reqs += fresh.length;\n for (const res of await Promise.all(\n fresh.map((k) =>\n queryEvents({\n kinds: [CHANNEL_DESCRIPTOR_KIND],\n ...filter,\n authors: [k],\n limit: VERSION_PAGE_LIMIT,\n })\n )\n )) {\n add(res, true);\n }\n };\n await read({ '#t': [cid] }, await keysOf(founder));\n const walked = new Set<string>();\n let round = 0;\n for (; round < VERSION_WALK_ROUNDS; round++) {\n const frontier: DescriptorContent[] = [];\n for (const e of merged.values()) {\n if (!walkable.has(e.id)) continue;\n const c = parseDescriptor(e);\n if (!c || c.channel_id !== cid) continue;\n const id = descriptorId(c);\n if (walked.has(id)) continue;\n walked.add(id);\n frontier.push(c);\n }\n if (frontier.length === 0) break;\n for (const c of frontier) {\n const keys = [\n ...new Set((await Promise.all([founder, ...c.admins].map(keysOf))).flat()),\n ];\n await read({ '#s': [descriptorId(c)] }, keys);\n }\n }\n if (round === VERSION_WALK_ROUNDS) incomplete = true;\n }\n\n // Back by exact d-tag to any version a supersedes names that no read returned.\n const asked = new Set<string>();\n for (let round = 0; round < VERSION_WALK_ROUNDS; round++) {\n const have = new Set<string>();\n // Each parent named, and whether a role holder's key signed a version naming it.\n const wanted = new Map<string, boolean>();\n for (const e of merged.values()) {\n const c = parseDescriptor(e);\n if (!c || c.channel_id !== cid) continue;\n have.add(descriptorId(c));\n if (c.supersedes)\n wanted.set(c.supersedes, !!wanted.get(c.supersedes) || roleKeys.has(e.pubkey));\n }\n const missing = [...wanted]\n .filter(([id]) => !have.has(id) && !asked.has(id))\n .sort((a, b) => Number(b[1]) - Number(a[1]))\n .slice(0, VERSION_BACK_IDS)\n .map(([id]) => id);\n if (missing.length === 0) break;\n for (const id of missing) asked.add(id);\n add(await queryEvents({ kinds: [CHANNEL_DESCRIPTOR_KIND], '#d': missing.map(versionDtag) }));\n }\n return {\n events: answeredEvents({ events: [...merged.values()], relayStatus: status }),\n truncated,\n incomplete,\n // Every read met the floor: only then can \"no newer version\" be said.\n floorMet,\n };\n}\n\n\nexport interface ChannelPost {\n post: PostContent;\n postId: string;\n event: NostrEvent;\n}\n\n/**\n * Deterministic public-feed order (§8.3.2). A public multi-author channel has no\n * single hash-chain (independent broadcasters), so order is the event-level\n * created_at as a DISPLAY hint, tie-broken by the content-addressed post_id so\n * two clients always agree. created_at is untrusted (a relay can backdate); the\n * post_id tiebreak makes the order at least stable + reproducible across clients.\n */\nexport function orderChannelPosts(posts: ChannelPost[]): ChannelPost[] {\n return [...posts].sort((a, b) => {\n const at = a.event.created_at - b.event.created_at;\n return at !== 0 ? at : a.postId < b.postId ? -1 : a.postId > b.postId ? 1 : 0;\n });\n}\n\n\n/**\n * The posts of a channel that verify against its resolved descriptor (§8.3.2):\n * each one authored by a bound key and through the write gate, removal\n * tombstones applied (forward-effective, §8.3.5), copies of one post_id kept\n * once at their lowest created_at, in feed order. A post that fails MUST NOT\n * render, so it is left out.\n */\nexport async function verifyChannelPosts(\n events: readonly NostrEvent[],\n descriptor: DescriptorContent,\n opts: Pick<VerifyPostOpts, 'tipHeight' | 'verifyBip322' | 'verifyOnChain'> & { isBound: IsBound }\n): Promise<ChannelPost[]> {\n const removed = new Set<string>();\n const byPostId = new Map<string, ChannelPost>();\n for (const ev of events) {\n const content = parsePost(ev);\n if (!content || content.channel_id !== descriptor.channel_id) continue;\n const controlSig = ev.tags.find((t) => t[0] === 'control_sig')?.[1];\n const v = await verifyPost(content, descriptor, {\n ...opts,\n event: ev,\n ...(controlSig ? { controlSig } : {}),\n });\n if (!v.ok) continue;\n if (v.isTombstone && content.removes) {\n removed.add(content.removes);\n continue;\n }\n const existing = byPostId.get(v.postId);\n if (!existing || ev.created_at < existing.event.created_at) {\n byPostId.set(v.postId, { post: content, postId: v.postId, event: ev });\n }\n }\n return orderChannelPosts([...byPostId.values()].filter((a) => !removed.has(a.postId)));\n}\n","[\n {\n \"note\": \"OC Chat 0.4 §8.2.8: the one v1 listing that carries a claim, anchored by the reference deployment.\",\n \"listing_event_id\": \"0f29b5859da8d5e1882f63a3a331679a8c35b865834239f9a993cc1d3ac045ec\",\n \"handle\": \"ochkroot\",\n \"address\": \"bc1pezn5yjxmz9nuahtqprvhfeya2nv4zdfk49u5amquhqptykx695rs60hqa2\",\n \"orangecheck\": true,\n \"outpoint\": \"bd20e0fb096e5bce89ec33f7cebe0c34e04e31d83db6de00551a6a86f12a00cd:0\",\n \"nonce\": \"9b2e4198ca4a243188ef76c46f31081ed69dcae9d7d60c9f82e7109faf7887bd\",\n \"claim_id\": \"80963cd5e12b76c3a08057957a48806631f3b0a4dcd8d82eb70cc587c30dc243\",\n \"ots\": \"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\"\n }\n]\n","// Who holds a handle under OC Chat 0.4 (SPEC §8.2.5–§8.2.6): the directory relays read\n// completely, public relays read as a bounded audit, and the walk itself from\n// @orangecheck/lock-core/directory, so every client and the directory relay decide alike.\n// Relays, the chain and the bindings are read through WalkDeps.\n\nimport {\n ANCHOR_CONFS,\n channelDirectoryDtag,\n directoryAnchor,\n directoryDtag,\n DIRECTORY_PARAMS,\n listingId,\n parseChannelDirectoryContent,\n parseDirectoryContent,\n repointId,\n resolveDirectory,\n sameAddress,\n type AnchorAnswer,\n type CoinFacts,\n type DirectoryRecord,\n type ParsedDirectoryContent,\n} from '@orangecheck/lock-core/directory';\nimport { hexDecode } from '@orangecheck/lock-crypto';\nimport type { NostrEvent } from '@orangecheck/lock-device';\nimport {\n base64Decode,\n bitcoinAnchors,\n parseProof,\n type BlockHeaderSource,\n} from '@orangecheck/stamp-ots';\n\nimport referenceLegacy from './directory-legacy.json';\n\nexport type DirectoryNamespace = 'people' | 'channel';\n\n/** The reference deployment's directory relay (§8.2.6), a named availability anchor. */\nexport const DIRECTORY_RELAYS: readonly string[] = ['wss://relay.ochk.io'];\n/** Public relays the reference deployment reads as the audit (§8.2.6). */\nexport const AUDIT_RELAYS: readonly string[] = [\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.primal.net',\n];\n\nconst PAGE = 200;\n/** A directory relay answering more pages than this has not been read completely. */\nconst MAX_DIRECTORY_PAGES = 25;\nconst AUDIT_PAGES = 2;\n/** Distinct header reads one resolution may make; past this a header is unread. */\nconst HEADER_BUDGET = 128;\n\n/** One page from one relay: its events, and whether the relay finished answering (EOSE). */\nexport type PageRead = (\n relay: string,\n filter: { kinds: number[]; '#d': string[]; limit: number; until?: number }\n) => Promise<{ events: NostrEvent[]; complete: boolean }>;\n\nexport interface WalkDeps {\n page: PageRead;\n tip(): Promise<number>;\n headers: BlockHeaderSource;\n coin(outpoint: string): Promise<CoinFacts | 'no-answer'>;\n /** The keys a kind-30078 device record binds to `address`, or 'no-answer'. */\n boundKeys(address: string): Promise<string[] | 'no-answer'>;\n /** NIP-01 id and signature. */\n verifyEvent(ev: NostrEvent): boolean;\n /** The deployment's directory relays; the reference deployment's by default. */\n directoryRelays?: readonly string[];\n /** The public relays read as the audit; the reference deployment's by default. */\n auditRelays?: readonly string[];\n /** §8.2.8 claims a deployment anchored for v1 listings; the reference deployment's by default. */\n legacy?: readonly LegacyClaim[];\n}\n\n/** A claim as a listing carries it (§8.2.1, §8.2.9). */\nexport interface CarriedClaim {\n outpoint: string;\n nonce: string;\n ots: string;\n repoints: { prev: string; outpoint: string; nonce: string; ots: string }[];\n}\n\n/** A record the walk took, with the event it came from. */\nexport interface WalkRecord {\n record: DirectoryRecord;\n event: NostrEvent;\n content: Record<string, unknown>;\n /** A listing's claim; for the §8.2.8 legacy listing, the shipped one. */\n claim: CarriedClaim | null;\n}\n\nexport type HandleAnswer =\n | {\n result: 'holds';\n holder: string;\n claimId: string;\n coin: string;\n /** The holder's state: its freshest listing signed by a bound key. */\n listing: { event: NostrEvent; content: Record<string, unknown> };\n /** The claim that state carries, re-points included. */\n claim: CarriedClaim;\n anchor: number;\n tip: number;\n }\n | { result: 'E_DIR_UNRESOLVED' | 'E_DIR_REVOKED' | 'E_DIR_UNVERIFIED' | 'not_found' };\n\n/** A claim a deployment anchored for one v1 listing (§8.2.8). */\nexport interface LegacyClaim {\n listing_event_id: string;\n handle: string;\n address: string;\n outpoint: string;\n nonce: string;\n claim_id: string;\n ots: string;\n /** orangecheck's own listing, which the reference client lets carry a name it reserves. */\n orangecheck?: true;\n}\n/** The reference deployment's §8.2.8 claims. */\nexport const REFERENCE_LEGACY_CLAIMS: readonly LegacyClaim[] = referenceLegacy as LegacyClaim[];\n\nconst legacyIndex = (entries: readonly LegacyClaim[]) =>\n new Map(entries.map((e) => [e.listing_event_id, e]));\n\n/** Every event a relay holds under one d tag, paged by `until`; null when the read is not complete. */\nasync function readAll(\n page: PageRead,\n relay: string,\n d: string,\n maxPages: number\n): Promise<NostrEvent[] | null> {\n const seen = new Map<string, NostrEvent>();\n let until: number | undefined;\n for (let i = 0; i < maxPages; i++) {\n const got = await page(relay, {\n kinds: [30114],\n '#d': [d],\n limit: PAGE,\n ...(until === undefined ? {} : { until }),\n });\n if (!got.complete) return null;\n let added = 0;\n for (const ev of got.events) {\n if (!seen.has(ev.id)) {\n seen.set(ev.id, ev);\n added++;\n }\n until = until === undefined ? ev.created_at : Math.min(until, ev.created_at);\n }\n // A short page is the end; a full page that adds nothing is a stalled read.\n if (got.events.length < PAGE) return [...seen.values()];\n if (added === 0) return null;\n }\n return null;\n}\n\n/** Up to `pages` pages of what an audit relay holds; whatever it answered, or nothing. */\nasync function readSome(\n page: PageRead,\n relay: string,\n d: string,\n pages: number\n): Promise<NostrEvent[]> {\n const seen = new Map<string, NostrEvent>();\n let until: number | undefined;\n for (let i = 0; i < pages; i++) {\n let got: { events: NostrEvent[]; complete: boolean };\n try {\n got = await page(relay, {\n kinds: [30114],\n '#d': [d],\n limit: PAGE,\n ...(until === undefined ? {} : { until }),\n });\n } catch {\n break;\n }\n for (const ev of got.events) {\n seen.set(ev.id, ev);\n until = until === undefined ? ev.created_at : Math.min(until, ev.created_at);\n }\n if (!got.complete || got.events.length < PAGE) break;\n }\n return [...seen.values()];\n}\n\n/** A header source that reads each height once and stops reading past the budget (a read without an answer). */\nfunction budgetedHeaders(source: BlockHeaderSource): BlockHeaderSource {\n const memo = new Map<number, Promise<Uint8Array | null>>();\n return {\n getHeaderAt(height) {\n const hit = memo.get(height);\n if (hit) return hit;\n if (memo.size >= HEADER_BUDGET) return Promise.reject(new Error('header budget spent'));\n const p = source.getHeaderAt(height);\n memo.set(height, p);\n return p;\n },\n };\n}\n\n/** Events by the lowest Bitcoin attestation their claim's proof names, read without a header; then by id. */\nfunction byClaimedAnchor(\n handle: string,\n ns: DirectoryNamespace,\n legacy: ReadonlyMap<string, LegacyClaim>\n) {\n const keyOf = new Map<string, number>();\n const claimed = (ev: NostrEvent) => {\n let k = keyOf.get(ev.id);\n if (k === undefined) {\n k = Infinity;\n try {\n const p = parseEvent(ev, handle, ns, legacy);\n if (p?.parsed.kind === 'listing' && p.ots) {\n const heights = bitcoinAnchors(\n parseProof(base64Decode(p.ots), hexDecode(p.parsed.claimId))\n ).map((a) => a.blockHeight);\n if (heights.length) k = Math.min(...heights);\n }\n } catch {\n /* an unreadable proof goes last */\n }\n keyOf.set(ev.id, k);\n }\n return k;\n };\n return (a: NostrEvent, b: NostrEvent) =>\n claimed(a) - claimed(b) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0);\n}\n\n/** The parsed record of one event, the §8.2.8 legacy entry included; null drops it in step 1. */\nfunction parseEvent(\n ev: NostrEvent,\n handle: string,\n ns: DirectoryNamespace,\n legacy: ReadonlyMap<string, LegacyClaim>\n): { parsed: ParsedDirectoryContent; content: Record<string, unknown>; ots: string | null } | null {\n let content: unknown;\n try {\n content = JSON.parse(ev.content);\n } catch {\n return null;\n }\n if (!content || typeof content !== 'object' || Array.isArray(content)) return null;\n const c = content as Record<string, unknown>;\n const legacyEntry = ns === 'people' ? legacy.get(ev.id) : undefined;\n if (legacyEntry && c.v === 1) {\n // Exactly this v1 listing carries the shipped claim, and only while its bytes are the ones anchored.\n if (listingId(c as never) !== legacyEntry.nonce || c.opted_in !== true) return null;\n if (c.handle !== handle.toLowerCase() || c.address !== legacyEntry.address) return null;\n if (typeof c.inbox_pubkey !== 'string') return null;\n return {\n parsed: {\n kind: 'listing',\n address: legacyEntry.address,\n inboxPubkey: c.inbox_pubkey,\n createdAt: typeof c.created_at === 'number' ? c.created_at : 0,\n claim: {\n outpoint: legacyEntry.outpoint,\n nonce: legacyEntry.nonce,\n ots: legacyEntry.ots,\n repoints: [],\n },\n claimId: legacyEntry.claim_id,\n },\n content: c,\n ots: legacyEntry.ots,\n };\n }\n const parsed =\n ns === 'people'\n ? parseDirectoryContent(c, handle)\n : parseChannelDirectoryContent(c, handle);\n if (!parsed) return null;\n return { parsed, content: c, ots: parsed.kind === 'listing' ? parsed.claim.ots : null };\n}\n\n/** The records one d tag holds, anchors computed, each tagged with where it was found. */\nasync function collect(\n handle: string,\n ns: DirectoryNamespace,\n deps: WalkDeps\n): Promise<{\n records: WalkRecord[];\n directoryAnswered: boolean;\n tip: number;\n seen: number;\n} | null> {\n const d = ns === 'people' ? directoryDtag(handle) : channelDirectoryDtag(handle);\n const [directoryReads, auditReads, tip] = await Promise.all([\n Promise.all(\n (deps.directoryRelays ?? DIRECTORY_RELAYS).map((r) =>\n readAll(deps.page, r, d, MAX_DIRECTORY_PAGES).catch(() => null)\n )\n ),\n Promise.all(\n (deps.auditRelays ?? AUDIT_RELAYS).map((r) => readSome(deps.page, r, d, AUDIT_PAGES))\n ),\n deps.tip().catch(() => null),\n ]);\n if (tip === null) return null;\n const directoryAnswered = directoryReads.some((r) => r !== null);\n const onDirectory = new Set(directoryReads.flatMap((r) => r ?? []).map((e) => e.id));\n const all = new Map<string, NostrEvent>();\n for (const ev of [...directoryReads.flatMap((r) => r ?? []), ...auditReads.flat()])\n all.set(ev.id, ev);\n\n const headers = budgetedHeaders(deps.headers);\n const out: WalkRecord[] = [];\n // The header budget goes to the directory relay's records first, so public records\n // never turn its answer into E_DIR_UNRESOLVED (§8.2.6); then lowest claimed anchor\n // first, so no relay's answer order decides which claims are read.\n const legacy = legacyIndex(deps.legacy ?? REFERENCE_LEGACY_CLAIMS);\n const byAnchor = byClaimedAnchor(handle, ns, legacy);\n const order = (a: NostrEvent, b: NostrEvent) =>\n Number(!onDirectory.has(a.id)) - Number(!onDirectory.has(b.id)) || byAnchor(a, b);\n for (const ev of [...all.values()].sort(order)) {\n if (ev.kind !== 30114 || !deps.verifyEvent(ev)) continue;\n const p = parseEvent(ev, handle, ns, legacy);\n if (!p) continue;\n const { parsed, content } = p;\n // With no directory relay answering, the public read is the walk itself (§8.2.6).\n const source = !directoryAnswered || onDirectory.has(ev.id) ? 'directory' : 'public';\n if (parsed.kind === 'tombstone') {\n out.push({\n record: {\n kind: 'tombstone',\n address: parsed.address,\n key: ev.pubkey,\n createdAt: parsed.createdAt,\n ends: parsed.ends,\n source,\n },\n event: ev,\n content,\n claim: null,\n });\n continue;\n }\n // A listing is signed by its inbox key (§8.2.2 (1)).\n if (ev.pubkey !== parsed.inboxPubkey) continue;\n const anchor: AnchorAnswer = await directoryAnchor(\n parsed.claim.ots,\n parsed.claimId,\n headers\n );\n const repoints = [];\n for (const r of parsed.claim.repoints) {\n const id = repointId({\n claim: parsed.claimId,\n prev: r.prev,\n outpoint: r.outpoint,\n nonce: r.nonce,\n });\n repoints.push({\n repointId: id,\n prev: r.prev,\n outpoint: r.outpoint,\n anchor: await directoryAnchor(r.ots, id, headers),\n });\n }\n out.push({\n record: {\n kind: 'listing',\n address: parsed.address,\n key: ev.pubkey,\n createdAt: parsed.createdAt,\n claimId: parsed.claimId,\n outpoint: parsed.claim.outpoint,\n anchor,\n repoints,\n source,\n },\n event: ev,\n content,\n claim: parsed.claim,\n });\n }\n return { records: out, directoryAnswered, tip, seen: all.size };\n}\n\n/** A listing whose anchor has 6 confirmations at `tip`: only these, and tombstones, are states (§8.2.5 (3)). */\nfunction keptAt(tip: number) {\n return (r: WalkRecord) => {\n if (r.record.kind === 'tombstone') return true;\n const a = r.record.anchor;\n const h = a === null ? null : typeof a === 'number' ? a : a.unread;\n return h !== null && tip - h + 1 >= ANCHOR_CONFS;\n };\n}\n\n/** The freshest of `records` by `created_at`. */\nfunction freshest(records: readonly WalkRecord[]): WalkRecord | null {\n return records.reduce<WalkRecord | null>(\n (best, r) => (!best || r.record.createdAt > best.record.createdAt ? r : best),\n null\n );\n}\n\nexport type AddressState =\n | {\n kind: 'listing';\n event: NostrEvent;\n content: Record<string, unknown>;\n claimId: string;\n claim: CarriedClaim;\n }\n | { kind: 'tombstone'; event: NostrEvent; ends: string }\n | { kind: 'none' }\n | { kind: 'unresolved' };\n\ntype Collected = NonNullable<Awaited<ReturnType<typeof collect>>>;\n\n/** One address's state among collected records: its freshest kept record signed by a bound key. */\nasync function stateOf(got: Collected, address: string, deps: WalkDeps): Promise<AddressState> {\n const mine = got.records.filter((r) => sameAddress(r.record.address, address));\n if (mine.length === 0) return got.directoryAnswered ? { kind: 'none' } : { kind: 'unresolved' };\n const keys = await deps.boundKeys(address);\n if (keys === 'no-answer') return { kind: 'unresolved' };\n const state = freshest(mine.filter((r) => keys.includes(r.record.key)).filter(keptAt(got.tip)));\n if (!state) return got.directoryAnswered ? { kind: 'none' } : { kind: 'unresolved' };\n if (state.record.kind === 'tombstone')\n return { kind: 'tombstone', event: state.event, ends: state.record.ends };\n if (!state.claim) return { kind: 'unresolved' };\n return {\n kind: 'listing',\n event: state.event,\n content: state.content,\n claimId: state.record.claimId,\n claim: state.claim,\n };\n}\n\n/**\n * One address's own state under `handle` (§8.2.5 (3)): its freshest record signed by a\n * key bound to it, among the records step 1 keeps. A client reads this before it\n * publishes for the address, so it carries the claim's re-points (§8.2.7).\n */\nexport async function readAddressState(\n handle: string,\n ns: DirectoryNamespace,\n address: string,\n deps: WalkDeps\n): Promise<AddressState> {\n try {\n const got = await collect(handle, ns, deps);\n return got ? await stateOf(got, address, deps) : { kind: 'unresolved' };\n } catch {\n return { kind: 'unresolved' };\n }\n}\n\n/** Who holds `handle`, and `address`'s own state under it, from one read of the relays. */\nexport async function resolveWithState(\n handle: string,\n ns: DirectoryNamespace,\n address: string,\n deps: WalkDeps\n): Promise<{ answer: HandleAnswer; state: AddressState }> {\n const unresolved = {\n answer: { result: 'E_DIR_UNRESOLVED' as const },\n state: { kind: 'unresolved' as const },\n };\n try {\n const got = await collect(handle, ns, deps);\n if (!got) return unresolved;\n const memo = new Map<string, Promise<string[] | 'no-answer'>>();\n const once: WalkDeps = {\n ...deps,\n boundKeys: (a) => {\n if (!memo.has(a)) memo.set(a, deps.boundKeys(a));\n return memo.get(a)!;\n },\n };\n return { answer: await walkCollected(got, once), state: await stateOf(got, address, once) };\n } catch {\n return unresolved;\n }\n}\n\n/** Who holds `handle` in namespace `ns`, by the 0.4 walk. Never throws. */\nexport async function resolveDirectoryHandle(\n handle: string,\n ns: DirectoryNamespace,\n deps: WalkDeps\n): Promise<HandleAnswer> {\n try {\n const got = await collect(handle, ns, deps);\n return got ? await walkCollected(got, deps) : { result: 'E_DIR_UNRESOLVED' };\n } catch {\n return { result: 'E_DIR_UNRESOLVED' };\n }\n}\n\nasync function walkCollected(got: Collected, deps: WalkDeps): Promise<HandleAnswer> {\n const { records, directoryAnswered, tip, seen } = got;\n // Nothing at all under the d tag is \"not listed\", but only when the directory relay answered in full.\n if (seen === 0)\n return directoryAnswered ? { result: 'not_found' } : { result: 'E_DIR_UNRESOLVED' };\n\n const bound = new Map<string, string[]>();\n const params = directoryAnswered\n ? DIRECTORY_PARAMS\n : {\n ...DIRECTORY_PARAMS,\n // §8.2.6: with no directory relay answering, the audit's bounds bound the walk.\n bounds: {\n bindingReads: DIRECTORY_PARAMS.bounds.auditBindingReads,\n coinReads: DIRECTORY_PARAMS.bounds.auditCoinReads,\n auditBindingReads: DIRECTORY_PARAMS.bounds.auditBindingReads,\n auditCoinReads: DIRECTORY_PARAMS.bounds.auditCoinReads,\n },\n };\n const out = await resolveDirectory(\n records.map((r) => r.record),\n tip,\n {\n boundKeys: async (address) => {\n const keys = await deps.boundKeys(address);\n if (keys !== 'no-answer') bound.set(address, keys);\n return keys;\n },\n coin: (outpoint) => deps.coin(outpoint),\n },\n params\n );\n if (out.result !== 'holds') return { result: out.result };\n // The holder's state: its freshest listing signed by a bound key that the walk kept (§8.2.5 (3)).\n const keys = bound.get(out.holder) ?? [];\n const carrying = records.filter(\n (r) =>\n r.record.kind === 'listing' &&\n r.record.address === out.holder &&\n r.record.claimId === out.claimId &&\n keptAt(tip)(r)\n );\n const state = freshest(carrying.filter((r) => keys.includes(r.record.key)));\n // The claim's place is its lowest anchor among the copies, as the walk ordered it.\n const anchors = carrying\n .map((r) => (r.record.kind === 'listing' ? r.record.anchor : null))\n .filter((a): a is number => typeof a === 'number');\n if (!state || !state.claim || anchors.length === 0) return { result: 'E_DIR_UNRESOLVED' };\n const anchor = Math.min(...anchors);\n return {\n result: 'holds',\n holder: out.holder,\n claimId: out.claimId,\n coin: out.coin,\n listing: { event: state.event, content: state.content },\n claim: state.claim,\n anchor,\n tip,\n };\n}\n\nconst HANDLE_RE = /^[a-z0-9_]{3,32}$/;\n\n/** A handle's shape (§8.2.1): 3 to 32 of a-z, 0-9 and _. */\nexport function isValidHandle(h: string): boolean {\n return HANDLE_RE.test(h);\n}\n\nconst AVATAR_MAX_CHARS = 24 * 1024;\nconst AVATAR_DATA_URL_RE = /^data:image\\/(?:png|jpe?g|webp|gif);base64,[A-Za-z0-9+/=]+$/;\n\n/** A listing's avatar is safe to render iff it is a bounded raster data URL (§8.2.1):\n * never an svg, html or script data URL, and never huge. */\nexport function safeAvatar(s: unknown): s is string {\n return typeof s === 'string' && s.length <= AVATAR_MAX_CHARS && AVATAR_DATA_URL_RE.test(s);\n}\n","// Who a principal's kind-30078 records bind, from the records a relay holds:\n// OC Lock's rule for a Bitcoin address (@orangecheck/lock-device), §8.6 for a\n// did:oc. The caller looks the records up; these answer from them.\n\nimport { isDidOc } from '@orangecheck/auth-core/identifiers';\nimport {\n authorizedDevices,\n boundNostrKeys,\n verifyDeviceRecords,\n type NostrEvent,\n type ParsedDeviceEvent,\n} from '@orangecheck/lock-device';\n\nimport type { IsBound } from './channel';\nimport { verifyNostrEvent } from './event';\nimport { completeAnswers, meetsReadFloor, readFloor, UnansweredReadError, type VerifyBip322 } from './read';\nimport { liveSessionDevices, sessionDeviceDtag, sessionKeysEverBound, type AuthHostKey } from './session';\nimport { btcBindingLive, sessionBindingRevoked, type Liveness, type VersionBinding } from './version-binding';\n\nexport { isDidOc };\n\n/** The d-tag a Bitcoin address's device records are published under (OC Lock SPEC §3). */\nexport function addressDeviceDtag(address: string): string {\n return `oc-lock:device:${address}`;\n}\n\n/** The d-tag a principal's device records are published under: an address's, or a did:oc's session records. */\nexport function deviceDtag(principal: string): string {\n return isDidOc(principal) ? sessionDeviceDtag(principal) : addressDeviceDtag(principal);\n}\n\n/**\n * Every inbox key an address's verified records have bound, revoked ones too\n * (§8.3.1): an earlier channel version stands on its binding whatever became\n * of the key since. A device's own revocation replaces its bind record at the\n * relay, so for a device no bind record of which remains, the key that carried\n * its revocation counts. A revocation carried by a fresh key adds nothing.\n */\nexport function addressKeysEverBound(verified: readonly ParsedDeviceEvent[], now: Date = new Date()): string[] {\n const binds = verified.filter((p) => !p.revoked);\n const boundIds = new Set(binds.map((p) => p.device_id));\n const replaced = verified.filter((p) => p.revoked && !boundIds.has(p.device_id)).map((p) => p.nostrPubkey);\n return [...new Set([...authorizedDevices(binds, { now }).map((d) => d.nostrPubkey), ...replaced])];\n}\n\n/**\n * The kind-30078 records the relays hold under a principal's d-tag, and per relay\n * asked whether it finished answering (EOSE). A record seen on any relay counts.\n * A conclusion that rests on a record not being there needs the read floor\n * (§8.7, `meetsReadFloor`): \"bound now\" and \"live\" (no revocation seen), and\n * \"not bound\". Below it those are not read.\n */\nexport type RecordLookup = (\n principal: string\n) => Promise<{ events: NostrEvent[]; relayStatus: readonly { eose: boolean }[] }>;\n\nexport interface RecordReadOptions {\n /** The auth host's published keys, retired ones included (§8.6). Read only for a did:oc. */\n hostKeys: () => Promise<readonly AuthHostKey[]>;\n verifyBip322: VerifyBip322;\n /** The reader's clock. */\n now?: () => Date;\n}\n\n/** The binding reads a resolver needs, answered from looked-up records. */\nexport interface RecordReads {\n /** The keys a principal's records bind now, or 'no-answer' when the read is below the floor. */\n boundKeys(principal: string): Promise<string[] | 'no-answer'>;\n /** Throws UnansweredReadError when the read is below the floor: \"bound now\" and\n * \"not bound\" both rest on what was not seen. */\n isBound: IsBound;\n liveness(b: VersionBinding): Promise<Liveness>;\n everBoundKeys(principal: string): Promise<{ keys: string[]; answered: boolean; floor: boolean }>;\n}\n\n/** Binding reads over `lookup`, one lookup per principal for the life of the object. */\nexport function recordReads(lookup: RecordLookup, opts: RecordReadOptions): RecordReads {\n const now = () => (opts.now ? opts.now() : new Date());\n const looked = new Map<string, ReturnType<RecordLookup>>();\n const records = (p: string) => {\n if (!looked.has(p)) looked.set(p, lookup(p));\n return looked.get(p)!;\n };\n // What one read of a principal's records allows: anything it returned, once a\n // relay answered; what it did not return, only at the floor.\n const read = async (p: string) => {\n const { events, relayStatus } = await records(p);\n return { events, answered: completeAnswers(relayStatus) > 0, floor: meetsReadFloor(relayStatus), asked: relayStatus.length };\n };\n const verified = async (address: string) => {\n const { events, answered, floor } = await read(address);\n return {\n answered,\n floor,\n verified: await verifyDeviceRecords(events, address, { verifyBip322: opts.verifyBip322 }),\n };\n };\n const sessionEvents = async (didOc: string) => {\n const { events, answered, floor } = await read(didOc);\n // Only records signed by the key they name count for anything (§8.6).\n return { answered, floor, events: events.filter(verifyNostrEvent) };\n };\n // Which keys are bound now rests on no revocation being seen: the read must meet the floor.\n const boundKeys = async (principal: string): Promise<string[] | 'no-answer'> => {\n if (isDidOc(principal)) {\n const { events, floor } = await sessionEvents(principal);\n if (!floor) return 'no-answer';\n const keys = events.length > 0 ? await opts.hostKeys() : [];\n return liveSessionDevices(events, principal, keys).map((d) => d.nostrPubkey);\n }\n const v = await verified(principal);\n if (!v.floor) return 'no-answer';\n return boundNostrKeys(v.verified, { now: now() });\n };\n return {\n boundKeys,\n async isBound(pubkey, principal) {\n const keys = await boundKeys(principal);\n if (keys === 'no-answer') {\n const { answered, asked } = await read(principal);\n throw new UnansweredReadError(\n answered\n ? `fewer than ${readFloor(asked)} of ${asked} relays answered, so a record that binds or revokes this key may not have been seen`\n : undefined\n );\n }\n return keys.includes(pubkey);\n },\n // A revocation seen settles 'revoked' on any answer; 'live' rests on none being\n // seen, so it needs the floor.\n async liveness(b) {\n if (b.kind === 'btc') {\n const v = await verified(b.principal);\n if (!v.answered) return 'unknown';\n if (!btcBindingLive(b, v.verified, now())) return 'revoked';\n return v.floor ? 'live' : 'unknown';\n }\n const { events, answered, floor } = await sessionEvents(b.principal);\n if (!answered) return 'unknown';\n const keys = await opts.hostKeys();\n if (keys.length === 0) return 'unknown';\n if (sessionBindingRevoked(b, events, keys)) return 'revoked';\n return floor ? 'live' : 'unknown';\n },\n async everBoundKeys(principal) {\n if (isDidOc(principal)) {\n const { events, answered, floor } = await sessionEvents(principal);\n const keys = events.length > 0 ? await opts.hostKeys() : [];\n return { keys: sessionKeysEverBound(events, principal, keys), answered, floor };\n }\n const v = await verified(principal);\n return { keys: addressKeysEverBound(v.verified, now()), answered: v.answered, floor: v.floor };\n },\n };\n}\n\n/**\n * The Bitcoin address a session message's signing key steps up to (§8.6), or\n * null: of the addresses named by the OC Lock device records `nostrPk` itself\n * published (`authored`), the lexicographically smallest that binds it.\n */\nexport async function stepUpAddress(\n nostrPk: string,\n authored: readonly NostrEvent[],\n isBound: IsBound\n): Promise<string | null> {\n const prefix = addressDeviceDtag('');\n const candidates = new Set<string>();\n for (const e of authored) {\n if (e.kind !== 30078 || e.pubkey !== nostrPk || !verifyNostrEvent(e)) continue;\n const d = e.tags.find((t) => t[0] === 'd')?.[1] ?? '';\n if (!d.startsWith(prefix)) continue;\n const address = d.slice(prefix.length);\n if (address && !isDidOc(address)) candidates.add(address);\n }\n for (const address of [...candidates].sort()) {\n if (await isBound(nostrPk, address)) return address;\n }\n return null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/attachment.ts","../src/canonical.ts","../src/event.ts","../src/session.ts","../src/version-binding.ts","../src/channel.ts","../src/directory-legacy.json","../src/directory.ts","../src/records.ts"],"names":["utf8Encode","p","key","curId","best","c","keys","authorizedDevices"],"mappings":";;;;;;;;;;;;;AAeO,IAAM,uBAAuB,GAAA,GAAM;AAInC,SAAS,kBAAkB,CAAA,EAA6B;AAC3D,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,UAAU,OAAO,KAAA;AACxC,EAAA,MAAM,CAAA,GAAI,CAAA;AACV,EAAA,IAAI,OAAO,EAAE,IAAA,KAAS,QAAA,IAAY,OAAO,CAAA,CAAE,IAAA,KAAS,UAAU,OAAO,KAAA;AACrE,EAAA,IAAI,OAAO,CAAA,CAAE,IAAA,KAAS,QAAA,IAAY,EAAE,CAAA,CAAE,IAAA,IAAQ,CAAA,IAAK,CAAA,CAAE,IAAA,IAAQ,oBAAA,CAAA,EAAuB,OAAO,KAAA;AAC3F,EAAA,IAAI,OAAO,CAAA,CAAE,IAAA,KAAS,QAAA,EAAU,OAAO,KAAA;AACvC,EAAA,IAAI,CAAA,CAAE,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,IAAA,CAAM,uBAAuB,CAAA,GAAK,CAAC,CAAA,GAAI,CAAA,EAAG,OAAO,KAAA;AAE1E,EAAA,IAAI;AACA,IAAA,IAAI,KAAK,CAAA,CAAE,IAAI,CAAA,CAAE,MAAA,GAAS,sBAAsB,OAAO,KAAA;AAAA,EAC3D,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,KAAA;AAAA,EACX;AACA,EAAA,OAAO,IAAA;AACX;AC5BO,SAAS,eAAe,KAAA,EAA4B;AACvD,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAAwB;AAClC,IAAA,IAAI,MAAM,OAAA,CAAQ,CAAC,GAAG,OAAO,CAAA,CAAE,IAAI,IAAI,CAAA;AACvC,IAAA,IAAI,CAAA,IAAK,OAAO,CAAA,KAAM,QAAA,EAAU;AAC5B,MAAA,MAAM,MAA+B,EAAC;AACtC,MAAA,KAAA,MAAW,KAAK,MAAA,CAAO,IAAA,CAAK,CAA4B,CAAA,CAAE,MAAK,EAAG;AAC9D,QAAA,GAAA,CAAI,CAAC,CAAA,GAAI,IAAA,CAAM,CAAA,CAA8B,CAAC,CAAC,CAAA;AAAA,MACnD;AACA,MAAA,OAAO,GAAA;AAAA,IACX;AACA,IAAA,OAAO,CAAA;AAAA,EACX,CAAA;AACA,EAAA,OAAO,WAAW,IAAA,CAAK,SAAA,CAAU,KAAK,KAAK,CAAC,IAAI,IAAI,CAAA;AACxD;AAGO,SAAS,YAAY,KAAA,EAA2B;AACnD,EAAA,OAAO,YAAA,CAAa,KAAK,CAAA,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AAChD;ACjBO,SAAS,QAAA,CAAS,IAAgB,MAAA,EAAyB;AAC9D,EAAA,OAAO,EAAA,CAAG,MAAA,KAAW,MAAA,IAAU,gBAAA,CAAiB,EAAE,CAAA;AACtD;ACQO,IAAM,kBAAA,GAAqB;AAC3B,IAAM,aAAA,GAAgB;AACtB,IAAM,kBAAA,GAAqB;AAG3B,SAAS,kBAAkB,KAAA,EAAuB;AACrD,EAAA,OAAO,kBAAkB,KAAK,CAAA,CAAA;AAClC;AAmBA,SAAS,MAAA,CAAO,IAAY,CAAA,EAA2B;AACnD,EAAA,OAAO;AAAA,IACH,EAAA;AAAA,IACA,CAAA,QAAA,EAAW,EAAE,KAAK,CAAA,CAAA;AAAA,IAClB,CAAA,WAAA,EAAc,EAAE,SAAS,CAAA,CAAA;AAAA,IACzB,CAAA,UAAA,EAAa,EAAE,QAAQ,CAAA,CAAA;AAAA,IACvB,CAAA,WAAA,EAAc,EAAE,SAAS,CAAA;AAAA,GAC7B;AACJ;AAGO,SAAS,sBAAsB,CAAA,EAAyB;AAC3D,EAAA,OAAO,OAAO,iCAAA,EAAmC,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,GAAI,IAAA;AACrE;AAEA,SAAS,aAAa,CAAA,EAAuB;AACzC,EAAA,MAAM,GAAA,GAAM,EAAE,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAM,GAAG,CAAA;AAClD,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,MAAA,GAAS,CAAA,KAAM,CAAA,GAAI,EAAA,GAAK,GAAA,CAAI,MAAA,CAAO,CAAA,GAAK,GAAA,CAAI,MAAA,GAAS,CAAE,CAAA;AACvE,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,GAAM,GAAG,CAAA;AAC1B,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,GAAA,CAAI,MAAM,CAAA;AACrC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,CAAA,EAAA,EAAK,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA,CAAI,UAAA,CAAW,CAAC,CAAA;AAC9D,EAAA,OAAO,GAAA;AACX;AAOA,SAAS,aAAA,CACL,GAAA,EACA,GAAA,EACA,SAAA,EACA,IAAA,EACe;AACf,EAAA,IAAI;AACA,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAC3B,IAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAC/B,IAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,GAAI,KAAA;AACpB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,WAAA,GAAc,MAAA,CAAO,YAAA,CAAa,CAAC,CAAC,CAAC,CAAA;AAInE,IAAA,IAAI,OAAO,GAAA,KAAQ,OAAA,IAAW,MAAA,CAAO,GAAA,KAAQ,KAAK,OAAO,IAAA;AACzD,IAAA,MAAM,MAAM,IAAA,CAAK,IAAA;AAAA,MACb,CAAC,CAAA,KAAM,CAAA,CAAE,GAAA,KAAQ,KAAA,IAAS,CAAA,CAAE,GAAA,KAAQ,SAAA,IAAa,CAAA,CAAE,CAAA,IAAK,CAAA,CAAE,GAAA,KAAQ,MAAA,CAAO;AAAA,KAC7E;AACA,IAAA,IAAI,CAAC,GAAA,EAAK,CAAA,EAAG,OAAO,IAAA;AACpB,IAAA,IAAI,CAAC,OAAA,CAAQ,MAAA,CAAO,YAAA,CAAa,GAAG,GAAGA,UAAAA,CAAW,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA,EAAG,aAAa,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG;AAClF,MAAA,OAAO,IAAA;AAAA,IACX;AACA,IAAA,MAAM,KAAA,GAAQ,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,aAAa,CAAC,CAAC,CAAA,CAAE,KAAA,CAAM,IAAI,CAAA;AAClE,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,EAAE,UAAA,CAAW,CAAA,EAAG,SAAS,CAAA,EAAA,CAAI,CAAC,CAAA;AAC3D,IAAA,MAAM,CAAA,GAAI,KAAK,MAAA,CAAO,EAAA,CAAG,MAAM,SAAA,CAAU,MAAA,GAAS,CAAC,CAAC,CAAA,GAAI,GAAA;AACxD,IAAA,IAAI,CAAC,OAAA,CAAQ,IAAA,CAAK,EAAA,EAAI,KAAA,CAAM,SAAA,CAAU,MAAA,GAAS,CAAC,CAAA,IAAK,EAAE,CAAA,EAAG,OAAO,IAAA;AACjE,IAAA,IACI,GAAA,CAAI,MAAA,KAAW,SAAA,IACf,EAAE,OAAO,IAAI,UAAA,KAAe,QAAA,IAAY,CAAA,GAAI,GAAA,CAAI,UAAA,CAAA,EAClD;AACE,MAAA,OAAO,IAAA;AAAA,IACX;AACA,IAAA,OAAO,KAAA;AAAA,EACX,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,IAAA;AAAA,EACX;AACJ;AAQO,SAAS,kBAAA,CACZ,KAAA,EACA,OAAA,EACA,IAAA,EACO;AACP,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,KAAA,EAAO,aAAA,EAAe,aAAa,IAAI,CAAA;AACnE,EAAA,IAAI,CAAC,OAAO,OAAO,KAAA;AACnB,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,yBAAA,EAA2B,OAAO,CAAA;AAE1D,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,QAAA,CAAS,MAAA,GAAS,GAAG,OAAO,KAAA;AACjD,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,MAAA,EAAQ,CAAA,EAAA,EAAK,IAAI,KAAA,CAAM,CAAC,CAAA,KAAM,QAAA,CAAS,CAAC,GAAG,OAAO,KAAA;AAC/E,EAAA,OAAO,kBAAA,CAAmB,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,MAAM,CAAE,CAAA,IAAK,KAAA,CAAM,EAAA,CAAG,EAAE,CAAA,KAAM,EAAA;AAChF;AAGO,SAAS,oBAAA,CACZ,KACA,IAAA,EAOK;AACL,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,GAAA,EAAK,kBAAA,EAAoB,cAAc,IAAI,CAAA;AACvE,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,CAAC,CAAA,KAAM,0BAAA,IAA8B,KAAA,CAAM,EAAA,CAAG,EAAE,CAAA,KAAM,EAAA,EAAI,OAAO,IAAA;AAGrF,EAAA,MAAM,KAAA,GAAQ,CAAC,IAAA,KAAiB;AAC5B,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,EAAE,UAAA,CAAW,CAAA,EAAG,IAAI,CAAA,EAAA,CAAI,CAAC,CAAA;AAC3D,IAAA,OAAO,KAAA,CAAM,MAAA,KAAW,CAAA,GAAI,KAAA,CAAM,CAAC,EAAG,KAAA,CAAM,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA,GAAI,IAAA;AAAA,EACnE,CAAA;AACA,EAAA,MAAM,KAAA,GAAQ,MAAM,QAAQ,CAAA;AAC5B,EAAA,MAAM,SAAA,GAAY,MAAM,WAAW,CAAA;AACnC,EAAA,MAAM,QAAA,GAAW,MAAM,UAAU,CAAA;AACjC,EAAA,MAAM,EAAA,GAAK,MAAM,YAAY,CAAA;AAC7B,EAAA,MAAM,UAAA,GAAa,EAAA,KAAO,IAAA,GAAO,GAAA,GAAM,OAAO,EAAE,CAAA;AAChD,EAAA,IAAI,CAAC,KAAA,IAAS,CAAC,SAAA,IAAa,CAAC,QAAA,IAAY,CAAC,MAAA,CAAO,QAAA,CAAS,UAAU,CAAA,EAAG,OAAO,IAAA;AAC9E,EAAA,OAAO,EAAE,OAAO,SAAA,EAAW,QAAA,EAAU,YAAY,SAAA,EAAW,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,EAAE;AACjF;AAGO,SAAS,cAAc,KAAA,EAA8B;AACxD,EAAA,IAAI;AACA,IAAA,MAAM,IAAI,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,IAAK,EAAA;AACjC,IAAA,MAAM,OAAO,IAAI,WAAA,GACZ,MAAA,CAAO,YAAA,CAAa,CAAC,CAAC,CAAA,CACtB,KAAA,CAAM,IAAI,EACV,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,UAAA,CAAW,aAAa,CAAC,CAAA;AAC5C,IAAA,MAAM,CAAA,GAAI,OAAO,MAAA,CAAO,IAAA,CAAK,MAAM,aAAA,CAAc,MAAM,CAAC,CAAA,GAAI,GAAA;AAC5D,IAAA,OAAO,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,GAAI,CAAA,GAAI,IAAA;AAAA,EACpC,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,IAAA;AAAA,EACX;AACJ;AAsBO,SAAS,wBAAwB,KAAA,EAA6C;AACjF,EAAA,IAAI,KAAA,CAAM,SAAS,WAAA,EAAa;AAC5B,IAAA,MAAM,IAAI,MAAM,oCAAoC,CAAA;AAAA,EACxD;AACA,EAAA,MAAM,GAAA,GAAM,CAAC,IAAA,KAAgC;AACzC,IAAA,KAAA,MAAW,CAAA,IAAK,MAAM,IAAA,EAAM;AACxB,MAAA,IAAI,CAAA,CAAE,CAAC,CAAA,KAAM,IAAA,IAAQ,CAAA,CAAE,SAAS,CAAA,EAAG,OAAO,CAAA,CAAE,CAAC,CAAA,IAAK,IAAA;AAAA,IACtD;AACA,IAAA,OAAO,IAAA;AAAA,EACX,CAAA;AACA,EAAA,MAAM,KAAA,GAAQ,IAAI,MAAM,CAAA;AACxB,EAAA,MAAM,SAAA,GAAY,IAAI,WAAW,CAAA;AACjC,EAAA,MAAM,SAAA,GAAY,IAAI,WAAW,CAAA;AACjC,EAAA,IAAI,CAAC,KAAA,IAAS,CAAC,SAAA,IAAa,CAAC,SAAA,EAAW;AACpC,IAAA,MAAM,IAAI,MAAM,4CAA4C,CAAA;AAAA,EAChE;AACA,EAAA,IAAI,GAAA,CAAI,MAAM,CAAA,KAAM,SAAA,EAAW;AAC3B,IAAA,MAAM,IAAI,MAAM,gDAAgD,CAAA;AAAA,EACpE;AACA,EAAA,OAAO;AAAA,IACH,KAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,kBAAkB,KAAA,CAAM,OAAA;AAAA,IACxB,SAAS,SAAA,KAAc,SAAA;AAAA,IACvB,eAAe,KAAA,CAAM,UAAA;AAAA,IACrB,aAAa,KAAA,CAAM,MAAA;AAAA,IACnB,SAAS,KAAA,CAAM,EAAA;AAAA,IACf,KAAA,EAAO,IAAI,OAAO;AAAA,GACtB;AACJ;AAYO,SAAS,kBAAA,CACZ,MAAA,EACA,KAAA,EACA,QAAA,EACkB;AAClB,EAAA,MAAM,GAAA,GAA0B,EAAE,IAAA,kBAAM,IAAI,GAAA,EAAI,EAAG,IAAA,kBAAM,IAAI,GAAA,EAAI,EAAG,SAAA,kBAAW,IAAI,KAAI,EAAE;AACzF,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACpB,IAAA,IAAI,CAAC,gBAAA,CAAiB,CAAC,CAAA,EAAG;AAC1B,IAAA,MAAM,GAAA,GAAM,CAAC,IAAA,KAAiB,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,CAAA,KAAM,IAAI,IAAI,CAAC,CAAA;AACnE,IAAA,MAAM,GAAA,GAAM,IAAI,YAAY,CAAA;AAC5B,IAAA,IAAI,GAAA,EAAK;AAIL,MAAA,MAAM,CAAA,GAAI,oBAAA,CAAqB,GAAA,EAAK,QAAQ,CAAA;AAC5C,MAAA,IACI,KACA,CAAA,CAAE,SAAA,KAAc,CAAA,CAAE,OAAA,IAClB,EAAE,KAAA,KAAU,KAAA,IACZ,GAAA,CAAI,GAAG,MAAM,CAAA,eAAA,EAAkB,KAAK,MACpC,GAAA,CAAI,MAAM,MAAM,KAAA,EAClB;AACE,QAAA,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,SAAA,EAAW,KAAK,GAAA,CAAI,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,EAAE,SAAS,CAAA,IAAK,EAAA,EAAI,CAAA,CAAE,UAAU,CAAC,CAAA;AACjF,QAAA,GAAA,CAAI,SAAA,CAAU,GAAA,CAAI,CAAA,CAAE,QAAQ,CAAA;AAAA,MAChC;AACA,MAAA;AAAA,IACJ;AACA,IAAA,IAAI;AACA,MAAA,MAAM,CAAA,GAAI,wBAAwB,CAAC,CAAA;AACnC,MAAA,IAAI,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,KAAA,KAAU,OAAO,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,SAAS,CAAA,CAAE,CAAA;AAAA,IACjF,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACJ;AACA,EAAA,OAAO,GAAA;AACX;AAIO,SAAS,oBAAA,CACZ,GACA,IAAA,EACO;AACP,EAAA,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,CAAA,CAAE,WAAW,CAAA,CAAA,EAAI,CAAA,CAAE,SAAS,CAAA,CAAE,CAAA,EAAG,OAAO,IAAA;AAC7D,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,EAAE,SAAS,CAAA;AACpC,EAAA,OAAO,OAAO,MAAA,KAAc,CAAA,CAAE,QAAA,KAAa,IAAA,IAAQ,EAAE,QAAA,IAAY,EAAA,CAAA;AACrE;AAGO,SAAS,qBAAA,CACZ,MAAA,EACA,KAAA,EACA,QAAA,EAC0B;AAC1B,EAAA,MAAM,MAAkC,EAAC;AACzC,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACpB,IAAA,IAAI;AACA,MAAA,MAAM,CAAA,GAAI,wBAAwB,CAAC,CAAA;AACnC,MAAA,IAAI,EAAE,OAAA,EAAS;AACf,MAAA,IAAI,CAAA,CAAE,UAAU,KAAA,EAAO;AACvB,MAAA,IAAI,CAAC,gBAAA,CAAiB,CAAC,CAAA,EAAG;AAE1B,MAAA,IACI,CAAC,CAAA,CAAE,KAAA,IACH,CAAC,kBAAA;AAAA,QACG,CAAA,CAAE,KAAA;AAAA,QACF;AAAA,UACI,KAAA;AAAA,UACA,WAAW,CAAA,CAAE,SAAA;AAAA,UACb,UAAU,CAAA,CAAE,WAAA;AAAA,UACZ,WAAW,CAAA,CAAE;AAAA,SACjB;AAAA,QACA;AAAA,OACJ,EACF;AACE,QAAA;AAAA,MACJ;AACA,MAAA,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,IACd,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACJ;AACA,EAAA,OAAO,GAAA;AACX;AAGO,SAAS,kBAAA,CACZ,MAAA,EACA,KAAA,EACA,QAAA,EAC0B;AAC1B,EAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,MAAA,EAAQ,KAAA,EAAO,QAAQ,CAAA;AAC1D,EAAA,OAAO,qBAAA,CAAsB,MAAA,EAAQ,KAAA,EAAO,QAAQ,CAAA,CAAE,MAAA;AAAA,IAClD,CAAC,MACG,CAAC,oBAAA;AAAA,MACG,EAAE,GAAG,CAAA,EAAG,QAAA,EAAU,CAAA,CAAE,QAAQ,aAAA,CAAc,CAAA,CAAE,KAAK,CAAA,GAAI,IAAA,EAAK;AAAA,MAC1D;AAAA;AACJ,GACR;AACJ;AASO,SAAS,oBAAA,CACZ,MAAA,EACA,KAAA,EACA,QAAA,EACQ;AACR,EAAA,MAAM,KAAA,GAAQ,qBAAA,CAAsB,MAAA,EAAQ,KAAA,EAAO,QAAQ,CAAA;AAC3D,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,KAAA,CAAM,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AACtD,EAAA,MAAM,IAAA,GAAO,kBAAA,CAAmB,MAAA,EAAQ,KAAA,EAAO,QAAQ,CAAA;AACvD,EAAA,MAAM,QAAA,GAAW,CAAC,GAAG,IAAA,CAAK,IAAI,CAAA,CACzB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,CAAM,GAAG,CAAqB,CAAA,CAC3C,MAAA,CAAO,CAAC,GAAG,EAAE,CAAA,KAAM,CAAC,SAAS,GAAA,CAAI,EAAE,CAAC,CAAA,CACpC,GAAA,CAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAA;AACrB,EAAA,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,MAAM,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,WAAW,GAAG,GAAG,QAAA,EAAU,GAAG,IAAA,CAAK,SAAS,CAAC,CAAC,CAAA;AAC5F;;;ACtTA,IAAM,UAAA,GAAa,CAAC,EAAA,KAChB,EAAA,CAAG,KAAK,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,CAAA,KAAM,SAAS,CAAA,GAAI,CAAC,CAAA,IAAK,IAAA;AAG7C,SAAS,cAAc,EAAA,EAAyB;AACnD,EAAA,OAAO,UAAA,CAAW,EAAE,CAAA,KAAM,IAAA;AAC9B;AAMA,eAAsB,kBAAA,CAClB,IACA,CAAA,EAC8B;AAC9B,EAAA,MAAM,GAAA,GAAM,WAAW,EAAE,CAAA;AACzB,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACA,IAAA,GAAA,GAAM,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACxB,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,IAAA;AAAA,EACX;AACA,EAAA,OAAO,aAAA,CAAc,GAAA,EAAK,EAAA,CAAG,MAAA,EAAQ,CAAC,CAAA;AAC1C;AAIA,eAAsB,aAAA,CAClB,GAAA,EACA,MAAA,EACA,CAAA,EAC8B;AAC9B,EAAA,IAAI;AACA,IAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,IAAA,KAAS,KAAA,IAAS,GAAA,CAAI,MAAA,KAAW,MAAA,IAAU,CAAC,gBAAA,CAAiB,GAAG,CAAA,EAAG,OAAO,IAAA;AAC1F,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,CAAA,KAAM,MAAM,CAAA,GAAI,CAAC,CAAA;AACtD,IAAA,IAAI,SAAS,SAAA,EAAW;AACpB,MAAA,MAAMC,EAAAA,GAAI,wBAAwB,GAAG,CAAA;AACrC,MAAA,IAAIA,EAAAA,CAAE,OAAA,IAAW,CAACA,EAAAA,CAAE,OAAO,OAAO,IAAA;AAClC,MAAA,MAAM,OAAA,GAAU;AAAA,QACZ,OAAOA,EAAAA,CAAE,KAAA;AAAA,QACT,WAAWA,EAAAA,CAAE,SAAA;AAAA,QACb,UAAU,GAAA,CAAI,MAAA;AAAA,QACd,WAAWA,EAAAA,CAAE;AAAA,OACjB;AACA,MAAA,IAAI,CAAC,kBAAA,CAAmBA,EAAAA,CAAE,KAAA,EAAO,OAAA,EAAS,MAAM,CAAA,CAAE,QAAA,EAAU,CAAA,EAAG,OAAO,IAAA;AACtE,MAAA,OAAO;AAAA,QACH,IAAA,EAAM,SAAA;AAAA,QACN,WAAWA,EAAAA,CAAE,KAAA;AAAA,QACb,QAAQ,GAAA,CAAI,MAAA;AAAA,QACZ,UAAUA,EAAAA,CAAE,SAAA;AAAA,QACZ,QAAA,EAAU,aAAA,CAAcA,EAAAA,CAAE,KAAK;AAAA,OACnC;AAAA,IACJ;AACA,IAAA,MAAM,CAAA,GAAI,iBAAiB,GAAG,CAAA;AAE9B,IAAA,IAAI,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,cAAA,KAAmB,MAAM,OAAO,IAAA;AACnD,IAAA,IAAI,CAAC,iBAAA,CAAkB,CAAC,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,KAAgB,MAAM,GAAG,OAAO,IAAA;AAC1E,IAAA,MAAM,EAAA,GAAK,MAAM,CAAA,CAAE,YAAA,CAAa;AAAA,MAC5B,SAAS,CAAA,CAAE,OAAA;AAAA,MACX,SAAS,CAAA,CAAE,gBAAA;AAAA,MACX,WAAW,CAAA,CAAE;AAAA,KAChB,CAAA;AACD,IAAA,OAAO,EAAA,KAAO,IAAA,GAAO,EAAE,IAAA,EAAM,KAAA,EAAO,SAAA,EAAW,CAAA,CAAE,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,CAAA,EAAE,GAAI,IAAA;AAAA,EACpF,SAAS,CAAA,EAAG;AAER,IAAA,IAAI,CAAA,YAAa,qBAAqB,MAAM,CAAA;AAC5C,IAAA,OAAO,IAAA;AAAA,EACX;AACJ;AAKO,SAAS,cAAA,CACZ,CAAA,EACA,QAAA,EACA,GAAA,EACO;AACP,EAAA,MAAM,IAAA,GAAO,iBAAA,CAAkB,WAAA,CAAY,CAAC,GAAG,QAAA,EAAU,CAAA,CAAE,MAAM,CAAA,EAAG,EAAE,GAAA,EAAK,CAAA,EAAG,EAAE,KAAK,CAAA;AACrF,EAAA,OAAO,KAAK,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,WAAA,KAAgB,EAAE,MAAM,CAAA;AACtD;AAGO,SAAS,qBAAA,CACZ,CAAA,EACA,MAAA,EACA,QAAA,EACO;AACP,EAAA,OAAO,oBAAA;AAAA,IACH,EAAE,aAAa,CAAA,CAAE,MAAA,EAAQ,WAAW,CAAA,CAAE,QAAA,EAAU,QAAA,EAAU,CAAA,CAAE,QAAA,EAAS;AAAA,IACrE,kBAAA,CAAmB,MAAA,EAAQ,CAAA,CAAE,SAAA,EAAW,QAAQ;AAAA,GACpD;AACJ;;;ACnGO,IAAM,uBAAA,GAA0B;AAChC,IAAM,iBAAA,GAAoB;AAEjC,IAAM,cAAA,GAAiB,kBAAA;AACvB,IAAM,gBAAA,GAAmB,mBAAA;AACzB,IAAM,aAAA,GAAgB,qBAAA;AAItB,IAAM,OAAA,GAAU,mBAAA;AA2GT,SAAS,SAAA,CAAU,gBAAwB,IAAA,EAAsB;AACpE,EAAA,OAAO,SAAA,CAAU,MAAA,CAAOD,UAAAA,CAAW,aAAA,GAAgB,cAAA,GAAiB,MAAM,IAAA,CAAK,WAAA,EAAa,CAAC,CAAC,CAAA;AAClG;AAIO,SAAS,eAAe,GAAA,EAAqB;AAChD,EAAA,OAAO,iBAAiB,WAAA,CAAY,MAAA,CAAOA,WAAW,aAAA,GAAgB,GAAG,CAAC,CAAC,CAAA;AAC/E;AAGO,SAAS,YAAY,GAAA,EAAqB;AAC7C,EAAA,OAAO,cAAA,GAAiB,GAAA;AAC5B;AAGO,SAAS,QAAA,CAAS,KAAa,GAAA,EAAqB;AACvD,EAAA,OAAO,gBAAA,GAAmB,YAAY,MAAA,CAAOA,UAAAA,CAAW,MAAM,GAAA,GAAM,GAAG,CAAC,CAAC,CAAA;AAC7E;AAEO,SAAS,YAAY,IAAA,EAAuB;AAC/C,EAAA,OAAO,OAAA,CAAQ,KAAK,IAAI,CAAA;AAC5B;AAGO,SAAS,aAAa,OAAA,EAAoC;AAC7D,EAAA,OAAO,SAAA,CAAU,MAAA,CAAO,cAAA,CAAe,OAAO,CAAC,CAAC,CAAA;AACpD;AAGO,SAAS,OAAO,OAAA,EAA8B;AACjD,EAAA,OAAO,SAAA,CAAU,MAAA,CAAO,cAAA,CAAe,OAAO,CAAC,CAAC,CAAA;AACpD;AAGO,SAAS,cAAc,SAAA,EAA6B;AACvD,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC,EAAE,IAAA,EAAK;AAC5C,EAAA,OAAO,SAAA,CAAU,MAAA,CAAO,cAAA,CAAe,MAAM,CAAC,CAAC,CAAA;AACnD;AAOO,SAAS,oBAAoB,KAAA,EAA8B;AAC9D,EAAA,OAAO,KAAA,CAAM,MAAA,MAAY,KAAA,CAAM,MAAA,KAAW,YAAA,CAAA;AAC9C;AAIO,SAAS,eAAe,MAAA,EAA8B;AACzD,EAAA,OAAO,MAAA,KAAW,YAAA;AACtB;AAEO,SAAS,MAAA,CAAO,SAAiB,CAAA,EAA4B;AAChE,EAAA,IAAI,OAAA,KAAY,CAAA,CAAE,eAAA,EAAiB,OAAO,SAAA;AAC1C,EAAA,IAAI,CAAA,CAAE,MAAA,CAAO,QAAA,CAAS,OAAO,GAAG,OAAO,OAAA;AACvC,EAAA,IAAI,CAAA,CAAE,UAAA,CAAW,QAAA,CAAS,OAAO,GAAG,OAAO,WAAA;AAC3C,EAAA,OAAO,QAAA;AACX;AAQO,SAAS,iBAAiB,IAAA,EAAuB;AACpD,EAAA,IAAI,wCAAA,CAAyC,IAAA,CAAK,IAAI,CAAA,EAAG,OAAO,IAAA;AAChE,EAAA,IAAI,mCAAA,CAAoC,IAAA,CAAK,IAAI,CAAA,EAAG,OAAO,IAAA;AAC3D,EAAA,OAAO,KAAA;AACX;AAkBO,SAAS,kBAAA,CACZ,KAAA,EACA,MAAA,EACA,SAAA,EACiB;AACjB,EAAA,MAAM,QAAA,GAAW,SAAA,GAAY,KAAA,CAAM,mBAAA,GAAsB,CAAA;AACzD,EAAA,MAAM,QAAA,GAAW,YAAY,MAAA,CAAO,gBAAA;AACpC,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,UAAA,IAAc,MAAA,CAAO,eAAA;AAC9C,EAAA,OAAO;AAAA,IACH,QAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA,EAAS,QAAA,IAAY,UAAA,GAAa,QAAA,GAAW;AAAA,GACjD;AACJ;AAGO,SAAS,gBAAgB,EAAA,EAA0C;AACtE,EAAA,IAAI;AACA,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,OAAO,CAAA;AAC/B,IAAA,IAAI,CAAA,CAAE,CAAA,KAAM,CAAA,EAAG,OAAO,IAAA;AACtB,IAAA,IAAI,OAAO,EAAE,UAAA,KAAe,QAAA,IAAY,OAAO,CAAA,CAAE,IAAA,KAAS,UAAU,OAAO,IAAA;AAC3E,IAAA,IAAI,OAAO,CAAA,CAAE,eAAA,KAAoB,QAAA,EAAU,OAAO,IAAA;AAClD,IAAA,IAAI,OAAO,CAAA,CAAE,oBAAA,KAAyB,QAAA,EAAU,OAAO,IAAA;AACvD,IAAA,IAAI,CAAC,CAAA,CAAE,KAAA,IAAS,OAAO,CAAA,CAAE,KAAA,KAAU,UAAU,OAAO,IAAA;AACpD,IAAA,IAAI,OAAO,CAAA,CAAE,UAAA,KAAe,QAAA,EAAU,OAAO,IAAA;AAE7C,IAAA,IAAI,OAAO,EAAE,KAAA,KAAU,QAAA,IAAY,OAAO,CAAA,CAAE,WAAA,KAAgB,UAAU,OAAO,IAAA;AAC7E,IAAA,OAAO,CAAA;AAAA,EACX,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,IAAA;AAAA,EACX;AACJ;AAEO,SAAS,UAAU,EAAA,EAAoC;AAC1D,EAAA,IAAI;AACA,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,OAAO,CAAA;AAC/B,IAAA,IAAI,EAAE,CAAA,KAAM,CAAA,IAAK,CAAA,CAAE,IAAA,KAAS,gBAAgB,OAAO,IAAA;AACnD,IAAA,IAAI,OAAO,EAAE,UAAA,KAAe,QAAA,IAAY,OAAO,CAAA,CAAE,cAAA,KAAmB,UAAU,OAAO,IAAA;AACrF,IAAA,IAAI,OAAO,EAAE,mBAAA,KAAwB,QAAA,IAAY,OAAO,CAAA,CAAE,IAAA,KAAS,UAAU,OAAO,IAAA;AAGpF,IAAA,IAAI,CAAA,CAAE,eAAe,KAAA,CAAA,IAAa,CAAC,kBAAkB,CAAA,CAAE,UAAU,GAAG,OAAO,IAAA;AAC3E,IAAA,OAAO,CAAA;AAAA,EACX,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,IAAA;AAAA,EACX;AACJ;AAoBA,eAAsB,gBAAA,CAClB,OAAA,EACA,KAAA,EACA,IAAA,EAKyB;AACzB,EAAA,MAAM,UAAU,IAAA,CAAK,OAAA;AAGrB,EAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,QAAA,IAAY,OAAA,CAAQ,eAAe,IAAA,EAAM;AAC1D,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,kBAAA,EAAmB;AAAA,EAClD;AAMA,EAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,MAAA,KAAW,WAAA,EAAa;AACtC,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,kBAAA,EAAmB;AAAA,EAClD;AAEA,EAAA,IAAI,UAAU,OAAA,CAAQ,eAAA,EAAiB,QAAQ,IAAI,CAAA,KAAM,QAAQ,UAAA,EAAY;AACzE,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,EACnD;AAEA,EAAA,IAAI,CAAC,mBAAA,CAAoB,OAAA,CAAQ,KAAK,CAAA,EAAG;AACrC,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,qBAAA,EAAsB;AAAA,EACrD;AAGA,EAAA,IAAI,CAAC,QAAA,CAAS,KAAA,EAAO,KAAA,CAAM,MAAM,CAAA,EAAG,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AACnF,EAAA,IAAI,KAAA,CAAM,OAAA,KAAY,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA,EAAG;AAG3C,IAAA,IAAI,YAAA,CAAa,gBAAgB,KAAK,CAAA,IAAK,OAAO,CAAA,KAAM,YAAA,CAAa,OAAO,CAAA,EAAG;AAC3E,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,IACnD;AAAA,EACJ;AAEA,EAAA,MAAM,GAAA,GAAM,aAAa,OAAO,CAAA;AAEhC,EAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AAGlB,IAAA,IAAI,OAAA,CAAQ,eAAe,IAAA,EAAM,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,mBAAA,EAAoB;AAChF,IAAA,IAAI,KAAA,CAAM,MAAA,KAAW,OAAA,CAAQ,oBAAA,EAAsB;AAC/C,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,IACnD;AACA,IAAA,IAAI,CAAE,MAAM,OAAA,CAAQ,MAAM,MAAA,EAAQ,OAAA,CAAQ,eAAe,CAAA,EAAI;AACzD,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,IACnD;AACA,IAAA,OAAO;AAAA,MACH,EAAA,EAAI,IAAA;AAAA,MACJ,WAAW,OAAA,CAAQ,UAAA;AAAA,MACnB,YAAA,EAAc,GAAA;AAAA,MACd,eAAe,OAAA,CAAQ;AAAA,KAC3B;AAAA,EACJ;AAEA,EAAA,MAAM,QAAQ,IAAA,CAAK,UAAA;AAEnB,EAAA,IAAI,OAAA,CAAQ,eAAe,KAAA,CAAM,UAAA,SAAmB,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAC5F,EAAA,IAAI,OAAA,CAAQ,UAAA,KAAe,YAAA,CAAa,KAAK,CAAA,EAAG;AAC5C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,EACnD;AAKA,EAAA,IAAI,OAAA,CAAQ,oBAAA,KAAyB,KAAA,CAAM,oBAAA,EAAsB;AAC7D,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,EACnD;AAGA,EAAA,IAAI,MAAM,OAAA,CAAQ,KAAA,CAAM,MAAA,EAAQ,KAAA,CAAM,eAAe,CAAA,EAAG;AACpD,IAAA,OAAO;AAAA,MACH,EAAA,EAAI,IAAA;AAAA,MACJ,WAAW,OAAA,CAAQ,UAAA;AAAA,MACnB,YAAA,EAAc,GAAA;AAAA,MACd,eAAe,KAAA,CAAM;AAAA,KACzB;AAAA,EACJ;AAOA,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,MAAA,EAAQ;AAC7B,IAAA,IAAI,MAAM,OAAA,CAAQ,KAAA,CAAM,MAAA,EAAQ,IAAI,CAAA,EAAG;AACnC,MAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,OAAA,CAAQ,MAAM,CAAA;AACzC,MAAA,IAAI,CAAC,KAAA,CAAM,MAAA,CAAO,KAAA,CAAM,CAAC,MAAM,UAAA,CAAW,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG;AAC/C,QAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,MACnD;AACA,MAAA,IAAA,CAAK,KAAA,CAAM,MAAA,IAAU,QAAA,OAAe,OAAA,CAAQ,UAAU,QAAA,CAAA,EAAW;AAC7D,QAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,MACnD;AACA,MAAA,IAAA,CAAK,KAAA,CAAM,oBAAA,IAAwB,IAAA,OAAW,OAAA,CAAQ,wBAAwB,IAAA,CAAA,EAAO;AACjF,QAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,MACnD;AACA,MAAA,OAAO;AAAA,QACH,EAAA,EAAI,IAAA;AAAA,QACJ,WAAW,OAAA,CAAQ,UAAA;AAAA,QACnB,YAAA,EAAc,GAAA;AAAA,QACd,aAAA,EAAe;AAAA,OACnB;AAAA,IACJ;AAAA,EACJ;AACA,EAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AACnD;AAsCA,eAAsB,gBAAA,CAClB,OAAA,EACA,UAAA,EACA,IAAA,EACmB;AACnB,EAAA,MAAM,SAAS,IAAA,CAAK,YAAA;AAGpB,EAAA,IAAI,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,UAAA,CAAW,SAAS,CAAA,EAAG;AAC/C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,sBAAA,EAAuB;AAAA,EACtD;AAGA,EAAA,IAAI,OAAA,CAAQ,SAAS,cAAA,EAAgB,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,mBAAA,EAAoB;AACpF,EAAA,IAAI,OAAA,CAAQ,UAAA,KAAe,UAAA,CAAW,UAAA,EAAY;AAC9C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,EACnD;AAEA,EAAA,MAAM,GAAA,GAAM,OAAO,OAAO,CAAA;AAC1B,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,CAAQ,cAAA,EAAgB,UAAU,CAAA;AAEtD,EAAA,MAAM,WAAA,GAAc,OAAO,OAAA,CAAQ,OAAA,KAAY,QAAA;AAG/C,EAAA,IAAI,WAAA,EAAa;AACb,IAAA,IAAI,SAAS,QAAA,EAAU,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,mBAAA,EAAoB;AACtE,IAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,QAAQ,GAAA,EAAK,IAAA,EAAM,aAAa,IAAA,EAAK;AAAA,EAC5D;AAKA,EAAA,IAAA,CAAK,UAAA,CAAW,MAAA,IAAU,QAAA,MAAc,QAAA,EAAU;AAC9C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,aAAA,EAAc;AAAA,EAC7C;AAEA,EAAA,MAAM,MAAA,GAAS,MAAM,oBAAA,CAAqB,OAAA,EAAS,YAAY,IAAA,EAAM,GAAA,EAAK,MAAM,MAAM,CAAA;AACtF,EAAA,IAAI,QAAQ,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,MAAA,EAAO;AAC9C,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,QAAQ,GAAA,EAAK,IAAA,EAAM,aAAa,KAAA,EAAM;AAC7D;AAUA,eAAsB,UAAA,CAClB,OAAA,EACA,UAAA,EACA,IAAA,EACmB;AACnB,EAAA,MAAM,UAAU,IAAA,CAAK,OAAA;AAIrB,EAAA,IAAI,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,UAAA,CAAW,SAAS,CAAA,EAAG;AAC/C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,sBAAA,EAAuB;AAAA,EACtD;AAEA,EAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,CAAC,OAAA,SAAgB,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAC5E,EAAA,IAAI,CAAC,QAAA,CAAS,IAAA,CAAK,KAAA,EAAO,OAAA,CAAQ,mBAAmB,CAAA,EAAG;AACpD,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,EACnD;AACA,EAAA,IAAI,CAAE,MAAM,OAAA,CAAQ,QAAQ,mBAAA,EAAqB,OAAA,CAAQ,cAAc,CAAA,EAAI;AACvE,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,mBAAA,EAAoB;AAAA,EACnD;AACA,EAAA,OAAO,gBAAA,CAAiB,OAAA,EAAS,UAAA,EAAY,IAAI,CAAA;AACrD;AAGA,eAAe,qBACX,OAAA,EACA,UAAA,EACA,IAAA,EACA,GAAA,EACA,MACA,MAAA,EAC4B;AAC5B,EAAA,IAAI,IAAA,KAAS,SAAA,IAAa,IAAA,KAAS,OAAA,EAAS,OAAO,IAAA;AACnD,EAAA,MAAM,IAAI,UAAA,CAAW,KAAA;AACrB,EAAA,QAAQ,EAAE,MAAA;AAAQ,IACd,KAAK,SAAA;AACD,MAAA,OAAO,iBAAA;AAAA;AAAA,IACX,KAAK,MAAA;AACD,MAAA,OAAO,IAAA;AAAA;AAAA,IACX,KAAK,WAAA,EAAa;AACd,MAAA,IAAI,CAAC,IAAA,CAAK,SAAA,EAAW,OAAO,mBAAA;AAC5B,MAAA,IAAI,aAAA,CAAc,IAAA,CAAK,SAAS,CAAA,KAAM,EAAE,cAAA,EAAgB;AACpD,QAAA,OAAO,mBAAA;AAAA,MACX;AACA,MAAA,OAAO,KAAK,SAAA,CAAU,QAAA,CAAS,OAAA,CAAQ,cAAc,IAAI,IAAA,GAAO,mBAAA;AAAA,IACpE;AAAA,IACA,KAAK,YAAA,EAAc;AACf,MAAA,IAAI,CAAC,OAAA,CAAQ,WAAA,EAAa,OAAO,cAAA;AACjC,MAAA,IAAI,CAAC,IAAA,CAAK,UAAA,EAAY,OAAO,cAAA;AAC7B,MAAA,IAAI,CAAC,gBAAA,CAAiB,OAAA,CAAQ,cAAc,GAAG,OAAO,cAAA;AAEtD,MAAA,IAAI,IAAA,CAAK,cAAc,YAAA,EAAc;AACjC,QAAA,MAAM,IAAI,oBAAoB,iCAAiC,CAAA;AAAA,MACnE;AAGA,MAAA,MAAM,IAAI,kBAAA,CAAmB,OAAA,CAAQ,WAAA,EAAa,CAAA,EAAG,KAAK,SAAS,CAAA;AACnE,MAAA,IAAI,CAAA,CAAE,OAAA,KAAY,QAAA,EAAU,OAAO,cAAA;AACnC,MAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO;AAAA,QACvB,SAAS,OAAA,CAAQ,cAAA;AAAA,QACjB,OAAA,EAAS,GAAA;AAAA,QACT,WAAW,IAAA,CAAK;AAAA,OACnB,CAAA;AACD,MAAA,IAAI,KAAA,KAAU,MAAM,OAAO,cAAA;AAK3B,MAAA,IAAK,MAAM,KAAK,aAAA,CAAc,OAAA,CAAQ,aAAa,OAAA,CAAQ,cAAc,MAAO,IAAA,EAAM;AAClF,QAAA,OAAO,cAAA;AAAA,MACX;AACA,MAAA,OAAO,IAAA;AAAA,IACX;AAAA;AAER;AA+DA,eAAsB,mBAAA,CAClB,MAAA,EACA,GAAA,EACA,IAAA,EAC+B;AAM/B,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAkE;AACpF,EAAA,KAAA,MAAW,MAAM,MAAA,EAAQ;AACrB,IAAA,MAAM,OAAA,GAAU,gBAAgB,EAAE,CAAA;AAClC,IAAA,IAAI,CAAC,OAAA,EAAS;AAGd,IAAA,IAAI,OAAA,CAAQ,eAAe,GAAA,EAAK;AAChC,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,EAAA,CAAG,MAAM,CAAA,EAAG;AAC9B,IAAA,MAAM,EAAA,GAAK,aAAa,OAAO,CAAA;AAC/B,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA;AACzB,IAAA,IAAI,CAAC,IAAA,EAAM,KAAA,CAAM,GAAA,CAAI,EAAA,EAAI,EAAE,OAAA,EAAS,MAAA,EAAQ,CAAC,EAAE,CAAA,EAAG,CAAA;AAAA,SAAA,IACzC,CAAC,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAA,CAAG,EAAE,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,KAAK,EAAE,CAAA;AAAA,EAC1E;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,CAAA,EAAG,OAAO,IAAA;AAE7B,EAAA,IAAI,IAAA,GAA+C,IAAA;AACnD,EAAA,MAAM,QAAA,GAAW,MAAO,IAAA,KAAA,IAAA,GAAS,IAAA,CAAK,QAAA,EAAS,CAAA;AAC/C,EAAA,MAAM,QAAA,uBAAe,GAAA,EAA4C;AACjE,EAAA,MAAM,SAAA,GAAY,CAAC,EAAA,KAAmB;AAClC,IAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,EAAA,CAAG,EAAE,CAAA;AACnB,MAAA,QAAA,CAAS,GAAA,CAAI,EAAA,CAAG,EAAA,EAAI,kBAAA,CAAmB,EAAA,EAAI,EAAE,QAAA,EAAU,YAAA,EAAc,IAAA,CAAK,YAAA,EAAc,CAAC,CAAA;AAC7F,IAAA,OAAO,QAAA,CAAS,GAAA,CAAI,EAAA,CAAG,EAAE,CAAA;AAAA,EAC7B,CAAA;AAKA,EAAA,MAAM,SAAA,GAAY,OACd,IAAA,EACA,UAAA,KAC4B;AAC5B,IAAA,MAAM,MAAwB,EAAC;AAC/B,IAAA,KAAA,MAAW,EAAA,IAAM,KAAK,MAAA,EAAQ;AAC1B,MAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAAU,EAAE,CAAA;AAClC,MAAA,MAAM,OAAA,GAAU,aAAA,CAAc,EAAE,CAAA,GAC1B,OAAO,EAAA,EAAY,SAAA,KACf,OAAA,KAAY,IAAA,IAAQ,OAAO,OAAA,CAAQ,MAAA,IAAU,SAAA,KAAc,OAAA,CAAQ,YACvE,IAAA,CAAK,OAAA;AACX,MAAA,MAAM,CAAA,GAAI,MAAM,gBAAA,CAAiB,IAAA,CAAK,SAAS,EAAA,EAAI;AAAA,QAC/C,GAAI,UAAA,GAAa,EAAE,UAAA,KAAe,EAAC;AAAA,QACnC;AAAA,OACH,CAAA;AACD,MAAA,IAAI,CAAC,EAAE,EAAA,EAAI;AACX,MAAA,MAAM,OAAA,GAAU,CAAC,UAAA,IAAc,CAAA,CAAE,kBAAkB,UAAA,CAAW,eAAA;AAC9D,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,EAAA,EAAI,OAAA,EAAS,SAAS,CAAA;AAAA,IACrC;AACA,IAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,MAAA,CAAO,CAAA,CAAE,OAAO,CAAA,GAAI,MAAA,CAAO,CAAA,CAAE,OAAO,CAAC,CAAA;AAAA,EACnE,CAAA;AAGA,EAAA,MAAM,MAAA,uBAAa,GAAA,EAA8B;AACjD,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAA2B;AAClD,EAAA,MAAM,aAAA,GAAgB,OAAO,EAAA,EAAY,IAAA,KAA8C;AACnF,IAAA,IAAI,WAAW,GAAA,CAAI,EAAE,GAAG,OAAO,UAAA,CAAW,IAAI,EAAE,CAAA;AAChD,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA;AACzB,IAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA,EAAG;AACvB,MAAA,UAAA,CAAW,GAAA,CAAI,IAAI,IAAI,CAAA;AACvB,MAAA,OAAO,IAAA;AAAA,IACX;AACA,IAAA,IAAA,CAAK,IAAI,EAAE,CAAA;AACX,IAAA,MAAM,MAAA,GAAS,KAAK,OAAA,CAAQ,UAAA;AAC5B,IAAA,IAAI,UAAA,GAAa,CAAA;AACjB,IAAA,IAAI,KAAA;AACJ,IAAA,IAAI,WAAW,IAAA,EAAM;AACjB,MAAA,MAAM,CAAA,GAAI,KAAA,CAAM,GAAA,CAAI,MAAM,CAAA;AAC1B,MAAA,MAAM,IAAI,CAAA,GAAI,MAAM,aAAA,CAAc,MAAA,EAAQ,IAAI,CAAA,GAAI,IAAA;AAClD,MAAA,IAAI,CAAC,CAAA,IAAK,CAAA,KAAM,IAAA,EAAM;AAClB,QAAA,UAAA,CAAW,GAAA,CAAI,IAAI,IAAI,CAAA;AACvB,QAAA,OAAO,IAAA;AAAA,MACX;AACA,MAAA,UAAA,GAAa,CAAA;AACb,MAAA,KAAA,GAAQ,CAAA,CAAE,OAAA;AAAA,IACd;AACA,IAAA,MAAM,CAAA,GAAI,MAAM,SAAA,CAAU,IAAA,EAAM,KAAK,CAAA;AACrC,IAAA,IAAI,CAAA,CAAE,MAAA,EAAQ,MAAA,CAAO,GAAA,CAAI,IAAI,CAAC,CAAA;AAC9B,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,MAAA,GAAS,UAAA,GAAa,CAAA,GAAI,IAAA;AAC1C,IAAA,UAAA,CAAW,GAAA,CAAI,IAAI,KAAK,CAAA;AACxB,IAAA,OAAO,KAAA;AAAA,EACX,CAAA;AACA,EAAA,KAAA,MAAW,EAAA,IAAM,MAAM,IAAA,EAAK,QAAS,aAAA,CAAc,EAAA,kBAAI,IAAI,GAAA,EAAK,CAAA;AAKhE,EAAA,MAAM,WAAW,IAAA,CAAK,QAAA;AACtB,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA+B;AACrD,EAAA,MAAM,MAAA,GAAS,OAAO,CAAA,KAAwC;AAC1D,IAAA,IAAI,CAAC,CAAA,CAAE,OAAA,EAAS,OAAO,IAAA;AAGvB,IAAA,MAAM,IAAI,CAAA,CAAE,OAAA;AACZ,IAAA,MAAME,IAAAA,GAAM,CAAA,EAAG,CAAA,CAAE,SAAS,IAAI,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,SAAS,SAAA,GAAY,CAAA,CAAE,QAAA,GAAW,CAAA,CAAE,OAAO,OAAO,CAAA,CAAA;AAC9F,IAAA,IAAI,CAAC,SAAA,CAAU,GAAA,CAAIA,IAAG,CAAA,EAAG,SAAA,CAAU,GAAA,CAAIA,IAAAA,EAAK,QAAA,CAAS,CAAA,CAAE,OAAO,CAAC,CAAA;AAC/D,IAAA,MAAM,CAAA,GAAI,MAAM,SAAA,CAAU,GAAA,CAAIA,IAAG,CAAA;AACjC,IAAA,IAAI,CAAA,KAAM,SAAA,EAAW,MAAM,IAAI,mBAAA,EAAoB;AACnD,IAAA,OAAO,CAAA,KAAM,MAAA;AAAA,EACjB,CAAA;AACA,EAAA,MAAM,OAAA,GAAU,OAAO,EAAA,KAA+C;AAClE,IAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA,IAAK,EAAC,EAAG,IAAI,MAAM,MAAA,CAAO,CAAC,CAAA,EAAG,OAAO,CAAA;AAClE,IAAA,OAAO,IAAA;AAAA,EACX,CAAA;AACA,EAAA,MAAM,IAAA,uBAAW,GAAA,EAA4B;AAC7C,EAAA,KAAA,MAAW,EAAA,IAAM,MAAA,CAAO,IAAA,EAAK,EAAG;AAC5B,IAAA,MAAM,CAAA,GAAI,MAAM,OAAA,CAAQ,EAAE,CAAA;AAC1B,IAAA,IAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,CAAC,CAAA;AAAA,EACzB;AAIA,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAY;AAClC,EAAA,KAAA,MAAW,GAAA,IAAO,IAAA,CAAK,IAAA,EAAK,EAAG;AAC3B,IAAA,IAAI,GAAA,GAAqB,GAAA;AACzB,IAAA,OAAO,GAAA,IAAO,CAAC,SAAA,CAAU,GAAA,CAAI,GAAG,CAAA,EAAG;AAC/B,MAAA,SAAA,CAAU,IAAI,GAAG,CAAA;AACjB,MAAA,GAAA,GAAM,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,EAAG,QAAQ,UAAA,IAAc,IAAA;AAAA,IAChD;AAAA,EACJ;AAGA,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAoB;AACrC,EAAA,KAAA,MAAW,MAAM,SAAA,EAAW;AACxB,IAAA,MAAM,aAAA,GAAA,CAAiB,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA,IAAK,EAAC,EAAG,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAA;AACpE,IAAA,IAAI,CAAA,GAAI,aAAA,CAAc,MAAA,GAAS,CAAA,GAAI,CAAA;AACnC,IAAA,KAAA,MAAW,KAAK,aAAA,EAAe,IAAI,MAAM,MAAA,CAAO,CAAC,GAAG,CAAA,GAAI,CAAA;AACxD,IAAA,IAAA,CAAK,GAAA,CAAI,IAAI,CAAC,CAAA;AAAA,EAClB;AAQA,EAAA,MAAM,SAAA,GAAY,CAAC,EAAA,KAAwB;AAGvC,IAAA,MAAM,MAAA,GAAS,CAACC,MAAAA,EAAe,QAAA,KAAqC;AAChE,MAAA,IAAIC,KAAAA,GAAO,CAAA;AACX,MAAA,KAAA,MAAW,CAAC,OAAA,EAAS,KAAK,CAAA,IAAK,KAAA,EAAO;AAClC,QAAA,IAAI,MAAM,OAAA,CAAQ,UAAA,KAAe,YAAY,SAAA,CAAU,GAAA,CAAI,OAAO,CAAA,EAAG;AACjE,UAAAA,QAAO,IAAA,CAAK,GAAA,CAAIA,OAAM,IAAA,CAAK,GAAA,CAAI,OAAO,CAAE,CAAA;AAAA,QAC5C;AAAA,MACJ;AACA,MAAA,OAAO,IAAA,CAAK,GAAA,CAAID,MAAK,CAAA,GAAKC,KAAAA;AAAA,IAC9B,CAAA;AACA,IAAA,IAAI,KAAA,GAAQ,EAAA;AACZ,IAAA,KAAA,IAAS,GAAA,GAAM,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,EAAG,KAAK,GAAA,GAAM,KAAA,CAAM,GAAA,CAAI,KAAK,CAAA,EAAG;AACvD,MAAA,MAAM,QAAA,GAAW,IAAI,OAAA,CAAQ,UAAA;AAC7B,MAAA,IAAI,MAAA,CAAO,KAAA,EAAO,QAAQ,CAAA,EAAG,OAAO,IAAA;AACpC,MAAA,IAAI,QAAA,KAAa,MAAM,OAAO,KAAA;AAC9B,MAAA,KAAA,GAAQ,QAAA;AAAA,IACZ;AACA,IAAA,OAAO,KAAA;AAAA,EACX,CAAA;AAEA,EAAA,MAAM,OAAA,GAAU,CAAC,EAAA,KAAyC;AACtD,IAAA,MAAM,MAAgC,EAAC;AACvC,IAAA,KAAA,IAAS,GAAA,GAAqB,IAAI,GAAA,EAAK,GAAA,GAAM,MAAM,GAAA,CAAI,GAAG,CAAA,CAAG,OAAA,CAAQ,UAAA,EAAY;AAC7E,MAAA,MAAM,EAAA,GAAK,MAAA,CAAO,GAAA,CAAI,GAAG,KAAK,EAAC;AAC/B,MAAA,GAAA,CAAI,OAAA,CAAQ;AAAA,QACR,YAAA,EAAc,GAAA;AAAA,QACd,UAAA,EAAY,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,CAAG,OAAA;AAAA,QAC5B,SAAS,EAAA,CAAG,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,GAAG,MAAM,CAAA;AAAA,QAClC,QAAQ,EAAA,CAAG,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,GAAG,EAAE;AAAA,OAChC,CAAA;AAAA,IACL;AACA,IAAA,OAAO,GAAA;AAAA,EACX,CAAA;AAKA,EAAA,MAAM,GAAA,GAAM,CAAC,EAAA,KAAe;AACxB,IAAA,MAAM,CAAA,GAAI,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,CAAG,OAAA;AACzB,IAAA,OAAO,CAAC,CAAA,CAAE,MAAA,KAAW,QAAA,GAAW,CAAA,GAAI,CAAA,EAAG,UAAA,CAAW,GAAA,CAAI,EAAE,CAAA,EAAI,CAAA,CAAE,UAAU,CAAA;AAAA,EAC5E,CAAA;AACA,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,EAAW,CAAA,KAAuB;AAC7C,IAAA,MAAM,EAAA,GAAK,IAAI,CAAC,CAAA;AAChB,IAAA,MAAM,EAAA,GAAK,IAAI,CAAC,CAAA;AAChB,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAG,MAAA,EAAQ,CAAA,EAAA,MAAS,EAAA,CAAG,CAAC,CAAA,KAAM,EAAA,CAAG,CAAC,CAAA,EAAG,OAAO,GAAG,CAAC,CAAA,GAAK,GAAG,CAAC,CAAA;AAC7E,IAAA,OAAO,CAAA,GAAI,CAAA;AAAA,EACf,CAAA;AAGA,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAY;AACnC,EAAA,KAAA,MAAW,MAAM,SAAA,EAAW;AACxB,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,EAAE,GAAG,OAAA,CAAQ,UAAA;AACtC,IAAA,IAAI,MAAA,EAAQ,UAAA,CAAW,GAAA,CAAI,MAAM,CAAA;AAAA,EACrC;AACA,EAAA,MAAM,UAAA,GAAa,CAAC,GAAG,IAAA,CAAK,MAAM,CAAA,CAC7B,MAAA,CAAO,CAAC,OAAO,CAAC,UAAA,CAAW,GAAA,CAAI,EAAE,KAAK,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,CAAG,QAAQ,MAAA,KAAW,QAAQ,CAAA,CAChF,GAAA,CAAI,CAAC,EAAA,MAAQ,EAAE,YAAA,EAAc,EAAA,EAAI,YAAY,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,CAAG,SAAQ,CAAE,CAAA;AAC3E,EAAA,IAAI,IAAA,GAA+B,IAAA;AACnC,EAAA,IAAI,MAAA,GAAwB,IAAA;AAC5B,EAAA,KAAA,MAAW,CAAC,EAAA,EAAI,CAAC,CAAA,IAAK,IAAA,EAAM;AACxB,IAAA,IAAI,WAAW,GAAA,CAAI,EAAE,CAAA,IAAK,SAAA,CAAU,EAAE,CAAA,EAAG;AACzC,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,GAAA,CAAI,EAAE,CAAA;AAC/B,IAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,KAAA,CAAM,EAAA,EAAI,MAAM,CAAA,EAAG;AACtC,MAAA,IAAA,GAAO;AAAA,QACH,UAAA,EAAY,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,CAAG,OAAA;AAAA,QAC3B,YAAA,EAAc,EAAA;AAAA,QACd,MAAA,EAAQ,KAAA;AAAA,QACR,SAAA,EAAW,EAAE,EAAA,CAAG,MAAA;AAAA,QAChB,KAAA,EAAO,QAAQ,EAAE,CAAA;AAAA,QACjB,QAAA,EAAU,CAAC,GAAG,MAAM,CAAA,CAAE,IAAI,CAAC,CAAC,GAAA,EAAK,EAAE,CAAA,MAAO;AAAA,UACtC,YAAA,EAAc,GAAA;AAAA,UACd,UAAA,EAAY,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,CAAG,OAAA;AAAA,UAC5B,SAAS,EAAA,CAAG,GAAA,CAAI,CAACC,EAAAA,KAAMA,EAAAA,CAAE,GAAG,MAAM,CAAA;AAAA,UAClC,QAAQ,EAAA,CAAG,GAAA,CAAI,CAACA,EAAAA,KAAMA,EAAAA,CAAE,GAAG,EAAE;AAAA,SACjC,CAAE,CAAA;AAAA,QACF;AAAA,OACJ;AACA,MAAA,MAAA,GAAS,EAAA;AAAA,IACb;AAAA,EACJ;AACA,EAAA,OAAO,IAAA;AACX;AAkBO,SAAS,cAAA,CAAe,UAAkC,EAAA,EAAqC;AAClG,EAAA,IAAI,CAAC,QAAA,IAAY,CAAC,gBAAA,CAAiB,EAAE,GAAG,OAAO,IAAA;AAC/C,EAAA,MAAM,CAAA,GAAI,QAAA,CAAS,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,CAAO,QAAA,CAAS,EAAA,CAAG,EAAE,CAAC,CAAA;AAChE,EAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AACf,EAAA,OAAO;AAAA,IACH,cAAc,CAAA,CAAE,YAAA;AAAA,IAChB,OAAA,EAAS,SAAS,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,YAAA,KAAiB,CAAA,CAAE,YAAY,CAAA;AAAA,IACrE,KAAA,EAAO,QAAA,CAAS,YAAA,KAAiB,CAAA,CAAE;AAAA,GACvC;AACJ;AAYA,IAAM,kBAAA,GAAqB,GAAA;AAE3B,IAAM,iBAAA,GAAoB,CAAA;AAE1B,IAAM,mBAAA,GAAsB,EAAA;AAE5B,IAAM,gBAAA,GAAmB,GAAA;AAEzB,IAAM,gBAAA,GAAmB,EAAA;AAEzB,IAAM,qBAAA,GAAwB,GAAA;AAG9B,SAAS,WAAA,CAAY,GAAe,GAAA,EAA4B;AAC5D,EAAA,MAAM,CAAA,GAAI,gBAAgB,CAAC,CAAA;AAC3B,EAAA,OAAO,CAAA,IAAK,CAAA,CAAE,UAAA,KAAe,GAAA,IAAO,SAAA,CAAU,CAAA,CAAE,eAAA,EAAiB,CAAA,CAAE,IAAI,CAAA,KAAM,GAAA,GACvE,CAAA,CAAE,eAAA,GACF,IAAA;AACV;AAeA,eAAsB,mBAAA,CAClB,GAAA,EACA,KAAA,EACA,WAAA,EAC6F;AAC7F,EAAA,MAAM,cAAc,KAAA,CAAM,KAAA;AAC1B,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAwB;AAC3C,EAAA,MAAM,SAA8B,EAAC;AAErC,EAAA,IAAI,QAAA,GAAW,IAAA;AAEf,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAY;AACjC,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAY;AACjC,EAAA,MAAM,GAAA,GAAM,CACR,GAAA,EACA,MAAA,GAAS,KAAA,KACR;AACD,IAAA,MAAA,CAAO,IAAA,CAAK,GAAI,GAAA,CAAI,WAAA,IAAe,EAAG,CAAA;AACtC,IAAA,IAAI,IAAI,WAAA,IAAe,CAAC,eAAe,GAAA,CAAI,WAAW,GAAG,QAAA,GAAW,KAAA;AACpE,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,KAAA,MAAW,CAAA,IAAK,GAAA,CAAI,MAAA,IAAU,EAAC,EAAG;AAC9B,MAAA,IAAI,MAAA,EAAQ,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA;AAC7B,MAAA,IAAI,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA,EAAG;AACtB,MAAA,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,CAAC,CAAA;AAClB,MAAA,KAAA,EAAA;AAAA,IACJ;AACA,IAAA,OAAO,KAAA;AAAA,EACX,CAAA;AACA,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,EAAE,KAAA,EAAO,CAAC,uBAAuB,CAAA,EAAG,IAAA,EAAM,CAAC,cAAA,CAAe,GAAG,CAAC,GAAG,CAAA;AAG5F,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,KAAA,IAAS,IAAA,GAAO,CAAA,EAAG,IAAA,GAAO,iBAAA,EAAmB,IAAA,EAAA,EAAQ;AACjD,IAAA,MAAM,GAAA,GAAM,MAAM,WAAA,CAAY;AAAA,MAC1B,KAAA,EAAO,CAAC,uBAAuB,CAAA;AAAA,MAC/B,IAAA,EAAM,CAAC,GAAG,CAAA;AAAA,MACV,KAAA,EAAO,kBAAA;AAAA,MACP,GAAI,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,KAAU;AAAC,KAC1C,CAAA;AACD,IAAA,MAAM,KAAA,GAAQ,IAAI,GAAG,CAAA;AACrB,IAAA,KAAA,MAAW,CAAA,IAAK,GAAA,CAAI,MAAA,IAAU,EAAC,EAAG,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS,QAAA,EAAU,CAAA,CAAE,UAAU,CAAA;AAGlF,IAAA,IAAA,CAAK,GAAA,CAAI,MAAA,IAAU,EAAC,EAAG,SAAS,kBAAA,EAAoB;AACpD,IAAA,IAAI,KAAA,KAAU,CAAA,IAAK,IAAA,KAAS,iBAAA,GAAoB,CAAA,EAAG;AAC/C,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA;AAAA,IACJ;AAAA,EACJ;AACA,EAAA,GAAA,CAAI,MAAM,MAAM,CAAA;AAOhB,EAAA,IAAI,UAAA,GAAa,KAAA;AACjB,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,MAAM,UACF,WAAA,IAAe,CAAC,GAAG,MAAA,CAAO,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,YAAY,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,OAAO,CAAA,IAAK,IAAA;AACzF,EAAA,IAAI,CAAC,SAAS,UAAA,GAAa,IAAA;AAAA,OACtB;AACD,IAAA,MAAM,SAAA,uBAAgB,GAAA,EAA+B;AACrD,IAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAc;AAC1B,MAAA,IAAI,CAAC,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA;AAChB,QAAA,SAAA,CAAU,GAAA;AAAA,UACN,CAAA;AAAA,UACA,KAAA,CACK,cAAc,CAAC,CAAA,CACf,MAAM,OAAO,EAAE,IAAA,EAAM,EAAC,EAAe,QAAA,EAAU,OAAO,KAAA,EAAO,KAAA,GAAQ,CAAA,CACrE,IAAA,CAAK,CAAC,EAAE,IAAA,EAAM,QAAA,EAAU,KAAA,EAAM,KAAM;AACjC,YAAA,IAAI,CAAC,QAAA,IAAY,IAAA,CAAK,MAAA,GAAS,kBAAkB,UAAA,GAAa,IAAA;AAC9D,YAAA,IAAI,CAAC,OAAO,QAAA,GAAW,KAAA;AACvB,YAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,gBAAgB,CAAA;AAC3C,YAAA,KAAA,MAAW,CAAA,IAAK,IAAA,EAAM,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA;AACpC,YAAA,OAAO,IAAA;AAAA,UACX,CAAC;AAAA,SACT;AACJ,MAAA,OAAO,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,IAC1B,CAAA;AACA,IAAA,MAAM,IAAA,GAAO,OAAO,MAAA,EAAiC,IAAA,KAA4B;AAC7E,MAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,CAAM,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,qBAAA,GAAwB,IAAI,CAAC,CAAA;AACrE,MAAA,IAAI,KAAA,CAAM,MAAA,GAAS,IAAA,CAAK,MAAA,EAAQ,UAAA,GAAa,IAAA;AAC7C,MAAA,IAAA,IAAQ,KAAA,CAAM,MAAA;AACd,MAAA,KAAA,MAAW,GAAA,IAAO,MAAM,OAAA,CAAQ,GAAA;AAAA,QAC5B,KAAA,CAAM,GAAA;AAAA,UAAI,CAAC,MACP,WAAA,CAAY;AAAA,YACR,KAAA,EAAO,CAAC,uBAAuB,CAAA;AAAA,YAC/B,GAAG,MAAA;AAAA,YACH,OAAA,EAAS,CAAC,CAAC,CAAA;AAAA,YACX,KAAA,EAAO;AAAA,WACV;AAAA;AACL,OACJ,EAAG;AACC,QAAA,GAAA,CAAI,KAAK,IAAI,CAAA;AAAA,MACjB;AAAA,IACJ,CAAA;AACA,IAAA,MAAM,IAAA,CAAK,EAAE,IAAA,EAAM,CAAC,GAAG,GAAE,EAAG,MAAM,MAAA,CAAO,OAAO,CAAC,CAAA;AACjD,IAAA,MAAM,MAAA,uBAAa,GAAA,EAAY;AAC/B,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,OAAO,KAAA,GAAQ,qBAAqB,KAAA,EAAA,EAAS;AACzC,MAAA,MAAM,WAAgC,EAAC;AACvC,MAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,MAAA,EAAO,EAAG;AAC7B,QAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA,EAAG;AACzB,QAAA,MAAM,CAAA,GAAI,gBAAgB,CAAC,CAAA;AAC3B,QAAA,IAAI,CAAC,CAAA,IAAK,CAAA,CAAE,UAAA,KAAe,GAAA,EAAK;AAChC,QAAA,MAAM,EAAA,GAAK,aAAa,CAAC,CAAA;AACzB,QAAA,IAAI,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA,EAAG;AACpB,QAAA,MAAA,CAAO,IAAI,EAAE,CAAA;AACb,QAAA,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,MACnB;AACA,MAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AAC3B,MAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACtB,QAAA,MAAM,IAAA,GAAO;AAAA,UACT,GAAG,IAAI,GAAA,CAAA,CAAK,MAAM,OAAA,CAAQ,IAAI,CAAC,OAAA,EAAS,GAAG,CAAA,CAAE,MAAM,CAAA,CAAE,GAAA,CAAI,MAAM,CAAC,CAAA,EAAG,MAAM;AAAA,SAC7E;AACA,QAAA,MAAM,IAAA,CAAK,EAAE,IAAA,EAAM,CAAC,aAAa,CAAC,CAAC,CAAA,EAAE,EAAG,IAAI,CAAA;AAAA,MAChD;AAAA,IACJ;AACA,IAAA,IAAI,KAAA,KAAU,qBAAqB,UAAA,GAAa,IAAA;AAAA,EACpD;AAGA,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAY;AAC9B,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,mBAAA,EAAqB,KAAA,EAAA,EAAS;AACtD,IAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAE7B,IAAA,MAAM,MAAA,uBAAa,GAAA,EAAqB;AACxC,IAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,MAAA,EAAO,EAAG;AAC7B,MAAA,MAAM,CAAA,GAAI,gBAAgB,CAAC,CAAA;AAC3B,MAAA,IAAI,CAAC,CAAA,IAAK,CAAA,CAAE,UAAA,KAAe,GAAA,EAAK;AAChC,MAAA,IAAA,CAAK,GAAA,CAAI,YAAA,CAAa,CAAC,CAAC,CAAA;AACxB,MAAA,IAAI,CAAA,CAAE,UAAA;AACF,QAAA,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,UAAA,EAAY,CAAC,CAAC,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,UAAU,CAAA,IAAK,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,MAAM,CAAC,CAAA;AAAA,IACrF;AACA,IAAA,MAAM,OAAA,GAAU,CAAC,GAAG,MAAM,EACrB,MAAA,CAAO,CAAC,CAAC,EAAE,CAAA,KAAM,CAAC,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA,IAAK,CAAC,MAAM,GAAA,CAAI,EAAE,CAAC,CAAA,CAChD,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,OAAO,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI,MAAA,CAAO,EAAE,CAAC,CAAC,CAAC,CAAA,CAC1C,KAAA,CAAM,GAAG,gBAAgB,CAAA,CACzB,IAAI,CAAC,CAAC,EAAE,CAAA,KAAM,EAAE,CAAA;AACrB,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC1B,IAAA,KAAA,MAAW,EAAA,IAAM,OAAA,EAAS,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA;AACtC,IAAA,GAAA,CAAI,MAAM,WAAA,CAAY,EAAE,KAAA,EAAO,CAAC,uBAAuB,CAAA,EAAG,IAAA,EAAM,OAAA,CAAQ,GAAA,CAAI,WAAW,CAAA,EAAG,CAAC,CAAA;AAAA,EAC/F;AACA,EAAA,OAAO;AAAA,IACH,MAAA,EAAQ,cAAA,CAAe,EAAE,MAAA,EAAQ,CAAC,GAAG,MAAA,CAAO,MAAA,EAAQ,CAAA,EAAG,WAAA,EAAa,MAAA,EAAQ,CAAA;AAAA,IAC5E,SAAA;AAAA,IACA,UAAA;AAAA;AAAA,IAEA;AAAA,GACJ;AACJ;AA4BO,SAAS,kBAAkB,KAAA,EAAqC;AACnE,EAAA,OAAO,CAAC,GAAG,KAAK,EAAE,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AAC7B,IAAA,MAAM,EAAA,GAAK,CAAA,CAAE,KAAA,CAAM,UAAA,GAAa,EAAE,KAAA,CAAM,UAAA;AACxC,IAAA,OAAO,EAAA,KAAO,CAAA,GAAI,EAAA,GAAK,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,MAAA,GAAS,EAAA,GAAK,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,MAAA,GAAS,CAAA,GAAI,CAAA;AAAA,EAChF,CAAC,CAAA;AACL;AAYA,eAAsB,kBAAA,CAClB,MAAA,EACA,UAAA,EACA,IAAA,EACqB;AACrB,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAyB;AAC9C,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAY;AAClC,EAAA,IAAI,cAAA,GAAiB,KAAA;AACrB,EAAA,KAAA,MAAW,MAAM,MAAA,EAAQ;AACrB,IAAA,MAAM,OAAA,GAAU,UAAU,EAAE,CAAA;AAC5B,IAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,UAAA,KAAe,WAAW,UAAA,EAAY;AAC9D,IAAA,MAAM,UAAA,GAAa,EAAA,CAAG,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,CAAA,KAAM,aAAa,CAAA,GAAI,CAAC,CAAA;AAClE,IAAA,IAAI,CAAA;AACJ,IAAA,IAAI;AACA,MAAA,CAAA,GAAI,MAAM,UAAA,CAAW,OAAA,EAAS,UAAA,EAAY;AAAA,QACtC,GAAG,IAAA;AAAA,QACH,KAAA,EAAO,EAAA;AAAA,QACP,GAAI,UAAA,GAAa,EAAE,UAAA,KAAe;AAAC,OACtC,CAAA;AAAA,IACL,SAAS,CAAA,EAAG;AACR,MAAA,IAAI,EAAE,CAAA,YAAa,mBAAA,CAAA,EAAsB,MAAM,CAAA;AAC/C,MAAA,SAAA,CAAU,GAAA,CAAI,MAAA,CAAO,OAAO,CAAC,CAAA;AAC7B,MAAA,IAAI,OAAO,OAAA,CAAQ,OAAA,KAAY,QAAA,EAAU,cAAA,GAAiB,IAAA;AAC1D,MAAA;AAAA,IACJ;AACA,IAAA,IAAI,CAAC,EAAE,EAAA,EAAI;AACX,IAAA,IAAI,CAAA,CAAE,WAAA,IAAe,OAAA,CAAQ,OAAA,EAAS;AAClC,MAAA,OAAA,CAAQ,GAAA,CAAI,QAAQ,OAAO,CAAA;AAC3B,MAAA;AAAA,IACJ;AACA,IAAA,MAAM,QAAA,GAAW,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,MAAM,CAAA;AACtC,IAAA,IAAI,CAAC,QAAA,IAAY,EAAA,CAAG,UAAA,GAAa,QAAA,CAAS,MAAM,UAAA,EAAY;AACxD,MAAA,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,MAAA,EAAQ,EAAE,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,KAAA,EAAO,EAAA,EAAI,CAAA;AAAA,IACzE;AAAA,EACJ;AACA,EAAA,OAAO;AAAA,IACH,OAAO,iBAAA,CAAkB,CAAC,GAAG,QAAA,CAAS,QAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,MAAM,CAAC,OAAA,CAAQ,IAAI,CAAA,CAAE,MAAM,CAAC,CAAC,CAAA;AAAA,IACrF,SAAA,EAAW,CAAC,GAAG,SAAS,CAAA,CAAE,MAAA,CAAO,CAAC,EAAA,KAAO,CAAC,QAAA,CAAS,GAAA,CAAI,EAAE,CAAC,CAAA,CAAE,MAAA;AAAA,IAC5D,iBAAiB,CAAC;AAAA,GACtB;AACJ;;;ACjqCA,IAAA,wBAAA,GAAA;AAAA,EACI;AAAA,IACI,IAAA,EAAQ,uGAAA;AAAA,IACR,gBAAA,EAAoB,kEAAA;AAAA,IACpB,MAAA,EAAU,UAAA;AAAA,IACV,OAAA,EAAW,gEAAA;AAAA,IACX,WAAA,EAAe,IAAA;AAAA,IACf,QAAA,EAAY,oEAAA;AAAA,IACZ,KAAA,EAAS,kEAAA;AAAA,IACT,QAAA,EAAY,kEAAA;AAAA,IACZ,GAAA,EAAO;AAAA;AAEf,CAAA;;;ACwBO,IAAM,gBAAA,GAAsC,CAAC,qBAAqB;AAElE,IAAM,YAAA,GAAkC;AAAA,EAC3C,sBAAA;AAAA,EACA,eAAA;AAAA,EACA;AACJ;AAEA,IAAM,IAAA,GAAO,GAAA;AAEb,IAAM,mBAAA,GAAsB,EAAA;AAC5B,IAAM,WAAA,GAAc,CAAA;AAEpB,IAAM,aAAA,GAAgB,GAAA;AAsEf,IAAM,uBAAA,GAAkD;AAE/D,IAAM,WAAA,GAAc,CAAC,OAAA,KACjB,IAAI,IAAI,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,gBAAA,EAAkB,CAAC,CAAC,CAAC,CAAA;AAGvD,eAAe,OAAA,CACX,IAAA,EACA,KAAA,EACA,CAAA,EACA,QAAA,EAC4B;AAC5B,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAwB;AACzC,EAAA,IAAI,KAAA;AACJ,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,EAAU,CAAA,EAAA,EAAK;AAC/B,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,EAAO;AAAA,MAC1B,KAAA,EAAO,CAAC,KAAK,CAAA;AAAA,MACb,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,MACR,KAAA,EAAO,IAAA;AAAA,MACP,GAAI,KAAA,KAAU,MAAA,GAAY,EAAC,GAAI,EAAE,KAAA;AAAM,KAC1C,CAAA;AACD,IAAA,IAAI,CAAC,GAAA,CAAI,QAAA,EAAU,OAAO,IAAA;AAC1B,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,KAAA,MAAW,EAAA,IAAM,IAAI,MAAA,EAAQ;AACzB,MAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,EAAA,CAAG,EAAE,CAAA,EAAG;AAClB,QAAA,IAAA,CAAK,GAAA,CAAI,EAAA,CAAG,EAAA,EAAI,EAAE,CAAA;AAClB,QAAA,KAAA,EAAA;AAAA,MACJ;AACA,MAAA,KAAA,GAAQ,KAAA,KAAU,SAAY,EAAA,CAAG,UAAA,GAAa,KAAK,GAAA,CAAI,KAAA,EAAO,GAAG,UAAU,CAAA;AAAA,IAC/E;AAEA,IAAA,IAAI,GAAA,CAAI,OAAO,MAAA,GAAS,IAAA,SAAa,CAAC,GAAG,IAAA,CAAK,MAAA,EAAQ,CAAA;AACtD,IAAA,IAAI,KAAA,KAAU,GAAG,OAAO,IAAA;AAAA,EAC5B;AACA,EAAA,OAAO,IAAA;AACX;AAGA,eAAe,QAAA,CACX,IAAA,EACA,KAAA,EACA,CAAA,EACA,KAAA,EACqB;AACrB,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAwB;AACzC,EAAA,IAAI,KAAA;AACJ,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC5B,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACA,MAAA,GAAA,GAAM,MAAM,KAAK,KAAA,EAAO;AAAA,QACpB,KAAA,EAAO,CAAC,KAAK,CAAA;AAAA,QACb,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,QACR,KAAA,EAAO,IAAA;AAAA,QACP,GAAI,KAAA,KAAU,KAAA,CAAA,GAAY,EAAC,GAAI,EAAE,KAAA;AAAM,OAC1C,CAAA;AAAA,IACL,CAAA,CAAA,MAAQ;AACJ,MAAA;AAAA,IACJ;AACA,IAAA,KAAA,MAAW,EAAA,IAAM,IAAI,MAAA,EAAQ;AACzB,MAAA,IAAA,CAAK,GAAA,CAAI,EAAA,CAAG,EAAA,EAAI,EAAE,CAAA;AAClB,MAAA,KAAA,GAAQ,KAAA,KAAU,SAAY,EAAA,CAAG,UAAA,GAAa,KAAK,GAAA,CAAI,KAAA,EAAO,GAAG,UAAU,CAAA;AAAA,IAC/E;AACA,IAAA,IAAI,CAAC,GAAA,CAAI,QAAA,IAAY,GAAA,CAAI,MAAA,CAAO,SAAS,IAAA,EAAM;AAAA,EACnD;AACA,EAAA,OAAO,CAAC,GAAG,IAAA,CAAK,MAAA,EAAQ,CAAA;AAC5B;AAGA,SAAS,gBAAgB,MAAA,EAA8C;AACnE,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAwC;AACzD,EAAA,OAAO;AAAA,IACH,YAAY,MAAA,EAAQ;AAChB,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AAC3B,MAAA,IAAI,KAAK,OAAO,GAAA;AAChB,MAAA,IAAI,IAAA,CAAK,QAAQ,aAAA,EAAe,OAAO,QAAQ,MAAA,CAAO,IAAI,KAAA,CAAM,qBAAqB,CAAC,CAAA;AACtF,MAAA,MAAM,CAAA,GAAI,MAAA,CAAO,WAAA,CAAY,MAAM,CAAA;AACnC,MAAA,IAAA,CAAK,GAAA,CAAI,QAAQ,CAAC,CAAA;AAClB,MAAA,OAAO,CAAA;AAAA,IACX;AAAA,GACJ;AACJ;AAGA,SAAS,eAAA,CACL,MAAA,EACA,EAAA,EACA,MAAA,EACF;AACE,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAoB;AACtC,EAAA,MAAM,OAAA,GAAU,CAAC,EAAA,KAAmB;AAChC,IAAA,IAAI,CAAA,GAAI,KAAA,CAAM,GAAA,CAAI,EAAA,CAAG,EAAE,CAAA;AACvB,IAAA,IAAI,MAAM,MAAA,EAAW;AACjB,MAAA,CAAA,GAAI,QAAA;AACJ,MAAA,IAAI;AACA,QAAA,MAAM,CAAA,GAAI,UAAA,CAAW,EAAA,EAAI,MAAA,EAAQ,IAAI,MAAM,CAAA;AAC3C,QAAA,IAAI,CAAA,EAAG,MAAA,CAAO,IAAA,KAAS,SAAA,IAAa,EAAE,GAAA,EAAK;AACvC,UAAA,MAAM,OAAA,GAAU,cAAA;AAAA,YACZ,UAAA,CAAW,aAAa,CAAA,CAAE,GAAG,GAAG,SAAA,CAAU,CAAA,CAAE,MAAA,CAAO,OAAO,CAAC;AAAA,WAC/D,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,WAAW,CAAA;AAC1B,UAAA,IAAI,QAAQ,MAAA,EAAQ,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,GAAG,OAAO,CAAA;AAAA,QAC/C;AAAA,MACJ,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,KAAA,CAAM,GAAA,CAAI,EAAA,CAAG,EAAA,EAAI,CAAC,CAAA;AAAA,IACtB;AACA,IAAA,OAAO,CAAA;AAAA,EACX,CAAA;AACA,EAAA,OAAO,CAAC,CAAA,EAAe,CAAA,KACnB,QAAQ,CAAC,CAAA,GAAI,QAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,GAAK,EAAE,EAAA,GAAK,EAAA,GAAK,EAAE,EAAA,GAAK,CAAA,CAAE,KAAK,CAAA,GAAI,CAAA,CAAA;AACzE;AAGA,SAAS,UAAA,CACL,EAAA,EACA,MAAA,EACA,EAAA,EACA,MAAA,EAC+F;AAC/F,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACA,IAAA,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,OAAO,CAAA;AAAA,EACnC,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,IAAA;AAAA,EACX;AACA,EAAA,IAAI,CAAC,WAAW,OAAO,OAAA,KAAY,YAAY,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,EAAG,OAAO,IAAA;AAC9E,EAAA,MAAM,CAAA,GAAI,OAAA;AACV,EAAA,MAAM,cAAc,EAAA,KAAO,QAAA,GAAW,OAAO,GAAA,CAAI,EAAA,CAAG,EAAE,CAAA,GAAI,MAAA;AAC1D,EAAA,IAAI,WAAA,IAAe,CAAA,CAAE,CAAA,KAAM,CAAA,EAAG;AAE1B,IAAA,IAAI,SAAA,CAAU,CAAU,CAAA,KAAM,WAAA,CAAY,SAAS,CAAA,CAAE,QAAA,KAAa,MAAM,OAAO,IAAA;AAC/E,IAAA,IAAI,CAAA,CAAE,WAAW,MAAA,CAAO,WAAA,MAAiB,CAAA,CAAE,OAAA,KAAY,WAAA,CAAY,OAAA,EAAS,OAAO,IAAA;AACnF,IAAA,IAAI,OAAO,CAAA,CAAE,YAAA,KAAiB,QAAA,EAAU,OAAO,IAAA;AAC/C,IAAA,OAAO;AAAA,MACH,MAAA,EAAQ;AAAA,QACJ,IAAA,EAAM,SAAA;AAAA,QACN,SAAS,WAAA,CAAY,OAAA;AAAA,QACrB,aAAa,CAAA,CAAE,YAAA;AAAA,QACf,WAAW,OAAO,CAAA,CAAE,UAAA,KAAe,QAAA,GAAW,EAAE,UAAA,GAAa,CAAA;AAAA,QAC7D,KAAA,EAAO;AAAA,UACH,UAAU,WAAA,CAAY,QAAA;AAAA,UACtB,OAAO,WAAA,CAAY,KAAA;AAAA,UACnB,KAAK,WAAA,CAAY,GAAA;AAAA,UACjB,UAAU;AAAC,SACf;AAAA,QACA,SAAS,WAAA,CAAY;AAAA,OACzB;AAAA,MACA,OAAA,EAAS,CAAA;AAAA,MACT,KAAK,WAAA,CAAY;AAAA,KACrB;AAAA,EACJ;AACA,EAAA,MAAM,MAAA,GACF,OAAO,QAAA,GACD,qBAAA,CAAsB,GAAG,MAAM,CAAA,GAC/B,4BAAA,CAA6B,CAAA,EAAG,MAAM,CAAA;AAChD,EAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,EAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,CAAA,EAAG,GAAA,EAAK,MAAA,CAAO,IAAA,KAAS,SAAA,GAAY,MAAA,CAAO,KAAA,CAAM,GAAA,GAAM,IAAA,EAAK;AAC1F;AAGA,eAAe,OAAA,CACX,MAAA,EACA,EAAA,EACA,IAAA,EAMM;AACN,EAAA,MAAM,IAAI,EAAA,KAAO,QAAA,GAAW,cAAc,MAAM,CAAA,GAAI,qBAAqB,MAAM,CAAA;AAC/E,EAAA,MAAM,CAAC,cAAA,EAAgB,UAAA,EAAY,GAAG,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,IACxD,OAAA,CAAQ,GAAA;AAAA,MAAA,CACH,IAAA,CAAK,mBAAmB,gBAAA,EAAkB,GAAA;AAAA,QAAI,CAAC,CAAA,KAC5C,OAAA,CAAQ,IAAA,CAAK,IAAA,EAAM,CAAA,EAAG,CAAA,EAAG,mBAAmB,CAAA,CAAE,KAAA,CAAM,MAAM,IAAI;AAAA;AAClE,KACJ;AAAA,IACA,OAAA,CAAQ,GAAA;AAAA,MAAA,CACH,IAAA,CAAK,WAAA,IAAe,YAAA,EAAc,GAAA,CAAI,CAAC,CAAA,KAAM,QAAA,CAAS,IAAA,CAAK,IAAA,EAAM,CAAA,EAAG,CAAA,EAAG,WAAW,CAAC;AAAA,KACxF;AAAA,IACA,IAAA,CAAK,GAAA,EAAI,CAAE,KAAA,CAAM,MAAM,IAAI;AAAA,GAC9B,CAAA;AACD,EAAA,IAAI,GAAA,KAAQ,MAAM,OAAO,IAAA;AACzB,EAAA,MAAM,oBAAoB,cAAA,CAAe,IAAA,CAAK,CAAC,CAAA,KAAM,MAAM,IAAI,CAAA;AAC/D,EAAA,MAAM,cAAc,IAAI,GAAA,CAAI,cAAA,CAAe,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,IAAK,EAAE,EAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,EAAE,CAAC,CAAA;AACnF,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAwB;AACxC,EAAA,KAAA,MAAW,EAAA,IAAM,CAAC,GAAG,cAAA,CAAe,QAAQ,CAAC,CAAA,KAAM,CAAA,IAAK,EAAE,CAAA,EAAG,GAAG,UAAA,CAAW,MAAM,CAAA;AAC7E,IAAA,GAAA,CAAI,GAAA,CAAI,EAAA,CAAG,EAAA,EAAI,EAAE,CAAA;AAErB,EAAA,MAAM,OAAA,GAAU,eAAA,CAAgB,IAAA,CAAK,OAAO,CAAA;AAC5C,EAAA,MAAM,MAAoB,EAAC;AAI3B,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,IAAA,CAAK,MAAA,IAAU,uBAAuB,CAAA;AACjE,EAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,MAAA,EAAQ,EAAA,EAAI,MAAM,CAAA;AACnD,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,EAAe,CAAA,KAC1B,OAAO,CAAC,WAAA,CAAY,GAAA,CAAI,CAAA,CAAE,EAAE,CAAC,IAAI,MAAA,CAAO,CAAC,YAAY,GAAA,CAAI,CAAA,CAAE,EAAE,CAAC,CAAA,IAAK,QAAA,CAAS,CAAA,EAAG,CAAC,CAAA;AACpF,EAAA,KAAA,MAAW,EAAA,IAAM,CAAC,GAAG,GAAA,CAAI,QAAQ,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA,EAAG;AAC5C,IAAA,IAAI,GAAG,IAAA,KAAS,KAAA,IAAS,CAAC,IAAA,CAAK,WAAA,CAAY,EAAE,CAAA,EAAG;AAChD,IAAA,MAAM,CAAA,GAAI,UAAA,CAAW,EAAA,EAAI,MAAA,EAAQ,IAAI,MAAM,CAAA;AAC3C,IAAA,IAAI,CAAC,CAAA,EAAG;AACR,IAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,EAAQ,GAAI,CAAA;AAE5B,IAAA,MAAM,MAAA,GAAS,CAAC,iBAAA,IAAqB,WAAA,CAAY,IAAI,EAAA,CAAG,EAAE,IAAI,WAAA,GAAc,QAAA;AAC5E,IAAA,IAAI,MAAA,CAAO,SAAS,WAAA,EAAa;AAC7B,MAAA,GAAA,CAAI,IAAA,CAAK;AAAA,QACL,MAAA,EAAQ;AAAA,UACJ,IAAA,EAAM,WAAA;AAAA,UACN,SAAS,MAAA,CAAO,OAAA;AAAA,UAChB,KAAK,EAAA,CAAG,MAAA;AAAA,UACR,WAAW,MAAA,CAAO,SAAA;AAAA,UAClB,MAAM,MAAA,CAAO,IAAA;AAAA,UACb;AAAA,SACJ;AAAA,QACA,KAAA,EAAO,EAAA;AAAA,QACP,OAAA;AAAA,QACA,KAAA,EAAO;AAAA,OACV,CAAA;AACD,MAAA;AAAA,IACJ;AAEA,IAAA,IAAI,EAAA,CAAG,MAAA,KAAW,MAAA,CAAO,WAAA,EAAa;AACtC,IAAA,MAAM,SAAuB,MAAM,eAAA;AAAA,MAC/B,OAAO,KAAA,CAAM,GAAA;AAAA,MACb,MAAA,CAAO,OAAA;AAAA,MACP;AAAA,KACJ;AACA,IAAA,MAAM,WAAW,EAAC;AAClB,IAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,KAAA,CAAM,QAAA,EAAU;AACnC,MAAA,MAAM,KAAK,SAAA,CAAU;AAAA,QACjB,OAAO,MAAA,CAAO,OAAA;AAAA,QACd,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,UAAU,CAAA,CAAE,QAAA;AAAA,QACZ,OAAO,CAAA,CAAE;AAAA,OACZ,CAAA;AACD,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACV,SAAA,EAAW,EAAA;AAAA,QACX,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,UAAU,CAAA,CAAE,QAAA;AAAA,QACZ,QAAQ,MAAM,eAAA,CAAgB,CAAA,CAAE,GAAA,EAAK,IAAI,OAAO;AAAA,OACnD,CAAA;AAAA,IACL;AACA,IAAA,GAAA,CAAI,IAAA,CAAK;AAAA,MACL,MAAA,EAAQ;AAAA,QACJ,IAAA,EAAM,SAAA;AAAA,QACN,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,KAAK,EAAA,CAAG,MAAA;AAAA,QACR,WAAW,MAAA,CAAO,SAAA;AAAA,QAClB,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,QAAA,EAAU,OAAO,KAAA,CAAM,QAAA;AAAA,QACvB,MAAA;AAAA,QACA,QAAA;AAAA,QACA;AAAA,OACJ;AAAA,MACA,KAAA,EAAO,EAAA;AAAA,MACP,OAAA;AAAA,MACA,OAAO,MAAA,CAAO;AAAA,KACjB,CAAA;AAAA,EACL;AACA,EAAA,OAAO,EAAE,OAAA,EAAS,GAAA,EAAK,mBAAmB,GAAA,EAAK,IAAA,EAAM,IAAI,IAAA,EAAK;AAClE;AAGA,SAAS,OAAO,GAAA,EAAa;AACzB,EAAA,OAAO,CAAC,CAAA,KAAkB;AACtB,IAAA,IAAI,CAAA,CAAE,MAAA,CAAO,IAAA,KAAS,WAAA,EAAa,OAAO,IAAA;AAC1C,IAAA,MAAM,CAAA,GAAI,EAAE,MAAA,CAAO,MAAA;AACnB,IAAA,MAAM,CAAA,GAAI,MAAM,IAAA,GAAO,IAAA,GAAO,OAAO,CAAA,KAAM,QAAA,GAAW,IAAI,CAAA,CAAE,MAAA;AAC5D,IAAA,OAAO,CAAA,KAAM,IAAA,IAAQ,GAAA,GAAM,CAAA,GAAI,CAAA,IAAK,YAAA;AAAA,EACxC,CAAA;AACJ;AAGA,SAAS,SAAS,OAAA,EAAmD;AACjE,EAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,IACX,CAAC,IAAA,EAAM,CAAA,KAAO,CAAC,IAAA,IAAQ,CAAA,CAAE,MAAA,CAAO,SAAA,GAAY,IAAA,CAAK,MAAA,CAAO,SAAA,GAAY,CAAA,GAAI,IAAA;AAAA,IACxE;AAAA,GACJ;AACJ;AAiBA,eAAe,OAAA,CAAQ,GAAA,EAAgB,OAAA,EAAiB,IAAA,EAAuC;AAC3F,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,WAAA,CAAY,CAAA,CAAE,MAAA,CAAO,OAAA,EAAS,OAAO,CAAC,CAAA;AAC7E,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,GAAA,CAAI,iBAAA,GAAoB,EAAE,IAAA,EAAM,MAAA,EAAO,GAAI,EAAE,IAAA,EAAM,YAAA,EAAa;AAC9F,EAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AACzC,EAAA,IAAI,IAAA,KAAS,WAAA,EAAa,OAAO,EAAE,MAAM,YAAA,EAAa;AACtD,EAAA,MAAM,QAAQ,QAAA,CAAS,IAAA,CAAK,OAAO,CAAC,CAAA,KAAM,KAAK,QAAA,CAAS,CAAA,CAAE,MAAA,CAAO,GAAG,CAAC,CAAA,CAAE,MAAA,CAAO,OAAO,GAAA,CAAI,GAAG,CAAC,CAAC,CAAA;AAC9F,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,GAAA,CAAI,iBAAA,GAAoB,EAAE,IAAA,EAAM,MAAA,EAAO,GAAI,EAAE,IAAA,EAAM,YAAA,EAAa;AACnF,EAAA,IAAI,KAAA,CAAM,OAAO,IAAA,KAAS,WAAA;AACtB,IAAA,OAAO,EAAE,MAAM,WAAA,EAAa,KAAA,EAAO,MAAM,KAAA,EAAO,IAAA,EAAM,KAAA,CAAM,MAAA,CAAO,IAAA,EAAK;AAC5E,EAAA,IAAI,CAAC,KAAA,CAAM,KAAA,EAAO,OAAO,EAAE,MAAM,YAAA,EAAa;AAC9C,EAAA,OAAO;AAAA,IACH,IAAA,EAAM,SAAA;AAAA,IACN,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,OAAA,EAAS,MAAM,MAAA,CAAO,OAAA;AAAA,IACtB,OAAO,KAAA,CAAM;AAAA,GACjB;AACJ;AAOA,eAAsB,gBAAA,CAClB,MAAA,EACA,EAAA,EACA,OAAA,EACA,IAAA,EACqB;AACrB,EAAA,IAAI;AACA,IAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,MAAA,EAAQ,IAAI,IAAI,CAAA;AAC1C,IAAA,OAAO,GAAA,GAAM,MAAM,OAAA,CAAQ,GAAA,EAAK,SAAS,IAAI,CAAA,GAAI,EAAE,IAAA,EAAM,YAAA,EAAa;AAAA,EAC1E,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,EAAE,MAAM,YAAA,EAAa;AAAA,EAChC;AACJ;AAGA,eAAsB,gBAAA,CAClB,MAAA,EACA,EAAA,EACA,OAAA,EACA,IAAA,EACsD;AACtD,EAAA,MAAM,UAAA,GAAa;AAAA,IACf,MAAA,EAAQ,EAAE,MAAA,EAAQ,kBAAA,EAA4B;AAAA,IAC9C,KAAA,EAAO,EAAE,IAAA,EAAM,YAAA;AAAsB,GACzC;AACA,EAAA,IAAI;AACA,IAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,MAAA,EAAQ,IAAI,IAAI,CAAA;AAC1C,IAAA,IAAI,CAAC,KAAK,OAAO,UAAA;AACjB,IAAA,MAAM,IAAA,uBAAW,GAAA,EAA6C;AAC9D,IAAA,MAAM,IAAA,GAAiB;AAAA,MACnB,GAAG,IAAA;AAAA,MACH,SAAA,EAAW,CAAC,CAAA,KAAM;AACd,QAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA;AAC/C,QAAA,OAAO,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,MACrB;AAAA,KACJ;AACA,IAAA,OAAO,EAAE,MAAA,EAAQ,MAAM,aAAA,CAAc,GAAA,EAAK,IAAI,CAAA,EAAG,KAAA,EAAO,MAAM,OAAA,CAAQ,GAAA,EAAK,OAAA,EAAS,IAAI,CAAA,EAAE;AAAA,EAC9F,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,UAAA;AAAA,EACX;AACJ;AAGA,eAAsB,sBAAA,CAClB,MAAA,EACA,EAAA,EACA,IAAA,EACqB;AACrB,EAAA,IAAI;AACA,IAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,MAAA,EAAQ,IAAI,IAAI,CAAA;AAC1C,IAAA,OAAO,GAAA,GAAM,MAAM,aAAA,CAAc,GAAA,EAAK,IAAI,CAAA,GAAI,EAAE,QAAQ,kBAAA,EAAmB;AAAA,EAC/E,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,EAAE,QAAQ,kBAAA,EAAmB;AAAA,EACxC;AACJ;AAEA,eAAe,aAAA,CAAc,KAAgB,IAAA,EAAuC;AAChF,EAAA,MAAM,EAAE,OAAA,EAAS,iBAAA,EAAmB,GAAA,EAAK,MAAK,GAAI,GAAA;AAElD,EAAA,IAAI,IAAA,KAAS,CAAA;AACT,IAAA,OAAO,oBAAoB,EAAE,MAAA,EAAQ,aAAY,GAAI,EAAE,QAAQ,kBAAA,EAAmB;AAEtF,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAsB;AACxC,EAAA,MAAM,MAAA,GAAS,oBACT,gBAAA,GACA;AAAA,IACI,GAAG,gBAAA;AAAA;AAAA,IAEH,MAAA,EAAQ;AAAA,MACJ,YAAA,EAAc,iBAAiB,MAAA,CAAO,iBAAA;AAAA,MACtC,SAAA,EAAW,iBAAiB,MAAA,CAAO,cAAA;AAAA,MACnC,iBAAA,EAAmB,iBAAiB,MAAA,CAAO,iBAAA;AAAA,MAC3C,cAAA,EAAgB,iBAAiB,MAAA,CAAO;AAAA;AAC5C,GACJ;AACN,EAAA,MAAM,MAAM,MAAM,gBAAA;AAAA,IACd,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,MAAM,CAAA;AAAA,IAC3B,GAAA;AAAA,IACA;AAAA,MACI,SAAA,EAAW,OAAO,OAAA,KAAY;AAC1B,QAAA,MAAMC,KAAAA,GAAO,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AACzC,QAAA,IAAIA,KAAAA,KAAS,WAAA,EAAa,KAAA,CAAM,GAAA,CAAI,SAASA,KAAI,CAAA;AACjD,QAAA,OAAOA,KAAAA;AAAA,MACX,CAAA;AAAA,MACA,IAAA,EAAM,CAAC,QAAA,KAAa,IAAA,CAAK,KAAK,QAAQ;AAAA,KAC1C;AAAA,IACA;AAAA,GACJ;AACA,EAAA,IAAI,IAAI,MAAA,KAAW,OAAA,SAAgB,EAAE,MAAA,EAAQ,IAAI,MAAA,EAAO;AAExD,EAAA,MAAM,OAAO,KAAA,CAAM,GAAA,CAAI,GAAA,CAAI,MAAM,KAAK,EAAC;AACvC,EAAA,MAAM,WAAW,OAAA,CAAQ,MAAA;AAAA,IACrB,CAAC,CAAA,KACG,CAAA,CAAE,OAAO,IAAA,KAAS,SAAA,IAClB,EAAE,MAAA,CAAO,OAAA,KAAY,IAAI,MAAA,IACzB,CAAA,CAAE,OAAO,OAAA,KAAY,GAAA,CAAI,WACzB,MAAA,CAAO,GAAG,EAAE,CAAC;AAAA,GACrB;AACA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,IAAA,CAAK,QAAA,CAAS,CAAA,CAAE,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAE1E,EAAA,MAAM,UAAU,QAAA,CACX,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,OAAO,IAAA,KAAS,SAAA,GAAY,EAAE,MAAA,CAAO,MAAA,GAAS,IAAK,CAAA,CACjE,MAAA,CAAO,CAAC,CAAA,KAAmB,OAAO,MAAM,QAAQ,CAAA;AACrD,EAAA,IAAI,CAAC,KAAA,IAAS,CAAC,KAAA,CAAM,KAAA,IAAS,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,EAAE,MAAA,EAAQ,kBAAA,EAAmB;AACxF,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,GAAG,OAAO,CAAA;AAClC,EAAA,OAAO;AAAA,IACH,MAAA,EAAQ,OAAA;AAAA,IACR,QAAQ,GAAA,CAAI,MAAA;AAAA,IACZ,SAAS,GAAA,CAAI,OAAA;AAAA,IACb,MAAM,GAAA,CAAI,IAAA;AAAA,IACV,SAAS,EAAE,KAAA,EAAO,MAAM,KAAA,EAAO,OAAA,EAAS,MAAM,OAAA,EAAQ;AAAA,IACtD,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,MAAA;AAAA,IACA;AAAA,GACJ;AACJ;AAEA,IAAM,SAAA,GAAY,mBAAA;AAGX,SAAS,cAAc,CAAA,EAAoB;AAC9C,EAAA,OAAO,SAAA,CAAU,KAAK,CAAC,CAAA;AAC3B;AAEA,IAAM,mBAAmB,EAAA,GAAK,IAAA;AAC9B,IAAM,kBAAA,GAAqB,6DAAA;AAIpB,SAAS,WAAW,CAAA,EAAyB;AAChD,EAAA,OAAO,OAAO,MAAM,QAAA,IAAY,CAAA,CAAE,UAAU,gBAAA,IAAoB,kBAAA,CAAmB,KAAK,CAAC,CAAA;AAC7F;ACpiBO,SAAS,kBAAkB,OAAA,EAAyB;AACvD,EAAA,OAAO,kBAAkB,OAAO,CAAA,CAAA;AACpC;AAGO,SAAS,WAAW,SAAA,EAA2B;AAClD,EAAA,OAAO,QAAQ,SAAS,CAAA,GAAI,kBAAkB,SAAS,CAAA,GAAI,kBAAkB,SAAS,CAAA;AAC1F;AASO,SAAS,oBAAA,CAAqB,QAAA,EAAwC,GAAA,mBAAY,IAAI,MAAK,EAAa;AAC3G,EAAA,MAAM,QAAQ,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,EAAE,OAAO,CAAA;AAC/C,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,KAAA,CAAM,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AACtD,EAAA,MAAM,WAAW,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,CAAC,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,SAAS,CAAC,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,EAAE,WAAW,CAAA;AACzG,EAAA,OAAO,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAGC,iBAAAA,CAAkB,OAAO,EAAE,GAAA,EAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,CAAA,EAAG,GAAG,QAAQ,CAAC,CAAC,CAAA;AACrG;AAiCO,SAAS,WAAA,CAAY,QAAsB,IAAA,EAAsC;AACpF,EAAA,MAAM,GAAA,GAAM,MAAO,IAAA,CAAK,GAAA,GAAM,KAAK,GAAA,EAAI,uBAAQ,IAAA,EAAK;AACpD,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAsC;AACzD,EAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAAc;AAC3B,IAAA,IAAI,CAAC,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,SAAU,GAAA,CAAI,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAC3C,IAAA,OAAO,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,EACvB,CAAA;AAGA,EAAA,MAAM,IAAA,GAAO,OAAO,CAAA,KAAc;AAC9B,IAAA,MAAM,EAAE,MAAA,EAAQ,WAAA,EAAY,GAAI,MAAM,QAAQ,CAAC,CAAA;AAC/C,IAAA,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,eAAA,CAAgB,WAAW,CAAA,GAAI,CAAA,EAAG,KAAA,EAAO,cAAA,CAAe,WAAW,CAAA,EAAG,KAAA,EAAO,YAAY,MAAA,EAAO;AAAA,EAC/H,CAAA;AACA,EAAA,MAAM,QAAA,GAAW,OAAO,OAAA,KAAoB;AACxC,IAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAU,OAAM,GAAI,MAAM,KAAK,OAAO,CAAA;AACtD,IAAA,OAAO;AAAA,MACH,QAAA;AAAA,MACA,KAAA;AAAA,MACA,QAAA,EAAU,MAAM,mBAAA,CAAoB,MAAA,EAAQ,SAAS,EAAE,YAAA,EAAc,IAAA,CAAK,YAAA,EAAc;AAAA,KAC5F;AAAA,EACJ,CAAA;AACA,EAAA,MAAM,aAAA,GAAgB,OAAO,KAAA,KAAkB;AAC3C,IAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAU,OAAM,GAAI,MAAM,KAAK,KAAK,CAAA;AAEpD,IAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,QAAQ,MAAA,CAAO,MAAA,CAAO,gBAAgB,CAAA,EAAE;AAAA,EACtE,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,OAAO,SAAA,KAAuD;AAC5E,IAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACpB,MAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAM,GAAI,MAAM,cAAc,SAAS,CAAA;AACvD,MAAA,IAAI,CAAC,OAAO,OAAO,WAAA;AACnB,MAAA,MAAM,IAAA,GAAO,OAAO,MAAA,GAAS,CAAA,GAAI,MAAM,IAAA,CAAK,QAAA,KAAa,EAAC;AAC1D,MAAA,OAAO,kBAAA,CAAmB,QAAQ,SAAA,EAAW,IAAI,EAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,CAAA;AAAA,IAC/E;AACA,IAAA,MAAM,CAAA,GAAI,MAAM,QAAA,CAAS,SAAS,CAAA;AAClC,IAAA,IAAI,CAAC,CAAA,CAAE,KAAA,EAAO,OAAO,WAAA;AACrB,IAAA,OAAO,eAAe,CAAA,CAAE,QAAA,EAAU,EAAE,GAAA,EAAK,GAAA,IAAO,CAAA;AAAA,EACpD,CAAA;AACA,EAAA,OAAO;AAAA,IACH,SAAA;AAAA,IACA,MAAM,OAAA,CAAQ,MAAA,EAAQ,SAAA,EAAW;AAC7B,MAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,SAAS,CAAA;AACtC,MAAA,IAAI,SAAS,WAAA,EAAa;AACtB,QAAA,MAAM,EAAE,QAAA,EAAU,KAAA,EAAM,GAAI,MAAM,KAAK,SAAS,CAAA;AAChD,QAAA,MAAM,IAAI,mBAAA;AAAA,UACN,WACM,CAAA,WAAA,EAAc,SAAA,CAAU,KAAK,CAAC,CAAA,IAAA,EAAO,KAAK,CAAA,mFAAA,CAAA,GAC1C;AAAA,SACV;AAAA,MACJ;AACA,MAAA,OAAO,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA,IAC/B,CAAA;AAAA;AAAA;AAAA,IAGA,MAAM,SAAS,CAAA,EAAG;AACd,MAAA,IAAI,CAAA,CAAE,SAAS,KAAA,EAAO;AAClB,QAAA,MAAM,CAAA,GAAI,MAAM,QAAA,CAAS,CAAA,CAAE,SAAS,CAAA;AACpC,QAAA,IAAI,CAAC,CAAA,CAAE,QAAA,EAAU,OAAO,SAAA;AACxB,QAAA,IAAI,CAAC,eAAe,CAAA,EAAG,CAAA,CAAE,UAAU,GAAA,EAAK,GAAG,OAAO,SAAA;AAClD,QAAA,OAAO,CAAA,CAAE,QAAQ,MAAA,GAAS,SAAA;AAAA,MAC9B;AACA,MAAA,MAAM,EAAE,QAAQ,QAAA,EAAU,KAAA,KAAU,MAAM,aAAA,CAAc,EAAE,SAAS,CAAA;AACnE,MAAA,IAAI,CAAC,UAAU,OAAO,SAAA;AACtB,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,QAAA,EAAS;AACjC,MAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,SAAA;AAC9B,MAAA,IAAI,qBAAA,CAAsB,CAAA,EAAG,MAAA,EAAQ,IAAI,GAAG,OAAO,SAAA;AACnD,MAAA,OAAO,QAAQ,MAAA,GAAS,SAAA;AAAA,IAC5B,CAAA;AAAA,IACA,MAAM,cAAc,SAAA,EAAW;AAC3B,MAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACpB,QAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAU,OAAM,GAAI,MAAM,cAAc,SAAS,CAAA;AACjE,QAAA,MAAM,IAAA,GAAO,OAAO,MAAA,GAAS,CAAA,GAAI,MAAM,IAAA,CAAK,QAAA,KAAa,EAAC;AAC1D,QAAA,OAAO,EAAE,MAAM,oBAAA,CAAqB,MAAA,EAAQ,WAAW,IAAI,CAAA,EAAG,UAAU,KAAA,EAAM;AAAA,MAClF;AACA,MAAA,MAAM,CAAA,GAAI,MAAM,QAAA,CAAS,SAAS,CAAA;AAClC,MAAA,OAAO,EAAE,IAAA,EAAM,oBAAA,CAAqB,CAAA,CAAE,QAAA,EAAU,GAAA,EAAK,CAAA,EAAG,QAAA,EAAU,CAAA,CAAE,QAAA,EAAU,KAAA,EAAO,EAAE,KAAA,EAAM;AAAA,IACjG;AAAA,GACJ;AACJ;AAOA,eAAsB,aAAA,CAClB,OAAA,EACA,QAAA,EACA,OAAA,EACsB;AACtB,EAAA,MAAM,MAAA,GAAS,kBAAkB,EAAE,CAAA;AACnC,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAY;AACnC,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACtB,IAAA,IAAI,CAAA,CAAE,SAAS,KAAA,IAAS,CAAA,CAAE,WAAW,OAAA,IAAW,CAAC,gBAAA,CAAiB,CAAC,CAAA,EAAG;AACtE,IAAA,MAAM,CAAA,GAAI,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,CAAA,KAAM,GAAG,CAAA,GAAI,CAAC,CAAA,IAAK,EAAA;AACnD,IAAA,IAAI,CAAC,CAAA,CAAE,UAAA,CAAW,MAAM,CAAA,EAAG;AAC3B,IAAA,MAAM,OAAA,GAAU,CAAA,CAAE,KAAA,CAAM,MAAA,CAAO,MAAM,CAAA;AACrC,IAAA,IAAI,WAAW,CAAC,OAAA,CAAQ,OAAO,CAAA,EAAG,UAAA,CAAW,IAAI,OAAO,CAAA;AAAA,EAC5D;AACA,EAAA,KAAA,MAAW,WAAW,CAAC,GAAG,UAAU,CAAA,CAAE,MAAK,EAAG;AAC1C,IAAA,IAAI,MAAM,OAAA,CAAQ,OAAA,EAAS,OAAO,GAAG,OAAO,OAAA;AAAA,EAChD;AACA,EAAA,OAAO,IAAA;AACX","file":"index.mjs","sourcesContent":["// An inline file attachment (SPEC §5.1, §8.3.2). Its bytes are attacker-influenced,\n// and on a public channel post they are fully attacker-chosen.\n\nexport interface Attachment {\n /** Original file name. */\n name: string;\n /** MIME type, untrusted off the wire. */\n type: string;\n /** Raw byte size (before base64). */\n size: number;\n /** base64 of the raw file bytes. */\n data: string;\n}\n\n/** Hard ceiling for an inline attachment (~100KB, ~135KB base64), whatever its source. */\nexport const MAX_ATTACHMENT_BYTES = 100 * 1024;\n\n/** Is a parsed attachment the §5.1 shape, real base64 and within the byte cap?\n * A post whose attachment fails is malformed and never renders. */\nexport function isValidAttachment(a: unknown): a is Attachment {\n if (!a || typeof a !== 'object') return false;\n const o = a as Record<string, unknown>;\n if (typeof o.name !== 'string' || typeof o.type !== 'string') return false;\n if (typeof o.size !== 'number' || !(o.size >= 0 && o.size <= MAX_ATTACHMENT_BYTES)) return false;\n if (typeof o.data !== 'string') return false;\n if (o.data.length > Math.ceil((MAX_ATTACHMENT_BYTES * 4) / 3) + 8) return false;\n // atob throws on a string that is not base64, which would crash a feed at render time.\n try {\n if (atob(o.data).length > MAX_ATTACHMENT_BYTES) return false;\n } catch {\n return false;\n }\n return true;\n}\n","// The canonical bytes OC Chat hashes for channel descriptors and posts (SPEC §0):\n// keys sorted at every depth, compact, LF-terminated. Arrays keep their order.\n\nimport { b64urlEncode, utf8Encode } from '@orangecheck/lock-crypto';\n\nexport function canonicalBytes(value: unknown): Uint8Array {\n const sort = (v: unknown): unknown => {\n if (Array.isArray(v)) return v.map(sort);\n if (v && typeof v === 'object') {\n const out: Record<string, unknown> = {};\n for (const k of Object.keys(v as Record<string, unknown>).sort()) {\n out[k] = sort((v as Record<string, unknown>)[k]);\n }\n return out;\n }\n return v;\n };\n return utf8Encode(JSON.stringify(sort(value)) + '\\n');\n}\n\n/** base64url without padding, the d-tag suffix encoding. */\nexport function b64urlNoPad(bytes: Uint8Array): string {\n return b64urlEncode(bytes).replace(/=+$/, '');\n}\n","import { verifyNostrEvent, type NostrEvent } from '@orangecheck/lock-device';\n\nexport type { NostrEvent };\nexport { verifyNostrEvent };\n\n/** NIP-01 holds and the event is signed by `pubkey`. */\nexport function signedBy(ev: NostrEvent, pubkey: string): boolean {\n return ev.pubkey === pubkey && verifyNostrEvent(ev);\n}\n","// did:oc session devices (SPEC §8.6): the auth host's vouch that binds a device\n// key to a did:oc, the host's signed revocations, and which keys stand.\n//\n// A session record has no BIP-322 signature, and its Nostr self-signature\n// proves only that SOME key published it. What binds it to a did:oc is the\n// auth host (ochk.io), the named trust anchor, signing the exact (did_oc,\n// device_pk, nostr_pk, device_id) after the device proved it holds the Nostr\n// key. This tier is not offline-verifiable and not Bitcoin-load-bearing.\n// The caller supplies the host's published keys.\n\nimport { ed25519 } from '@noble/curves/ed25519';\nimport { utf8Encode } from '@orangecheck/lock-crypto';\nimport { DEVICE_KIND, type NostrEvent } from '@orangecheck/lock-device';\n\nimport { verifyNostrEvent } from './event';\n\nexport const AUTH_HOST_JWKS_URL = 'https://ochk.io/.well-known/jwks.json';\nexport const VOUCH_JWS_TYP = 'oc-chat-device-vouch';\nexport const REVOCATION_JWS_TYP = 'oc-chat-device-revoke';\n\n/** The d-tag a did:oc's session device records are published under. */\nexport function sessionDeviceDtag(didOc: string): string {\n return `oc-chat:device:${didOc}`;\n}\n\nexport interface VouchSubject {\n didOc: string;\n device_pk: string;\n nostr_pk: string;\n device_id: string;\n}\n\nexport interface AuthHostKey {\n kid?: string;\n kty?: string;\n crv?: string;\n x?: string;\n /** A key rotated out: it verifies only what it signed before `retired_at`. */\n status?: string;\n retired_at?: number;\n}\n\nfunction fields(ns: string, s: VouchSubject): string[] {\n return [\n ns,\n `did_oc: ${s.didOc}`,\n `device_pk: ${s.device_pk}`,\n `nostr_pk: ${s.nostr_pk}`,\n `device_id: ${s.device_id}`,\n ];\n}\n\n/** The request the device's Nostr key signs (proof of possession). */\nexport function vouchRequestStatement(s: VouchSubject): string {\n return fields('oc-chat:device-vouch-request:v1', s).join('\\n') + '\\n';\n}\n\nfunction b64urlDecode(s: string): Uint8Array {\n const b64 = s.replace(/-/g, '+').replace(/_/g, '/');\n const pad = b64.length % 4 === 0 ? '' : '='.repeat(4 - (b64.length % 4));\n const bin = atob(b64 + pad);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n/**\n * The plain-text statement of a host JWS of type `typ`, signed by a published\n * key, or null. A retired key counts only for a statement whose signed time\n * (`timeField`) is before its `retired_at` (SPEC §8.6).\n */\nfunction hostStatement(\n jws: string,\n typ: string,\n timeField: string,\n keys: readonly AuthHostKey[]\n): string[] | null {\n try {\n const parts = jws.split('.');\n if (parts.length !== 3) return null;\n const [h, p, sig] = parts as [string, string, string];\n const header = JSON.parse(new TextDecoder().decode(b64urlDecode(h))) as Record<\n string,\n unknown\n >;\n if (header.alg !== 'EdDSA' || header.typ !== typ) return null;\n const key = keys.find(\n (k) => k.kty === 'OKP' && k.crv === 'Ed25519' && k.x && k.kid === header.kid\n );\n if (!key?.x) return null;\n if (!ed25519.verify(b64urlDecode(sig), utf8Encode(`${h}.${p}`), b64urlDecode(key.x))) {\n return null;\n }\n const lines = new TextDecoder().decode(b64urlDecode(p)).split('\\n');\n const at = lines.find((l) => l.startsWith(`${timeField}: `));\n const t = at ? Number(at.slice(timeField.length + 2)) : NaN;\n if (!/^\\d+$/.test(at?.slice(timeField.length + 2) ?? '')) return null;\n if (\n key.status === 'retired' &&\n !(typeof key.retired_at === 'number' && t < key.retired_at)\n ) {\n return null;\n }\n return lines;\n } catch {\n return null;\n }\n}\n\n/**\n * Does `vouch` — a compact JWS from the auth host — vouch for exactly this\n * subject? Checks the header, the Ed25519 signature against a published key\n * (a retired one only for a vouch issued before it retired), and every\n * statement field. Pure; the caller supplies the keys.\n */\nexport function verifySessionVouch(\n vouch: string,\n subject: VouchSubject,\n keys: readonly AuthHostKey[]\n): boolean {\n const lines = hostStatement(vouch, VOUCH_JWS_TYP, 'issued_at', keys);\n if (!lines) return false;\n const expected = fields('oc-chat:device-vouch:v1', subject);\n // The statement is the expected fields, an issued_at line, and the final LF.\n if (lines.length !== expected.length + 2) return false;\n for (let i = 0; i < expected.length; i++) if (lines[i] !== expected[i]) return false;\n return /^issued_at: \\d+$/.test(lines[expected.length]!) && lines.at(-1) === '';\n}\n\n/** Who a host-signed device revocation names (SPEC §8.6), or null if it does not verify. */\nexport function verifyHostRevocation(\n jws: string,\n keys: readonly AuthHostKey[]\n): {\n didOc: string;\n device_id: string;\n nostr_pk: string;\n revoked_at: number;\n statement: string;\n} | null {\n const lines = hostStatement(jws, REVOCATION_JWS_TYP, 'revoked_at', keys);\n if (!lines || lines[0] !== 'oc-chat:device-revoke:v1' || lines.at(-1) !== '') return null;\n // The signature covers every line. The named ones are read by name, once\n // each, and a line the host adds later is kept in the statement but not read.\n const field = (name: string) => {\n const found = lines.filter((l) => l.startsWith(`${name}: `));\n return found.length === 1 ? found[0]!.slice(name.length + 2) : null;\n };\n const didOc = field('did_oc');\n const device_id = field('device_id');\n const nostr_pk = field('nostr_pk');\n const at = field('revoked_at');\n const revoked_at = at === null ? NaN : Number(at);\n if (!didOc || !device_id || !nostr_pk || !Number.isFinite(revoked_at)) return null;\n return { didOc, device_id, nostr_pk, revoked_at, statement: lines.join('\\n') };\n}\n\n/** The signed issued_at of a vouch, read without verifying it (callers verify first). */\nexport function vouchIssuedAt(vouch: string): number | null {\n try {\n const p = vouch.split('.')[1] ?? '';\n const line = new TextDecoder()\n .decode(b64urlDecode(p))\n .split('\\n')\n .find((l) => l.startsWith('issued_at: '));\n const t = line ? Number(line.slice('issued_at: '.length)) : NaN;\n return Number.isFinite(t) ? t : null;\n } catch {\n return null;\n }\n}\n\n\nexport interface ParsedSessionDeviceEvent {\n /** The did:oc this device is published under. */\n didOc: string;\n device_id: string;\n device_pk: string;\n bindingStatement: string;\n revoked: boolean;\n createdAtUnix: number;\n nostrPubkey: string;\n eventId: string;\n /** The auth host's vouch, or null when the record carries none. */\n vouch: string | null;\n}\n\n/**\n * Parse a session device event. Unlike lock-device's parseDeviceEvent, this does\n * NOT require a non-empty binding_sig (session devices have none) and asserts\n * the `auth=session` tag so a lock-namespace record can never be parsed here.\n */\nexport function parseSessionDeviceEvent(event: NostrEvent): ParsedSessionDeviceEvent {\n if (event.kind !== DEVICE_KIND) {\n throw new Error('not a device event (kind mismatch)');\n }\n const tag = (name: string): string | null => {\n for (const t of event.tags) {\n if (t[0] === name && t.length > 1) return t[1] ?? null;\n }\n return null;\n };\n const didOc = tag('addr');\n const device_id = tag('device_id');\n const device_pk = tag('device_pk');\n if (!didOc || !device_id || !device_pk) {\n throw new Error('session device event missing required tags');\n }\n if (tag('auth') !== 'session') {\n throw new Error('not a session device event (auth tag mismatch)');\n }\n return {\n didOc,\n device_id,\n device_pk,\n bindingStatement: event.content,\n revoked: device_pk === 'revoked',\n createdAtUnix: event.created_at,\n nostrPubkey: event.pubkey,\n eventId: event.id,\n vouch: tag('vouch'),\n };\n}\n\n/** Every revocation of `didOc`'s session devices seen on any relay (SPEC §8.6). */\nexport interface SessionRevocations {\n /** \"nostr_pk:device_id\" of devices whose own key signed a revocation. */\n self: Set<string>;\n /** device_id → the latest host-signed revoked_at for it. */\n host: Map<string, number>;\n /** The nostr_pk each host revocation names. */\n hostNamed: Set<string>;\n}\n\nexport function sessionRevocations(\n events: readonly NostrEvent[],\n didOc: string,\n hostKeys: readonly AuthHostKey[]\n): SessionRevocations {\n const out: SessionRevocations = { self: new Set(), host: new Map(), hostNamed: new Set() };\n for (const e of events) {\n if (!verifyNostrEvent(e)) continue;\n const tag = (name: string) => e.tags.find((t) => t[0] === name)?.[1];\n const jws = tag('revocation');\n if (jws) {\n // Whatever key carried it: the host's signature is the authority. The\n // device is the one the statement names, whatever the other tags say;\n // only the d tag and addr must name this did:oc (SPEC §8.6).\n const r = verifyHostRevocation(jws, hostKeys);\n if (\n r &&\n r.statement === e.content &&\n r.didOc === didOc &&\n tag('d') === `oc-chat:device:${didOc}` &&\n tag('addr') === didOc\n ) {\n out.host.set(r.device_id, Math.max(out.host.get(r.device_id) ?? -1, r.revoked_at));\n out.hostNamed.add(r.nostr_pk);\n }\n continue;\n }\n try {\n const p = parseSessionDeviceEvent(e);\n if (p.revoked && p.didOc === didOc) out.self.add(`${e.pubkey}:${p.device_id}`);\n } catch {\n // not a session record\n }\n }\n return out;\n}\n\n/** Is this bind retired: by its own key, or by a host revocation dated at or\n * after its vouch was issued (both times the host's own)? */\nexport function sessionDeviceRevoked(\n d: { nostrPubkey: string; device_id: string; issuedAt: number | null },\n revs: SessionRevocations\n): boolean {\n if (revs.self.has(`${d.nostrPubkey}:${d.device_id}`)) return true;\n const at = revs.host.get(d.device_id);\n return at !== undefined && (d.issuedAt === null || d.issuedAt <= at);\n}\n\n/** The session records for `didOc` whose own signature and host vouch verify, revoked or not. */\nexport function vouchedSessionDevices(\n events: readonly NostrEvent[],\n didOc: string,\n hostKeys: readonly AuthHostKey[]\n): ParsedSessionDeviceEvent[] {\n const out: ParsedSessionDeviceEvent[] = [];\n for (const e of events) {\n try {\n const p = parseSessionDeviceEvent(e);\n if (p.revoked) continue;\n if (p.didOc !== didOc) continue; // namespace must match the queried did:oc\n if (!verifyNostrEvent(e)) continue; // integrity gate\n // The binding itself: the auth host vouched for this did:oc + keys.\n if (\n !p.vouch ||\n !verifySessionVouch(\n p.vouch,\n {\n didOc,\n device_pk: p.device_pk,\n nostr_pk: p.nostrPubkey,\n device_id: p.device_id,\n },\n hostKeys\n )\n ) {\n continue;\n }\n out.push(p);\n } catch {\n // skip malformed / non-session records\n }\n }\n return out;\n}\n\n/** The session devices that bind for `didOc` now: vouched, and retired by no revocation seen (§8.6). */\nexport function liveSessionDevices(\n events: readonly NostrEvent[],\n didOc: string,\n hostKeys: readonly AuthHostKey[]\n): ParsedSessionDeviceEvent[] {\n const revoked = sessionRevocations(events, didOc, hostKeys);\n return vouchedSessionDevices(events, didOc, hostKeys).filter(\n (p) =>\n !sessionDeviceRevoked(\n { ...p, issuedAt: p.vouch ? vouchIssuedAt(p.vouch) : null },\n revoked\n )\n );\n}\n\n/**\n * Every inbox key the auth host has vouched for `didOc`, revoked ones too. An\n * earlier channel version stands on its binding whatever became of the key\n * since (§8.3.1), so a version reader asks each. A device's own revocation\n * replaces its record at the relay, so for a device no record of which remains,\n * the key that carried it counts; a host revocation names its key.\n */\nexport function sessionKeysEverBound(\n events: readonly NostrEvent[],\n didOc: string,\n hostKeys: readonly AuthHostKey[]\n): string[] {\n const bound = vouchedSessionDevices(events, didOc, hostKeys);\n const boundIds = new Set(bound.map((p) => p.device_id));\n const revs = sessionRevocations(events, didOc, hostKeys);\n const replaced = [...revs.self]\n .map((s) => s.split(':') as [string, string])\n .filter(([, id]) => !boundIds.has(id))\n .map(([pk]) => pk);\n return [...new Set([...bound.map((p) => p.nostrPubkey), ...replaced, ...revs.hostNamed])];\n}\n","// A channel version's own proof of who signed it (SPEC §8.3.1, 0.3.0): the\n// kind-30078 device record carried in the version event's `binding` tag. An\n// earlier version stands on this proof alone; the last version of a chain also\n// needs it to be live, which is the one read that goes to the relays.\n\nimport {\n authorizedDevices,\n liveDevices,\n parseDeviceEvent,\n type NostrEvent,\n type ParsedDeviceEvent,\n} from '@orangecheck/lock-device';\n\nimport { verifyNostrEvent } from './event';\nimport { UnansweredReadError, type VerifyBip322 } from './read';\nimport {\n parseSessionDeviceEvent,\n sessionDeviceRevoked,\n sessionRevocations,\n verifySessionVouch,\n vouchIssuedAt,\n type AuthHostKey,\n} from './session';\n\n/** Who a version event's key is bound to, by the record in its `binding` tag. */\nexport type VersionBinding =\n | { kind: 'btc'; principal: string; pubkey: string; record: ParsedDeviceEvent }\n | {\n kind: 'session';\n principal: string;\n pubkey: string;\n deviceId: string;\n /** The vouch's signed issued_at (the host's clock). */\n issuedAt: number | null;\n };\n\nexport type Liveness = 'live' | 'revoked' | 'unknown';\n\n/** What reading a `binding` record needs: the host's keys (retired ones included) and a BIP-322 verifier. */\nexport interface BindingVerifiers {\n /** Throw UnansweredReadError when they could not be read; an empty list binds nothing. */\n hostKeys: () => Promise<readonly AuthHostKey[]>;\n verifyBip322: VerifyBip322;\n}\n\nconst bindingTag = (ev: NostrEvent): string | null =>\n ev.tags.find((t) => t[0] === 'binding')?.[1] ?? null;\n\n/** True when the version carries a `binding` tag, valid or not (0.3.0 and later). */\nexport function hasBindingTag(ev: NostrEvent): boolean {\n return bindingTag(ev) !== null;\n}\n\n/**\n * The principal the event's `binding` record binds its key to, or null when the\n * tag is absent or does not bind this key.\n */\nexport async function readVersionBinding(\n ev: NostrEvent,\n v: BindingVerifiers\n): Promise<VersionBinding | null> {\n const raw = bindingTag(ev);\n if (!raw) return null;\n let rec: NostrEvent;\n try {\n rec = JSON.parse(raw) as NostrEvent;\n } catch {\n return null;\n }\n return recordBinding(rec, ev.pubkey, v);\n}\n\n/** The principal a kind-30078 record binds `pubkey` to, or null. Throws\n * UnansweredReadError when the host's keys could not be read. */\nexport async function recordBinding(\n rec: NostrEvent,\n pubkey: string,\n v: BindingVerifiers\n): Promise<VersionBinding | null> {\n try {\n if (!rec || rec.kind !== 30078 || rec.pubkey !== pubkey || !verifyNostrEvent(rec)) return null;\n const auth = rec.tags.find((t) => t[0] === 'auth')?.[1];\n if (auth === 'session') {\n const p = parseSessionDeviceEvent(rec);\n if (p.revoked || !p.vouch) return null;\n const subject = {\n didOc: p.didOc,\n device_pk: p.device_pk,\n nostr_pk: rec.pubkey,\n device_id: p.device_id,\n };\n if (!verifySessionVouch(p.vouch, subject, await v.hostKeys())) return null;\n return {\n kind: 'session',\n principal: p.didOc,\n pubkey: rec.pubkey,\n deviceId: p.device_id,\n issuedAt: vouchIssuedAt(p.vouch),\n };\n }\n const p = parseDeviceEvent(rec);\n // Only a v3 statement signs the key that carries it (OC Lock SPEC §3.4).\n if (p.revoked || p.bindingVersion !== 'v3') return null;\n if (!authorizedDevices([p]).some((d) => d.nostrPubkey === pubkey)) return null;\n const ok = await v.verifyBip322({\n address: p.address,\n message: p.bindingStatement,\n signature: p.bindingSigBase64,\n });\n return ok === true ? { kind: 'btc', principal: p.address, pubkey, record: p } : null;\n } catch (e) {\n // A read with no answer (the host's keys) proves nothing: the caller hears it.\n if (e instanceof UnansweredReadError) throw e;\n return null;\n }\n}\n\n/** Is an address binding live, given every verified record seen for that address:\n * OC Lock's own rule, with the version's bind included so a relay dropping it\n * does not count as a revocation. */\nexport function btcBindingLive(\n b: Extract<VersionBinding, { kind: 'btc' }>,\n verified: readonly ParsedDeviceEvent[],\n now: Date\n): boolean {\n const live = authorizedDevices(liveDevices([...verified, b.record], { now }), { now });\n return live.some((d) => d.nostrPubkey === b.pubkey);\n}\n\n/** Is a session device revoked on any relay, by its own key or by the auth host (§8.6)? */\nexport function sessionBindingRevoked(\n b: Extract<VersionBinding, { kind: 'session' }>,\n events: readonly NostrEvent[],\n hostKeys: readonly AuthHostKey[]\n): boolean {\n return sessionDeviceRevoked(\n { nostrPubkey: b.pubkey, device_id: b.deviceId, issuedAt: b.issuedAt },\n sessionRevocations(events, b.principal, hostKeys)\n );\n}\n","// Channels (oc-chat-protocol SPEC §8.3) — the pure, offline-verifiable core.\n//\n// v1 = PUBLIC channels: a kind-30110 founder-rooted governance descriptor +\n// kind-30111 `chat-channel` posts + a Bitcoin-priced write gate. Private\n// channels (read:\"members\" + an encryption block + kind-30113 group keys) are\n// reserved behind the SAME descriptor (§8.3.7) and are NOT implemented here —\n// the v1 verifier rejects them as unsupported, never silently downgrades.\n//\n// A public channel makes NO E2EE claim (S-CH-4): it uses OC Lock *identity\n// binding* (BIP-322 device signatures via the kind-30078 record) + OC Chat's\n// *Bitcoin-priced access control*, not confidentiality. Posts are plaintext,\n// recipient-less (`recipients=[]` → E_CHANNEL_RECIPIENTS otherwise), and\n// content-addressed.\n//\n// Bitcoin-load-bearing axis (§8.3.3): ONLY `utxo-floor` (rooted:true) carries\n// the Bitcoin claim — a funded, aged UTXO has no Ed25519 analog, so spam is\n// priced in Bitcoin maturity. allowlist / founder / open are rooted:false (NOT\n// Bitcoin-load-bearing; rendered the muted \"via ochk.io\" tier). The\n// `write.rooted` flag MUST match the policy (E_CH_POLICY_INVALID), making the\n// Bitcoin claim a property of the artifact, not a UI label.\n//\n\n// Every read a verdict needs (bindings, liveness, the chain, BIP-322) is passed\n// in, so the same rules run in a browser, a relay's write gate or a terminal.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport { hexEncode, utf8Encode } from '@orangecheck/lock-crypto';\n\nimport { isValidAttachment, type Attachment } from './attachment';\nimport { b64urlNoPad, canonicalBytes } from './canonical';\nimport { signedBy, verifyNostrEvent, type NostrEvent } from './event';\nimport { answeredEvents, meetsReadFloor, UnansweredReadError, type Query, type VerifyBip322 } from './read';\nimport type { AuthHostKey } from './session';\nimport {\n hasBindingTag,\n readVersionBinding,\n type Liveness,\n type VersionBinding,\n} from './version-binding';\n\nexport const CHANNEL_DESCRIPTOR_KIND = 30110;\nexport const CHANNEL_POST_KIND = 30111;\n\nconst CH_DTAG_PREFIX = 'oc-lock-chat-ch:';\nconst POST_DTAG_PREFIX = 'oc-lock-chat-msg:';\nconst CH_SALT_LABEL = 'oc-lock-chat-ch/v1:';\n\n/** Slug: a NON-authoritative display label (S17). The trust root is the founder\n * address, never the slug. */\nconst SLUG_RE = /^[a-z0-9-]{3,48}$/;\n\n/** Wire-error + client-capability codes (§8.3 / §9). The first six are normative\n * protocol errors; `E_CH_UNSUPPORTED` is a v1-client capability signal (a\n * private-channel descriptor a public-only client can't render). */\nexport type ChannelError =\n | 'E_CHANNEL_RECIPIENTS'\n | 'E_CH_POLICY_INVALID'\n | 'E_CH_UNAUTHORIZED'\n | 'E_CH_WRITE_DENIED'\n | 'E_CH_NOT_WRITER'\n | 'E_CHAN_FLOOR'\n | 'E_CH_CLOSED'\n | 'E_CH_UNSUPPORTED';\n\n// ───────────────────────── types ─────────────────────────\n\n/** Is this inbox key bound to this principal (a Bitcoin address or a did:oc) by a\n * kind-30078 record? A reader that could not tell should throw, not answer false. */\nexport type IsBound = (pubkey: string, principal: string) => Promise<boolean>;\n\n/** Does this utxo-floor write proof match current chain state: an unspent output\n * of `address` with exactly the proof's value, height and block hash (§8.3.3)?\n * A reader that could not tell throws UnansweredReadError, not false. */\nexport type VerifyOnChain = (proof: WriteProof, address: string) => Promise<boolean>;\n\nexport type WritePolicy = 'utxo-floor' | 'allowlist' | 'founder' | 'open';\n\nexport interface ChannelWrite {\n policy: WritePolicy;\n /** utxo-floor: minimum UTXO age (blocks) the write-proof must clear. */\n utxo_floor_confs: number;\n /** utxo-floor: minimum UTXO value (sats) counting toward the age test. */\n utxo_floor_sats: number;\n /** allowlist: hex SHA-256 of the canonical sorted writer-address list. */\n allowlist_root: string | null;\n /** MUST be true iff policy === 'utxo-floor' (§8.3.3). */\n rooted: boolean;\n}\n\n/** kind-30110 descriptor content (the hashed bytes; the binding sig + signer\n * ride in the event tags, NOT in here). */\nexport interface DescriptorContent {\n v: 1;\n channel_id: string;\n slug: string;\n founder_address: string;\n founder_inbox_pubkey: string;\n read: 'public'; // v1 (private \"members\" reserved, §8.3.7)\n encryption: null; // v1 (reserved private block)\n write: ChannelWrite;\n admins: string[];\n moderators: string[];\n title: string;\n description: string;\n avatar: string | null;\n rules: string | null;\n directory_opt_in: boolean;\n created_at: number;\n supersedes: string | null;\n /** §8.3.8 lifecycle. OMITTED when active (byte-compat with pre-close\n * descriptors + vc14/vc15); present as \"closed\" when the founder retires the\n * channel. A closed channel is read-only (only removal tombstones land);\n * re-openable via a later status:\"active\" founder revision. Only the FOUNDER\n * may change status (verifyDescriptor), so an admin cannot close via a coup. */\n status?: 'active' | 'closed';\n /** §8.3.8 optional pointer to a replacement channel a closed channel succeeds\n * to. A user-confirmed link, never an auto-redirect. */\n successor_channel_id?: string | null;\n}\n\n/** Self-contained, height-anchored UTXO write-proof (§8.3.3). Verified OFFLINE\n * against the reader's own tip — no per-post live point-query. `control_sig`\n * (BIP-322 over post_id) is NOT in this hashed struct; it rides the event. */\nexport interface WriteProof {\n outpoint: string;\n value_sats: number;\n anchor_block_height: number;\n anchor_block_hash: string;\n}\n\n/** kind-30111 `chat-channel` post content (the hashed bytes). A removal\n * tombstone (§8.3.5) is a post with `removes` = target post_id, written with `body:\"\"`. */\nexport interface PostContent {\n v: 1;\n kind: 'chat-channel';\n channel_id: string;\n author_address: string;\n author_inbox_pubkey: string;\n body: string;\n seq: number;\n parent_id: string | null;\n /** REQUIRED iff the channel's write.policy === 'utxo-floor'. */\n write_proof?: WriteProof;\n /** Moderation tombstone: the target post_id this removes (§8.3.5). */\n removes?: string;\n /** Optional PUBLIC inline file attachment (§8.3.2). UNLIKE a DM attachment it\n * is NOT encrypted — a public channel post is plaintext, so the file is\n * public too. It rides base64 in the content and is committed to post_id\n * (tamper-evident), size-bounded to MAX_ATTACHMENT_BYTES. */\n attachment?: Attachment;\n}\n\nexport type Role = 'founder' | 'admin' | 'moderator' | 'member';\n\n/** channel_id = SHA-256('oc-lock-chat-ch/v1:' ‖ founder_address ‖ ':' ‖ slug)\n * — identity binds to the founder address, the trust root (vc14, §8.3.1). */\nexport function channelId(founderAddress: string, slug: string): string {\n return hexEncode(sha256(utf8Encode(CH_SALT_LABEL + founderAddress + ':' + slug.toLowerCase())));\n}\n\n/** The pre-0.3.0 descriptor d-tag, \"oc-lock-chat-ch:\" ‖ b64url(SHA-256(salt ‖ channel_id)).\n * Readers still fetch it; nothing is published at it any more (§8.3.1). */\nexport function descriptorDtag(cid: string): string {\n return CH_DTAG_PREFIX + b64urlNoPad(sha256(utf8Encode(CH_SALT_LABEL + cid)));\n}\n\n/** A descriptor version's own d-tag, \"oc-lock-chat-ch:\" ‖ descriptor_id (0.3.0). */\nexport function versionDtag(did: string): string {\n return CH_DTAG_PREFIX + did;\n}\n\n/** Post d-tag = \"oc-lock-chat-msg:\" ‖ b64url(SHA-256(channel_id ‖ \":\" ‖ post_id)). */\nexport function postDtag(cid: string, pid: string): string {\n return POST_DTAG_PREFIX + b64urlNoPad(sha256(utf8Encode(cid + ':' + pid)));\n}\n\nexport function isValidSlug(slug: string): boolean {\n return SLUG_RE.test(slug);\n}\n\n/** descriptor_id = SHA-256(canonical(content)), hex (content-addressed, vc14). */\nexport function descriptorId(content: DescriptorContent): string {\n return hexEncode(sha256(canonicalBytes(content)));\n}\n\n/** post_id = SHA-256(canonical(content)), hex (content-addressed, vc16). */\nexport function postId(content: PostContent): string {\n return hexEncode(sha256(canonicalBytes(content)));\n}\n\n/** allowlist_root = hex SHA-256(canonical(sorted unique writer-address list)). */\nexport function allowlistRoot(addresses: string[]): string {\n const sorted = [...new Set(addresses)].sort();\n return hexEncode(sha256(canonicalBytes(sorted)));\n}\n\n// ─────────────────────── policy / roles ───────────────────────\n\n/** §8.3.3: utxo-floor ⇒ rooted:true; allowlist/founder/open ⇒ rooted:false.\n * A mismatch is E_CH_POLICY_INVALID — the Bitcoin claim is a property of the\n * artifact, not a UI label. */\nexport function policyRootedMatches(write: ChannelWrite): boolean {\n return write.rooted === (write.policy === 'utxo-floor');\n}\n\n/** Is a write policy Bitcoin-load-bearing (passes the Ed25519 substitution\n * test)? Only utxo-floor in v1 (pay-to-post is the deferred kind-30115 one). */\nexport function isRootedPolicy(policy: WritePolicy): boolean {\n return policy === 'utxo-floor';\n}\n\nexport function roleOf(address: string, d: DescriptorContent): Role {\n if (address === d.founder_address) return 'founder';\n if (d.admins.includes(address)) return 'admin';\n if (d.moderators.includes(address)) return 'moderator';\n return 'member';\n}\n\n/**\n * The badge the roster shows. A founder lists admins and moderators without\n * their say, so one who has never posted here reads as named by the founder,\n/** Rough address-shape guard: a utxo-floor author MUST post under a Bitcoin\n * address (a did:oc can't own a UTXO). The BIP-322 control_sig is the real\n * check; this only rejects an obviously non-Bitcoin principal early. */\nexport function isBitcoinAddress(addr: string): boolean {\n if (/^(bc1|tb1|bcrt1)[02-9ac-hj-np-z]{6,}$/i.test(addr)) return true; // bech32(m)\n if (/^[13][a-km-zA-HJ-NP-Z1-9]{25,39}$/.test(addr)) return true; // base58 p2pkh/p2sh\n return false;\n}\n\n// ─────────────────── write-proof arithmetic (vc17) ───────────────────\n\nexport interface WriteProofVerdict {\n /** Age of the anchored UTXO at the reader's tip: tip − anchor + 1. */\n ageConfs: number;\n meetsAge: boolean;\n meetsValue: boolean;\n verdict: 'accept' | 'E_CHAN_FLOOR';\n}\n\n/**\n * Evaluate a height-anchored UTXO write-proof OFFLINE against the reader's own\n * current tip (one tip read per render batch, never per post). Pure arithmetic\n * — reproduces vc17. The control_sig (BIP-322 over post_id) is verified\n * separately in checkWritePermission; this only gates value + age.\n */\nexport function evaluateWriteProof(\n proof: Pick<WriteProof, 'value_sats' | 'anchor_block_height'>,\n policy: Pick<ChannelWrite, 'utxo_floor_confs' | 'utxo_floor_sats'>,\n tipHeight: number\n): WriteProofVerdict {\n const ageConfs = tipHeight - proof.anchor_block_height + 1;\n const meetsAge = ageConfs >= policy.utxo_floor_confs;\n const meetsValue = proof.value_sats >= policy.utxo_floor_sats;\n return {\n ageConfs,\n meetsAge,\n meetsValue,\n verdict: meetsAge && meetsValue ? 'accept' : 'E_CHAN_FLOOR',\n };\n}\n\n\nexport function parseDescriptor(ev: NostrEvent): DescriptorContent | null {\n try {\n const c = JSON.parse(ev.content) as Record<string, unknown>;\n if (c.v !== 1) return null;\n if (typeof c.channel_id !== 'string' || typeof c.slug !== 'string') return null;\n if (typeof c.founder_address !== 'string') return null;\n if (typeof c.founder_inbox_pubkey !== 'string') return null;\n if (!c.write || typeof c.write !== 'object') return null;\n if (typeof c.created_at !== 'number') return null;\n // Text every reader shows; not text is not a descriptor (§8.3.1).\n if (typeof c.title !== 'string' || typeof c.description !== 'string') return null;\n return c as unknown as DescriptorContent;\n } catch {\n return null;\n }\n}\n\nexport function parsePost(ev: NostrEvent): PostContent | null {\n try {\n const c = JSON.parse(ev.content) as Record<string, unknown>;\n if (c.v !== 1 || c.kind !== 'chat-channel') return null;\n if (typeof c.channel_id !== 'string' || typeof c.author_address !== 'string') return null;\n if (typeof c.author_inbox_pubkey !== 'string' || typeof c.body !== 'string') return null;\n // A malformed/oversized attachment is a render-DoS — drop the whole post\n // (the attachment is committed to post_id, so it can't be stripped).\n if (c.attachment !== undefined && !isValidAttachment(c.attachment)) return null;\n return c as unknown as PostContent;\n } catch {\n return null;\n }\n}\n\n\n// ───────────────────────── verify ─────────────────────────\n\nexport type DescriptorVerify =\n | { ok: true; channelId: string; descriptorId: string; signerAddress: string }\n | { ok: false; error: ChannelError };\n\n/**\n * Verify a channel descriptor (§8.3.1) OFFLINE given the descriptor content + its\n * kind-30110 event. Authorship = the event's schnorr signature by an inbox key\n * that is bound (kind-30078) to the founder (genesis) or a PRIOR-epoch admin\n * (supersede) — the governance hash-chain, the §5 parent_id trick applied to\n * governance (vc15). No per-edit wallet ceremony: the device record IS the\n * binding, established once. The Bitcoin claim is in the write policy, not here.\n *\n * v1 rejects private descriptors (read != \"public\" or encryption != null) as\n * E_CH_UNSUPPORTED — a public-only client never silently downgrades them.\n */\nexport async function verifyDescriptor(\n content: DescriptorContent,\n event: NostrEvent,\n opts: {\n priorEpoch?: DescriptorContent;\n /** Is this inbox key bound to this principal (an address or a did:oc)? */\n isBound: IsBound;\n }\n): Promise<DescriptorVerify> {\n const isBound = opts.isBound;\n\n // Phase guard: v1 is public-only.\n if (content.read !== 'public' || content.encryption !== null) {\n return { ok: false, error: 'E_CH_UNSUPPORTED' };\n }\n // Capability guard: the public-only v1 client does not implement allowlist\n // membership proofs (§8.3.3), so it cannot resolve the writer set on read —\n // every post would then fail-closed and silently vanish. Reject the descriptor\n // as unsupported instead, so the unsupported state is honest rather than a\n // channel that renders permanently empty with no error.\n if (content.write.policy === 'allowlist') {\n return { ok: false, error: 'E_CH_UNSUPPORTED' };\n }\n // Identity integrity: channel_id MUST bind to founder_address ‖ slug.\n if (channelId(content.founder_address, content.slug) !== content.channel_id) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n // Policy/rooted match (the Bitcoin claim is a property of the artifact).\n if (!policyRootedMatches(content.write)) {\n return { ok: false, error: 'E_CH_POLICY_INVALID' };\n }\n // The event must be self-consistent + schnorr-signed by its own pubkey, and\n // actually carry this content (its content hashes to descriptor_id).\n if (!signedBy(event, event.pubkey)) return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n if (event.content !== JSON.stringify(content)) {\n // Allow a re-serialization match (key order may differ on the wire); the\n // content-addressed id is canonical, so compare on descriptorId instead.\n if (descriptorId(parseDescriptor(event) ?? content) !== descriptorId(content)) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n }\n\n const did = descriptorId(content);\n\n if (!opts.priorEpoch) {\n // Genesis: supersedes MUST be null; the signing inbox key IS the founder's\n // and is bound to founder_address via the kind-30078 record.\n if (content.supersedes !== null) return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n if (event.pubkey !== content.founder_inbox_pubkey) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n if (!(await isBound(event.pubkey, content.founder_address))) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n return {\n ok: true,\n channelId: content.channel_id,\n descriptorId: did,\n signerAddress: content.founder_address,\n };\n }\n\n const prior = opts.priorEpoch;\n // Same channel, and the chain links to the prior descriptor_id.\n if (content.channel_id !== prior.channel_id) return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n if (content.supersedes !== descriptorId(prior)) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n // The inbox TRUST-ROOT key is immutable across epochs (founder_address is\n // already pinned by channel_id at line 465). A supersede that mutates\n // founder_inbox_pubkey — e.g. an admin redirecting the channel's trust root to\n // their own device key — is unauthorized.\n if (content.founder_inbox_pubkey !== prior.founder_inbox_pubkey) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n // The FOUNDER is the trust root (§8.3.4: \"may do anything, including replace the\n // descriptor\") — a founder-signed supersede may make any change.\n if (await isBound(event.pubkey, prior.founder_address)) {\n return {\n ok: true,\n channelId: content.channel_id,\n descriptorId: did,\n signerAddress: prior.founder_address,\n };\n }\n // An ADMIN-signed supersede may edit metadata/policy but MUST NOT stage a\n // governance coup: it cannot remove the founder or any prior admin (require\n // prior.admins ⊆ next.admins), and it cannot CLOSE or RE-OPEN the channel\n // (§8.3.8 status change is founder-only — an admin nuking a channel others\n // rely on is exactly the coup we forbid). Only the founder may do either, and\n // only the founder may set or change successor_channel_id, at any status.\n for (const addr of prior.admins) {\n if (await isBound(event.pubkey, addr)) {\n const nextAdmins = new Set(content.admins);\n if (!prior.admins.every((a) => nextAdmins.has(a))) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n if ((prior.status ?? 'active') !== (content.status ?? 'active')) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n if ((prior.successor_channel_id ?? null) !== (content.successor_channel_id ?? null)) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n return {\n ok: true,\n channelId: content.channel_id,\n descriptorId: did,\n signerAddress: addr,\n };\n }\n }\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n}\n\nexport interface VerifyPostOpts {\n /** Reader's current tip height (one read per render batch), or 'unanswered'\n * when it could not be read: a utxo-floor post that needs it then throws\n * UnansweredReadError rather than being refused. */\n tipHeight: number | 'unanswered';\n /** BIP-322 by author_address over post_id — REQUIRED for utxo-floor. */\n controlSig?: string;\n /** The full writer-address list for an allowlist channel (membership proof). */\n allowlist?: string[];\n /** The Nostr event (to verify the author device signature). verifyPost\n * rejects a post without it; checkWritePolicy does not read it. */\n event?: NostrEvent;\n /** Is this inbox key bound to this principal? verifyPost needs it. */\n isBound?: IsBound;\n /** BIP-322, for a utxo-floor post's control_sig. */\n verifyBip322: VerifyBip322;\n /** A non-empty recipients[] on a chat-channel envelope is E_CHANNEL_RECIPIENTS. */\n recipients?: unknown[];\n /** utxo-floor: binds the write_proof to real chain state (io.ts has one\n * over an esplora API). Fail-closed: false drops the post; a read that got\n * no answer throws UnansweredReadError. */\n verifyOnChain: VerifyOnChain;\n}\n\nexport type PostVerify =\n | { ok: true; postId: string; role: Role; isTombstone: boolean }\n | { ok: false; error: ChannelError };\n\n/**\n * NON-AUTHORITATIVE policy check (§8.3.2/§8.3.3): recipient-exclusion, channel\n * match, writer role, and the write-policy gate — ASSUMING the author is already\n * authenticated. It does NOT verify the author device signature or the kind-30078\n * binding. `verifyPost` wraps this with that authentication; this is exposed only\n * so the write-gate arithmetic (vc17) can be unit-tested without minting a real\n * device record. Never call it as an authorization decision on its own.\n */\nexport async function checkWritePolicy(\n content: PostContent,\n descriptor: DescriptorContent,\n opts: VerifyPostOpts\n): Promise<PostVerify> {\n const verify = opts.verifyBip322;\n\n // (0) recipient-exclusion: a chat-channel post is public + recipient-less.\n if (opts.recipients && opts.recipients.length > 0) {\n return { ok: false, error: 'E_CHANNEL_RECIPIENTS' };\n }\n // A non-channel envelope kind is not a valid channel post (distinct from the\n // recipient-exclusion condition — they are different defects).\n if (content.kind !== 'chat-channel') return { ok: false, error: 'E_CH_WRITE_DENIED' };\n if (content.channel_id !== descriptor.channel_id) {\n return { ok: false, error: 'E_CH_WRITE_DENIED' };\n }\n\n const pid = postId(content);\n const role = roleOf(content.author_address, descriptor);\n // A removal names its target in `removes`; its body grants nothing (§8.3.5).\n const isTombstone = typeof content.removes === 'string';\n\n // Moderation tombstone: roster moderator/admin/founder only (§8.3.5).\n if (isTombstone) {\n if (role === 'member') return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n return { ok: true, postId: pid, role, isTombstone: true };\n }\n\n // §8.3.8: a CLOSED channel is read-only. Removal tombstones (above) still land\n // so moderation works after close; every other post is denied. Forward-\n // effective only — posts already propagated are unaffected.\n if ((descriptor.status ?? 'active') === 'closed') {\n return { ok: false, error: 'E_CH_CLOSED' };\n }\n\n const denied = await checkWritePermission(content, descriptor, role, pid, opts, verify);\n if (denied) return { ok: false, error: denied };\n return { ok: true, postId: pid, role, isTombstone: false };\n}\n\n/**\n * AUTHORITATIVE verify of a public channel post (§8.3.2). REQUIRES the kind-30111\n * event so it can prove authorship — there is no unauthenticated accept path:\n * (0) recipient-exclusion; (1) the event schnorr-signed by author_inbox_pubkey\n * AND that inbox key bound to author_address via the kind-30078 record; (2)/(3)\n * the §8.3.3 write-policy gate + writer role (via checkWritePolicy). A post with\n * no event cannot be authenticated and is rejected E_CH_UNAUTHORIZED.\n */\nexport async function verifyPost(\n content: PostContent,\n descriptor: DescriptorContent,\n opts: VerifyPostOpts\n): Promise<PostVerify> {\n const isBound = opts.isBound;\n\n // (0) recipient-exclusion is structural — check before authentication so a\n // recipient-bearing post returns the precise code, not E_CH_UNAUTHORIZED.\n if (opts.recipients && opts.recipients.length > 0) {\n return { ok: false, error: 'E_CHANNEL_RECIPIENTS' };\n }\n // (1) authorship is MANDATORY: no event ⇒ unauthenticated ⇒ reject.\n if (!opts.event || !isBound) return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n if (!signedBy(opts.event, content.author_inbox_pubkey)) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n if (!(await isBound(content.author_inbox_pubkey, content.author_address))) {\n return { ok: false, error: 'E_CH_UNAUTHORIZED' };\n }\n return checkWritePolicy(content, descriptor, opts);\n}\n\n/** The §8.3.3 write gate. founder/admin bypass all policies (the trust root). */\nasync function checkWritePermission(\n content: PostContent,\n descriptor: DescriptorContent,\n role: Role,\n pid: string,\n opts: VerifyPostOpts,\n verify: VerifyBip322\n): Promise<ChannelError | null> {\n if (role === 'founder' || role === 'admin') return null;\n const w = descriptor.write;\n switch (w.policy) {\n case 'founder':\n return 'E_CH_NOT_WRITER'; // only founder/admin (handled above)\n case 'open':\n return null; // any valid device may post\n case 'allowlist': {\n if (!opts.allowlist) return 'E_CH_WRITE_DENIED';\n if (allowlistRoot(opts.allowlist) !== w.allowlist_root) {\n return 'E_CH_WRITE_DENIED';\n }\n return opts.allowlist.includes(content.author_address) ? null : 'E_CH_WRITE_DENIED';\n }\n case 'utxo-floor': {\n if (!content.write_proof) return 'E_CHAN_FLOOR';\n if (!opts.controlSig) return 'E_CHAN_FLOOR';\n if (!isBitcoinAddress(content.author_address)) return 'E_CHAN_FLOOR';\n // With no tip read, the age cannot be told: not a refusal (§8.3.3).\n if (opts.tipHeight === 'unanswered') {\n throw new UnansweredReadError('the chain tip could not be read');\n }\n // Cheap offline gates first (no network): the floor arithmetic + the\n // control_sig (author controls the address, over post_id).\n const v = evaluateWriteProof(content.write_proof, w, opts.tipHeight);\n if (v.verdict !== 'accept') return 'E_CHAN_FLOOR';\n const sigOk = await verify({\n address: content.author_address,\n message: pid,\n signature: opts.controlSig,\n });\n if (sigOk !== true) return 'E_CHAN_FLOOR';\n // THE Bitcoin-load-bearing leg: bind the proof to real chain state — the\n // claimed coin must actually exist, be unspent, be owned by the author's\n // address, and carry the asserted value/height/hash. Without this the\n // value/age are unverified author claims (the §8.3.3 forgery). Fail-closed.\n if ((await opts.verifyOnChain(content.write_proof, content.author_address)) !== true) {\n return 'E_CHAN_FLOOR';\n }\n return null;\n }\n }\n}\n\n// ───────────────────── the governance chain ─────────────────────\n\n/** A version of a channel the resolution authorized (§8.3.1). */\nexport interface ResolvedVersion {\n descriptorId: string;\n descriptor: DescriptorContent;\n /** The keys of its authorized copies, the founder's first. */\n signers: string[];\n /** The event ids of its authorized copies. A copy of the same content under any\n * other key or event is not one: the id covers the content, not the signer. */\n copies: string[];\n}\n\nexport interface ResolvedChannel {\n descriptor: DescriptorContent;\n descriptorId: string;\n /** How many governance epochs validated back to genesis (1 = genesis only). */\n epochs: number;\n /** The key that signed the copy of the tip the channel resolved by. */\n tipPubkey: string;\n /** The resolved chain from the genesis to the tip, with every key that signed\n * an authorized copy of each version, and those copies' event ids. */\n chain: ResolvedVersion[];\n /** Every authorized version, on any branch, with every key that signed a copy. */\n versions: ResolvedVersion[];\n /** Every closed tip, overruled ones included: a re-open supersedes each (§8.3.8). */\n closedTips: { descriptorId: string; descriptor: DescriptorContent }[];\n}\n\n/** What a resolver needs beyond the events themselves. */\nexport interface ChainReads {\n /** A pre-0.3.0 version (no `binding` tag): is its key bound to the principal now? */\n isBound: IsBound;\n /** Every key the auth host publishes, retired ones included (§8.6). Read once, when a session record needs them. */\n hostKeys: () => Promise<readonly AuthHostKey[]>;\n /** Is a version's binding still live: no revocation of it seen on any relay,\n * and an address bind not dated ahead of the reader's clock? 'unknown' (no\n * relay answered) stops the resolution with UnansweredReadError; a liveness\n * read may also throw its own error. */\n liveness: (b: VersionBinding) => Promise<Liveness>;\n verifyBip322: VerifyBip322;\n}\n\n/** An authorized copy of a version: whether the founder signed it, and its binding\n * (null for a pre-0.3.0 copy, authorized by a binding read from the relays). */\ninterface AuthorizedCopy {\n ev: NostrEvent;\n founder: boolean;\n binding: VersionBinding | null;\n}\n\n/**\n * Walk the governance hash-chain over every version of a channel and return the\n * tip that resolves (§8.3.1). A version with a later version after it stands on\n * the binding its event carries; the last version of a chain also needs that\n * binding to be live, else the chain ends at the version before it. Competing\n * tips: a founder-signed branch at a fork wins, then a closed tip, then the\n * longest chain, then the freshest signed created_at, then the lowest\n * descriptor_id. Null if nothing resolves; UnansweredReadError if a liveness\n * read could not be answered.\n */\nexport async function resolveChannelChain(\n events: NostrEvent[],\n cid: string,\n opts: ChainReads\n): Promise<ResolvedChannel | null> {\n // Index descriptors by their own descriptor_id, keeping EVERY event that\n // carries it. Authorship is the event's key, which sits outside the id, so\n // anyone can re-sign a descriptor under their own key: keeping one copy let\n // a stranger's unauthorized copy replace the founder's and roll the channel\n // back. A descriptor stands if any copy is authorized (§8.3.1).\n const nodes = new Map<string, { content: DescriptorContent; events: NostrEvent[] }>();\n for (const ev of events) {\n const content = parseDescriptor(ev);\n if (!content) continue;\n // The d-tag is a relay-side lookup key, not a trust boundary: another\n // founder's valid channel published under this d-tag must not compete.\n if (content.channel_id !== cid) continue;\n if (!signedBy(ev, ev.pubkey)) continue;\n const id = descriptorId(content);\n const node = nodes.get(id);\n if (!node) nodes.set(id, { content, events: [ev] });\n else if (!node.events.some((e) => e.id === ev.id)) node.events.push(ev);\n }\n if (nodes.size === 0) return null;\n\n let keys: Promise<readonly AuthHostKey[]> | null = null;\n const hostKeys = () => (keys ??= opts.hostKeys());\n const bindings = new Map<string, Promise<VersionBinding | null>>();\n const bindingOf = (ev: NostrEvent) => {\n if (!bindings.has(ev.id))\n bindings.set(ev.id, readVersionBinding(ev, { hostKeys, verifyBip322: opts.verifyBip322 }));\n return bindings.get(ev.id)!;\n };\n\n // Every authorized copy of a version, the founder's first. A version with a\n // `binding` tag is signed by the principal its record names; one without\n // (pre-0.3.0) only by a key a record on the relays binds now.\n const authorize = async (\n node: { content: DescriptorContent; events: NostrEvent[] },\n priorEpoch?: DescriptorContent\n ): Promise<AuthorizedCopy[]> => {\n const out: AuthorizedCopy[] = [];\n for (const ev of node.events) {\n const binding = await bindingOf(ev);\n const isBound = hasBindingTag(ev)\n ? async (pk: string, principal: string) =>\n binding !== null && pk === binding.pubkey && principal === binding.principal\n : opts.isBound;\n const v = await verifyDescriptor(node.content, ev, {\n ...(priorEpoch ? { priorEpoch } : {}),\n isBound,\n });\n if (!v.ok) continue;\n const founder = !priorEpoch || v.signerAddress === priorEpoch.founder_address;\n out.push({ ev, founder, binding });\n }\n return out.sort((a, b) => Number(b.founder) - Number(a.founder));\n };\n\n // Validate each version's chain back to a genesis; memoize its depth.\n const copies = new Map<string, AuthorizedCopy[]>();\n const depthCache = new Map<string, number | null>();\n const validateChain = async (id: string, seen: Set<string>): Promise<number | null> => {\n if (depthCache.has(id)) return depthCache.get(id)!;\n const node = nodes.get(id);\n if (!node || seen.has(id)) {\n depthCache.set(id, null);\n return null;\n }\n seen.add(id);\n const prevId = node.content.supersedes;\n let priorDepth = 0;\n let prior: DescriptorContent | undefined;\n if (prevId !== null) {\n const p = nodes.get(prevId);\n const d = p ? await validateChain(prevId, seen) : null;\n if (!p || d === null) {\n depthCache.set(id, null);\n return null;\n }\n priorDepth = d;\n prior = p.content;\n }\n const a = await authorize(node, prior);\n if (a.length) copies.set(id, a);\n const depth = a.length ? priorDepth + 1 : null;\n depthCache.set(id, depth);\n return depth;\n };\n for (const id of nodes.keys()) await validateChain(id, new Set());\n\n // The copy a version counts by as the last of its chain: an authorized copy\n // whose binding is live, the founder's first. A pre-0.3.0 copy was authorized\n // by a binding read just now, so it is live by that read.\n const liveness = opts.liveness;\n const liveCache = new Map<string, Promise<Liveness>>();\n const isLive = async (c: AuthorizedCopy): Promise<boolean> => {\n if (!c.binding) return true;\n // Per binding, not per key: the same key under a later vouch can be live\n // while its earlier one is revoked.\n const b = c.binding;\n const key = `${b.principal}:${b.pubkey}:${b.kind === 'session' ? b.issuedAt : b.record.eventId}`;\n if (!liveCache.has(key)) liveCache.set(key, liveness(c.binding));\n const l = await liveCache.get(key)!;\n if (l === 'unknown') throw new UnansweredReadError();\n return l === 'live';\n };\n const tipCopy = async (id: string): Promise<AuthorizedCopy | null> => {\n for (const c of copies.get(id) ?? []) if (await isLive(c)) return c;\n return null;\n };\n const tips = new Map<string, AuthorizedCopy>();\n for (const id of copies.keys()) {\n const c = await tipCopy(id);\n if (c) tips.set(id, c);\n }\n\n // Only versions on a chain that resolves count at a fork: a revoked key's\n // dead branch must not overrule a live one.\n const resolving = new Set<string>();\n for (const tip of tips.keys()) {\n let cur: string | null = tip;\n while (cur && !resolving.has(cur)) {\n resolving.add(cur);\n cur = nodes.get(cur)?.content.supersedes ?? null;\n }\n }\n // A version's rank at a fork: 1 the founder signed it with a live binding,\n // 2 the founder signed it with a binding since revoked, 3 anything else.\n const rank = new Map<string, number>();\n for (const id of resolving) {\n const founderCopies = (copies.get(id) ?? []).filter((c) => c.founder);\n let r = founderCopies.length ? 2 : 3;\n for (const c of founderCopies) if (await isLive(c)) r = 1;\n rank.set(id, r);\n }\n\n // Longest chain alone would let an admin fork from a version before the\n // founder's latest decision (e.g. before being removed) and outgrow it, and\n // a stolen founder key, once revoked, outgrow the founder's live device, by\n // a fork or by a genesis of its own. So at a fork, and among geneses, every\n // branch through a version ranked below the best is overruled, however long\n // it grows.\n const overruled = (id: string): boolean => {\n // Siblings at a fork share a parent; the geneses of one channel are\n // siblings under a virtual root (null).\n const beaten = (curId: string, parentId: string | null): boolean => {\n let best = 3;\n for (const [otherId, other] of nodes) {\n if (other.content.supersedes === parentId && resolving.has(otherId)) {\n best = Math.min(best, rank.get(otherId)!);\n }\n }\n return rank.get(curId)! > best;\n };\n let curId = id;\n for (let cur = nodes.get(id); cur; cur = nodes.get(curId)) {\n const parentId = cur.content.supersedes;\n if (beaten(curId, parentId)) return true;\n if (parentId === null) return false;\n curId = parentId;\n }\n return false;\n };\n\n const chainTo = (id: string): ResolvedChannel['chain'] => {\n const out: ResolvedChannel['chain'] = [];\n for (let cur: string | null = id; cur; cur = nodes.get(cur)!.content.supersedes) {\n const cs = copies.get(cur) ?? [];\n out.unshift({\n descriptorId: cur,\n descriptor: nodes.get(cur)!.content,\n signers: cs.map((c) => c.ev.pubkey),\n copies: cs.map((c) => c.ev.id),\n });\n }\n return out;\n };\n\n // Among the tips left (versions nothing supersedes): a closed one, then the\n // longest chain, then the freshest signed created_at, then the lowest\n // descriptor_id, so every reader picks the same tip (§8.3.1, 0.3.2).\n const key = (id: string) => {\n const d = nodes.get(id)!.content;\n return [d.status === 'closed' ? 1 : 0, depthCache.get(id)!, d.created_at] as const;\n };\n const beats = (a: string, b: string): boolean => {\n const ka = key(a);\n const kb = key(b);\n for (let i = 0; i < ka.length; i++) if (ka[i] !== kb[i]) return ka[i]! > kb[i]!;\n return a < b;\n };\n // A tip is a version no resolving version supersedes: a close that a re-open\n // superseded is no longer one.\n const superseded = new Set<string>();\n for (const id of resolving) {\n const parent = nodes.get(id)?.content.supersedes;\n if (parent) superseded.add(parent);\n }\n const closedTips = [...tips.keys()]\n .filter((id) => !superseded.has(id) && nodes.get(id)!.content.status === 'closed')\n .map((id) => ({ descriptorId: id, descriptor: nodes.get(id)!.content }));\n let best: ResolvedChannel | null = null;\n let bestId: string | null = null;\n for (const [id, c] of tips) {\n if (superseded.has(id) || overruled(id)) continue;\n const depth = depthCache.get(id)!;\n if (bestId === null || beats(id, bestId)) {\n best = {\n descriptor: nodes.get(id)!.content,\n descriptorId: id,\n epochs: depth,\n tipPubkey: c.ev.pubkey,\n chain: chainTo(id),\n versions: [...copies].map(([vid, cs]) => ({\n descriptorId: vid,\n descriptor: nodes.get(vid)!.content,\n signers: cs.map((c) => c.ev.pubkey),\n copies: cs.map((c) => c.ev.id),\n })),\n closedTips,\n };\n bestId = id;\n }\n }\n return best;\n}\n\n/** Where one version event stands in a resolved channel. */\nexport interface CopyStanding {\n descriptorId: string;\n /** Its version is on the chain from the genesis to the tip. */\n onChain: boolean;\n /** Its version is the tip the channel resolved to. */\n isTip: boolean;\n}\n\n/**\n * Is this event an authorized copy of a version of `resolved` (§8.3.1)? A version\n * stands when any copy of it is authorized, but an event is authorized only when\n * it is one of those copies: the same content signed by another key, or carried\n * by another event, is not, though its descriptor_id is the same. Null when the\n * event is not an authorized copy, or does not verify (NIP-01).\n */\nexport function authorizedCopy(resolved: ResolvedChannel | null, ev: NostrEvent): CopyStanding | null {\n if (!resolved || !verifyNostrEvent(ev)) return null;\n const v = resolved.versions.find((x) => x.copies.includes(ev.id));\n if (!v) return null;\n return {\n descriptorId: v.descriptorId,\n onChain: resolved.chain.some((c) => c.descriptorId === v.descriptorId),\n isTip: resolved.descriptorId === v.descriptorId,\n };\n}\n\n/** The reads readChannelVersions makes: one relay query, and every inbox key a principal's records have ever bound. */\nexport interface VersionReads {\n /** One REQ to the reader's relays. */\n query: Query;\n /** Every key a principal's device records have bound, revoked ones too (§8.3.1); whether a\n * relay answered; and whether the read met the floor (§8.7), so that no key is missing. */\n everBoundKeys: (principal: string) => Promise<{ keys: string[]; answered: boolean; floor: boolean }>;\n}\n\n/** Events asked for per page: relays commonly cap one REQ at 500. */\nconst VERSION_PAGE_LIMIT = 500;\n/** Pages read for one channel's `t` tag: up to 2,000 events, as attest reads a subject. */\nconst VERSION_MAX_PAGES = 4;\n/** Rounds of walking forward by `s` or back by exact d-tag past what the pages read. */\nconst VERSION_WALK_ROUNDS = 64;\n/** Exact d-tags asked for per round of the walk back, so a REQ stays small. */\nconst VERSION_BACK_IDS = 100;\n/** Keys read per principal: past this, one principal's rotations cannot fan the reader out. */\nconst VERSION_MAX_KEYS = 32;\n/** REQs the founder's-keys read and the walk by `s` make in all. */\nconst VERSION_MAX_ROLE_REQS = 256;\n\n/** The founder a version names, when its founder and slug derive `cid`. */\nfunction founderFrom(e: NostrEvent, cid: string): string | null {\n const c = parseDescriptor(e);\n return c && c.channel_id === cid && channelId(c.founder_address, c.slug) === cid\n ? c.founder_address\n : null;\n}\n\n/**\n * Every version of a channel a reader can find (§8.3.1, 0.3.0), whether the open\n * read under its `t` tag stopped at the page bound, and whether the reads by\n * role holders' keys stopped short (an unanswered key lookup, or a bound).\n * Anyone can publish under that tag, so besides the paged open read and the\n * legacy d-tag it reads where a flood cannot reach: the versions the founder's\n * keys signed, then forward by `s` from each of those, by the keys of the role\n * holders that version names. Then back by exact d-tag to any version a\n * `supersedes` names, the parents role holders named first. Every copy is\n * kept. Throws UnansweredReadError when no read was answered. `floorMet` is\n * false when any read, of versions or of a role holder's keys, fell below the\n * read floor (§8.7), so a newer version may exist.\n */\nexport async function readChannelVersions(\n cid: string,\n reads: VersionReads,\n founderHint?: string\n): Promise<{ events: NostrEvent[]; truncated: boolean; incomplete: boolean; floorMet: boolean }> {\n const queryEvents = reads.query;\n const merged = new Map<string, NostrEvent>();\n const status: { eose: boolean }[] = [];\n // A read without relay statuses is taken as it is, as answeredEvents takes it.\n let floorMet = true;\n // Versions a role holder's key signed: the only ones the walk goes forward from.\n const walkable = new Set<string>();\n const roleKeys = new Set<string>();\n const add = (\n res: { events?: NostrEvent[]; relayStatus?: readonly { eose: boolean }[] },\n byRole = false\n ) => {\n status.push(...(res.relayStatus ?? []));\n if (res.relayStatus && !meetsReadFloor(res.relayStatus)) floorMet = false;\n let fresh = 0;\n for (const e of res.events ?? []) {\n if (byRole) walkable.add(e.id);\n if (merged.has(e.id)) continue;\n merged.set(e.id, e);\n fresh++;\n }\n return fresh;\n };\n const legacy = queryEvents({ kinds: [CHANNEL_DESCRIPTOR_KIND], '#d': [descriptorDtag(cid)] });\n\n // The open read, paged with `until` (inclusive; events already read are skipped).\n let until: number | undefined;\n let truncated = false;\n for (let page = 0; page < VERSION_MAX_PAGES; page++) {\n const res = await queryEvents({\n kinds: [CHANNEL_DESCRIPTOR_KIND],\n '#t': [cid],\n limit: VERSION_PAGE_LIMIT,\n ...(until !== undefined ? { until } : {}),\n });\n const fresh = add(res);\n for (const e of res.events ?? []) until = Math.min(until ?? Infinity, e.created_at);\n // A full page may have more behind it. One that brought nothing new is\n // stuck on a second it cannot page past: the read stops there, cut off.\n if ((res.events ?? []).length < VERSION_PAGE_LIMIT) break;\n if (fresh === 0 || page === VERSION_MAX_PAGES - 1) {\n truncated = true;\n break;\n }\n }\n add(await legacy);\n\n // The founder's keys first, then forward from each version by `s`, from the\n // keys of the founder and the admins that version names. Every key their\n // records have bound counts, revoked ones too: an earlier version stands on\n // its binding whatever became of the key since. One REQ per key, so what one\n // key floods its own reads with hides only that key's own versions.\n let incomplete = false;\n let reqs = 0;\n const founder =\n founderHint ?? [...merged.values()].map((e) => founderFrom(e, cid)).find(Boolean) ?? null;\n if (!founder) incomplete = true;\n else {\n const keysCache = new Map<string, Promise<string[]>>();\n const keysOf = (p: string) => {\n if (!keysCache.has(p))\n keysCache.set(\n p,\n reads\n .everBoundKeys(p)\n .catch(() => ({ keys: [] as string[], answered: false, floor: false }))\n .then(({ keys, answered, floor }) => {\n if (!answered || keys.length > VERSION_MAX_KEYS) incomplete = true;\n if (!floor) floorMet = false;\n const used = keys.slice(0, VERSION_MAX_KEYS);\n for (const k of used) roleKeys.add(k);\n return used;\n })\n );\n return keysCache.get(p)!;\n };\n const read = async (filter: Record<string, unknown>, keys: readonly string[]) => {\n const fresh = keys.slice(0, Math.max(0, VERSION_MAX_ROLE_REQS - reqs));\n if (fresh.length < keys.length) incomplete = true;\n reqs += fresh.length;\n for (const res of await Promise.all(\n fresh.map((k) =>\n queryEvents({\n kinds: [CHANNEL_DESCRIPTOR_KIND],\n ...filter,\n authors: [k],\n limit: VERSION_PAGE_LIMIT,\n })\n )\n )) {\n add(res, true);\n }\n };\n await read({ '#t': [cid] }, await keysOf(founder));\n const walked = new Set<string>();\n let round = 0;\n for (; round < VERSION_WALK_ROUNDS; round++) {\n const frontier: DescriptorContent[] = [];\n for (const e of merged.values()) {\n if (!walkable.has(e.id)) continue;\n const c = parseDescriptor(e);\n if (!c || c.channel_id !== cid) continue;\n const id = descriptorId(c);\n if (walked.has(id)) continue;\n walked.add(id);\n frontier.push(c);\n }\n if (frontier.length === 0) break;\n for (const c of frontier) {\n const keys = [\n ...new Set((await Promise.all([founder, ...c.admins].map(keysOf))).flat()),\n ];\n await read({ '#s': [descriptorId(c)] }, keys);\n }\n }\n if (round === VERSION_WALK_ROUNDS) incomplete = true;\n }\n\n // Back by exact d-tag to any version a supersedes names that no read returned.\n const asked = new Set<string>();\n for (let round = 0; round < VERSION_WALK_ROUNDS; round++) {\n const have = new Set<string>();\n // Each parent named, and whether a role holder's key signed a version naming it.\n const wanted = new Map<string, boolean>();\n for (const e of merged.values()) {\n const c = parseDescriptor(e);\n if (!c || c.channel_id !== cid) continue;\n have.add(descriptorId(c));\n if (c.supersedes)\n wanted.set(c.supersedes, !!wanted.get(c.supersedes) || roleKeys.has(e.pubkey));\n }\n const missing = [...wanted]\n .filter(([id]) => !have.has(id) && !asked.has(id))\n .sort((a, b) => Number(b[1]) - Number(a[1]))\n .slice(0, VERSION_BACK_IDS)\n .map(([id]) => id);\n if (missing.length === 0) break;\n for (const id of missing) asked.add(id);\n add(await queryEvents({ kinds: [CHANNEL_DESCRIPTOR_KIND], '#d': missing.map(versionDtag) }));\n }\n return {\n events: answeredEvents({ events: [...merged.values()], relayStatus: status }),\n truncated,\n incomplete,\n // Every read met the floor: only then can \"no newer version\" be said.\n floorMet,\n };\n}\n\n\nexport interface ChannelPost {\n post: PostContent;\n postId: string;\n event: NostrEvent;\n}\n\nexport interface ChannelPosts {\n /** The posts that verify, removals applied, in feed order. */\n posts: ChannelPost[];\n /** Posts that could not be checked (a binding, coin or tip read with no\n * answer): never shown, and counted so a reader can say so and try again\n * (§8.3.3). A post shown from another copy is not counted. */\n unchecked: number;\n /** False when a removal could not be checked, so a post it names may be\n * on show. */\n removalsChecked: boolean;\n}\n\n/**\n * Deterministic public-feed order (§8.3.2). A public multi-author channel has no\n * single hash-chain (independent broadcasters), so order is the event-level\n * created_at as a DISPLAY hint, tie-broken by the content-addressed post_id so\n * two clients always agree. created_at is untrusted (a relay can backdate); the\n * post_id tiebreak makes the order at least stable + reproducible across clients.\n */\nexport function orderChannelPosts(posts: ChannelPost[]): ChannelPost[] {\n return [...posts].sort((a, b) => {\n const at = a.event.created_at - b.event.created_at;\n return at !== 0 ? at : a.postId < b.postId ? -1 : a.postId > b.postId ? 1 : 0;\n });\n}\n\n\n/**\n * The posts of a channel that verify against its resolved descriptor (§8.3.2):\n * each one authored by a bound key and through the write gate, removal\n * tombstones applied (forward-effective, §8.3.5), copies of one post_id kept\n * once at their lowest created_at, in feed order. A post that fails MUST NOT\n * render, so it is left out. A post whose binding, coin or tip read got no\n * answer (UnansweredReadError) is not shown either, and is counted unchecked\n * rather than refused; the rest of the feed still verifies.\n */\nexport async function verifyChannelPosts(\n events: readonly NostrEvent[],\n descriptor: DescriptorContent,\n opts: Pick<VerifyPostOpts, 'tipHeight' | 'verifyBip322' | 'verifyOnChain'> & { isBound: IsBound }\n): Promise<ChannelPosts> {\n const removed = new Set<string>();\n const byPostId = new Map<string, ChannelPost>();\n const unchecked = new Set<string>();\n let removalsUnread = false;\n for (const ev of events) {\n const content = parsePost(ev);\n if (!content || content.channel_id !== descriptor.channel_id) continue;\n const controlSig = ev.tags.find((t) => t[0] === 'control_sig')?.[1];\n let v: PostVerify;\n try {\n v = await verifyPost(content, descriptor, {\n ...opts,\n event: ev,\n ...(controlSig ? { controlSig } : {}),\n });\n } catch (e) {\n if (!(e instanceof UnansweredReadError)) throw e;\n unchecked.add(postId(content));\n if (typeof content.removes === 'string') removalsUnread = true;\n continue;\n }\n if (!v.ok) continue;\n if (v.isTombstone && content.removes) {\n removed.add(content.removes);\n continue;\n }\n const existing = byPostId.get(v.postId);\n if (!existing || ev.created_at < existing.event.created_at) {\n byPostId.set(v.postId, { post: content, postId: v.postId, event: ev });\n }\n }\n return {\n posts: orderChannelPosts([...byPostId.values()].filter((a) => !removed.has(a.postId))),\n unchecked: [...unchecked].filter((id) => !byPostId.has(id)).length,\n removalsChecked: !removalsUnread,\n };\n}\n","[\n {\n \"note\": \"OC Chat 0.4 §8.2.8: the one v1 listing that carries a claim, anchored by the reference deployment.\",\n \"listing_event_id\": \"0f29b5859da8d5e1882f63a3a331679a8c35b865834239f9a993cc1d3ac045ec\",\n \"handle\": \"ochkroot\",\n \"address\": \"bc1pezn5yjxmz9nuahtqprvhfeya2nv4zdfk49u5amquhqptykx695rs60hqa2\",\n \"orangecheck\": true,\n \"outpoint\": \"bd20e0fb096e5bce89ec33f7cebe0c34e04e31d83db6de00551a6a86f12a00cd:0\",\n \"nonce\": \"9b2e4198ca4a243188ef76c46f31081ed69dcae9d7d60c9f82e7109faf7887bd\",\n \"claim_id\": \"80963cd5e12b76c3a08057957a48806631f3b0a4dcd8d82eb70cc587c30dc243\",\n \"ots\": \"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\"\n }\n]\n","// Who holds a handle under OC Chat 0.4 (SPEC §8.2.5–§8.2.6): the directory relays read\n// completely, public relays read as a bounded audit, and the walk itself from\n// @orangecheck/lock-core/directory, so every client and the directory relay decide alike.\n// Relays, the chain and the bindings are read through WalkDeps.\n\nimport {\n ANCHOR_CONFS,\n channelDirectoryDtag,\n directoryAnchor,\n directoryDtag,\n DIRECTORY_PARAMS,\n listingId,\n parseChannelDirectoryContent,\n parseDirectoryContent,\n repointId,\n resolveDirectory,\n sameAddress,\n type AnchorAnswer,\n type CoinFacts,\n type DirectoryRecord,\n type ParsedDirectoryContent,\n} from '@orangecheck/lock-core/directory';\nimport { hexDecode } from '@orangecheck/lock-crypto';\nimport type { NostrEvent } from '@orangecheck/lock-device';\nimport {\n base64Decode,\n bitcoinAnchors,\n parseProof,\n type BlockHeaderSource,\n} from '@orangecheck/stamp-ots';\n\nimport referenceLegacy from './directory-legacy.json';\n\nexport type DirectoryNamespace = 'people' | 'channel';\n\n/** The reference deployment's directory relay (§8.2.6), a named availability anchor. */\nexport const DIRECTORY_RELAYS: readonly string[] = ['wss://relay.ochk.io'];\n/** Public relays the reference deployment reads as the audit (§8.2.6). */\nexport const AUDIT_RELAYS: readonly string[] = [\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.primal.net',\n];\n\nconst PAGE = 200;\n/** A directory relay answering more pages than this has not been read completely. */\nconst MAX_DIRECTORY_PAGES = 25;\nconst AUDIT_PAGES = 2;\n/** Distinct header reads one resolution may make; past this a header is unread. */\nconst HEADER_BUDGET = 128;\n\n/** One page from one relay: its events, and whether the relay finished answering (EOSE). */\nexport type PageRead = (\n relay: string,\n filter: { kinds: number[]; '#d': string[]; limit: number; until?: number }\n) => Promise<{ events: NostrEvent[]; complete: boolean }>;\n\nexport interface WalkDeps {\n page: PageRead;\n tip(): Promise<number>;\n headers: BlockHeaderSource;\n coin(outpoint: string): Promise<CoinFacts | 'no-answer'>;\n /** The keys a kind-30078 device record binds to `address`, or 'no-answer'. */\n boundKeys(address: string): Promise<string[] | 'no-answer'>;\n /** NIP-01 id and signature. */\n verifyEvent(ev: NostrEvent): boolean;\n /** The deployment's directory relays; the reference deployment's by default. */\n directoryRelays?: readonly string[];\n /** The public relays read as the audit; the reference deployment's by default. */\n auditRelays?: readonly string[];\n /** §8.2.8 claims a deployment anchored for v1 listings; the reference deployment's by default. */\n legacy?: readonly LegacyClaim[];\n}\n\n/** A claim as a listing carries it (§8.2.1, §8.2.9). */\nexport interface CarriedClaim {\n outpoint: string;\n nonce: string;\n ots: string;\n repoints: { prev: string; outpoint: string; nonce: string; ots: string }[];\n}\n\n/** A record the walk took, with the event it came from. */\nexport interface WalkRecord {\n record: DirectoryRecord;\n event: NostrEvent;\n content: Record<string, unknown>;\n /** A listing's claim; for the §8.2.8 legacy listing, the shipped one. */\n claim: CarriedClaim | null;\n}\n\nexport type HandleAnswer =\n | {\n result: 'holds';\n holder: string;\n claimId: string;\n coin: string;\n /** The holder's state: its freshest listing signed by a bound key. */\n listing: { event: NostrEvent; content: Record<string, unknown> };\n /** The claim that state carries, re-points included. */\n claim: CarriedClaim;\n anchor: number;\n tip: number;\n }\n | { result: 'E_DIR_UNRESOLVED' | 'E_DIR_REVOKED' | 'E_DIR_UNVERIFIED' | 'not_found' };\n\n/** A claim a deployment anchored for one v1 listing (§8.2.8). */\nexport interface LegacyClaim {\n listing_event_id: string;\n handle: string;\n address: string;\n outpoint: string;\n nonce: string;\n claim_id: string;\n ots: string;\n /** orangecheck's own listing, which the reference client lets carry a name it reserves. */\n orangecheck?: true;\n}\n/** The reference deployment's §8.2.8 claims. */\nexport const REFERENCE_LEGACY_CLAIMS: readonly LegacyClaim[] = referenceLegacy as LegacyClaim[];\n\nconst legacyIndex = (entries: readonly LegacyClaim[]) =>\n new Map(entries.map((e) => [e.listing_event_id, e]));\n\n/** Every event a relay holds under one d tag, paged by `until`; null when the read is not complete. */\nasync function readAll(\n page: PageRead,\n relay: string,\n d: string,\n maxPages: number\n): Promise<NostrEvent[] | null> {\n const seen = new Map<string, NostrEvent>();\n let until: number | undefined;\n for (let i = 0; i < maxPages; i++) {\n const got = await page(relay, {\n kinds: [30114],\n '#d': [d],\n limit: PAGE,\n ...(until === undefined ? {} : { until }),\n });\n if (!got.complete) return null;\n let added = 0;\n for (const ev of got.events) {\n if (!seen.has(ev.id)) {\n seen.set(ev.id, ev);\n added++;\n }\n until = until === undefined ? ev.created_at : Math.min(until, ev.created_at);\n }\n // A short page is the end; a full page that adds nothing is a stalled read.\n if (got.events.length < PAGE) return [...seen.values()];\n if (added === 0) return null;\n }\n return null;\n}\n\n/** Up to `pages` pages of what an audit relay holds; whatever it answered, or nothing. */\nasync function readSome(\n page: PageRead,\n relay: string,\n d: string,\n pages: number\n): Promise<NostrEvent[]> {\n const seen = new Map<string, NostrEvent>();\n let until: number | undefined;\n for (let i = 0; i < pages; i++) {\n let got: { events: NostrEvent[]; complete: boolean };\n try {\n got = await page(relay, {\n kinds: [30114],\n '#d': [d],\n limit: PAGE,\n ...(until === undefined ? {} : { until }),\n });\n } catch {\n break;\n }\n for (const ev of got.events) {\n seen.set(ev.id, ev);\n until = until === undefined ? ev.created_at : Math.min(until, ev.created_at);\n }\n if (!got.complete || got.events.length < PAGE) break;\n }\n return [...seen.values()];\n}\n\n/** A header source that reads each height once and stops reading past the budget (a read without an answer). */\nfunction budgetedHeaders(source: BlockHeaderSource): BlockHeaderSource {\n const memo = new Map<number, Promise<Uint8Array | null>>();\n return {\n getHeaderAt(height) {\n const hit = memo.get(height);\n if (hit) return hit;\n if (memo.size >= HEADER_BUDGET) return Promise.reject(new Error('header budget spent'));\n const p = source.getHeaderAt(height);\n memo.set(height, p);\n return p;\n },\n };\n}\n\n/** Events by the lowest Bitcoin attestation their claim's proof names, read without a header; then by id. */\nfunction byClaimedAnchor(\n handle: string,\n ns: DirectoryNamespace,\n legacy: ReadonlyMap<string, LegacyClaim>\n) {\n const keyOf = new Map<string, number>();\n const claimed = (ev: NostrEvent) => {\n let k = keyOf.get(ev.id);\n if (k === undefined) {\n k = Infinity;\n try {\n const p = parseEvent(ev, handle, ns, legacy);\n if (p?.parsed.kind === 'listing' && p.ots) {\n const heights = bitcoinAnchors(\n parseProof(base64Decode(p.ots), hexDecode(p.parsed.claimId))\n ).map((a) => a.blockHeight);\n if (heights.length) k = Math.min(...heights);\n }\n } catch {\n /* an unreadable proof goes last */\n }\n keyOf.set(ev.id, k);\n }\n return k;\n };\n return (a: NostrEvent, b: NostrEvent) =>\n claimed(a) - claimed(b) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0);\n}\n\n/** The parsed record of one event, the §8.2.8 legacy entry included; null drops it in step 1. */\nfunction parseEvent(\n ev: NostrEvent,\n handle: string,\n ns: DirectoryNamespace,\n legacy: ReadonlyMap<string, LegacyClaim>\n): { parsed: ParsedDirectoryContent; content: Record<string, unknown>; ots: string | null } | null {\n let content: unknown;\n try {\n content = JSON.parse(ev.content);\n } catch {\n return null;\n }\n if (!content || typeof content !== 'object' || Array.isArray(content)) return null;\n const c = content as Record<string, unknown>;\n const legacyEntry = ns === 'people' ? legacy.get(ev.id) : undefined;\n if (legacyEntry && c.v === 1) {\n // Exactly this v1 listing carries the shipped claim, and only while its bytes are the ones anchored.\n if (listingId(c as never) !== legacyEntry.nonce || c.opted_in !== true) return null;\n if (c.handle !== handle.toLowerCase() || c.address !== legacyEntry.address) return null;\n if (typeof c.inbox_pubkey !== 'string') return null;\n return {\n parsed: {\n kind: 'listing',\n address: legacyEntry.address,\n inboxPubkey: c.inbox_pubkey,\n createdAt: typeof c.created_at === 'number' ? c.created_at : 0,\n claim: {\n outpoint: legacyEntry.outpoint,\n nonce: legacyEntry.nonce,\n ots: legacyEntry.ots,\n repoints: [],\n },\n claimId: legacyEntry.claim_id,\n },\n content: c,\n ots: legacyEntry.ots,\n };\n }\n const parsed =\n ns === 'people'\n ? parseDirectoryContent(c, handle)\n : parseChannelDirectoryContent(c, handle);\n if (!parsed) return null;\n return { parsed, content: c, ots: parsed.kind === 'listing' ? parsed.claim.ots : null };\n}\n\n/** The records one d tag holds, anchors computed, each tagged with where it was found. */\nasync function collect(\n handle: string,\n ns: DirectoryNamespace,\n deps: WalkDeps\n): Promise<{\n records: WalkRecord[];\n directoryAnswered: boolean;\n tip: number;\n seen: number;\n} | null> {\n const d = ns === 'people' ? directoryDtag(handle) : channelDirectoryDtag(handle);\n const [directoryReads, auditReads, tip] = await Promise.all([\n Promise.all(\n (deps.directoryRelays ?? DIRECTORY_RELAYS).map((r) =>\n readAll(deps.page, r, d, MAX_DIRECTORY_PAGES).catch(() => null)\n )\n ),\n Promise.all(\n (deps.auditRelays ?? AUDIT_RELAYS).map((r) => readSome(deps.page, r, d, AUDIT_PAGES))\n ),\n deps.tip().catch(() => null),\n ]);\n if (tip === null) return null;\n const directoryAnswered = directoryReads.some((r) => r !== null);\n const onDirectory = new Set(directoryReads.flatMap((r) => r ?? []).map((e) => e.id));\n const all = new Map<string, NostrEvent>();\n for (const ev of [...directoryReads.flatMap((r) => r ?? []), ...auditReads.flat()])\n all.set(ev.id, ev);\n\n const headers = budgetedHeaders(deps.headers);\n const out: WalkRecord[] = [];\n // The header budget goes to the directory relay's records first, so public records\n // never turn its answer into E_DIR_UNRESOLVED (§8.2.6); then lowest claimed anchor\n // first, so no relay's answer order decides which claims are read.\n const legacy = legacyIndex(deps.legacy ?? REFERENCE_LEGACY_CLAIMS);\n const byAnchor = byClaimedAnchor(handle, ns, legacy);\n const order = (a: NostrEvent, b: NostrEvent) =>\n Number(!onDirectory.has(a.id)) - Number(!onDirectory.has(b.id)) || byAnchor(a, b);\n for (const ev of [...all.values()].sort(order)) {\n if (ev.kind !== 30114 || !deps.verifyEvent(ev)) continue;\n const p = parseEvent(ev, handle, ns, legacy);\n if (!p) continue;\n const { parsed, content } = p;\n // With no directory relay answering, the public read is the walk itself (§8.2.6).\n const source = !directoryAnswered || onDirectory.has(ev.id) ? 'directory' : 'public';\n if (parsed.kind === 'tombstone') {\n out.push({\n record: {\n kind: 'tombstone',\n address: parsed.address,\n key: ev.pubkey,\n createdAt: parsed.createdAt,\n ends: parsed.ends,\n source,\n },\n event: ev,\n content,\n claim: null,\n });\n continue;\n }\n // A listing is signed by its inbox key (§8.2.2 (1)).\n if (ev.pubkey !== parsed.inboxPubkey) continue;\n const anchor: AnchorAnswer = await directoryAnchor(\n parsed.claim.ots,\n parsed.claimId,\n headers\n );\n const repoints = [];\n for (const r of parsed.claim.repoints) {\n const id = repointId({\n claim: parsed.claimId,\n prev: r.prev,\n outpoint: r.outpoint,\n nonce: r.nonce,\n });\n repoints.push({\n repointId: id,\n prev: r.prev,\n outpoint: r.outpoint,\n anchor: await directoryAnchor(r.ots, id, headers),\n });\n }\n out.push({\n record: {\n kind: 'listing',\n address: parsed.address,\n key: ev.pubkey,\n createdAt: parsed.createdAt,\n claimId: parsed.claimId,\n outpoint: parsed.claim.outpoint,\n anchor,\n repoints,\n source,\n },\n event: ev,\n content,\n claim: parsed.claim,\n });\n }\n return { records: out, directoryAnswered, tip, seen: all.size };\n}\n\n/** A listing whose anchor has 6 confirmations at `tip`: only these, and tombstones, are states (§8.2.5 (3)). */\nfunction keptAt(tip: number) {\n return (r: WalkRecord) => {\n if (r.record.kind === 'tombstone') return true;\n const a = r.record.anchor;\n const h = a === null ? null : typeof a === 'number' ? a : a.unread;\n return h !== null && tip - h + 1 >= ANCHOR_CONFS;\n };\n}\n\n/** The freshest of `records` by `created_at`. */\nfunction freshest(records: readonly WalkRecord[]): WalkRecord | null {\n return records.reduce<WalkRecord | null>(\n (best, r) => (!best || r.record.createdAt > best.record.createdAt ? r : best),\n null\n );\n}\n\nexport type AddressState =\n | {\n kind: 'listing';\n event: NostrEvent;\n content: Record<string, unknown>;\n claimId: string;\n claim: CarriedClaim;\n }\n | { kind: 'tombstone'; event: NostrEvent; ends: string }\n | { kind: 'none' }\n | { kind: 'unresolved' };\n\ntype Collected = NonNullable<Awaited<ReturnType<typeof collect>>>;\n\n/** One address's state among collected records: its freshest kept record signed by a bound key. */\nasync function stateOf(got: Collected, address: string, deps: WalkDeps): Promise<AddressState> {\n const mine = got.records.filter((r) => sameAddress(r.record.address, address));\n if (mine.length === 0) return got.directoryAnswered ? { kind: 'none' } : { kind: 'unresolved' };\n const keys = await deps.boundKeys(address);\n if (keys === 'no-answer') return { kind: 'unresolved' };\n const state = freshest(mine.filter((r) => keys.includes(r.record.key)).filter(keptAt(got.tip)));\n if (!state) return got.directoryAnswered ? { kind: 'none' } : { kind: 'unresolved' };\n if (state.record.kind === 'tombstone')\n return { kind: 'tombstone', event: state.event, ends: state.record.ends };\n if (!state.claim) return { kind: 'unresolved' };\n return {\n kind: 'listing',\n event: state.event,\n content: state.content,\n claimId: state.record.claimId,\n claim: state.claim,\n };\n}\n\n/**\n * One address's own state under `handle` (§8.2.5 (3)): its freshest record signed by a\n * key bound to it, among the records step 1 keeps. A client reads this before it\n * publishes for the address, so it carries the claim's re-points (§8.2.7).\n */\nexport async function readAddressState(\n handle: string,\n ns: DirectoryNamespace,\n address: string,\n deps: WalkDeps\n): Promise<AddressState> {\n try {\n const got = await collect(handle, ns, deps);\n return got ? await stateOf(got, address, deps) : { kind: 'unresolved' };\n } catch {\n return { kind: 'unresolved' };\n }\n}\n\n/** Who holds `handle`, and `address`'s own state under it, from one read of the relays. */\nexport async function resolveWithState(\n handle: string,\n ns: DirectoryNamespace,\n address: string,\n deps: WalkDeps\n): Promise<{ answer: HandleAnswer; state: AddressState }> {\n const unresolved = {\n answer: { result: 'E_DIR_UNRESOLVED' as const },\n state: { kind: 'unresolved' as const },\n };\n try {\n const got = await collect(handle, ns, deps);\n if (!got) return unresolved;\n const memo = new Map<string, Promise<string[] | 'no-answer'>>();\n const once: WalkDeps = {\n ...deps,\n boundKeys: (a) => {\n if (!memo.has(a)) memo.set(a, deps.boundKeys(a));\n return memo.get(a)!;\n },\n };\n return { answer: await walkCollected(got, once), state: await stateOf(got, address, once) };\n } catch {\n return unresolved;\n }\n}\n\n/** Who holds `handle` in namespace `ns`, by the 0.4 walk. Never throws. */\nexport async function resolveDirectoryHandle(\n handle: string,\n ns: DirectoryNamespace,\n deps: WalkDeps\n): Promise<HandleAnswer> {\n try {\n const got = await collect(handle, ns, deps);\n return got ? await walkCollected(got, deps) : { result: 'E_DIR_UNRESOLVED' };\n } catch {\n return { result: 'E_DIR_UNRESOLVED' };\n }\n}\n\nasync function walkCollected(got: Collected, deps: WalkDeps): Promise<HandleAnswer> {\n const { records, directoryAnswered, tip, seen } = got;\n // Nothing at all under the d tag is \"not listed\", but only when the directory relay answered in full.\n if (seen === 0)\n return directoryAnswered ? { result: 'not_found' } : { result: 'E_DIR_UNRESOLVED' };\n\n const bound = new Map<string, string[]>();\n const params = directoryAnswered\n ? DIRECTORY_PARAMS\n : {\n ...DIRECTORY_PARAMS,\n // §8.2.6: with no directory relay answering, the audit's bounds bound the walk.\n bounds: {\n bindingReads: DIRECTORY_PARAMS.bounds.auditBindingReads,\n coinReads: DIRECTORY_PARAMS.bounds.auditCoinReads,\n auditBindingReads: DIRECTORY_PARAMS.bounds.auditBindingReads,\n auditCoinReads: DIRECTORY_PARAMS.bounds.auditCoinReads,\n },\n };\n const out = await resolveDirectory(\n records.map((r) => r.record),\n tip,\n {\n boundKeys: async (address) => {\n const keys = await deps.boundKeys(address);\n if (keys !== 'no-answer') bound.set(address, keys);\n return keys;\n },\n coin: (outpoint) => deps.coin(outpoint),\n },\n params\n );\n if (out.result !== 'holds') return { result: out.result };\n // The holder's state: its freshest listing signed by a bound key that the walk kept (§8.2.5 (3)).\n const keys = bound.get(out.holder) ?? [];\n const carrying = records.filter(\n (r) =>\n r.record.kind === 'listing' &&\n r.record.address === out.holder &&\n r.record.claimId === out.claimId &&\n keptAt(tip)(r)\n );\n const state = freshest(carrying.filter((r) => keys.includes(r.record.key)));\n // The claim's place is its lowest anchor among the copies, as the walk ordered it.\n const anchors = carrying\n .map((r) => (r.record.kind === 'listing' ? r.record.anchor : null))\n .filter((a): a is number => typeof a === 'number');\n if (!state || !state.claim || anchors.length === 0) return { result: 'E_DIR_UNRESOLVED' };\n const anchor = Math.min(...anchors);\n return {\n result: 'holds',\n holder: out.holder,\n claimId: out.claimId,\n coin: out.coin,\n listing: { event: state.event, content: state.content },\n claim: state.claim,\n anchor,\n tip,\n };\n}\n\nconst HANDLE_RE = /^[a-z0-9_]{3,32}$/;\n\n/** A handle's shape (§8.2.1): 3 to 32 of a-z, 0-9 and _. */\nexport function isValidHandle(h: string): boolean {\n return HANDLE_RE.test(h);\n}\n\nconst AVATAR_MAX_CHARS = 24 * 1024;\nconst AVATAR_DATA_URL_RE = /^data:image\\/(?:png|jpe?g|webp|gif);base64,[A-Za-z0-9+/=]+$/;\n\n/** A listing's avatar is safe to render iff it is a bounded raster data URL (§8.2.1):\n * never an svg, html or script data URL, and never huge. */\nexport function safeAvatar(s: unknown): s is string {\n return typeof s === 'string' && s.length <= AVATAR_MAX_CHARS && AVATAR_DATA_URL_RE.test(s);\n}\n","// Who a principal's kind-30078 records bind, from the records a relay holds:\n// OC Lock's rule for a Bitcoin address (@orangecheck/lock-device), §8.6 for a\n// did:oc. The caller looks the records up; these answer from them.\n\nimport { isDidOc } from '@orangecheck/auth-core/identifiers';\nimport {\n authorizedDevices,\n boundNostrKeys,\n verifyDeviceRecords,\n type NostrEvent,\n type ParsedDeviceEvent,\n} from '@orangecheck/lock-device';\n\nimport type { IsBound } from './channel';\nimport { verifyNostrEvent } from './event';\nimport { completeAnswers, meetsReadFloor, readFloor, UnansweredReadError, type VerifyBip322 } from './read';\nimport { liveSessionDevices, sessionDeviceDtag, sessionKeysEverBound, type AuthHostKey } from './session';\nimport { btcBindingLive, sessionBindingRevoked, type Liveness, type VersionBinding } from './version-binding';\n\nexport { isDidOc };\n\n/** The d-tag a Bitcoin address's device records are published under (OC Lock SPEC §3). */\nexport function addressDeviceDtag(address: string): string {\n return `oc-lock:device:${address}`;\n}\n\n/** The d-tag a principal's device records are published under: an address's, or a did:oc's session records. */\nexport function deviceDtag(principal: string): string {\n return isDidOc(principal) ? sessionDeviceDtag(principal) : addressDeviceDtag(principal);\n}\n\n/**\n * Every inbox key an address's verified records have bound, revoked ones too\n * (§8.3.1): an earlier channel version stands on its binding whatever became\n * of the key since. A device's own revocation replaces its bind record at the\n * relay, so for a device no bind record of which remains, the key that carried\n * its revocation counts. A revocation carried by a fresh key adds nothing.\n */\nexport function addressKeysEverBound(verified: readonly ParsedDeviceEvent[], now: Date = new Date()): string[] {\n const binds = verified.filter((p) => !p.revoked);\n const boundIds = new Set(binds.map((p) => p.device_id));\n const replaced = verified.filter((p) => p.revoked && !boundIds.has(p.device_id)).map((p) => p.nostrPubkey);\n return [...new Set([...authorizedDevices(binds, { now }).map((d) => d.nostrPubkey), ...replaced])];\n}\n\n/**\n * The kind-30078 records the relays hold under a principal's d-tag, and per relay\n * asked whether it finished answering (EOSE). A record seen on any relay counts.\n * A conclusion that rests on a record not being there needs the read floor\n * (§8.7, `meetsReadFloor`): \"bound now\" and \"live\" (no revocation seen), and\n * \"not bound\". Below it those are not read.\n */\nexport type RecordLookup = (\n principal: string\n) => Promise<{ events: NostrEvent[]; relayStatus: readonly { eose: boolean }[] }>;\n\nexport interface RecordReadOptions {\n /** The auth host's published keys, retired ones included (§8.6). Read only for a did:oc. */\n hostKeys: () => Promise<readonly AuthHostKey[]>;\n verifyBip322: VerifyBip322;\n /** The reader's clock. */\n now?: () => Date;\n}\n\n/** The binding reads a resolver needs, answered from looked-up records. */\nexport interface RecordReads {\n /** The keys a principal's records bind now, or 'no-answer' when the read is below the floor. */\n boundKeys(principal: string): Promise<string[] | 'no-answer'>;\n /** Throws UnansweredReadError when the read is below the floor: \"bound now\" and\n * \"not bound\" both rest on what was not seen. */\n isBound: IsBound;\n liveness(b: VersionBinding): Promise<Liveness>;\n everBoundKeys(principal: string): Promise<{ keys: string[]; answered: boolean; floor: boolean }>;\n}\n\n/** Binding reads over `lookup`, one lookup per principal for the life of the object. */\nexport function recordReads(lookup: RecordLookup, opts: RecordReadOptions): RecordReads {\n const now = () => (opts.now ? opts.now() : new Date());\n const looked = new Map<string, ReturnType<RecordLookup>>();\n const records = (p: string) => {\n if (!looked.has(p)) looked.set(p, lookup(p));\n return looked.get(p)!;\n };\n // What one read of a principal's records allows: anything it returned, once a\n // relay answered; what it did not return, only at the floor.\n const read = async (p: string) => {\n const { events, relayStatus } = await records(p);\n return { events, answered: completeAnswers(relayStatus) > 0, floor: meetsReadFloor(relayStatus), asked: relayStatus.length };\n };\n const verified = async (address: string) => {\n const { events, answered, floor } = await read(address);\n return {\n answered,\n floor,\n verified: await verifyDeviceRecords(events, address, { verifyBip322: opts.verifyBip322 }),\n };\n };\n const sessionEvents = async (didOc: string) => {\n const { events, answered, floor } = await read(didOc);\n // Only records signed by the key they name count for anything (§8.6).\n return { answered, floor, events: events.filter(verifyNostrEvent) };\n };\n // Which keys are bound now rests on no revocation being seen: the read must meet the floor.\n const boundKeys = async (principal: string): Promise<string[] | 'no-answer'> => {\n if (isDidOc(principal)) {\n const { events, floor } = await sessionEvents(principal);\n if (!floor) return 'no-answer';\n const keys = events.length > 0 ? await opts.hostKeys() : [];\n return liveSessionDevices(events, principal, keys).map((d) => d.nostrPubkey);\n }\n const v = await verified(principal);\n if (!v.floor) return 'no-answer';\n return boundNostrKeys(v.verified, { now: now() });\n };\n return {\n boundKeys,\n async isBound(pubkey, principal) {\n const keys = await boundKeys(principal);\n if (keys === 'no-answer') {\n const { answered, asked } = await read(principal);\n throw new UnansweredReadError(\n answered\n ? `fewer than ${readFloor(asked)} of ${asked} relays answered, so a record that binds or revokes this key may not have been seen`\n : undefined\n );\n }\n return keys.includes(pubkey);\n },\n // A revocation seen settles 'revoked' on any answer; 'live' rests on none being\n // seen, so it needs the floor.\n async liveness(b) {\n if (b.kind === 'btc') {\n const v = await verified(b.principal);\n if (!v.answered) return 'unknown';\n if (!btcBindingLive(b, v.verified, now())) return 'revoked';\n return v.floor ? 'live' : 'unknown';\n }\n const { events, answered, floor } = await sessionEvents(b.principal);\n if (!answered) return 'unknown';\n const keys = await opts.hostKeys();\n if (keys.length === 0) return 'unknown';\n if (sessionBindingRevoked(b, events, keys)) return 'revoked';\n return floor ? 'live' : 'unknown';\n },\n async everBoundKeys(principal) {\n if (isDidOc(principal)) {\n const { events, answered, floor } = await sessionEvents(principal);\n const keys = events.length > 0 ? await opts.hostKeys() : [];\n return { keys: sessionKeysEverBound(events, principal, keys), answered, floor };\n }\n const v = await verified(principal);\n return { keys: addressKeysEverBound(v.verified, now()), answered: v.answered, floor: v.floor };\n },\n };\n}\n\n/**\n * The Bitcoin address a session message's signing key steps up to (§8.6), or\n * null: of the addresses named by the OC Lock device records `nostrPk` itself\n * published (`authored`), the lexicographically smallest that binds it.\n */\nexport async function stepUpAddress(\n nostrPk: string,\n authored: readonly NostrEvent[],\n isBound: IsBound\n): Promise<string | null> {\n const prefix = addressDeviceDtag('');\n const candidates = new Set<string>();\n for (const e of authored) {\n if (e.kind !== 30078 || e.pubkey !== nostrPk || !verifyNostrEvent(e)) continue;\n const d = e.tags.find((t) => t[0] === 'd')?.[1] ?? '';\n if (!d.startsWith(prefix)) continue;\n const address = d.slice(prefix.length);\n if (address && !isDidOc(address)) candidates.add(address);\n }\n for (const address of [...candidates].sort()) {\n if (await isBound(nostrPk, address)) return address;\n }\n return null;\n}\n"]}
|