@cotal-ai/core 0.14.11 → 0.16.0

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.
@@ -0,0 +1,97 @@
1
+ import type { KV, KvEntry } from "@nats-io/kv";
2
+ /**
3
+ * The ONE sanctioned way to read every live entry of a KV bucket.
4
+ *
5
+ * ## Why this exists
6
+ *
7
+ * Four call sites independently open-coded a whole-bucket read. `readMembership` had the worst
8
+ * shape: enumerate keys, then fetch each key's value. `kv.keys()` is one ordered-consumer pass, but
9
+ * every yielded key then costs a separate `STREAM.MSG.GET` round trip, sequentially. That is O(N)
10
+ * round trips to read N records. It is invisible against a loopback broker and catastrophic anywhere
11
+ * else: 89 membership keys measured 30-34 seconds against a mesh at 534ms RTT, where a single pass is
12
+ * ~3 round trips regardless of N.
13
+ *
14
+ * The other three were already close to a single pass; what they gained is the completeness
15
+ * guarantee below, which none of them had.
16
+ *
17
+ * Fixing the call sites one at a time guarantees a fifth, so no call site may open-code this. That is
18
+ * currently a CONVENTION, not an enforced rule: nothing in the build rejects a new `keys()`-then-
19
+ * `get()` loop.
20
+ *
21
+ * ## Why it owns the pass instead of wrapping `kv.history()`
22
+ *
23
+ * `kv.history()` would deliver values in one pass, but its public iterator does not expose the
24
+ * consumer's `num_pending`. Without it, a caller cannot distinguish an EMPTY bucket from a pass that
25
+ * died before its first message — both arrive as zero entries and a clean end. For membership and
26
+ * ACL reads that ambiguity produces a confident empty set, which is worse than a short one because
27
+ * nothing about it looks wrong.
28
+ *
29
+ * ## What the completeness check guarantees
30
+ *
31
+ * In `@nats-io/kv`, `iter.closed().then(...)` ends an iterator CLEANLY on any mid-stream
32
+ * termination: a dropped connection, a deleted consumer, a server error. Nothing throws. On exactly
33
+ * the high-latency, jittery links this helper exists to serve, a silently truncated read would
34
+ * otherwise be the default failure mode.
35
+ *
36
+ * Because the pass is bound here, both halves are decidable:
37
+ * - EMPTY is proven, not inferred. `num_pending` is read at bind, before any delivery, so an empty
38
+ * result means the bucket (or the filtered subset) really had nothing — never that the pass died
39
+ * before its first message. That distinction is why this does not wrap `history()`, which hides
40
+ * the count: read through that, a dropped link during a filtered ACL scan reported a provisioned
41
+ * principal as having no row, and a durable join was refused as "not provisioned".
42
+ * - COMPLETE means a delivered message reported nothing behind it. An idle heartbeat is NOT
43
+ * accepted as completion, unlike `history()`, whose "a heartbeat means we got all the keys"
44
+ * shortcut is how a stalled pass returns a short list wearing a clean end.
45
+ *
46
+ * Anything else raises {@link IncompleteKvScan}. Treat it as retryable: it says this read did not
47
+ * finish, never that data was lost.
48
+ *
49
+ * ## Why tombstones are carried through the collapse
50
+ *
51
+ * Filtering DEL/PURGE markers DURING iteration resurrects deleted keys: if a key's PUT is delivered
52
+ * and its later DEL is skipped, the stale PUT survives as the "latest". So the collapse keeps
53
+ * markers, picks the greatest revision per key, and only then drops keys whose final state is a
54
+ * marker.
55
+ *
56
+ * This is required for CONCURRENCY, not merely for misconfigured buckets. `DeliverPolicy.All` chases
57
+ * a moving tail, so a key rewritten while the pass drains legitimately appears at two revisions even
58
+ * on a `history: 1` bucket.
59
+ *
60
+ * ## What it deliberately does NOT do
61
+ *
62
+ * It never asserts `status().history === 1`. Greatest-revision-with-tombstones is correct for every
63
+ * `history >= 1`, so a drifted bucket is read correctly rather than refused; throwing on a read
64
+ * because PROVISIONING drifted would turn a bucket-config problem into a mesh-wide outage. Bucket
65
+ * reconcile is a privileged setup concern and needs `STREAM.UPDATE`, which read credentials do not
66
+ * have and must not be given.
67
+ *
68
+ * ## Grant
69
+ *
70
+ * Same broker authority as the `keys()` + `get()` pair it replaces: one ordered/push consumer over
71
+ * `$KV.<bucket>.>`, differing only in `deliver_policy`. Values are not new authority — the existing
72
+ * `keys()` consumer grant could already request bodies. No ACL widening anywhere.
73
+ */
74
+ /** Thrown when a pass ends without reaching its terminal message. The caller decides whether to
75
+ * retry or surface it; what it may NOT do is treat the partial set as the answer. */
76
+ export declare class IncompleteKvScan extends Error {
77
+ readonly bucket: string;
78
+ readonly received: number;
79
+ readonly expected: number;
80
+ constructor(bucket: string, received: number, expected: number);
81
+ }
82
+ /**
83
+ * Every currently-live entry of `kv`, in ONE pass, with values.
84
+ *
85
+ * `filter` narrows the scan to matching keys (NATS subject wildcards), for callers that scan a
86
+ * key prefix rather than the whole bucket. Returns entries whose final operation is a real value;
87
+ * deleted and purged keys are absent.
88
+ *
89
+ * Throws {@link IncompleteKvScan} if the pass is cut short. Returns `[]` for a bucket that is
90
+ * genuinely empty (proven at bind time, not inferred from silence).
91
+ */
92
+ export declare function liveKvEntries(kv: KV, filter?: string | string[]): Promise<KvEntry[]>;
93
+ /** {@link liveKvEntries}, decoded. `decode` returning `undefined` drops the entry — for callers that
94
+ * skip garbled records rather than failing the whole read (the prevailing convention in the
95
+ * registries: one unparseable row must not blind the surface to every other row). */
96
+ export declare function liveKvValues<T>(kv: KV, decode: (e: KvEntry) => T | undefined, filter?: string | string[]): Promise<T[]>;
97
+ //# sourceMappingURL=kv-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv-scan.d.ts","sourceRoot":"","sources":["../src/kv-scan.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,OAAO,EAAgB,MAAM,aAAa,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AAEH;sFACsF;AACtF,qBAAa,gBAAiB,SAAQ,KAAK;IAEvC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAFhB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;CAO5B;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAoE1F;AAED;;sFAEsF;AACtF,wBAAsB,YAAY,CAAC,CAAC,EAClC,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,CAAC,GAAG,SAAS,EACrC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GACzB,OAAO,CAAC,CAAC,EAAE,CAAC,CAOd"}
@@ -0,0 +1,184 @@
1
+ import { Bucket, KvWatchInclude } from "@nats-io/kv/internal";
2
+ /**
3
+ * The ONE sanctioned way to read every live entry of a KV bucket.
4
+ *
5
+ * ## Why this exists
6
+ *
7
+ * Four call sites independently open-coded a whole-bucket read. `readMembership` had the worst
8
+ * shape: enumerate keys, then fetch each key's value. `kv.keys()` is one ordered-consumer pass, but
9
+ * every yielded key then costs a separate `STREAM.MSG.GET` round trip, sequentially. That is O(N)
10
+ * round trips to read N records. It is invisible against a loopback broker and catastrophic anywhere
11
+ * else: 89 membership keys measured 30-34 seconds against a mesh at 534ms RTT, where a single pass is
12
+ * ~3 round trips regardless of N.
13
+ *
14
+ * The other three were already close to a single pass; what they gained is the completeness
15
+ * guarantee below, which none of them had.
16
+ *
17
+ * Fixing the call sites one at a time guarantees a fifth, so no call site may open-code this. That is
18
+ * currently a CONVENTION, not an enforced rule: nothing in the build rejects a new `keys()`-then-
19
+ * `get()` loop.
20
+ *
21
+ * ## Why it owns the pass instead of wrapping `kv.history()`
22
+ *
23
+ * `kv.history()` would deliver values in one pass, but its public iterator does not expose the
24
+ * consumer's `num_pending`. Without it, a caller cannot distinguish an EMPTY bucket from a pass that
25
+ * died before its first message — both arrive as zero entries and a clean end. For membership and
26
+ * ACL reads that ambiguity produces a confident empty set, which is worse than a short one because
27
+ * nothing about it looks wrong.
28
+ *
29
+ * ## What the completeness check guarantees
30
+ *
31
+ * In `@nats-io/kv`, `iter.closed().then(...)` ends an iterator CLEANLY on any mid-stream
32
+ * termination: a dropped connection, a deleted consumer, a server error. Nothing throws. On exactly
33
+ * the high-latency, jittery links this helper exists to serve, a silently truncated read would
34
+ * otherwise be the default failure mode.
35
+ *
36
+ * Because the pass is bound here, both halves are decidable:
37
+ * - EMPTY is proven, not inferred. `num_pending` is read at bind, before any delivery, so an empty
38
+ * result means the bucket (or the filtered subset) really had nothing — never that the pass died
39
+ * before its first message. That distinction is why this does not wrap `history()`, which hides
40
+ * the count: read through that, a dropped link during a filtered ACL scan reported a provisioned
41
+ * principal as having no row, and a durable join was refused as "not provisioned".
42
+ * - COMPLETE means a delivered message reported nothing behind it. An idle heartbeat is NOT
43
+ * accepted as completion, unlike `history()`, whose "a heartbeat means we got all the keys"
44
+ * shortcut is how a stalled pass returns a short list wearing a clean end.
45
+ *
46
+ * Anything else raises {@link IncompleteKvScan}. Treat it as retryable: it says this read did not
47
+ * finish, never that data was lost.
48
+ *
49
+ * ## Why tombstones are carried through the collapse
50
+ *
51
+ * Filtering DEL/PURGE markers DURING iteration resurrects deleted keys: if a key's PUT is delivered
52
+ * and its later DEL is skipped, the stale PUT survives as the "latest". So the collapse keeps
53
+ * markers, picks the greatest revision per key, and only then drops keys whose final state is a
54
+ * marker.
55
+ *
56
+ * This is required for CONCURRENCY, not merely for misconfigured buckets. `DeliverPolicy.All` chases
57
+ * a moving tail, so a key rewritten while the pass drains legitimately appears at two revisions even
58
+ * on a `history: 1` bucket.
59
+ *
60
+ * ## What it deliberately does NOT do
61
+ *
62
+ * It never asserts `status().history === 1`. Greatest-revision-with-tombstones is correct for every
63
+ * `history >= 1`, so a drifted bucket is read correctly rather than refused; throwing on a read
64
+ * because PROVISIONING drifted would turn a bucket-config problem into a mesh-wide outage. Bucket
65
+ * reconcile is a privileged setup concern and needs `STREAM.UPDATE`, which read credentials do not
66
+ * have and must not be given.
67
+ *
68
+ * ## Grant
69
+ *
70
+ * Same broker authority as the `keys()` + `get()` pair it replaces: one ordered/push consumer over
71
+ * `$KV.<bucket>.>`, differing only in `deliver_policy`. Values are not new authority — the existing
72
+ * `keys()` consumer grant could already request bodies. No ACL widening anywhere.
73
+ */
74
+ /** Thrown when a pass ends without reaching its terminal message. The caller decides whether to
75
+ * retry or surface it; what it may NOT do is treat the partial set as the answer. */
76
+ export class IncompleteKvScan extends Error {
77
+ bucket;
78
+ received;
79
+ expected;
80
+ constructor(bucket, received, expected) {
81
+ super(`reading ${bucket} ended after ${received} of ~${expected} entries without reaching the end of the bucket - the connection or consumer died mid-pass. Refusing to return a partial view (a short or empty result here is indistinguishable from a real answer). Retry; if it persists, the link to the broker is dropping.`);
82
+ this.bucket = bucket;
83
+ this.received = received;
84
+ this.expected = expected;
85
+ this.name = "IncompleteKvScan";
86
+ }
87
+ }
88
+ /**
89
+ * Every currently-live entry of `kv`, in ONE pass, with values.
90
+ *
91
+ * `filter` narrows the scan to matching keys (NATS subject wildcards), for callers that scan a
92
+ * key prefix rather than the whole bucket. Returns entries whose final operation is a real value;
93
+ * deleted and purged keys are absent.
94
+ *
95
+ * Throws {@link IncompleteKvScan} if the pass is cut short. Returns `[]` for a bucket that is
96
+ * genuinely empty (proven at bind time, not inferred from silence).
97
+ */
98
+ export async function liveKvEntries(kv, filter) {
99
+ // OWN THE PASS. This deliberately does NOT call `kv.history()`. That helper hides the consumer's
100
+ // bind-time `num_pending`, and without it an empty result is ambiguous: a genuinely empty bucket
101
+ // and a pass that died before its first message look identical. For a FILTERED scan that ambiguity
102
+ // is not academic — `enumerateLiveAclRows` reads this way, so a dropped link mid-scan would report
103
+ // a provisioned principal as having no ACL row at all, and `deliveryJoin` would refuse the join as
104
+ // "not provisioned" rather than as "could not read". A wrong reason on an authorization path.
105
+ //
106
+ // The pinned client exposes what is needed through its `@nats-io/kv/internal` entry point: the
107
+ // `Bucket` implementation carries the JetStream client, the stream name, the consumer-config
108
+ // builder the public watchers use, and the entry decoder. Binding through those keeps this on
109
+ // EXACTLY the ordered push consumer over `$KV.<bucket>.>` that `keys()` and `history()` already
110
+ // use — same subject, same verbs, no new broker authority.
111
+ if (!(kv instanceof Bucket))
112
+ throw new Error(`liveKvEntries needs the @nats-io/kv Bucket implementation to bind its own consumer (got ${kv?.constructor?.name ?? typeof kv}). Refusing to fall back to history(), whose hidden bind-time pending count is exactly the ambiguity this exists to remove.`);
113
+ const bucket = kv;
114
+ const cc = bucket._buildCC(filter ?? ">", KvWatchInclude.AllHistory, { headers_only: false });
115
+ const oc = await bucket.js.consumers.getPushConsumer(bucket.stream, cc);
116
+ // THE BIND-TIME PROOF: `num_pending` is how many messages this consumer will deliver, read before
117
+ // a single one arrives. Zero means the bucket (or the filtered subset) really is empty; it is
118
+ // never inferred from silence.
119
+ // ONE try/finally around EVERY exit. The consumer must be reclaimed on the empty path too: an
120
+ // empty read is not rare, it is the normal answer for a filtered ACL miss, and `readAclForAlias`
121
+ // performs TWO of those per unknown principal. `_buildCC` sets a 5s idle heartbeat, so an
122
+ // undeleted consumer lingers until its inactivity threshold; at alias-check churn that piles up on
123
+ // the broker for no reason.
124
+ const latest = new Map();
125
+ let received = 0;
126
+ let sawTerminal = false;
127
+ let bucketName = bucket.bucket;
128
+ let expected = 0;
129
+ try {
130
+ // THE BIND-TIME PROOF, continued: zero here is the only thing that yields an empty result.
131
+ expected = (await oc.info(true)).num_pending;
132
+ if (expected === 0)
133
+ return [];
134
+ // Greatest revision per key, markers INCLUDED — see the header. Collapsing after the fact is
135
+ // what makes concurrent rewrites and drifted `history` settings both correct.
136
+ const iter = await oc.consume();
137
+ try {
138
+ for await (const m of iter) {
139
+ const e = bucket.jmToWatchEntry(m, false);
140
+ received++;
141
+ bucketName = e.bucket;
142
+ const prior = latest.get(e.key);
143
+ if (prior === undefined || e.revision >= prior.revision)
144
+ latest.set(e.key, e);
145
+ // The ONLY completion signal accepted: a delivered message that says nothing is left behind
146
+ // it. Unlike `history()`, an idle heartbeat is NOT treated as "we got everything" — that
147
+ // shortcut is precisely how a stalled pass returns a short list wearing a clean end.
148
+ if (m.info.pending === 0) {
149
+ sawTerminal = true;
150
+ break;
151
+ }
152
+ }
153
+ }
154
+ finally {
155
+ iter.stop();
156
+ }
157
+ }
158
+ finally {
159
+ await oc.delete().catch(() => { });
160
+ }
161
+ // Fell out without the terminal message: the connection dropped, the consumer was removed, or the
162
+ // stream stalled past the heartbeat. Whatever the cause, this is a PARTIAL view and saying so is
163
+ // the whole point. Filtered and unfiltered obey the same rule, including zero-received.
164
+ if (!sawTerminal)
165
+ throw new IncompleteKvScan(bucketName, received, expected);
166
+ const out = [];
167
+ for (const e of latest.values())
168
+ if (e.operation !== "DEL" && e.operation !== "PURGE")
169
+ out.push(e);
170
+ return out;
171
+ }
172
+ /** {@link liveKvEntries}, decoded. `decode` returning `undefined` drops the entry — for callers that
173
+ * skip garbled records rather than failing the whole read (the prevailing convention in the
174
+ * registries: one unparseable row must not blind the surface to every other row). */
175
+ export async function liveKvValues(kv, decode, filter) {
176
+ const out = [];
177
+ for (const e of await liveKvEntries(kv, filter)) {
178
+ const v = decode(e);
179
+ if (v !== undefined)
180
+ out.push(v);
181
+ }
182
+ return out;
183
+ }
184
+ //# sourceMappingURL=kv-scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv-scan.js","sourceRoot":"","sources":["../src/kv-scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AAEH;sFACsF;AACtF,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAE9B;IACA;IACA;IAHX,YACW,MAAc,EACd,QAAgB,EAChB,QAAgB;QAEzB,KAAK,CACH,WAAW,MAAM,gBAAgB,QAAQ,QAAQ,QAAQ,kQAAkQ,CAC5T,CAAC;QANO,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAQ;QAChB,aAAQ,GAAR,QAAQ,CAAQ;QAKzB,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAM,EAAE,MAA0B;IACpE,iGAAiG;IACjG,iGAAiG;IACjG,mGAAmG;IACnG,mGAAmG;IACnG,mGAAmG;IACnG,8FAA8F;IAC9F,EAAE;IACF,+FAA+F;IAC/F,6FAA6F;IAC7F,8FAA8F;IAC9F,gGAAgG;IAChG,2DAA2D;IAC3D,IAAI,CAAC,CAAC,EAAE,YAAY,MAAM,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,2FAA2F,EAAE,EAAE,WAAW,EAAE,IAAI,IAAI,OAAO,EAAE,6HAA6H,CAC3P,CAAC;IACJ,MAAM,MAAM,GAAW,EAAE,CAAC;IAC1B,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,cAAc,CAAC,UAAU,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9F,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAExE,kGAAkG;IAClG,8FAA8F;IAC9F,+BAA+B;IAC/B,8FAA8F;IAC9F,iGAAiG;IACjG,0FAA0F;IAC1F,mGAAmG;IACnG,4BAA4B;IAC5B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC/C,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IAC/B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,CAAC;QACH,2FAA2F;QAC3F,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC;QAC7C,IAAI,QAAQ,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAE9B,6FAA6F;QAC7F,8EAA8E;QAC9E,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;gBAC1C,QAAQ,EAAE,CAAC;gBACX,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;gBACtB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBAChC,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ;oBAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC9E,4FAA4F;gBAC5F,yFAAyF;gBACzF,qFAAqF;gBACrF,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;oBAAC,WAAW,GAAG,IAAI,CAAC;oBAAC,MAAM;gBAAC,CAAC;YAC1D,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqD,CAAC,CAAC,CAAC;IACvF,CAAC;IACD,kGAAkG;IAClG,iGAAiG;IACjG,wFAAwF;IACxF,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAE7E,MAAM,GAAG,GAAc,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,CAAC,SAAS,KAAK,KAAK,IAAI,CAAC,CAAC,SAAS,KAAK,OAAO;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnG,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;sFAEsF;AACtF,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,EAAM,EACN,MAAqC,EACrC,MAA0B;IAE1B,MAAM,GAAG,GAAQ,EAAE,CAAC;IACpB,KAAK,MAAM,CAAC,IAAI,MAAM,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;QAChD,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,KAAK,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
package/dist/members.d.ts CHANGED
@@ -66,10 +66,14 @@ export declare function deleteMember(kv: KV, channel: string, owner: string, lif
66
66
  /**
67
67
  * Scan the registry, yielding every live (non-deleted) record matching the filter. `channel` →
68
68
  * that channel's members (fan-out's per-channel list); `owner` → that owner's memberships. With no
69
- * filter, every record. MVP does a full `keys()` scan + per-key get + in-code filter — correct and
70
- * fine at local scale; a derived channel→members index is the deferred web-scale optimization
71
- * (the registry stays the single canonical source). Tombstones (with `leaveCursor`) ARE yielded —
72
- * a caller that wants only currently-open memberships filters on `leaveCursor === undefined`.
69
+ * filter, every record. Tombstones (with `leaveCursor`) ARE yielded a caller that wants only
70
+ * currently-open memberships filters on `leaveCursor === undefined`.
71
+ *
72
+ * ONE pass. This was a `keys()` scan plus a sequential per-key `get()`, which cost one round trip
73
+ * per surviving key; a filtered caller paid for the keys that matched, an unfiltered one paid for
74
+ * all of them. The filtering is still done in code (the registry stays the single canonical source;
75
+ * a derived channel→members index remains a separate, deferred decision), but the READ is now
76
+ * independent of record count.
73
77
  */
74
78
  export declare function listMembers(kv: KV, filter?: {
75
79
  channel?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../src/members.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAO,KAAK,EAAE,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;oFACoF;AACpF,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAM/E;AAED;mEACmE;AACnE,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,OAAO,yBAAyB,EAAE,cAAc,EACpD,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,OAAO,CAAC,EAAE,CAAC,CAGb;AAED;;gGAEgG;AAChG,wBAAsB,UAAU,CAC9B,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CAQrE;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuB5F;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAoBvC;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,EAC1B,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAoBvC;AAED;;2FAE2F;AAC3F,wBAAsB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9G;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,EAAE,EACN,MAAM,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAc7B;AAED;;;;;;;;;;;;;gEAagE;AAChE,wBAAgB,eAAe,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAI3E"}
1
+ {"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../src/members.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAO,KAAK,EAAE,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnD;oFACoF;AACpF,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAM/E;AAED;mEACmE;AACnE,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,OAAO,yBAAyB,EAAE,cAAc,EACpD,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,OAAO,CAAC,EAAE,CAAC,CAGb;AAED;;gGAEgG;AAChG,wBAAsB,UAAU,CAC9B,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CAQrE;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuB5F;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAoBvC;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,EAC1B,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAoBvC;AAED;;2FAE2F;AAC3F,wBAAsB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9G;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,EAAE,EACN,MAAM,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAmB7B;AAED;;;;;;;;;;;;;gEAagE;AAChE,wBAAgB,eAAe,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAI3E"}
package/dist/members.js CHANGED
@@ -14,6 +14,7 @@
14
14
  */
15
15
  import { Kvm } from "@nats-io/kv";
16
16
  import { membersBucket, memberKey, parseMemberKey } from "./subjects.js";
17
+ import { liveKvEntries } from "./kv-scan.js";
17
18
  /** Thrown when a write would regress membership generation — a stale/late control reply. Callers
18
19
  * treat this as "a newer membership change already won", not an error to retry. */
19
20
  export class StaleMembershipWrite extends Error {
@@ -148,15 +149,19 @@ export async function deleteMember(kv, channel, owner, lifecycleUid) {
148
149
  /**
149
150
  * Scan the registry, yielding every live (non-deleted) record matching the filter. `channel` →
150
151
  * that channel's members (fan-out's per-channel list); `owner` → that owner's memberships. With no
151
- * filter, every record. MVP does a full `keys()` scan + per-key get + in-code filter — correct and
152
- * fine at local scale; a derived channel→members index is the deferred web-scale optimization
153
- * (the registry stays the single canonical source). Tombstones (with `leaveCursor`) ARE yielded —
154
- * a caller that wants only currently-open memberships filters on `leaveCursor === undefined`.
152
+ * filter, every record. Tombstones (with `leaveCursor`) ARE yielded a caller that wants only
153
+ * currently-open memberships filters on `leaveCursor === undefined`.
154
+ *
155
+ * ONE pass. This was a `keys()` scan plus a sequential per-key `get()`, which cost one round trip
156
+ * per surviving key; a filtered caller paid for the keys that matched, an unfiltered one paid for
157
+ * all of them. The filtering is still done in code (the registry stays the single canonical source;
158
+ * a derived channel→members index remains a separate, deferred decision), but the READ is now
159
+ * independent of record count.
155
160
  */
156
161
  export async function listMembers(kv, filter = {}) {
157
162
  const out = [];
158
- for await (const key of await kv.keys()) {
159
- const parsed = parseMemberKey(key);
163
+ for (const e of await liveKvEntries(kv)) {
164
+ const parsed = parseMemberKey(e.key);
160
165
  if (!parsed)
161
166
  continue;
162
167
  // `parsed.principal` is the member's owner+actor dot-form (membership is per-agent); the
@@ -166,9 +171,14 @@ export async function listMembers(kv, filter = {}) {
166
171
  continue;
167
172
  if (filter.owner !== undefined && parsed.principal !== filter.owner)
168
173
  continue;
169
- const rec = await readMember(kv, parsed.channel, parsed.principal, parsed.lifecycleUid);
170
- if (rec)
171
- out.push(rec.record);
174
+ // Same decode + skip-garbled behaviour readMember applies; the DEL/PURGE half is already handled
175
+ // by the collapse in liveKvEntries.
176
+ try {
177
+ out.push(e.json());
178
+ }
179
+ catch {
180
+ /* skip undecodable */
181
+ }
172
182
  }
173
183
  return out;
174
184
  }
@@ -1 +1 @@
1
- {"version":3,"file":"members.js","sourceRoot":"","sources":["../src/members.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"members.js","sourceRoot":"","sources":["../src/members.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,8 +1,24 @@
1
1
  {
2
2
  "name": "@cotal-ai/core",
3
3
  "description": "The Cotal protocol: endpoint, subjects, message types, the NATS client layer, and the extension contracts.",
4
- "version": "0.14.11",
4
+ "version": "0.16.0",
5
5
  "license": "Apache-2.0",
6
+ "keywords": [
7
+ "cotal",
8
+ "agents",
9
+ "ai-agents",
10
+ "multi-agent",
11
+ "agent-communication",
12
+ "agent-coordination",
13
+ "agent-orchestration",
14
+ "swarm",
15
+ "pubsub",
16
+ "protocol",
17
+ "nats",
18
+ "jetstream",
19
+ "mcp",
20
+ "a2a"
21
+ ],
6
22
  "repository": {
7
23
  "type": "git",
8
24
  "url": "https://github.com/Cotal-AI/Cotal.git",