@ghostlytools/cli 1.3.7 → 1.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +8 -5
  2. package/SKILL.md +2 -0
  3. package/dist/assets/{api-BL0vpWGN.js → api-CYG-sByy.js} +2 -2
  4. package/dist/assets/{api-DlxlF4jP.js → api-Q6QZ0oIy.js} +50 -24
  5. package/dist/assets/api-Q6QZ0oIy.js.map +1 -0
  6. package/dist/assets/{apiKit-BnpVuZrZ.js → apiKit-C9lLXQwt.js} +2 -2
  7. package/dist/assets/{apiKit-BnpVuZrZ.js.map → apiKit-C9lLXQwt.js.map} +1 -1
  8. package/dist/assets/{apps-B_6Q-Mq-.js → apps-Bs8xpLGv.js} +1 -1
  9. package/dist/assets/{apps-Bs6QYQjm.js → apps-tcynvhlC.js} +2 -2
  10. package/dist/assets/{apps-Bs6QYQjm.js.map → apps-tcynvhlC.js.map} +1 -1
  11. package/dist/assets/{arkade-DwgUNqCz.js → arkade-BgmB0fUk.js} +2 -2
  12. package/dist/assets/{arkade-DwgUNqCz.js.map → arkade-BgmB0fUk.js.map} +1 -1
  13. package/dist/assets/{backup-BqtsbjOT.js → backup-OlEHNkqQ.js} +1 -1
  14. package/dist/assets/{backup-DEe1NqKb.js → backup-XtMACsQ0.js} +4 -4
  15. package/dist/assets/{backup-DEe1NqKb.js.map → backup-XtMACsQ0.js.map} +1 -1
  16. package/dist/assets/buttons-BoGOYSHb.js +2 -0
  17. package/dist/assets/{buttons-D9NQ3kV0.js → buttons-mdl2Gol2.js} +3 -3
  18. package/dist/assets/{buttons-D9NQ3kV0.js.map → buttons-mdl2Gol2.js.map} +1 -1
  19. package/dist/assets/{envelope-WC8QWYIL.js → envelope-DHf3mrHv.js} +2 -2
  20. package/dist/assets/{envelope-WC8QWYIL.js.map → envelope-DHf3mrHv.js.map} +1 -1
  21. package/dist/assets/{groupFiles-BrCMSXxg.js → groupFiles-CqrujNN1.js} +3 -3
  22. package/dist/assets/{groupFiles-BrCMSXxg.js.map → groupFiles-CqrujNN1.js.map} +1 -1
  23. package/dist/assets/{host-H0IYKNoK.js → host-Mz74S9cM.js} +29 -9
  24. package/dist/assets/host-Mz74S9cM.js.map +1 -0
  25. package/dist/assets/{hyperdhtRelay-CEfwbaCO.js → hyperdhtRelay-BnqdXvmv.js} +2 -2
  26. package/dist/assets/{hyperdhtRelay-CEfwbaCO.js.map → hyperdhtRelay-BnqdXvmv.js.map} +1 -1
  27. package/dist/assets/{irohWeb-Bn-JA2kp.js → irohWeb-C8iKFl8d.js} +2 -2
  28. package/dist/assets/{irohWeb-Bn-JA2kp.js.map → irohWeb-C8iKFl8d.js.map} +1 -1
  29. package/dist/assets/{main-DiCC-Vjq.js → main-BXwlJall.js} +52 -27
  30. package/dist/assets/main-BXwlJall.js.map +1 -0
  31. package/dist/assets/{mainline-gU7pE7s2.js → mainline-CbrPHUrZ.js} +2 -2
  32. package/dist/assets/{mainline-gU7pE7s2.js.map → mainline-CbrPHUrZ.js.map} +1 -1
  33. package/dist/assets/{networkReason-Dl9JThBQ.js → networkReason-CrrB031Y.js} +2 -2
  34. package/dist/assets/{networkReason-Dl9JThBQ.js.map → networkReason-CrrB031Y.js.map} +1 -1
  35. package/dist/assets/{nwc-CKjZjg-q.js → nwc-Cu5zwrE8.js} +3 -3
  36. package/dist/assets/{nwc-CKjZjg-q.js.map → nwc-Cu5zwrE8.js.map} +1 -1
  37. package/dist/assets/{nwcProvider-GDrc0HM4.js → nwcProvider-BVVFfJM5.js} +2 -2
  38. package/dist/assets/{nwcProvider-GDrc0HM4.js.map → nwcProvider-BVVFfJM5.js.map} +1 -1
  39. package/dist/assets/{registry-JGOFtJDE.js → registry-BKm8N_TI.js} +3 -3
  40. package/dist/assets/{registry-JGOFtJDE.js.map → registry-BKm8N_TI.js.map} +1 -1
  41. package/dist/assets/{registry-Wk7ZHuwm.js → registry-CshC1EyV.js} +1 -1
  42. package/dist/assets/{resolve-CVpEbud3.js → resolve-DKGaPeMz.js} +2 -2
  43. package/dist/assets/{resolve-CVpEbud3.js.map → resolve-DKGaPeMz.js.map} +1 -1
  44. package/dist/assets/{server-CkYscxE3.js → server-CaDVxJKy.js} +17 -13
  45. package/dist/assets/{server-CkYscxE3.js.map → server-CaDVxJKy.js.map} +1 -1
  46. package/dist/assets/{src-gJqfoRKI.js → src-CVYir6mP.js} +127 -17
  47. package/dist/assets/src-CVYir6mP.js.map +1 -0
  48. package/dist/assets/{turnRefs-zUQbFkl3.js → turnRefs-BeWsTX0o.js} +2 -2
  49. package/dist/assets/{turnRefs-zUQbFkl3.js.map → turnRefs-BeWsTX0o.js.map} +1 -1
  50. package/dist/assets/{usdt-BkDMGqZa.js → usdt-C5Q0BWHr.js} +3 -3
  51. package/dist/assets/{usdt-BkDMGqZa.js.map → usdt-C5Q0BWHr.js.map} +1 -1
  52. package/dist/ghostly.mjs +1 -1
  53. package/package.json +1 -1
  54. package/dist/assets/api-DlxlF4jP.js.map +0 -1
  55. package/dist/assets/buttons-CB1opfZP.js +0 -2
  56. package/dist/assets/host-H0IYKNoK.js.map +0 -1
  57. package/dist/assets/main-DiCC-Vjq.js.map +0 -1
  58. package/dist/assets/src-gJqfoRKI.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"api-DlxlF4jP.js","names":["TYPES","constants","randomBytes","randomBytes","open","METHODS"],"sources":["../../src/typing.ts","../../src/voicePeaks.ts","../../src/files.ts","../../src/statusCards.ts","../../src/holds.ts","../../src/views.ts","../../src/groupAdmin.ts","../../src/identities.ts","../../src/services.ts","../../src/calls/api.ts","../../src/appServe.ts","../../src/appEvents.ts","../../src/appChat.ts","../../src/wallets.ts","../../src/api.ts"],"sourcesContent":["import { TYPING_REFRESH_MS, type TypingKind } from \"@ghostly/core\";\nimport type { EngineState } from \"@ghostly/browser/shared/types\";\nimport { node, state, type ApiContext } from \"./apiKit\";\n\n/**\n * `typing --for` and `group typing --for`: a `start` holds 6 s on the other side (WISP 401 § Typing, WISP 902 · Group\n * Mesh § Typing), so the daemon says it again until the time is up, a message goes to that chat or group, or a\n * `--stop`. The engine sends a `start` at most once per refresh, counted from when the last one went: asking every half\n * refresh missed the tick at 3 s by a millisecond about half the time, so a start went every 4.5 s, 1.5 s inside the\n * contact's 6 s, and a busy machine flickered the contact's indicator off and on. Asking every half second sends one\n * at most 3.5 s after the last, and soon again when the send limit held one back.\n */\nconst KEEP_EVERY_MS = TYPING_REFRESH_MS / 6;\nconst keepers = new WeakMap<ApiContext, Map<string, () => void>>();\n\n/** Where typing is said: a 1:1 chat, or a private group. */\nexport type TypingTarget = { linkId: string } | { groupId: string };\ntype Word = { kind?: TypingKind; status?: string };\n\nfunction keepersOf(ctx: ApiContext): Map<string, () => void> {\n let map = keepers.get(ctx);\n if (!map) keepers.set(ctx, (map = new Map()));\n return map;\n}\n\nconst keyOf = (target: TypingTarget) => \"groupId\" in target ? `group:${target.groupId}` : target.linkId;\n\n/** Says it once: this side is typing (with its word), or stopped. */\nexport function sayTyping(ctx: ApiContext, target: TypingTarget, typing: boolean, word: Word = {}): void {\n const said = typing ? word : {};\n if (\"groupId\" in target) node(ctx).setGroupTyping({ groupId: target.groupId, typing, ...said });\n else node(ctx).setTyping({ linkId: target.linkId, typing, ...said });\n}\n\n/**\n * Says this side is typing in the chat or group for `ms`, with the kind and status it gave (`--kind`, `--status`) each\n * time; resolves when that ends, whichever way.\n */\nexport function keepTyping(ctx: ApiContext, target: TypingTarget, ms: number, word: Word = {}): Promise<void> {\n endTyping(ctx, target, false);\n const map = keepersOf(ctx), key = keyOf(target);\n return new Promise<void>((resolve) => {\n const end = () => { clearInterval(again); clearTimeout(until); off(); if (map.get(key) === end) map.delete(key); resolve(); };\n const again = setInterval(() => sayTyping(ctx, target, true, word), KEEP_EVERY_MS);\n const until = setTimeout(() => { end(); sayTyping(ctx, target, false); }, ms);\n // A message ends it, sent from anywhere (the engine said `stop` with it).\n const off = ctx.hub.onEvent((event) => {\n if (\"groupId\" in target ? event.type === \"group.sent\" && event.group === target.groupId : event.type === \"message.sent\" && event.chat === target.linkId) end();\n });\n map.set(key, end);\n });\n}\n\n/** How long a one-shot's `--for` waits for its chat or group to be live: a fresh one-shot connects first. */\nexport const ONE_SHOT_LIVE_GRACE_MS = 15_000;\n\n/**\n * A one-shot's `--for` (it holds the profile while it runs): kept the whole time once the chat or group is live, as a\n * daemon keeps it; ended when it is not live within `ONE_SHOT_LIVE_GRACE_MS`, since nobody would see it, and `--stop`\n * or a send from another shell could not end it.\n */\nexport async function keepOneShot(ctx: ApiContext, target: TypingTarget, kept: Promise<void>, live: (state: EngineState) => boolean): Promise<void> {\n let stop = () => {};\n const cameLive = new Promise<boolean>((resolve) => {\n if (live(state(ctx))) return resolve(true);\n const timer = setTimeout(() => { off(); resolve(false); }, ONE_SHOT_LIVE_GRACE_MS);\n const off = ctx.hub.onState((next) => { if (live(next)) { clearTimeout(timer); off(); resolve(true); } });\n stop = () => { clearTimeout(timer); off(); resolve(true); };\n });\n if (await Promise.race([kept.then(() => true), cameLive])) { stop(); await kept; return; }\n endTyping(ctx, target, false);\n}\n\n/** Ends a kept `--for` in the chat or group; `tell`: and says this side stopped. Whether one was kept. */\nexport function endTyping(ctx: ApiContext, target: TypingTarget, tell: boolean): boolean {\n const end = keepersOf(ctx).get(keyOf(target));\n if (!end) return false;\n end();\n if (tell) sayTyping(ctx, target, false);\n return true;\n}\n","import { spawn } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { voicePeaksOf } from \"@ghostly/core\";\n\n/**\n * The waveform and length of a voice note sent from a file (`file send --voice`), measured as the apps measure their\n * own recordings (packages/core voice.ts `voicePeaksOf`, the recorder's meter) so the bars look the same. The sound is\n * decoded here, without native code: WAV by hand, Opus in WebM or Ogg and MP3 with the wasm decoders, anything\n * else (AAC in MP4, FLAC…) with `ffmpeg` when it is on the PATH.\n */\n\nexport interface Sound {\n /** One channel, -1 to 1: the channels averaged, as the recorder's analyser hears them. */\n mono: Float32Array;\n sampleRate: number;\n}\n\nexport interface VoiceMeasure { duration: number; peaks: number[] }\n\n/** Longer than any voice note (15 minutes) with room: a file past it is not decoded into memory. */\nconst MAX_BYTES = 256 * 1024 * 1024;\nconst FFMPEG_TIMEOUT_MS = 120_000;\n\n/** The waveform and length of the sound in `path`, or why they could not be read. */\nexport async function measureVoice(path: string): Promise<{ voice: VoiceMeasure } | { problem: string }> {\n let sound: Sound;\n try {\n sound = await decodeSound(path);\n } catch (error) {\n return { problem: error instanceof Error ? error.message : String(error) };\n }\n if (sound.mono.length === 0) return { problem: \"no sound in it\" };\n return { voice: { duration: Math.round((sound.mono.length / sound.sampleRate) * 1000), peaks: voicePeaksOf(sound.mono, sound.sampleRate) } };\n}\n\nexport async function decodeSound(path: string): Promise<Sound> {\n const bytes = await readFile(path);\n if (bytes.length > MAX_BYTES) throw new Error(\"too large to decode\");\n let own: Error | undefined;\n try {\n const sound = await decodeBytes(bytes);\n if (sound) return sound;\n } catch (error) {\n own = error instanceof Error ? error : new Error(String(error));\n }\n try {\n return await decodeWithFfmpeg(path);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(own ? `${own.message}; ${reason}` : reason, { cause: error });\n }\n}\n\n/** The sound in a file this module decodes itself, or null for a kind it leaves to ffmpeg. */\nexport async function decodeBytes(bytes: Uint8Array): Promise<Sound | null> {\n if (ascii(bytes, 0, 4) === \"RIFF\" && ascii(bytes, 8, 4) === \"WAVE\") return decodeWav(bytes);\n if (bytes[0] === 0x1a && bytes[1] === 0x45 && bytes[2] === 0xdf && bytes[3] === 0xa3) {\n const opus = demuxWebm(bytes);\n return opus ? decodeOpus(opus) : null;\n }\n if (ascii(bytes, 0, 4) === \"OggS\") {\n const opus = demuxOgg(bytes);\n return opus ? decodeOpus(opus) : null;\n }\n if (ascii(bytes, 0, 3) === \"ID3\" || (bytes[0] === 0xff && (bytes[1]! & 0xe0) === 0xe0)) return decodeMp3(bytes);\n return null;\n}\n\nfunction ascii(bytes: Uint8Array, at: number, length: number): string {\n return String.fromCharCode(...bytes.subarray(at, at + length));\n}\n\nfunction mix(channels: Float32Array[], length: number): Float32Array {\n if (channels.length === 1) return channels[0]!.subarray(0, length);\n const mono = new Float32Array(length);\n for (const channel of channels) for (let i = 0; i < length; i++) mono[i]! += channel[i]! / channels.length;\n return mono;\n}\n\n// ---------- WAV ----------\n\n/** PCM (8, 16, 24 or 32 bit) or float (32 or 64 bit) WAV. A data chunk whose size is unknown (a pipe) runs to the end. */\nexport function decodeWav(bytes: Uint8Array): Sound {\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n let format = 0, channels = 0, sampleRate = 0, bits = 0;\n let at = 12;\n while (at + 8 <= bytes.length) {\n const id = ascii(bytes, at, 4);\n const size = view.getUint32(at + 4, true);\n const body = at + 8;\n if (id === \"fmt \") {\n format = view.getUint16(body, true);\n channels = view.getUint16(body + 2, true);\n sampleRate = view.getUint32(body + 4, true);\n bits = view.getUint16(body + 14, true);\n // WAVE_FORMAT_EXTENSIBLE: the real format is the sub-format GUID's first two bytes.\n if (format === 0xfffe && size >= 26) format = view.getUint16(body + 24, true);\n } else if (id === \"data\") {\n if (!channels || !sampleRate || !bits) throw new Error(\"a WAV without its format\");\n const end = size === 0 || size === 0xffffffff || body + size > bytes.length ? bytes.length : body + size;\n return { mono: wavSamples(view, body, end, format, channels, bits), sampleRate };\n }\n at = body + size + (size & 1);\n }\n throw new Error(\"a WAV without sound\");\n}\n\nfunction wavSamples(view: DataView, from: number, to: number, format: number, channels: number, bits: number): Float32Array {\n const width = bits / 8;\n const read: ((at: number) => number) | undefined =\n format === 1 && bits === 8 ? (at) => (view.getUint8(at) - 128) / 128\n : format === 1 && bits === 16 ? (at) => view.getInt16(at, true) / 32768\n : format === 1 && bits === 24 ? (at) => (((view.getInt8(at + 2) << 16) | (view.getUint8(at + 1) << 8) | view.getUint8(at)) / 8388608)\n : format === 1 && bits === 32 ? (at) => view.getInt32(at, true) / 2147483648\n : format === 3 && bits === 32 ? (at) => view.getFloat32(at, true)\n : format === 3 && bits === 64 ? (at) => view.getFloat64(at, true)\n : undefined;\n if (!read) throw new Error(`a WAV in a format not read here (${format}, ${bits} bit)`);\n const frames = Math.floor((to - from) / (width * channels));\n const mono = new Float32Array(frames);\n for (let frame = 0; frame < frames; frame++) {\n let sum = 0;\n for (let c = 0; c < channels; c++) sum += read(from + (frame * channels + c) * width);\n mono[frame] = sum / channels;\n }\n return mono;\n}\n\n// ---------- Opus (WebM, Ogg) ----------\n\nexport interface OpusStream {\n /** The OpusHead (RFC 7845): channels, pre-skip, channel mapping. */\n head: Uint8Array | null;\n channels: number;\n frames: Uint8Array[];\n /** Ogg's last granule position: where the sound really ends (the last frame is padded). */\n endGranule?: number;\n}\n\n/** A variable-length number in EBML: its length in bytes and value (the marker bit kept for ids, dropped for sizes). */\nfunction vint(bytes: Uint8Array, at: number, keepMarker: boolean): { length: number; value: number; unknown: boolean } | null {\n const first = bytes[at];\n if (first === undefined || first === 0) return null;\n const length = Math.clz32(first) - 23;\n if (at + length > bytes.length) return null;\n let value = keepMarker ? first : first & (0xff >> length);\n let allOnes = value === (0xff >> length);\n for (let i = 1; i < length; i++) {\n value = value * 256 + bytes[at + i]!;\n if (bytes[at + i] !== 0xff) allOnes = false;\n }\n return { length, value, unknown: !keepMarker && allOnes };\n}\n\n/** Elements whose children are read: EBML Segment, Tracks, TrackEntry, Audio, Cluster, BlockGroup. */\nconst WEBM_PARENTS = new Set([0x18538067, 0x1654ae6b, 0xae, 0xe1, 0x1f43b675, 0xa0]);\n\n/**\n * The Opus track of a WebM (Matroska) file. It reads the file in order, stepping into the elements that hold what it\n * needs rather than jumping by their sizes: MediaRecorder writes the Segment and every Cluster with an unknown size.\n */\nexport function demuxWebm(bytes: Uint8Array): OpusStream | null {\n interface Track { number: number; codec: string; head: Uint8Array | null; channels: number }\n const tracks: Track[] = [];\n const blocks: { track: number; data: Uint8Array }[] = [];\n let at = 0;\n while (at < bytes.length) {\n const id = vint(bytes, at, true);\n if (!id) break;\n const size = vint(bytes, at + id.length, false);\n if (!size) break;\n const body = at + id.length + size.length;\n if (WEBM_PARENTS.has(id.value)) {\n if (id.value === 0xae) tracks.push({ number: 0, codec: \"\", head: null, channels: 0 });\n at = body;\n continue;\n }\n if (size.unknown) break;\n const end = Math.min(bytes.length, body + size.value);\n const data = bytes.subarray(body, end);\n const track = tracks.at(-1);\n if (id.value === 0xd7 && track) track.number = uint(data);\n else if (id.value === 0x86 && track) track.codec = ascii(data, 0, data.length);\n else if (id.value === 0x63a2 && track) track.head = data;\n else if (id.value === 0x9f && track) track.channels = uint(data);\n else if (id.value === 0xa3 || id.value === 0xa1) {\n const number = vint(data, 0, false);\n if (number) for (const frame of laced(data, number.length)) blocks.push({ track: number.value, data: frame });\n }\n at = end;\n }\n const opus = tracks.find((t) => t.codec === \"A_OPUS\");\n if (!opus) return null;\n return { head: opus.head, channels: opus.channels || 1, frames: blocks.filter((b) => b.track === opus.number).map((b) => b.data) };\n}\n\nfunction uint(data: Uint8Array): number {\n let value = 0;\n for (const byte of data) value = value * 256 + byte;\n return value;\n}\n\n/** The frames in a (Simple)Block after its track number: one, or several laced (Xiph, fixed-size or EBML). */\nfunction laced(data: Uint8Array, at: number): Uint8Array[] {\n const flags = data[at + 2]!;\n let pos = at + 3;\n const lacing = (flags >> 1) & 3;\n if (lacing === 0) return [data.subarray(pos)];\n const count = data[pos++]! + 1;\n const sizes: number[] = [];\n if (lacing === 1) {\n for (let i = 0; i < count - 1; i++) {\n let size = 0;\n for (let byte = 255; byte === 255; size += byte) byte = data[pos++]!;\n sizes.push(size);\n }\n } else if (lacing === 3) {\n const first = vint(data, pos, false)!;\n pos += first.length;\n sizes.push(first.value);\n for (let i = 1; i < count - 1; i++) {\n const delta = vint(data, pos, false)!;\n pos += delta.length;\n // A signed difference from the size before: the value less half its range.\n sizes.push(sizes[i - 1]! + delta.value - (2 ** (7 * delta.length - 1) - 1));\n }\n } else {\n const each = Math.floor((data.length - pos) / count);\n for (let i = 0; i < count - 1; i++) sizes.push(each);\n }\n sizes.push(data.length - pos - sizes.reduce((a, b) => a + b, 0));\n const frames: Uint8Array[] = [];\n for (const size of sizes) { frames.push(data.subarray(pos, pos + size)); pos += size; }\n return frames;\n}\n\n/** The first Opus stream of an Ogg file: its packets put back together from the pages' segments. */\nexport function demuxOgg(bytes: Uint8Array): OpusStream | null {\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n let serial: number | undefined;\n let head: Uint8Array | null = null;\n const frames: Uint8Array[] = [];\n let packet: Uint8Array[] = [];\n let endGranule: number | undefined;\n let at = 0;\n while (at + 27 <= bytes.length && ascii(bytes, at, 4) === \"OggS\") {\n const segments = bytes[at + 26]!;\n const table = bytes.subarray(at + 27, at + 27 + segments);\n let pos = at + 27 + segments;\n const pageSerial = view.getUint32(at + 14, true);\n const granule = Number(view.getBigInt64(at + 6, true));\n const mine = serial === undefined ? ascii(bytes, pos, 8) === \"OpusHead\" : pageSerial === serial;\n if (mine) {\n serial = pageSerial;\n if (granule >= 0) endGranule = granule;\n for (const size of table) {\n packet.push(bytes.subarray(pos, pos + size));\n pos += size;\n if (size < 255) {\n const whole = packet.length === 1 ? packet[0]! : Buffer.concat(packet);\n packet = [];\n if (!head) head = whole;\n else if (ascii(whole, 0, 8) !== \"OpusTags\") frames.push(whole);\n }\n }\n } else pos += table.reduce((a, b) => a + b, 0);\n at = pos;\n }\n if (!head) return null;\n return { head, channels: head[9] ?? 1, frames, endGranule };\n}\n\nexport async function decodeOpus(stream: OpusStream): Promise<Sound> {\n const { OpusDecoder } = await import(\"opus-decoder\");\n const head = stream.head && ascii(stream.head, 0, 8) === \"OpusHead\" ? stream.head : null;\n const channels = head ? head[9]! : Math.max(1, stream.channels);\n const preSkip = head ? head[10]! | (head[11]! << 8) : 0;\n const family = head ? head[18]! : 0;\n const mapping = family !== 0 && head\n ? { streamCount: head[19]!, coupledStreamCount: head[20]!, channelMappingTable: [...head.subarray(21, 21 + channels)] }\n : { streamCount: 1, coupledStreamCount: channels - 1, channelMappingTable: channels === 1 ? [0] : [0, 1] };\n const decoder = new OpusDecoder({ channels, preSkip, ...mapping });\n await decoder.ready;\n try {\n const decoded = decoder.decodeFrames(stream.frames);\n let length = decoded.samplesDecoded;\n // Ogg says where the sound ends; the rest of the last frame is padding.\n if (stream.endGranule !== undefined && stream.endGranule > preSkip) length = Math.min(length, stream.endGranule - preSkip);\n return { mono: mix(decoded.channelData, length), sampleRate: decoded.sampleRate };\n } finally {\n decoder.free();\n }\n}\n\n// ---------- MP3 ----------\n\nexport async function decodeMp3(bytes: Uint8Array): Promise<Sound> {\n const { MPEGDecoder } = await import(\"mpg123-decoder\");\n const decoder = new MPEGDecoder();\n await decoder.ready;\n try {\n const decoded = decoder.decode(bytes);\n if (!decoded.samplesDecoded) throw new Error(\"no MP3 frames in it\");\n return { mono: mix(decoded.channelData, decoded.samplesDecoded), sampleRate: decoded.sampleRate };\n } finally {\n decoder.free();\n }\n}\n\n// ---------- ffmpeg ----------\n\n/** Anything ffmpeg reads, as a float WAV on its output (the channels kept, so they are averaged as above). */\nexport function decodeWithFfmpeg(path: string, command = process.env.GHOSTLY_FFMPEG || \"ffmpeg\"): Promise<Sound> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, [\"-v\", \"error\", \"-nostdin\", \"-i\", path, \"-vn\", \"-f\", \"wav\", \"-c:a\", \"pcm_f32le\", \"-\"], { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n const chunks: Buffer[] = [];\n let size = 0, errors = \"\";\n const timer = setTimeout(() => child.kill(\"SIGKILL\"), FFMPEG_TIMEOUT_MS);\n child.stdout.on(\"data\", (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_BYTES * 2) child.kill(\"SIGKILL\");\n else chunks.push(chunk);\n });\n child.stderr.on(\"data\", (chunk: Buffer) => { if (errors.length < 2000) errors += chunk.toString(); });\n child.on(\"error\", (error: NodeJS.ErrnoException) => {\n clearTimeout(timer);\n reject(new Error(error.code === \"ENOENT\" ? \"no decoder here for this kind of audio (install ffmpeg to read it)\" : `ffmpeg: ${error.message}`));\n });\n child.on(\"close\", (code) => {\n clearTimeout(timer);\n if (code !== 0) { reject(new Error(`ffmpeg could not read it${errors.trim() ? `: ${errors.trim().split(\"\\n\")[0]}` : \"\"}`)); return; }\n try { resolve(decodeWav(Buffer.concat(chunks))); } catch (error) { reject(error); }\n });\n });\n}\n","import { openAsBlob } from \"node:fs\";\nimport { access, constants, open, rm, stat } from \"node:fs/promises\";\nimport { basename, extname, join, resolve } from \"node:path\";\nimport { GROUP_FILE_LIMITS, LIMITS, PLAYABLE_AUDIO, VOICE_LIMITS, baseMime, parseVoiceMeta, randomBytes, readImageMeta, sanitizeFileName, sanitizeMime, toBase64Url, type VoiceMeta } from \"@ghostly/core\";\nimport { FILE_BYTES_STEP, fileBytes, fileBytesOf } from \"@ghostly/browser/shared/fileBytes\";\nimport { fileStore } from \"@ghostly/browser/shared/idb\";\nimport { removeStored, waitingGroupFile } from \"@ghostly/browser/shared/storedFiles\";\nimport { replyRef } from \"@ghostly/browser/shared/replies\";\nimport type { GroupView, MessageFile } from \"@ghostly/browser/shared/types\";\nimport { groupFileId, groupOfFile } from \"@ghostly/browser/engine/groupFiles\";\nimport { bool, chatOf, findChatOrGroup, list, node, num, oneOf, sentAt, state, str, waitForState, type ApiContext, type Method, type Params } from \"./apiKit\";\nimport { groupSendRefused } from \"./api\";\nimport { CliError } from \"./errors\";\nimport { endTyping } from \"./typing\";\nimport { measureVoice } from \"./voicePeaks\";\n\n/**\n * Files and voice notes in a chat (WISP 1100, phase 3), as the app's composer sends them (packages/browser\n * platform/services.ts `sendFile`): the bytes go into the profile's file store first, then the engine offers them.\n * Large files follow files/3: the receiving side's person (here, a command) accepts or declines each offer.\n *\n * In a group (WISP 503 · Group Files) the file is announced as a group message, and each member's app fetches the\n * bytes from whoever holds them: by itself up to the automatic limits, on `file accept` past them.\n */\n\nconst TYPES: Record<string, string> = {\n \".png\": \"image/png\", \".jpg\": \"image/jpeg\", \".jpeg\": \"image/jpeg\", \".gif\": \"image/gif\", \".webp\": \"image/webp\",\n \".pdf\": \"application/pdf\", \".txt\": \"text/plain\", \".md\": \"text/markdown\", \".json\": \"application/json\", \".csv\": \"text/csv\",\n \".zip\": \"application/zip\", \".mp3\": \"audio/mpeg\", \".m4a\": \"audio/mp4\", \".ogg\": \"audio/ogg\", \".opus\": \"audio/ogg\", \".wav\": \"audio/wav\",\n \".webm\": \"audio/webm\", \".mp4\": \"video/mp4\", \".mov\": \"video/quicktime\",\n};\n\nexport function mimeOf(path: string, given?: string): string {\n return sanitizeMime(given ?? TYPES[extname(path).toLowerCase()] ?? \"application/octet-stream\");\n}\n\n/** A chat's files as the timeline shows them, with where each transfer stands (`transferOf`, by file id). */\nexport function filesOf(messages: { id: string; file?: MessageFile; sender: string; timestamp: number }[], transferOf: (fileId: string) => unknown) {\n return messages.filter((m) => m.file).map((m) => ({\n messageId: m.id, from: m.sender, timestamp: m.timestamp,\n file: { id: m.file!.id, name: m.file!.name, size: m.file!.size, mime: m.file!.mime, ...(m.file!.voice ? { voice: m.file!.voice } : {}), ...(m.file!.image ? { image: m.file!.image } : {}) },\n transfer: transferOf(m.file!.id) ?? null,\n }));\n}\n\n/** The chat or the group a file command names (`findChatOrGroup`). */\nconst chatOrGroupOf = (ctx: ApiContext, params: Params) => findChatOrGroup(state(ctx).links, state(ctx).groups, str(params, \"chat\", true));\n\n/**\n * The chat or group a file belongs to: a file id starts with its chat's id (a group's file with `group-<id>-`), so it\n * may be left out; given, it must be the file's own. `where` is what the answer names it by.\n */\nfunction fileChat(ctx: ApiContext, params: Params, fileId: string): { linkId: string; where: { chat: string } | { group: string } } {\n const groupId = groupOfFile(fileId, state(ctx).groups.map((g) => g.id));\n if (groupId) {\n const named = params.chat === undefined ? undefined : chatOrGroupOf(ctx, params);\n if (named && !(\"group\" in named && named.group.id === groupId)) throw new CliError(\"not_found\", `No file ${fileId} in this ${\"group\" in named ? \"group\" : \"chat\"}`);\n return { linkId: `group:${groupId}`, where: { group: groupId } };\n }\n const link = params.chat === undefined\n ? state(ctx).links.find((l) => fileId.startsWith(`${l.id}-in-`) || fileId.startsWith(`${l.id}-out-`))\n : chatOf(ctx, params);\n if (!link) throw new CliError(\"not_found\", `No file ${fileId}`);\n if (!fileId.startsWith(`${link.id}-`)) throw new CliError(\"not_found\", `No file ${fileId} in this chat`);\n return { linkId: link.id, where: { chat: link.id } };\n}\n\nconst VOICE_ONLY = \"A voice note is audio (webm, ogg, mp4, mpeg, aac, m4a or wav) of at most 15 minutes, with peaks from 0 to 255\";\n\n/** `--voice [ms] [--peaks …]`: the voice description, its length and waveform measured from the sound when not given. */\nasync function voiceOf(params: Params, path: string, mime: string): Promise<{ voice?: VoiceMeta; warning?: string }> {\n if (params.voice === undefined) return {};\n if (!PLAYABLE_AUDIO.test(baseMime(mime))) throw new CliError(\"bad_request\", VOICE_ONLY);\n // Without a length or a waveform, both are measured from the sound, as the apps measure their recordings.\n let duration = params.voice === true ? undefined : num(params, \"voice\", 0, { min: 1 });\n let peaks = list(params, \"peaks\").map(Number);\n let warning: string | undefined;\n if (duration === undefined || !peaks.length) {\n const measured = await measureVoice(path);\n if (\"voice\" in measured) {\n duration ??= measured.voice.duration;\n if (!peaks.length) peaks = measured.voice.peaks;\n } else if (duration === undefined) {\n throw new CliError(\"bad_request\", `Could not measure the voice note (${measured.problem}): give its length as --voice <ms>`);\n } else warning = `Sent without a waveform: could not read the sound (${measured.problem})`;\n }\n const voice = parseVoiceMeta({ duration, peaks: peaks.length ? peaks : new Array(VOICE_LIMITS.bars).fill(0) }, mime);\n if (!voice) throw new CliError(\"bad_request\", VOICE_ONLY);\n return { voice, ...(warning ? { warning } : {}) };\n}\n\n/**\n * A file announced in a group (WISP 503): its bytes staged under a group file id with their digest, as a chat's are, then\n * the announcement. This device is its first holder and serves the members who ask.\n */\nasync function sendToGroup(ctx: ApiContext, params: Params, group: GroupView, path: string, size: number) {\n if (size > GROUP_FILE_LIMITS.maxBytes) throw new CliError(\"refused\", `Too large for a group (at most ${GROUP_FILE_LIMITS.maxBytes} bytes)`);\n if (!size) throw new CliError(\"refused\", \"An empty file cannot go to a group\");\n const mime = mimeOf(path, str(params, \"mime\"));\n const replyTo = str(params, \"reply\");\n if (replyTo) {\n const messages = await node(ctx).groupMessages({ groupId: group.id });\n if (!messages.some((m) => m.id === replyTo || replyRef(m) === replyTo)) throw new CliError(\"not_found\", \"That message is not in this group, or cannot be replied to\");\n }\n // A send the group would refuse anyway (its files of the minute are taken, or this device is not in it) is refused\n // before a byte is copied in: a retry loop writes nothing. The announcement checks again.\n const check = await node(ctx).groupFileCheck({ groupId: group.id });\n if (check.error) throw check.refused ? new CliError(\"refused\", check.error) : groupSendRefused(check.error);\n const { voice, warning } = await voiceOf(params, path, mime);\n const source = await openAsBlob(path, { type: mime });\n const image = voice ? undefined : await readImageMeta(source, mime);\n const fileId = groupFileId(group.id, \"out\");\n const file: MessageFile = { id: fileId, name: sanitizeFileName(str(params, \"name\") ?? basename(path)), size, mime, ...(voice ? { voice } : {}), ...(image ? { image } : {}) };\n const timestamp = Date.now();\n const bytes = await fileBytes();\n const digest = await bytes.stage(fileId, source);\n await fileStore.put({\n id: fileId, linkId: `group:${group.id}`, bytes: bytes.kind, digest, createdAt: timestamp, direction: \"out\",\n metadata: { name: file.name, size, mime, timestamp, ...(voice ? { voice } : {}), ...(image ? { image } : {}) },\n transfer: { state: \"transferring\", transferred: 0, size },\n });\n endTyping(ctx, { groupId: group.id }, false);\n const result = await node(ctx).sendGroupFile({ groupId: group.id, file, ...(replyTo ? { replyTo } : {}) });\n if (result.error) {\n // Not announced: nothing is in the group, so the staged copy goes too.\n await removeStored(fileId).catch(() => {});\n throw result.refused ? new CliError(\"refused\", result.error) : groupSendRefused(result.error);\n }\n return { group: group.id, messageId: result.messageId ?? null, file: { id: fileId, name: file.name, size, mime, ...(voice ? { voice: true } : {}), ...(image ? { image } : {}) }, ...(warning ? { warning } : {}) };\n}\n\n/** Bytes a file system takes in one name: 255 on ext4, btrfs, APFS (NTFS counts 255 UTF-16 units, within this too). */\nconst NAME_BYTES = 255;\n\n/**\n * `name` as an entry of a folder: an app's name may have 200 characters, which in UTF-8 can be 800 bytes. The end of\n * its stem goes until it fits, its extension stays (as `sanitizeFileName` shortens it), so \"文…文.txt\" is saved as a text.\n */\nexport function fitName(name: string): string {\n const fits = (candidate: string) => Buffer.byteLength(candidate) <= NAME_BYTES;\n if (fits(name)) return name;\n const extension = /\\.[^.\\s]{1,15}$/u.exec(name)?.[0] ?? \"\";\n const stem = [...name.slice(0, name.length - extension.length)];\n while (stem.length && !fits(stem.join(\"\").trimEnd() + extension)) stem.pop();\n return (stem.join(\"\").trimEnd() || \"file\") + extension;\n}\n\n/**\n * The name `file save --dir` writes a file under. Its sender chose it, and the folder is one scripts and people run\n * tools in: a name that starts with a dash is an option to the tool a `*` hands it to (\"-rf\", \"--checkpoint-action=…\"),\n * so it gets a `_` first, as a Windows device name does in `sanitizeFileName`.\n */\nexport function saveName(name: string): string {\n const clean = sanitizeFileName(name);\n return fitName(clean.startsWith(\"-\") ? `_${clean}` : clean);\n}\n\nconst ACTIONS = [\"accept\", \"decline\", \"pause\", \"resume\", \"cancel\", \"resend\", \"request\"] as const;\n\nexport const FILE_METHODS: Record<string, Method> = {\n async \"file.send\"(ctx, params) {\n const target = chatOrGroupOf(ctx, params);\n const path = resolve(str(params, \"path\", true));\n let info;\n try { info = await stat(path); } catch { throw new CliError(\"not_found\", `No file ${path}`); }\n if (!info.isFile()) throw new CliError(\"bad_request\", `${path} is not a file`);\n // A file this user may not read: refused with its path (errors.ts), not the engine's \"The blob could not be read\" later.\n await access(path, constants.R_OK);\n if (\"group\" in target) return sendToGroup(ctx, params, target.group, path, info.size);\n const { link } = target;\n if (link.profile && link.dataLink === \"open\" && !link.capabilities?.files) throw new CliError(\"unavailable\", \"The contact's app takes no files\");\n if (!link.capabilities?.largeFiles && info.size > LIMITS.maxFileBytes) throw new CliError(\"refused\", `Too large for the contact's app (at most ${LIMITS.maxFileBytes} bytes)`);\n if (typeof link.peerFileRoom === \"number\" && info.size > link.peerFileRoom) throw new CliError(\"refused\", `Not enough space on the contact's device (${link.peerFileRoom} bytes free)`);\n const mime = mimeOf(path, str(params, \"mime\"));\n // A reply names a message of this chat, as `send --reply` does: checked before anything is stored.\n const replyTo = str(params, \"reply\");\n if (replyTo) {\n const messages = await node(ctx).getMessages(link.id);\n if (!messages.some((m) => m.id === replyTo || replyRef(m) === replyTo)) throw new CliError(\"not_found\", \"That message is not in this chat, or cannot be replied to\");\n }\n const { voice, warning } = await voiceOf(params, path, mime);\n const source = await openAsBlob(path, { type: mime });\n // A picture goes with its size, read from its first bytes as the apps read it (PNG, JPEG, GIF, WebP).\n const image = voice ? undefined : await readImageMeta(source, mime);\n const wireId = toBase64Url(randomBytes(12));\n const file: MessageFile = { id: `${link.id}-out-${wireId}`, name: sanitizeFileName(str(params, \"name\") ?? basename(path)), size: info.size, mime, ...(voice ? { voice } : {}), ...(image ? { image } : {}) };\n const timestamp = sentAt();\n const bytes = await fileBytes();\n const digest = await bytes.stage(file.id, source);\n await fileStore.put({\n id: file.id, linkId: link.id, bytes: bytes.kind, digest, createdAt: timestamp, direction: \"out\", wireId,\n metadata: { name: file.name, size: file.size, mime: file.mime, timestamp, ...(voice ? { voice } : {}), ...(image ? { image } : {}) },\n transfer: { state: \"transferring\", transferred: 0, size: file.size },\n });\n endTyping(ctx, { linkId: link.id }, true);\n try {\n await node(ctx).sendFile({ linkId: link.id, file, timestamp, ...(replyTo ? { replyTo } : {}) });\n } catch (error) {\n // Refused before it started (offline, a stopped chat, a contact whose app takes no files): nothing is in the chat,\n // so the staged copy goes too.\n await removeStored(file.id).catch(() => {});\n throw new CliError(\"refused\", error instanceof Error ? error.message : String(error));\n }\n return { chat: link.id, file: { id: file.id, name: file.name, size: file.size, mime: file.mime, ...(voice ? { voice: true } : {}), ...(image ? { image } : {}) }, ...(warning ? { warning } : {}) };\n },\n\n async \"file.list\"(ctx, params) {\n const target = chatOrGroupOf(ctx, params);\n const views = state(ctx).transfers;\n // A file that finished before this run has no transfer in the engine's state: its record says it is done. Nor has a\n // group's file waiting for a Download: its record says it is not here.\n const keptOf = async (linkId: string) => new Map((await fileStore.listForLink(linkId).catch(() => [])).flatMap((f) => {\n const kept = f.transfer?.state === \"done\" ? { ...f.transfer, direction: f.direction } : waitingGroupFile(f);\n return kept ? [[f.id, kept] as const] : [];\n }));\n if (\"group\" in target) {\n const kept = await keptOf(`group:${target.group.id}`);\n return { group: target.group.id, files: filesOf(await node(ctx).groupMessages({ groupId: target.group.id }), (id) => views[id] ?? kept.get(id)) };\n }\n const kept = await keptOf(target.link.id);\n return { chat: target.link.id, files: filesOf(await node(ctx).getMessages(target.link.id), (id) => views[id] ?? kept.get(id)) };\n },\n\n /**\n * files/3: answer an offer, or pause, resume or cancel a transfer, either way; `resend` a file sent from here that\n * stopped moving (or failed), `request` again one that stopped arriving. Without a chat, the file's id names it.\n * A group's file (WISP 503) takes `accept` (download one this device did not fetch by itself), `request`, and `cancel`,\n * `decline`, `pause` and `resume` for one that is coming.\n */\n async \"file.action\"(ctx, params) {\n const fileId = str(params, \"file\", true);\n const { linkId, where } = fileChat(ctx, params, fileId);\n const action = oneOf(params, \"action\", ACTIONS, \"accept\");\n // One all here has no transfer in the engine's state, only its record; the engine takes any action on it and does nothing.\n const refuseAllHere = async () => {\n if ((state(ctx).transfers[fileId] ?? (await fileStore.get(fileId).catch(() => undefined))?.transfer)?.state === \"done\") throw new CliError(\"refused\", action === \"accept\" || action === \"request\" || action === \"resume\" ? \"Nothing to ask for: the file is all here\" : \"Nothing to stop: the file is all here\");\n };\n if (\"group\" in where) {\n if (action === \"resend\") throw new CliError(\"bad_request\", \"A group's file is downloaded (file accept) or asked for again (file request)\");\n await refuseAllHere();\n try { await node(ctx).fileAction({ linkId, fileId, action }); } catch (error) { throw new CliError(\"refused\", error instanceof Error ? error.message : String(error)); }\n return { ...where, file: fileId, action, transfer: state(ctx).transfers[fileId] ?? null };\n }\n if (action === \"resend\" || action === \"request\") {\n const outgoing = fileId.startsWith(`${linkId}-out-`);\n if (outgoing !== (action === \"resend\")) throw new CliError(\"bad_request\", outgoing ? \"A file sent from here is sent again: file resend\" : \"A received file is asked for again: file request\");\n const transfer = state(ctx).transfers[fileId];\n if (!transfer || transfer.state === \"done\") throw new CliError(\"refused\", outgoing ? \"Nothing to send again: it arrived whole\" : \"Nothing to ask for: the file is all here\");\n if (transfer.state === \"failed\" && (!outgoing || !transfer.retry)) throw new CliError(\"refused\", `It ended: ${transfer.error ?? \"failed\"}`);\n } else await refuseAllHere();\n await node(ctx).fileAction({ linkId, fileId, action });\n return { ...where, file: fileId, action, transfer: state(ctx).transfers[fileId] ?? null };\n },\n\n /**\n * Until a transfer ends: done answers, failed is an `engine` error with the transfer's words (and whether `file\n * resend` can go on). A file whose transfer this run has not seen answers from the file store.\n */\n async \"file.wait\"(ctx, params) {\n const fileId = str(params, \"file\", true);\n const { where } = fileChat(ctx, params, fileId);\n const stored = await fileStore.get(fileId);\n if (!stored && !state(ctx).transfers[fileId]) throw new CliError(\"not_found\", `No file ${fileId}`);\n const ms = num(params, \"timeout\", 300, { min: 1, max: 86_400 }) * 1000;\n const transfer = await waitForState(ctx, (s) => {\n const now = s.transfers[fileId] ?? stored?.transfer;\n return now && (now.state === \"done\" || now.state === \"failed\") ? now : undefined;\n }, ms, `file ${fileId} to arrive`).catch((error: unknown) => {\n const now = state(ctx).transfers[fileId];\n if (error instanceof CliError && error.code === \"timeout\" && now) throw new CliError(\"timeout\", `${error.message} (${now.transferred} of ${now.size} bytes${now.stage ? `, ${now.stage}` : \"\"})`, { file: fileId, transferred: now.transferred, size: now.size, stage: now.stage ?? null });\n throw error;\n });\n if (transfer.state === \"failed\") throw new CliError(\"engine\", transfer.error ?? \"The transfer failed\", { file: fileId, ...where, retry: !!transfer.retry });\n return { ...where, file: fileId, state: \"done\", size: transfer.size };\n },\n\n /** Writes a received (or sent) file to disk: into `dir` under its own name (`saveName`), or to `path`. Never over a file unless `force`. */\n async \"file.save\"(ctx, params) {\n const fileId = str(params, \"file\", true);\n if (params.chat !== undefined) fileChat(ctx, params, fileId);\n if (bool(params, \"wait\")) await FILE_METHODS[\"file.wait\"](ctx, { file: fileId, timeout: params.timeout });\n const stored = await fileStore.get(fileId);\n if (!stored?.metadata) throw new CliError(\"not_found\", `No file ${fileId}`);\n if (stored.leftOut) throw new CliError(\"not_found\", \"Not in this backup: the light backup this profile was restored from left the file out\");\n // A sent file's bytes were staged whole at send: its transfer is the contact's download, not bytes missing here.\n const transfer = stored.direction === \"out\" ? undefined : state(ctx).transfers[fileId] ?? stored.transfer;\n if (transfer && transfer.state !== \"done\") throw new CliError(\"unavailable\", `The file is not all here yet (${transfer.transferred} of ${transfer.size} bytes)`);\n const target = str(params, \"path\") ? resolve(str(params, \"path\", true)) : join(resolve(str(params, \"dir\") ?? \".\"), saveName(stored.metadata.name));\n const flags = bool(params, \"force\") ? \"w\" : \"wx\";\n let out;\n try { out = await open(target, flags, 0o600); } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n // A folder there is no file to replace: before, it asked for --force, and the --force then failed \"is a folder\".\n if ((code === \"EEXIST\" || code === \"EISDIR\") && (await stat(target).catch(() => undefined))?.isDirectory()) throw new CliError(\"bad_request\", `${target} is a folder: name a file, or use dir (--dir ${target})`);\n if (code === \"EEXIST\") throw new CliError(\"confirm\", `${target} exists: pass force (--force) to replace it`);\n throw error;\n }\n let written = 0, complete = false;\n try {\n const backend = stored.bytes ? await fileBytesOf(stored.bytes) : null;\n if (backend) {\n const size = await backend.size(fileId);\n if (size === null) throw new CliError(\"not_found\", \"The file's bytes are not on this device\");\n for (let offset = 0; offset < size; offset += FILE_BYTES_STEP) {\n const chunk = await backend.read(fileId, offset, FILE_BYTES_STEP);\n await out.write(chunk);\n written += chunk.length;\n }\n } else if (stored.blob) {\n const chunk = new Uint8Array(await stored.blob.arrayBuffer());\n await out.write(chunk);\n written = chunk.length;\n } else throw new CliError(\"not_found\", \"The file's bytes are not on this device\");\n complete = true;\n } finally {\n await out.close();\n if (!complete) await rm(target, { force: true });\n }\n return { file: fileId, path: target, size: written, name: stored.metadata.name, mime: stored.metadata.mime };\n },\n};\n","import { STATUS_CARD_LIMITS, cardLine, checkStatusCard, randomBytes, toBase64Url, type StatusCard } from \"@ghostly/core\";\nimport type { StoredMessage } from \"@ghostly/browser/shared/types\";\nimport { findSecret } from \"../../../apps/ui/src/lib/parse/secrets\";\nimport { bool, chatOrGroup, node, num, oneOf, state, str, type ApiContext, type Method, type Params } from \"./apiKit\";\nimport { CliError, asCliError } from \"./errors\";\nimport { waitForEdit, waitForGroupFrame, waitForMessage } from \"./waits\";\n\n/*\n * Status cards (WISP 405 · Status Cards): a bot's task or routine, sent as a message with a card and kept current by\n * editing it. A routine's run (`run`) becomes its last run and the newest of its recent runs.\n * The engine checks every card by the sender's rule and writes its fallback text; this is the bot's side of it: a card\n * built from flags or JSON, found again by its id, merged with an update, and paced, one update per card every\n * `CARD_UPDATE_GAP_MS`. An update that comes sooner is merged into the next one, which goes when the time is up.\n */\n\n/** A card's updates go at most this often: the rest merge into the next, so a chatty bot spends few edits. */\nexport const CARD_UPDATE_GAP_MS = 2_500;\n\ntype Kind = StatusCard[\"kind\"];\ntype Target = { id: string; linkId: string; group: boolean };\n\n/** Per card (its message): when its last update went, what waits to go next, and how to send it now. */\ninterface Pace { last: number; next?: Record<string, unknown>; timer?: ReturnType<typeof setTimeout>; flushed?: Promise<void>; flush?: () => void }\nconst paces = new WeakMap<ApiContext, Map<string, Pace>>();\n\nfunction paceOf(ctx: ApiContext, key: string): Pace {\n let map = paces.get(ctx);\n if (!map) paces.set(ctx, (map = new Map()));\n let pace = map.get(key);\n if (!pace) map.set(key, (pace = { last: 0 }));\n return pace;\n}\n\nconst isObject = (value: unknown): value is Record<string, unknown> => typeof value === \"object\" && value !== null && !Array.isArray(value);\n\n/** The fields a command gave: an object, or a usage error that says so. */\nfunction fieldsOf(params: Params): Record<string, unknown> {\n const fields = params.card ?? {};\n if (!isObject(fields)) throw new CliError(\"bad_request\", \"card must be an object of the card's fields\");\n return fields;\n}\n\n/**\n * An update merged over a card: fields given replace those there, `pr` field by field, and a field given as null goes\n * (`--json '{\"step\":null}'`). The kind and the id never change.\n */\nexport function mergeCard(base: Record<string, unknown>, patch: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(patch)) {\n if (key === \"kind\" || key === \"id\") continue;\n if (value === null) { delete out[key]; continue; }\n if (key === \"pr\" && isObject(value) && isObject(base.pr)) {\n const pr: Record<string, unknown> = { ...base.pr };\n for (const [k, v] of Object.entries(value)) { if (v === null) delete pr[k]; else pr[k] = v; }\n out.pr = pr;\n continue;\n }\n out[key] = value;\n }\n return out;\n}\n\n/**\n * A routine's run from the command (`run: {result, summary?}`), as its last run and the first of its recent runs,\n * `STATUS_CARD_LIMITS.runs` kept. Undefined when the command names none.\n */\nexport function withRun(fields: Record<string, unknown>, params: Params, now = Date.now()): Record<string, unknown> {\n const run = params.run;\n if (run === undefined) return fields;\n if (!isObject(run) || typeof run.result !== \"string\") throw new CliError(\"bad_request\", \"run is {result: ok|failed|skipped, summary?}\");\n const lastRun = { at: now, result: run.result, ...(typeof run.summary === \"string\" && run.summary ? { summary: run.summary } : {}) };\n const before = Array.isArray(fields.runs) ? fields.runs : [];\n return { ...fields, lastRun, runs: [lastRun, ...before].slice(0, STATUS_CARD_LIMITS.runs) };\n}\n\n/** A card checked by the sender's rule, or a `bad_request` that says what is wrong. */\nfunction checked(card: Record<string, unknown>): StatusCard {\n const result = checkStatusCard(card);\n if (\"error\" in result) throw new CliError(\"bad_request\", `Status card: ${result.error}`, { card });\n return result.card;\n}\n\n/** Every text in a card's fields (title, step, items, runs, links…), as the contact's app may show it. */\nfunction cardTexts(value: unknown, out: string[] = []): string[] {\n if (typeof value === \"string\") out.push(value);\n else if (Array.isArray(value)) for (const item of value) cardTexts(item, out);\n else if (isObject(value)) for (const item of Object.values(value)) cardTexts(item, out);\n return out;\n}\n\n/**\n * The first text in `value` (a card's fields, a message's text…) that looks like a seed, a private key or a Cashu token,\n * read as given and as a card carries it (`cardLine`).\n */\nexport function secretIn(value: unknown): ReturnType<typeof findSecret> {\n for (const text of cardTexts(value)) {\n const secret = findSecret(text) ?? findSecret(cardLine(text, Infinity) ?? \"\");\n if (secret) return secret;\n }\n return null;\n}\n\n/**\n * The secret guard `send` has (docs/CLI.md § Safety): a card whose text looks like a seed, a private key or a Cashu\n * token goes only with `--force`. `fields` are what this command gives (an update's own, not the card it merges over).\n * A card's text is read as given and as the card carries it (`cardLine`): a line loses its invisible characters on the\n * way, so a key one of them broke in two is whole again on the card. The fallback text goes as it is, as `send`'s.\n */\nfunction guardSecrets(fields: unknown, params: Params, verb: string): void {\n if (bool(params, \"force\")) return;\n const check = (text: string) => {\n const secret = findSecret(text);\n if (secret) throw new CliError(\"confirm\", `The card's text looks like ${secret.kind === \"cashu\" ? \"a Cashu token (money anyone who reads it can take)\" : \"a secret (a seed or a private key)\"}; ${verb} it with --force if you mean to`, { kind: secret.kind });\n };\n for (const text of cardTexts([fields, params.run])) { check(text); check(cardLine(text, Infinity) ?? \"\"); }\n if (typeof params.text === \"string\") check(params.text);\n}\n\n/** How many cards a process remembers the message of; one past them is found in the history again. */\nexport const CARDS_REMEMBERED = 1_000;\n\n/** Per card (its chat or group, its kind and its id): the message of mine that carries it, as this process last saw it. */\nconst carriers = new WeakMap<ApiContext, Map<string, string>>();\nconst carrierKey = (linkId: string, kind: string, id: string) => `${linkId}\\n${kind}\\n${id}`;\n\nfunction carriersOf(ctx: ApiContext): Map<string, string> {\n let map = carriers.get(ctx);\n if (map) return map;\n carriers.set(ctx, (map = new Map()));\n const cards = map;\n // A newer card of mine stands for its id from the moment it is stored, whoever sent it (`engine call` too).\n ctx.hub.onEvent((event) => {\n if (event.type !== \"message.sent\" && event.type !== \"group.sent\") return;\n const message = event.message as { id?: unknown; card?: { kind?: unknown; id?: unknown } } | undefined;\n const card = message?.card;\n if (typeof message?.id !== \"string\" || typeof card?.id !== \"string\" || (card.kind !== \"task\" && card.kind !== \"routine\" && card.kind !== \"usage\")) return;\n carried(cards, carrierKey(event.type === \"group.sent\" ? `group:${String(event.group)}` : String(event.chat), card.kind, card.id), message.id);\n });\n return map;\n}\n\nfunction carried(cards: Map<string, string>, key: string, messageId: string): void {\n cards.delete(key);\n cards.set(key, messageId);\n if (cards.size > CARDS_REMEMBERED) cards.delete(cards.keys().next().value!);\n}\n\n/**\n * The latest message of mine in this chat or group with a card of this kind and id: the one an update edits. A card\n * this process sent or found before is read by its message's key, so its updates cost the same in a long chat as in a\n * short one; only a card not seen yet (the first update after a start, a one-shot) is looked for in the whole history.\n */\nasync function cardMessage(ctx: ApiContext, target: Target, kind: Kind, id: string): Promise<StoredMessage> {\n const cards = carriersOf(ctx), key = carrierKey(target.linkId, kind, id);\n const carries = (message: StoredMessage | undefined): message is StoredMessage => message?.sender === \"me\" && message.card?.kind === kind && message.card.id === id;\n const known = cards.get(key);\n if (known !== undefined) {\n const message = await node(ctx).getMessage(target.linkId, known);\n if (carries(message)) return message;\n // Deleted since, or it carries another card now: the history says which message stands for the id.\n cards.delete(key);\n }\n const messages = target.group ? await node(ctx).groupMessages({ groupId: target.id }) : await node(ctx).getMessages(target.linkId);\n // A card stored while the history was read is newer than what was read: that one stands for the id.\n if (cards.has(key)) return cardMessage(ctx, target, kind, id);\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i]!;\n if (!carries(message)) continue;\n carried(cards, key, message.id);\n return message;\n }\n throw new CliError(\"not_found\", `No ${kind} ${JSON.stringify(id)} of yours in this ${target.group ? \"group\" : \"chat\"}: send it first with ghostly ${kind} send`);\n}\n\nfunction answer(target: Target, kind: Kind, id: string, messageId: string, extra: Record<string, unknown>): Record<string, unknown> {\n return { [target.group ? \"group\" : \"chat\"]: target.id, [kind]: id, messageId, ...extra };\n}\n\n/**\n * A task's parent is another task of mine in the same chat or group (WISP 405 · Status Cards § A task): one that is\n * not there is refused here, with its name, rather than sent to stand alone on every board (a reader keeps the field\n * and shows the task ungrouped). Send the parent first.\n */\nasync function parentThere(ctx: ApiContext, target: Target, card: StatusCard): Promise<void> {\n if (card.kind !== \"task\" || !card.parent) return;\n const parent = card.parent;\n await cardMessage(ctx, target, \"task\", parent).catch(() => {\n throw new CliError(\"not_found\", `--parent: no task ${JSON.stringify(parent)} of yours in this ${target.group ? \"group\" : \"chat\"}: send the parent first`);\n });\n}\n\n/** A new card: a message whose text is written from it, in a chat or a group. */\nasync function sendCard(ctx: ApiContext, params: Params, kind: Kind): Promise<Record<string, unknown>> {\n const target = chatOrGroup(ctx, str(params, \"chat\", true));\n const fields = fieldsOf(params);\n guardSecrets(fields, params, \"send\");\n const now = Date.now();\n const id = typeof fields.id === \"string\" && fields.id ? fields.id : `${kind}-${toBase64Url(randomBytes(6))}`;\n const card = checked(withRun({\n ...(kind === \"task\" ? { status: \"running\", startedAt: now, updatedAt: now } : kind === \"routine\" ? { state: \"active\" } : {}),\n ...fields, kind, id,\n }, params, now));\n await parentThere(ctx, target, card);\n const text = str(params, \"text\") ?? \"\";\n const wait = oneOf(params, \"wait\", target.group ? [\"none\", \"sent\"] as const : [\"none\", \"sent\", \"delivered\"] as const, \"none\");\n const ms = num(params, \"timeout\", 30, { min: 1, max: 3600 }) * 1000;\n if (target.group) {\n const result = await node(ctx).sendGroupMessage({ groupId: target.id, text, card });\n if (result.error || !result.messageId) throw new CliError(result.refused ? \"refused\" : \"unavailable\", result.error ?? \"Nothing to send\");\n carried(carriersOf(ctx), carrierKey(target.linkId, kind, id), result.messageId);\n const edges = wait === \"sent\" ? await waitForGroupFrame(ctx, target.id, result.messageId, undefined, ms) : undefined;\n return answer(target, kind, id, result.messageId, { card, ...(edges !== undefined && { edges }) });\n }\n const result = await node(ctx).sendMessage({ linkId: target.linkId, text, card });\n if (result.error) throw new CliError(result.refused ? \"refused\" : \"unavailable\", result.error);\n if (!result.messageId) throw new CliError(\"bad_request\", \"Nothing to send\");\n carried(carriersOf(ctx), carrierKey(target.linkId, kind, id), result.messageId);\n let message = await node(ctx).getMessage(target.linkId, result.messageId);\n if (wait !== \"none\") message = await waitForMessage(ctx, target.linkId, result.messageId, wait, ms);\n return answer(target, kind, id, result.messageId, { card, delivery: message?.delivery ?? null });\n}\n\n/** Edits the card's message with its merged card, now. */\nasync function editCard(ctx: ApiContext, target: Target, messageId: string, card: StatusCard, text: string): Promise<void> {\n const result = await node(ctx).editMessage({ linkId: target.linkId, messageId, text, card });\n if (result.error) throw new CliError(result.refused ? \"refused\" : \"unavailable\", result.error);\n}\n\n/**\n * An update of a card of mine: the fields given, merged over its latest state (what waits to go included). It goes at\n * once when the card's last update is `CARD_UPDATE_GAP_MS` old; otherwise it waits for that, merged with any update\n * that comes meanwhile (`queued: true`). A one-shot command waits the time out itself: it has no daemon to wait in.\n */\nasync function updateCard(ctx: ApiContext, params: Params, kind: Kind): Promise<Record<string, unknown>> {\n const target = chatOrGroup(ctx, str(params, \"chat\", true));\n const id = str(params, kind, true);\n const patch = fieldsOf(params);\n guardSecrets(patch, params, \"update\");\n const message = await cardMessage(ctx, target, kind, id);\n // A card message takes `STATUS_CARD_LIMITS.edits` updates (WISP 405 · Status Cards); past them, a new card goes on.\n if ((message.edit?.seq ?? 0) >= STATUS_CARD_LIMITS.edits)\n throw new CliError(\"refused\", `This ${kind}'s message took ${STATUS_CARD_LIMITS.edits} updates, the most one takes: start a new card with ghostly ${kind} send (a new --id, or the same one: the newest card of an id stands for it)`, { messageId: message.id, edits: message.edit!.seq });\n const pace = paceOf(ctx, `${target.linkId}\\n${message.id}`);\n const base = pace.next ?? (message.card as unknown as Record<string, unknown>);\n const merged = withRun(mergeCard(base, { ...patch, ...(kind === \"task\" && { updatedAt: Date.now() }) }), params);\n const card = checked(merged);\n if (isObject(patch) && patch.parent !== undefined) await parentThere(ctx, target, card);\n const text = str(params, \"text\") ?? \"\";\n const wait = oneOf(params, \"wait\", target.group ? [\"none\", \"sent\"] as const : [\"none\", \"confirmed\"] as const, \"none\");\n const ms = num(params, \"timeout\", 30, { min: 1, max: 3600 }) * 1000;\n const last = Math.max(pace.last, message.edit?.at ?? message.timestamp);\n const due = last + CARD_UPDATE_GAP_MS - Date.now();\n let queued = false;\n if (due > 0 && ctx.mode === \"daemon\") {\n // Merged into what goes next; the first update in the gap sets the timer, the later ones only change what it sends.\n pace.next = card as unknown as Record<string, unknown>;\n queued = true;\n if (!pace.timer) pace.flushed = new Promise<void>((resolve) => {\n const send = () => {\n const next = pace.next;\n clearTimeout(pace.timer);\n pace.timer = undefined; pace.next = undefined; pace.flush = undefined; pace.last = Date.now();\n void (next ? editCard(ctx, target, message.id, next as unknown as StatusCard, text) : Promise.resolve()).catch(() => {}).finally(resolve);\n };\n pace.flush = send;\n pace.timer = setTimeout(send, due);\n });\n if (wait !== \"none\") await pace.flushed;\n } else {\n if (due > 0) await new Promise((resolve) => setTimeout(resolve, due));\n pace.last = Date.now();\n await editCard(ctx, target, message.id, card, text);\n }\n let edited = await node(ctx).getMessage(target.linkId, message.id);\n if (wait === \"confirmed\" && edited?.edit?.pending) edited = await waitForEdit(ctx, target.linkId, message.id, ms);\n const edges = wait === \"sent\" && edited?.edit ? await waitForGroupFrame(ctx, target.id, message.id, edited.edit.seq, ms) : undefined;\n return answer(target, kind, id, message.id, {\n card, queued, edits: edited?.edit?.seq ?? 0,\n // An update still waiting for its time went nowhere yet: it is not confirmed, whatever the message's last edit says.\n ...(target.group ? { ...(edges !== undefined && { edges }) } : { confirmed: (!queued || wait !== \"none\") && !!edited && !edited.edit?.pending }),\n });\n}\n\n/**\n * Sends now every update still waiting for its time: the daemon is stopping, and the update it answered `queued` for\n * (often a task's last one, done or failed) would otherwise go with it, leaving the card running for good. Called\n * while the engine can still store the edit; it goes to the contact as any edit does, now or once they are back.\n */\nexport async function flushCardUpdates(ctx: ApiContext): Promise<void> {\n const waiting = [...(paces.get(ctx)?.values() ?? [])].filter((pace) => pace.flush);\n for (const pace of waiting) pace.flush!();\n await Promise.all(waiting.map((pace) => pace.flushed));\n}\n\n/** A usage card's fields: all of them are said again by each report, so one not given goes from the card. */\nconst USAGE_FIELDS = [\"left\", \"used\", \"limit\", \"label\", \"account\", \"window\", \"resetsAt\", \"updatedAt\", \"windows\"] as const;\n\n/** The id a bot's usage card goes by when it names none: one live card per chat. */\nexport const USAGE_CARD_ID = \"usage\";\n\n/**\n * One chat's usage report (WISP 405 § Usage): the bot's usage card there, kept as one message. The first report sends\n * it; every later one edits it in place (quiet: no sound, no unread, no move in the list), paced as a task's updates.\n * A report is whole: what it does not say goes from the card. A card at its edits' cap gives way to a new message.\n */\nasync function reportUsage(ctx: ApiContext, ref: string, fields: Record<string, unknown>, params: Params): Promise<Record<string, unknown>> {\n const target = chatOrGroup(ctx, ref);\n const id = typeof fields.id === \"string\" && fields.id ? fields.id : USAGE_CARD_ID;\n const report = { updatedAt: Date.now(), ...fields, kind: \"usage\", id };\n checked(report);\n const sent = await cardMessage(ctx, target, \"usage\", id).catch(() => undefined);\n const wait = oneOf(params, \"wait\", [\"none\", \"sent\"] as const, \"none\");\n if (!sent || (sent.edit?.seq ?? 0) >= STATUS_CARD_LIMITS.edits) {\n const answer = await sendCard(ctx, { ...params, chat: ref, card: report, wait }, \"usage\");\n return { ...answer, updated: false };\n }\n const patch: Record<string, unknown> = {};\n for (const key of USAGE_FIELDS) patch[key] = report[key as keyof typeof report] ?? null;\n const answer = await updateCard(ctx, { ...params, chat: ref, usage: id, card: patch, wait: wait === \"none\" ? \"none\" : target.group ? \"sent\" : \"confirmed\" }, \"usage\");\n return { ...answer, updated: true };\n}\n\n/**\n * `usage send`: one chat or group, or (`all`) every 1:1 chat with a contact; a chat that refuses is said (its\n * `{code, message}`), not fatal, unless every chat refused: then nothing was reported and the call fails.\n */\nasync function sendUsage(ctx: ApiContext, params: Params): Promise<Record<string, unknown>> {\n const fields = fieldsOf(params);\n if (!bool(params, \"all\")) return reportUsage(ctx, str(params, \"chat\", true), fields, params);\n if (str(params, \"chat\")) throw new CliError(\"bad_request\", \"Name a chat or --all, not both\");\n checked({ updatedAt: Date.now(), ...fields, kind: \"usage\", id: typeof fields.id === \"string\" && fields.id ? fields.id : USAGE_CARD_ID });\n // The person's mistake, said once: before, each chat refused it on its own and the call still answered.\n oneOf(params, \"wait\", [\"none\", \"sent\"] as const, \"none\");\n num(params, \"timeout\", 30, { min: 1, max: 3600 });\n const chats = state(ctx).links.filter((link) => link.profile && link.peerPubKeyZ32);\n const results: Record<string, unknown>[] = [];\n const failed: { chat: string; error: CliError }[] = [];\n for (const link of chats) {\n try { results.push(await reportUsage(ctx, link.id, fields, params)); }\n catch (error) {\n const refusal = { chat: link.id, error: asCliError(error) };\n failed.push(refusal);\n results.push({ chat: link.id, error: refusal.error.toJSON() });\n }\n }\n if (failed.length && failed.length === chats.length) {\n const codes = new Set(failed.map((f) => f.error.code));\n throw new CliError(codes.size === 1 ? failed[0]!.error.code : \"refused\", `No chat took the usage card: ${failed.map((f) => `${f.chat}: ${f.error.message}`).join(\"; \")}`, { chats: results });\n }\n return { chats: results };\n}\n\nexport const STATUS_CARD_METHODS: Record<string, Method> = {\n /** WISP 405 · Status Cards: a task card in a chat or a group; the answer names the task's id and its message. */\n \"task.send\": (ctx, params) => sendCard(ctx, params, \"task\"),\n /** A task's update: the fields given, merged over its latest state, paced one per `CARD_UPDATE_GAP_MS`. */\n \"task.update\": (ctx, params) => updateCard(ctx, params, \"task\"),\n /** A routine card (its schedule, state, runs); `run` records one. */\n \"routine.send\": (ctx, params) => sendCard(ctx, params, \"routine\"),\n /** A routine's update, as a task's; `run` records a run as its last and the newest of its recent ones. */\n \"routine.update\": (ctx, params) => updateCard(ctx, params, \"routine\"),\n /** WISP 405 § Usage: how much of a quota the bot has left, kept as one card per chat; `all` for every 1:1 chat. */\n \"usage.send\": sendUsage,\n};\n","import { readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { LinkView } from \"@ghostly/browser/shared/types\";\nimport { node, state, type ApiContext } from \"./apiKit\";\nimport { CliError } from \"./errors\";\n\n/**\n * `chat disconnect --hold <minutes>`: a chat kept off its direct link for a while. It is the chat's own \"DHT only\"\n * choice (WISP 400: either side choosing it keeps both off the live link, so the contact's app does not redial),\n * taken back when the time is up. Text still goes over the DHT (short texts), files wait. The holds are kept in\n * the profile folder: a daemon that restarts takes back the ones whose time is up, and never a DHT only the chat had\n * chosen before (that one is not a hold).\n */\nexport const HOLD_MAX_MINUTES = 7 * 24 * 60;\n\ninterface Hold { until: number; since: number }\ntype Holds = Record<string, Hold>;\n\nconst timers = new WeakMap<ApiContext, Map<string, ReturnType<typeof setTimeout>>>();\n\nfunction holdsFile(ctx: ApiContext): string {\n return join(ctx.runtime.paths.dir, \"holds.json\");\n}\n\nfunction readHolds(ctx: ApiContext): Holds {\n try { return JSON.parse(readFileSync(holdsFile(ctx), \"utf8\")) as Holds; } catch { return {}; }\n}\n\nfunction writeHolds(ctx: ApiContext, holds: Holds): void {\n const file = holdsFile(ctx);\n writeFileSync(file + \".tmp\", JSON.stringify(holds) + \"\\n\", { mode: 0o600 });\n renameSync(file + \".tmp\", file);\n}\n\nfunction timersOf(ctx: ApiContext): Map<string, ReturnType<typeof setTimeout>> {\n let map = timers.get(ctx);\n if (!map) timers.set(ctx, (map = new Map()));\n return map;\n}\n\nfunction schedule(ctx: ApiContext, linkId: string, until: number): void {\n const map = timersOf(ctx);\n clearTimeout(map.get(linkId));\n const timer = setTimeout(() => {\n map.delete(linkId);\n void releaseHold(ctx, linkId, \"expired\").catch((error: unknown) => process.stderr.write(`ghostly: the hold on ${linkId} could not end: ${error instanceof Error ? error.message : String(error)}\\n`));\n }, Math.max(0, until - Date.now()));\n // A one-shot leaves when its command is done; the next start takes the hold back.\n timer.unref?.();\n map.set(linkId, timer);\n}\n\n/** When the chat's hold ends, or null. */\nexport function holdOf(ctx: ApiContext, linkId: string): number | null {\n return readHolds(ctx)[linkId]?.until ?? null;\n}\n\n/** Keeps the chat off its direct link for `minutes` (again: from now). */\nexport async function holdChat(ctx: ApiContext, link: LinkView, minutes: number): Promise<number> {\n const holds = readHolds(ctx);\n if (link.deliveryMode === \"dht\" && !holds[link.id]) throw new CliError(\"refused\", \"This chat is on DHT only already, by its own choice: chat transport auto leaves it\");\n if (!link.profile) throw new CliError(\"unavailable\", \"A chat of the older protocol has no DHT only\");\n const until = Date.now() + minutes * 60_000;\n if (link.deliveryMode !== \"dht\") {\n try { await node(ctx).setChatTransport({ linkId: link.id, transport: \"dht\" }); } catch (error) {\n throw new CliError(\"unavailable\", error instanceof Error ? error.message : String(error));\n }\n }\n holds[link.id] = { until, since: holds[link.id]?.since ?? Date.now() };\n writeHolds(ctx, holds);\n schedule(ctx, link.id, until);\n ctx.hub.emit(\"chat.held\", `chat.held:${link.id}:${until}`, { chat: link.id, until });\n return until;\n}\n\n/**\n * Ends a hold: the chat leaves DHT only, unless someone chose otherwise meanwhile. Whether there was one. `reason`:\n * expired, connect (`chat connect`) or lifted (`--hold 0`).\n */\nexport async function releaseHold(ctx: ApiContext, linkId: string, reason: \"expired\" | \"connect\" | \"lifted\"): Promise<boolean> {\n const holds = readHolds(ctx);\n if (!holds[linkId]) return false;\n clearTimeout(timersOf(ctx).get(linkId));\n timersOf(ctx).delete(linkId);\n const link = state(ctx).links.find((l) => l.id === linkId);\n if (link?.deliveryMode === \"dht\") await node(ctx).setDeliveryMode({ linkId, mode: \"stream\" });\n delete holds[linkId];\n writeHolds(ctx, holds);\n ctx.hub.emit(\"chat.released\", `chat.released:${linkId}:${Date.now()}`, { chat: linkId, reason });\n return true;\n}\n\n/** At start: holds whose time is up end now, the others are timed again. */\nexport function resumeHolds(ctx: ApiContext): void {\n for (const [linkId, hold] of Object.entries(readHolds(ctx))) schedule(ctx, linkId, hold.until);\n}\n","import type { GroupView, LinkView, MessageFile, StoredMessage } from \"@ghostly/browser/shared/types\";\nimport type { StatusCard } from \"@ghostly/core\";\n\n/**\n * The JSON shapes the CLI and the daemon answer with. They are the contract bots code against (WISP 1100), kept\n * apart from the engine's views: those change with the app, these only by adding fields.\n */\n\nexport interface ChatJson {\n id: string;\n /** The label set here, else the name the contact gave, else null. */\n name: string | null;\n label: string | null;\n peerName: string | null;\n /** The contact's key for this chat (z-base-32). */\n peer: string;\n createdAt: number;\n lastMessageAt: number;\n /** A live session carries the chat now, in this run (text, files, payments go at once). */\n live: boolean;\n /** The transport of the live session, or null. */\n transport: string | null;\n /** How text goes now: `stream` (live), `dht` (the DHT floor, 256 bytes), `hold`, or `unavailable`. */\n text: string;\n /** The pairing's state: connecting, waiting, ready, failed. */\n pairing: string | null;\n /** How far the first pairing got (publishing, waiting, resolving, on-dht, live, …), while it is under way. */\n stage: string | null;\n verified: boolean;\n /**\n * The invite this side made for the chat, while it waits for the contact: `<hidden>` unless asked for\n * (`--show-secret`), since whoever reads the code can take the chat. Null once the chat is paired, or without one.\n */\n invite: string | null;\n /** A chat of the older protocol (WISP 402). */\n compatibility: boolean;\n /** The contact sent a picture (checked by the engine; `engine getState` has it). */\n peerPicture: boolean;\n}\n\n/**\n * A live session carries the chat now, in this run: its link is open and, on a paired chat, the session authenticated\n * on a transport. The engine's own rule for a chat's connection line (`observeTransport`). `textDelivery` alone says\n * how a text would go, and nothing the engine remembers from an earlier run (a chat that was live when the app last\n * ran, WISP 100) counts: until the contact answers again the link is not open and the pairing is `connecting`.\n */\nexport function isLive(link: LinkView): boolean {\n if (link.textDelivery !== \"stream\" || link.dataLink !== \"open\") return false;\n return !link.profile || (link.pairing?.status === \"ready\" && !!link.pairing.transport);\n}\n\nexport function chatJson(link: LinkView, showSecret?: boolean): ChatJson {\n const label = link.label?.trim() || null;\n const peerName = link.peerNick?.trim() || null;\n const live = isLive(link);\n return {\n id: link.id,\n name: label ?? peerName,\n label,\n peerName,\n peer: link.peerPubKeyZ32,\n createdAt: link.createdAt,\n lastMessageAt: link.lastMessageAt,\n live,\n transport: live ? (link.pairing?.transport ?? link.pairingProgress?.transport ?? null) : null,\n text: link.textDelivery ?? (link.profile ? \"unavailable\" : \"dht\"),\n pairing: link.pairing?.status ?? null,\n stage: link.pairingProgress?.stage ?? null,\n verified: !!link.peerVerified,\n invite: link.pairing?.status === \"ready\" || !link.inviteCode ? null : showSecret === true ? link.inviteCode : \"<hidden>\",\n compatibility: !link.profile,\n peerPicture: !!link.peerAvatar,\n };\n}\n\n/** A chat's details: the summary plus what its connection panel shows. */\nexport function chatDetailsJson(link: LinkView, showSecret?: boolean) {\n return {\n ...chatJson(link, showSecret),\n progress: link.pairingProgress ?? null,\n transports: { mine: link.availableTransports ?? [], peer: link.peerTransports ?? [], preferred: link.preferredTransport ?? null, fallback: link.transportFallback ?? null, automatic: link.transportAutomatic ?? null, relayed: link.relayedTransports ?? [] },\n wait: link.transportWait ?? null,\n lastAttempt: link.liveAttempt ?? null,\n liveSince: link.transportLive?.since ?? null,\n rttMs: link.transportRttMs ?? null,\n relays: link.transportRelayed?.relays ?? null,\n deliveryMode: link.deliveryMode ?? null,\n capabilities: link.capabilities ?? null,\n hold: link.hold ?? null,\n peerOnline: link.peerOnline,\n peerLastSeenAt: link.peerLastSeenAt || null,\n history: link.transportHistory ?? null,\n errors: link.transportErrors ?? null,\n comparisonCode: link.pairing?.code ?? null,\n };\n}\n\nexport interface MessageJson {\n id: string;\n chat: string;\n /** `system`: a line of the group's own (`event`: created, joined, renamed…), whoever's key is on it; nobody wrote it. */\n from: \"me\" | \"peer\" | \"system\";\n text: string;\n /** Its place in the history, which is ordered by it: when I sent it, or when it came here (never the sender's clock). */\n timestamp: number;\n /** Received: when its sender says it was sent, by its own clock. */\n sentAt?: number;\n delivery: string | null;\n deliveryError: string | null;\n via: string;\n nick: string | null;\n member?: string;\n mentions?: { key: string; offset: number; length: number }[];\n mentioned?: boolean;\n /** A file or voice message: its id is what `file wait`, `file save` and the `file.*` events name. */\n file?: { id: string; name: string; size: number; mime: string; voice?: { duration: number; peaks?: number[] }; image?: { width: number; height: number } };\n paymentId?: string;\n event?: unknown;\n /**\n * The message this one answers (WISP 400 § Replies). `id`: the original's message id here when it is in this chat\n * (`found`), else the id the reply named. `from`: null when nothing says (only the id came, over the DHT).\n */\n replyTo?: { id: string; snippet: string; from: \"me\" | \"peer\" | null; member?: string; found: boolean; button?: string };\n /** Reactions to it, one per person (WISP 400 § Reactions): `by` is `me`, `peer` or a member's key. */\n reactions?: { by: string; emoji: string; at: number }[];\n /** An edited text (WISP 400 § Edits): `text` is the latest version, `edits` its number, `editedAt` when it was made. */\n edits?: number;\n editedAt?: number;\n /** Mine: the contact has not confirmed the latest edit yet. */\n editPending?: boolean;\n /** A forwarded message (WISP 400 § Forwards): how many times it has been forwarded. Never who wrote it first. */\n forwarded?: number;\n /** A bot's task or routine (WISP 405 · Status Cards), as its version says it; `text` is its fallback. Or its buttons. */\n card?: StatusCard;\n /**\n * A reply that pressed a button of a message of mine (WISP 406 · Message Buttons), as this side's engine took it:\n * `messageId` the question here, `button` its id, `label`, `inferred` when only the text named it.\n */\n press?: { messageId: string; button: string; label: string; inferred?: true };\n}\n\nexport function messageJson(message: StoredMessage): MessageJson {\n return {\n id: message.id,\n chat: message.linkId,\n // The engine keeps a group's own lines as the peer's, mine with my key: a bot reading others' words by `from` took them for a member's.\n from: message.event ? \"system\" : message.sender,\n text: message.text,\n timestamp: message.timestamp,\n ...(message.sentAt !== undefined ? { sentAt: message.sentAt } : {}),\n // A received message is delivered by definition; one of mine without a state went before states existed.\n delivery: message.delivery ?? (message.sender === \"peer\" ? null : \"sent\"),\n deliveryError: message.deliveryError ?? null,\n via: message.via,\n nick: message.nick ?? null,\n ...(message.member ? { member: message.member } : {}),\n ...(message.mentions?.length ? { mentions: message.mentions.map((m) => ({ key: m.k, offset: m.o, length: m.l })) } : {}),\n ...(message.mentioned ? { mentioned: true } : {}),\n ...(message.file ? { file: fileJson(message.file) } : {}),\n ...(message.paymentId ? { paymentId: message.paymentId } : {}),\n ...(message.event ? { event: message.event } : {}),\n ...(message.replyTo ? { replyTo: { id: message.replyTo.messageId ?? message.replyTo.id, snippet: message.replyTo.snippet, from: message.replyTo.from ?? null,\n ...(message.replyTo.member ? { member: message.replyTo.member } : {}), found: !!message.replyTo.messageId,\n ...(message.replyTo.button ? { button: message.replyTo.button } : {}) } } : {}),\n ...(reactionsJson(message).length ? { reactions: reactionsJson(message) } : {}),\n ...(message.edit ? { edits: message.edit.seq, editedAt: message.edit.at, ...(message.edit.pending ? { editPending: true } : {}) } : {}),\n ...(message.forwarded ? { forwarded: message.forwarded } : {}),\n ...(message.card ? { card: message.card } : {}),\n ...(message.press ? { press: { messageId: message.press.messageId, button: message.press.button, label: message.press.label, ...(message.press.inferred ? { inferred: true as const } : {}) } } : {}),\n };\n}\n\n/**\n * A message's file; a voice note's length (ms) and loudness bars ride along (older releases said only `voice: true`),\n * and a picture's size as it is shown when its sender sent it.\n */\nexport function fileJson(file: MessageFile): NonNullable<MessageJson[\"file\"]> {\n return {\n id: file.id, name: file.name, size: file.size, mime: file.mime,\n ...(file.voice ? { voice: { duration: file.voice.duration, ...(file.voice.peaks?.length ? { peaks: [...file.voice.peaks] } : {}) } } : {}),\n ...(file.image ? { image: { width: file.image.width, height: file.image.height } } : {}),\n };\n}\n\n/** A message's reactions shown now (taken-back ones left out), oldest first. */\nexport function reactionsJson(message: StoredMessage): { by: string; emoji: string; at: number }[] {\n return Object.entries(message.reactions ?? {}).filter(([, r]) => r.e).sort(([, a], [, b]) => a.at - b.at).map(([by, r]) => ({ by, emoji: r.e, at: r.at }));\n}\n\n/**\n * A 1:1 chat's message with its author named: the engine keeps a contact's message without a name (the name rides on\n * the chat), so the name the contact gave fills `nick`, as a group's roster does. Mine keep null. Before, `nick` was\n * always null in a 1:1 chat, and so was an agent turn's `untrusted.name`.\n */\nexport function chatMessageJson(message: StoredMessage, link: Pick<LinkView, \"peerNick\"> | undefined): MessageJson {\n const json = messageJson(message);\n if (json.nick || message.sender !== \"peer\") return json;\n const nick = link?.peerNick?.trim();\n return nick ? { ...json, nick } : json;\n}\n\n/**\n * A group's message with its author named: mesh and community messages are kept with the member's key only (the\n * name rides on the edge or the roster), so the roster fills `nick` when the message has none, and for an author no\n * longer in it (removed, or back with a new member key) the name the group knew them by.\n */\nexport function groupMessageJson(message: StoredMessage, group: Pick<GroupView, \"members\" | \"formerNames\"> | undefined): MessageJson {\n const json = messageJson(message);\n if (json.nick || !message.member) return json;\n const nick = group?.members.find((m) => m.key === message.member)?.nick ?? group?.formerNames?.[message.member];\n return nick ? { ...json, nick } : json;\n}\n\n/**\n * A group as the CLI prints it. The entry link lets anyone who reads it join, so it is `<hidden>` unless asked for\n * (`--show-secret`, or `group link`); null when the group has none.\n */\nexport function groupJson(group: GroupView, showSecret = false) {\n return {\n id: group.id,\n name: group.name,\n profile: group.profile,\n status: group.status ?? (group.invitation ? \"invited\" : null),\n statusReason: group.statusReason ?? null,\n admin: group.isAdmin,\n me: group.myKey ?? null,\n canSend: group.canSend,\n link: group.entryLink ? (showSecret ? group.entryLink : \"<hidden>\") : null,\n lastMessageAt: group.lastMessageAt,\n // Past 16 members with hubs (WISP 902 · Group Mesh § Hubs): who is one, who is reached through them, what the admin chose.\n members: group.members.map((m) => ({ key: m.key, name: m.nick ?? null, role: m.role, me: m.me, online: m.online,\n ...(m.hub ? { hub: true } : {}), ...(m.viaHub ? { viaHub: true } : {}), ...(m.hubRole ? { hubRole: m.hubRole } : {}) })),\n ...(group.hubs ? { hubs: group.hubs } : {}),\n invitation: group.invitation ? { chat: group.invitation.linkId, accepted: group.invitation.accepted, viaLink: !!group.invitation.viaLink, stage: group.invitation.stage ?? null } : null,\n community: group.community ?? null,\n picture: !!group.picture,\n };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { MAX_AVATAR_LENGTH, MAX_AVATAR_SIDE, MAX_GROUP_NAME_LENGTH, groupName, sanitizeAvatar } from \"@ghostly/core\";\nimport type { GroupView } from \"@ghostly/browser/shared/types\";\nimport { bool, chatOf, groupOf, node, state, str, type ApiContext, type Method, type Params } from \"./apiKit\";\nimport { CliError, localFileError } from \"./errors\";\nimport { groupJson } from \"./views\";\n\n/**\n * Group administration and pictures (WISP 1100, phase 3): what the app's group menu and profile screen do. The\n * engine enforces who may do what (the admin); these check the arguments and name members.\n */\n\n/**\n * A member by key, unique key prefix or name; never this profile itself. A whole key is that member, whatever another\n * member calls itself; a prefix and a name stand side by side (two members is an error, not a guess).\n */\nexport function findMember(group: GroupView, ref: string) {\n const lower = ref.toLowerCase();\n const others = group.members.filter((m) => !m.me);\n const byKey = others.filter((m) => m.key === ref);\n const matches = byKey.length ? byKey : others.filter((m) => m.key.startsWith(ref) || m.nick?.trim().toLowerCase() === lower);\n if (matches.length === 1) return matches[0];\n throw matches.length ? new CliError(\"bad_request\", `${JSON.stringify(ref)} names more than one member`) : noMember(group, ref);\n}\n\n/**\n * A ref no other member answers to. When it is this profile's own key (or a prefix of it), it says so: \"No member\"\n * read as if this profile were not in the group.\n */\nexport function noMember(group: GroupView, ref: string): CliError {\n if (group.members.some((m) => m.me && m.key.startsWith(ref))) return new CliError(\"bad_request\", `${JSON.stringify(ref)} is you: name another member of ${group.name}`);\n return new CliError(\"not_found\", `No member ${JSON.stringify(ref)} in ${group.name}`);\n}\n\n/**\n * A picture as Ghostly sends it: a square JPEG data URL, checked as a contact would check it. The app scales and\n * crops any image to 128×128; here the file must already be a JPEG within the bounds (no image library on Node).\n */\nexport async function pictureFrom(path: string): Promise<string> {\n let bytes: Buffer;\n // A folder or a file this user may not read is named as such, not \"No file\" for a path that is there.\n try { bytes = await readFile(resolve(path)); } catch (error) { throw localFileError(error, path) ?? new CliError(\"not_found\", `No file ${path}`); }\n const url = `data:image/jpeg;base64,${bytes.toString(\"base64\")}`;\n const checked = sanitizeAvatar(url);\n if (!checked) throw new CliError(\"bad_request\", `A picture is a JPEG of at most ${MAX_AVATAR_SIDE}×${MAX_AVATAR_SIDE} px and about ${Math.floor(MAX_AVATAR_LENGTH * 0.74 / 1000)} KB (128×128 is what the app sends): resize it first`);\n return checked;\n}\n\nasync function picture(params: Params): Promise<string | null> {\n if (bool(params, \"clear\")) return null;\n return pictureFrom(str(params, \"path\", true));\n}\n\nconst view = (ctx: ApiContext, id: string, params: Params) => groupJson(state(ctx).groups.find((g) => g.id === id) ?? groupOf(ctx, { group: id }), bool(params, \"showSecret\"));\n\nexport const GROUP_ADMIN_METHODS: Record<string, Method> = {\n async \"group.invite\"(ctx, params) {\n const group = groupOf(ctx, params);\n const link = chatOf(ctx, params);\n await node(ctx).inviteToGroup({ groupId: group.id, linkId: link.id });\n return view(ctx, group.id, params);\n },\n async \"group.remove\"(ctx, params) {\n const group = groupOf(ctx, params);\n await node(ctx).removeGroupMember({ groupId: group.id, key: findMember(group, str(params, \"member\", true)).key });\n return view(ctx, group.id, params);\n },\n async \"group.admin\"(ctx, params) {\n const group = groupOf(ctx, params);\n await node(ctx).makeGroupAdmin({ groupId: group.id, key: findMember(group, str(params, \"member\", true)).key });\n return view(ctx, group.id, params);\n },\n async \"group.hub\"(ctx, params) {\n const group = groupOf(ctx, params);\n const role = str(params, \"role\") ?? \"auto\";\n if (![\"pin\", \"exclude\", \"auto\"].includes(role)) throw new CliError(\"bad_request\", \"role is pin, exclude or auto\");\n await node(ctx).setGroupHub({ groupId: group.id, key: findMember(group, str(params, \"member\", true)).key, role: role === \"auto\" ? null : role as \"pin\" | \"exclude\" });\n return view(ctx, group.id, params);\n },\n async \"group.rename\"(ctx, params) {\n const group = groupOf(ctx, params);\n const name = groupName(str(params, \"name\", true));\n if (!name) throw new CliError(\"bad_request\", `A group's name is 1 to ${MAX_GROUP_NAME_LENGTH} characters on one line`);\n await node(ctx).renameGroup({ groupId: group.id, name });\n return view(ctx, group.id, params);\n },\n async \"group.rotate\"(ctx, params) {\n const group = groupOf(ctx, params);\n await node(ctx).rotateGroup({ groupId: group.id });\n return view(ctx, group.id, params);\n },\n async \"group.link\"(ctx, params) {\n const group = groupOf(ctx, params);\n if (params.on === false) {\n await node(ctx).disableGroupLink({ groupId: group.id });\n return { group: group.id, link: null };\n }\n const { link } = await node(ctx).enableGroupLink({ groupId: group.id, ...(bool(params, \"reset\") ? { reset: true } : {}) });\n return { group: group.id, link };\n },\n async \"group.picture\"(ctx, params) {\n const group = groupOf(ctx, params);\n await node(ctx).setGroupPicture({ groupId: group.id, picture: await picture(params) });\n return { group: group.id, picture: !bool(params, \"clear\") };\n },\n async \"profile.picture\"(ctx, params) {\n const avatar = await picture(params);\n await node(ctx).updateSettings({ settings: { avatar: avatar ?? \"\" } });\n return { picture: avatar !== null };\n },\n};\n","import { identityStatement, type IdentityBinding, type IdentityStatement } from \"@ghostly/core\";\nimport { IDENTITY_PROVIDERS } from \"@ghostly/browser/proofs/registry\";\nimport type { IdentityProofProvider, IdentitySigner, SignerInstructions } from \"@ghostly/browser/proofs/contract\";\nimport type { IdentityProofView } from \"@ghostly/browser/shared/types\";\nimport { chatOf, node, num, state, str, type ApiContext, type Method, type Params } from \"./apiKit\";\nimport { CliError } from \"./errors\";\n\n/**\n * Identity proofs (WISP 300, WISP 1100 phase 3b), as the Identities page makes them: the engine draws the proof key\n * and the statement; a signer of the provider makes the evidence; the engine checks it as a contact would before it\n * keeps it. Signers run here, where the app runs them in its page:\n *\n * - `external-tool` (ssh-keygen, gpg, a Bitcoin wallet): `identity add` prints the statement and what to run, and\n * `identity complete` takes what the tool printed. Between the two the draft lives in the daemon's memory.\n * - `publish` (a DNS record, a file on a domain): the same, and `complete` asks the engine to look it up.\n * - `in-app` (a Nostr signer over NIP-46, Pubky): one `identity add`, with the signer's fields; a link or code the\n * signer waits on is reported as an `identity.approval` event and printed by the command.\n * - `redirect` (OpenID Connect), and the in-app signers that live in the page (a NIP-07 extension, an AT Protocol\n * sign-in window), need a browser window: app only.\n */\n\ninterface Draft { draftId: string; provider: string; signer: string; binding: IdentityBinding; createdAt: number }\n/** Drafts per daemon: a proof made in two steps needs the same process for both. */\nconst drafts = new Map<string, Draft>();\nconst DRAFT_TTL_MS = 60 * 60 * 1000;\n\nfunction provider(id: string): IdentityProofProvider {\n const found = IDENTITY_PROVIDERS.find((p) => p.id === id);\n if (!found) throw new CliError(\"not_found\", `No identity provider ${id} (ghostly identity providers)`);\n return found;\n}\n\n/**\n * A signer that runs in this process: not a browser sign-in, and not one that says it cannot run here (a NIP-07\n * extension, an AT Protocol sign-in window: neither exists outside the app's page).\n */\nfunction headless(s: IdentitySigner<unknown>): boolean {\n if (s.kind === \"redirect\") return false;\n try { return s.available?.() ?? true; } catch { return false; }\n}\n\nfunction signerOf(p: IdentityProofProvider, id?: string): IdentitySigner<unknown> {\n const usable = p.signers.filter(headless);\n const found = id ? p.signers.find((s) => s.id === id) : usable[0];\n if (!found) throw new CliError(id ? \"not_found\" : \"unavailable\", id ? `${p.label} has no signer ${id}` : `${p.label} proofs need a browser window: make them in the app`);\n if (!headless(found)) {\n const instead = usable.length ? ` (here: --signer ${usable.map((s) => s.id).join(\" or \")})` : \"\";\n throw new CliError(\"unavailable\", `${found.label} needs a browser window: make this proof in the app${instead}`);\n }\n return found as IdentitySigner<unknown>;\n}\n\nfunction instructionsJson(i: SignerInstructions) {\n return { steps: i.steps.map((s) => ({ text: s.text, ...(s.copy ? { copy: s.copy } : {}) })), ...(i.paste ? { paste: i.paste.label } : {}) };\n}\n\nexport function proofJson(p: IdentityProofView) {\n return {\n id: p.id, provider: p.provider, subject: p.subject, verified: p.verified, issuedAt: p.issuedAt, expiresAt: p.expiresAt,\n sharedWith: p.sharedWith, ...(p.publicUri ? { publicUri: p.publicUri } : {}),\n };\n}\n\nfunction pruneDrafts(now = Date.now()) {\n for (const [id, draft] of drafts) if (now - draft.createdAt > DRAFT_TTL_MS) drafts.delete(id);\n}\n\nasync function begin(ctx: ApiContext, p: IdentityProofProvider, subject: string, params: Params) {\n let normalized: string;\n try { normalized = p.subject?.normalize ? p.subject.normalize(subject) : subject; } catch (error) {\n throw new CliError(\"bad_request\", error instanceof Error ? error.message : String(error));\n }\n if (!normalized) throw new CliError(\"bad_request\", `Not a ${p.subject?.label ?? \"subject\"} ${p.label} takes`);\n const days = params.days === undefined ? undefined : num(params, \"days\", 0, { min: 1, max: p.validity.maxDays });\n return node(ctx).beginIdentityProof({ provider: p.id, subject: normalized, ...(days ? { validityDays: days } : {}) });\n}\n\nexport const IDENTITY_METHODS: Record<string, Method> = {\n async \"identity.providers\"() {\n return {\n providers: IDENTITY_PROVIDERS.map((p) => ({\n id: p.id, label: p.label, category: p.category, subject: p.subject ? { label: p.subject.label, placeholder: p.subject.placeholder ?? null } : null,\n signers: p.signers.map((s) => ({ id: s.id, kind: s.kind, label: s.label, headless: headless(s),\n ...(s.kind === \"in-app\" && s.fields ? { fields: s.fields.map((f) => ({ name: f.name, label: f.label, kind: f.kind, optional: !!f.optional })) } : {}) })),\n })),\n };\n },\n\n async \"identity.list\"(ctx) {\n return { proofs: state(ctx).identityProofs.map(proofJson) };\n },\n\n /** Starts a proof. In-app signers finish it here; the others return the statement and what to do with it. */\n async \"identity.add\"(ctx, params) {\n pruneDrafts();\n const p = provider(str(params, \"provider\", true));\n const signer = signerOf(p, str(params, \"signer\"));\n if (signer.kind === \"in-app\") {\n const values = (params.fields ?? {}) as Record<string, string>;\n if (typeof values !== \"object\" || Array.isArray(values) || Object.values(values).some((v) => typeof v !== \"string\")) throw new CliError(\"bad_request\", \"fields must be an object of strings\");\n for (const field of signer.fields ?? []) if (!field.optional && !values[field.name]) throw new CliError(\"bad_request\", `${signer.label} needs ${field.name} (${field.label})`);\n const signal = AbortSignal.timeout(num(params, \"timeout\", 300, { min: 5, max: 3600 }) * 1000);\n const proof = await signer.run({\n values, signal,\n onAuthUrl: (url) => { ctx.hub.emit(\"identity.approval\", `identity.approval:${Date.now()}`, { provider: p.id, url }); },\n onProgress: (message) => { ctx.hub.emit(\"identity.progress\", `identity.progress:${Date.now()}`, { provider: p.id, message }); },\n onApproval: (request) => {\n if (request) ctx.hub.emit(\"identity.approval\", `identity.approval:${Date.now()}`, { provider: p.id, ...(request.qr ? { qr: request.qr.value, label: request.qr.label } : {}), notes: request.notes ?? [] });\n },\n }, async (session) => {\n const { draftId, binding } = await begin(ctx, p, await session.subject(), params);\n try {\n return await node(ctx).completeIdentityProof({ draftId, evidence: await session.sign(identityStatement(binding)) });\n } catch (error) {\n try { await node(ctx).cancelIdentityProof({ draftId }); } catch { /* already gone */ }\n throw error;\n }\n });\n return { done: true, proof: proofJson(proof) };\n }\n if (signer.kind === \"redirect\") throw new CliError(\"unavailable\", `${signer.label} needs a browser window: make this proof in the app`);\n const subject = str(params, \"subject\");\n // In the provider's words and where it goes: `identity add <provider> [subject]` shows it optional (in-app signers bring theirs).\n if (!subject) {\n const what = p.subject ? `, its ${p.subject.label.toLowerCase()}${p.subject.placeholder ? ` (${p.subject.placeholder})` : \"\"}` : \"\";\n throw new CliError(\"bad_request\", `${p.label} takes a subject${what}: ghostly identity add ${p.id} <subject>`);\n }\n const { draftId, binding } = await begin(ctx, p, subject, params);\n const statement = identityStatement(binding);\n drafts.set(draftId, { draftId, provider: p.id, signer: signer.id, binding, createdAt: Date.now() });\n return { done: false, draft: draftId, provider: p.id, signer: signer.id, statement: statement.text, instructions: instructionsJson(signer.instructions(statement)), expiresInSeconds: DRAFT_TTL_MS / 1000 };\n },\n\n /** Finishes a two-step proof: what the tool printed (external-tool), or nothing (publish: the engine looks it up). */\n async \"identity.complete\"(ctx, params) {\n const draft = drafts.get(str(params, \"draft\", true));\n if (!draft) throw new CliError(\"not_found\", \"No such draft here: it is kept by the daemon that made it, for an hour\");\n const p = provider(draft.provider);\n const signer = signerOf(p, draft.signer);\n const statement: IdentityStatement = identityStatement(draft.binding);\n let evidence: unknown;\n try {\n if (signer.kind === \"external-tool\") evidence = await signer.parse(str(params, \"evidence\", true), statement);\n else if (signer.kind === \"publish\") evidence = await signer.evidence(statement);\n else throw new CliError(\"bad_request\", \"This draft needs no completion\");\n } catch (error) {\n if (error instanceof CliError) throw error;\n throw new CliError(\"bad_request\", error instanceof Error ? error.message : String(error));\n }\n const proof = await node(ctx).completeIdentityProof({ draftId: draft.draftId, evidence });\n drafts.delete(draft.draftId);\n return { done: true, proof: proofJson(proof) };\n },\n\n async \"identity.cancel\"(ctx, params) {\n const draftId = str(params, \"draft\", true);\n // As `identity.complete` says it: a draft that is not here was never made, is done, or is another daemon's.\n if (!drafts.delete(draftId)) throw new CliError(\"not_found\", \"No such draft here: it is kept by the daemon that made it, for an hour\");\n await node(ctx).cancelIdentityProof({ draftId });\n return { cancelled: draftId };\n },\n\n async \"identity.remove\"(ctx, params) {\n const id = str(params, \"id\", true);\n // The engine removes nothing for an id it does not know, and says nothing.\n if (!state(ctx).identityProofs.some((p) => p.id === id)) throw new CliError(\"not_found\", `No identity proof ${JSON.stringify(id)} (ghostly identity list)`);\n await node(ctx).removeIdentityProof({ id });\n return { removed: id };\n },\n\n async \"identity.share\"(ctx, params) {\n const link = chatOf(ctx, params);\n const id = str(params, \"id\", true);\n if (!state(ctx).identityProofs.some((p) => p.id === id)) throw new CliError(\"not_found\", `No identity proof ${JSON.stringify(id)} (ghostly identity list)`);\n await node(ctx).shareIdentityProof({ linkId: link.id, id });\n return { chat: link.id, shared: id };\n },\n\n async \"identity.withdraw\"(ctx, params) {\n const link = chatOf(ctx, params);\n const id = str(params, \"id\", true);\n if (!link.identities?.shared.some((s) => s.id === id)) throw new CliError(\"not_found\", `No identity proof ${JSON.stringify(id)} shared in this chat (ghostly identity contact ${link.id})`);\n await node(ctx).withdrawIdentityProof({ linkId: link.id, id });\n return { chat: link.id, withdrawn: id };\n },\n\n /** What a contact shared in a chat, as this device checked it, and what this side shares there. */\n async \"identity.contact\"(ctx, params) {\n const link = chatOf(ctx, params);\n const view = link.identities;\n return {\n chat: link.id, support: view?.support ?? false,\n received: (view?.received ?? []).map((r) => ({ id: r.id, provider: r.provider, subject: r.subject, status: r.status, verified: r.verified, verifiedAt: r.verifiedAt, checkedAt: r.checkedAt, expiresAt: r.expiresAt, error: r.error ?? null, recheckDue: r.recheckDue, ...(r.publicProfile ? { publicProfile: r.publicProfile } : {}) })),\n shared: view?.shared ?? [],\n };\n },\n\n async \"identity.recheck\"(ctx, params) {\n const link = chatOf(ctx, params);\n const id = str(params, \"id\", true);\n if (!link.identities?.received.some((r) => r.id === id)) throw new CliError(\"not_found\", `No identity proof ${JSON.stringify(id)} from this contact (ghostly identity contact ${link.id})`);\n await node(ctx).recheckIdentityProof({ linkId: link.id, id });\n return IDENTITY_METHODS[\"identity.contact\"](ctx, { chat: link.id });\n },\n};\n","import { randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { GhostlyHttpError, LIMITS, type ClientRequest, type ClientResponse, type LocalFetch } from \"@ghostly/core\";\nimport { bool, chatOf, node, num, state, str, type ApiContext, type Method, type Params } from \"./apiKit\";\nimport { CliError } from \"./errors\";\nimport { isLive } from \"./views\";\n\n/**\n * Shared services (WISP 700/701, WISP 1100 phase 3b): a web app on this machine a contact may open over the chat's live\n * link, and a contact's app opened here on a loopback port. As on the Desktop: only loopback is reached, redirects are\n * handed back rather than followed, and a service is shared with each contact by name, never by default.\n */\n\nconst LOOPBACK = new Set([\"127.0.0.1\", \"localhost\", \"[::1]\", \"::1\"]);\n\n/** The engine's way to reach a shared app: loopback only, no redirect followed, no cookies (Node sends none). */\nexport const nodeLocalFetch: LocalFetch = async (request) => {\n const url = new URL(request.url);\n if (![\"http:\", \"https:\"].includes(url.protocol) || !(LOOPBACK.has(url.hostname) || /^127\\.\\d+\\.\\d+\\.\\d+$/.test(url.hostname))) {\n throw new Error(\"Shared services are reached on this machine only\");\n }\n const response = await fetch(url, { method: request.method, headers: request.headers, body: request.body as BodyInit | null, signal: request.signal, redirect: \"manual\", ...(request.body ? { duplex: \"half\" } : {}) } as RequestInit);\n const headers: [string, string][] = [];\n response.headers.forEach((value, name) => headers.push([name, value]));\n return {\n status: response.status, headers,\n body: response.body ? (async function* () {\n const reader = response.body!.getReader();\n try { for (;;) { const { done, value } = await reader.read(); if (done) return; if (value?.length) yield value; } } finally { reader.cancel().catch(() => {}); }\n })() : null,\n };\n};\n\n/** Contact services open on loopback ports, by `<peer>/<service>`, while this process runs. */\nconst open = new Map<string, OpenedService>();\nconst MAX_RESPONSE_BYTES = 32 * 1024 * 1024;\n/** Cookie names an opened service may set and have passed back (browsers keep about 180 per host). */\nconst MAX_COOKIE_NAMES = 256;\n\n/**\n * The cookie that shows a browser was given this service's link here. It is this machine's, never the contact's:\n * it is not passed on to the contact, and a `Set-Cookie` from the contact by that name is dropped.\n */\nexport const OPEN_COOKIE = \"ghostly_open\";\n/** The link `service open` prints: it sets `OPEN_COOKIE` and sends the browser on to `/`. */\nconst OPEN_PATH = \"/.ghostly-open/\";\n\n/**\n * Only the cookies this service set itself (by name, from its own `Set-Cookie`) go on to the contact; any other a\n * browser sends (one set for localhost by another app here, this machine's `OPEN_COOKIE`) stays here.\n */\nexport function ownCookies(header: string, names: ReadonlySet<string>): string | null {\n const kept = header.split(\";\").map((pair) => pair.trim()).filter((pair) => {\n const at = pair.indexOf(\"=\");\n const name = at > 0 ? pair.slice(0, at).trim() : \"\";\n return !!name && name !== OPEN_COOKIE && names.has(name);\n });\n return kept.length ? kept.join(\"; \") : null;\n}\n\n/** The cookie a `Set-Cookie` sets, by name. */\nexport function setCookieName(value: string): string | null {\n const at = value.indexOf(\"=\"), end = value.indexOf(\";\");\n if (at <= 0 || (end !== -1 && end < at)) return null;\n return value.slice(0, at).trim() || null;\n}\n\n/**\n * A contact's `Set-Cookie` as this machine passes it to the browser: without `Domain`, so the cookie stays on the\n * service's own host name (not every *.localhost). Null for one this machine does not take (`OPEN_COOKIE`, no name).\n */\nexport function hostOnlyCookie(value: string): string | null {\n const name = setCookieName(value);\n if (!name || name === OPEN_COOKIE) return null;\n return value.split(\";\").filter((part, i) => i === 0 || !/^\\s*domain\\s*(=|$)/i.test(part)).join(\";\");\n}\n\n/** A cookie's values in a `Cookie` header, by name (a page may set another by the same name on a narrower path). */\nfunction cookieValues(header: string | undefined, name: string): string[] {\n return (header ?? \"\").split(\";\").flatMap((pair) => {\n const at = pair.indexOf(\"=\");\n return at > 0 && pair.slice(0, at).trim() === name ? [pair.slice(at + 1).trim()] : [];\n });\n}\n\nfunction sameSecret(a: string, b: string): boolean {\n return a.length === b.length && timingSafeEqual(Buffer.from(a), Buffer.from(b));\n}\n\n/** How an opened service reaches the contact's app: the engine's `request` for that contact and service. */\nexport type ServiceSend = (request: ClientRequest) => Promise<ClientResponse>;\n\nexport interface OpenedService {\n server: Server;\n /** The link to open: it hands the browser this service's cookie, then shows `/`. */\n url: string;\n /** The service's own host name, `<random>.localhost:<port>`: any other `Host` is not this service. */\n host: string;\n}\n\nfunction plain(response: ServerResponse, status: number, text: string, headers: Record<string, string> = {}): void {\n response.writeHead(status, { \"content-type\": \"text/plain; charset=utf-8\", \"cache-control\": \"no-store\", ...headers });\n response.end(text);\n}\n\n/**\n * A contact's app on a loopback port of this machine, under a host name of its own (`<random>.localhost`): its\n * cookies and storage are its own, apart from any other app on 127.0.0.1 or localhost, and a name that merely\n * resolves here (DNS rebinding) is not it. Only a browser given the link (which sets `OPEN_COOKIE`) is served; anyone\n * else on this machine who finds the port gets 404. The body streams through, bounded by `MAX_RESPONSE_BYTES`.\n */\nexport async function openServiceServer(send: ServiceSend, port = 0): Promise<OpenedService> {\n const name = `${randomBytes(16).toString(\"hex\")}.localhost`;\n const token = randomBytes(32).toString(\"hex\");\n const cookies = new Set<string>();\n let host = \"\";\n const server = createServer((request, response) => {\n if (request.headers.host?.toLowerCase() !== host) return plain(response, 404, \"Not found\");\n const path = request.url ?? \"/\";\n if (path.startsWith(OPEN_PATH)) {\n if (!sameSecret(path.slice(OPEN_PATH.length), token)) return plain(response, 404, \"Not found\");\n return plain(response, 303, \"\", { location: \"/\", \"referrer-policy\": \"no-referrer\", \"set-cookie\": `${OPEN_COOKIE}=${token}; Path=/; HttpOnly; SameSite=Lax` });\n }\n if (!cookieValues(request.headers.cookie, OPEN_COOKIE).some((value) => sameSecret(value, token))) return plain(response, 404, \"Not found\");\n const chunks: Buffer[] = [];\n let size = 0, refused = false;\n request.on(\"data\", (chunk: Buffer) => {\n if (refused) return;\n size += chunk.length;\n if (size > LIMITS.maxRequestBodyBytes) {\n refused = true;\n chunks.length = 0;\n plain(response, 413, \"The request body is too large\", { connection: \"close\" });\n return;\n }\n chunks.push(chunk);\n });\n request.on(\"end\", () => { if (!refused) void proxy(request, response, chunks, send, cookies); });\n });\n await new Promise<void>((resolve, reject) => { server.once(\"error\", reject); server.listen(port, \"127.0.0.1\", () => { server.off(\"error\", reject); resolve(); }); });\n host = `${name}:${(server.address() as AddressInfo).port}`;\n return { server, host, url: `http://${host}${OPEN_PATH}${token}` };\n}\n\nasync function proxy(request: IncomingMessage, response: ServerResponse, chunks: Buffer[], send: ServiceSend, cookies: Set<string>): Promise<void> {\n // A browser that goes away stops the contact's answer too.\n const stop = new AbortController();\n response.on(\"close\", () => { if (!response.writableFinished) stop.abort(); });\n try {\n const headers = Object.entries(request.headers).flatMap(([name, value]) => (Array.isArray(value) ? value.map((v) => [name, v] as [string, string]) : value === undefined ? [] : [[name, value] as [string, string]]))\n .flatMap(([name, value]): [string, string][] => {\n if (name.toLowerCase() !== \"cookie\") return [[name, value]];\n const own = ownCookies(value, cookies);\n return own ? [[name, own]] : [];\n });\n const answer = await send({ method: request.method ?? \"GET\", path: request.url ?? \"/\", headers, body: chunks.length ? new Uint8Array(Buffer.concat(chunks)) : null, maxResponseBytes: MAX_RESPONSE_BYTES, signal: stop.signal });\n const out: Record<string, string | string[]> = {};\n for (const [name, value] of answer.headers) {\n const lower = name.toLowerCase();\n if (lower === \"transfer-encoding\" || lower === \"connection\") continue;\n if (lower === \"set-cookie\") {\n const cookie = hostOnlyCookie(value);\n if (!cookie) continue;\n if (cookies.size < MAX_COOKIE_NAMES) cookies.add(setCookieName(cookie)!);\n out[lower] = [...((out[lower] as string[] | undefined) ?? []), cookie];\n } else out[lower] = value;\n }\n response.writeHead(answer.status, out);\n // Streamed, not gathered: past the cap (or when the contact drops it) the body stops and the connection closes.\n await pipeline(Readable.from(answer.body, { objectMode: false }), response);\n } catch (error) {\n // Once the status line is out, a second one cannot follow: the response is cut, and the browser sees it end short.\n if (response.headersSent) { response.destroy(); return; }\n const gone = error instanceof GhostlyHttpError && [\"unreachable\", \"timeout\", \"closed\", \"offline\"].includes(error.code);\n plain(response, gone ? 503 : 502, gone ? \"This service is not reachable. Services exist while their ghost is online.\" : `The request failed: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * The service a command names, by its id: one of this profile's. The engine changes nothing for an id it does not\n * know and says nothing, so a mistyped id read as done (\"shared\": true, with a contact).\n */\nfunction serviceOf(ctx: ApiContext, params: Params): string {\n const serviceId = str(params, \"service\", true);\n if (!state(ctx).services.some((s) => s.id === serviceId)) throw new CliError(\"not_found\", `No service ${JSON.stringify(serviceId)} (ghostly service list)`);\n return serviceId;\n}\n\nexport const SERVICE_METHODS: Record<string, Method> = {\n async \"service.list\"(ctx) {\n return { services: state(ctx).services.map((s) => ({ id: s.id, name: s.name, target: s.target, enabled: s.enabled, sharedWith: s.sharedWith ?? [], requests: s.requests })) };\n },\n async \"service.add\"(ctx, params) {\n const target = str(params, \"target\", true);\n let url: URL;\n try { url = new URL(target); } catch { throw new CliError(\"bad_request\", `Not a URL: ${target}`); }\n if (!(LOOPBACK.has(url.hostname) || /^127\\.\\d+\\.\\d+\\.\\d+$/.test(url.hostname))) throw new CliError(\"refused\", \"Only a web app on this machine (127.0.0.1, localhost) can be shared\");\n return node(ctx).addService({ name: str(params, \"name\", true), target });\n },\n async \"service.remove\"(ctx, params) {\n const serviceId = serviceOf(ctx, params);\n await node(ctx).removeService({ serviceId });\n return { removed: serviceId };\n },\n async \"service.enable\"(ctx, params) {\n const serviceId = serviceOf(ctx, params);\n await node(ctx).setServiceEnabled({ serviceId, enabled: !bool(params, \"off\") });\n return { service: serviceId, enabled: !bool(params, \"off\") };\n },\n async \"service.share\"(ctx, params) {\n const link = chatOf(ctx, params);\n const shared = !bool(params, \"off\");\n const serviceId = serviceOf(ctx, params);\n await node(ctx).setServiceShared({ serviceId, peerPubKeyZ32: link.peerPubKeyZ32, shared });\n return { service: serviceId, chat: link.id, shared };\n },\n /** What a contact shares with this profile (while its app is live). */\n async \"service.peer\"(ctx, params) {\n const link = chatOf(ctx, params);\n return { chat: link.id, live: isLive(link), services: link.peerServices ?? [] };\n },\n /** A contact's shared app on a loopback port of this machine, as the Desktop opens it in a window. */\n async \"service.open\"(ctx, params) {\n if (ctx.mode !== \"daemon\") throw new CliError(\"unavailable\", \"An opened service lives in the daemon: start `ghostly daemon --detach` first\");\n const link = chatOf(ctx, params);\n const service = str(params, \"service\", true);\n const key = `${link.peerPubKeyZ32}/${service}`;\n const already = open.get(key);\n if (already) return { chat: link.id, service, url: already.url };\n if (!link.peerServices?.some((s) => s.id === service)) throw new CliError(\"not_found\", `The contact shares no service ${service} (or is not live)`);\n const peer = link.peerPubKeyZ32;\n const opened = await openServiceServer((request) => node(ctx).request(peer, service, request), num(params, \"port\", 0, { min: 0, max: 65535 }));\n open.set(key, opened);\n return { chat: link.id, service, url: opened.url };\n },\n async \"service.close\"(ctx, params) {\n const link = chatOf(ctx, params);\n const key = `${link.peerPubKeyZ32}/${str(params, \"service\", true)}`;\n const entry = open.get(key);\n if (!entry) throw new CliError(\"not_found\", \"That service is not open here\");\n open.delete(key);\n await new Promise<void>((resolve) => entry.server.close(() => resolve()));\n return { closed: key };\n },\n};\n","import { bool, list, str, type Method } from \"../apiKit\";\n\n/** Voice calls (WISP 1100 § Calls): the API methods. The audio itself goes over each call's own socket. */\nexport const CALL_METHODS: Record<string, Method> = {\n async \"call.start\"(ctx, params) {\n return ctx.calls.start(str(params, \"chat\", true), { rate: params.rate });\n },\n async \"call.answer\"(ctx, params) {\n return ctx.calls.answer(str(params, \"call\"), { rate: params.rate });\n },\n async \"call.hangup\"(ctx, params) {\n return ctx.calls.hangup(str(params, \"call\"));\n },\n async \"call.list\"(ctx) {\n return { calls: ctx.calls.list(), autoAnswer: ctx.calls.getAuto(), available: ctx.runtime.callsUnavailable === null, ...(ctx.runtime.callsUnavailable ? { unavailable: ctx.runtime.callsUnavailable } : {}) };\n },\n async \"call.get\"(ctx, params) {\n return ctx.calls.get(str(params, \"call\"));\n },\n async \"call.flush\"(ctx, params) {\n return ctx.calls.flush(str(params, \"call\"));\n },\n async \"call.auto\"(ctx, params) {\n if (params.on === undefined) return { autoAnswer: ctx.calls.getAuto() };\n return { autoAnswer: ctx.calls.setAuto({ on: bool(params, \"on\"), from: list(params, \"from\"), rate: params.rate }) };\n },\n};\n","import { readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { APP_PERMISSIONS, appRef, isAppRef, isAppUrl, type AppPermission } from \"@ghostly/core\";\nimport { list, str, type ApiContext, type Method } from \"./apiKit\";\nimport { checkedBundle } from \"./apps\";\nimport { CliError } from \"./errors\";\n\n/*\n * `app serve` (WISP 1200 § A bot on the other side): the apps this profile speaks for, in chats, as a bot. No app runs\n * here: a program of the bot's own speaks the app's messages. An app is served from its signed bundle, checked as a\n * client checks one, and each permission its manifest asks is answered on the command line, never by itself. The list\n * is kept in the profile folder (`apps.json`); the engine offers apps/1 to contacts only while it holds an app, which\n * it reads when it starts.\n */\n\n/** The permissions a bot can be granted: `internet` is a page's, and no page runs here. */\nconst GRANTABLE: readonly AppPermission[] = [\"chat\", \"name\"];\n\nexport interface ServedApp {\n ref: string;\n title: string;\n version: string;\n sequence: number;\n digest: string;\n /** Where a contact's app fetches the bundle (the app card's `url`), when one is known. */\n url?: string;\n /** What the manifest asks, and what this profile granted of it. */\n permissions: AppPermission[];\n granted: AppPermission[];\n servedAt: number;\n}\n\nconst servedFile = (dir: string) => join(dir, \"apps.json\");\n\n/** The apps a profile serves, by its folder: none when the file is missing or not a list of them. */\nexport function servedApps(dir: string): ServedApp[] {\n try {\n const read = JSON.parse(readFileSync(servedFile(dir), \"utf8\")) as unknown;\n return Array.isArray(read) ? read.filter((app): app is ServedApp => !!app && typeof app === \"object\" && isAppRef((app as ServedApp).ref)) : [];\n } catch { return []; }\n}\n\nfunction writeServed(dir: string, apps: ServedApp[]): void {\n const file = servedFile(dir);\n writeFileSync(file + \".tmp\", JSON.stringify(apps, null, 2) + \"\\n\", { mode: 0o600 });\n renameSync(file + \".tmp\", file);\n}\n\n/** A served app by its reference or, when only one has it, its name. */\nexport function servedApp(apps: readonly ServedApp[], ref: string): ServedApp {\n const matches = apps.filter((a) => a.ref === ref || a.ref.split(\"/\")[1] === ref);\n if (matches.length !== 1) throw new CliError(matches.length ? \"bad_request\" : \"not_found\", matches.length ? `${JSON.stringify(ref)} names more than one served app: give its whole reference` : `No served app ${JSON.stringify(ref)}: app serve its bundle first`);\n return matches[0];\n}\n\n/** Whether this engine offers apps/1 now: it read the list when it started, so the first app served waits for a restart. */\nconst offered = (ctx: ApiContext, apps: ServedApp[]) => ({ offered: ctx.runtime.apps, ...(apps.length > 0 && !ctx.runtime.apps && { restart: true }) });\n\nexport const APP_SERVE_METHODS: Record<string, Method> = {\n async \"app.serve\"(ctx, params) {\n const source = str(params, \"bundle\", true);\n const grant = list(params, \"grant\");\n const unknown = grant.filter((p) => !(APP_PERMISSIONS as readonly string[]).includes(p));\n if (unknown.length) throw new CliError(\"bad_request\", `grant takes ${GRANTABLE.join(\" or \")}, not ${unknown.map((p) => JSON.stringify(p)).join(\", \")}`);\n if (grant.includes(\"internet\")) throw new CliError(\"refused\", \"internet cannot be granted here: no app's page runs on the CLI, and a bot reaches the network as its own program\");\n const given = str(params, \"url\");\n if (given !== undefined && !isAppUrl(given)) throw new CliError(\"bad_request\", \"url is where a contact's app reads the bundle: https only, no user or password, jsDelivr only at a full commit\");\n const { bundle, url } = await checkedBundle(source);\n const m = bundle.manifest;\n if (!m.permissions.includes(\"chat\")) throw new CliError(\"refused\", `${m.title} does not ask for chat: it talks to no contact, so a bot has nothing to speak for it`);\n const extra = grant.filter((p) => !m.permissions.includes(p as AppPermission));\n if (extra.length) throw new CliError(\"bad_request\", `${m.title} does not ask for ${extra.join(\" or \")}: grant only what its manifest asks (${m.permissions.join(\", \")})`);\n const missing = m.permissions.filter((p) => GRANTABLE.includes(p) && !grant.includes(p));\n if (missing.length)\n throw new CliError(\"confirm\", `${m.title} asks for ${missing.join(\" and \")}: serve it with ${missing.map((p) => `--grant ${p}`).join(\" \")} to allow that`, { asks: m.permissions, missing });\n const ref = appRef(m.publisher, m.name);\n const cardUrl = given ?? url ?? m.sources?.[0];\n const app: ServedApp = {\n ref, title: m.title, version: m.version, sequence: m.sequence, digest: bundle.digest, ...(cardUrl !== undefined && { url: cardUrl }),\n permissions: m.permissions, granted: m.permissions.filter((p) => grant.includes(p)), servedAt: Date.now(),\n };\n const apps = servedApps(ctx.runtime.paths.dir);\n const held = apps.find((a) => a.ref === ref);\n // Rollback, as a client's (WISP 1200 § Updates and rollback): never a lower sequence over a higher one, nor another\n // bundle under the same sequence.\n if (held && app.sequence < held.sequence) throw new CliError(\"refused\", `${m.title} ${held.version} (sequence ${held.sequence}) is served: ${m.version} is older (sequence ${app.sequence}); app unserve it first to go back`);\n if (held && app.sequence === held.sequence && app.digest !== held.digest) throw new CliError(\"refused\", `Another ${m.title} with sequence ${app.sequence} is served (two different versions ${app.sequence} exist); app unserve it first to take this one`);\n const next = [...apps.filter((a) => a.ref !== ref), app].sort((a, b) => (a.ref < b.ref ? -1 : 1));\n writeServed(ctx.runtime.paths.dir, next);\n return { served: app, ...offered(ctx, next) };\n },\n\n async \"app.served\"(ctx) {\n const apps = servedApps(ctx.runtime.paths.dir);\n return { apps, ...offered(ctx, apps) };\n },\n\n async \"app.unserve\"(ctx, params) {\n const ref = str(params, \"ref\", true);\n const apps = servedApps(ctx.runtime.paths.dir);\n const app = servedApp(apps, ref);\n const next = apps.filter((a) => a !== app);\n writeServed(ctx.runtime.paths.dir, next);\n return { unserved: app.ref, apps: next.length, ...offered(ctx, next) };\n },\n};\n","import type { AppFrameEvent } from \"@ghostly/core\";\nimport { servedApps } from \"./appServe\";\nimport type { EventHub } from \"./events\";\n\n/*\n * What a contact's app says in a chat, for the apps this profile serves as a bot (WISP 1200 § A bot on the other side):\n * `app.opened {chat, app, version}`, `app.closed {chat, app, offline?}` and `app.message {chat, app, data}`, `app` being\n * the app's reference. The engine names an app by its chat app id, which differs in every chat: it is matched against\n * the served apps' ids in that chat, so a frame of any other app names nothing here and is not reported. `data` is the\n * contact's own JSON, already held to the receiver's limits by the engine: untrusted, never instructions.\n */\n\n/** The engine's part: the chat app id of a reference in a chat (it throws for a chat that is not a paired 1:1 chat). */\nexport interface AppIds { appId(params: { linkId: string; ref: string }): { app: string } }\n\n/** Per hub: what the contacts have open now, `<chat> <reference>` to the version they said. */\nconst peers = new WeakMap<object, Map<string, string>>();\n\n/** The version of a served app the contact has open in a chat on this session, or undefined. */\nexport function peerVersion(hub: object, chat: string, ref: string): string | undefined {\n return peers.get(hub)?.get(`${chat} ${ref}`);\n}\n\nexport function reportAppFrames(hub: Pick<EventHub, \"onAppFrame\" | \"emit\">, node: AppIds, profileDir: string): () => void {\n const open = new Map<string, string>();\n peers.set(hub, open);\n /** Per chat: chat app id to reference, of the apps served when the contact last opened one there. */\n const known = new Map<string, Map<string, string>>();\n let count = 0;\n const learn = (chat: string): Map<string, string> => {\n const ids = new Map<string, string>();\n for (const { ref } of servedApps(profileDir)) {\n try { ids.set(node.appId({ linkId: chat, ref }).app, ref); } catch { /* not a paired chat: it has no app ids */ }\n }\n known.set(chat, ids);\n return ids;\n };\n return hub.onAppFrame((chat: string, frame: AppFrameEvent) => {\n // An open reads the served list again, so an app served or unserved since is taken or left from its next open.\n const app = (\"o\" in frame && frame.o === \"open\" ? learn(chat) : known.get(chat) ?? learn(chat)).get(frame.app);\n if (!app) return;\n // Frames are not stored, so nothing names one but its place in this run: the id is unique, and never derived again.\n const id = `${chat}:${app}:${Date.now()}-${++count}`;\n if (\"o\" in frame) { if (frame.o === \"open\") open.set(`${chat} ${app}`, frame.v); else open.delete(`${chat} ${app}`); }\n if (!(\"o\" in frame)) hub.emit(\"app.message\", `app.message:${id}`, { chat, app, data: frame.d });\n else if (frame.o === \"open\") hub.emit(\"app.opened\", `app.opened:${id}`, { chat, app, version: frame.v });\n else hub.emit(\"app.closed\", `app.closed:${id}`, { chat, app, ...(frame.offline && { offline: true }) });\n });\n}\n","import { APP_DATA_MAX_BYTES, APP_SEND_LIMIT, appCardId, type AppCard, type AppSendError } from \"@ghostly/core\";\nimport { bool, chatOf, node, str, type ApiContext, type Method, type Params } from \"./apiKit\";\nimport { peerVersion } from \"./appEvents\";\nimport { servedApp, servedApps, type ServedApp } from \"./appServe\";\nimport { CliError } from \"./errors\";\nimport { isLive } from \"./views\";\n\n/*\n * A served app in a chat (WISP 1200 § A bot on the other side): `app open` says the app is open on this side and, when\n * the contact's app is not open there yet, sends the app's card, as a person's app does when they open one; `app send`\n * is one frame of the app's own protocol to the contact's app, once both opened it; `app close` ends it. What is open is the engine's, in memory: only a daemon holds it, and a restarted one opens again.\n */\n\n/** The chat and the served app a command names, on an engine that speaks apps/1. */\nfunction target(ctx: ApiContext, params: Params): { chat: string; live: boolean; app: ServedApp } {\n const app = servedApp(servedApps(ctx.runtime.paths.dir), str(params, \"ref\", true));\n if (ctx.mode !== \"daemon\") throw new CliError(\"unavailable\", \"An app is open only while a daemon runs: start one (ghostly daemon start) and open it there\");\n if (!ctx.runtime.apps) throw new CliError(\"unavailable\", \"This daemon started before an app was served, so it offers no apps/1 yet: ghostly daemon restart\");\n const link = chatOf(ctx, params);\n return { chat: link.id, live: isLive(link), app };\n}\n\n/** The engine's own words for a call it refused (a chat not paired yet, a group), as `refused`. */\nasync function engine<T>(run: () => T | Promise<T>): Promise<T> {\n try { return await run(); } catch (error) { throw new CliError(\"refused\", error instanceof Error ? error.message : String(error)); }\n}\n\nexport const APP_CHAT_METHODS: Record<string, Method> = {\n async \"app.open\"(ctx, params) {\n const { chat, live, app } = target(ctx, params);\n const peer = peerVersion(ctx.hub, chat, app.ref) ?? null;\n await engine(() => node(ctx).appOpen({ linkId: chat, ref: app.ref, version: app.version }));\n let card: string | null = null;\n // The card is how a person learns of the app and gets it (\"Install to play\"); one whose app is open has no use for it.\n if (!bool(params, \"noCard\") && peer === null) {\n const sent: AppCard = { kind: \"app\", id: appCardId(app.ref), ref: app.ref, digest: app.digest, sequence: app.sequence, title: app.title, version: app.version, ...(app.url !== undefined && { url: app.url }), opened: true };\n const result = await node(ctx).sendMessage({ linkId: chat, text: \"\", card: sent });\n if (result.error || !result.messageId) {\n // Not half open: with no card the contact would never know, so the open is taken back.\n await engine(() => node(ctx).appClose({ linkId: chat, ref: app.ref }));\n throw new CliError(result.refused ? \"refused\" : \"unavailable\", result.error ?? \"The app's card could not be sent\");\n }\n card = result.messageId;\n }\n return { chat, app: app.ref, version: app.version, card, peer, live };\n },\n\n async \"app.close\"(ctx, params) {\n const { chat, app } = target(ctx, params);\n await engine(() => node(ctx).appClose({ linkId: chat, ref: app.ref }));\n return { chat, app: app.ref, closed: true };\n },\n\n async \"app.send\"(ctx, params) {\n const { chat, app } = target(ctx, params);\n if (!(\"data\" in params) || params.data === undefined) throw new CliError(\"bad_request\", \"data is required: the app's message, any JSON value\");\n const { error } = await engine(() => node(ctx).appSend({ linkId: chat, ref: app.ref, data: params.data }));\n if (error) throw new CliError(NOT_SENT[error].code, NOT_SENT[error].message, { reason: error });\n return { chat, app: app.ref, sent: true };\n },\n};\n\n/** Why a frame did not go (WISP 1200 § In a chat), in `details.reason`. Nothing is kept to send later. */\nconst NOT_SENT: Record<AppSendError, { code: \"refused\" | \"bad_request\" | \"unavailable\"; message: string }> = {\n \"not-open\": { code: \"refused\", message: \"The app is not open in this chat on this side: app open it first\" },\n \"too-large\": { code: \"bad_request\", message: `The message is over ${APP_DATA_MAX_BYTES} bytes of JSON, the most an app's frame carries` },\n offline: { code: \"unavailable\", message: \"The chat is not live: an app's frames go on the live session only, and none is kept for later\" },\n \"peer-closed\": { code: \"unavailable\", message: \"The contact's app is not open in this chat (or their Ghostly runs no apps): wait for app.opened\" },\n \"too-fast\": { code: \"refused\", message: `More than ${APP_SEND_LIMIT} frames in a second, or the connection is still sending earlier ones: slow down and send it again` },\n};\n","import { generateMnemonic } from \"@scure/bip39\";\nimport { wordlist } from \"@scure/bip39/wordlists/english.js\";\nimport type { WalletNetwork } from \"@ghostly/core\";\nimport type { EngineState, NetworkWalletsView, PaymentView, WalletInstanceView, WalletOffer, WalletType } from \"@ghostly/browser/shared/types\";\nimport { bool, chatOf, inviteTaken, node, num, oneOf, sentAt, state, str, type ApiContext, type Method, type Params } from \"./apiKit\";\nimport { paymentNetwork } from \"@ghostly/browser/engine/paymentAdapters/walletInstances\";\nimport { CliError, type ErrorCode } from \"./errors\";\n\n/**\n * Wallets and payments (WISP 1100, phase 2): the app's wallet deck and a chat's payment sheet, as methods. Test\n * networks move nothing real. On Mainnet every spend passes `confirmedReal`, which the engine requires, only when the\n * call says `confirmReal: true` (the CLI's `--confirm-real`): no flag, no spend.\n */\n\nconst NETWORKS = [\"mainnet\", \"testnet\"] as const;\nconst TYPES = [\"cashu\", \"lightning\", \"arkade\", \"bark\", \"spark\", \"bitcoin\", \"fedimint\", \"usdt\"] as const;\nconst METHODS = [\"cashu\", \"arkade\", \"usdt\", \"bark\", \"bitcoin\", \"fedimint\", \"spark\"] as const;\nconst CHAT_METHODS = [\"cashu\", \"lightning\", ...METHODS.filter((m) => m !== \"cashu\")] as const;\n\n/**\n * What the app has and a headless Ghostly cannot run yet, and why (WISP 1100 § Wallet SDKs on Node). New offers\n * them as unavailable; creating one is refused before the engine is asked.\n */\nexport const NODE_GAPS: Partial<Record<WalletType, string>> = {\n bark: \"Bark's SDK ships a browser build only: its WebAssembly needs a browser window. Use it from the app.\",\n};\n\n/** Sources the engine lists that live in a browser page (`window.webln`): a headless Ghostly never offers them. */\nconst BROWSER_SOURCES = new Set([\"webln\"]);\n\n/** The sources of an offer a headless Ghostly can connect. */\nconst nodeSources = (offer: WalletOffer | undefined) => offer?.providers?.filter((p) => !BROWSER_SOURCES.has(p.id));\n\n/**\n * What `wallet create` was given checked against the offer's own form, before the engine is asked: a source, a field\n * or a flag left out, or one the wallet does not take, is the person's value, said naming the flag. Before, the engine\n * refused it in the app's words (\"Enter connection uri\", \"Nothing was saved; try again\") as `engine`, or the flag was\n * dropped without a word.\n */\nfunction createChecked(type: WalletType, n: WalletNetwork, offer: WalletOffer | undefined, provider: string | undefined, values: Record<string, string>, params: Params): void {\n if (type !== \"lightning\" && type !== \"bitcoin\") {\n if (provider || Object.keys(values).length) throw new CliError(\"usage\", `--provider and --value name a lightning or bitcoin source: not with ${type}`);\n if (offer?.needs === \"invite\" && !str(params, \"invite\")?.trim()) throw new CliError(\"bad_request\", `${type} needs --invite <fed11…>`);\n if (offer?.needs === \"apiKey\" && !str(params, \"apiKey\")?.trim()) throw new CliError(\"bad_request\", `${type} on ${n} needs --api-key <key> (or api-key=… on --stdin)`);\n return;\n }\n // None offered on this network: the engine says why.\n const sources = nodeSources(offer);\n if (!sources?.length) return;\n if (!provider) throw new CliError(\"bad_request\", `${type} needs --provider: one of ${sources.map((p) => p.id).join(\", \")} (ghostly wallet list)`);\n const source = sources.find((p) => p.id === provider);\n if (!source) throw new CliError(\"bad_request\", `No ${type} source ${JSON.stringify(provider)} on ${n} (ghostly wallet list)`);\n const unknown = Object.keys(values).find((name) => !source.fields.some((f) => f.name === name));\n if (unknown) throw new CliError(\"bad_request\", `${provider} takes no --value ${unknown}: ${source.fields.length ? `its fields are ${source.fields.map((f) => f.name).join(\", \")}` : \"it has no fields\"}`);\n const missing = source.fields.find((f) => !f.optional && !f.defaults?.[n] && !values[f.name]?.trim());\n if (missing) throw new CliError(\"bad_request\", `${provider} needs --value ${missing.name}=<${missing.options?.map((o) => o.value).join(\"|\") ?? missing.placeholder ?? missing.label.toLowerCase()}>`);\n}\n\nconst network = (params: Params, fallback: WalletNetwork = \"testnet\") => oneOf(params, \"network\", NETWORKS, fallback);\n\n/** `confirmedReal` for the engine: only when the caller confirmed real money, and only then. */\nconst real = (params: Params): { confirmedReal?: true } => (bool(params, \"confirmReal\") ? { confirmedReal: true } : {});\n\nfunction netView(s: EngineState, n: WalletNetwork): NetworkWalletsView | undefined {\n return s.wallet.networks?.[n];\n}\n\n/** A Lightning card named by `card` on the network asked: one that is not there is not_found, before the engine is asked. */\nfunction lightningCard(ctx: ApiContext, params: Params): void {\n const n = network(params), card = str(params, \"card\", true);\n if (!netView(state(ctx), n)?.lightnings?.some((c) => c.card === card)) throw new CliError(\"not_found\", `No Lightning card ${JSON.stringify(card)} on ${n} (ghostly wallet list)`);\n}\n\n/**\n * The Lightning card `card` names, checked before the engine is asked: given with another type of wallet it is a usage\n * error, and one not on the network is not_found. Before, the engine dropped it for every type but Lightning, so a card\n * that named nothing removed the whole wallet of that type and the answer echoed the card as removed.\n */\nfunction cardOf(ctx: ApiContext, params: Params, type: WalletType): string | undefined {\n const card = str(params, \"card\");\n if (card === undefined) return undefined;\n if (type !== \"lightning\") throw new CliError(\"usage\", `--card names a Lightning card: not with ${type}`);\n lightningCard(ctx, params);\n return card;\n}\n\n/**\n * The engine opens the federations joined before in the background as it starts. A daemon has long done so when a call\n * comes; a one-shot command waits for them (at most 30 s) before its balances are read or money moves through one.\n */\nasync function federationsOpen(ctx: ApiContext, ms = 30_000): Promise<void> {\n if (ctx.mode !== \"one-shot\") return;\n const until = Date.now() + ms;\n const connecting = () => NETWORKS.some((n) => (netView(state(ctx), n)?.fedimint?.federations ?? []).some((f) => f.status === \"connecting\"));\n while (connecting() && Date.now() < until) await new Promise((resolve) => setTimeout(resolve, 250));\n}\n\n/** One wallet of the deck with its balance, in its own unit. Never a key, a phrase or a token. */\nexport function walletJson(instance: WalletInstanceView, s: EngineState) {\n const view = netView(s, instance.network);\n let balance: number | string | null = null, unit = \"sat\", address: string | null = null, status: string | null = null, error: string | null = null;\n switch (instance.type) {\n case \"cashu\": balance = view?.balance ?? null; break;\n case \"lightning\": {\n const card = view?.lightnings?.find((c) => c.card === instance.card);\n balance = card?.balance ?? null; status = card?.status ?? null; error = card?.error ?? null;\n break;\n }\n case \"arkade\": balance = view?.ark?.balance ?? null; address = view?.ark?.address ?? null; error = view?.ark?.error ?? null; break;\n case \"bark\": balance = view?.bark?.balance ?? null; error = view?.bark?.error ?? null; break;\n case \"spark\": balance = view?.spark?.balance ?? null; address = view?.spark?.address ?? null; error = view?.spark?.error ?? null; break;\n case \"bitcoin\": balance = view?.bitcoin?.balance ?? null; address = view?.bitcoin?.address ?? null; status = view?.bitcoin?.status ?? null; error = view?.bitcoin?.error ?? null; break;\n case \"fedimint\": balance = view?.fedimint?.balance ?? null; error = view?.fedimint?.error ?? null; break;\n case \"usdt\": balance = view?.usdt?.balance ?? null; unit = \"token-base\"; address = view?.usdt?.address ?? null; error = view?.usdt?.error ?? null; break;\n }\n return {\n id: instance.id, type: instance.type, network: instance.network,\n ...(instance.card ? { card: instance.card, name: instance.name ?? null, receive: !!instance.receive } : {}),\n balance, unit, address, status, error, config: instance.config,\n };\n}\n\nexport function paymentJson(p: PaymentView) {\n return {\n id: p.id, chat: p.linkId, kind: p.kind, direction: p.direction, amount: p.amount, unit: p.unit, memo: p.memo ?? null,\n state: p.state, error: p.error ?? null, network: paymentNetwork(p), method: p.target?.method ?? (p.federation || p.federations ? \"fedimint\" : p.invoice ? \"lightning\" : p.mint || p.mints ? \"cashu\" : null),\n createdAt: p.createdAt, ...(p.group ? { group: p.group } : {}), ...(p.closed ? { closed: true } : {}), ...(p.txid ? { txid: p.txid } : {}),\n };\n}\n\n/**\n * A Lightning invoice's network by its prefix (BOLT 11), for a hint only: test mints issue `lnbc` invoices too, so\n * the paying wallet's network is always named by the caller.\n */\nexport function invoiceNetwork(invoice: string): WalletNetwork | null {\n const lower = invoice.trim().toLowerCase().replace(/^lightning:/, \"\");\n if (!lower.startsWith(\"ln\")) return null;\n if (/^lnbcrt/.test(lower)) return \"testnet\";\n if (/^lnbc\\d|^lnbc1/.test(lower)) return \"mainnet\";\n return /^ln(tb|tbs|sb)/.test(lower) ? \"testnet\" : null;\n}\n\nconst isInvoice = (text: string) => /^(lightning:)?ln(bc|tb|tbs|sb|bcrt)[0-9a-z]+$/i.test(text.trim());\nconst isLnurl = (text: string) => /^(lightning:)?lnurl[0-9a-z]+$/i.test(text.trim()) || /^[a-z0-9._+-]+@[a-z0-9.-]+\\.[a-z]{2,}$/i.test(text.trim());\n\n/**\n * The engine refusing the mint URL the person typed (not a URL, or not https): their value, so `bad_request`, as\n * `service add` says; before, it was `engine` (exit 1), which a bot reads as the engine failing and may retry. Read by\n * its shape: the engine's `EngineError` carries `engineCode`.\n */\nfunction badMintUrl(error: unknown): boolean {\n const code = error instanceof Error ? (error as { engineCode?: unknown }).engineCode : undefined;\n return code === \"invalidMintUrl\" || code === \"mintNotHttps\";\n}\n\n/**\n * The engine's wallet refusals about what the person asked, by the words it writes (they carry no `engineCode`): a\n * wallet or card that is not there, a token or invoice that is not one, a wallet already made, no mint or source to do\n * it with. Before, each was `engine` (exit 1), which a bot reads as the engine failing and may retry.\n */\nconst WALLET_REFUSALS: [RegExp, ErrorCode][] = [\n [/^There is no .+ to remove$/, \"not_found\"],\n [/^That Lightning card is gone\\b/, \"not_found\"],\n [/^That is not a (valid ecash token|Lightning invoice)$/, \"bad_request\"],\n [/^You already have a .+ wallet$/, \"refused\"],\n [/^No mint could create an invoice: No mint configured$/, \"unavailable\"],\n [/^No Bitcoin source is set up$/, \"unavailable\"],\n [/^The faucet did not pay: This wallet has no test mint\\b/, \"unavailable\"],\n [/^Ghostly cannot ask this wallet's faucet by itself\\b/, \"unavailable\"],\n];\n\nfunction walletRefusal(error: unknown): unknown {\n if (!(error instanceof Error) || error instanceof CliError) return error;\n const code = WALLET_REFUSALS.find(([pattern]) => pattern.test(error.message))?.[1];\n return code ? new CliError(code, error.message) : error;\n}\n\nconst WALLETS: Record<string, Method> = {\n async \"wallet.list\"(ctx, params) {\n await federationsOpen(ctx);\n const s = state(ctx);\n const only = params.network === undefined ? null : network(params);\n const wallets = (s.wallet.wallets ?? []).filter((w) => !only || w.network === only).map((w) => walletJson(w, s));\n const offers = (s.wallet.offers ?? []).filter((o) => !only || o.network === only).map((o) => {\n const gap = NODE_GAPS[o.type];\n return { type: o.type, network: o.network, available: o.available && !gap, reason: gap ?? o.reason ?? null, exists: !!o.exists, several: !!o.several, needs: o.needs ?? null,\n ...(o.providers ? { providers: nodeSources(o)!.map((p) => ({ id: p.id, label: p.label, fields: p.fields.map((f) => ({ name: f.name, label: f.label, kind: f.kind, optional: !!f.optional })) })) } : {}) };\n });\n return { wallets, offers };\n },\n\n async \"wallet.create\"(ctx, params) {\n const type = oneOf(params, \"type\", TYPES, \"cashu\");\n const n = network(params);\n const gap = NODE_GAPS[type];\n if (gap) throw new CliError(\"unavailable\", gap);\n // A Fedimint Lightning card needs its federation open.\n await federationsOpen(ctx);\n const values: Record<string, string> = {};\n const raw = params.values ?? {};\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw) || Object.values(raw).some((v) => typeof v !== \"string\")) throw new CliError(\"bad_request\", \"values must be an object of strings\");\n Object.assign(values, raw);\n // On-chain is BDK unless another source is named.\n const provider = str(params, \"provider\") ?? (type === \"bitcoin\" ? \"bdk\" : undefined);\n // BDK asks for a recovery phrase and makes a new wallet from one the app draws: here, one drawn now.\n if (type === \"bitcoin\" && provider === \"bdk\" && !values.mnemonic) values.mnemonic = generateMnemonic(wordlist, 128);\n createChecked(type, n, state(ctx).wallet.offers?.find((o) => o.type === type && o.network === n), provider, values, params);\n const made = await node(ctx).walletCreate({ type, network: n, ...(provider ? { providerId: provider } : {}), ...(Object.keys(values).length ? { values } : {}), ...(str(params, \"invite\") ? { invite: str(params, \"invite\") } : {}), ...(str(params, \"apiKey\") ? { apiKey: str(params, \"apiKey\") } : {}) });\n return walletJson(made, state(ctx));\n },\n\n async \"wallet.remove\"(ctx, params) {\n const type = oneOf(params, \"type\", TYPES, \"cashu\");\n const n = network(params);\n const card = cardOf(ctx, params, type);\n try {\n await node(ctx).walletRemove({ type, network: n, ...(card ? { card } : {}), ...(bool(params, \"acceptLoss\") ? { acceptLoss: true } : {}) });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n // The engine keeps a wallet that holds money here, or that someone still pays into (#303): only the person decides.\n if (!bool(params, \"acceptLoss\") && /hold|still|awaiting|lose|backup/i.test(message)) throw new CliError(\"confirm\", `${message} (pass acceptLoss, --accept-loss, only if that is intended)`);\n throw error;\n }\n return { removed: { type, network: n, card: card ?? null } };\n },\n\n async \"wallet.faucet\"(ctx, params) {\n const type = oneOf(params, \"type\", TYPES, \"cashu\");\n if (network(params) !== \"testnet\") throw new CliError(\"refused\", \"Test coins are for Testnet wallets only\");\n const card = cardOf(ctx, params, type);\n return node(ctx).walletTestCoins({ type, network: \"testnet\", ...(card ? { card } : {}) });\n },\n\n async \"wallet.history\"(ctx, params) {\n const n = network(params);\n const limit = num(params, \"limit\", 50, { min: 1, max: 10_000, whole: true });\n await federationsOpen(ctx);\n return { network: n, history: (netView(state(ctx), n)?.history ?? []).slice(0, limit) };\n },\n\n async \"wallet.receive\"(ctx, params) {\n const amount = num(params, \"amount\", 0, { min: 1 });\n if (!amount) throw new CliError(\"bad_request\", \"amount is required\");\n const n = network(params);\n await federationsOpen(ctx);\n const card = cardOf(ctx, params, \"lightning\");\n const invoice = await node(ctx).walletReceiveLightning({ amount, network: n, ...(card ? { card } : {}) });\n return { network: n, amount, invoice: invoice.invoice, expiresAt: invoice.expiresAt, paymentHash: invoice.paymentHash ?? null, source: invoice.source };\n },\n\n async \"wallet.address\"(ctx, params) {\n const type = oneOf(params, \"type\", [\"bitcoin\", \"arkade\", \"spark\", \"usdt\"] as const, \"bitcoin\");\n const n = network(params);\n if (type === \"bitcoin\") return { type, network: n, address: await node(ctx).bitcoinReceiveAddress({ network: n }) };\n const view = netView(state(ctx), n);\n const address = type === \"arkade\" ? view?.ark?.address : type === \"spark\" ? view?.spark?.address : view?.usdt?.address;\n if (!address) throw new CliError(\"unavailable\", `No ${type} wallet with an address on ${n}`);\n return { type, network: n, address };\n },\n\n async \"wallet.redeem\"(ctx, params) {\n return node(ctx).walletReceiveToken({ token: str(params, \"token\", true).trim() });\n },\n\n async \"wallet.mint.add\"(ctx, params) {\n return node(ctx).walletAddMint({ url: str(params, \"url\", true), ...(bool(params, \"primary\") ? { primary: true } : {}) }).catch((error: unknown) => {\n throw badMintUrl(error) ? new CliError(\"bad_request\", (error as Error).message) : error;\n });\n },\n\n async \"lightning.default\"(ctx, params) {\n lightningCard(ctx, params);\n await node(ctx).lightningSetReceive({ network: network(params), card: str(params, \"card\", true) });\n return { network: network(params), receive: str(params, \"card\", true) };\n },\n\n async \"lightning.rename\"(ctx, params) {\n lightningCard(ctx, params);\n await node(ctx).lightningRename({ network: network(params), card: str(params, \"card\", true), name: str(params, \"name\", true) });\n return { network: network(params), card: str(params, \"card\", true), name: str(params, \"name\", true) };\n },\n\n /** An invoice, a Lightning address or an LNURL, from the network's Lightning (a card of it, or its default). */\n async \"pay\"(ctx, params) {\n const text = str(params, \"target\", true).trim();\n const card = str(params, \"card\");\n let invoice = text.replace(/^lightning:/i, \"\");\n let n: WalletNetwork;\n let note: string | undefined;\n if (isInvoice(text)) {\n // Which wallet pays is named, never guessed from the invoice: test mints issue `lnbc` invoices too, and a\n // guess must never be what makes real money move. Testnet unless `network` says mainnet.\n n = network(params);\n } else if (isLnurl(text)) {\n n = network(params);\n const amount = num(params, \"amount\", 0, { min: 1 });\n if (!amount) throw new CliError(\"bad_request\", \"amount is required to pay a Lightning address or LNURL\");\n const view = await node(ctx).lnurlResolve({ text, network: n });\n if (amount < view.minSat || amount > view.maxSat) throw new CliError(\"refused\", `${view.domain} takes from ${view.minSat} to ${view.maxSat} sats`);\n const got = await node(ctx).lnurlInvoice({ id: view.id, amount, ...(str(params, \"comment\") ? { comment: str(params, \"comment\") } : {}), network: n });\n invoice = got.invoice; note = got.note;\n } else throw new CliError(\"bad_request\", \"Not a Lightning invoice, Lightning address or LNURL\");\n if (n === \"mainnet\" && !bool(params, \"confirmReal\")) throw new CliError(\"confirm\", \"This pays real money (Mainnet): pass --confirm-real to confirm this payment\");\n await federationsOpen(ctx);\n const quote =await node(ctx).walletQuoteInvoice({ invoice, network: n, ...(card ? { card } : {}) });\n const maxFee = params.maxFee === undefined ? null : num(params, \"maxFee\", 0);\n if (maxFee !== null && quote.feeReserve > maxFee) throw new CliError(\"refused\", `The fee may reach ${quote.feeReserve} sats, more than the ${maxFee} allowed`);\n const paid = await node(ctx).walletPayQuote({ quote: quote.quote, mint: quote.mint, ...(note ? { note } : {}), ...real(params) });\n return { network: n, amount: quote.amount, feeReserve: quote.feeReserve, source: (quote as { source?: string }).source ?? quote.mint, paid: paid.paid };\n },\n\n /** Ecash to a contact in a chat (the payment sheet's Pay). */\n async \"chat.pay\"(ctx, params) {\n const link = chatOf(ctx, params);\n inviteTaken(link);\n const amount = num(params, \"amount\", 0, { min: 1 });\n if (!amount) throw new CliError(\"bad_request\", \"amount is required\");\n const n = network(params);\n if (n === \"mainnet\" && !bool(params, \"confirmReal\")) throw new CliError(\"confirm\", \"This pays real money (Mainnet): pass --confirm-real to confirm this payment\");\n await federationsOpen(ctx);\n const { paymentId } = await node(ctx).sendPayment({ linkId: link.id, amount, timestamp: sentAt(), network: n, ...(str(params, \"memo\") ? { memo: str(params, \"memo\") } : {}), ...real(params) });\n return { chat: link.id, paymentId };\n },\n\n /** A request in a chat (the payment sheet's Request): the contact's app pays it. */\n async \"chat.request\"(ctx, params) {\n const link = chatOf(ctx, params);\n const amount = num(params, \"amount\", 0, { min: 1 });\n if (!amount) throw new CliError(\"bad_request\", \"amount is required\");\n const method = params.method === undefined ? undefined : oneOf(params, \"method\", METHODS, \"cashu\");\n const rail = params.rail === undefined ? undefined : oneOf(params, \"rail\", [\"cashu\", \"lightning\"] as const, \"cashu\");\n await federationsOpen(ctx);\n const { paymentId } = await node(ctx).requestPayment({\n linkId: link.id, amount, timestamp: sentAt(), network: network(params),\n ...(str(params, \"memo\") ? { memo: str(params, \"memo\") } : {}), ...(method ? { method } : {}), ...(rail ? { rail } : {}), ...(str(params, \"card\") ? { card: str(params, \"card\") } : {}),\n });\n return { chat: link.id, paymentId };\n },\n\n /** Pays a request the contact made in a chat. */\n async \"chat.payRequest\"(ctx, params) {\n const link = chatOf(ctx, params);\n const paymentId = str(params, \"payment\", true);\n const request = state(ctx).payments[paymentId];\n if (!request || request.linkId !== link.id || request.kind !== \"request\") throw new CliError(\"not_found\", `No request ${paymentId} in this chat`);\n // The request says which network it is paid on: real money or test coins, never the choice of the payer.\n const n = paymentNetwork(request);\n if (n === \"mainnet\" && !bool(params, \"confirmReal\")) throw new CliError(\"confirm\", \"This request is for real money (Mainnet): pass --confirm-real to confirm this payment\", { network: n });\n const via = params.via === undefined ? undefined : oneOf(params, \"via\", [\"lightning\"] as const, \"lightning\");\n await federationsOpen(ctx);\n await node(ctx).payRequest({ linkId: link.id, paymentId, network: n, ...(via ? { via } : {}), ...(params.maxFee !== undefined ? { maxFee: num(params, \"maxFee\", 0) } : {}), ...(str(params, \"card\") ? { card: str(params, \"card\") } : {}), ...real(params) });\n return paymentJson(state(ctx).payments[paymentId] ?? request);\n },\n\n /** Which ways of paying this chat takes, per network (the chat's Accept switches). */\n async \"chat.accept\"(ctx, params) {\n const link = chatOf(ctx, params);\n const method = oneOf(params, \"method\", CHAT_METHODS, \"cashu\");\n const on = bool(params, \"on\");\n const nets = params.networks === undefined ? undefined : (() => {\n const value = params.networks;\n if (!Array.isArray(value) || !value.every((v) => v === \"mainnet\" || v === \"testnet\")) throw new CliError(\"bad_request\", \"networks must list mainnet and/or testnet\");\n // An empty list names no network: the method would stay on while it is taken nowhere.\n if (value.length === 0) throw new CliError(\"bad_request\", \"networks must list mainnet and/or testnet: to stop taking it, --off\");\n return value as WalletNetwork[];\n })();\n await node(ctx).setChatPaymentMethods({ linkId: link.id, methods: { [method]: on }, ...(nets ? { networks: { [method]: nets } } : {}) });\n const now = state(ctx).links.find((l) => l.id === link.id);\n return { chat: link.id, methods: now?.paymentMethods ?? null, networks: now?.paymentNetworks ?? null };\n },\n\n async \"payment.list\"(ctx, params) {\n const chat = params.chat === undefined ? null : chatOf(ctx, params).id;\n const payments = Object.values(state(ctx).payments).filter((p) => !chat || p.linkId === chat).sort((a, b) => b.createdAt - a.createdAt).map(paymentJson);\n return { payments };\n },\n\n async \"payment.check\"(ctx, params) {\n const link = chatOf(ctx, params);\n if (state(ctx).payments[str(params, \"payment\", true)]?.linkId !== link.id) throw new CliError(\"not_found\", `No payment ${JSON.stringify(str(params, \"payment\", true))} in this chat (ghostly payment list --chat ${link.id})`);\n await node(ctx).checkPayment({ linkId: link.id, paymentId: str(params, \"payment\", true) });\n return { chat: link.id, paymentId: str(params, \"payment\", true) };\n },\n\n async \"payment.reclaim\"(ctx, params) {\n if (!state(ctx).payments[str(params, \"payment\", true)]) throw new CliError(\"not_found\", `No payment ${JSON.stringify(str(params, \"payment\", true))} (ghostly payment list)`);\n await node(ctx).reclaimPayment({ paymentId: str(params, \"payment\", true) });\n const p = state(ctx).payments[str(params, \"payment\", true)];\n return p ? paymentJson(p) : { paymentId: str(params, \"payment\", true) };\n },\n};\n\nexport const WALLET_METHODS: Record<string, Method> = Object.fromEntries(Object.entries(WALLETS).map(([name, method]) => [name,\n (ctx: ApiContext, params: Params) => method(ctx, params).catch((error: unknown) => { throw walletRefusal(error); })]));\n\nexport type { ApiContext };\n","import { AWAITING_PEER_MS, groupName, inviteLink, LIMITS, MAX_GROUP_NAME_LENGTH, MENTION_EVERYONE, ownInviteRefusal, sanitizeTypingStatus, TYPING_KINDS, TYPING_STATUS_MAX, type GroupMention, type PairedTransport, type TypingKind } from \"@ghostly/core\";\nimport type { EngineState, GroupView, Settings, StoredMessage } from \"@ghostly/browser/shared/types\";\nimport { iceServerProblem, iceServerSetting } from \"@ghostly/browser/shared/ice\";\nimport { findSecret } from \"../../../apps/ui/src/lib/parse/secrets\";\nimport { ENGINE_METHODS, ENGINE_READS } from \"./engineMethods\";\nimport { CliError } from \"./errors\";\nimport {\n bool, chatOf, chatOrGroup, findChat, findGroup, groupOf, inviteTaken, list, messageOf, node, num, oneOf, state, str, waitForState,\n type ApiContext, type Method, type Params,\n} from \"./apiKit\";\nimport { FILE_METHODS } from \"./files\";\nimport { waitForEdit, waitForGroupFrame, waitForMessage } from \"./waits\";\nimport { STATUS_CARD_METHODS, secretIn } from \"./statusCards\";\nimport { BUTTON_METHODS, buttonsCard, pressable } from \"./buttons\";\nimport { HOLD_MAX_MINUTES, holdChat, holdOf, releaseHold } from \"./holds\";\nimport { endTyping, keepOneShot, keepTyping, sayTyping } from \"./typing\";\nimport { GROUP_ADMIN_METHODS, noMember } from \"./groupAdmin\";\nimport { withStoredIds } from \"./turnRefs\";\nimport { IDENTITY_METHODS } from \"./identities\";\nimport { SERVICE_METHODS } from \"./services\";\nimport { BACKUP_METHODS } from \"./backup\";\nimport { CALL_METHODS } from \"./calls/api\";\nimport { APP_SERVE_METHODS } from \"./appServe\";\nimport { APP_CHAT_METHODS } from \"./appChat\";\nimport { WALLET_METHODS } from \"./wallets\";\nimport { chatDetailsJson, chatJson, chatMessageJson, groupJson, groupMessageJson, isLive, messageJson, type MessageJson } from \"./views\";\n\n/**\n * A text past what a chat or a group carries (16 KiB of UTF-8, as the engine counts it: trimmed) is refused before the\n * engine is asked, with a code that says it never goes as it is, not \"unavailable\", which reads as \"try later\".\n */\nfunction checkTextSize(text: string): void {\n const bytes = new TextEncoder().encode(text.trim()).length;\n if (bytes > LIMITS.maxChatMessageBytes) throw new CliError(\"bad_request\", `Message exceeds ${LIMITS.maxChatMessageBytes} UTF-8 bytes (${bytes}): shorten it, or send it as a file`, { bytes, max: LIMITS.maxChatMessageBytes });\n}\n\n// ---------- settings ----------\n\n/**\n * The engine's state as `engine getState` prints it without `--show-secret`: the settings' credentials, a group's\n * entry link (anyone who reads it can join) and a pending chat's invite code (whoever reads it can take the chat)\n * are `<hidden>`.\n */\nexport function hideStateSecrets<T extends { settings: Settings; groups?: { entryLink?: string }[]; links?: { inviteCode?: string }[] }>(state: T) {\n return {\n ...state,\n settings: redactSettings(state.settings),\n ...(state.groups ? { groups: state.groups.map((g) => (g.entryLink ? { ...g, entryLink: \"<hidden>\" } : g)) } : {}),\n ...(state.links ? { links: state.links.map((l) => (l.inviteCode ? { ...l, inviteCode: \"<hidden>\" } : l)) } : {}),\n };\n}\n\n/** Settings as a bot may read them: storage credentials and other secrets masked unless asked for. */\nexport function redactSettings(settings: Settings, showSecret = false): Record<string, unknown> {\n if (showSecret) return settings as unknown as Record<string, unknown>;\n const mask = (value: unknown, key = \"\"): unknown => {\n if (value && typeof value === \"object\" && !Array.isArray(value)) return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, mask(v, k)]));\n if (Array.isArray(value)) return value.map((item) => mask(item, key));\n if (typeof value === \"string\" && (/secret|password|token|credential|privatekey|nsec|bunker/i.test(key) || key === \"auth\" || key === \"space\")) return \"<hidden>\";\n return value;\n };\n // The push subscription (wake-up push) is a capability: who holds it can wake this profile's web app.\n const { avatar, wake, ...rest } = settings;\n return { ...(mask(rest) as Record<string, unknown>), ...(avatar ? { avatar: \"<set>\" } : {}), ...(wake ? { wake: \"<set>\" } : {}) };\n}\n\n/** Settings a command may change; the rest are the app's to manage. */\nexport const SETTABLE: Record<string, \"strings\" | \"string\" | \"boolean\" | \"ice\"> = {\n relays: \"strings\", irohRelays: \"strings\", hyperdhtRelay: \"string\", readRelays: \"boolean\",\n iceServers: \"ice\", publicProfiles: \"boolean\", online: \"boolean\", shareProfile: \"boolean\", sendTyping: \"boolean\", nick: \"string\",\n autoDownloads: \"boolean\", serveFiles: \"boolean\",\n};\n\n/**\n * A relay address the engine refuses (node.ts `updateSettings`, irohWeb.ts, hyperdhtRelay.ts): the person's value, so\n * `bad_request` named by its key, in a terminal's words (\"give\", not the app's \"Enter\"). Before, `engine` (exit 1). A\n * wrong scheme (\"Use an https:// relay address\") too.\n */\nfunction relayRefused(error: unknown, patch: Record<string, unknown>): unknown {\n if (!(error instanceof Error) || !/^(?:Enter (?:at least one|a) relay address|Not a relay address|Use an? \\S+ relay address)\\b/.test(error.message)) return error;\n const keys = [\"relays\", \"irohRelays\", \"hyperdhtRelay\"].filter((key) => Object.hasOwn(patch, key));\n return new CliError(\"bad_request\", `${keys.join(\", \") || \"relays\"}: ${error.message.replace(/^Enter /, \"give \").replace(/^(Not|Use) /, (word) => word.toLowerCase())}`);\n}\n\n// ---------- transports ----------\n\nconst TRANSPORT_NAMES: Record<string, PairedTransport | \"auto\" | \"dht\"> = {\n auto: \"auto\", dht: \"dht\", webrtc: \"webrtc/1\", iroh: \"iroh/1\", hyperdht: \"hyperdht/1\",\n \"webrtc/1\": \"webrtc/1\", \"iroh/1\": \"iroh/1\", \"hyperdht/1\": \"hyperdht/1\",\n};\n\n// ---------- chat names ----------\n\n/** The engine keeps a chat's name to 48 UTF-16 units (renameLink). */\nconst CHAT_NAME_UNITS = 48;\n\n/**\n * A chat's name on this side (`chat rename`, an invite's `--label`): what the engine keeps whole, on one line, refused\n * with the rule as a profile's or a group's name is. Taken as given, the engine cut it at 48 UTF-16 units without a\n * word (half an emoji left as a lone surrogate) and kept line breaks. Counted as the engine counts: an emoji is two.\n */\nfunction chatName(params: Params, name: string): string | undefined {\n const value = str(params, name);\n if (value !== undefined && (value.trim().length > CHAT_NAME_UNITS || /\\p{Cc}/u.test(value.trim()))) {\n throw new CliError(\"bad_request\", `A chat's name is up to ${CHAT_NAME_UNITS} characters on one line (an emoji counts as two)`);\n }\n return value;\n}\n\n// ---------- mentions ----------\n\n/** Code points before `index` (UTF-16) in `text`: mentions count code points (WISP 902 § Mentions). */\nconst codePoints = (text: string, index: number) => [...text.slice(0, index)].length;\n\n/**\n * Mentions for a group message: each ref (a member key, a unique prefix of one, a member's name, or `everyone`) must\n * be written in the text as `@<name>` (or `@<key prefix>`, `@everyone`); the first such place is the mention.\n */\nexport function mentionsFor(text: string, refs: readonly string[], group: GroupView): GroupMention[] {\n const out: GroupMention[] = [];\n for (const ref of refs) {\n let key: string, spelled: string[];\n if (ref === \"everyone\" || ref === MENTION_EVERYONE) { key = MENTION_EVERYONE; spelled = [\"everyone\", \"all\"]; }\n else {\n const lower = ref.toLowerCase();\n // A member's key is that member, whatever another member calls itself.\n const byKey = group.members.filter((m) => !m.me && m.key === ref);\n const matches = byKey.length ? byKey : group.members.filter((m) => !m.me && (m.key.startsWith(ref) || m.nick?.trim().toLowerCase() === lower));\n if (matches.length > 1) throw new CliError(\"bad_request\", `${JSON.stringify(ref)} names more than one member`);\n if (!matches.length) throw noMember(group, ref);\n key = matches[0].key;\n spelled = [matches[0].nick?.trim(), ref, key.slice(0, 8)].filter((s): s is string => !!s);\n }\n const found = spelled.map((name) => ({ name, index: text.toLowerCase().indexOf(\"@\" + name.toLowerCase()) })).find((f) => f.index >= 0);\n if (!found) throw new CliError(\"bad_request\", `Write @${spelled[0]} in the text to mention ${ref}`);\n out.push({ k: key, o: codePoints(text, found.index), l: [...\"@\" + found.name].length });\n }\n return out;\n}\n\n/** Per host: stops watching the invite it marked as the chat on screen. */\nconst inviteShown = new WeakMap<ApiContext, () => void>();\n\n/**\n * Marks a new invite as the chat on screen (native listeners, the quick pace) only until it is paired: a paired chat\n * keeps its listeners anyway, and a daemon nobody looks at reads an away contact at the background pace, as its\n * other chats and the same chat after a restart do. Nor past its wait for a peer (`AWAITING_PEER_MS`): an invite\n * nobody joined is then read at the background pace like the daemon's other ones, which it no longer holds back.\n */\nfunction showUntilPaired(ctx: ApiContext, linkId: string): void {\n inviteShown.get(ctx)?.();\n node(ctx).setActiveLink({ linkId });\n // Gone only once a state had it: one pushed before the invite was made does not end it.\n let seen = false;\n const done = (s: EngineState) => {\n const link = s.links.find((l) => l.id === linkId);\n if (link) seen = true;\n return link ? !!link.peerParticipationKey : seen;\n };\n const stop = () => { off(); clearTimeout(timer); if (inviteShown.get(ctx) === stop) inviteShown.delete(ctx); };\n const hide = () => { stop(); node(ctx).setActiveLink({ linkId: null }); };\n const timer = setTimeout(hide, AWAITING_PEER_MS);\n timer.unref?.();\n const off = ctx.hub.onState((s) => { if (done(s)) hide(); });\n inviteShown.set(ctx, stop);\n}\n\n// ---------- methods ----------\n\nconst METHODS: Record<string, Method> = {\n ...WALLET_METHODS,\n ...FILE_METHODS,\n ...STATUS_CARD_METHODS,\n ...BUTTON_METHODS,\n ...GROUP_ADMIN_METHODS,\n ...IDENTITY_METHODS,\n ...SERVICE_METHODS,\n ...BACKUP_METHODS,\n ...CALL_METHODS,\n ...APP_SERVE_METHODS,\n ...APP_CHAT_METHODS,\n\n async status(ctx) {\n const s = state(ctx);\n return {\n version: ctx.version, profile: ctx.runtime.paths.name, mode: ctx.mode, pid: process.pid,\n online: s.settings.online, name: s.settings.nick || null, webrtc: ctx.runtime.webrtc, calls: ctx.runtime.callsUnavailable === null,\n chats: s.links.length, live: s.links.filter(isLive).length, groups: s.groups.length,\n discovery: { protocol: s.transport.protocol, relays: s.transport.relays },\n events: { lastSeq: ctx.hub.lastSeq },\n };\n },\n\n async \"profile.get\"(ctx) {\n const { settings } = state(ctx);\n return { profile: ctx.runtime.paths.name, name: settings.nick || null, shareProfile: settings.shareProfile !== false, picture: !!settings.avatar, online: settings.online };\n },\n async \"profile.set\"(ctx, params) {\n const patch: Partial<Settings> = {};\n const name = params.name;\n if (name !== undefined) {\n if (typeof name !== \"string\" || [...name].length > 64) throw new CliError(\"bad_request\", \"name must be a string of up to 64 characters\");\n patch.nick = name.trim();\n }\n if (params.shareProfile !== undefined) patch.shareProfile = bool(params, \"shareProfile\");\n await node(ctx).updateSettings({ settings: patch });\n return METHODS[\"profile.get\"](ctx, {});\n },\n\n async \"settings.get\"(ctx, params) {\n return redactSettings(state(ctx).settings, bool(params, \"showSecret\"));\n },\n async \"settings.set\"(ctx, params) {\n const patch: Record<string, unknown> = {};\n let warning: string | undefined;\n for (const [key, value] of Object.entries(params)) {\n // The table's own keys only: every object has `constructor` and `toString`, which are no settings.\n const kind = Object.hasOwn(SETTABLE, key) ? SETTABLE[key] : undefined;\n if (!kind) throw new CliError(\"bad_request\", `${key} is not a setting the CLI changes (${Object.keys(SETTABLE).join(\", \")})`);\n if (kind === \"strings\" && !(Array.isArray(value) && value.every((v) => typeof v === \"string\"))) throw new CliError(\"bad_request\", `${key} must be a list of strings`);\n if (kind === \"string\" && typeof value !== \"string\") throw new CliError(\"bad_request\", `${key} must be a string`);\n if (kind === \"boolean\" && typeof value !== \"boolean\") throw new CliError(\"bad_request\", `${key} must be true or false`);\n if (kind === \"ice\") {\n if (!(Array.isArray(value) && value.every((v) => v && typeof v === \"object\"))) throw new CliError(\"bad_request\", `${key} must be a list of ICE servers`);\n // WebRTC's own form (`urls` a list) is taken; a server without urls is said here, not as the engine's TypeError.\n const servers = value.map(iceServerSetting);\n for (const server of servers) { const problem = iceServerProblem(server); if (problem) throw new CliError(\"bad_request\", `${key}: ${problem}`); }\n patch[key] = servers;\n // libdatachannel (libjuice) skips TURN over TCP and TLS without a word; the apps' browsers use them, so they stay.\n const unused = servers.flatMap((server) => server.urls.split(/[\\s,]+/)).filter((url) => /^turns:|\\?transport=tcp$/i.test(url));\n if (unused.length) warning = `The CLI reaches TURN over UDP only: it does not use ${unused.join(\", \")} (the apps do). Add a turn: server over UDP for the CLI`;\n continue;\n }\n patch[key] = value;\n }\n await node(ctx).updateSettings({ settings: patch }).catch((error: unknown) => { throw relayRefused(error, patch); });\n return { ...redactSettings(state(ctx).settings), ...(warning ? { warning } : {}) };\n },\n\n async \"invite.create\"(ctx, params) {\n const label = chatName(params, \"label\");\n const { linkId, inviteCode } = await node(ctx).createLink();\n if (label) await node(ctx).renameLink({ linkId, label });\n // Native listeners start for the chat on screen (or a paired one): a new invite is the chat a bot waits on.\n showUntilPaired(ctx, linkId);\n // Its first records must be out before a one-shot leaves. A daemon publishes them later too: it answers at once when\n // the relays' request budget holds them back (a few invites in a minute), and says when they go.\n const progressOf = (s: EngineState) => s.links.find((l) => l.id === linkId)?.pairingProgress;\n const progress = await waitForState(ctx, (s) => { const p = progressOf(s); return p && (p.stage !== \"publishing\" || (ctx.mode === \"daemon\" && p.relayWaitUntil)) ? p : undefined; }, 20_000, \"the invite to be published\")\n .catch(() => progressOf(state(ctx)));\n const published = !!progress && progress.stage !== \"publishing\" && progress.reason !== \"publish\";\n const waitUntil = published ? undefined : progress?.relayWaitUntil;\n return { chat: linkId, invite: inviteCode, link: inviteLink(inviteCode), published, ...(waitUntil !== undefined && { retryInMs: Math.max(0, waitUntil - Date.now()) }) };\n },\n async \"invite.join\"(ctx, params) {\n let invite = str(params, \"invite\", true).trim();\n const label = chatName(params, \"label\");\n const hash = invite.indexOf(\"#\");\n if (/^https?:\\/\\//i.test(invite) && hash !== -1) invite = invite.slice(hash + 1);\n let linkId: string;\n try {\n ({ linkId } = await node(ctx).joinLink({ inviteCode: invite }));\n } catch (error) {\n // This profile's own invite: the sentence alone, and the chat that owns it as its own field, not the engine's tag\n // for its RPC clients (\"own-invite <chat>: …\").\n const own = ownInviteRefusal(error);\n if (own) throw new CliError(\"refused\", \"This is your own invite. Share it with a contact; they join with it.\", own.linkId ? { chat: own.linkId } : undefined);\n const message = error instanceof Error ? error.message : String(error);\n if (/does not look like/i.test(message)) throw new CliError(\"bad_request\", message);\n throw error;\n }\n if (label) await node(ctx).renameLink({ linkId, label });\n showUntilPaired(ctx, linkId);\n return { chat: linkId };\n },\n\n async \"chat.list\"(ctx, params) {\n const showSecret = bool(params, \"showSecret\");\n return { chats: state(ctx).links.map((link) => chatJson(link, showSecret)).sort((a, b) => b.lastMessageAt - a.lastMessageAt || b.createdAt - a.createdAt) };\n },\n async \"chat.get\"(ctx, params) {\n const link = chatNotGroup(ctx, params, \"group show\");\n return { ...chatDetailsJson(link, bool(params, \"showSecret\")), heldUntil: holdOf(ctx, link.id) };\n },\n async \"chat.history\"(ctx, params) {\n const link = chatNotGroup(ctx, params, \"group history\");\n return historyOf(ctx, link.id, params, (m) => chatMessageJson(m, link));\n },\n async \"chat.send\"(ctx, params) {\n const link = chatNotGroup(ctx, params, \"group send\", \"[text...]\");\n const text = str(params, \"text\", true);\n checkTextSize(text);\n if (!bool(params, \"force\")) {\n const secret = findSecret(text);\n if (secret) throw new CliError(\"confirm\", `The text looks like ${secret.kind === \"cashu\" ? \"a Cashu token (money anyone who reads it can take)\" : \"a secret (a seed or a private key)\"}; send it with --force if you mean to`, { kind: secret.kind });\n }\n const wait = oneOf(params, \"wait\", [\"none\", \"sent\", \"delivered\"] as const, \"none\");\n const replyTo = str(params, \"reply\");\n // Buttons under the text (WISP 406 · Message Buttons): the text is the question, and what older apps show.\n const card = buttonsCard(params);\n // A kept `typing --for` ends with the message (the engine says stop with it).\n endTyping(ctx, { linkId: link.id }, false);\n const result = await node(ctx).sendMessage({ linkId: link.id, text, ...(replyTo ? { replyTo } : {}), ...(card ? { card } : {}) });\n // A `--reply` to a message this chat does not have is not_found (exit 3), as `file send --reply` and `group send` say.\n if (result.error) throw /not in this chat|cannot be replied to/.test(result.error) ? new CliError(\"not_found\", result.error) : new CliError(result.refused ? \"refused\" : \"unavailable\", result.error);\n if (!result.messageId) throw new CliError(\"bad_request\", \"Nothing to send\");\n let message = await node(ctx).getMessage(link.id, result.messageId);\n if (wait !== \"none\") message = await waitForMessage(ctx, link.id, result.messageId, wait, num(params, \"timeout\", 30, { min: 1, max: 3600 }) * 1000);\n return { chat: link.id, messageId: result.messageId, delivery: message?.delivery ?? null, ...(card ? { buttons: card.id, card, pressable: pressable(link) } : {}) };\n },\n /**\n * WISP 400 § Edits: the whole new text of one of my texts in a 1:1 chat. It shows here at once and reaches the contact\n * once the chat is live and both apps offer edit/1; `--wait confirmed` waits for the contact to confirm it.\n */\n async \"chat.edit\"(ctx, params) {\n const link = chatNotGroup(ctx, params, \"group edit\", \"<message> <text...>\");\n const messageId = str(params, \"message\", true);\n const text = str(params, \"text\", true);\n if (!bool(params, \"force\")) {\n const secret = findSecret(text);\n if (secret) throw new CliError(\"confirm\", `The text looks like ${secret.kind === \"cashu\" ? \"a Cashu token (money anyone who reads it can take)\" : \"a secret (a seed or a private key)\"}; edit with --force if you mean to`, { kind: secret.kind });\n }\n const wait = oneOf(params, \"wait\", [\"none\", \"confirmed\"] as const, \"none\");\n const result = await node(ctx).editMessage({ linkId: link.id, messageId, text });\n if (result.error) throw editRefused(await messageOf(ctx, link.id, messageId), messageId, \"chat\", result.error, result.refused);\n const id = result.messageId ?? messageId;\n let message = await node(ctx).getMessage(link.id, id);\n if (wait === \"confirmed\" && message?.edit?.pending) message = await waitForEdit(ctx, link.id, id, num(params, \"timeout\", 30, { min: 1, max: 3600 }) * 1000);\n return { chat: link.id, messageId: id, edits: message?.edit?.seq ?? 0, confirmed: !!message && !message.edit?.pending };\n },\n /**\n * WISP 401 § Typing: said on the live session only, and a start only while `sendTyping` is on; it holds 6 s there.\n * `kind` (typing, recording, thinking) and `status` (a short line, e.g. \"Transcribing your audio…\") say what this\n * side is doing; a new one reaches the contact at once.\n * `for`: kept that many seconds (a one-shot stays that long once the chat is live, and stops when it is not live\n * within `ONE_SHOT_LIVE_GRACE_MS`), until a message to the chat or a stop.\n */\n async \"chat.typing\"(ctx, params) {\n const link = chatNotGroup(ctx, params, \"group typing\");\n const typing = !bool(params, \"stop\");\n const { kind, status } = typingWord(params, typing);\n const word = { ...(kind !== \"typing\" ? { kind } : {}), ...(status ? { status } : {}) };\n const seconds = params.for === undefined ? 0 : num(params, \"for\", 0, { min: 1, max: 600 });\n if (!typing && seconds) throw new CliError(\"bad_request\", \"for keeps typing on: not with stop\");\n endTyping(ctx, { linkId: link.id }, false);\n node(ctx).setTyping({ linkId: link.id, typing, ...word });\n const until = seconds ? Date.now() + seconds * 1000 : null;\n const kept = seconds ? keepTyping(ctx, { linkId: link.id }, seconds * 1000, word) : null;\n const open = (s: EngineState) => s.links.find((l) => l.id === link.id)?.dataLink === \"open\";\n if (kept && ctx.mode === \"one-shot\") await keepOneShot(ctx, { linkId: link.id }, kept, open);\n return {\n chat: link.id, typing, ...(typing ? { kind } : {}), ...(status ? { status } : {}),\n live: open(state(ctx)), sendTyping: state(ctx).settings.sendTyping !== false, ...(until ? { until } : {}),\n };\n },\n /** WISP 400 § Reactions: one emoji per person per message, a new one replaces mine; `remove` takes mine back. */\n async \"chat.react\"(ctx, params) {\n const link = chatNotGroup(ctx, params, \"group react\", \"<message> <emoji>\");\n return { chat: link.id, ...(await react(ctx, link.id, params)) };\n },\n /**\n * WISP 400 § Pinned message: one per chat or group, a new pin replaces it; `remove` unpins. In a community only the\n * admin pins. Answers the chat (or group) and the message now pinned (null once unpinned).\n */\n async \"chat.pin\"(ctx, params) {\n const target = chatOrGroup(ctx, str(params, \"chat\", true));\n const remove = bool(params, \"remove\"), messageId = remove ? str(params, \"message\") : str(params, \"message\", true);\n const result = await node(ctx).pinMessage({ linkId: target.linkId, ...(messageId && { messageId }), remove });\n if (result.error) throw new CliError(/not in this chat|Nothing is pinned/.test(result.error) ? \"not_found\" : /Only the admin/.test(result.error) ? \"refused\" : \"bad_request\", result.error);\n return { [target.group ? \"group\" : \"chat\"]: target.id, messageId: remove ? null : messageId, removed: remove };\n },\n /**\n * WISP 400 § Forwards: messages of a chat or a group sent on to up to 5 chats and groups, each as a new message of mine\n * that says it was forwarded (one hop more) and nothing of who wrote it. A file goes from the bytes here, never\n * fetched again; a group takes texts only. `wait: sent`: each text until it is on its way (a group's until an edge\n * took it), each file until its transfer is done. What a chat refused comes back per chat; any refusal fails the call.\n */\n async \"chat.forward\"(ctx, params) {\n const from = chatOrGroup(ctx, str(params, \"chat\", true));\n const messageIds = list(params, \"messages\");\n if (!messageIds.length) throw new CliError(\"bad_request\", \"Name the messages to forward (their ids, from history or an event)\");\n const to = list(params, \"to\").map((ref) => chatOrGroup(ctx, ref));\n if (!to.length) throw new CliError(\"bad_request\", \"Forward to which chat? Name one or more with --to\");\n // Each by its id here, one row each: never the whole history of the chat or group.\n const chosen: StoredMessage[] = [];\n for (const id of messageIds) {\n const message = await node(ctx).getMessage(from.linkId, id);\n if (!message) throw new CliError(\"not_found\", `No message ${id} in this ${from.group ? \"group\" : \"chat\"}`);\n chosen.push(message);\n }\n if (!bool(params, \"force\")) for (const message of chosen) {\n const secret = message.file ? null : findSecret(message.text);\n if (secret) throw new CliError(\"confirm\", `A message looks like ${secret.kind === \"cashu\" ? \"a Cashu token (money anyone who reads it can take)\" : \"a secret (a seed or a private key)\"}; forward it with --force if you mean to`, { kind: secret.kind, messageId: message.id });\n }\n const wait = oneOf(params, \"wait\", [\"none\", \"sent\"] as const, \"none\");\n let results;\n try { ({ results } = await node(ctx).forwardMessages({ linkId: from.linkId, messageIds, to: to.map((t) => t.linkId) })); }\n catch (error) { throw new CliError(\"refused\", error instanceof Error ? error.message : String(error)); }\n const ms = num(params, \"timeout\", 30, { min: 1, max: 3600 }) * 1000;\n const out = results.map((result, i) => ({ to: to[i]!.id, kind: to[i]!.group ? \"group\" as const : \"chat\" as const, messageIds: result.messageIds, error: result.error }));\n if (wait === \"sent\") for (const [i, result] of out.entries()) for (const messageId of result.messageIds) {\n if (to[i]!.group) { await waitForGroupFrame(ctx, to[i]!.id, messageId, undefined, ms); continue; }\n const sent = await node(ctx).getMessage(to[i]!.id, messageId);\n if (sent?.file) await FILE_METHODS[\"file.wait\"](ctx, { chat: to[i]!.id, file: sent.file.id, timeout: ms / 1000 });\n else await waitForMessage(ctx, to[i]!.id, messageId, \"sent\", ms);\n }\n const failed = out.filter((r) => r.error);\n if (failed.length) throw new CliError(failed.length === out.length ? \"refused\" : \"engine\", failed.map((r) => `${r.to}: ${r.error}`).join(\"; \"), { from: from.id, results: out });\n return { from: from.id, results: out };\n },\n async \"chat.retry\"(ctx, params) {\n const link = chatOf(ctx, params);\n const messageId = str(params, \"message\", true);\n const message = await node(ctx).getMessage(link.id, messageId);\n if (!message) throw new CliError(\"not_found\", `No message ${messageId} in this chat`);\n // Before, both answered done and nothing was sent: the engine sends again whatever id it is given.\n if (message.sender !== \"me\") throw new CliError(\"not_found\", `No message ${messageId} of yours in this chat: only your own messages are sent again`);\n if (message.delivery === \"delivered\") throw new CliError(\"refused\", \"Nothing to send again: it was delivered\");\n await node(ctx).retryMessage({ linkId: link.id, messageId });\n return { chat: link.id, messageId };\n },\n async \"chat.delete\"(ctx, params) {\n const link = chatOf(ctx, params);\n const messageId = str(params, \"message\", true);\n if (!(await node(ctx).getMessage(link.id, messageId))) throw new CliError(\"not_found\", `No message ${messageId} in this chat`);\n await node(ctx).deleteMessage({ linkId: link.id, messageId });\n return { chat: link.id, deleted: messageId };\n },\n async \"chat.details\"(ctx, params) {\n const link = chatOf(ctx, params);\n const details = await node(ctx).messageDetails({ linkId: link.id, messageId: str(params, \"message\", true) });\n if (!details) throw new CliError(\"not_found\", `No message ${String(params.message)} in this chat`);\n return details;\n },\n async \"chat.rename\"(ctx, params) {\n const link = chatNotGroup(ctx, params, \"group rename\", \"<name...>\");\n await node(ctx).renameLink({ linkId: link.id, label: chatName(params, \"name\") ?? \"\" });\n return chatJson(findChat(state(ctx).links, link.id));\n },\n async \"chat.remove\"(ctx, params) {\n const link = chatNotGroup(ctx, params, \"group forget\", \"--yes\");\n if (!bool(params, \"yes\")) throw new CliError(\"confirm\", \"Removing a chat deletes its keys and history on this device; pass yes (--yes) to go on\");\n await node(ctx).removeLink({ linkId: link.id });\n return { removed: link.id };\n },\n async \"chat.transport\"(ctx, params) {\n const link = chatOf(ctx, params);\n const name = str(params, \"transport\", true);\n const transport = Object.hasOwn(TRANSPORT_NAMES, name) ? TRANSPORT_NAMES[name] : undefined;\n if (!transport) throw new CliError(\"bad_request\", `transport must be one of auto, dht, webrtc, iroh, hyperdht`);\n await node(ctx).setChatTransport({ linkId: link.id, transport });\n return chatDetailsJson(findChat(state(ctx).links, link.id));\n },\n /** Reconnects now; a chat held off its direct link (`chat disconnect --hold`) leaves the hold first. */\n async \"chat.connect\"(ctx, params) {\n const link = chatOf(ctx, params);\n await releaseHold(ctx, link.id, \"connect\");\n inviteTaken(link);\n await node(ctx).connect({ linkId: link.id });\n return chatJson(findChat(state(ctx).links, link.id));\n },\n /**\n * Closes the live session; the contact's app may dial again at once. `hold` (minutes): the chat stays off its\n * direct link that long, on the DHT (its \"DHT only\" choice, taken back after); 0 ends a hold now.\n */\n async \"chat.disconnect\"(ctx, params) {\n const link = chatOf(ctx, params);\n if (params.hold === undefined) {\n node(ctx).disconnect({ linkId: link.id });\n return chatJson(findChat(state(ctx).links, link.id));\n }\n const minutes = num(params, \"hold\", 0, { min: 0, max: HOLD_MAX_MINUTES });\n if (minutes === 0) await releaseHold(ctx, link.id, \"lifted\");\n else await holdChat(ctx, link, minutes);\n return { ...chatJson(findChat(state(ctx).links, link.id)), heldUntil: holdOf(ctx, link.id) };\n },\n async \"chat.verify\"(ctx, params) {\n const link = chatOf(ctx, params);\n const code = str(params, \"code\", true).replace(/\\s+/g, \"\").toLowerCase();\n const mine = link.pairing?.code?.replace(/\\s+/g, \"\").toLowerCase();\n if (!mine) throw new CliError(\"unavailable\", \"This chat shows no comparison code yet (it needs a live session)\");\n if (code !== mine) throw new CliError(\"refused\", \"The code does not match the one this side shows: do not trust this chat until you know why\");\n await node(ctx).confirmPair({ linkId: link.id, code: link.pairing!.code! });\n return chatJson(findChat(state(ctx).links, link.id));\n },\n async \"chat.wait\"(ctx, params) {\n const link = chatOf(ctx, params);\n const until = oneOf(params, \"until\", [\"live\", \"text\", \"paired\"] as const, \"live\");\n const ms = num(params, \"timeout\", 60, { min: 1, max: 86_400 }) * 1000;\n const view = await waitForState(ctx, (s) => {\n const now = s.links.find((l) => l.id === link.id);\n if (!now) throw new CliError(\"not_found\", `Chat ${link.id} was removed`);\n // Live: a session that exists now, never one remembered from the last run (`isLive`).\n const ok = until === \"live\" ? isLive(now)\n : until === \"text\" ? now.textDelivery === \"stream\" || now.textDelivery === \"dht\" || now.textDelivery === \"hold\"\n : !!now.pairingProgress?.peerSeen || now.pairing?.status === \"ready\" || isLive(now);\n return ok ? now : undefined;\n }, ms, `chat ${link.id} to be ${until}`);\n return chatJson(view);\n },\n\n async \"group.create\"(ctx, params) {\n // As `group rename` checks it: a name a group cannot have is said here, before anything is made.\n const name = groupName(str(params, \"name\", true));\n if (!name) throw new CliError(\"bad_request\", `A group's name is 1 to ${MAX_GROUP_NAME_LENGTH} characters on one line`);\n const profile = oneOf(params, \"profile\", [\"community\", \"mesh\"] as const, \"community\");\n const { groupId } = await node(ctx).createGroup({ name, profile });\n let link: string | null = null;\n if (profile === \"community\") ({ link } = await node(ctx).enableGroupLink({ groupId }));\n return { group: groupId, link };\n },\n async \"group.join\"(ctx, params) {\n let groupId: string;\n try {\n ({ groupId } = await node(ctx).joinGroupByLink({ link: str(params, \"link\", true) }));\n } catch (error) {\n // Not a link to a group at all: the caller's input, as `invite join` answers a word that is no invite.\n if (error instanceof Error && error.message === \"This is not a link to a group\") throw new CliError(\"bad_request\", error.message);\n throw error;\n }\n return { group: groupId };\n },\n async \"group.list\"(ctx, params) {\n const showSecret = bool(params, \"showSecret\");\n return { groups: state(ctx).groups.map((g) => groupJson(g, showSecret)).sort((a, b) => b.lastMessageAt - a.lastMessageAt) };\n },\n async \"group.get\"(ctx, params) {\n return groupJson(groupOf(ctx, params), bool(params, \"showSecret\"));\n },\n async \"group.history\"(ctx, params) {\n const group = groupOf(ctx, params);\n return historyOf(ctx, `group:${group.id}`, params, (m) => groupMessageJson(m, group));\n },\n async \"group.send\"(ctx, params) {\n const group = groupOf(ctx, params);\n const text = str(params, \"text\", true);\n checkTextSize(text);\n if (!bool(params, \"force\")) {\n const secret = findSecret(text);\n if (secret) throw new CliError(\"confirm\", \"The text looks like a secret or a Cashu token; send it with --force if you mean to\", { kind: secret.kind });\n }\n const mentions = mentionsFor(text, list(params, \"mentions\"), group);\n const replyTo = str(params, \"reply\");\n const wait = oneOf(params, \"wait\", [\"none\", \"sent\"] as const, \"none\");\n const card = buttonsCard(params);\n // A kept `group typing --for` ends with the message (the engine says stop with it).\n endTyping(ctx, { groupId: group.id }, false);\n const result = await node(ctx).sendGroupMessage({ groupId: group.id, text, ...(mentions.length ? { mentions } : {}), ...(replyTo ? { replyTo } : {}), ...(card ? { card } : {}) });\n // Not a member (removed, say): refused, and nothing was sent. Anything else by what a bot can do about it.\n if (result.error) throw result.refused ? new CliError(\"refused\", result.error) : groupSendRefused(result.error);\n const messageId = result.messageId ?? null;\n // `edges`: how many took it so far (none yet is not an error: it goes when one opens). `sent`: whether one did.\n // Before 2026-10-02 `sent` was always true, also for a message no edge had taken.\n const edges = messageId ? (wait === \"sent\" ? await waitForGroupFrame(ctx, group.id, messageId, undefined, num(params, \"timeout\", 30, { min: 1, max: 3600 }) * 1000) : node(ctx).groupTaken({ groupId: group.id, messageId })) : 0;\n return { group: group.id, messageId, sent: edges > 0, edges, ...(card ? { buttons: card.id, card } : {}) };\n },\n /**\n * WISP 902 § Edits: the whole new text of one of my messages in a group. It shows here at once and goes to the members\n * (a private group's over the edges that are up, the others when theirs open; a community's through the group).\n * `mentions`: members the new text names beyond those the message named. `sent`: no longer waiting for the pace.\n */\n async \"group.edit\"(ctx, params) {\n const group = groupOf(ctx, params);\n const messageId = str(params, \"message\", true);\n const text = str(params, \"text\", true);\n if (!bool(params, \"force\")) {\n const secret = findSecret(text);\n if (secret) throw new CliError(\"confirm\", `The text looks like ${secret.kind === \"cashu\" ? \"a Cashu token (money anyone who reads it can take)\" : \"a secret (a seed or a private key)\"}; edit with --force if you mean to`, { kind: secret.kind });\n }\n const mentions = mentionsFor(text, list(params, \"mentions\"), group);\n const wait = oneOf(params, \"wait\", [\"none\", \"sent\"] as const, \"none\");\n const linkId = `group:${group.id}`;\n const before = (await node(ctx).getMessage(linkId, messageId))?.edit?.seq ?? 0;\n const result = await node(ctx).editMessage({ linkId, messageId, text, ...(mentions.length ? { mentions } : {}) });\n if (result.error) throw editRefused(await messageOf(ctx, linkId, messageId), messageId, \"group\", result.error, result.refused);\n const message = await node(ctx).getMessage(linkId, messageId);\n const edits = message?.edit?.seq ?? 0;\n // The text the message already has: no edit was made and nothing went. It answered `sent: true` before, for a\n // message never edited, as if an edit had gone.\n if (edits === before) return { group: group.id, messageId, edits, sent: false, edges: 0, unchanged: true };\n // An edit waiting for the pace is not said yet: `--wait sent` waits for that too, then for an edge to take it.\n const edges = !edits ? 0 : wait === \"sent\" ? await waitForGroupFrame(ctx, group.id, messageId, edits, num(params, \"timeout\", 30, { min: 1, max: 3600 }) * 1000)\n : node(ctx).groupTaken({ groupId: group.id, messageId, edit: edits });\n return { group: group.id, messageId, edits, sent: edges > 0 || (!!message && !message.edit?.pending), edges };\n },\n async \"group.react\"(ctx, params) {\n const group = groupOf(ctx, params);\n return { group: group.id, ...(await react(ctx, `group:${group.id}`, params)) };\n },\n /**\n * WISP 902 · Group Mesh § Typing: `chat.typing` in a private group, said on the edges that are open (`reached`: to\n * how many members), with the same kinds, status rules, 6 s hold and `for`. A community does not carry typing yet.\n */\n async \"group.typing\"(ctx, params) {\n const group = groupOf(ctx, params);\n if (group.profile !== \"mesh\") throw new CliError(\"unavailable\", \"A community does not carry typing yet: only a private group does\");\n const typing = !bool(params, \"stop\");\n const { kind, status } = typingWord(params, typing);\n const word = { ...(kind !== \"typing\" ? { kind } : {}), ...(status ? { status } : {}) };\n const seconds = params.for === undefined ? 0 : num(params, \"for\", 0, { min: 1, max: 600 });\n if (!typing && seconds) throw new CliError(\"bad_request\", \"for keeps typing on: not with stop\");\n if (typing && group.status !== \"active\") throw new CliError(\"bad_request\", \"You are not in this group\");\n const target = { groupId: group.id };\n endTyping(ctx, target, false);\n sayTyping(ctx, target, typing, word);\n const until = seconds ? Date.now() + seconds * 1000 : null;\n const kept = seconds ? keepTyping(ctx, target, seconds * 1000, word) : null;\n const reached = (s: EngineState) => (s.groups.find((g) => g.id === group.id) ?? group).members.filter((m) => !m.me && m.online && !m.viaHub).length;\n if (kept && ctx.mode === \"one-shot\") await keepOneShot(ctx, target, kept, (s) => reached(s) > 0);\n return {\n group: group.id, typing, ...(typing ? { kind } : {}), ...(status ? { status } : {}),\n reached: reached(state(ctx)), sendTyping: state(ctx).settings.sendTyping !== false, ...(until ? { until } : {}),\n };\n },\n async \"group.leave\"(ctx, params) {\n const group = groupOf(ctx, params);\n if (!bool(params, \"yes\")) throw new CliError(\"confirm\", \"Leaving a group deletes its history and files on this device; pass yes (--yes) to go on\");\n const { admin } = await node(ctx).leaveGroup({ groupId: group.id });\n // The member who became the admin, named from the roster read before leaving: the group is gone from the state now.\n const next = admin ? group.members.find((m) => m.key === admin) : undefined;\n return { left: group.id, ...(admin ? { admin: { key: admin, name: next?.nick ?? null } } : {}) };\n },\n async \"group.forget\"(ctx, params) {\n const group = groupOf(ctx, params);\n if (!bool(params, \"yes\")) throw new CliError(\"confirm\", \"Forgetting a group deletes its history on this device; pass yes (--yes) to go on\");\n await node(ctx).forgetGroup({ groupId: group.id });\n return { forgotten: group.id };\n },\n async \"group.accept\"(ctx, params) {\n const group = groupOf(ctx, params);\n await node(ctx).acceptGroupInvitation({ groupId: group.id });\n return { group: group.id };\n },\n async \"group.decline\"(ctx, params) {\n const group = groupOf(ctx, params);\n await node(ctx).declineGroupInvitation({ groupId: group.id });\n return { group: group.id };\n },\n\n async \"events.replay\"(ctx, params) {\n return { events: ctx.hub.replay(num(params, \"since\", 0)), lastSeq: ctx.hub.lastSeq };\n },\n\n async \"daemon.stop\"(ctx) {\n if (ctx.mode !== \"daemon\" || !ctx.stop) throw new CliError(\"unavailable\", \"No daemon runs this profile\");\n setTimeout(() => ctx.stop!(), 10);\n return { stopping: true, pid: process.pid };\n },\n\n async \"engine.call\"(ctx, params) {\n const method = str(params, \"method\", true);\n if (!ENGINE_METHODS.includes(method) && !ENGINE_READS.includes(method)) throw new CliError(\"not_found\", `The engine has no call ${method}`);\n const raw = params.params;\n if (raw !== undefined && (raw === null || typeof raw !== \"object\" || Array.isArray(raw))) throw new CliError(\"bad_request\", \"params must be an object\");\n let args = raw as Params | undefined;\n // Real money moves only on an explicit confirmation of this call (WISP 1100 § Mainnet).\n if (args && \"confirmedReal\" in args && !bool(params, \"confirmReal\")) {\n throw new CliError(\"confirm\", `${method} spends real money: pass --confirm-real (confirmReal: true over the socket) to confirm it`);\n }\n if (args && ENGINE_SENDS.has(method) && !bool(params, \"force\")) await guardEngineSend(ctx, method, args);\n if (method === \"getMessages\") return node(ctx).getMessages(str(args ?? {}, \"linkId\", true));\n if (method === \"getState\") return state(ctx);\n // Someone chose the chat on screen: an invite's mark no longer clears it.\n if (method === \"setActiveLink\") inviteShown.get(ctx)?.();\n const target = (node(ctx) as unknown as Record<string, (p?: unknown) => unknown>)[method];\n if (typeof target !== \"function\") throw new CliError(\"not_found\", `The engine has no call ${method}`);\n if (args === undefined) args = undefined;\n return (await target.call(node(ctx), args)) ?? null;\n },\n};\n\n/**\n * The engine's calls that send a text this side writes: `engine.call` runs the secret guard of `send`, `edit` and\n * `forward` on them too (docs/CLI.md § Safety), so a raw call is no way around it. `force: true` (`--force`) sends it.\n */\nconst ENGINE_SENDS: ReadonlySet<string> = new Set([\"sendMessage\", \"sendGroupMessage\", \"editMessage\", \"forwardMessages\"]);\n\nasync function guardEngineSend(ctx: ApiContext, method: string, args: Params): Promise<void> {\n let texts: unknown = [args.text, args.card];\n if (method === \"forwardMessages\") {\n const ids = Array.isArray(args.messageIds) ? args.messageIds.filter((id): id is string => typeof id === \"string\") : [];\n const linkId = args.linkId;\n texts = typeof linkId === \"string\" && linkId ? await Promise.all(ids.map(async (id) => {\n const message = await node(ctx).getMessage(linkId, id);\n return message && !message.file ? message.text : null;\n })) : [];\n }\n const secret = secretIn(texts);\n if (secret) throw new CliError(\"confirm\", `The text looks like ${secret.kind === \"cashu\" ? \"a Cashu token (money anyone who reads it can take)\" : \"a secret (a seed or a private key)\"}; call ${method} with --force if you mean to`, { kind: secret.kind });\n}\n\n/** Reacts to a message of a chat or a group (`group:<id>`): `emoji`, or `remove` for \"\" (WISP 400 § Reactions). */\nasync function react(ctx: ApiContext, linkId: string, params: Params): Promise<{ messageId: string; emoji: string | null; removed: boolean }> {\n const messageId = str(params, \"message\", true);\n const removed = bool(params, \"remove\");\n const emoji = removed ? \"\" : str(params, \"emoji\");\n if (!removed && !emoji) throw new CliError(\"usage\", \"Give one emoji, or --remove to take yours back\");\n const result = await node(ctx).react({ linkId, messageId, emoji: emoji ?? \"\" });\n if (result.error) throw new CliError(result.refused ? \"refused\" : /not in this chat|No reaction of yours/.test(result.error) ? \"not_found\" : \"bad_request\", result.error);\n return { messageId, emoji: emoji || null, removed };\n}\n\n/**\n * What `typing` says: a kind, and a status a bot writes. The contact's app would cut a long status and drop one with\n * a link; here that is an error instead, so the bot learns what the contact will (not) see.\n */\nfunction typingWord(params: Params, typing: boolean): { kind: TypingKind; status?: string } {\n const kind = oneOf(params, \"kind\", TYPING_KINDS, \"typing\");\n const raw = str(params, \"status\");\n if (!typing && (params.kind !== undefined || raw !== undefined)) throw new CliError(\"bad_request\", \"kind and status go with a start, not with stop\");\n if (raw === undefined) return { kind };\n const oneLine = raw.replace(/\\s+/g, \" \").trim();\n if ([...oneLine].length > TYPING_STATUS_MAX) throw new CliError(\"bad_request\", `status: at most ${TYPING_STATUS_MAX} characters`);\n const status = sanitizeTypingStatus(oneLine);\n if (!status) throw new CliError(\"bad_request\", \"status: plain text, with no link or markup\");\n return { kind, status };\n}\n\n/**\n * A group message the engine did not send, by what a bot can do about it: a `--reply` to a message this group does not\n * have is `not_found` (exit 3), as `group react`, `group edit` and `pin` answer for one; out of the group (removed,\n * left, a forked history) is `refused`: it will not go later either. Anything else may go on a later try\n * (`unavailable`): the epoch's key is still on its way. All three were `unavailable` (exit 1) before.\n */\nexport function groupSendRefused(error: string): CliError {\n if (/not in this chat|cannot be replied to/.test(error)) return new CliError(\"not_found\", error);\n if (/^You (were removed from|left|are no longer in) this group$|Membership changes are halted/.test(error)) return new CliError(\"refused\", error);\n return new CliError(\"unavailable\", error);\n}\n\n/**\n * A chat command given a group's id, prefix or name: `not_found` that says it is a group, with the group command that\n * takes it (`react` on a group, where `group react` is meant). A name no chat and no group has stays the chat's error.\n */\nfunction notAGroup<T>(ctx: ApiContext, params: Params, chat: () => T, command: string, rest: string): T {\n try { return chat(); } catch (error) {\n if (!(error instanceof CliError) || error.code !== \"not_found\") throw error;\n const ref = str(params, \"chat\", true);\n let group: GroupView;\n try { group = findGroup(state(ctx).groups, ref); } catch { throw error; }\n const shown = /^[\\w.:-]+$/.test(ref) ? ref : JSON.stringify(ref);\n throw new CliError(\"not_found\", `${JSON.stringify(ref)} is a group, not a chat: ghostly ${command} ${shown}${rest ? ` ${rest}` : \"\"}`, { group: group.id });\n }\n}\n\n/** The chat a chat command with a group twin names: a group's name says so, with `command`, the twin (see `notAGroup`). */\nfunction chatNotGroup(ctx: ApiContext, params: Params, command: string, rest = \"\") {\n return notAGroup(ctx, params, () => chatOf(ctx, params), command, rest);\n}\n\n/**\n * An edit the engine refused. A message that is not in the chat or group at all is `not_found` (exit 3), naming the id\n * to give, as `button update` and `task update` do; before, a mistyped or lost id read \"Only your own text messages\n * can be edited\" (`refused`, exit 1), as if the message were someone else's.\n */\nfunction editRefused(message: StoredMessage | undefined, ref: string, where: \"chat\" | \"group\", error: string, refused: boolean | undefined): CliError {\n if (refused && !message)\n return new CliError(\"not_found\", `No message ${JSON.stringify(ref)} in this ${where}: give the messageId ${where === \"group\" ? \"group send\" : \"send\"} printed`);\n return new CliError(refused ? \"refused\" : \"unavailable\", error);\n}\n\n/**\n * A page of a chat's or a group's history. Without `after` only that page is read from the store (the newest, or those\n * before `before`), so a long chat's is as quick as a short one's; with `after` the whole history is read and cut.\n */\nasync function historyOf(ctx: ApiContext, chat: string, params: Params, json: (message: StoredMessage) => MessageJson = messageJson) {\n if (params.after !== undefined && params.after !== null) return history(await node(ctx).getMessages(chat), params, json);\n const limit = num(params, \"limit\", 50, { min: 1, max: 10_000, whole: true });\n const before = params.before ?? undefined;\n if (before !== undefined && typeof before !== \"number\" && typeof before !== \"string\") throw new CliError(\"bad_request\", \"before must be a timestamp or a message id\");\n const page = await node(ctx).messagePage({ linkId: chat, limit, before }).catch((error: unknown) => {\n throw error instanceof Error && error.message === `No message ${before}` ? new CliError(\"not_found\", error.message) : error;\n });\n return { messages: page.messages.map((m) => json(m)), more: page.more };\n}\n\nfunction history(messages: StoredMessage[], params: Params, json: (message: StoredMessage) => MessageJson = messageJson) {\n const limit = num(params, \"limit\", 50, { min: 1, max: 10_000, whole: true });\n const before = params.before;\n const after = params.after;\n let list = messages.slice().sort((a, b) => a.timestamp - b.timestamp);\n const cut = (value: unknown, side: \"before\" | \"after\") => {\n if (value === undefined || value === null) return;\n if (typeof value === \"number\") { list = list.filter((m) => (side === \"before\" ? m.timestamp < value : m.timestamp > value)); return; }\n if (typeof value !== \"string\") throw new CliError(\"bad_request\", `${side} must be a timestamp or a message id`);\n const index = list.findIndex((m) => m.id === value);\n if (index === -1) throw new CliError(\"not_found\", `No message ${value}`);\n list = side === \"before\" ? list.slice(0, index) : list.slice(index + 1);\n };\n cut(before, \"before\");\n cut(after, \"after\");\n const more = after !== undefined && after !== null ? list.length > limit : list.length > limit;\n const page = after !== undefined && after !== null ? list.slice(0, limit) : list.slice(-limit);\n return { messages: page.map((m) => json(m)), more };\n}\n\nexport { findChat, findGroup } from \"./apiKit\";\nexport type { ApiContext } from \"./apiKit\";\nexport const API_METHODS: readonly string[] = Object.keys(METHODS);\n\n/** Runs one method of the API: one the table lists itself (`constructor`, which every object has, is none). */\nexport async function callApi(ctx: ApiContext, method: string, params: unknown = {}): Promise<unknown> {\n const run = Object.hasOwn(METHODS, method) ? METHODS[method] : undefined;\n if (!run) throw new CliError(\"not_found\", `No method ${method}`);\n if (params === null || typeof params !== \"object\" || Array.isArray(params)) throw new CliError(\"bad_request\", \"params must be an object\");\n return run(ctx, await withStoredIds(ctx, params as Params));\n}\n"],"mappings":"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"}