@cello-protocol/daemon 0.0.35 → 0.0.36
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 +25 -7
- package/dist/daemon.js.map +1 -1
- package/dist/session-node-manager.d.ts +3 -2
- package/dist/session-node-manager.d.ts.map +1 -1
- package/dist/session-node-manager.js +8 -3
- package/dist/session-node-manager.js.map +1 -1
- package/package.json +3 -3
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,EAQrB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAQ/D,OAAO,EAAoD,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAsB7G,OAAO,KAAK,EAAE,kBAAkB,EAA+C,MAAM,yBAAyB,CAAC;AAO/G,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AA0InF,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;AA2CD,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAE1D,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EAQrB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAQ/D,OAAO,EAAoD,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAsB7G,OAAO,KAAK,EAAE,kBAAkB,EAA+C,MAAM,yBAAyB,CAAC;AAO/G,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AA0InF,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;AA2CD,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAE1D,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAi9K7E"}
|
package/dist/daemon.js
CHANGED
|
@@ -1559,13 +1559,19 @@ export async function startDaemon(config) {
|
|
|
1559
1559
|
// no background timer). A session the standing receiver opened from an inbound offer the initiator
|
|
1560
1560
|
// ABANDONED stays "active" forever (the counterparty never joins), clutters the open/active lists, and
|
|
1561
1561
|
// its normal close fires an unsealable bilateral seal. Mark such a session terminal ("abandoned") once
|
|
1562
|
-
// it is PROVABLY dead:
|
|
1563
|
-
//
|
|
1564
|
-
//
|
|
1562
|
+
// it is PROVABLY dead: counterparty never established (liveness != "alive" AND 0 RECEIVED messages —
|
|
1563
|
+
// message_count alone counts our own auto-"Dispatched." ack, so it is NOT the signal) + age past the
|
|
1564
|
+
// grace TTL (a genuinely fresh session still setting up must survive).
|
|
1565
|
+
// CC-10 (live 2026-07-08 Phase-2 block): scan 'interrupted' too, not just 'active'. A daemon restart
|
|
1566
|
+
// flips dead half-opens to 'interrupted'; those classify as "failed" (invisible in every list) yet
|
|
1567
|
+
// still count toward the unknown-sender acceptance bound (D18 deliberately counts 'interrupted') — so
|
|
1568
|
+
// a stranger whose first handshakes died was silently locked out FOREVER. Reaping only 0-RECEIVED
|
|
1569
|
+
// ghosts keeps D18 intact: the disconnect-evasion attacker's sessions always carry received content.
|
|
1565
1570
|
const HALF_OPEN_TTL_MS = Number(process.env["CELLO_HALF_OPEN_TTL_MS"]) || 5 * 60 * 1000;
|
|
1566
1571
|
function reapDeadHalfOpenSessions(agentName) {
|
|
1567
1572
|
const now = Date.now();
|
|
1568
|
-
|
|
1573
|
+
const candidates = [...sessionNodeManager.getSessionsByStatus("active"), ...sessionNodeManager.getSessionsByStatus("interrupted")];
|
|
1574
|
+
for (const row of candidates) {
|
|
1569
1575
|
if (agentName !== undefined && row.agent_name !== agentName)
|
|
1570
1576
|
continue;
|
|
1571
1577
|
if (now - row.created_at <= HALF_OPEN_TTL_MS)
|
|
@@ -1575,11 +1581,18 @@ export async function startDaemon(config) {
|
|
|
1575
1581
|
if (sessionNodeManager.countReceivedMessages(row.agent_name, row.session_id) > 0)
|
|
1576
1582
|
continue; // counterparty spoke
|
|
1577
1583
|
// Non-awaited: abandonSession flips the DB status synchronously (before its first await), so THIS
|
|
1578
|
-
// read reflects it; the async node teardown finishes in the background.
|
|
1579
|
-
|
|
1584
|
+
// read reflects it; the async node teardown finishes in the background. CC-10 reviewer LOW: only
|
|
1585
|
+
// log "reaped" if the status flip actually wrote — a swallowed write failure already logs
|
|
1586
|
+
// session.status.write.failed, and reporting success over it would hide a still-counting ghost.
|
|
1587
|
+
void sessionNodeManager.abandonSession(row.agent_name, row.session_id)
|
|
1588
|
+
.then((flipped) => {
|
|
1589
|
+
if (flipped) {
|
|
1590
|
+
logger.info("session.half_open.reaped", { agentName: row.agent_name, sessionId: row.session_id, priorStatus: row.status, ageMs: now - row.created_at });
|
|
1591
|
+
}
|
|
1592
|
+
})
|
|
1593
|
+
.catch((err) => {
|
|
1580
1594
|
logger.warn("session.half_open.reap.failed", { agentName: row.agent_name, sessionId: row.session_id, reason: err instanceof Error ? err.message : String(err) });
|
|
1581
1595
|
});
|
|
1582
|
-
logger.info("session.half_open.reaped", { agentName: row.agent_name, sessionId: row.session_id, ageMs: now - row.created_at });
|
|
1583
1596
|
}
|
|
1584
1597
|
}
|
|
1585
1598
|
// M8B F16: per-session liveness for ACTIVE sessions, shared by both status surfaces
|
|
@@ -4044,6 +4057,11 @@ export async function startDaemon(config) {
|
|
|
4044
4057
|
// senders — a per-sender cap (many sessions from ONE stranger) and a global cap (many
|
|
4045
4058
|
// sessions across ALL strangers combined). Known contacts are exempt ("bounded only by
|
|
4046
4059
|
// disk" — DoD). Checked FIRST, before any standing-receiver work, so a refusal is cheap.
|
|
4060
|
+
// CC-10: reap provably-dead ghosts for THIS agent before counting — otherwise invisible
|
|
4061
|
+
// interrupted 0-received sessions (post-restart shape) consume the sender's budget forever
|
|
4062
|
+
// and lock the stranger out with no list read ever clearing them. Safe here: abandonSession
|
|
4063
|
+
// flips the DB status synchronously, so the bound query below sees the reaped state.
|
|
4064
|
+
reapDeadHalfOpenSessions(agentName);
|
|
4047
4065
|
const bound = sessionNodeManager.checkUnknownSenderAcceptanceBound(agentName, parsed.participantAPubkeyHex);
|
|
4048
4066
|
if (!bound.ok) {
|
|
4049
4067
|
logger.warn("session.inbound.accept.failed", {
|