@cotal-ai/delivery 0.10.1 → 0.11.1
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/delivery.d.ts.map +1 -1
- package/dist/delivery.js +55 -14
- package/dist/delivery.js.map +1 -1
- package/dist/evict-exec.d.ts +11 -0
- package/dist/evict-exec.d.ts.map +1 -0
- package/dist/evict-exec.js +40 -0
- package/dist/evict-exec.js.map +1 -0
- package/dist/membership.d.ts.map +1 -1
- package/dist/membership.js +4 -1
- package/dist/membership.js.map +1 -1
- package/package.json +6 -3
package/dist/delivery.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAEA,OAAO,EAUL,KAAK,UAAU,EAChB,MAAM,gBAAgB,CAAC;AA8DxB;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAmIjE"}
|
package/dist/delivery.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { CotalEndpoint, DEFAULT_SERVER, LEASE_TTL_MS, isReachable, mintCreds, newIdentity, } from "@cotal-ai/core";
|
|
3
|
+
import { CotalEndpoint, DEFAULT_SERVER, LEASE_TTL_MS, credsClaims, idFromCreds, isReachable, mintCreds, newIdentity, } from "@cotal-ai/core";
|
|
4
4
|
import { authDir, findCotalRoot, loadSpaceAuth } from "@cotal-ai/workspace";
|
|
5
5
|
import { startMembership } from "./membership.js";
|
|
6
|
+
import { executeEviction } from "./evict-exec.js";
|
|
6
7
|
/** Default location of the pre-minted scoped `delivery` creds the daemon loads (the CLI's
|
|
7
8
|
* `ensureDelivery` mints it once from the signer and writes it here, then launches the daemon WITHOUT
|
|
8
9
|
* signer access). A container mounts it read-only and passes `--creds`. */
|
|
@@ -11,19 +12,46 @@ function deliveryCredsPath() {
|
|
|
11
12
|
}
|
|
12
13
|
/** The daemon's scoped `delivery` creds — the PRODUCTION path reads a PRE-MINTED file (`--creds` or the
|
|
13
14
|
* default `.cotal/delivery.creds`, written by the CLI's `ensureDelivery` setup helper) and NEVER touches
|
|
14
|
-
* the signer: this runtime does not load `.cotal/auth`.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* the signer: this runtime does not load `.cotal/auth`. Returned as `{ initial, source }`: the SOURCE
|
|
16
|
+
* is the D5 slice-5 class-2 reload seam — the endpoint re-invokes it at 75% of each JWT's lifetime, so
|
|
17
|
+
* the daemon renews from the renewal-owner-re-signed file without a restart or a signal. Adoption is
|
|
18
|
+
* IDEMPOTENT on an unchanged file while its cred is still ahead of the renewal point (explicit reload
|
|
19
|
+
* may race the backstop); past it, an unchanged file is a MISSED remint, surfaced loudly with the
|
|
20
|
+
* exact repair — never a silent ride to expiry. A standalone dev run
|
|
21
|
+
* with no creds file can opt into `--dev-mint`, which loads the local signer and self-remints a scoped
|
|
22
|
+
* `delivery` cred (one stable identity) — LOUDLY flagged as dev-only, never the production contract. */
|
|
17
23
|
async function loadDeliveryCreds(v) {
|
|
18
24
|
const path = v.creds ?? deliveryCredsPath();
|
|
19
|
-
if (existsSync(path))
|
|
20
|
-
|
|
25
|
+
if (existsSync(path)) {
|
|
26
|
+
const initial = readFileSync(path, "utf8");
|
|
27
|
+
let last; // set by the FIRST source call (the endpoint's initial fetch)
|
|
28
|
+
return {
|
|
29
|
+
initial,
|
|
30
|
+
source: async () => {
|
|
31
|
+
const content = readFileSync(path, "utf8");
|
|
32
|
+
if (last !== undefined && content === last) {
|
|
33
|
+
// Unchanged file: adoption is IDEMPOTENT while the cred is still ahead of its renewal
|
|
34
|
+
// point (the explicit reload may race the 75% backstop that just adopted the same
|
|
35
|
+
// re-sign — both succeeding is correct). Past the renewal point an unchanged file is a
|
|
36
|
+
// MISSED remint: fail loud with the exact repair, never a silent ride to expiry.
|
|
37
|
+
const { iat, exp } = credsClaims(content);
|
|
38
|
+
if (typeof exp === "number" && typeof iat === "number" && Date.now() / 1000 < iat + 0.75 * (exp - iat))
|
|
39
|
+
return content;
|
|
40
|
+
throw new Error(`${path} still holds the previous cred — the renewal owner has not re-signed it (the manager re-signs + reloads every half-TTL); run \`cotal doctor auth --fix\`, or restart the mesh's manager, before this JWT expires`);
|
|
41
|
+
}
|
|
42
|
+
last = content;
|
|
43
|
+
return content;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
21
47
|
if (v["dev-mint"] !== undefined) {
|
|
22
48
|
const auth = loadSpaceAuth(authDir(findCotalRoot()));
|
|
23
49
|
if (!auth)
|
|
24
50
|
throw new Error("delivery --dev-mint: no .cotal/auth here to mint from");
|
|
25
51
|
console.error("⚠ delivery: --dev-mint — minting a scoped delivery cred from the LOCAL SIGNER (DEV ONLY; production mounts a pre-minted delivery.creds and the daemon never sees the signer)");
|
|
26
|
-
|
|
52
|
+
const identity = newIdentity(); // stable across self-remints — the endpoint pins it
|
|
53
|
+
const initial = await mintCreds(auth, identity, "delivery");
|
|
54
|
+
return { initial, source: () => mintCreds(auth, identity, "delivery") };
|
|
27
55
|
}
|
|
28
56
|
throw new Error(`delivery: no scoped creds at ${path}. Launch via \`cotal setup\`/\`cotal go\` (the setup helper mints + writes it), or pass --creds <file>; for a standalone dev run use --dev-mint.`);
|
|
29
57
|
}
|
|
@@ -50,19 +78,23 @@ export async function runDelivery(args) {
|
|
|
50
78
|
throw new Error("delivery: --space is required (the scoped creds file does not encode it)");
|
|
51
79
|
const server = v.server ?? DEFAULT_SERVER;
|
|
52
80
|
const creds = await loadDeliveryCreds(v); // pre-minted scoped cred; NO signer/loadSpaceAuth in this path
|
|
53
|
-
|
|
81
|
+
let latestCreds = creds.initial; // freshest renewal — the broker-reachability poll below presents it
|
|
82
|
+
if (!(await isReachable(server, { creds: latestCreds }))) {
|
|
54
83
|
console.error(`✗ delivery: can't reach NATS at ${server}. Run: cotal up`);
|
|
55
84
|
process.exit(1);
|
|
56
85
|
}
|
|
57
86
|
const ep = new CotalEndpoint({
|
|
58
87
|
space,
|
|
59
88
|
servers: server,
|
|
60
|
-
|
|
89
|
+
// The RELOAD seam (D5 slice 5 class 2): the endpoint re-invokes the source at 75% of each JWT's
|
|
90
|
+
// lifetime and swaps the connection onto the re-signed file — bounded delivery creds renew with
|
|
91
|
+
// no daemon restart. The explicit card.id pins the daemon's nkey across renewals.
|
|
92
|
+
creds: async () => (latestCreds = await creds.source()),
|
|
61
93
|
channels: [],
|
|
62
94
|
consume: false, // it pulls the Plane-3 consumers itself; no agent live-tail
|
|
63
95
|
watchPresence: true, // read the roster for @mention resolution …
|
|
64
96
|
registerPresence: false, // … but NEVER publish the daemon onto the roster (it's infra, not a peer)
|
|
65
|
-
card: { name: "delivery", role: "delivery", kind: "endpoint" },
|
|
97
|
+
card: { id: idFromCreds(creds.initial), name: "delivery", role: "delivery", kind: "endpoint" },
|
|
66
98
|
});
|
|
67
99
|
ep.on("error", (e) => console.error(`! delivery endpoint: ${e.message}`));
|
|
68
100
|
await ep.start();
|
|
@@ -79,9 +111,19 @@ export async function runDelivery(args) {
|
|
|
79
111
|
process.exit(1);
|
|
80
112
|
return;
|
|
81
113
|
}
|
|
114
|
+
// Broker-sourced graph membership handle — declared BEFORE Plane-3 so the delivery-admin reload
|
|
115
|
+
// hook below can close over it (it starts further down; the closure reads it live).
|
|
116
|
+
let membership;
|
|
82
117
|
// Host Plane-3 (fan-out writer + trusted reader) AND serve the ctl.delivery runtime durable ops. The
|
|
83
|
-
// reader re-authorizes each entry against the durable ACL registry, read FRESH per entry.
|
|
84
|
-
|
|
118
|
+
// reader re-authorizes each entry against the durable ACL registry, read FRESH per entry. The
|
|
119
|
+
// delivery-admin rail's `reloadCreds` (explicit class-2 adoption) also reloads the membership feed's
|
|
120
|
+
// rw connection via this hook.
|
|
121
|
+
await ep.startPlane3((owner) => ep.aclForOwner(owner), {
|
|
122
|
+
reloadMembershipCreds: async () => membership ? membership.reloadRwCreds() : "membership feed not running (nothing to reload)",
|
|
123
|
+
// Live-eviction executor (D5 slice 6): per-call $SYS observer/evictor connections; refuses
|
|
124
|
+
// loudly on a pre-evictor space. Rare repair/flip step — never a standing $SYS conn here.
|
|
125
|
+
evictPrincipal: (principal) => executeEviction(server, principal),
|
|
126
|
+
});
|
|
85
127
|
// Flip the lease to READY only now — after the loops + ctl.delivery responder are bound — so readiness
|
|
86
128
|
// waiters (ensureDelivery) and the cotal_channels health surface see "ready" iff the responder is up,
|
|
87
129
|
// not merely that the single-flight slot was claimed.
|
|
@@ -93,7 +135,6 @@ export async function runDelivery(args) {
|
|
|
93
135
|
// Broker-sourced graph membership: a SEPARATE module on its OWN connections (system-account CONNZ
|
|
94
136
|
// reader + data-account feed writer), isolated from Plane-3. Fail-soft — a missing cred / start error
|
|
95
137
|
// logs and the graph degrades to traffic-only; Plane-3 delivery is never affected.
|
|
96
|
-
let membership;
|
|
97
138
|
try {
|
|
98
139
|
membership = await startMembership({ space, server });
|
|
99
140
|
}
|
|
@@ -145,7 +186,7 @@ export async function runDelivery(args) {
|
|
|
145
186
|
const brokerWatch = setInterval(() => {
|
|
146
187
|
if (stopping)
|
|
147
188
|
return;
|
|
148
|
-
void isReachable(server, { creds })
|
|
189
|
+
void isReachable(server, { creds: latestCreds })
|
|
149
190
|
.then((ok) => {
|
|
150
191
|
if (ok) {
|
|
151
192
|
lastReachable = Date.now();
|
package/dist/delivery.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,aAAa,EACb,cAAc,EACd,YAAY,EACZ,WAAW,EACX,SAAS,EACT,WAAW,GAGZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIlD;;4EAE4E;AAC5E,SAAS,iBAAiB;IACxB,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AAC3D,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type EvictionResult } from "@cotal-ai/core";
|
|
2
|
+
/**
|
|
3
|
+
* The delivery daemon's LIVE-EVICTION executor (D5 slice 6, on the privileged delivery-admin rail):
|
|
4
|
+
* force-drop a denied principal's live connections via the core scan→KICK→verify primitive. The two
|
|
5
|
+
* $SYS creds are the real gate — the KICK-only evictor and the CONNZ observer, both minted only at a
|
|
6
|
+
* fresh `up` — and core opens them PER CALL (eviction is a rare repair/flip step, never a standing
|
|
7
|
+
* $SYS connection in the daemon). A space provisioned before the evictor existed refuses loudly with
|
|
8
|
+
* the regeneration step — deny-new-only (durable reauth) remains its honest posture.
|
|
9
|
+
*/
|
|
10
|
+
export declare function executeEviction(server: string, principal: string): Promise<EvictionResult>;
|
|
11
|
+
//# sourceMappingURL=evict-exec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evict-exec.d.ts","sourceRoot":"","sources":["../src/evict-exec.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAGxB;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CA2BhG"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { evictDeniedPrincipalWithCreds, isPrincipalOwnerToken, parsePrincipalKey, } from "@cotal-ai/core";
|
|
4
|
+
import { findCotalRoot } from "@cotal-ai/workspace";
|
|
5
|
+
/**
|
|
6
|
+
* The delivery daemon's LIVE-EVICTION executor (D5 slice 6, on the privileged delivery-admin rail):
|
|
7
|
+
* force-drop a denied principal's live connections via the core scan→KICK→verify primitive. The two
|
|
8
|
+
* $SYS creds are the real gate — the KICK-only evictor and the CONNZ observer, both minted only at a
|
|
9
|
+
* fresh `up` — and core opens them PER CALL (eviction is a rare repair/flip step, never a standing
|
|
10
|
+
* $SYS connection in the daemon). A space provisioned before the evictor existed refuses loudly with
|
|
11
|
+
* the regeneration step — deny-new-only (durable reauth) remains its honest posture.
|
|
12
|
+
*/
|
|
13
|
+
export async function executeEviction(server, principal) {
|
|
14
|
+
// Fail-closed principal validation — the KICK targets come from the observer's own CONNZ scan,
|
|
15
|
+
// but the FILTER must be a REAL principal: syntax alone is not enough, because CONNZ attribution
|
|
16
|
+
// only ever surfaces owners that pass isPrincipalOwnerToken (`local` / derived `u_…`), so a
|
|
17
|
+
// syntactically-valid non-principal like `foo.bar` could scan completely, match nothing, and
|
|
18
|
+
// return a HEALTHY verified no-op — false confidence for a typo'd or old-shape target (the
|
|
19
|
+
// critic's slice-6 catch). Same owner boundary as attribution, refused loudly instead.
|
|
20
|
+
const parsed = parsePrincipalKey(principal);
|
|
21
|
+
if (!parsed || !isPrincipalOwnerToken(parsed.owner))
|
|
22
|
+
throw new Error(`evictPrincipal: "${principal}" is not a real owner.actor principal (owner must be \`local\` or a derived \`u_…\` token — the only shapes CONNZ attribution can surface)`);
|
|
23
|
+
const dir = join(findCotalRoot(), ".cotal");
|
|
24
|
+
const obsPath = join(dir, "membership-observer.creds");
|
|
25
|
+
const evPath = join(dir, "connection-evictor.creds");
|
|
26
|
+
const cfgPath = join(dir, "membership.json");
|
|
27
|
+
if (!existsSync(obsPath) || !existsSync(evPath) || !existsSync(cfgPath))
|
|
28
|
+
throw new Error("evictPrincipal: the $SYS observer/evictor creds are not provisioned here (a space created before live eviction) — regenerate the space auth (`cotal down` + fresh `cotal up`); until then removal is deny-new-only (durable reauth)");
|
|
29
|
+
const accountId = JSON.parse(readFileSync(cfgPath, "utf8")).accountId;
|
|
30
|
+
if (!accountId)
|
|
31
|
+
throw new Error("evictPrincipal: .cotal/membership.json has no accountId");
|
|
32
|
+
return evictDeniedPrincipalWithCreds({
|
|
33
|
+
servers: server,
|
|
34
|
+
observerCreds: readFileSync(obsPath, "utf8"),
|
|
35
|
+
evictorCreds: readFileSync(evPath, "utf8"),
|
|
36
|
+
accountId,
|
|
37
|
+
principal,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=evict-exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evict-exec.js","sourceRoot":"","sources":["../src/evict-exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,6BAA6B,EAC7B,qBAAqB,EACrB,iBAAiB,GAElB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc,EAAE,SAAiB;IACrE,+FAA+F;IAC/F,iGAAiG;IACjG,4FAA4F;IAC5F,6FAA6F;IAC7F,2FAA2F;IAC3F,uFAAuF;IACvF,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,KAAK,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,oBAAoB,SAAS,4IAA4I,CAAC,CAAC;IAC7L,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,0BAA0B,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;IAC7C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QACrE,MAAM,IAAI,KAAK,CACb,qOAAqO,CACtO,CAAC;IACJ,MAAM,SAAS,GAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAA4B,CAAC,SAAS,CAAC;IAClG,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC3F,OAAO,6BAA6B,CAAC;QACnC,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC;QAC5C,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC;QAC1C,SAAS;QACT,SAAS;KACV,CAAC,CAAC;AACL,CAAC"}
|
package/dist/membership.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"membership.d.ts","sourceRoot":"","sources":["../src/membership.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGhF;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"membership.d.ts","sourceRoot":"","sources":["../src/membership.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGhF;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAiCxH"}
|
package/dist/membership.js
CHANGED
|
@@ -31,8 +31,11 @@ export async function startMembership(opts) {
|
|
|
31
31
|
servers: opts.server,
|
|
32
32
|
space: opts.space,
|
|
33
33
|
accountId,
|
|
34
|
+
// Observer is rotation-renewed ($SYS): a static read — its renewal is a system rotation + restart.
|
|
34
35
|
observerCreds: readFileSync(obsPath, "utf8"),
|
|
35
|
-
|
|
36
|
+
// rw is class-2 standing-renewable: re-read per (re)connect attempt, so the manager's re-signed
|
|
37
|
+
// file renews the feed's data connection across the broker's expiry-close (D5 slice 5).
|
|
38
|
+
rwCreds: () => readFileSync(rwPath, "utf8"),
|
|
36
39
|
intervalMs,
|
|
37
40
|
});
|
|
38
41
|
console.log(`✓ membership feed up (broker-sourced channel membership) — space ${opts.space}`);
|
package/dist/membership.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"membership.js","sourceRoot":"","sources":["../src/membership.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAA6B,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAuC;IAC3E,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;IAE7C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxE,OAAO,CAAC,KAAK,CACX,+PAA+P,CAChQ,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,SAAS,GAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAA4B,CAAC,SAAS,CAAC;IAClG,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,mGAAmG,CAAC,CAAC;QACnH,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,IAAI,SAAS,CAAC,CAAC,oBAAoB;IACtG,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC;QACvC,OAAO,EAAE,IAAI,CAAC,MAAM;QACpB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS;QACT,aAAa,EAAE,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC;QAC5C,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"membership.js","sourceRoot":"","sources":["../src/membership.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAA6B,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAuC;IAC3E,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;IAE7C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxE,OAAO,CAAC,KAAK,CACX,+PAA+P,CAChQ,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,SAAS,GAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAA4B,CAAC,SAAS,CAAC;IAClG,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,mGAAmG,CAAC,CAAC;QACnH,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,IAAI,SAAS,CAAC,CAAC,oBAAoB;IACtG,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC;QACvC,OAAO,EAAE,IAAI,CAAC,MAAM;QACpB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS;QACT,mGAAmG;QACnG,aAAa,EAAE,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC;QAC5C,gGAAgG;QAChG,wFAAwF;QACxF,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC;QAC3C,UAAU;KACX,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,oEAAoE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9F,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cotal-ai/delivery",
|
|
3
3
|
"description": "Cotal delivery daemon: the server-side Plane-3 durable backstop (fan-out writer + trusted reader + membership/ACL authority), a scoped least-privilege NATS client co-located with the broker.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.11.1",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@cotal-ai/core": "0.
|
|
22
|
-
"@cotal-ai/workspace": "0.
|
|
21
|
+
"@cotal-ai/core": "0.11.1",
|
|
22
|
+
"@cotal-ai/workspace": "0.11.1"
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"dist"
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@nats-io/transport-node": "^3.4.0"
|
|
32
|
+
},
|
|
30
33
|
"scripts": {
|
|
31
34
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
32
35
|
"build": "tsc -p tsconfig.json"
|