@cotal-ai/core 0.11.6 → 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.
Files changed (170) hide show
  1. package/dist/acls.d.ts +31 -7
  2. package/dist/acls.d.ts.map +1 -1
  3. package/dist/acls.js +105 -17
  4. package/dist/acls.js.map +1 -1
  5. package/dist/agent-file.js +1 -1
  6. package/dist/agent-file.js.map +1 -1
  7. package/dist/auth-provider.d.ts +90 -10
  8. package/dist/auth-provider.d.ts.map +1 -1
  9. package/dist/auth-provider.js.map +1 -1
  10. package/dist/backup-config.d.ts +55 -0
  11. package/dist/backup-config.d.ts.map +1 -0
  12. package/dist/backup-config.js +243 -0
  13. package/dist/backup-config.js.map +1 -0
  14. package/dist/backup.d.ts +86 -0
  15. package/dist/backup.d.ts.map +1 -0
  16. package/dist/backup.js +497 -0
  17. package/dist/backup.js.map +1 -0
  18. package/dist/broker-floor.d.ts +34 -0
  19. package/dist/broker-floor.d.ts.map +1 -0
  20. package/dist/broker-floor.js +39 -0
  21. package/dist/broker-floor.js.map +1 -0
  22. package/dist/canonical.d.ts +24 -0
  23. package/dist/canonical.d.ts.map +1 -0
  24. package/dist/canonical.js +159 -0
  25. package/dist/canonical.js.map +1 -0
  26. package/dist/channels.d.ts.map +1 -1
  27. package/dist/channels.js +8 -1
  28. package/dist/channels.js.map +1 -1
  29. package/dist/connector.d.ts +4 -0
  30. package/dist/connector.d.ts.map +1 -1
  31. package/dist/endpoint-action.d.ts +424 -0
  32. package/dist/endpoint-action.d.ts.map +1 -0
  33. package/dist/endpoint-action.js +910 -0
  34. package/dist/endpoint-action.js.map +1 -0
  35. package/dist/endpoint-binding.d.ts +344 -0
  36. package/dist/endpoint-binding.d.ts.map +1 -0
  37. package/dist/endpoint-binding.js +753 -0
  38. package/dist/endpoint-binding.js.map +1 -0
  39. package/dist/endpoint-checkpoint.d.ts +292 -0
  40. package/dist/endpoint-checkpoint.d.ts.map +1 -0
  41. package/dist/endpoint-checkpoint.js +818 -0
  42. package/dist/endpoint-checkpoint.js.map +1 -0
  43. package/dist/endpoint-cluster.d.ts +95 -0
  44. package/dist/endpoint-cluster.d.ts.map +1 -0
  45. package/dist/endpoint-cluster.js +194 -0
  46. package/dist/endpoint-cluster.js.map +1 -0
  47. package/dist/endpoint-contract-store.d.ts +90 -0
  48. package/dist/endpoint-contract-store.d.ts.map +1 -0
  49. package/dist/endpoint-contract-store.js +348 -0
  50. package/dist/endpoint-contract-store.js.map +1 -0
  51. package/dist/endpoint-envelope.d.ts +165 -0
  52. package/dist/endpoint-envelope.d.ts.map +1 -0
  53. package/dist/endpoint-envelope.js +346 -0
  54. package/dist/endpoint-envelope.js.map +1 -0
  55. package/dist/endpoint-grants.d.ts +123 -0
  56. package/dist/endpoint-grants.d.ts.map +1 -0
  57. package/dist/endpoint-grants.js +215 -0
  58. package/dist/endpoint-grants.js.map +1 -0
  59. package/dist/endpoint-guard.d.ts +222 -0
  60. package/dist/endpoint-guard.d.ts.map +1 -0
  61. package/dist/endpoint-guard.js +468 -0
  62. package/dist/endpoint-guard.js.map +1 -0
  63. package/dist/endpoint-handle.d.ts +176 -0
  64. package/dist/endpoint-handle.d.ts.map +1 -0
  65. package/dist/endpoint-handle.js +608 -0
  66. package/dist/endpoint-handle.js.map +1 -0
  67. package/dist/endpoint-journal.d.ts +225 -0
  68. package/dist/endpoint-journal.d.ts.map +1 -0
  69. package/dist/endpoint-journal.js +431 -0
  70. package/dist/endpoint-journal.js.map +1 -0
  71. package/dist/endpoint-receipt.d.ts +225 -0
  72. package/dist/endpoint-receipt.d.ts.map +1 -0
  73. package/dist/endpoint-receipt.js +417 -0
  74. package/dist/endpoint-receipt.js.map +1 -0
  75. package/dist/endpoint-records.d.ts +243 -0
  76. package/dist/endpoint-records.d.ts.map +1 -0
  77. package/dist/endpoint-records.js +591 -0
  78. package/dist/endpoint-records.js.map +1 -0
  79. package/dist/endpoint-serve.d.ts +176 -0
  80. package/dist/endpoint-serve.d.ts.map +1 -0
  81. package/dist/endpoint-serve.js +446 -0
  82. package/dist/endpoint-serve.js.map +1 -0
  83. package/dist/endpoint-service.d.ts +518 -0
  84. package/dist/endpoint-service.d.ts.map +1 -0
  85. package/dist/endpoint-service.js +973 -0
  86. package/dist/endpoint-service.js.map +1 -0
  87. package/dist/endpoint-session.d.ts +398 -0
  88. package/dist/endpoint-session.d.ts.map +1 -0
  89. package/dist/endpoint-session.js +834 -0
  90. package/dist/endpoint-session.js.map +1 -0
  91. package/dist/endpoint-signing.d.ts +105 -0
  92. package/dist/endpoint-signing.d.ts.map +1 -0
  93. package/dist/endpoint-signing.js +190 -0
  94. package/dist/endpoint-signing.js.map +1 -0
  95. package/dist/endpoint-subjects.d.ts +222 -0
  96. package/dist/endpoint-subjects.d.ts.map +1 -0
  97. package/dist/endpoint-subjects.js +381 -0
  98. package/dist/endpoint-subjects.js.map +1 -0
  99. package/dist/endpoint-supervisor.d.ts +19 -0
  100. package/dist/endpoint-supervisor.d.ts.map +1 -0
  101. package/dist/endpoint-supervisor.js +12 -0
  102. package/dist/endpoint-supervisor.js.map +1 -0
  103. package/dist/endpoint-traits.d.ts +225 -0
  104. package/dist/endpoint-traits.d.ts.map +1 -0
  105. package/dist/endpoint-traits.js +469 -0
  106. package/dist/endpoint-traits.js.map +1 -0
  107. package/dist/endpoint-verbs.d.ts +277 -0
  108. package/dist/endpoint-verbs.d.ts.map +1 -0
  109. package/dist/endpoint-verbs.js +576 -0
  110. package/dist/endpoint-verbs.js.map +1 -0
  111. package/dist/endpoint-virtual.d.ts +308 -0
  112. package/dist/endpoint-virtual.d.ts.map +1 -0
  113. package/dist/endpoint-virtual.js +440 -0
  114. package/dist/endpoint-virtual.js.map +1 -0
  115. package/dist/endpoint-work.d.ts +304 -0
  116. package/dist/endpoint-work.d.ts.map +1 -0
  117. package/dist/endpoint-work.js +728 -0
  118. package/dist/endpoint-work.js.map +1 -0
  119. package/dist/endpoint.d.ts +66 -22
  120. package/dist/endpoint.d.ts.map +1 -1
  121. package/dist/endpoint.js +289 -89
  122. package/dist/endpoint.js.map +1 -1
  123. package/dist/evict.d.ts +95 -32
  124. package/dist/evict.d.ts.map +1 -1
  125. package/dist/evict.js +193 -3
  126. package/dist/evict.js.map +1 -1
  127. package/dist/index.d.ts +29 -0
  128. package/dist/index.d.ts.map +1 -1
  129. package/dist/index.js +29 -0
  130. package/dist/index.js.map +1 -1
  131. package/dist/lease.d.ts +4 -0
  132. package/dist/lease.d.ts.map +1 -1
  133. package/dist/lease.js.map +1 -1
  134. package/dist/members.d.ts +4 -4
  135. package/dist/members.d.ts.map +1 -1
  136. package/dist/members.js +12 -12
  137. package/dist/members.js.map +1 -1
  138. package/dist/provision.d.ts +78 -20
  139. package/dist/provision.d.ts.map +1 -1
  140. package/dist/provision.js +214 -37
  141. package/dist/provision.js.map +1 -1
  142. package/dist/runtime.d.ts +3 -0
  143. package/dist/runtime.d.ts.map +1 -1
  144. package/dist/safe-pattern.d.ts +33 -0
  145. package/dist/safe-pattern.d.ts.map +1 -0
  146. package/dist/safe-pattern.js +486 -0
  147. package/dist/safe-pattern.js.map +1 -0
  148. package/dist/schema-profile.d.ts +93 -0
  149. package/dist/schema-profile.d.ts.map +1 -0
  150. package/dist/schema-profile.js +284 -0
  151. package/dist/schema-profile.js.map +1 -0
  152. package/dist/secret-store.d.ts +46 -0
  153. package/dist/secret-store.d.ts.map +1 -0
  154. package/dist/secret-store.js +2 -0
  155. package/dist/secret-store.js.map +1 -0
  156. package/dist/space-auth.d.ts +9 -0
  157. package/dist/space-auth.d.ts.map +1 -0
  158. package/dist/space-auth.js +126 -0
  159. package/dist/space-auth.js.map +1 -0
  160. package/dist/streams.d.ts +14 -10
  161. package/dist/streams.d.ts.map +1 -1
  162. package/dist/streams.js +47 -76
  163. package/dist/streams.js.map +1 -1
  164. package/dist/subjects.d.ts +100 -40
  165. package/dist/subjects.d.ts.map +1 -1
  166. package/dist/subjects.js +136 -60
  167. package/dist/subjects.js.map +1 -1
  168. package/dist/types.d.ts +9 -0
  169. package/dist/types.d.ts.map +1 -1
  170. package/package.json +6 -2
@@ -0,0 +1,348 @@
1
+ /**
2
+ * The CONTRACT STORE (SPEC §13.7): content-addressed, public, immutable, permanent. One
3
+ * artifact per digest-keyed subject `cotal.<space>.epc.<digest-hex>`, published as a SINGLE
4
+ * message (bounded at 256 KiB; the §13.12 operator floor asserts `max_payload` covers it) —
5
+ * deliberately NOT a chunked object store, whose chunk replay needs a consumer with a
6
+ * body-selected delivery target (§13.9 forbids that shape). A closure is fetched
7
+ * artifact-by-artifact through its digest references, never as one blob.
8
+ *
9
+ * CONTENT IDENTITY (§13.7 "Content addressing"): an artifact is its STRICT RFC 8785 CANONICAL
10
+ * JSON — the digest is computed over the canonical bytes, publication REFUSES bytes that are
11
+ * not already the canonical serialization of their own parse (a noncanonical encoding of an
12
+ * equivalent value never gets its own identity; non-JSON bytes are never artifacts), and
13
+ * verify-on-read re-proves BOTH the digest and the canonical form (a garbled store never
14
+ * serves). TWO DIGESTS, NEVER CONFLATED: an ARTIFACT digest identifies one document's
15
+ * canonical bytes; a CLOSURE digest identifies a whole resolved bundle and is the artifact
16
+ * digest of that bundle's MANIFEST `{ v: 1, root, members }` — `members` being every artifact
17
+ * transitively reachable THROUGH BY-DIGEST REFERENCES from `root` (the root itself is named by
18
+ * its own field and appears in `members` only if a reference re-reaches it), sorted
19
+ * lexicographically and deduplicated. The manifest is itself an ordinary artifact on its own
20
+ * digest subject. Closure verification fetches the manifest BY the closure digest, walks the
21
+ * references from `root`, and PROVES the walked set equals `members` EXACTLY — a manifest that
22
+ * under- or over-names its closure never verifies.
23
+ *
24
+ * Reads are the subject-scoped last-by-subject Direct Get on the exact digest subject — no
25
+ * consumer, no replay machinery, nothing body-selected. Publication is mediated and
26
+ * create-only (`Nats-Expected-Last-Subject-Sequence: 0`): a digest subject is written at most
27
+ * once, and the digest is computed HERE from the canonical bytes (never a caller claim). The
28
+ * store seams run on a space-bonded BRANDED context (§13.4): JS + JSM derive from ONE
29
+ * connection, so a lost publish CAS can never validate its "recorded artifact" through a
30
+ * different broker. Every walk is BOUNDED by the frozen §13.7 registration bounds (closure
31
+ * <= 1 MiB, ref chain <= 32, document <= 256 KiB, plus the artifact-count ceiling) and ONE
32
+ * total monotonic time budget — the ceilings are non-raiseable (a caller may narrow, never
33
+ * widen) and a truncated closure never verifies as complete.
34
+ */
35
+ import { jetstream, jetstreamManager } from "@nats-io/jetstream";
36
+ import { headers as natsHeaders } from "@nats-io/transport-node";
37
+ import { createHash } from "node:crypto";
38
+ import { canonicalJson } from "./canonical.js";
39
+ import { EpEnvelopeError } from "./endpoint-envelope.js";
40
+ import { epcSubject } from "./endpoint-subjects.js";
41
+ import { epcStreamName } from "./endpoint-binding.js";
42
+ /** The §13.7 artifact bound: a document above it cannot ride one message and is refused. */
43
+ export const CONTRACT_ARTIFACT_MAX_BYTES = 256 * 1024;
44
+ /** The §13.7 closure byte bound: the sum of every fetched artifact's canonical bytes. */
45
+ export const CONTRACT_CLOSURE_MAX_BYTES = 1024 * 1024;
46
+ /** The §13.7 reference-chain bound: the walk's depth from the root. */
47
+ export const CONTRACT_CLOSURE_MAX_REF_DEPTH = 32;
48
+ /** The artifact-count ceiling: a walk that would exceed it fails loud, never truncates. */
49
+ export const CONTRACT_CLOSURE_MAX_ARTIFACTS = 64;
50
+ const HEX64 = /^[0-9a-f]{64}$/;
51
+ /** The resources, unreachable from the context token itself. A structural look-alike never
52
+ * appears in this map (so never authorizes); and `ctx.js`/`ctx.jsm` do not exist to reassign. */
53
+ const STORE_RESOURCES = new WeakMap();
54
+ /** Bond the resources to one space by CONSTRUCTION (frozen token + WeakMap-private resources, the
55
+ * shared context discipline): a hand-assembled structural look-alike is rejected at every seam,
56
+ * and the broker cannot be rebound out from under a live operation. */
57
+ export async function contractStoreContext(nc, space) {
58
+ if (nc === null || typeof nc !== "object" || typeof nc.close !== "function")
59
+ throw new EpEnvelopeError("failed-precondition", "a contract-store context is constructed from ONE binding-layer connection; separate resources are never accepted (SPEC 13.4)");
60
+ if (typeof space !== "string" || space.length === 0)
61
+ throw new EpEnvelopeError("failed-precondition", "a contract-store context needs a space");
62
+ const js = jetstream(nc);
63
+ const jsm = await jetstreamManager(nc);
64
+ const ctx = Object.freeze({ space });
65
+ STORE_RESOURCES.set(ctx, { js, jsm });
66
+ return ctx;
67
+ }
68
+ /** The brand check AND the resource fetch in one: a context not minted by contractStoreContext()
69
+ * is absent from the map and never authorizes. */
70
+ function resources(ctx) {
71
+ const r = ctx === null || typeof ctx !== "object" ? undefined : STORE_RESOURCES.get(ctx);
72
+ if (r === undefined)
73
+ throw new EpEnvelopeError("failed-precondition", `the contract-store context was not constructed by contractStoreContext(); a hand-assembled resource bundle never authorizes - the space bond is constructed, not asserted (SPEC 13.4)`);
74
+ return r;
75
+ }
76
+ /** The artifact's subject token: SHA-256 hex over the artifact's CANONICAL bytes (§13.7: the
77
+ * `sha256:` prefix is not a subject token). The bytes handed here MUST already be canonical —
78
+ * publication and verify-on-read enforce that ({@link assertCanonicalArtifactBytes}). */
79
+ export function contractArtifactDigestHex(bytes) {
80
+ return createHash("sha256").update(bytes).digest("hex");
81
+ }
82
+ /** Normalize a digest reference (`<hex>` or `sha256:<hex>`) to the bare subject token; a
83
+ * malformed reference fails loud (a garbled ref never fetches an unintended subject). */
84
+ export function contractRefToHex(ref) {
85
+ const hex = ref.startsWith("sha256:") ? ref.slice("sha256:".length) : ref;
86
+ if (!HEX64.test(hex))
87
+ throw new EpEnvelopeError("contract-invalid", `contract reference ${JSON.stringify(ref)} is not a sha256 digest; a garbled reference never resolves (SPEC 13.7)`);
88
+ return hex;
89
+ }
90
+ /** A value's canonical artifact bytes (strict RFC 8785 over I-JSON): what publication stores
91
+ * and what the digest identifies. Non-interchangeable values refuse. */
92
+ export function contractArtifactCanonicalBytes(value) {
93
+ try {
94
+ return new TextEncoder().encode(canonicalJson(value));
95
+ }
96
+ catch (e) {
97
+ throw new EpEnvelopeError("contract-invalid", `the value is not interchangeable JSON (${e.message}); only strict I-JSON is a contract artifact (SPEC 13.7)`);
98
+ }
99
+ }
100
+ /** Prove presented bytes ARE their own parse's strict RFC 8785 canonical serialization and
101
+ * return the parsed value (§13.7 content identity): invalid UTF-8, non-JSON, and every
102
+ * noncanonical encoding (reordered keys, whitespace, duplicate keys, noncanonical numbers)
103
+ * refuse — an equivalent value in a different encoding never gets its own identity, so two
104
+ * implementations can never disagree on an artifact's digest. */
105
+ export function assertCanonicalArtifactBytes(bytes, what) {
106
+ let text;
107
+ try {
108
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
109
+ }
110
+ catch {
111
+ throw new EpEnvelopeError("contract-invalid", `${what} is not valid UTF-8; only strict canonical JSON is a contract artifact (SPEC 13.7)`);
112
+ }
113
+ let value;
114
+ try {
115
+ value = JSON.parse(text);
116
+ }
117
+ catch (e) {
118
+ throw new EpEnvelopeError("contract-invalid", `${what} does not parse as JSON (${e.message}); only strict canonical JSON is a contract artifact (SPEC 13.7)`);
119
+ }
120
+ let canonical;
121
+ try {
122
+ canonical = canonicalJson(value);
123
+ }
124
+ catch (e) {
125
+ throw new EpEnvelopeError("contract-invalid", `${what} is not interchangeable I-JSON (${e.message}); only strict canonical JSON is a contract artifact (SPEC 13.7)`);
126
+ }
127
+ if (canonical !== text)
128
+ throw new EpEnvelopeError("contract-invalid", `${what} is not its own RFC 8785 canonical serialization; a noncanonical encoding never gets its own content identity (SPEC 13.7)`);
129
+ return value;
130
+ }
131
+ /** Publish one artifact at its content address, create-only. The bytes are DETACHED at entry
132
+ * (a caller mutating the buffer across the publish await changes nothing), PROVEN canonical
133
+ * ({@link assertCanonicalArtifactBytes}), and the digest is computed FROM that snapshot; a
134
+ * lost CAS fetches the recorded artifact and — because the subject IS the digest and the
135
+ * fetch verifies — the loss is an idempotent no-op ({won: false}). Oversize refuses. */
136
+ export async function publishContractArtifact(ctx, bytes) {
137
+ const { js } = resources(ctx);
138
+ if (!(bytes instanceof Uint8Array) || bytes.length === 0)
139
+ throw new EpEnvelopeError("contract-invalid", "a contract artifact is non-empty canonical JSON bytes (SPEC 13.7)");
140
+ if (bytes.length > CONTRACT_ARTIFACT_MAX_BYTES)
141
+ throw new EpEnvelopeError("contract-invalid", `a contract artifact is bounded at ${CONTRACT_ARTIFACT_MAX_BYTES} bytes (got ${bytes.length}); a document above the bound cannot ride one message and is refused, never chunked (SPEC 13.7/13.12)`);
142
+ const snapshot = new Uint8Array(bytes); // detached at entry (a real copy — Buffer.slice would ALIAS): validated, digested, and published as ONE value
143
+ assertCanonicalArtifactBytes(snapshot, "the artifact");
144
+ const digestHex = contractArtifactDigestHex(snapshot);
145
+ const subject = epcSubject(ctx.space, digestHex);
146
+ const h = natsHeaders();
147
+ h.set("Nats-Expected-Last-Subject-Sequence", "0");
148
+ try {
149
+ await js.publish(subject, snapshot, { headers: h });
150
+ return { digestHex, won: true };
151
+ }
152
+ catch (e) {
153
+ const code = e?.code;
154
+ if (code !== 10071 && code !== 10164)
155
+ throw e;
156
+ // The subject is the digest: a prior write with this address holds these bytes (verified
157
+ // on fetch). The loss is idempotent; an unreadable prior write is loud.
158
+ const prior = await fetchContractArtifact(ctx, digestHex);
159
+ if (prior === undefined)
160
+ throw new EpEnvelopeError("internal", `the artifact CAS for ${subject} was lost but the recorded artifact is not readable (SPEC 13.4)`);
161
+ return { digestHex, won: false };
162
+ }
163
+ }
164
+ /** Fetch one artifact by digest (`undefined` = not published). VERIFY-ON-READ is unconditional
165
+ * and TWO-PROOF: the fetched bytes must recompute the digest AND be strict canonical JSON —
166
+ * content addressing is the tamper boundary and a garbled store never serves (§13.7). */
167
+ export async function fetchContractArtifact(ctx, digestHex) {
168
+ const { jsm } = resources(ctx);
169
+ const subject = epcSubject(ctx.space, digestHex); // validates the token
170
+ let stored;
171
+ try {
172
+ stored = await jsm.direct.getMessage(epcStreamName(ctx.space), { last_by_subj: subject });
173
+ }
174
+ catch (e) {
175
+ if (e?.code === 10037)
176
+ return undefined; // the ONLY "genuinely absent" result
177
+ throw new EpEnvelopeError("unavailable", `the contract-store read for ${digestHex} failed (a failed observation is never absence, SPEC 13.7): ${e?.message ?? String(e)}`);
178
+ }
179
+ if (stored === null)
180
+ return undefined;
181
+ // The 256 KiB document bound is enforced on EVERY consuming read, not just publication (distsys
182
+ // 8dcad72 M2): a directly-planted oversize artifact (bypassing publishContractArtifact) must
183
+ // never be served, and the closure walk (which reads through here) inherits the per-document cap.
184
+ if (stored.data.length > CONTRACT_ARTIFACT_MAX_BYTES)
185
+ throw new EpEnvelopeError("internal", `the artifact at ${subject} is ${stored.data.length} bytes, above the ${CONTRACT_ARTIFACT_MAX_BYTES} document bound; a store that admitted an oversize artifact never serves it (SPEC 13.7)`);
186
+ if (contractArtifactDigestHex(stored.data) !== digestHex)
187
+ throw new EpEnvelopeError("internal", `the artifact at ${subject} does not recompute its digest; verify-on-read is the tamper boundary and fails loud (SPEC 13.7)`);
188
+ try {
189
+ assertCanonicalArtifactBytes(stored.data, `the artifact at ${subject}`);
190
+ }
191
+ catch {
192
+ throw new EpEnvelopeError("internal", `the artifact at ${subject} is not strict canonical JSON; a garbled store never serves (SPEC 13.7)`);
193
+ }
194
+ return stored.data;
195
+ }
196
+ const sha256Ref = (hex) => `sha256:${hex}`;
197
+ /** A manifest digest field is EXACTLY `sha256:<64-hex>` (frozen SPEC 13.7:1858-1861), never a
198
+ * bare `<hex>` or any other spelling (distsys 8dcad72 HIGH): two manifests differing only in
199
+ * digest spelling are both canonical JSON, receive DIFFERENT closure digests, yet verify the same
200
+ * walked graph - so one closure would have two identities. Normalization belongs in the BUILDER's
201
+ * input; the consuming parse requires the canonical prefixed form and refuses anything else. */
202
+ const SHA256_REF = /^sha256:[0-9a-f]{64}$/;
203
+ function assertManifestDigest(ref, what) {
204
+ if (typeof ref !== "string" || !SHA256_REF.test(ref))
205
+ throw new EpEnvelopeError("contract-invalid", `${what} must be exactly "sha256:<64-hex>" (SPEC 13.7); a bare-hex or otherwise-spelled digest gives one closure two identities and never names it`);
206
+ }
207
+ /** Build the canonical manifest for a walked closure: refs normalize, members sort + dedup.
208
+ * The ROOT is named by its own field and belongs in `members` only when a reference
209
+ * re-reaches it (the §13.7 "reachable THROUGH references" rule, pinned here so two
210
+ * implementations always mint the identical manifest). */
211
+ export function buildContractClosureManifest(rootRef, memberRefs) {
212
+ const root = sha256Ref(contractRefToHex(rootRef));
213
+ const members = [...new Set(memberRefs.map((r) => sha256Ref(contractRefToHex(r))))].sort();
214
+ return { v: 1, root, members };
215
+ }
216
+ function parseClosureManifest(value, what) {
217
+ if (value === null || typeof value !== "object" || Array.isArray(value))
218
+ throw new EpEnvelopeError("contract-invalid", `${what} is not a manifest object (SPEC 13.7)`);
219
+ const o = value;
220
+ for (const k of Object.keys(o))
221
+ if (!["v", "root", "members"].includes(k))
222
+ throw new EpEnvelopeError("contract-invalid", `${what} carries the unknown field "${k}"; the manifest schema is closed (SPEC 13.7)`);
223
+ if (o.v !== 1 || typeof o.root !== "string" || !Array.isArray(o.members))
224
+ throw new EpEnvelopeError("contract-invalid", `${what} is not { v: 1, root, members } (SPEC 13.7)`);
225
+ assertManifestDigest(o.root, `${what} root`);
226
+ if (o.members.length > CONTRACT_CLOSURE_MAX_ARTIFACTS)
227
+ throw new EpEnvelopeError("contract-invalid", `${what} names ${o.members.length} members, above the ${CONTRACT_CLOSURE_MAX_ARTIFACTS}-artifact ceiling (SPEC 13.7)`);
228
+ for (let i = 0; i < o.members.length; i++) {
229
+ const m = o.members[i];
230
+ assertManifestDigest(m, `${what} member ${i}`);
231
+ // The canonical form IS sorted + deduplicated: an unsorted or duplicated members list is a
232
+ // DIFFERENT byte sequence claiming the same closure — refused, never silently normalized.
233
+ if (i > 0 && o.members[i - 1] >= m)
234
+ throw new EpEnvelopeError("contract-invalid", `${what} members are not strictly sorted/deduplicated at index ${i}; a noncanonical manifest never names a closure (SPEC 13.7)`);
235
+ }
236
+ return { v: 1, root: o.root, members: o.members };
237
+ }
238
+ /** Publish a closure's manifest as an ordinary canonical artifact; the returned digest IS the
239
+ * closure digest (§13.7). */
240
+ export async function publishContractClosureManifest(ctx, manifest) {
241
+ resources(ctx); // brand-check (resources unused here; the delegated publish/fetch use them)
242
+ const value = parseClosureManifest(manifest, "the manifest");
243
+ const res = await publishContractArtifact(ctx, contractArtifactCanonicalBytes(value));
244
+ return { closureDigestHex: res.digestHex, won: res.won };
245
+ }
246
+ /** Fetch and VERIFY a closure by its CLOSURE digest (§13.7): fetch the manifest artifact at
247
+ * that digest (its identity is proven by the fetch), then walk the by-digest references from
248
+ * `root` through the `extractRefs` resolution seam and PROVE the walked set equals
249
+ * `manifest.members` exactly — an under-naming manifest (the walk reaches an unlisted
250
+ * artifact) and an over-naming one (a listed member is never reached) both refuse; a missing
251
+ * artifact anywhere is all-or-nothing loud. The walk is BOUNDED: the frozen closure byte
252
+ * bound, the reference-chain depth, the artifact-count ceiling (non-raiseable; a caller may
253
+ * narrow), a per-artifact reference cap, and ONE total monotonic time budget. `extractRefs`
254
+ * receives a DETACHED copy of each artifact's bytes (a mutating seam cannot poison the
255
+ * returned map) and its answer is size-capped. Returns digest → bytes (manifest excluded;
256
+ * root first, then first-visit order) plus the parsed manifest. */
257
+ export async function fetchContractClosure(ctx, closureDigestRef, extractRefs, opts = {}) {
258
+ resources(ctx); // brand-check (resources unused here; the delegated publish/fetch use them)
259
+ const max = opts.maxArtifacts ?? CONTRACT_CLOSURE_MAX_ARTIFACTS;
260
+ if (!Number.isSafeInteger(max) || max <= 0 || max > CONTRACT_CLOSURE_MAX_ARTIFACTS)
261
+ throw new EpEnvelopeError("failed-precondition", `maxArtifacts must be a positive integer at or below the frozen ${CONTRACT_CLOSURE_MAX_ARTIFACTS}-artifact ceiling (a caller narrows, never widens); got ${JSON.stringify(opts.maxArtifacts)} (SPEC 13.7)`);
262
+ const budgetMs = opts.walkBudgetMs ?? 30_000;
263
+ if (!Number.isSafeInteger(budgetMs) || budgetMs <= 0)
264
+ throw new EpEnvelopeError("failed-precondition", `walkBudgetMs must be a positive integer; got ${JSON.stringify(opts.walkBudgetMs)}`);
265
+ if (typeof extractRefs !== "function")
266
+ throw new EpEnvelopeError("failed-precondition", "a closure fetch requires the reference-resolution seam (extractRefs); the store never guesses a document's reference shape (SPEC 13.7)");
267
+ const startedAt = performance.now();
268
+ const overBudget = () => performance.now() - startedAt > budgetMs;
269
+ // The ONE monotonic budget bounds the WHOLE walk, including the awaited reads and the synchronous
270
+ // extractor (distsys 8dcad72 M1): every Direct Get is raced against the REMAINING budget (a stuck
271
+ // read is a bounded deadline, never a hang), and overBudget() is checked after each extractRefs
272
+ // and before returning, so a slow synchronous seam cannot blow the budget and still return success.
273
+ const raceBudget = async (p, what) => {
274
+ const rem = budgetMs - (performance.now() - startedAt);
275
+ if (rem <= 0)
276
+ throw new EpEnvelopeError("deadline-exceeded", `the closure walk exhausted its ${budgetMs}ms budget before ${what} (SPEC 13.7/13.8)`);
277
+ let timer;
278
+ const deadline = new Promise((_, reject) => { timer = setTimeout(() => reject(new EpEnvelopeError("deadline-exceeded", `the closure walk exceeded its ${budgetMs}ms budget during ${what}; a closure fetch is bounded and fails loud, never hangs (SPEC 13.7/13.8)`)), rem); });
279
+ try {
280
+ return await Promise.race([p, deadline]);
281
+ }
282
+ finally {
283
+ clearTimeout(timer);
284
+ }
285
+ };
286
+ const closureHex = contractRefToHex(closureDigestRef);
287
+ const manifestBytes = await raceBudget(fetchContractArtifact(ctx, closureHex), `the manifest fetch for ${closureHex}`);
288
+ if (manifestBytes === undefined)
289
+ throw new EpEnvelopeError("failed-precondition", `the closure manifest ${closureHex} is not published; a closure digest names its manifest artifact (SPEC 13.7)`);
290
+ const manifest = parseClosureManifest(assertCanonicalArtifactBytes(manifestBytes, `the manifest ${closureHex}`), `the manifest ${closureHex}`);
291
+ const rootHex = contractRefToHex(manifest.root);
292
+ const out = new Map();
293
+ let totalBytes = 0;
294
+ let rootReReached = false; // a reference naming the root makes it reference-reachable (a member)
295
+ // BFS with depth tracking: the queue carries (hex, depth); depth is the reference-chain
296
+ // length from the root (§13.7 ref chain <= 32).
297
+ const queue = [{ hex: rootHex, depth: 0 }];
298
+ while (queue.length > 0) {
299
+ if (overBudget())
300
+ throw new EpEnvelopeError("deadline-exceeded", `the closure walk for ${closureHex} exceeded its ${budgetMs}ms budget; a closure fetch is bounded and fails loud, never hangs (SPEC 13.7/13.8)`);
301
+ const { hex, depth } = queue.shift();
302
+ // The reference-chain depth is checked on EVERY dequeued edge, BEFORE the visited dedupe
303
+ // (distsys 8dcad72 M4): an over-depth edge that happens to re-reach an already-visited node
304
+ // (e.g. a 33-deep cycle back to the root) must still trip the bound, never be silently skipped.
305
+ if (depth > CONTRACT_CLOSURE_MAX_REF_DEPTH)
306
+ throw new EpEnvelopeError("contract-invalid", `the closure walk for ${closureHex} exceeds the ${CONTRACT_CLOSURE_MAX_REF_DEPTH}-deep reference chain bound (SPEC 13.7)`);
307
+ if (out.has(hex))
308
+ continue; // cycle/diamond-safe (after the depth bound)
309
+ if (out.size >= max)
310
+ throw new EpEnvelopeError("failed-precondition", `the contract closure exceeds the ${max}-artifact bound; a truncated closure never verifies as complete (SPEC 13.7)`);
311
+ const bytes = await raceBudget(fetchContractArtifact(ctx, hex), `the fetch of ${hex}`);
312
+ if (bytes === undefined)
313
+ throw new EpEnvelopeError("failed-precondition", `the closure references artifact ${hex} but it is not published; a closure is fetched all-or-nothing (SPEC 13.7)`);
314
+ totalBytes += bytes.length;
315
+ if (totalBytes > CONTRACT_CLOSURE_MAX_BYTES)
316
+ throw new EpEnvelopeError("contract-invalid", `the closure for ${closureHex} exceeds the ${CONTRACT_CLOSURE_MAX_BYTES}-byte bound (SPEC 13.7)`);
317
+ out.set(hex, bytes);
318
+ const refs = extractRefs(new Uint8Array(bytes), hex); // DETACHED copy (a real copy — Buffer.slice would ALIAS the stored bytes): a mutating seam cannot poison the returned map
319
+ if (!Array.isArray(refs) || !refs.every((r) => typeof r === "string"))
320
+ throw new EpEnvelopeError("internal", `the reference-resolution seam returned a non-string-array for ${hex}; a garbled resolution never extends a closure (SPEC 13.7)`);
321
+ if (refs.length > CONTRACT_CLOSURE_MAX_ARTIFACTS)
322
+ throw new EpEnvelopeError("contract-invalid", `artifact ${hex} names ${refs.length} references, above the ${CONTRACT_CLOSURE_MAX_ARTIFACTS}-reference cap; an unbounded reference list never extends a closure (SPEC 13.7)`);
323
+ if (overBudget()) // a slow synchronous extractRefs cannot be interrupted mid-run, but it must not blow the budget and still return success (M1)
324
+ throw new EpEnvelopeError("deadline-exceeded", `the closure walk for ${closureHex} exceeded its ${budgetMs}ms budget resolving references for ${hex} (SPEC 13.7/13.8)`);
325
+ for (const r of refs) {
326
+ const rHex = contractRefToHex(r);
327
+ if (rHex === rootHex)
328
+ rootReReached = true; // a cycle back makes the root a member too
329
+ queue.push({ hex: rHex, depth: depth + 1 });
330
+ }
331
+ }
332
+ // The walked reachable-THROUGH-references set must equal the manifest's members EXACTLY
333
+ // (§13.7): the root belongs iff a reference re-reached it — tracked during the walk, so
334
+ // exactly ONE manifest (one closure digest) names any given closure, never two.
335
+ const walked = new Set();
336
+ for (const hex of out.keys())
337
+ if (hex !== rootHex || rootReReached)
338
+ walked.add(sha256Ref(hex));
339
+ const memberSet = new Set(manifest.members);
340
+ for (const m of walked)
341
+ if (!memberSet.has(m))
342
+ throw new EpEnvelopeError("contract-invalid", `the closure walk reached ${m} but the manifest ${closureHex} does not name it; an under-naming manifest never verifies (SPEC 13.7)`);
343
+ for (const m of memberSet)
344
+ if (!walked.has(m))
345
+ throw new EpEnvelopeError("contract-invalid", `the manifest ${closureHex} names ${m} but the walk never reached it; an over-naming manifest never verifies (SPEC 13.7)`);
346
+ return { manifest, artifacts: out };
347
+ }
348
+ //# sourceMappingURL=endpoint-contract-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-contract-store.js","sourceRoot":"","sources":["../src/endpoint-contract-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * v0.4 endpoint control-surface envelope (SPEC §13.3) — the versioned typed shapes riding the
3
+ * §13.2 rails (`EndpointRequest`/`EndpointReply`/`EndpointEvent`), the structured error catalog,
4
+ * W3C Trace Context correlation, and the consuming-boundary validators.
5
+ *
6
+ * Validation is FAIL-LOUD with the exact catalog code the spec assigns to each violation
7
+ * (`unsupported-version`, `bad-request`, `contract-mismatch`, `op-mismatch`, `target-mismatch`,
8
+ * `sender-mismatch`) so a rejecting boundary never invents a classification. Unknown object
9
+ * fields are ignored (§5); the parsers return a picked copy carrying exactly the defined fields,
10
+ * so nothing downstream can quietly grow a dependency on an undeclared one. Contract-schema
11
+ * validation of `args`/`data` is §13.7's job ({@link import("./schema-profile.js")}); the helpers
12
+ * here only map its outcome to the invocation-time code (`bad-request`, distinct from
13
+ * registration-time `contract-invalid`).
14
+ */
15
+ import type { ValidateFunction } from "ajv/dist/2020.js";
16
+ import { type ParsedEpRequest } from "./endpoint-subjects.js";
17
+ import type { EndpointRef } from "./types.js";
18
+ /** The envelope schema version — independent of the wire `protocolVersion`; starts at its own
19
+ * v1 inside the v0.4 revision. Other values are rejected (`unsupported-version`). */
20
+ export declare const EP_ENVELOPE_V = 1;
21
+ /** The §13.3 error catalog. Extensions add codes only under reverse-DNS; any code (catalog or
22
+ * extension) is one token of at most 64 bytes. */
23
+ export declare const EP_ERROR_CODES: readonly ["bad-request", "unsupported-version", "op-mismatch", "class-mismatch", "target-mismatch", "sender-mismatch", "unauthenticated", "permission-denied", "not-found", "already-exists", "conflict", "contract-mismatch", "contract-invalid", "failed-precondition", "deadline-exceeded", "cancelled", "expired", "unavailable", "unimplemented", "resource-exhausted", "internal"];
24
+ export type EpErrorCode = (typeof EP_ERROR_CODES)[number];
25
+ /** True iff `code` is a catalog token or a reverse-DNS extension token within the 64-byte bound. */
26
+ export declare function isEpErrorCode(code: string): boolean;
27
+ /** One `details[]` entry: `kind` is reverse-DNS-namespaced (§13.3), the rest is open. */
28
+ export interface EpErrorDetail {
29
+ kind: string;
30
+ [key: string]: unknown;
31
+ }
32
+ /** The `EndpointReply.error` shape. */
33
+ export interface EpError {
34
+ code: string;
35
+ message: string;
36
+ details?: EpErrorDetail[];
37
+ }
38
+ /** A consuming-boundary rejection: the catalog code plus a human message. Boundaries convert it
39
+ * to an `EndpointReply` error via {@link EpEnvelopeError.toEpError} (or, on reply-less planes,
40
+ * to the §13.4 decision/quarantine fact carrying the same code). */
41
+ export declare class EpEnvelopeError extends Error {
42
+ readonly code: EpErrorCode;
43
+ readonly details?: EpErrorDetail[] | undefined;
44
+ constructor(code: EpErrorCode, message: string, details?: EpErrorDetail[] | undefined);
45
+ toEpError(): EpError;
46
+ }
47
+ /** W3C Trace Context correlation slot, propagated to downstream calls, events, facts, receipts. */
48
+ export interface EpCorrelation {
49
+ traceparent?: string;
50
+ tracestate?: string;
51
+ baggage?: string;
52
+ }
53
+ /** The invocation binding: endpoint + command MUST agree with the subject (`op-mismatch`); the
54
+ * digests pin the described contract and are REQUIRED on every command except `describe`
55
+ * (`contract-mismatch` when missing — a payload-free side pins the void schema's digest). */
56
+ export interface EpOp {
57
+ endpoint: string;
58
+ command: string;
59
+ inputDigest?: string;
60
+ outputDigest?: string;
61
+ }
62
+ /** The body target block (§13.3): present exactly for the targeted modes, `owner` pinned to the
63
+ * subject token; `actor`/`lifecycleUid` are validator-compared against the current mapping. */
64
+ export interface EpTargetBlock {
65
+ owner: string;
66
+ actor: string;
67
+ lifecycleUid: string;
68
+ mappingRevision?: number;
69
+ }
70
+ /** A submission's declared delivery contract (`record` is a state contract, never a request
71
+ * class; an action command's submissions are `journal`). */
72
+ export type EpClass = "ephemeral" | "journal";
73
+ export interface EndpointRequest {
74
+ v: typeof EP_ENVELOPE_V;
75
+ id: string;
76
+ op: EpOp;
77
+ class: EpClass;
78
+ /** The verb: `true` = call (reply expected, `deadlineMs` required), `false` = cast. The
79
+ * subject shape is identical for both; the verb never changes the grammar. */
80
+ replyExpected: boolean;
81
+ /** MUST for a command whose contract declares the action composite (a contract-level rule the
82
+ * serve machinery enforces with the contract in hand); shape-checked here when present. */
83
+ goalId?: string;
84
+ target?: EpTargetBlock;
85
+ /** The input payload: a JSON object, or explicit `null` — a canonical-void side's payload is
86
+ * absent OR `null` (§13.7), so `null` must survive parsing for the command's own schema
87
+ * validator to decide (an object-input contract still rejects it there, as `bad-request`). */
88
+ args?: Record<string, unknown> | null;
89
+ from: EndpointRef;
90
+ /** Caller deadline budget, bounded never unbounded: required for calls and for journal-class
91
+ * submissions (there it is the decision deadline, §13.4). */
92
+ deadlineMs?: number;
93
+ correlation?: EpCorrelation;
94
+ /** Opaque signed authorization-context slot; identity never rides it. Its fingerprint binding
95
+ * is {@link authDigest} over these bytes exactly as carried. */
96
+ auth?: string;
97
+ }
98
+ export interface EndpointReply {
99
+ v: typeof EP_ENVELOPE_V;
100
+ id: string;
101
+ ok: boolean;
102
+ data?: unknown;
103
+ error?: EpError;
104
+ /** Opaque signed receipt slot (§13.10). */
105
+ receipt?: string;
106
+ }
107
+ /** An event (incl. per-goal progress) on the `epe` plane. The publishing instance and epoch are
108
+ * read from the SUBJECT (§13.2), never from payload fields. */
109
+ export interface EndpointEvent {
110
+ v: typeof EP_ENVELOPE_V;
111
+ topic: string;
112
+ ts: number;
113
+ data: unknown;
114
+ correlation?: EpCorrelation;
115
+ }
116
+ /** `authDigest`: `sha256:<hex>` over the UTF-8 bytes of the `auth` slot EXACTLY as carried. The
117
+ * slot is already a canonical signed artifact, so it is digested as bytes, never
118
+ * re-canonicalized; absent from the §13.4 fingerprint iff `auth` is absent. A malformed-UTF-16
119
+ * slot is refused (`bad-request`): a lone surrogate has no UTF-8 encoding, so its "digest"
120
+ * would be over a substituted value and two distinct slots could share one fingerprint. */
121
+ export declare function authDigest(auth: string): string;
122
+ /** Shape-validate an incoming request envelope (the pre-subject half of the consuming boundary;
123
+ * {@link checkRequestSubjectAgreement} is the other half). Throws {@link EpEnvelopeError} with
124
+ * the exact catalog code; returns a picked copy with exactly the §13.3 fields. */
125
+ export declare function parseEndpointRequest(raw: unknown): EndpointRequest;
126
+ /** The body↔subject agreement half of the consuming boundary (§13.3): `op` MUST agree with the
127
+ * subject (`op-mismatch`); the body target is ABSENT for `self`/untargeted forms (a supplied
128
+ * one is `target-mismatch`, never ignored) and REQUIRED with a subject-equal owner (and, in
129
+ * `handle` mode, subject-equal actor + lifecycleUid) for the targeted forms; `from.id` MUST
130
+ * equal the subject sender principal (`sender-mismatch`). Currency of `target.actor`/
131
+ * `target.lifecycleUid` against the live mapping is the handler's fresh-read (`expired`),
132
+ * deliberately not checkable here. */
133
+ export declare function checkRequestSubjectAgreement(env: EndpointRequest, subject: ParsedEpRequest): void;
134
+ /** The contract-class agreement check (`class-mismatch`): the envelope's declared class MUST
135
+ * equal the command's contract class. Split out because it needs the contract in hand. */
136
+ export declare function assertClassMatches(env: EndpointRequest, declaredClass: EpClass): void;
137
+ /** Shape-validate a reply at the caller's consuming boundary. `data` is schema-validated by the
138
+ * caller against its PINNED output digest (§13.7), not here. */
139
+ export declare function parseEndpointReply(raw: unknown): EndpointReply;
140
+ /** Shape-validate an event at its consuming boundary (§13.3: every plane is runtime-validated).
141
+ * The publishing instance and epoch come from the SUBJECT; payload claims are display data. */
142
+ export declare function parseEndpointEvent(raw: unknown): EndpointEvent;
143
+ /** Validate `args` against the command's compiled input schema BEFORE any effect: failure is the
144
+ * invocation-time `bad-request` (registration-time violations are `contract-invalid`,
145
+ * {@link import("./schema-profile.js").ContractInvalidError}). Against the void schema the
146
+ * payload is absent or `null` (§13.7), so `undefined` args validate as `null` here and only
147
+ * here; an explicit `null` passes through unchanged, and it is the SCHEMA (an object-typed
148
+ * input contract) that rejects null for non-void commands. The §13.8 validation budget is the
149
+ * PROFILE's fixed 10ms, read internally so no caller
150
+ * can tune it away, and is enforced post-hoc, fail-loud as `bad-request` (the spec's
151
+ * over-budget code for validate time, distinct from compile's `contract-invalid`). Post-hoc
152
+ * measurement classifies, it cannot preempt — the pre-emptive defense is the registration-time
153
+ * bounded-pattern gate (schema-profile), which keeps the exponential backtracking class out of
154
+ * registered contracts in the first place. */
155
+ export declare function assertArgsValid(validate: ValidateFunction, args: Record<string, unknown> | null | undefined): unknown;
156
+ /** Validate an output payload against the command's compiled output schema at EITHER §13.7
157
+ * boundary — the responder's, before the success publish, or the caller's, on the consumed
158
+ * reply — the symmetric budgeted half of {@link assertArgsValid}, under the SAME fixed
159
+ * §13.8 `validateBudgetMs` (read internally, never caller-tunable). Both failure classes are
160
+ * structured `internal`: an invalid output is a responder bug (§13.3/§13.7) whichever side
161
+ * detects it, and an over-budget output validation is the same bug class, never the caller's
162
+ * `bad-request`. A void output is `undefined`, validated as `null` against the void schema,
163
+ * mirroring the args side. */
164
+ export declare function assertOutputValid(validate: ValidateFunction, data: unknown): void;
165
+ //# sourceMappingURL=endpoint-envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-envelope.d.ts","sourceRoot":"","sources":["../src/endpoint-envelope.ts"],"names":[],"mappings":"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"}