@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.
- package/dist/agent-loader.d.ts +41 -0
- package/dist/agent-loader.d.ts.map +1 -0
- package/dist/agent-loader.js +94 -0
- package/dist/agent-loader.js.map +1 -0
- package/dist/bin/cello-daemon.d.ts +13 -0
- package/dist/bin/cello-daemon.d.ts.map +1 -0
- package/dist/bin/cello-daemon.js +170 -0
- package/dist/bin/cello-daemon.js.map +1 -0
- package/dist/cello-node-transport-dialer.d.ts +59 -0
- package/dist/cello-node-transport-dialer.d.ts.map +1 -0
- package/dist/cello-node-transport-dialer.js +108 -0
- package/dist/cello-node-transport-dialer.js.map +1 -0
- package/dist/challenge-verifier.d.ts +12 -0
- package/dist/challenge-verifier.d.ts.map +1 -0
- package/dist/challenge-verifier.js +11 -0
- package/dist/challenge-verifier.js.map +1 -0
- package/dist/connect-or-start.d.ts +25 -0
- package/dist/connect-or-start.d.ts.map +1 -0
- package/dist/connect-or-start.js +117 -0
- package/dist/connect-or-start.js.map +1 -0
- package/dist/content-park-client.d.ts +49 -0
- package/dist/content-park-client.d.ts.map +1 -0
- package/dist/content-park-client.js +196 -0
- package/dist/content-park-client.js.map +1 -0
- package/dist/daemon.d.ts +65 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +3202 -0
- package/dist/daemon.js.map +1 -0
- package/dist/directory-bootstrap.d.ts +55 -0
- package/dist/directory-bootstrap.d.ts.map +1 -0
- package/dist/directory-bootstrap.js +102 -0
- package/dist/directory-bootstrap.js.map +1 -0
- package/dist/file-manifest-provider.d.ts +18 -0
- package/dist/file-manifest-provider.d.ts.map +1 -0
- package/dist/file-manifest-provider.js +72 -0
- package/dist/file-manifest-provider.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc-client.d.ts +31 -0
- package/dist/ipc-client.d.ts.map +1 -0
- package/dist/ipc-client.js +112 -0
- package/dist/ipc-client.js.map +1 -0
- package/dist/ipc-server.d.ts +49 -0
- package/dist/ipc-server.d.ts.map +1 -0
- package/dist/ipc-server.js +268 -0
- package/dist/ipc-server.js.map +1 -0
- package/dist/lock-file.d.ts +27 -0
- package/dist/lock-file.d.ts.map +1 -0
- package/dist/lock-file.js +84 -0
- package/dist/lock-file.js.map +1 -0
- package/dist/manifest-loader.d.ts +33 -0
- package/dist/manifest-loader.d.ts.map +1 -0
- package/dist/manifest-loader.js +70 -0
- package/dist/manifest-loader.js.map +1 -0
- package/dist/manifest-poll-scheduler.d.ts +31 -0
- package/dist/manifest-poll-scheduler.d.ts.map +1 -0
- package/dist/manifest-poll-scheduler.js +59 -0
- package/dist/manifest-poll-scheduler.js.map +1 -0
- package/dist/manifest-version-store-file.d.ts +18 -0
- package/dist/manifest-version-store-file.d.ts.map +1 -0
- package/dist/manifest-version-store-file.js +40 -0
- package/dist/manifest-version-store-file.js.map +1 -0
- package/dist/manifest-version-store.d.ts +14 -0
- package/dist/manifest-version-store.d.ts.map +1 -0
- package/dist/manifest-version-store.js +13 -0
- package/dist/manifest-version-store.js.map +1 -0
- package/dist/network-directory-node.d.ts +94 -0
- package/dist/network-directory-node.d.ts.map +1 -0
- package/dist/network-directory-node.js +626 -0
- package/dist/network-directory-node.js.map +1 -0
- package/dist/nonce-dedup.d.ts +68 -0
- package/dist/nonce-dedup.d.ts.map +1 -0
- package/dist/nonce-dedup.js +204 -0
- package/dist/nonce-dedup.js.map +1 -0
- package/dist/notification-dispatcher.d.ts +65 -0
- package/dist/notification-dispatcher.d.ts.map +1 -0
- package/dist/notification-dispatcher.js +138 -0
- package/dist/notification-dispatcher.js.map +1 -0
- package/dist/registration-context.d.ts +69 -0
- package/dist/registration-context.d.ts.map +1 -0
- package/dist/registration-context.js +118 -0
- package/dist/registration-context.js.map +1 -0
- package/dist/registration-manager.d.ts +72 -0
- package/dist/registration-manager.d.ts.map +1 -0
- package/dist/registration-manager.js +267 -0
- package/dist/registration-manager.js.map +1 -0
- package/dist/registration-persistence.d.ts +131 -0
- package/dist/registration-persistence.d.ts.map +1 -0
- package/dist/registration-persistence.js +233 -0
- package/dist/registration-persistence.js.map +1 -0
- package/dist/retry-queue.d.ts +144 -0
- package/dist/retry-queue.d.ts.map +1 -0
- package/dist/retry-queue.js +444 -0
- package/dist/retry-queue.js.map +1 -0
- package/dist/seal-frontier-verify.d.ts +58 -0
- package/dist/seal-frontier-verify.d.ts.map +1 -0
- package/dist/seal-frontier-verify.js +87 -0
- package/dist/seal-frontier-verify.js.map +1 -0
- package/dist/seal-legibility-tbs.d.ts +25 -0
- package/dist/seal-legibility-tbs.d.ts.map +1 -0
- package/dist/seal-legibility-tbs.js +78 -0
- package/dist/seal-legibility-tbs.js.map +1 -0
- package/dist/seal-upgrade.d.ts +90 -0
- package/dist/seal-upgrade.d.ts.map +1 -0
- package/dist/seal-upgrade.js +178 -0
- package/dist/seal-upgrade.js.map +1 -0
- package/dist/session-assignment-parser.d.ts +22 -0
- package/dist/session-assignment-parser.d.ts.map +1 -0
- package/dist/session-assignment-parser.js +139 -0
- package/dist/session-assignment-parser.js.map +1 -0
- package/dist/session-ceremony.d.ts +156 -0
- package/dist/session-ceremony.d.ts.map +1 -0
- package/dist/session-ceremony.js +447 -0
- package/dist/session-ceremony.js.map +1 -0
- package/dist/session-connection-gater.d.ts +91 -0
- package/dist/session-connection-gater.d.ts.map +1 -0
- package/dist/session-connection-gater.js +146 -0
- package/dist/session-connection-gater.js.map +1 -0
- package/dist/session-node-manager.d.ts +585 -0
- package/dist/session-node-manager.d.ts.map +1 -0
- package/dist/session-node-manager.js +2609 -0
- package/dist/session-node-manager.js.map +1 -0
- package/dist/session-relay-client.d.ts +101 -0
- package/dist/session-relay-client.d.ts.map +1 -0
- package/dist/session-relay-client.js +520 -0
- package/dist/session-relay-client.js.map +1 -0
- package/dist/session-tree.d.ts +80 -0
- package/dist/session-tree.d.ts.map +1 -0
- package/dist/session-tree.js +123 -0
- package/dist/session-tree.js.map +1 -0
- package/dist/signaling-connect.d.ts +83 -0
- package/dist/signaling-connect.d.ts.map +1 -0
- package/dist/signaling-connect.js +266 -0
- package/dist/signaling-connect.js.map +1 -0
- package/dist/transcript-cipher.d.ts +31 -0
- package/dist/transcript-cipher.d.ts.map +1 -0
- package/dist/transcript-cipher.js +74 -0
- package/dist/transcript-cipher.js.map +1 -0
- package/dist/transport-composition.d.ts +31 -0
- package/dist/transport-composition.d.ts.map +1 -0
- package/dist/transport-composition.js +55 -0
- package/dist/transport-composition.js.map +1 -0
- package/dist/transport-selector.d.ts +189 -0
- package/dist/transport-selector.d.ts.map +1 -0
- package/dist/transport-selector.js +195 -0
- package/dist/transport-selector.js.map +1 -0
- package/dist/types.d.ts +265 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +33 -0
- package/dist/types.js.map +1 -0
- 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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"}
|
package/dist/daemon.d.ts
ADDED
|
@@ -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"}
|