@cello-protocol/daemon 0.0.175 → 0.0.176
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/daemon.d.ts.map +1 -1
- package/dist/daemon.js +54 -2
- package/dist/daemon.js.map +1 -1
- package/dist/session-content-handlers.d.ts.map +1 -1
- package/dist/session-content-handlers.js +82 -1
- package/dist/session-content-handlers.js.map +1 -1
- package/dist/session-node-manager.d.ts +231 -5
- package/dist/session-node-manager.d.ts.map +1 -1
- package/dist/session-node-manager.js +684 -17
- package/dist/session-node-manager.js.map +1 -1
- package/package.json +5 -5
package/dist/daemon.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EAOrB,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAmC,KAAK,UAAU,EAAsB,MAAM,iBAAiB,CAAC;AAEvG,OAAO,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EAOrB,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAmC,KAAK,UAAU,EAAsB,MAAM,iBAAiB,CAAC;AAEvG,OAAO,EAAE,kBAAkB,EAA6C,MAAM,2BAA2B,CAAC;AAO1G,OAAO,EAAoD,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAiB7G,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAsB,MAAM,2BAA2B,CAAC;AAS5G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAIlE,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AA2BnF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAYlD,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,SAAS,IAAI,oBAAoB,CAAC;IAClC;;;;;OAKG;IACH,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACpE;;;;OAIG;IACH,qBAAqB,IAAI,kBAAkB,CAAC;IAC5C;;;;OAIG;IACH,oBAAoB,IAAI,kBAAkB,CAAC;IAC3C;;;OAGG;IACH,iBAAiB,IAAI,eAAe,CAAC;IACrC;;OAEG;IACH,eAAe,IAAI,YAAY,CAAC;IAChC;;;;;;;;OAQG;IACH,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACxC;AAYD,qBAAa,4BAA6B,YAAW,mBAAmB;IAChE,UAAU,CAAC,MAAM,EAAE,iBAAiB;CAuC3C;AAID,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAS7E"}
|
package/dist/daemon.js
CHANGED
|
@@ -35,7 +35,7 @@ import { acquireLock, removeLockIfOwned } from "./lock-file.js";
|
|
|
35
35
|
import { acquireSingletonLock } from "./singleton-lock.js";
|
|
36
36
|
import { createIpcServer } from "./ipc-server.js";
|
|
37
37
|
import { renderForSurface } from "./vocabulary.js";
|
|
38
|
-
import { SessionNodeManager } from "./session-node-manager.js";
|
|
38
|
+
import { SessionNodeManager, REVIVAL_WINDOW_MS, REVIVAL_BOUND_SWEEP_MS } from "./session-node-manager.js";
|
|
39
39
|
import { registerGatewayConfigHandlers } from "./gateway-config-handlers.js";
|
|
40
40
|
import { RetryQueue } from "./retry-queue.js";
|
|
41
41
|
import { NonceDedupStore } from "./nonce-dedup.js";
|
|
@@ -115,7 +115,11 @@ export class ProductionSessionNodeFactory {
|
|
|
115
115
|
// agent ever did). CELLO_LISTEN_ADDR / CELLO_ANNOUNCE_ADDRS remain as
|
|
116
116
|
// overrides for publicly-hosted agents (M6 parity). Ephemeral session nodes
|
|
117
117
|
// (which dial OUT and need no inbound reachability) stay on loopback.
|
|
118
|
-
|
|
118
|
+
// DOD-M12B-SESSION-SEED-1 (case B review HIGH-1): `inboundReachable` is the REVIVED session
|
|
119
|
+
// node. Every production session node reached its role by promotion and so inherited the
|
|
120
|
+
// receiver's routable bind; a rebuilt one inherits nothing and would come back on loopback,
|
|
121
|
+
// preserving an identity nobody can dial.
|
|
122
|
+
const isReceiver = config.nodeType === "standing_receiver" || config.inboundReachable === true;
|
|
119
123
|
const listenAddr = isReceiver
|
|
120
124
|
? (process.env["CELLO_LISTEN_ADDR"] ?? "/ip4/0.0.0.0/tcp/0")
|
|
121
125
|
: "/ip4/127.0.0.1/tcp/0";
|
|
@@ -134,6 +138,11 @@ export class ProductionSessionNodeFactory {
|
|
|
134
138
|
// type; nodeType's remaining transport effect is the HOP gate (client
|
|
135
139
|
// types never advertise circuit-relay HOP).
|
|
136
140
|
nodeType: config.nodeType,
|
|
141
|
+
// DOD-M12B-SESSION-SEED-1: forward the caller's transport seed when it supplied one, so a
|
|
142
|
+
// rebuilt session node returns at the peer id the counterparty already holds. Omitted (rather
|
|
143
|
+
// than passed as undefined) when absent, keeping createNode's "generate a fresh key" default
|
|
144
|
+
// for every node that is not session-scoped.
|
|
145
|
+
...(config.transportPrivateKey ? { transportPrivateKey: config.transportPrivateKey } : {}),
|
|
137
146
|
});
|
|
138
147
|
}
|
|
139
148
|
}
|
|
@@ -3963,6 +3972,7 @@ async function startDaemonHoldingLock(config, singletonLock) {
|
|
|
3963
3972
|
let stoppedHookFired = false;
|
|
3964
3973
|
async function stop(reason) {
|
|
3965
3974
|
clearInterval(reconcileSweepTimer);
|
|
3975
|
+
clearInterval(revivalBoundSweepTimer);
|
|
3966
3976
|
// DOD-M12B-SHUTDOWN-1: clearing the timer only stops the NEXT tick. The pass already running
|
|
3967
3977
|
// walks every agent, and each step dials a peer and opens a session — which is why a daemon
|
|
3968
3978
|
// reported down, with its socket already removed, was still logging `document.reconcile.sweep`
|
|
@@ -4147,6 +4157,48 @@ async function startDaemonHoldingLock(config, singletonLock) {
|
|
|
4147
4157
|
markGaveUp: (agentName, sessionId, reason) => sessionNodeManager.markRestartSealGaveUp(agentName, sessionId, reason),
|
|
4148
4158
|
});
|
|
4149
4159
|
restartSealResolver.start();
|
|
4160
|
+
/**
|
|
4161
|
+
* DOD-M12B-REVIVAL-BOUND-1 — close the interrupted sessions the revival window has expired.
|
|
4162
|
+
*
|
|
4163
|
+
* Runs at boot beside the restart-seal resolver, and is its complement: the resolver takes the
|
|
4164
|
+
* sessions we can describe truthfully (`interrupted_by = 'local'`) and gets them a receipt; this
|
|
4165
|
+
* takes everything else and shuts the door without asserting a cause.
|
|
4166
|
+
*
|
|
4167
|
+
* It must run even though nothing has revived a session yet — the reason is Andre's 2026-08-18
|
|
4168
|
+
* tenet, *"leave nothing open that is no longer needed."* `ingestReceivedContent` accepts content
|
|
4169
|
+
* into an `interrupted` session by design, so a session that can never be revived is a write
|
|
4170
|
+
* surface a reprogrammed peer can use for as long as the row exists. Boot is where the store is
|
|
4171
|
+
* swept for exactly that.
|
|
4172
|
+
*
|
|
4173
|
+
* NOT AWAITED, and caught: this is a best-effort sweep over rows that have already waited a day.
|
|
4174
|
+
* Blocking the daemon's startup on a directory-free DB walk buys nothing, and a throw here would
|
|
4175
|
+
* take down a daemon that is otherwise healthy.
|
|
4176
|
+
*/
|
|
4177
|
+
const runRevivalBoundSweep = () => {
|
|
4178
|
+
void sessionNodeManager
|
|
4179
|
+
.closeExpiredUnrevivableSessions(Date.now(), REVIVAL_WINDOW_MS)
|
|
4180
|
+
.catch((err) => {
|
|
4181
|
+
logger.warn("session.revival_bound.sweep.failed", {
|
|
4182
|
+
error: err instanceof Error ? err.message : String(err),
|
|
4183
|
+
impact: "expired sessions were not closed this pass and still accept content",
|
|
4184
|
+
});
|
|
4185
|
+
});
|
|
4186
|
+
};
|
|
4187
|
+
runRevivalBoundSweep();
|
|
4188
|
+
/**
|
|
4189
|
+
* RE-ARMED, because boot alone is not a bound.
|
|
4190
|
+
*
|
|
4191
|
+
* A session interrupted at 09:00 on a daemon that stays up all week would otherwise be writable
|
|
4192
|
+
* for the whole week — and a long-lived daemon is the normal case, not the exception. Boot-only
|
|
4193
|
+
* would have made the control fire exactly when it is least needed (a machine that restarts often
|
|
4194
|
+
* is a machine whose sessions get swept often) and never when it is most needed.
|
|
4195
|
+
*
|
|
4196
|
+
* Hourly against a 24-hour window: the overshoot is at most an hour on a bound measured in days,
|
|
4197
|
+
* and the pass is a single indexed DB walk with no network in it. `unref` so a pending timer
|
|
4198
|
+
* never holds the process open, matching `reconcileSweepTimer` beside it.
|
|
4199
|
+
*/
|
|
4200
|
+
const revivalBoundSweepTimer = setInterval(runRevivalBoundSweep, REVIVAL_BOUND_SWEEP_MS);
|
|
4201
|
+
revivalBoundSweepTimer.unref?.();
|
|
4150
4202
|
/**
|
|
4151
4203
|
* The live handler map.
|
|
4152
4204
|
*
|