@cello-protocol/daemon 0.0.3 → 0.0.4

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 (153) hide show
  1. package/dist/agent-loader.d.ts +41 -0
  2. package/dist/agent-loader.d.ts.map +1 -0
  3. package/dist/agent-loader.js +94 -0
  4. package/dist/agent-loader.js.map +1 -0
  5. package/dist/bin/cello-daemon.d.ts +13 -0
  6. package/dist/bin/cello-daemon.d.ts.map +1 -0
  7. package/dist/bin/cello-daemon.js +170 -0
  8. package/dist/bin/cello-daemon.js.map +1 -0
  9. package/dist/cello-node-transport-dialer.d.ts +59 -0
  10. package/dist/cello-node-transport-dialer.d.ts.map +1 -0
  11. package/dist/cello-node-transport-dialer.js +108 -0
  12. package/dist/cello-node-transport-dialer.js.map +1 -0
  13. package/dist/challenge-verifier.d.ts +12 -0
  14. package/dist/challenge-verifier.d.ts.map +1 -0
  15. package/dist/challenge-verifier.js +11 -0
  16. package/dist/challenge-verifier.js.map +1 -0
  17. package/dist/connect-or-start.d.ts +25 -0
  18. package/dist/connect-or-start.d.ts.map +1 -0
  19. package/dist/connect-or-start.js +117 -0
  20. package/dist/connect-or-start.js.map +1 -0
  21. package/dist/content-park-client.d.ts +49 -0
  22. package/dist/content-park-client.d.ts.map +1 -0
  23. package/dist/content-park-client.js +196 -0
  24. package/dist/content-park-client.js.map +1 -0
  25. package/dist/daemon.d.ts +65 -0
  26. package/dist/daemon.d.ts.map +1 -0
  27. package/dist/daemon.js +3202 -0
  28. package/dist/daemon.js.map +1 -0
  29. package/dist/directory-bootstrap.d.ts +55 -0
  30. package/dist/directory-bootstrap.d.ts.map +1 -0
  31. package/dist/directory-bootstrap.js +102 -0
  32. package/dist/directory-bootstrap.js.map +1 -0
  33. package/dist/file-manifest-provider.d.ts +18 -0
  34. package/dist/file-manifest-provider.d.ts.map +1 -0
  35. package/dist/file-manifest-provider.js +72 -0
  36. package/dist/file-manifest-provider.js.map +1 -0
  37. package/dist/index.d.ts +18 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +18 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/ipc-client.d.ts +31 -0
  42. package/dist/ipc-client.d.ts.map +1 -0
  43. package/dist/ipc-client.js +112 -0
  44. package/dist/ipc-client.js.map +1 -0
  45. package/dist/ipc-server.d.ts +49 -0
  46. package/dist/ipc-server.d.ts.map +1 -0
  47. package/dist/ipc-server.js +268 -0
  48. package/dist/ipc-server.js.map +1 -0
  49. package/dist/lock-file.d.ts +27 -0
  50. package/dist/lock-file.d.ts.map +1 -0
  51. package/dist/lock-file.js +84 -0
  52. package/dist/lock-file.js.map +1 -0
  53. package/dist/manifest-loader.d.ts +33 -0
  54. package/dist/manifest-loader.d.ts.map +1 -0
  55. package/dist/manifest-loader.js +70 -0
  56. package/dist/manifest-loader.js.map +1 -0
  57. package/dist/manifest-poll-scheduler.d.ts +31 -0
  58. package/dist/manifest-poll-scheduler.d.ts.map +1 -0
  59. package/dist/manifest-poll-scheduler.js +59 -0
  60. package/dist/manifest-poll-scheduler.js.map +1 -0
  61. package/dist/manifest-version-store-file.d.ts +18 -0
  62. package/dist/manifest-version-store-file.d.ts.map +1 -0
  63. package/dist/manifest-version-store-file.js +40 -0
  64. package/dist/manifest-version-store-file.js.map +1 -0
  65. package/dist/manifest-version-store.d.ts +14 -0
  66. package/dist/manifest-version-store.d.ts.map +1 -0
  67. package/dist/manifest-version-store.js +13 -0
  68. package/dist/manifest-version-store.js.map +1 -0
  69. package/dist/network-directory-node.d.ts +94 -0
  70. package/dist/network-directory-node.d.ts.map +1 -0
  71. package/dist/network-directory-node.js +626 -0
  72. package/dist/network-directory-node.js.map +1 -0
  73. package/dist/nonce-dedup.d.ts +68 -0
  74. package/dist/nonce-dedup.d.ts.map +1 -0
  75. package/dist/nonce-dedup.js +204 -0
  76. package/dist/nonce-dedup.js.map +1 -0
  77. package/dist/notification-dispatcher.d.ts +65 -0
  78. package/dist/notification-dispatcher.d.ts.map +1 -0
  79. package/dist/notification-dispatcher.js +138 -0
  80. package/dist/notification-dispatcher.js.map +1 -0
  81. package/dist/registration-context.d.ts +69 -0
  82. package/dist/registration-context.d.ts.map +1 -0
  83. package/dist/registration-context.js +118 -0
  84. package/dist/registration-context.js.map +1 -0
  85. package/dist/registration-manager.d.ts +72 -0
  86. package/dist/registration-manager.d.ts.map +1 -0
  87. package/dist/registration-manager.js +267 -0
  88. package/dist/registration-manager.js.map +1 -0
  89. package/dist/registration-persistence.d.ts +131 -0
  90. package/dist/registration-persistence.d.ts.map +1 -0
  91. package/dist/registration-persistence.js +233 -0
  92. package/dist/registration-persistence.js.map +1 -0
  93. package/dist/retry-queue.d.ts +144 -0
  94. package/dist/retry-queue.d.ts.map +1 -0
  95. package/dist/retry-queue.js +444 -0
  96. package/dist/retry-queue.js.map +1 -0
  97. package/dist/seal-frontier-verify.d.ts +58 -0
  98. package/dist/seal-frontier-verify.d.ts.map +1 -0
  99. package/dist/seal-frontier-verify.js +87 -0
  100. package/dist/seal-frontier-verify.js.map +1 -0
  101. package/dist/seal-legibility-tbs.d.ts +25 -0
  102. package/dist/seal-legibility-tbs.d.ts.map +1 -0
  103. package/dist/seal-legibility-tbs.js +78 -0
  104. package/dist/seal-legibility-tbs.js.map +1 -0
  105. package/dist/seal-upgrade.d.ts +90 -0
  106. package/dist/seal-upgrade.d.ts.map +1 -0
  107. package/dist/seal-upgrade.js +178 -0
  108. package/dist/seal-upgrade.js.map +1 -0
  109. package/dist/session-assignment-parser.d.ts +22 -0
  110. package/dist/session-assignment-parser.d.ts.map +1 -0
  111. package/dist/session-assignment-parser.js +139 -0
  112. package/dist/session-assignment-parser.js.map +1 -0
  113. package/dist/session-ceremony.d.ts +156 -0
  114. package/dist/session-ceremony.d.ts.map +1 -0
  115. package/dist/session-ceremony.js +447 -0
  116. package/dist/session-ceremony.js.map +1 -0
  117. package/dist/session-connection-gater.d.ts +91 -0
  118. package/dist/session-connection-gater.d.ts.map +1 -0
  119. package/dist/session-connection-gater.js +146 -0
  120. package/dist/session-connection-gater.js.map +1 -0
  121. package/dist/session-node-manager.d.ts +585 -0
  122. package/dist/session-node-manager.d.ts.map +1 -0
  123. package/dist/session-node-manager.js +2609 -0
  124. package/dist/session-node-manager.js.map +1 -0
  125. package/dist/session-relay-client.d.ts +101 -0
  126. package/dist/session-relay-client.d.ts.map +1 -0
  127. package/dist/session-relay-client.js +520 -0
  128. package/dist/session-relay-client.js.map +1 -0
  129. package/dist/session-tree.d.ts +80 -0
  130. package/dist/session-tree.d.ts.map +1 -0
  131. package/dist/session-tree.js +123 -0
  132. package/dist/session-tree.js.map +1 -0
  133. package/dist/signaling-connect.d.ts +83 -0
  134. package/dist/signaling-connect.d.ts.map +1 -0
  135. package/dist/signaling-connect.js +266 -0
  136. package/dist/signaling-connect.js.map +1 -0
  137. package/dist/transcript-cipher.d.ts +31 -0
  138. package/dist/transcript-cipher.d.ts.map +1 -0
  139. package/dist/transcript-cipher.js +74 -0
  140. package/dist/transcript-cipher.js.map +1 -0
  141. package/dist/transport-composition.d.ts +31 -0
  142. package/dist/transport-composition.d.ts.map +1 -0
  143. package/dist/transport-composition.js +55 -0
  144. package/dist/transport-composition.js.map +1 -0
  145. package/dist/transport-selector.d.ts +189 -0
  146. package/dist/transport-selector.d.ts.map +1 -0
  147. package/dist/transport-selector.js +195 -0
  148. package/dist/transport-selector.js.map +1 -0
  149. package/dist/types.d.ts +265 -0
  150. package/dist/types.d.ts.map +1 -0
  151. package/dist/types.js +33 -0
  152. package/dist/types.js.map +1 -0
  153. package/package.json +1 -1
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Connect-or-start logic for the CELLO daemon.
3
+ *
4
+ * Pseudocode:
5
+ * 1. connectOrStart(celloDir, logger):
6
+ * a. Read lock file at ~/.cello/daemon.lock
7
+ * b. If lock exists:
8
+ * - Check if PID is alive (signal 0)
9
+ * - If alive, attempt to connect to socket
10
+ * - If connection succeeds, return existing daemon client
11
+ * - If connection fails (socket gone), remove stale lock and start fresh
12
+ * c. If lock doesn't exist or is stale:
13
+ * - Remove stale lock (log daemon_lock_stale_removed)
14
+ * - Spawn daemon as detached child process
15
+ * - Wait for daemon.started event (read from child stdout)
16
+ * - Return client connected to new daemon
17
+ */
18
+ import { spawn } from "node:child_process";
19
+ import { join } from "node:path";
20
+ import { readLock, removeLock, isProcessAlive } from "./lock-file.js";
21
+ import { connectToDaemon } from "./ipc-client.js";
22
+ export async function connectOrStart(celloDir, logger, daemonBin) {
23
+ const lockFilePath = join(celloDir, "daemon.lock");
24
+ // Read existing lock
25
+ const lock = await readLock(lockFilePath);
26
+ if (lock) {
27
+ if (isProcessAlive(lock.pid)) {
28
+ // Try connecting to the existing daemon
29
+ try {
30
+ const client = await connectToDaemon(lock.socketPath);
31
+ return { client, alreadyRunning: true };
32
+ }
33
+ catch (err) {
34
+ logger.info("daemon.lock.stale", {
35
+ pid: lock.pid,
36
+ reason: "socket_unreachable",
37
+ error: err instanceof Error ? err.message : String(err),
38
+ });
39
+ await removeLock(lockFilePath, logger);
40
+ }
41
+ }
42
+ else {
43
+ // PID is dead — stale lock
44
+ logger.info("daemon.lock.stale", {
45
+ pid: lock.pid,
46
+ reason: "process_dead",
47
+ });
48
+ await removeLock(lockFilePath, logger);
49
+ }
50
+ }
51
+ // Start a new daemon
52
+ const client = await spawnDaemon(celloDir, daemonBin, lockFilePath, logger);
53
+ return { client, alreadyRunning: false };
54
+ }
55
+ async function spawnDaemon(celloDir, daemonBin, _lockFilePath, _logger) {
56
+ return new Promise((resolve, reject) => {
57
+ const child = spawn(process.execPath, [daemonBin], {
58
+ detached: true,
59
+ stdio: ["ignore", "pipe", "ignore"],
60
+ env: {
61
+ ...process.env,
62
+ CELLO_DIR: celloDir,
63
+ },
64
+ });
65
+ let stdoutBuf = "";
66
+ const timeout = setTimeout(() => {
67
+ child.kill();
68
+ reject(new Error("Daemon failed to start within 10 seconds"));
69
+ }, 10_000);
70
+ child.stdout.on("data", (chunk) => {
71
+ stdoutBuf += chunk.toString("utf-8");
72
+ // Look for daemon.started event line
73
+ const lines = stdoutBuf.split("\n");
74
+ for (const line of lines) {
75
+ if (line.trim().length === 0)
76
+ continue;
77
+ try {
78
+ const event = JSON.parse(line);
79
+ if (event.event === "daemon.started") {
80
+ clearTimeout(timeout);
81
+ child.stdout.removeAllListeners();
82
+ child.unref();
83
+ // Connect to the newly started daemon
84
+ const socketPath = event.ipcSocketPath;
85
+ connectToDaemon(socketPath).then(resolve).catch(reject);
86
+ return;
87
+ }
88
+ if (event.event === "daemon.startup.failed") {
89
+ clearTimeout(timeout);
90
+ child.stdout.removeAllListeners();
91
+ const errorMsg = typeof event.error === "string"
92
+ ? event.error
93
+ : event.error instanceof Error
94
+ ? event.error.message
95
+ : String(event.error || "Daemon startup failed");
96
+ reject(new Error(errorMsg));
97
+ return;
98
+ }
99
+ }
100
+ catch {
101
+ // Not JSON — ignore
102
+ }
103
+ }
104
+ });
105
+ child.on("error", (err) => {
106
+ clearTimeout(timeout);
107
+ reject(err);
108
+ });
109
+ child.on("exit", (code) => {
110
+ clearTimeout(timeout);
111
+ if (code !== 0) {
112
+ reject(new Error(`Daemon exited with code ${code}`));
113
+ }
114
+ });
115
+ });
116
+ }
117
+ //# sourceMappingURL=connect-or-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect-or-start.js","sourceRoot":"","sources":["../src/connect-or-start.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { CelloNode } from "@cello-protocol/transport";
2
+ import type { KeyProvider } from "@cello-protocol/crypto";
3
+ import type { Logger } from "./types.js";
4
+ /** A single parked entry returned by pull(). */
5
+ export interface ParkedEntry {
6
+ contentHashHex: string;
7
+ sessionIdHex: string;
8
+ ciphertext: Uint8Array;
9
+ }
10
+ export interface ContentParkClientOptions {
11
+ /** Relay libp2p peer id (12D3Koo…) — from the session assignment's relay endpoint. */
12
+ relayPeerId: string;
13
+ /** Relay multiaddrs to dial. */
14
+ relayAddrs: string[];
15
+ logger: Logger;
16
+ }
17
+ export declare class ContentParkClient {
18
+ #private;
19
+ constructor(opts: ContentParkClientOptions);
20
+ /**
21
+ * Deposit ciphertext into the recipient's relay mailbox (sender side). Deposit is OPEN by
22
+ * design — the blob is E2E-encrypted to the recipient, so an unauthenticated deposit cannot
23
+ * leak plaintext.
24
+ */
25
+ deposit(node: CelloNode, args: {
26
+ recipientPubkey: Uint8Array;
27
+ contentHash: Uint8Array;
28
+ sessionId: Uint8Array;
29
+ ciphertext: Uint8Array;
30
+ }): Promise<{
31
+ ok: boolean;
32
+ reason?: string;
33
+ }>;
34
+ /**
35
+ * Pull the recipient's parked entries (recipient side). Runs the relay's auth challenge:
36
+ * sign buildContentParkAuthMsg(nonce, recipientPubkey) with the recipient's K_local to prove
37
+ * ownership before the relay releases anything.
38
+ */
39
+ pull(node: CelloNode, recipientPubkey: Uint8Array, signer: KeyProvider): Promise<ParkedEntry[]>;
40
+ /**
41
+ * Confirm-delete one parked entry (recipient side). The relay is delete-on-CONFIRM, not
42
+ * delete-on-pull, so without this the mailbox never drains and every reconnect re-pulls the whole
43
+ * history. Mirrors pull's I1 auth (sign buildContentParkAuthMsg(nonce, recipientPubkey)). Called
44
+ * after a parked entry is durably ingested. Best-effort: a failed confirm leaves the entry (it will
45
+ * be re-pulled + deduped next time, and the relay TTL eventually evicts it) — never loses content.
46
+ */
47
+ confirm(node: CelloNode, recipientPubkey: Uint8Array, contentHash: Uint8Array, signer: KeyProvider): Promise<boolean>;
48
+ }
49
+ //# sourceMappingURL=content-park-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-park-client.d.ts","sourceRoot":"","sources":["../src/content-park-client.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAkBzC,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,iBAAiB;;gBAKhB,IAAI,EAAE,wBAAwB;IAM1C;;;;OAIG;IACG,OAAO,CACX,IAAI,EAAE,SAAS,EACf,IAAI,EAAE;QAAE,eAAe,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,GAC5G,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA+B5C;;;;OAIG;IACG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAoDrG;;;;;;OAMG;IACG,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;CAwD5H"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * M7 MSG-001-3b — daemon-side content-park CLIENT (deposit + pull).
3
+ *
4
+ * The relay runs a store-and-forward "mailbox" so a message survives the recipient being
5
+ * OFFLINE: the sender DEPOSITS ciphertext keyed to the recipient's pubkey; when the
6
+ * recipient comes online it PULLS its parked entries. The relay holds CIPHERTEXT only
7
+ * (sealed to the recipient — INV-3); it is a hash custodian, not a data custodian.
8
+ *
9
+ * This is the daemon counterpart to `packages/relay/src/content-park.ts` (the relay handler).
10
+ * It speaks the same protocol (`/cello/content-park/1.0.0`, CBOR frames, length-prefixed) over
11
+ * a libp2p stream, exactly mirroring the dial/stream/framing of `session-relay-client.ts` (the
12
+ * hash-witness client) — only the protocol ID and the frames differ.
13
+ *
14
+ * Wire contract (relay is authoritative — packages/relay/src/content-park.ts):
15
+ * deposit: → content_park_deposit { recipient_pubkey, content_hash, session_id, ciphertext }
16
+ * ← content_park_deposit_ack { content_hash, ok, reason? }
17
+ * pull: → content_park_pull_request { recipient_pubkey, content_hash? }
18
+ * ← content_park_auth_challenge { nonce(32) } (I1: prove recipient identity)
19
+ * → content_park_auth_response { signature(64) } Ed25519(buildContentParkAuthMsg)
20
+ * ← content_park_pull_count { count }
21
+ * ← count × content_park_pull_response { found, content_hash, session_id?, ciphertext? }
22
+ *
23
+ * Crypto: Ed25519 (RFC 8032). The pull auth binds the caller to the recipient identity key so a
24
+ * stranger cannot drain another recipient's mailbox (the recipient pubkey is public).
25
+ */
26
+ import * as lp from "it-length-prefixed";
27
+ import { Encoder, decode } from "cbor-x";
28
+ import { CONTENT_PARK_PROTOCOL_ID, buildContentParkAuthMsg } from "@cello-protocol/protocol-types";
29
+ const CBOR_ENC = new Encoder({ tagUint8Array: false });
30
+ const FRAME_TIMEOUT_MS = 8_000;
31
+ function toU8(chunk) {
32
+ if (chunk instanceof Uint8Array)
33
+ return chunk;
34
+ const c = chunk;
35
+ if (typeof c?.subarray === "function")
36
+ return c.subarray();
37
+ return new Uint8Array(chunk);
38
+ }
39
+ function asBytes(v) {
40
+ if (v instanceof Uint8Array)
41
+ return v;
42
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(v))
43
+ return new Uint8Array(v);
44
+ return null;
45
+ }
46
+ export class ContentParkClient {
47
+ #relayPeerId;
48
+ #relayAddrs;
49
+ #logger;
50
+ constructor(opts) {
51
+ this.#relayPeerId = opts.relayPeerId;
52
+ this.#relayAddrs = opts.relayAddrs;
53
+ this.#logger = opts.logger;
54
+ }
55
+ /**
56
+ * Deposit ciphertext into the recipient's relay mailbox (sender side). Deposit is OPEN by
57
+ * design — the blob is E2E-encrypted to the recipient, so an unauthenticated deposit cannot
58
+ * leak plaintext.
59
+ */
60
+ async deposit(node, args) {
61
+ const stream = await this.#open(node);
62
+ try {
63
+ const iter = this.#iter(stream);
64
+ stream.send(lp.encode.single(CBOR_ENC.encode({
65
+ type: "content_park_deposit",
66
+ recipient_pubkey: args.recipientPubkey,
67
+ content_hash: args.contentHash,
68
+ session_id: args.sessionId,
69
+ ciphertext: args.ciphertext,
70
+ })));
71
+ const ack = await this.#read(iter);
72
+ if (!ack || ack["type"] !== "content_park_deposit_ack") {
73
+ return { ok: false, reason: "no_deposit_ack" };
74
+ }
75
+ const ok = ack["ok"] === true;
76
+ this.#logger.info("content.park.deposit.result", {
77
+ relayPeerId: this.#relayPeerId,
78
+ ok,
79
+ reason: typeof ack["reason"] === "string" ? ack["reason"] : undefined,
80
+ });
81
+ return { ok, reason: typeof ack["reason"] === "string" ? ack["reason"] : undefined };
82
+ }
83
+ finally {
84
+ await stream.close().catch(() => { });
85
+ }
86
+ }
87
+ /**
88
+ * Pull the recipient's parked entries (recipient side). Runs the relay's auth challenge:
89
+ * sign buildContentParkAuthMsg(nonce, recipientPubkey) with the recipient's K_local to prove
90
+ * ownership before the relay releases anything.
91
+ */
92
+ async pull(node, recipientPubkey, signer) {
93
+ const stream = await this.#open(node);
94
+ try {
95
+ const iter = this.#iter(stream);
96
+ stream.send(lp.encode.single(CBOR_ENC.encode({ type: "content_park_pull_request", recipient_pubkey: recipientPubkey })));
97
+ // I1 auth challenge → response.
98
+ const challenge = await this.#read(iter);
99
+ if (!challenge || challenge["type"] !== "content_park_auth_challenge") {
100
+ this.#logger.warn("content.park.pull.failed", { relayPeerId: this.#relayPeerId, reason: "no_auth_challenge" });
101
+ return [];
102
+ }
103
+ const nonce = asBytes(challenge["nonce"]);
104
+ if (!nonce)
105
+ return [];
106
+ const signature = await signer.sign(buildContentParkAuthMsg(nonce, recipientPubkey));
107
+ stream.send(lp.encode.single(CBOR_ENC.encode({ type: "content_park_auth_response", signature })));
108
+ // Count header, then N responses.
109
+ const countFrame = await this.#read(iter);
110
+ if (!countFrame || countFrame["type"] !== "content_park_pull_count") {
111
+ this.#logger.warn("content.park.pull.failed", { relayPeerId: this.#relayPeerId, reason: "no_pull_count" });
112
+ return [];
113
+ }
114
+ const count = typeof countFrame["count"] === "number" ? countFrame["count"] : 0;
115
+ const entries = [];
116
+ for (let i = 0; i < count; i++) {
117
+ const r = await this.#read(iter);
118
+ if (!r || r["type"] !== "content_park_pull_response")
119
+ break;
120
+ if (r["found"] !== true)
121
+ continue;
122
+ const contentHash = asBytes(r["content_hash"]);
123
+ const sessionId = asBytes(r["session_id"]);
124
+ const ciphertext = asBytes(r["ciphertext"]);
125
+ if (!contentHash || !ciphertext)
126
+ continue;
127
+ entries.push({
128
+ contentHashHex: Buffer.from(contentHash).toString("hex"),
129
+ sessionIdHex: sessionId ? Buffer.from(sessionId).toString("hex") : "",
130
+ ciphertext,
131
+ });
132
+ }
133
+ this.#logger.info("content.park.pull.result", { relayPeerId: this.#relayPeerId, count: entries.length });
134
+ return entries;
135
+ }
136
+ finally {
137
+ await stream.close().catch(() => { });
138
+ }
139
+ }
140
+ /**
141
+ * Confirm-delete one parked entry (recipient side). The relay is delete-on-CONFIRM, not
142
+ * delete-on-pull, so without this the mailbox never drains and every reconnect re-pulls the whole
143
+ * history. Mirrors pull's I1 auth (sign buildContentParkAuthMsg(nonce, recipientPubkey)). Called
144
+ * after a parked entry is durably ingested. Best-effort: a failed confirm leaves the entry (it will
145
+ * be re-pulled + deduped next time, and the relay TTL eventually evicts it) — never loses content.
146
+ */
147
+ async confirm(node, recipientPubkey, contentHash, signer) {
148
+ const stream = await this.#open(node);
149
+ try {
150
+ const iter = this.#iter(stream);
151
+ stream.send(lp.encode.single(CBOR_ENC.encode({ type: "content_park_confirm", recipient_pubkey: recipientPubkey, content_hash: contentHash })));
152
+ const challenge = await this.#read(iter);
153
+ if (!challenge || challenge["type"] !== "content_park_auth_challenge") {
154
+ this.#logger.warn("content.park.confirm.failed", { relayPeerId: this.#relayPeerId, reason: "no_auth_challenge" });
155
+ return false;
156
+ }
157
+ const nonce = asBytes(challenge["nonce"]);
158
+ if (!nonce)
159
+ return false;
160
+ const signature = await signer.sign(buildContentParkAuthMsg(nonce, recipientPubkey));
161
+ stream.send(lp.encode.single(CBOR_ENC.encode({ type: "content_park_auth_response", signature })));
162
+ const ack = await this.#read(iter);
163
+ const ok = !!ack && ack["type"] === "content_park_confirm_ack" && ack["ok"] === true;
164
+ if (!ok)
165
+ this.#logger.warn("content.park.confirm.failed", { relayPeerId: this.#relayPeerId, reason: "no_confirm_ack" });
166
+ return ok;
167
+ }
168
+ finally {
169
+ await stream.close().catch(() => { });
170
+ }
171
+ }
172
+ /** Dial the relay (best-effort per addr) and open a content-park stream. */
173
+ async #open(node) {
174
+ for (const addr of this.#relayAddrs) {
175
+ try {
176
+ await node.dial(addr);
177
+ break;
178
+ }
179
+ catch {
180
+ /* try the next addr; newStream below may still succeed from the peerstore */
181
+ }
182
+ }
183
+ return node.newStream(this.#relayPeerId, CONTENT_PARK_PROTOCOL_ID);
184
+ }
185
+ #iter(stream) {
186
+ return lp.decode(stream)[Symbol.asyncIterator]();
187
+ }
188
+ async #read(iter) {
189
+ const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error("content_park_frame_timeout")), FRAME_TIMEOUT_MS));
190
+ const res = (await Promise.race([iter.next(), timeout]));
191
+ if (res.done || res.value === undefined)
192
+ return null;
193
+ return decode(toU8(res.value));
194
+ }
195
+ }
196
+ //# sourceMappingURL=content-park-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-park-client.js","sourceRoot":"","sources":["../src/content-park-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * CELLO Daemon process — the long-running background service.
3
+ *
4
+ * Pseudocode:
5
+ * 1. startDaemon(config):
6
+ * a. M7-MANIFEST-002: Load and verify consortium manifest (BEFORE any directory connection)
7
+ * - On signature failure: log error, skip connection
8
+ * - On expiry: log directory.auth.manifest.expired at ERROR, skip connection
9
+ * - On version rollback: log directory.auth.manifest.version.rollback at ERROR
10
+ * - On success: log directory.auth.manifest.verified at INFO
11
+ * b. Load agents from ~/.cello/agents/ (or legacy ~/.cello/key)
12
+ * c. Acquire lock file atomically
13
+ * d. Initialize SessionNodeManager (creates standing receiver, detects interrupted sessions)
14
+ * e. Start IPC server on Unix domain socket
15
+ * f. Register method handlers (status, shutdown)
16
+ * g. Log daemon.started event (with manifestVerified field)
17
+ * h. Set up SIGTERM/SIGINT handlers for graceful shutdown
18
+ * i. Start background manifest polling (if pollScheduler provided and manifest verified)
19
+ *
20
+ * 2. shutdown(reason):
21
+ * a. Cancel manifest poll scheduler
22
+ * b. Log daemon.stopped event
23
+ * c. Call SessionNodeManager.gracefulShutdown() (marks sessions interrupted)
24
+ * d. Stop IPC server (finishes in-flight, sends shutdown frame)
25
+ * e. Remove lock file
26
+ * f. Exit 0
27
+ */
28
+ import type { DaemonConfig, DaemonStatusResponse } from "./types.js";
29
+ import { SessionNodeManager } from "./session-node-manager.js";
30
+ import { type CelloNode } from "@cello-protocol/transport";
31
+ import type { ITransportSelector } from "./transport-selector.js";
32
+ import { type IAutoNatService } from "@cello-protocol/transport";
33
+ export interface DaemonHandle {
34
+ stop(reason: string): Promise<void>;
35
+ getStatus(): DaemonStatusResponse;
36
+ /**
37
+ * AC-016 test hook: exposes the session node manager so integration tests can
38
+ * call registerRelayStream directly and verify the composition root is wired.
39
+ * Not part of the production API surface.
40
+ */
41
+ getSessionNodeManager(): SessionNodeManager;
42
+ /**
43
+ * M7 Action 2: the live directory-facing libp2p node (or null when signaling is not
44
+ * connected). Registration's FROST DKG and future ceremonies open streams to the
45
+ * directory on this node. Consumers must gate use on signaling being connected AND
46
+ * always null-check the result: there is a brief window during stream death where the
47
+ * reference is already cleared (null) while signalingManager.status still reads
48
+ * "connected". Null is the safe direction (never a tearing-down node); do not assume
49
+ * non-null just because status is connected.
50
+ */
51
+ getDirectoryNode(): CelloNode | null;
52
+ /**
53
+ * CELLO-M7-TRANSPORT-001 (AC-010): exposes the composition-root transport
54
+ * selector so integration tests can confirm the adapter is wired (not dead
55
+ * code) and exercise the selection path without "adapter not wired".
56
+ */
57
+ getTransportSelector(): ITransportSelector;
58
+ /**
59
+ * CELLO-M7-TRANSPORT-001 (AC-010): exposes the composition-root AutoNAT service
60
+ * adapter (stub default dialable=false in local/test).
61
+ */
62
+ getAutoNatService(): IAutoNatService;
63
+ }
64
+ export declare function startDaemon(config: DaemonConfig): Promise<DaemonHandle>;
65
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EAIrB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAK/D,OAAO,EAAoD,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAkB7G,OAAO,KAAK,EAAE,kBAAkB,EAA+C,MAAM,yBAAyB,CAAC;AAM/G,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAmInF,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,SAAS,IAAI,oBAAoB,CAAC;IAClC;;;;OAIG;IACH,qBAAqB,IAAI,kBAAkB,CAAC;IAC5C;;;;;;;;OAQG;IACH,gBAAgB,IAAI,SAAS,GAAG,IAAI,CAAC;IACrC;;;;OAIG;IACH,oBAAoB,IAAI,kBAAkB,CAAC;IAC3C;;;OAGG;IACH,iBAAiB,IAAI,eAAe,CAAC;CACtC;AAyBD,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA80G7E"}