@cotal-ai/core 0.12.0 → 0.13.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 +31 -7
- package/dist/acls.d.ts.map +1 -1
- package/dist/acls.js +105 -17
- package/dist/acls.js.map +1 -1
- package/dist/agent-file.js +1 -1
- package/dist/agent-file.js.map +1 -1
- package/dist/auth-provider.d.ts +8 -0
- package/dist/auth-provider.d.ts.map +1 -1
- package/dist/auth-provider.js.map +1 -1
- package/dist/backup.d.ts.map +1 -1
- package/dist/backup.js +6 -4
- package/dist/backup.js.map +1 -1
- package/dist/broker-floor.d.ts +34 -0
- package/dist/broker-floor.d.ts.map +1 -0
- package/dist/broker-floor.js +39 -0
- package/dist/broker-floor.js.map +1 -0
- package/dist/canonical.d.ts +24 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +159 -0
- package/dist/canonical.js.map +1 -0
- package/dist/connector.d.ts +4 -0
- package/dist/connector.d.ts.map +1 -1
- package/dist/endpoint-action.d.ts +424 -0
- package/dist/endpoint-action.d.ts.map +1 -0
- package/dist/endpoint-action.js +910 -0
- package/dist/endpoint-action.js.map +1 -0
- package/dist/endpoint-binding.d.ts +344 -0
- package/dist/endpoint-binding.d.ts.map +1 -0
- package/dist/endpoint-binding.js +753 -0
- package/dist/endpoint-binding.js.map +1 -0
- package/dist/endpoint-checkpoint.d.ts +292 -0
- package/dist/endpoint-checkpoint.d.ts.map +1 -0
- package/dist/endpoint-checkpoint.js +818 -0
- package/dist/endpoint-checkpoint.js.map +1 -0
- package/dist/endpoint-cluster.d.ts +95 -0
- package/dist/endpoint-cluster.d.ts.map +1 -0
- package/dist/endpoint-cluster.js +194 -0
- package/dist/endpoint-cluster.js.map +1 -0
- package/dist/endpoint-contract-store.d.ts +90 -0
- package/dist/endpoint-contract-store.d.ts.map +1 -0
- package/dist/endpoint-contract-store.js +348 -0
- package/dist/endpoint-contract-store.js.map +1 -0
- package/dist/endpoint-envelope.d.ts +165 -0
- package/dist/endpoint-envelope.d.ts.map +1 -0
- package/dist/endpoint-envelope.js +346 -0
- package/dist/endpoint-envelope.js.map +1 -0
- package/dist/endpoint-grants.d.ts +123 -0
- package/dist/endpoint-grants.d.ts.map +1 -0
- package/dist/endpoint-grants.js +215 -0
- package/dist/endpoint-grants.js.map +1 -0
- package/dist/endpoint-guard.d.ts +222 -0
- package/dist/endpoint-guard.d.ts.map +1 -0
- package/dist/endpoint-guard.js +468 -0
- package/dist/endpoint-guard.js.map +1 -0
- package/dist/endpoint-handle.d.ts +176 -0
- package/dist/endpoint-handle.d.ts.map +1 -0
- package/dist/endpoint-handle.js +608 -0
- package/dist/endpoint-handle.js.map +1 -0
- package/dist/endpoint-journal.d.ts +225 -0
- package/dist/endpoint-journal.d.ts.map +1 -0
- package/dist/endpoint-journal.js +431 -0
- package/dist/endpoint-journal.js.map +1 -0
- package/dist/endpoint-receipt.d.ts +225 -0
- package/dist/endpoint-receipt.d.ts.map +1 -0
- package/dist/endpoint-receipt.js +417 -0
- package/dist/endpoint-receipt.js.map +1 -0
- package/dist/endpoint-records.d.ts +243 -0
- package/dist/endpoint-records.d.ts.map +1 -0
- package/dist/endpoint-records.js +591 -0
- package/dist/endpoint-records.js.map +1 -0
- package/dist/endpoint-serve.d.ts +176 -0
- package/dist/endpoint-serve.d.ts.map +1 -0
- package/dist/endpoint-serve.js +446 -0
- package/dist/endpoint-serve.js.map +1 -0
- package/dist/endpoint-service.d.ts +518 -0
- package/dist/endpoint-service.d.ts.map +1 -0
- package/dist/endpoint-service.js +973 -0
- package/dist/endpoint-service.js.map +1 -0
- package/dist/endpoint-session.d.ts +398 -0
- package/dist/endpoint-session.d.ts.map +1 -0
- package/dist/endpoint-session.js +834 -0
- package/dist/endpoint-session.js.map +1 -0
- package/dist/endpoint-signing.d.ts +105 -0
- package/dist/endpoint-signing.d.ts.map +1 -0
- package/dist/endpoint-signing.js +190 -0
- package/dist/endpoint-signing.js.map +1 -0
- package/dist/endpoint-subjects.d.ts +222 -0
- package/dist/endpoint-subjects.d.ts.map +1 -0
- package/dist/endpoint-subjects.js +381 -0
- package/dist/endpoint-subjects.js.map +1 -0
- package/dist/endpoint-supervisor.d.ts +19 -0
- package/dist/endpoint-supervisor.d.ts.map +1 -0
- package/dist/endpoint-supervisor.js +12 -0
- package/dist/endpoint-supervisor.js.map +1 -0
- package/dist/endpoint-traits.d.ts +225 -0
- package/dist/endpoint-traits.d.ts.map +1 -0
- package/dist/endpoint-traits.js +469 -0
- package/dist/endpoint-traits.js.map +1 -0
- package/dist/endpoint-verbs.d.ts +277 -0
- package/dist/endpoint-verbs.d.ts.map +1 -0
- package/dist/endpoint-verbs.js +576 -0
- package/dist/endpoint-verbs.js.map +1 -0
- package/dist/endpoint-virtual.d.ts +308 -0
- package/dist/endpoint-virtual.d.ts.map +1 -0
- package/dist/endpoint-virtual.js +440 -0
- package/dist/endpoint-virtual.js.map +1 -0
- package/dist/endpoint-work.d.ts +304 -0
- package/dist/endpoint-work.d.ts.map +1 -0
- package/dist/endpoint-work.js +728 -0
- package/dist/endpoint-work.js.map +1 -0
- package/dist/endpoint.d.ts +66 -22
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +289 -89
- package/dist/endpoint.js.map +1 -1
- package/dist/evict.d.ts +95 -32
- package/dist/evict.d.ts.map +1 -1
- package/dist/evict.js +193 -3
- package/dist/evict.js.map +1 -1
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/lease.d.ts +4 -0
- package/dist/lease.d.ts.map +1 -1
- package/dist/lease.js.map +1 -1
- package/dist/members.d.ts +4 -4
- package/dist/members.d.ts.map +1 -1
- package/dist/members.js +12 -12
- package/dist/members.js.map +1 -1
- package/dist/provision.d.ts +70 -18
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +194 -33
- package/dist/provision.js.map +1 -1
- package/dist/safe-pattern.d.ts +33 -0
- package/dist/safe-pattern.d.ts.map +1 -0
- package/dist/safe-pattern.js +486 -0
- package/dist/safe-pattern.js.map +1 -0
- package/dist/schema-profile.d.ts +93 -0
- package/dist/schema-profile.d.ts.map +1 -0
- package/dist/schema-profile.js +284 -0
- package/dist/schema-profile.js.map +1 -0
- package/dist/streams.d.ts +13 -8
- package/dist/streams.d.ts.map +1 -1
- package/dist/streams.js +35 -18
- package/dist/streams.js.map +1 -1
- package/dist/subjects.d.ts +100 -40
- package/dist/subjects.d.ts.map +1 -1
- package/dist/subjects.js +136 -60
- package/dist/subjects.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.4 record-contract helpers (SPEC §13.4 "Record", §13.7 kinds, §13.9 writer table, §13.12
|
|
3
|
+
* binding) — the registered kind table with its pinned key grammars, the split-key CAS write
|
|
4
|
+
* discipline, and the merged read/watch with the §13.4 staleness rules.
|
|
5
|
+
*
|
|
6
|
+
* A record is stored in the per-space `cotal_records_<space>` KV as TWO keys with independent
|
|
7
|
+
* revisions, `<key>.spec` and `<key>.status` — the split IS the broker-enforced writer boundary
|
|
8
|
+
* (each writer role holds publish authority on its own key only). The single exception is the
|
|
9
|
+
* lifecycle alias HEAD, one atomic unsplit key. Writes are per-key CAS and a lost race is a
|
|
10
|
+
* LOUD `conflict` the caller re-reads and re-decides (§13.8) — deliberately unlike the ACL
|
|
11
|
+
* registry's internal retry, because record writers are fenced principals whose lost CAS is a
|
|
12
|
+
* decision point, never a last-writer-wins policy.
|
|
13
|
+
*
|
|
14
|
+
* These are the primitives the mediated writer principals (§13.9) build on; nothing here grants
|
|
15
|
+
* anything. Untrusted callers never hold raw reads on this bucket — their reads ride the
|
|
16
|
+
* mediator (§13.9 "Mediated reads"); the helpers below run inside trusted principals.
|
|
17
|
+
*/
|
|
18
|
+
import { Kvm } from "@nats-io/kv";
|
|
19
|
+
import { token } from "./subjects.js";
|
|
20
|
+
import { endpointToken, assertBoundedOwner, assertIdToken, assertLifecycleToken, assertPoolToken, } from "./endpoint-subjects.js";
|
|
21
|
+
import { EpEnvelopeError } from "./endpoint-envelope.js";
|
|
22
|
+
/** The per-space records bucket (§13.12): per-key CAS; `allow_direct=true`, but the lifecycle
|
|
23
|
+
* head and every FENCED read are leader-served `STREAM.MSG.GET` (§13.9) — helpers here are the
|
|
24
|
+
* non-fencing paths; a fence is always a revision-pinned CAS WRITE, never a read. */
|
|
25
|
+
export function recordsBucket(space) {
|
|
26
|
+
return `cotal_records_${token(space)}`;
|
|
27
|
+
}
|
|
28
|
+
/** Open the records bucket. Auth mode OPENs the bucket pre-created at space setup; a privileged
|
|
29
|
+
* caller passes `{ create: true }` to CREATE it (setup only). Mirrors {@link openAclRegistry}. */
|
|
30
|
+
export async function openRecordsBucket(nc, space, opts = {}) {
|
|
31
|
+
const kvm = new Kvm(nc);
|
|
32
|
+
return opts.create ? kvm.create(recordsBucket(space)) : kvm.open(recordsBucket(space));
|
|
33
|
+
}
|
|
34
|
+
/** LEADER-SERVED read of one records-KV key: `STREAM.MSG.GET last_by_subj` on the bucket's
|
|
35
|
+
* backing stream, never `kv.get`/`DIRECT.GET`. A FENCING read — a fresh-check a mediated
|
|
36
|
+
* writer acts on before publishing authority state — needs read-your-writes against the
|
|
37
|
+
* leader; the bucket keeps `allow_direct=true` for the non-fencing paths, and a
|
|
38
|
+
* follower-served Direct Get may answer with a superseded revision, which is exactly the
|
|
39
|
+
* staleness a fence must not carry (§13.9, the same rule as {@link readLastFact}).
|
|
40
|
+
* `undefined` = the key has never been written. A DEL/PURGE marker is a DELETION, never
|
|
41
|
+
* absence — fail-closed refusal, the caller reconciles the store. */
|
|
42
|
+
export async function readRecordLeader(jsm, space, key) {
|
|
43
|
+
const bucket = recordsBucket(space);
|
|
44
|
+
let m;
|
|
45
|
+
try {
|
|
46
|
+
m = await jsm.streams.getMessage(`KV_${bucket}`, { last_by_subj: `$KV.${bucket}.${key}` });
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
if (e.code === 10037)
|
|
50
|
+
return undefined; // no message on the subject
|
|
51
|
+
throw e;
|
|
52
|
+
}
|
|
53
|
+
if (!m)
|
|
54
|
+
return undefined;
|
|
55
|
+
const op = m.header?.get("KV-Operation");
|
|
56
|
+
if (op)
|
|
57
|
+
throw new EpEnvelopeError("failed-precondition", `the record ${key} carries a ${op} marker; a deletion is never absence - reconcile the store (SPEC 13.7)`);
|
|
58
|
+
try {
|
|
59
|
+
return { value: JSON.parse(new TextDecoder().decode(m.data)), revision: m.seq };
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
throw new EpEnvelopeError("internal", `record ${key} does not decode as JSON: ${e.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const qEndpoint = { name: "endpoint", assert: (v) => endpointToken(v) };
|
|
66
|
+
const qOwner = (name) => ({ name, assert: (v) => assertBoundedOwner(v, name) });
|
|
67
|
+
const qUid = (name) => ({ name, assert: (v) => assertLifecycleToken(v, name) });
|
|
68
|
+
const qId = (name) => ({ name, assert: (v) => assertIdToken(v, name) });
|
|
69
|
+
/** The lifecycle alias HEAD (§13.7/§13.9): `lifecycle.<owner>.<actor>` — ONE atomic unsplit
|
|
70
|
+
* key, the authoritative current mapping and the only `mappingRevision` source. Activation
|
|
71
|
+
* and terminal retirement serialize on its CAS; a fresh authority read of it is a
|
|
72
|
+
* leader-served `STREAM.MSG.GET` by the trusted mapping-reader, never a follower-served get. */
|
|
73
|
+
export const LIFECYCLE_HEAD = {
|
|
74
|
+
kind: "lifecycle",
|
|
75
|
+
qualifiers: [qOwner("owner"), qOwner("actor")],
|
|
76
|
+
split: false,
|
|
77
|
+
writers: { spec: "minting-manager-commit", status: "minting-manager-commit" },
|
|
78
|
+
mediation: "mediated",
|
|
79
|
+
};
|
|
80
|
+
/** The §13.1 space-global UID RESERVATION (§13.7): `uid.<lifecycleUid>` — ONE atomic unsplit
|
|
81
|
+
* key, create-only and NEVER-DELETED for the life of the space. The KEY is the reservation
|
|
82
|
+
* (the value records the reserving authority + intended alias, audit only): the minting
|
|
83
|
+
* authority wins this create BEFORE any gate or head write, a create conflict BURNS the
|
|
84
|
+
* candidate (the alias head alone cannot reject the same UID under a different alias, and
|
|
85
|
+
* the gate./cred. families key by UID alone), and a DEL/PURGE marker is corruption, never
|
|
86
|
+
* reusable absence. */
|
|
87
|
+
export const UID_RESERVATION = {
|
|
88
|
+
kind: "uid",
|
|
89
|
+
qualifiers: [qUid("lifecycleUid")],
|
|
90
|
+
split: false,
|
|
91
|
+
writers: { spec: "minting-authority", status: "minting-authority" },
|
|
92
|
+
mediation: "mediated",
|
|
93
|
+
};
|
|
94
|
+
/** The fixed sentinel target token for an admission with no target lifecycle (§13.7/§13.8). */
|
|
95
|
+
export const OBLIGATION_EP_SENTINEL = "ep";
|
|
96
|
+
/** The §13.8 TARGET-INDEXED ACCEPTANCE OBLIGATION (§13.7): one atomic unsplit key per
|
|
97
|
+
* acceptance identity, `oblig.<targetUid>.<endpoint>.<cOwner>.<cActor>.<cUid>.<id>` — the ONE
|
|
98
|
+
* durable serialization coordinate on which a durable acceptance/start contends with its
|
|
99
|
+
* authority head's movement (no cross-stream CAS exists). Target-first, so a retirement
|
|
100
|
+
* barrier enumerates `oblig.<targetUid>.>`; an admission under policy with NO target lifecycle
|
|
101
|
+
* keys the row with the fixed sentinel target token `ep` (which the §13.1 UID grammar can
|
|
102
|
+
* never produce), excluded from retirement drains and included in the endpoint's policy drain
|
|
103
|
+
* via `oblig.*.<endpoint>.>`. Create-only winner, monotonic value states
|
|
104
|
+
* (`provisional → accepted → terminal` | `provisional → rejected`), NEVER-DELETED. Writer:
|
|
105
|
+
* the admission mediator ONLY (§13.9; the canonicalizer holds no raw `oblig.` grant). */
|
|
106
|
+
export const OBLIGATION = {
|
|
107
|
+
kind: "oblig",
|
|
108
|
+
qualifiers: [
|
|
109
|
+
{ name: "targetUid", assert: (v) => (v === OBLIGATION_EP_SENTINEL ? v : assertLifecycleToken(v, "targetUid")) },
|
|
110
|
+
qEndpoint, qOwner("cOwner"), qOwner("cActor"), qUid("cUid"), qId("id"),
|
|
111
|
+
],
|
|
112
|
+
split: false,
|
|
113
|
+
writers: { spec: "admission-mediator", status: "admission-mediator" },
|
|
114
|
+
mediation: "mediated",
|
|
115
|
+
};
|
|
116
|
+
/** The §13.6 IMMUTABLE ADMISSION-POLICY VERSION (§13.7): `policy.<endpoint>.<digest-hex>` — one
|
|
117
|
+
* atomic unsplit key per policy version, create-only, NEVER-DELETED, never overwritten.
|
|
118
|
+
* `<digest-hex>` is the SHA-256 hex of the record's canonical value bytes, so the key is
|
|
119
|
+
* SELF-CERTIFYING: a reader re-digests the value it read and refuses a mismatch. The govern
|
|
120
|
+
* head's `enforcedPolicyKey`/`pendingPolicyKey` name keys of exactly this kind, which is what
|
|
121
|
+
* keeps both the enforced and the pending policy readable through a mutation's whole drain
|
|
122
|
+
* window (§13.6). Writer: the provisioner registration path ONLY (§13.9). */
|
|
123
|
+
export const POLICY_VERSION = {
|
|
124
|
+
kind: "policy",
|
|
125
|
+
qualifiers: [qEndpoint, {
|
|
126
|
+
name: "digestHex",
|
|
127
|
+
assert: (v) => {
|
|
128
|
+
if (!/^[0-9a-f]{64}$/.test(v))
|
|
129
|
+
throw new Error(`policy digest ${JSON.stringify(v)} is not 64 lowercase hex chars (SPEC 13.7)`);
|
|
130
|
+
return v;
|
|
131
|
+
},
|
|
132
|
+
}],
|
|
133
|
+
split: false,
|
|
134
|
+
writers: { spec: "provisioner-registration", status: "provisioner-registration" },
|
|
135
|
+
mediation: "mediated",
|
|
136
|
+
};
|
|
137
|
+
/** The §13.1 PER-STREAM RETIREMENT FRONTIERS (§13.7): `frontier.<lifecycleUid>` — ONE atomic
|
|
138
|
+
* unsplit key per retired lifecycle, create-only, NEVER-DELETED, written by the terminal
|
|
139
|
+
* retirement barrier AFTER the obligation drain, the pool cleaner, and the cleaner-credential
|
|
140
|
+
* revoke+evict, and BEFORE the gate/head terminals (§13.1 order). The value records the
|
|
141
|
+
* retirement `opId` and each bounded stream's last sequence at retirement — the cutoffs that
|
|
142
|
+
* bound the predecessor's half-open interval `(activationFrontier, retirementFrontier]`; they
|
|
143
|
+
* are never a successor's start (a successor captures its OWN activation frontier). */
|
|
144
|
+
export const RETIREMENT_FRONTIER = {
|
|
145
|
+
kind: "frontier",
|
|
146
|
+
qualifiers: [qUid("lifecycleUid")],
|
|
147
|
+
split: false,
|
|
148
|
+
writers: { spec: "minting-authority", status: "minting-authority" },
|
|
149
|
+
mediation: "mediated",
|
|
150
|
+
};
|
|
151
|
+
/** The endpoint-wide GOVERNANCE HEAD (§13.7 "a self-published descriptor cannot strip, forge,
|
|
152
|
+
* or downgrade a governed annotation"): `govern.<endpoint>` — ONE atomic unsplit key holding
|
|
153
|
+
* the endpoint's MONOTONIC (append-only) BINDING governed-trait imposition per command, plus
|
|
154
|
+
* the single in-flight registration's PROVISIONAL slot (endpoint-service.ts): the head is the
|
|
155
|
+
* endpoint's registration linearization point — every registration CAS-takes the slot under
|
|
156
|
+
* its frozen gate, holds it through spec publication, and promotes its impositions to binding
|
|
157
|
+
* only after the publish commits. Governance is a HISTORY-bearing, endpoint-wide property, not
|
|
158
|
+
* a per-instance descriptor state: once BOUND, an imposition persists across instances AND
|
|
159
|
+
* across command removal (a tombstone), until an authorized revocation (the D18
|
|
160
|
+
* governance-consent artifact) lifts it — so a re-registration, a fresh instanceId, and a
|
|
161
|
+
* remove→re-add cannot launder a strip.
|
|
162
|
+
*
|
|
163
|
+
* NORMATIVE STATUS: `govern` is NOT yet in the frozen SPEC's §13.7 kind table, §13.9 writer
|
|
164
|
+
* matrix, or §13.12 records-bucket binding — it is implemented ahead of a pending P0
|
|
165
|
+
* reconciliation decision (the spec's governance-continuity requirement implies a durable,
|
|
166
|
+
* shared imposition record the frozen text does not name; multiple provisioners must read one
|
|
167
|
+
* head, so a process-internal store cannot satisfy it). The amendment is recorded in the
|
|
168
|
+
* control-surface STATUS; the operator decides spec changes. */
|
|
169
|
+
export const GOVERN_HEAD = {
|
|
170
|
+
kind: "govern",
|
|
171
|
+
qualifiers: [qEndpoint],
|
|
172
|
+
split: false,
|
|
173
|
+
writers: { spec: "provisioner-registration", status: "provisioner-registration" },
|
|
174
|
+
mediation: "mediated",
|
|
175
|
+
};
|
|
176
|
+
/** The §13.7 core kinds, pinned. Keys: `<kind>.<qualifiers…>` then `.spec`/`.status`. */
|
|
177
|
+
export const RECORD_KINDS = {
|
|
178
|
+
svc: {
|
|
179
|
+
kind: "svc",
|
|
180
|
+
qualifiers: [qEndpoint, qUid("instanceId")],
|
|
181
|
+
split: true,
|
|
182
|
+
writers: { spec: "provisioner-registration", status: "instance-commit-epoch-fenced" },
|
|
183
|
+
mediation: "mediated",
|
|
184
|
+
},
|
|
185
|
+
signer: {
|
|
186
|
+
kind: "signer",
|
|
187
|
+
qualifiers: [qId("keyId")],
|
|
188
|
+
split: true,
|
|
189
|
+
writers: { spec: "operator-registry", status: "operator-registry" },
|
|
190
|
+
mediation: "mediated",
|
|
191
|
+
},
|
|
192
|
+
handle: {
|
|
193
|
+
// Issuer-namespaced (§13.9): two issuers can never collide or cross-revoke.
|
|
194
|
+
kind: "handle",
|
|
195
|
+
qualifiers: [qId("issuerKeyId"), qId("id")],
|
|
196
|
+
split: true,
|
|
197
|
+
writers: { spec: "issuer-create-only", status: "issuer-or-operator-monotonic" },
|
|
198
|
+
mediation: "mediated",
|
|
199
|
+
},
|
|
200
|
+
contracts: {
|
|
201
|
+
// Advisory browse index; `describe` is authoritative. Readers fail loud on invalid state.
|
|
202
|
+
kind: "contracts",
|
|
203
|
+
qualifiers: [qEndpoint],
|
|
204
|
+
split: true,
|
|
205
|
+
writers: { spec: "instance", status: "instance" },
|
|
206
|
+
mediation: "direct",
|
|
207
|
+
},
|
|
208
|
+
goal: {
|
|
209
|
+
kind: "goal",
|
|
210
|
+
qualifiers: [qEndpoint, qOwner("cOwner"), qOwner("cActor"), qUid("cUid"), qId("goalId")],
|
|
211
|
+
split: true,
|
|
212
|
+
writers: { spec: "commit-path", status: "commit-path" },
|
|
213
|
+
mediation: "mediated",
|
|
214
|
+
},
|
|
215
|
+
cp: {
|
|
216
|
+
kind: "cp",
|
|
217
|
+
qualifiers: [qEndpoint, qId("token")],
|
|
218
|
+
split: true,
|
|
219
|
+
writers: { spec: "commit-path", status: "commit-path" },
|
|
220
|
+
mediation: "mediated",
|
|
221
|
+
},
|
|
222
|
+
lease: {
|
|
223
|
+
// The item's acceptance identity (§13.2) keys the lease.
|
|
224
|
+
kind: "lease",
|
|
225
|
+
qualifiers: [qEndpoint, { name: "pool", assert: assertPoolToken }, qOwner("cOwner"), qOwner("cActor"), qUid("cUid"), qId("id")],
|
|
226
|
+
split: true,
|
|
227
|
+
writers: { spec: "pool-owner-lease-command", status: "pool-owner-lease-command" },
|
|
228
|
+
mediation: "mediated",
|
|
229
|
+
},
|
|
230
|
+
lifecycle: {
|
|
231
|
+
// The optional per-UID append-only audit detail — never the authority (that is the HEAD).
|
|
232
|
+
kind: "lifecycle",
|
|
233
|
+
qualifiers: [qOwner("owner"), qOwner("actor"), qUid("lifecycleUid")],
|
|
234
|
+
split: true,
|
|
235
|
+
writers: { spec: "minting-manager-commit", status: "minting-manager-commit" },
|
|
236
|
+
mediation: "mediated",
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
/** The canonical AUTHORITY-CONTROL record kinds (§13.9): the mapping head, the UID reservation,
|
|
240
|
+
* the governance/policy heads, the acceptance obligation, and the retirement frontier. This is
|
|
241
|
+
* the SINGLE SOURCE consumed BOTH by the registry below AND by the record-reader seam
|
|
242
|
+
* ({@link ../endpoint-binding.ts}.recordReaderConfig): a caller reader durable may target NONE of
|
|
243
|
+
* these authority-only subtrees (nats-server#8274, the sealed records scanner owns `oblig.`), so
|
|
244
|
+
* adding a kind here extends registration AND the reader exclusion together — no parallel
|
|
245
|
+
* hand-kept deny-list to drift. `lifecycle` is DUAL: its atomic HEAD (`LIFECYCLE_HEAD`) is
|
|
246
|
+
* authority, while its deeper per-UID `RECORD_KINDS.lifecycle` detail is a caller-readable audit
|
|
247
|
+
* record; the seam admits the detail but head-guards the atomic key. */
|
|
248
|
+
export const AUTHORITY_KIND_DEFS = [
|
|
249
|
+
LIFECYCLE_HEAD, UID_RESERVATION, GOVERN_HEAD, OBLIGATION, POLICY_VERSION, RETIREMENT_FRONTIER,
|
|
250
|
+
];
|
|
251
|
+
/** RUNTIME-freeze a def: `readonly` is type-level only, and this module's collections are a
|
|
252
|
+
* SECURITY classification the reader seam consults, so identity (built here) must also be
|
|
253
|
+
* integrity (unchangeable after export). Every def, its qualifiers array, each qualifier, and
|
|
254
|
+
* its writers object freeze; under ESM strict mode a later mutation THROWS instead of silently
|
|
255
|
+
* removing an exclusion or a head guard (the panel's identity-vs-integrity class, the same as
|
|
256
|
+
* the sealed-scanner handle). */
|
|
257
|
+
function freezeDef(def) {
|
|
258
|
+
for (const q of def.qualifiers)
|
|
259
|
+
Object.freeze(q);
|
|
260
|
+
Object.freeze(def.qualifiers);
|
|
261
|
+
Object.freeze(def.writers);
|
|
262
|
+
return Object.freeze(def);
|
|
263
|
+
}
|
|
264
|
+
const registry = new Map();
|
|
265
|
+
for (const def of [...Object.values(RECORD_KINDS), ...AUTHORITY_KIND_DEFS]) {
|
|
266
|
+
freezeDef(def);
|
|
267
|
+
const list = registry.get(def.kind) ?? [];
|
|
268
|
+
list.push(def);
|
|
269
|
+
registry.set(def.kind, list);
|
|
270
|
+
}
|
|
271
|
+
Object.freeze(AUTHORITY_KIND_DEFS);
|
|
272
|
+
Object.freeze(RECORD_KINDS);
|
|
273
|
+
/** The record-reader ALLOWLIST predicate (§13.9): a kind is CALLER-READABLE iff the registry holds
|
|
274
|
+
* a def for it that is NOT an authority-control def — a caller `RECORD_KIND` (core or a registered
|
|
275
|
+
* third-party kind). A PURE authority kind (`oblig`/`uid`/`govern`/`policy`/`frontier`) and any
|
|
276
|
+
* UNREGISTERED kind return false (a reader may target neither); a DUAL-token kind (`lifecycle`)
|
|
277
|
+
* returns true because its audit detail is readable, and the seam then head-guards it. The
|
|
278
|
+
* record-reader seam calls this instead of a deny-list, so an unregistered/authority kind can
|
|
279
|
+
* never pass and a new authority kind added to {@link AUTHORITY_KIND_DEFS} is excluded by
|
|
280
|
+
* construction. */
|
|
281
|
+
const AUTHORITY_DEF_SET = new Set(AUTHORITY_KIND_DEFS);
|
|
282
|
+
export function callerReadableRecordKind(kind) {
|
|
283
|
+
const defs = registry.get(kind);
|
|
284
|
+
return defs !== undefined && defs.some((d) => !AUTHORITY_DEF_SET.has(d));
|
|
285
|
+
}
|
|
286
|
+
/** Register a third-party record kind. Reverse-DNS names ONLY — single-label kind names are
|
|
287
|
+
* reserved for the kinds this module pins (§13.7); a re-registration throws, no silent
|
|
288
|
+
* replacement. The kind name tokenizes `.`→`_` exactly like an endpoint name. */
|
|
289
|
+
export function registerRecordKind(def) {
|
|
290
|
+
const kindToken = endpointToken(def.kind);
|
|
291
|
+
if (!kindToken.includes("_"))
|
|
292
|
+
throw new Error(`record kind "${def.kind}" is single-label: those are reserved for core kinds; third-party kinds are reverse-DNS (SPEC 13.7)`);
|
|
293
|
+
const entry = { ...def, kind: kindToken };
|
|
294
|
+
const list = registry.get(kindToken) ?? [];
|
|
295
|
+
if (list.some((d) => d.qualifiers.length === entry.qualifiers.length && d.split === entry.split))
|
|
296
|
+
throw new Error(`record kind "${def.kind}" is already registered with this key arity`);
|
|
297
|
+
freezeDef(entry); // registered defs carry the same runtime integrity as the core ones
|
|
298
|
+
list.push(entry);
|
|
299
|
+
registry.set(kindToken, list);
|
|
300
|
+
return entry;
|
|
301
|
+
}
|
|
302
|
+
// ---- key grammar (§13.7): build and parse ---------------------------------------------------
|
|
303
|
+
function baseTokens(def, qualifiers) {
|
|
304
|
+
if (qualifiers.length !== def.qualifiers.length)
|
|
305
|
+
throw new Error(`record kind "${def.kind}" takes ${def.qualifiers.length} qualifier(s) (${def.qualifiers.map((q) => q.name).join(", ")}); got ${qualifiers.length}`);
|
|
306
|
+
return [def.kind, ...def.qualifiers.map((q, i) => q.assert(qualifiers[i]))];
|
|
307
|
+
}
|
|
308
|
+
/** The unsplit key of an atomic kind (the lifecycle head). Throws for a split kind. */
|
|
309
|
+
export function recordAtomicKey(def, qualifiers) {
|
|
310
|
+
if (def.split)
|
|
311
|
+
throw new Error(`record kind "${def.kind}" is .spec/.status-split; it has no atomic key`);
|
|
312
|
+
return baseTokens(def, qualifiers).join(".");
|
|
313
|
+
}
|
|
314
|
+
/** The `.spec` key of a split kind. */
|
|
315
|
+
export function recordSpecKey(def, qualifiers) {
|
|
316
|
+
if (!def.split)
|
|
317
|
+
throw new Error(`record kind "${def.kind}" is atomic; it has no .spec key`);
|
|
318
|
+
return [...baseTokens(def, qualifiers), "spec"].join(".");
|
|
319
|
+
}
|
|
320
|
+
/** The `.status` key of a split kind. */
|
|
321
|
+
export function recordStatusKey(def, qualifiers) {
|
|
322
|
+
if (!def.split)
|
|
323
|
+
throw new Error(`record kind "${def.kind}" is atomic; it has no .status key`);
|
|
324
|
+
return [...baseTokens(def, qualifiers), "status"].join(".");
|
|
325
|
+
}
|
|
326
|
+
/** Parse a records-bucket key against the registry. `null` = no registered grammar matches —
|
|
327
|
+
* fail-closed, MUST NOT be handled (an unknown kind throws at the caller, no silent fallback).
|
|
328
|
+
* Split-only trust model as in the subject parser: shape and registry dispatch here; token
|
|
329
|
+
* grammars were enforced at build/mint time. */
|
|
330
|
+
export function parseRecordKey(key) {
|
|
331
|
+
const toks = key.split(".");
|
|
332
|
+
const candidates = registry.get(toks[0]);
|
|
333
|
+
if (!candidates)
|
|
334
|
+
return null;
|
|
335
|
+
const last = toks[toks.length - 1];
|
|
336
|
+
for (const def of candidates) {
|
|
337
|
+
if (def.split && (last === "spec" || last === "status") && toks.length === def.qualifiers.length + 2)
|
|
338
|
+
return { def, qualifiers: toks.slice(1, -1), part: last };
|
|
339
|
+
if (!def.split && toks.length === def.qualifiers.length + 1)
|
|
340
|
+
return { def, qualifiers: toks.slice(1), part: "atomic" };
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
// ---- split-key CAS writes (§13.4/§13.8: a lost CAS is a LOUD conflict) ----------------------
|
|
345
|
+
function encodeValue(value) {
|
|
346
|
+
return new TextEncoder().encode(JSON.stringify(value));
|
|
347
|
+
}
|
|
348
|
+
/** JetStream's expected-last-subject-sequence failure — the ONE broker condition behind every
|
|
349
|
+
* create-only/revision-pinned CAS loss here and in the journal (§13.4/§13.8). Keyed on the
|
|
350
|
+
* STRUCTURED `err_code` (`JetStreamApiCodes.StreamWrongLastSequence` 10071 and its
|
|
351
|
+
* `…Unknown` sibling 10164, the same pair the KV client's own create() classifies), never on
|
|
352
|
+
* message text: wording varies across server versions and a missed classification would turn
|
|
353
|
+
* a benign concurrent write into an unhandled throw inside a mediated writer. */
|
|
354
|
+
export function isCasLoss(e) {
|
|
355
|
+
const code = e?.code;
|
|
356
|
+
return code === 10071 || code === 10164;
|
|
357
|
+
}
|
|
358
|
+
function conflict(message, cause) {
|
|
359
|
+
const err = new EpEnvelopeError("conflict", message);
|
|
360
|
+
err.cause = cause;
|
|
361
|
+
throw err;
|
|
362
|
+
}
|
|
363
|
+
/** Create-only write of one record key, CAS-fenced against the key's ENTIRE history (a
|
|
364
|
+
* revision-0 expectation on the subject): an existing key OR a DEL/PURGE tombstone is a loud
|
|
365
|
+
* `conflict`. Deliberately NOT the KV client's own `create()`, which silently RECREATES over a
|
|
366
|
+
* tombstone — that would let whoever can delete a key re-open a one-use identity (rebind a
|
|
367
|
+
* settled checkpoint's holder, reset a decided lease, resurrect a terminal goal). Here a
|
|
368
|
+
* deletion permanently CLOSES the key (§13.8's create-only discipline; deletion is fail-closed
|
|
369
|
+
* state, never absence), and this CAS is the arbiter — a caller's marker pre-check is only a
|
|
370
|
+
* fast path, since a delete landing between check and create loses here, not there. Residual:
|
|
371
|
+
* a tombstone COMPACTED out of the bucket's history is indistinguishable from true absence at
|
|
372
|
+
* the broker; nothing in core compacts or deletes records keys, so that is operator store
|
|
373
|
+
* surgery — reconcile-the-store territory. Any other broker failure propagates untranslated.
|
|
374
|
+
* Returns the created revision. */
|
|
375
|
+
export async function createRecordEntry(kv, key, value) {
|
|
376
|
+
try {
|
|
377
|
+
return await kv.put(key, encodeValue(value), { previousSeq: 0 });
|
|
378
|
+
}
|
|
379
|
+
catch (e) {
|
|
380
|
+
if (isCasLoss(e))
|
|
381
|
+
conflict(`create of ${key} lost its CAS: the key already exists or carries a deletion marker (re-read and re-decide, SPEC 13.8)`, e);
|
|
382
|
+
throw e;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/** Revision-pinned CAS update of one record key. A moved revision is a loud `conflict`; any
|
|
386
|
+
* other broker failure propagates untranslated. Returns the new revision. */
|
|
387
|
+
export async function updateRecordEntry(kv, key, value, expectedRevision) {
|
|
388
|
+
try {
|
|
389
|
+
return await kv.update(key, encodeValue(value), expectedRevision);
|
|
390
|
+
}
|
|
391
|
+
catch (e) {
|
|
392
|
+
if (isCasLoss(e))
|
|
393
|
+
conflict(`update of ${key} at revision ${expectedRevision} lost its CAS (re-read and re-decide, SPEC 13.8)`, e);
|
|
394
|
+
throw e;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/** Status values MUST carry `observedSpecRevision` (§13.4) — the merged-read staleness rules
|
|
398
|
+
* key on it. Enforced at the write seam so a status without it can never exist. */
|
|
399
|
+
export function assertStatusValue(value) {
|
|
400
|
+
const o = value.observedSpecRevision;
|
|
401
|
+
if (typeof o !== "number" || !Number.isSafeInteger(o) || o < 0)
|
|
402
|
+
throw new Error(`a record status value must carry a non-negative integer observedSpecRevision (SPEC 13.4); got ${JSON.stringify(o)}`);
|
|
403
|
+
return value;
|
|
404
|
+
}
|
|
405
|
+
function decodeEntry(e, key) {
|
|
406
|
+
try {
|
|
407
|
+
return e.json();
|
|
408
|
+
}
|
|
409
|
+
catch (err) {
|
|
410
|
+
// Mediated-writer state that does not decode is a writer bug; readers fail loud (§13.9).
|
|
411
|
+
throw new EpEnvelopeError("internal", `record ${key} does not decode as JSON: ${err.message}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const liveEntry = (e) => !!e && e.operation === "PUT";
|
|
415
|
+
/** §13.8 retry/backoff: exponential, base 250 ms, factor 2, cap 15 s, full jitter. */
|
|
416
|
+
function backoffMs(attempt) {
|
|
417
|
+
return Math.random() * Math.min(15_000, 250 * 2 ** attempt);
|
|
418
|
+
}
|
|
419
|
+
/** Merged logical read of a split record (§13.4): both keys, both revisions, the staleness
|
|
420
|
+
* classification. `observedSpecRevision > spec.revision` (a lagging spec read, possible across
|
|
421
|
+
* replica freshness points) triggers bounded spec re-reads until caught up or the deadline —
|
|
422
|
+
* the mismatched pair is NEVER returned. Absent record → `undefined`; a status without its
|
|
423
|
+
* spec is torn state → `failed-precondition`. */
|
|
424
|
+
export async function readRecord(kv, def, qualifiers, opts = {}) {
|
|
425
|
+
const sKey = recordSpecKey(def, qualifiers);
|
|
426
|
+
const tKey = recordStatusKey(def, qualifiers);
|
|
427
|
+
const deadline = Date.now() + (opts.deadlineMs ?? 15_000);
|
|
428
|
+
let specEntry = await kv.get(sKey);
|
|
429
|
+
let statusEntry = await kv.get(tKey);
|
|
430
|
+
// Absent spec + live status is USUALLY a read-order artifact, not corruption: the spec get
|
|
431
|
+
// can land just before an ordered create commits spec-then-status, both visible by the time
|
|
432
|
+
// the status get runs. Stabilize with bounded spec re-reads (re-checking status in case the
|
|
433
|
+
// record is mid-deletion) and declare torn state only when the absence is STABLE across the
|
|
434
|
+
// deadline — a transient interleaving must never be classified as corruption (§13.4).
|
|
435
|
+
for (let attempt = 0; !liveEntry(specEntry) && liveEntry(statusEntry); attempt++) {
|
|
436
|
+
if (Date.now() >= deadline)
|
|
437
|
+
throw new EpEnvelopeError("failed-precondition", `record ${tKey} exists without its spec key (stable across bounded re-reads); torn record state, refusing to read`);
|
|
438
|
+
await new Promise((r) => setTimeout(r, Math.min(backoffMs(attempt), Math.max(0, deadline - Date.now()))));
|
|
439
|
+
specEntry = await kv.get(sKey);
|
|
440
|
+
if (!liveEntry(specEntry))
|
|
441
|
+
statusEntry = await kv.get(tKey);
|
|
442
|
+
}
|
|
443
|
+
if (!liveEntry(specEntry))
|
|
444
|
+
return undefined;
|
|
445
|
+
if (!liveEntry(statusEntry)) {
|
|
446
|
+
return { spec: { value: decodeEntry(specEntry, sKey), revision: specEntry.revision }, staleProjection: false };
|
|
447
|
+
}
|
|
448
|
+
const statusValue = decodeEntry(statusEntry, tKey);
|
|
449
|
+
const observed = statusValue.observedSpecRevision;
|
|
450
|
+
if (typeof observed !== "number" || !Number.isSafeInteger(observed) || observed < 0)
|
|
451
|
+
throw new EpEnvelopeError("internal", `record ${tKey} carries no valid observedSpecRevision (SPEC 13.4)`);
|
|
452
|
+
// A lagging spec read: re-read the spec key, bounded, until it catches up to what the status
|
|
453
|
+
// writer demonstrably observed. Never trust the mismatched pair (§13.4).
|
|
454
|
+
for (let attempt = 0; (specEntry?.revision ?? 0) < observed; attempt++) {
|
|
455
|
+
if (Date.now() >= deadline)
|
|
456
|
+
throw new EpEnvelopeError("deadline-exceeded", `spec ${sKey} (revision ${specEntry?.revision}) never caught up to the status writer's observed revision ${observed} within the deadline`);
|
|
457
|
+
await new Promise((r) => setTimeout(r, Math.min(backoffMs(attempt), Math.max(0, deadline - Date.now()))));
|
|
458
|
+
specEntry = await kv.get(sKey);
|
|
459
|
+
if (!liveEntry(specEntry))
|
|
460
|
+
throw new EpEnvelopeError("failed-precondition", `record ${sKey} disappeared while resolving a lagging spec read`);
|
|
461
|
+
}
|
|
462
|
+
return {
|
|
463
|
+
spec: { value: decodeEntry(specEntry, sKey), revision: specEntry.revision },
|
|
464
|
+
status: { value: statusValue, revision: statusEntry.revision, observedSpecRevision: observed },
|
|
465
|
+
staleProjection: observed < specEntry.revision,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
/** Read an atomic (unsplit) record — the lifecycle head. NOT a fence: an authority read of the
|
|
469
|
+
* head (mapping currency before effect) is a leader-served `STREAM.MSG.GET` by the trusted
|
|
470
|
+
* mapping-reader (§13.9); this helper is the ordinary non-fencing read, and every fence is a
|
|
471
|
+
* revision-pinned CAS write against the returned revision. */
|
|
472
|
+
export async function readAtomicRecord(kv, def, qualifiers) {
|
|
473
|
+
const key = recordAtomicKey(def, qualifiers);
|
|
474
|
+
const e = await kv.get(key);
|
|
475
|
+
if (!liveEntry(e))
|
|
476
|
+
return undefined;
|
|
477
|
+
return { value: decodeEntry(e, key), revision: e.revision };
|
|
478
|
+
}
|
|
479
|
+
// ---- merged watch (§13.4/§13.8 snapshot-then-deltas, resync on gap) -------------------------
|
|
480
|
+
/** Watch a split record: the current merged snapshot first, then a re-merged view per delta.
|
|
481
|
+
*
|
|
482
|
+
* Cursor discipline (§13.4/§13.8): ONE ordered consumer supplies BOTH the snapshot (the
|
|
483
|
+
* per-key last values the watch replays first) and the deltas after it — the cursor is the
|
|
484
|
+
* consumer's own position, so nothing between "snapshot" and "watch start" can ever be
|
|
485
|
+
* skipped. (A cursor derived from independent `get` reads — `max(specRev,statusRev)+1` — is
|
|
486
|
+
* provably gap-prone: mixed-freshness/TOCTOU reads let a higher revision on one key jump the
|
|
487
|
+
* resume point past an unseen update on the other.) Replay entries accumulate silently; the
|
|
488
|
+
* first merged view is yielded when the replay completes, and every later delta re-yields the
|
|
489
|
+
* merged view. A watcher that errors, ends, or observes a status ahead of its cached spec
|
|
490
|
+
* (impossible from honest writers in an unbroken ordered watch) RESYNCS with a fresh consumer
|
|
491
|
+
* — a fresh full snapshot, duplicates tolerated, never a patch across a gap.
|
|
492
|
+
*
|
|
493
|
+
* Resyncs are budgeted on CONSECUTIVE no-progress incarnations, reset once an incarnation
|
|
494
|
+
* delivers at least one ordered post-snapshot delta (a lifetime-cumulative budget would kill a
|
|
495
|
+
* long-lived watch on accumulated benign blips; a snapshot alone must not count as progress or
|
|
496
|
+
* an immediately-ending iterator would spin forever). Ends when the spec key is deleted (the
|
|
497
|
+
* record is retired — a watch started on an already-retired record ends immediately) or when
|
|
498
|
+
* `signal` aborts. A status whose spec key NEVER existed in the consistent replay view is real
|
|
499
|
+
* torn state (`failed-precondition`) — the single-consumer view cannot false-positive this. */
|
|
500
|
+
export async function* watchRecord(kv, def, qualifiers, opts = {}) {
|
|
501
|
+
const sKey = recordSpecKey(def, qualifiers);
|
|
502
|
+
const tKey = recordStatusKey(def, qualifiers);
|
|
503
|
+
const maxResyncs = opts.maxResyncs ?? 8;
|
|
504
|
+
let consecutiveNoProgress = 0;
|
|
505
|
+
for (;;) {
|
|
506
|
+
if (consecutiveNoProgress > maxResyncs)
|
|
507
|
+
throw new EpEnvelopeError("unavailable", `watch of ${sKey} exhausted ${maxResyncs} consecutive resyncs without delta progress`);
|
|
508
|
+
// Last values + updates from one ordered consumer. The client marks replay entries with
|
|
509
|
+
// isUpdate=false up to the LAST initial entry (which arrives with isUpdate=true) — so the
|
|
510
|
+
// first isUpdate=true entry completes the snapshot, and a zero-entry replay (absent record)
|
|
511
|
+
// yields nothing until the first live delta arrives.
|
|
512
|
+
const iter = await kv.watch({ key: [sKey, tKey] });
|
|
513
|
+
const stop = () => iter.stop();
|
|
514
|
+
opts.signal?.addEventListener("abort", stop, { once: true });
|
|
515
|
+
let spec;
|
|
516
|
+
let status;
|
|
517
|
+
let specSeen = false; // a DEL/PURGE last value counts as seen (retired), just not live
|
|
518
|
+
let initialized = false;
|
|
519
|
+
let progressed = false;
|
|
520
|
+
const merged = () => spec
|
|
521
|
+
? { spec, ...(status ? { status } : {}), staleProjection: !!status && status.observedSpecRevision < spec.revision }
|
|
522
|
+
: undefined;
|
|
523
|
+
try {
|
|
524
|
+
for await (const e of iter) {
|
|
525
|
+
if (opts.signal?.aborted)
|
|
526
|
+
return;
|
|
527
|
+
const completesReplay = !initialized && e.isUpdate;
|
|
528
|
+
if (e.key === sKey) {
|
|
529
|
+
specSeen = true;
|
|
530
|
+
if (e.operation !== "PUT")
|
|
531
|
+
return; // spec deleted: the record is (or was) retired
|
|
532
|
+
spec = { value: decodeEntry(e, sKey), revision: e.revision };
|
|
533
|
+
}
|
|
534
|
+
else if (e.key === tKey) {
|
|
535
|
+
if (e.operation !== "PUT") {
|
|
536
|
+
status = undefined;
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
const v = decodeEntry(e, tKey);
|
|
540
|
+
const observed = v.observedSpecRevision;
|
|
541
|
+
if (typeof observed !== "number" || !Number.isSafeInteger(observed) || observed < 0)
|
|
542
|
+
throw new EpEnvelopeError("internal", `record ${tKey} carries no valid observedSpecRevision (SPEC 13.4)`);
|
|
543
|
+
// Within replay, a status may precede its spec in stream order (older last value
|
|
544
|
+
// first) — judge coherence only once the replay's consistent view is complete.
|
|
545
|
+
if ((initialized || completesReplay) && spec && observed > spec.revision)
|
|
546
|
+
break; // status ahead of spec: writer anomaly — resync, never patch forward
|
|
547
|
+
status = { value: v, revision: e.revision, observedSpecRevision: observed };
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (!initialized && !e.isUpdate)
|
|
551
|
+
continue; // mid-replay: accumulate silently
|
|
552
|
+
if (completesReplay) {
|
|
553
|
+
initialized = true;
|
|
554
|
+
// The replay is a consistent view: a live status whose spec key never appeared is
|
|
555
|
+
// REAL torn state, not a read-order artifact — fail loud, never relist over it.
|
|
556
|
+
if (status && !specSeen)
|
|
557
|
+
throw new EpEnvelopeError("failed-precondition", `record ${tKey} exists without its spec key in a consistent watch replay; torn record state`);
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
progressed = true;
|
|
561
|
+
}
|
|
562
|
+
// Never yield a mismatched ahead-pair — a status observed a spec revision higher than the
|
|
563
|
+
// one we hold (a re-read signal, §13.4). The per-status-entry check above catches a
|
|
564
|
+
// status DELTA arriving ahead; this universal guard also catches the replay case where a
|
|
565
|
+
// status was cached first and the SPEC entry then completed replay behind it, which that
|
|
566
|
+
// check would miss (it fires only while processing a status entry).
|
|
567
|
+
if (spec && status && status.observedSpecRevision > spec.revision)
|
|
568
|
+
break; // resync, never patch forward
|
|
569
|
+
const m = merged();
|
|
570
|
+
if (m)
|
|
571
|
+
yield m;
|
|
572
|
+
}
|
|
573
|
+
if (opts.signal?.aborted)
|
|
574
|
+
return;
|
|
575
|
+
// gap-break or iterator end: stream hiccup / writer anomaly — resync below
|
|
576
|
+
}
|
|
577
|
+
catch (e) {
|
|
578
|
+
if (e instanceof EpEnvelopeError && (e.code === "internal" || e.code === "failed-precondition"))
|
|
579
|
+
throw e; // writer bug, not a gap
|
|
580
|
+
// watcher transport error — resync from a fresh consumer
|
|
581
|
+
}
|
|
582
|
+
finally {
|
|
583
|
+
opts.signal?.removeEventListener("abort", stop);
|
|
584
|
+
iter.stop();
|
|
585
|
+
}
|
|
586
|
+
if (opts.signal?.aborted)
|
|
587
|
+
return;
|
|
588
|
+
consecutiveNoProgress = progressed ? 0 : consecutiveNoProgress + 1;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
//# sourceMappingURL=endpoint-records.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-records.js","sourceRoot":"","sources":["../src/endpoint-records.ts"],"names":[],"mappings":"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"}
|