@cotal-ai/core 0.15.0 → 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.
- package/dist/acls.d.ts.map +1 -1
- package/dist/acls.js +31 -11
- package/dist/acls.js.map +1 -1
- package/dist/channels.d.ts.map +1 -1
- package/dist/channels.js +14 -5
- package/dist/channels.js.map +1 -1
- package/dist/endpoint.d.ts +33 -4
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +162 -19
- package/dist/endpoint.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/kv-scan.d.ts +97 -0
- package/dist/kv-scan.d.ts.map +1 -0
- package/dist/kv-scan.js +184 -0
- package/dist/kv-scan.js.map +1 -0
- package/dist/members.d.ts +8 -4
- package/dist/members.d.ts.map +1 -1
- package/dist/members.js +19 -9
- package/dist/members.js.map +1 -1
- package/package.json +1 -1
|
@@ -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"}
|
package/dist/kv-scan.js
ADDED
|
@@ -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":"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"}
|
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.
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* a
|
|
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;
|
package/dist/members.d.ts.map
CHANGED
|
@@ -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;
|
|
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.
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* a
|
|
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
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
}
|
package/dist/members.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"members.js","sourceRoot":"","sources":["../src/members.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,GAAG,EAAW,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"members.js","sourceRoot":"","sources":["../src/members.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED