@noeos/verification-engine 0.0.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 (184) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +11 -0
  4. package/README.md +7 -0
  5. package/dist/cjs/api/engine.js +271 -0
  6. package/dist/cjs/api/types.js +10 -0
  7. package/dist/cjs/chains/chain-builder.js +541 -0
  8. package/dist/cjs/chains/duplicate-detector.js +208 -0
  9. package/dist/cjs/chains/verify-chain.js +656 -0
  10. package/dist/cjs/contracts/generated.js +512 -0
  11. package/dist/cjs/contracts/schema-assets.js +6 -0
  12. package/dist/cjs/contracts/vector-assets.js +6 -0
  13. package/dist/cjs/domain/algorithm-id.js +5 -0
  14. package/dist/cjs/domain/byte-view.js +7 -0
  15. package/dist/cjs/domain/chain.js +3 -0
  16. package/dist/cjs/domain/diagnostic.js +6 -0
  17. package/dist/cjs/domain/digest.js +37 -0
  18. package/dist/cjs/domain/duplicate-policy.js +3 -0
  19. package/dist/cjs/domain/evidence.js +10 -0
  20. package/dist/cjs/domain/identifiers.js +52 -0
  21. package/dist/cjs/domain/json-value.js +3 -0
  22. package/dist/cjs/domain/limits.js +24 -0
  23. package/dist/cjs/domain/operation-result.js +19 -0
  24. package/dist/cjs/domain/position.js +16 -0
  25. package/dist/cjs/domain/protocol-version.js +5 -0
  26. package/dist/cjs/domain/rule.js +3 -0
  27. package/dist/cjs/domain/stream.js +3 -0
  28. package/dist/cjs/domain/version.js +16 -0
  29. package/dist/cjs/evidence/digest-evidence.js +22 -0
  30. package/dist/cjs/evidence/evidence-parser.js +288 -0
  31. package/dist/cjs/framing/frame-builders.js +124 -0
  32. package/dist/cjs/framing/frame-encoder.js +238 -0
  33. package/dist/cjs/framing/frame-parser.js +173 -0
  34. package/dist/cjs/framing/frame-types.js +3 -0
  35. package/dist/cjs/hashing/hash-adapter.js +90 -0
  36. package/dist/cjs/hashing/hash-frame.js +16 -0
  37. package/dist/cjs/index.js +16 -0
  38. package/dist/cjs/normalization/byte-sink.js +70 -0
  39. package/dist/cjs/normalization/jcs-profile.js +154 -0
  40. package/dist/cjs/normalization/normalize.js +56 -0
  41. package/dist/cjs/normalization/profile-registry.js +66 -0
  42. package/dist/cjs/normalization/profile.js +3 -0
  43. package/dist/cjs/normalization/raw-bytes-profile.js +27 -0
  44. package/dist/cjs/package.json +3 -0
  45. package/dist/cjs/profiles.js +9 -0
  46. package/dist/cjs/records/record-service.js +278 -0
  47. package/dist/cjs/rules/rule-set.js +211 -0
  48. package/dist/cjs/schemas.js +6 -0
  49. package/dist/cjs/validation/algorithm-validation.js +12 -0
  50. package/dist/cjs/validation/diagnostic-collector.js +159 -0
  51. package/dist/cjs/validation/digest-validation.js +48 -0
  52. package/dist/cjs/validation/identifier-validation.js +33 -0
  53. package/dist/cjs/validation/json-text-parser.js +297 -0
  54. package/dist/cjs/validation/json-value-validation.js +155 -0
  55. package/dist/cjs/validation/limit-validation.js +75 -0
  56. package/dist/cjs/validation/object-inspection.js +60 -0
  57. package/dist/cjs/validation/position-validation.js +13 -0
  58. package/dist/cjs/validation/result-helpers.js +9 -0
  59. package/dist/cjs/validation/utf8-validation.js +69 -0
  60. package/dist/cjs/validation/version-validation.js +31 -0
  61. package/dist/cjs/vectors.js +6 -0
  62. package/dist/esm/api/engine.js +266 -0
  63. package/dist/esm/api/types.js +4 -0
  64. package/dist/esm/chains/chain-builder.js +536 -0
  65. package/dist/esm/chains/duplicate-detector.js +204 -0
  66. package/dist/esm/chains/verify-chain.js +652 -0
  67. package/dist/esm/contracts/generated.js +509 -0
  68. package/dist/esm/contracts/schema-assets.js +2 -0
  69. package/dist/esm/contracts/vector-assets.js +2 -0
  70. package/dist/esm/domain/algorithm-id.js +2 -0
  71. package/dist/esm/domain/byte-view.js +4 -0
  72. package/dist/esm/domain/chain.js +2 -0
  73. package/dist/esm/domain/diagnostic.js +3 -0
  74. package/dist/esm/domain/digest.js +32 -0
  75. package/dist/esm/domain/duplicate-policy.js +2 -0
  76. package/dist/esm/domain/evidence.js +7 -0
  77. package/dist/esm/domain/identifiers.js +45 -0
  78. package/dist/esm/domain/json-value.js +2 -0
  79. package/dist/esm/domain/limits.js +21 -0
  80. package/dist/esm/domain/operation-result.js +15 -0
  81. package/dist/esm/domain/position.js +12 -0
  82. package/dist/esm/domain/protocol-version.js +2 -0
  83. package/dist/esm/domain/rule.js +2 -0
  84. package/dist/esm/domain/stream.js +2 -0
  85. package/dist/esm/domain/version.js +12 -0
  86. package/dist/esm/evidence/digest-evidence.js +19 -0
  87. package/dist/esm/evidence/evidence-parser.js +281 -0
  88. package/dist/esm/framing/frame-builders.js +114 -0
  89. package/dist/esm/framing/frame-encoder.js +234 -0
  90. package/dist/esm/framing/frame-parser.js +170 -0
  91. package/dist/esm/framing/frame-types.js +2 -0
  92. package/dist/esm/hashing/hash-adapter.js +84 -0
  93. package/dist/esm/hashing/hash-frame.js +12 -0
  94. package/dist/esm/index.js +5 -0
  95. package/dist/esm/normalization/byte-sink.js +66 -0
  96. package/dist/esm/normalization/jcs-profile.js +151 -0
  97. package/dist/esm/normalization/normalize.js +52 -0
  98. package/dist/esm/normalization/profile-registry.js +62 -0
  99. package/dist/esm/normalization/profile.js +2 -0
  100. package/dist/esm/normalization/raw-bytes-profile.js +24 -0
  101. package/dist/esm/profiles.js +6 -0
  102. package/dist/esm/records/record-service.js +270 -0
  103. package/dist/esm/rules/rule-set.js +206 -0
  104. package/dist/esm/schemas.js +2 -0
  105. package/dist/esm/validation/algorithm-validation.js +9 -0
  106. package/dist/esm/validation/diagnostic-collector.js +154 -0
  107. package/dist/esm/validation/digest-validation.js +43 -0
  108. package/dist/esm/validation/identifier-validation.js +27 -0
  109. package/dist/esm/validation/json-text-parser.js +294 -0
  110. package/dist/esm/validation/json-value-validation.js +152 -0
  111. package/dist/esm/validation/limit-validation.js +71 -0
  112. package/dist/esm/validation/object-inspection.js +54 -0
  113. package/dist/esm/validation/position-validation.js +10 -0
  114. package/dist/esm/validation/result-helpers.js +6 -0
  115. package/dist/esm/validation/utf8-validation.js +63 -0
  116. package/dist/esm/validation/version-validation.js +26 -0
  117. package/dist/esm/vectors.js +2 -0
  118. package/dist/types/api/engine.d.ts +8 -0
  119. package/dist/types/api/types.d.ts +124 -0
  120. package/dist/types/chains/chain-builder.d.ts +42 -0
  121. package/dist/types/chains/duplicate-detector.d.ts +18 -0
  122. package/dist/types/chains/verify-chain.d.ts +9 -0
  123. package/dist/types/contracts/generated.d.ts +442 -0
  124. package/dist/types/contracts/schema-assets.d.ts +2 -0
  125. package/dist/types/contracts/vector-assets.d.ts +2 -0
  126. package/dist/types/domain/algorithm-id.d.ts +4 -0
  127. package/dist/types/domain/byte-view.d.ts +1 -0
  128. package/dist/types/domain/chain.d.ts +43 -0
  129. package/dist/types/domain/diagnostic.d.ts +23 -0
  130. package/dist/types/domain/digest.d.ts +12 -0
  131. package/dist/types/domain/duplicate-policy.d.ts +26 -0
  132. package/dist/types/domain/evidence.d.ts +100 -0
  133. package/dist/types/domain/identifiers.d.ts +29 -0
  134. package/dist/types/domain/json-value.d.ts +6 -0
  135. package/dist/types/domain/limits.d.ts +13 -0
  136. package/dist/types/domain/operation-result.d.ts +12 -0
  137. package/dist/types/domain/position.d.ts +8 -0
  138. package/dist/types/domain/protocol-version.d.ts +2 -0
  139. package/dist/types/domain/rule.d.ts +34 -0
  140. package/dist/types/domain/stream.d.ts +5 -0
  141. package/dist/types/domain/version.d.ts +8 -0
  142. package/dist/types/evidence/digest-evidence.d.ts +4 -0
  143. package/dist/types/evidence/evidence-parser.d.ts +8 -0
  144. package/dist/types/framing/frame-builders.d.ts +40 -0
  145. package/dist/types/framing/frame-encoder.d.ts +6 -0
  146. package/dist/types/framing/frame-parser.d.ts +4 -0
  147. package/dist/types/framing/frame-types.d.ts +27 -0
  148. package/dist/types/hashing/hash-adapter.d.ts +12 -0
  149. package/dist/types/hashing/hash-frame.d.ts +6 -0
  150. package/dist/types/index.d.ts +8 -0
  151. package/dist/types/normalization/byte-sink.d.ts +19 -0
  152. package/dist/types/normalization/jcs-profile.d.ts +3 -0
  153. package/dist/types/normalization/normalize.d.ts +11 -0
  154. package/dist/types/normalization/profile-registry.d.ts +26 -0
  155. package/dist/types/normalization/profile.d.ts +22 -0
  156. package/dist/types/normalization/raw-bytes-profile.d.ts +2 -0
  157. package/dist/types/profiles.d.ts +8 -0
  158. package/dist/types/records/record-service.d.ts +38 -0
  159. package/dist/types/rules/rule-set.d.ts +13 -0
  160. package/dist/types/schemas.d.ts +2 -0
  161. package/dist/types/validation/algorithm-validation.d.ts +3 -0
  162. package/dist/types/validation/diagnostic-collector.d.ts +24 -0
  163. package/dist/types/validation/digest-validation.d.ts +6 -0
  164. package/dist/types/validation/identifier-validation.d.ts +6 -0
  165. package/dist/types/validation/json-text-parser.d.ts +4 -0
  166. package/dist/types/validation/json-value-validation.d.ts +4 -0
  167. package/dist/types/validation/limit-validation.d.ts +4 -0
  168. package/dist/types/validation/object-inspection.d.ts +11 -0
  169. package/dist/types/validation/position-validation.d.ts +3 -0
  170. package/dist/types/validation/result-helpers.d.ts +3 -0
  171. package/dist/types/validation/utf8-validation.d.ts +5 -0
  172. package/dist/types/validation/version-validation.d.ts +9 -0
  173. package/dist/types/vectors.d.ts +2 -0
  174. package/package.json +61 -0
  175. package/schemas/chain-summary.v1.schema.json +156 -0
  176. package/schemas/diagnostic.v1.schema.json +107 -0
  177. package/schemas/link-evidence.v1.schema.json +165 -0
  178. package/schemas/record-evidence.v1.schema.json +91 -0
  179. package/schemas/vector-set.v1.schema.json +52 -0
  180. package/vectors/evidence.json +26 -0
  181. package/vectors/framing.json +136 -0
  182. package/vectors/hashing.json +58 -0
  183. package/vectors/invalid.json +56 -0
  184. package/vectors/manifest.json +46 -0
@@ -0,0 +1,536 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import { CHAIN_SUMMARY_EVIDENCE_SCHEMA, LINK_EVIDENCE_SCHEMA } from "../domain/evidence.js";
3
+ import { failure, success } from "../domain/operation-result.js";
4
+ import { buildTrustedLinkFrame } from "../framing/frame-builders.js";
5
+ import { hashTrustedFrame } from "../hashing/hash-frame.js";
6
+ import { computeRecord, validateProfile, } from "../records/record-service.js";
7
+ import { RuleSet } from "../rules/rule-set.js";
8
+ import { DiagnosticCollector } from "../validation/diagnostic-collector.js";
9
+ import { validateAlgorithmId } from "../validation/algorithm-validation.js";
10
+ import { equalDigest, validateDigest } from "../validation/digest-validation.js";
11
+ import { validateContextId, validateRecordId, validateSequenceId, } from "../validation/identifier-validation.js";
12
+ import { inspectPlainObject } from "../validation/object-inspection.js";
13
+ import { validatePosition } from "../validation/position-validation.js";
14
+ import { createDuplicateDetector, observedLink } from "./duplicate-detector.js";
15
+ export class ChainLifecycleError extends Error {
16
+ code;
17
+ constructor(code) {
18
+ super(code);
19
+ this.code = code;
20
+ this.name = "ChainLifecycleError";
21
+ }
22
+ }
23
+ export class ChainBuilder {
24
+ config;
25
+ rules;
26
+ options;
27
+ state = "active";
28
+ nextPosition = 0;
29
+ previous = Object.freeze({ kind: "none" });
30
+ firstDigest;
31
+ finalDigest;
32
+ diagnostics;
33
+ count = 0;
34
+ duplicates;
35
+ operationActive = false;
36
+ recordServiceOptions;
37
+ constructor(config, rules, options) {
38
+ this.config = config;
39
+ this.rules = rules;
40
+ this.options = options;
41
+ this.diagnostics = new DiagnosticCollector(options.limits);
42
+ this.duplicates = createDuplicateDetector(config.duplicatePolicy, options.limits);
43
+ this.recordServiceOptions = Object.freeze({
44
+ limits: options.limits,
45
+ profiles: options.profiles,
46
+ rules,
47
+ });
48
+ }
49
+ static create(input, options) {
50
+ const config = validateChainConfig(input, options.limits);
51
+ if (!config.ok)
52
+ return config;
53
+ const rules = RuleSet.create(config.value.rules, options.limits);
54
+ if (!rules.ok)
55
+ return rules;
56
+ return success(new ChainBuilder(config.value, rules.value, options));
57
+ }
58
+ append(input) {
59
+ if (this.operationActive)
60
+ return failure([createInternalDiagnostic("CONCURRENT_USE_FORBIDDEN")]);
61
+ return this.appendCore(input);
62
+ }
63
+ appendCore(input) {
64
+ this.requireActive();
65
+ const chainInput = validateChainRecordInput(input, this.config.algorithm, this.options.limits);
66
+ if (!chainInput.ok)
67
+ return chainInput;
68
+ const collector = new DiagnosticCollector(this.options.limits);
69
+ if (chainInput.value.position !== this.nextPosition) {
70
+ collector.addCode("POSITION_MISMATCH", "link", { position: chainInput.value.position });
71
+ }
72
+ if (!samePrevious(chainInput.value.previous, this.previous, this.config.algorithm)) {
73
+ collector.addCode("PREVIOUS_LINK_MISMATCH", "link", { position: chainInput.value.position });
74
+ }
75
+ if (collector.hasErrors())
76
+ return failure(collector.finish());
77
+ const record = computeRecord({
78
+ contextId: this.config.contextId,
79
+ recordId: chainInput.value.recordId,
80
+ payload: chainInput.value.payload,
81
+ profile: this.config.profile,
82
+ algorithm: this.config.algorithm,
83
+ }, this.recordServiceOptions);
84
+ if (!record.ok)
85
+ return record;
86
+ addAll(collector, record.diagnostics);
87
+ const previousDigest = chainInput.value.previous.kind === "digest"
88
+ ? validateDigest(chainInput.value.previous.value, this.config.algorithm)
89
+ : undefined;
90
+ if (previousDigest !== undefined && !previousDigest.ok)
91
+ return previousDigest;
92
+ const linkDigest = hashTrustedFrame(this.config.algorithm, buildTrustedLinkFrame({
93
+ algorithm: this.config.algorithm,
94
+ contextId: this.config.contextId,
95
+ sequenceId: this.config.sequenceId,
96
+ position: chainInput.value.position,
97
+ recordId: chainInput.value.recordId,
98
+ recordDigest: record.value.recordDigest,
99
+ ...(previousDigest === undefined ? {} : { previousLinkDigest: previousDigest.value }),
100
+ }, this.options.limits));
101
+ if (!linkDigest.ok)
102
+ return linkDigest;
103
+ const evidence = freezeLinkEvidence({
104
+ ...record.value.evidence,
105
+ $schema: LINK_EVIDENCE_SCHEMA,
106
+ sequenceId: this.config.sequenceId,
107
+ position: chainInput.value.position,
108
+ previous: chainInput.value.previous,
109
+ linkDigest: linkDigest.value.toHex(),
110
+ });
111
+ if (this.rules.hasRules()) {
112
+ addAll(collector, this.rules.evaluate(Object.freeze({
113
+ phase: "link",
114
+ link: evidence,
115
+ recordId: evidence.recordId,
116
+ position: evidence.position,
117
+ }), this.options.limits));
118
+ }
119
+ if (collector.hasErrors())
120
+ return failure(collector.finish());
121
+ const observed = observedLink(evidence);
122
+ const duplicate = this.duplicates.inspect(observed);
123
+ if (!duplicate.ok) {
124
+ this.state = "failed";
125
+ return duplicate;
126
+ }
127
+ addAll(collector, duplicate.value);
128
+ if (collector.hasErrors())
129
+ return failure(collector.finish());
130
+ try {
131
+ this.duplicates.commit(observed);
132
+ this.commit(evidence);
133
+ }
134
+ catch {
135
+ this.state = "failed";
136
+ return failure([createInternalDiagnostic()]);
137
+ }
138
+ addAll(this.diagnostics, collector.finish());
139
+ return success(evidence, collector.finish());
140
+ }
141
+ appendAll(input) {
142
+ if (this.operationActive)
143
+ return failure([createInternalDiagnostic("CONCURRENT_USE_FORBIDDEN")]);
144
+ this.requireActive();
145
+ try {
146
+ for (const item of input) {
147
+ const result = this.append(item);
148
+ if (!result.ok)
149
+ return result;
150
+ }
151
+ }
152
+ catch {
153
+ this.state = "failed";
154
+ return failure([createStreamDiagnostic("INPUT_STREAM_FAILED")]);
155
+ }
156
+ return this.finalize();
157
+ }
158
+ async appendStream(input, options = {}) {
159
+ if (this.operationActive)
160
+ return failure([createInternalDiagnostic("CONCURRENT_USE_FORBIDDEN")]);
161
+ this.requireActive();
162
+ this.operationActive = true;
163
+ let iterator;
164
+ let terminal = false;
165
+ let closeIterator = false;
166
+ try {
167
+ if (isAborted(options.signal)) {
168
+ this.state = "aborted";
169
+ terminal = true;
170
+ return failure([createStreamDiagnostic("OPERATION_ABORTED")]);
171
+ }
172
+ try {
173
+ iterator = input[Symbol.asyncIterator]();
174
+ }
175
+ catch {
176
+ this.state = "failed";
177
+ terminal = true;
178
+ return failure([createStreamDiagnostic("INPUT_STREAM_FAILED")]);
179
+ }
180
+ for (;;) {
181
+ if (isAborted(options.signal)) {
182
+ this.state = "aborted";
183
+ terminal = true;
184
+ closeIterator = true;
185
+ return failure([createStreamDiagnostic("OPERATION_ABORTED")]);
186
+ }
187
+ let next;
188
+ try {
189
+ next = await iterator.next();
190
+ }
191
+ catch {
192
+ this.state = "failed";
193
+ terminal = true;
194
+ closeIterator = true;
195
+ return failure([createStreamDiagnostic("INPUT_STREAM_FAILED")]);
196
+ }
197
+ if (next.done === true) {
198
+ if (isAborted(options.signal)) {
199
+ this.state = "aborted";
200
+ terminal = true;
201
+ closeIterator = true;
202
+ return failure([createStreamDiagnostic("OPERATION_ABORTED")]);
203
+ }
204
+ const finalized = this.finalize();
205
+ terminal = true;
206
+ return finalized;
207
+ }
208
+ const appended = this.appendCore(next.value);
209
+ if (!appended.ok) {
210
+ this.state = "failed";
211
+ terminal = true;
212
+ closeIterator = true;
213
+ return appended;
214
+ }
215
+ if (isAborted(options.signal)) {
216
+ this.state = "aborted";
217
+ terminal = true;
218
+ closeIterator = true;
219
+ return failure([createStreamDiagnostic("OPERATION_ABORTED")]);
220
+ }
221
+ if (options.onEvidence !== undefined) {
222
+ try {
223
+ await options.onEvidence(appended.value);
224
+ }
225
+ catch {
226
+ this.state = "failed";
227
+ terminal = true;
228
+ closeIterator = true;
229
+ return failure([createStreamDiagnostic("OUTPUT_SINK_FAILED")]);
230
+ }
231
+ }
232
+ }
233
+ }
234
+ finally {
235
+ if (iterator !== undefined && (closeIterator || !terminal)) {
236
+ try {
237
+ await iterator.return?.();
238
+ }
239
+ catch {
240
+ this.state = "failed";
241
+ }
242
+ }
243
+ this.operationActive = false;
244
+ }
245
+ }
246
+ snapshot() {
247
+ this.requireReadable();
248
+ return Object.freeze({
249
+ contextId: this.config.contextId,
250
+ sequenceId: this.config.sequenceId,
251
+ profile: Object.freeze({ ...this.config.profile }),
252
+ algorithm: this.config.algorithm,
253
+ nextPosition: this.nextPosition,
254
+ previous: freezePrevious(this.previous),
255
+ count: this.count,
256
+ });
257
+ }
258
+ finalize() {
259
+ this.requireActive();
260
+ if (this.count === 0 && !this.config.allowEmpty) {
261
+ return failure([{ ...createInternalDiagnostic("EMPTY_CHAIN_FORBIDDEN"), phase: "chain" }]);
262
+ }
263
+ const collector = new DiagnosticCollector(this.options.limits);
264
+ if (this.rules.hasRules()) {
265
+ addAll(collector, this.rules.evaluate(Object.freeze({ phase: "chain", chain: this.snapshot() }), this.options.limits));
266
+ }
267
+ if (collector.hasErrors())
268
+ return failure(collector.finish());
269
+ addAll(this.diagnostics, collector.finish());
270
+ const evidence = this.summary("valid", "verified", "verified");
271
+ this.state = "finalized";
272
+ return success(evidence, this.diagnostics.finish());
273
+ }
274
+ abort(reason) {
275
+ void reason;
276
+ if (this.state === "active")
277
+ this.state = "aborted";
278
+ }
279
+ commit(evidence) {
280
+ if (this.count === 0)
281
+ this.firstDigest = evidence.linkDigest;
282
+ this.finalDigest = evidence.linkDigest;
283
+ this.previous = Object.freeze({ kind: "digest", value: evidence.linkDigest });
284
+ this.nextPosition += 1;
285
+ this.count += 1;
286
+ }
287
+ summary(status, start, end) {
288
+ const diagnostics = this.diagnostics.finish();
289
+ const summary = diagnosticSummary(diagnostics);
290
+ const base = {
291
+ $schema: CHAIN_SUMMARY_EVIDENCE_SCHEMA,
292
+ protocolVersion: 1,
293
+ contextId: this.config.contextId,
294
+ sequenceId: this.config.sequenceId,
295
+ profile: Object.freeze({ ...this.config.profile }),
296
+ algorithm: this.config.algorithm,
297
+ count: this.count,
298
+ boundaries: Object.freeze({ start, end }),
299
+ status,
300
+ diagnostics: summary,
301
+ };
302
+ if (this.count === 0)
303
+ return Object.freeze(base);
304
+ if (this.firstDigest === undefined || this.finalDigest === undefined) {
305
+ throw new Error("chain summary invariant broken");
306
+ }
307
+ return Object.freeze({
308
+ ...base,
309
+ firstPosition: 0,
310
+ lastPosition: this.count - 1,
311
+ firstLinkDigest: this.firstDigest,
312
+ finalLinkDigest: this.finalDigest,
313
+ });
314
+ }
315
+ requireActive() {
316
+ if (this.state === "finalized")
317
+ throw new ChainLifecycleError("BUILDER_FINALIZED");
318
+ if (this.state === "failed" || this.state === "aborted")
319
+ throw new ChainLifecycleError("BUILDER_FAILED");
320
+ }
321
+ requireReadable() {
322
+ if (this.state === "failed" || this.state === "aborted")
323
+ throw new ChainLifecycleError("BUILDER_FAILED");
324
+ }
325
+ }
326
+ function validateChainConfig(value, limits) {
327
+ const entries = inspectPlainObject(value);
328
+ if (entries === undefined)
329
+ return invalidConfig(limits);
330
+ const fields = new Map(entries);
331
+ for (const key of fields.keys()) {
332
+ if (![
333
+ "contextId",
334
+ "sequenceId",
335
+ "profile",
336
+ "algorithm",
337
+ "duplicatePolicy",
338
+ "rules",
339
+ "allowEmpty",
340
+ ].includes(key))
341
+ return invalidConfig(limits);
342
+ }
343
+ if (!fields.has("contextId") ||
344
+ !fields.has("sequenceId") ||
345
+ !fields.has("profile") ||
346
+ !fields.has("algorithm")) {
347
+ return invalidConfig(limits);
348
+ }
349
+ const contextId = validateContextId(fields.get("contextId"));
350
+ const sequenceId = validateSequenceId(fields.get("sequenceId"));
351
+ const profile = validateProfile(fields.get("profile"), limits);
352
+ const algorithm = validateAlgorithmId(fields.get("algorithm"));
353
+ const duplicates = validateDuplicatePolicy(fields.get("duplicatePolicy"), limits);
354
+ const allowEmpty = fields.get("allowEmpty") ?? false;
355
+ if (!contextId.ok)
356
+ return contextId;
357
+ if (!sequenceId.ok)
358
+ return sequenceId;
359
+ if (!profile.ok)
360
+ return profile;
361
+ if (!algorithm.ok)
362
+ return algorithm;
363
+ if (!duplicates.ok || typeof allowEmpty !== "boolean")
364
+ return invalidConfig(limits);
365
+ return success(Object.freeze({
366
+ contextId: contextId.value.value,
367
+ sequenceId: sequenceId.value.value,
368
+ profile: profile.value,
369
+ algorithm: algorithm.value,
370
+ duplicatePolicy: duplicates.value,
371
+ rules: fields.get("rules"),
372
+ allowEmpty,
373
+ }));
374
+ }
375
+ function validateDuplicatePolicy(value, limits) {
376
+ if (value === undefined)
377
+ return success(Object.freeze({ kind: "none" }));
378
+ const entries = inspectPlainObject(value);
379
+ if (entries === undefined)
380
+ return invalidConfig(limits);
381
+ const fields = new Map(entries);
382
+ const kind = fields.get("kind");
383
+ if (kind === "none" && fields.size === 1)
384
+ return success(Object.freeze({ kind }));
385
+ if (kind === "window" && fields.size === 2 && typeof fields.get("size") === "number") {
386
+ const size = fields.get("size");
387
+ if (typeof size !== "number" ||
388
+ !Number.isSafeInteger(size) ||
389
+ size < 1 ||
390
+ size > limits.maxFullRecords)
391
+ return invalidConfig(limits);
392
+ return success(Object.freeze({ kind, size }));
393
+ }
394
+ if (kind === "full" && fields.size === 2 && typeof fields.get("maxRecords") === "number") {
395
+ const maxRecords = fields.get("maxRecords");
396
+ if (typeof maxRecords !== "number" ||
397
+ !Number.isSafeInteger(maxRecords) ||
398
+ maxRecords < 1 ||
399
+ maxRecords > limits.maxFullRecords)
400
+ return invalidConfig(limits);
401
+ return success(Object.freeze({ kind, maxRecords }));
402
+ }
403
+ if (kind === "external" && fields.size === 2 && fields.has("index")) {
404
+ const index = fields.get("index");
405
+ const indexEntries = inspectPlainObject(index);
406
+ if (indexEntries === undefined) {
407
+ return invalidConfig(limits);
408
+ }
409
+ const indexFields = new Map(indexEntries);
410
+ const observe = indexFields.get("observe");
411
+ if (indexFields.size !== 1 || typeof observe !== "function")
412
+ return invalidConfig(limits);
413
+ return success(Object.freeze({
414
+ kind,
415
+ index: Object.freeze({
416
+ observe(batch) {
417
+ return Reflect.apply(observe, undefined, [batch]);
418
+ },
419
+ }),
420
+ }));
421
+ }
422
+ return invalidConfig(limits);
423
+ }
424
+ function validateChainRecordInput(value, algorithm, limits) {
425
+ const entries = inspectPlainObject(value);
426
+ if (entries === undefined)
427
+ return invalidConfig(limits);
428
+ const fields = new Map(entries);
429
+ if (fields.size !== 4 ||
430
+ !fields.has("recordId") ||
431
+ !fields.has("payload") ||
432
+ !fields.has("position") ||
433
+ !fields.has("previous")) {
434
+ return invalidConfig(limits);
435
+ }
436
+ const recordId = validateRecordId(fields.get("recordId"));
437
+ const position = validatePosition(fields.get("position"));
438
+ const previous = validatePrevious(fields.get("previous"), algorithm, limits);
439
+ if (!recordId.ok)
440
+ return recordId;
441
+ if (!position.ok)
442
+ return position;
443
+ if (!previous.ok)
444
+ return previous;
445
+ return success(Object.freeze({
446
+ recordId: recordId.value.value,
447
+ payload: fields.get("payload"),
448
+ position: position.value.value,
449
+ previous: previous.value,
450
+ }));
451
+ }
452
+ function validatePrevious(value, algorithm, limits) {
453
+ const entries = inspectPlainObject(value);
454
+ if (entries === undefined)
455
+ return invalidConfig(limits);
456
+ const fields = new Map(entries);
457
+ if (fields.get("kind") === "none" && fields.size === 1)
458
+ return success(Object.freeze({ kind: "none" }));
459
+ if (fields.get("kind") === "digest" && fields.size === 2 && fields.has("value")) {
460
+ const digest = validateDigest(fields.get("value"), algorithm);
461
+ if (!digest.ok)
462
+ return digest;
463
+ return success(Object.freeze({ kind: "digest", value: digest.value.toHex() }));
464
+ }
465
+ return invalidConfig(limits);
466
+ }
467
+ function samePrevious(left, right, algorithm) {
468
+ if (left.kind !== right.kind)
469
+ return false;
470
+ if (left.kind === "none" || right.kind === "none")
471
+ return true;
472
+ const expected = validateDigest(left.value, algorithm);
473
+ const actual = validateDigest(right.value, algorithm);
474
+ return expected.ok && actual.ok && equalDigest(expected.value, actual.value);
475
+ }
476
+ function freezePrevious(value) {
477
+ return value.kind === "none"
478
+ ? Object.freeze({ kind: "none" })
479
+ : Object.freeze({ kind: "digest", value: value.value });
480
+ }
481
+ function freezeLinkEvidence(value) {
482
+ return Object.freeze({
483
+ ...value,
484
+ profile: Object.freeze({ ...value.profile }),
485
+ previous: freezePrevious(value.previous),
486
+ });
487
+ }
488
+ function diagnosticSummary(diagnostics) {
489
+ let errors = 0;
490
+ let warnings = 0;
491
+ let info = 0;
492
+ for (const diagnostic of diagnostics) {
493
+ if (diagnostic.severity === "error")
494
+ errors += 1;
495
+ else if (diagnostic.severity === "warning")
496
+ warnings += 1;
497
+ else
498
+ info += 1;
499
+ }
500
+ return Object.freeze({
501
+ errors,
502
+ warnings,
503
+ info,
504
+ truncated: diagnostics.some(({ code }) => code === "DIAGNOSTIC_LIMIT_REACHED"),
505
+ });
506
+ }
507
+ function addAll(collector, diagnostics) {
508
+ for (const diagnostic of diagnostics)
509
+ collector.add(diagnostic);
510
+ }
511
+ function invalidConfig(limits) {
512
+ const collector = new DiagnosticCollector(limits);
513
+ collector.addCode("INPUT_TYPE_INVALID", "input");
514
+ return failure(collector.finish());
515
+ }
516
+ function createInternalDiagnostic(code = "INTERNAL_INVARIANT_BROKEN") {
517
+ return Object.freeze({
518
+ $schema: "urn:noeos:verification-engine:diagnostic:1",
519
+ code,
520
+ severity: "error",
521
+ phase: "chain",
522
+ messageKey: code.toLowerCase().replaceAll("_", "."),
523
+ });
524
+ }
525
+ function createStreamDiagnostic(code) {
526
+ return Object.freeze({
527
+ $schema: "urn:noeos:verification-engine:diagnostic:1",
528
+ code,
529
+ severity: code === "OPERATION_ABORTED" ? "info" : "error",
530
+ phase: "output",
531
+ messageKey: code.toLowerCase().replaceAll("_", "."),
532
+ });
533
+ }
534
+ function isAborted(signal) {
535
+ return signal?.aborted === true;
536
+ }