@cello-protocol/daemon 0.0.137 → 0.0.139
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/column-birth.d.ts +40 -0
- package/dist/column-birth.d.ts.map +1 -0
- package/dist/column-birth.js +60 -0
- package/dist/column-birth.js.map +1 -0
- package/dist/daemon.js +42 -0
- package/dist/daemon.js.map +1 -1
- package/dist/document-ack-inbound.d.ts +7 -0
- package/dist/document-ack-inbound.d.ts.map +1 -1
- package/dist/document-ack-inbound.js +3 -0
- package/dist/document-ack-inbound.js.map +1 -1
- package/dist/document-delivery-transport.d.ts +38 -0
- package/dist/document-delivery-transport.d.ts.map +1 -1
- package/dist/document-delivery-transport.js +72 -1
- package/dist/document-delivery-transport.js.map +1 -1
- package/dist/document-delivery.d.ts +32 -0
- package/dist/document-delivery.d.ts.map +1 -1
- package/dist/document-delivery.js +52 -6
- package/dist/document-delivery.js.map +1 -1
- package/dist/document-handlers.d.ts.map +1 -1
- package/dist/document-handlers.js +171 -15
- package/dist/document-handlers.js.map +1 -1
- package/dist/document-handshake.d.ts +4 -0
- package/dist/document-handshake.d.ts.map +1 -1
- package/dist/document-handshake.js +40 -13
- package/dist/document-handshake.js.map +1 -1
- package/dist/document-layer.d.ts +15 -0
- package/dist/document-layer.d.ts.map +1 -1
- package/dist/document-layer.js +53 -1
- package/dist/document-layer.js.map +1 -1
- package/dist/document-lifecycle.d.ts +10 -0
- package/dist/document-lifecycle.d.ts.map +1 -1
- package/dist/document-lifecycle.js +23 -2
- package/dist/document-lifecycle.js.map +1 -1
- package/dist/document-screen.d.ts +16 -0
- package/dist/document-screen.d.ts.map +1 -1
- package/dist/document-screen.js +40 -20
- package/dist/document-screen.js.map +1 -1
- package/dist/document-store.d.ts +29 -0
- package/dist/document-store.d.ts.map +1 -1
- package/dist/document-store.js +49 -7
- package/dist/document-store.js.map +1 -1
- package/dist/session-content-handlers.d.ts.map +1 -1
- package/dist/session-content-handlers.js +30 -2
- package/dist/session-content-handlers.js.map +1 -1
- package/dist/session-node-manager.d.ts.map +1 -1
- package/dist/session-node-manager.js +33 -0
- package/dist/session-node-manager.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COLUMN BIRTH — adding a column to a table an operator already holds data in.
|
|
3
|
+
*
|
|
4
|
+
* `ALTER TABLE … ADD COLUMN` throws when the column is already there, and that throw is the guard:
|
|
5
|
+
* it is how a birth-gated migration stays idempotent without a version table nobody maintains. The
|
|
6
|
+
* pattern is right. The way it was written twice in this codebase was not:
|
|
7
|
+
*
|
|
8
|
+
* try { db.exec(sql); } catch { }
|
|
9
|
+
*
|
|
10
|
+
* A bare catch cannot tell "already present" — the expected, benign case, which happens on every
|
|
11
|
+
* start after the first — from a schema that is actually broken. So a real failure produced no log
|
|
12
|
+
* line, no throw, and no symptom at the point of failure. The only evidence would be every later
|
|
13
|
+
* query on that column failing, in a different subsystem, with a message that names neither the
|
|
14
|
+
* migration nor the table.
|
|
15
|
+
*
|
|
16
|
+
* That matters most exactly where it is least observable: the FIRST run on a new machine. A second
|
|
17
|
+
* operator, or a fresh database, is where a migration executes for real — and it was the one place
|
|
18
|
+
* the code was guaranteed to say nothing.
|
|
19
|
+
*
|
|
20
|
+
* So: match the benign case by its message and return; anything else is logged under its own event
|
|
21
|
+
* and rethrown. Rethrowing is the deliberate half. If the column cannot be added, every query that
|
|
22
|
+
* reads it fails anyway — the choice is not between working and failing, it is between failing at
|
|
23
|
+
* startup with the cause named and failing later somewhere else with the cause lost.
|
|
24
|
+
*/
|
|
25
|
+
import type { Logger } from "./types.js";
|
|
26
|
+
/**
|
|
27
|
+
* Run one `ADD COLUMN`, treating "already present" as success and everything else as a fault.
|
|
28
|
+
*
|
|
29
|
+
* `table` and `column` are for the log line only — the SQL is the authority. They are separate
|
|
30
|
+
* arguments rather than parsed out of it because a regex over SQL is a second, worse parser, and
|
|
31
|
+
* the caller already knows both.
|
|
32
|
+
*/
|
|
33
|
+
export declare function addColumnIfMissing(db: {
|
|
34
|
+
exec(sql: string): void;
|
|
35
|
+
}, logger: Logger, input: {
|
|
36
|
+
table: string;
|
|
37
|
+
column: string;
|
|
38
|
+
sql: string;
|
|
39
|
+
}): void;
|
|
40
|
+
//# sourceMappingURL=column-birth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"column-birth.d.ts","sourceRoot":"","sources":["../src/column-birth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAYzC;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE;IAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACpD,IAAI,CAgBN"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COLUMN BIRTH — adding a column to a table an operator already holds data in.
|
|
3
|
+
*
|
|
4
|
+
* `ALTER TABLE … ADD COLUMN` throws when the column is already there, and that throw is the guard:
|
|
5
|
+
* it is how a birth-gated migration stays idempotent without a version table nobody maintains. The
|
|
6
|
+
* pattern is right. The way it was written twice in this codebase was not:
|
|
7
|
+
*
|
|
8
|
+
* try { db.exec(sql); } catch { }
|
|
9
|
+
*
|
|
10
|
+
* A bare catch cannot tell "already present" — the expected, benign case, which happens on every
|
|
11
|
+
* start after the first — from a schema that is actually broken. So a real failure produced no log
|
|
12
|
+
* line, no throw, and no symptom at the point of failure. The only evidence would be every later
|
|
13
|
+
* query on that column failing, in a different subsystem, with a message that names neither the
|
|
14
|
+
* migration nor the table.
|
|
15
|
+
*
|
|
16
|
+
* That matters most exactly where it is least observable: the FIRST run on a new machine. A second
|
|
17
|
+
* operator, or a fresh database, is where a migration executes for real — and it was the one place
|
|
18
|
+
* the code was guaranteed to say nothing.
|
|
19
|
+
*
|
|
20
|
+
* So: match the benign case by its message and return; anything else is logged under its own event
|
|
21
|
+
* and rethrown. Rethrowing is the deliberate half. If the column cannot be added, every query that
|
|
22
|
+
* reads it fails anyway — the choice is not between working and failing, it is between failing at
|
|
23
|
+
* startup with the cause named and failing later somewhere else with the cause lost.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* SQLite's wording for "this column is already here", which is the whole benign case.
|
|
27
|
+
*
|
|
28
|
+
* Matched on the MESSAGE rather than a code because the driver surfaces a plain `Error`. Anchored
|
|
29
|
+
* to the phrase rather than the column name so one expression covers every call site — and
|
|
30
|
+
* deliberately NOT a loose `/duplicate/`, which would also swallow a duplicate-table or
|
|
31
|
+
* duplicate-index failure that has nothing to do with this column.
|
|
32
|
+
*/
|
|
33
|
+
const ALREADY_PRESENT = /duplicate column name/i;
|
|
34
|
+
/**
|
|
35
|
+
* Run one `ADD COLUMN`, treating "already present" as success and everything else as a fault.
|
|
36
|
+
*
|
|
37
|
+
* `table` and `column` are for the log line only — the SQL is the authority. They are separate
|
|
38
|
+
* arguments rather than parsed out of it because a regex over SQL is a second, worse parser, and
|
|
39
|
+
* the caller already knows both.
|
|
40
|
+
*/
|
|
41
|
+
export function addColumnIfMissing(db, logger, input) {
|
|
42
|
+
try {
|
|
43
|
+
db.exec(input.sql);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
47
|
+
if (ALREADY_PRESENT.test(message))
|
|
48
|
+
return;
|
|
49
|
+
// NAMED, at error, before the rethrow — so the cause is in the log even if something upstream
|
|
50
|
+
// catches the throw and reports it as a generic startup failure.
|
|
51
|
+
logger.error("db.column_birth.failed", {
|
|
52
|
+
table: input.table,
|
|
53
|
+
column: input.column,
|
|
54
|
+
sql: input.sql,
|
|
55
|
+
error: message,
|
|
56
|
+
});
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=column-birth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"column-birth.js","sourceRoot":"","sources":["../src/column-birth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH;;;;;;;GAOG;AACH,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,EAA+B,EAC/B,MAAc,EACd,KAAqD;IAErD,IAAI,CAAC;QACH,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO;QAC1C,8FAA8F;QAC9F,iEAAiE;QACjE,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE;YACrC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,KAAK,EAAE,OAAO;SACf,CAAC,CAAC;QACH,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|
package/dist/daemon.js
CHANGED
|
@@ -3333,6 +3333,48 @@ async function startDaemonHoldingLock(config, singletonLock) {
|
|
|
3333
3333
|
// `0x00` domain prefix, so a bare hash is discarded at the authenticity check.
|
|
3334
3334
|
return { bytes, hash: wireContentHash(bytes) };
|
|
3335
3335
|
},
|
|
3336
|
+
// The owner KEY, not the agent name — every document row is scoped by our own pubkey hex
|
|
3337
|
+
// (M14-D5), and the store query behind this reads that column. Passing the name here
|
|
3338
|
+
// returns no rows and the wait times out on every delivery.
|
|
3339
|
+
awaitAck: async (envelopeHash, timeoutMs) => {
|
|
3340
|
+
const ownerKey = documentOwnerKeyFor(agentName);
|
|
3341
|
+
if (ownerKey === null) {
|
|
3342
|
+
// NOT "the peer stayed silent". `false` means the grace expired with no answer, and the
|
|
3343
|
+
// caller logs exactly that — `graceMs: 10000`, a claim that ten seconds elapsed when
|
|
3344
|
+
// none did, about a peer that was never asked. A delivery worker running for an agent
|
|
3345
|
+
// whose own pubkey cannot be resolved is a wiring bug, and it says so here rather than
|
|
3346
|
+
// arriving downstream dressed as a fact about the counterparty. Same distinction
|
|
3347
|
+
// `abandoned_at` exists to keep: giving up is our decision, not evidence about them.
|
|
3348
|
+
logger.error("document.delivery.ack_wait_unwired", { agentName, envelopeHash });
|
|
3349
|
+
return null;
|
|
3350
|
+
}
|
|
3351
|
+
return documentLayer.awaitAck(ownerKey, envelopeHash, timeoutMs);
|
|
3352
|
+
},
|
|
3353
|
+
drainHeld: async (sessionId, correlationId) => {
|
|
3354
|
+
// ONLY WHEN THERE IS A GAP. `sealReadiness` already answers exactly this question, and
|
|
3355
|
+
// gating on it keeps the ordinary delivery — the overwhelming majority — free of a relay
|
|
3356
|
+
// round trip it does not need.
|
|
3357
|
+
const readiness = sessionNodeManager.sealReadiness(agentName, sessionId);
|
|
3358
|
+
if (readiness.heldCount === 0 && readiness.missingLeaves === 0)
|
|
3359
|
+
return;
|
|
3360
|
+
logger.info("document.delivery.drain_held", {
|
|
3361
|
+
agentName,
|
|
3362
|
+
sessionId,
|
|
3363
|
+
heldCount: readiness.heldCount,
|
|
3364
|
+
missingLeaves: readiness.missingLeaves,
|
|
3365
|
+
correlationId,
|
|
3366
|
+
});
|
|
3367
|
+
await autoRecoverForAgent(agentName, "delivery_ack_grace").catch((err) => {
|
|
3368
|
+
// CONTAINED. A recovery that fails leaves the ack held and the grace expires — the same
|
|
3369
|
+
// outcome as before, and never a reason to fail a delivery whose content already left.
|
|
3370
|
+
logger.warn("document.delivery.drain_held_failed", {
|
|
3371
|
+
agentName,
|
|
3372
|
+
sessionId,
|
|
3373
|
+
correlationId,
|
|
3374
|
+
error: err instanceof Error ? err.message : String(err),
|
|
3375
|
+
});
|
|
3376
|
+
});
|
|
3377
|
+
},
|
|
3336
3378
|
});
|
|
3337
3379
|
documentTransports.set(agentName, transport);
|
|
3338
3380
|
return transport;
|