@pulse-compute/wasm-contracts 0.0.0 → 1.0.0-beta.2

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 (97) hide show
  1. package/README.md +35 -2
  2. package/package.json +124 -6
  3. package/src/assets/contracts.js +296 -0
  4. package/src/config/provider-resolution.js +54 -0
  5. package/src/config/runtime-provider-kv.js +73 -0
  6. package/src/config/symbolic-refs.js +192 -0
  7. package/src/crypto/contracts.js +647 -0
  8. package/src/definitions/config-schema.js +30 -0
  9. package/src/definitions/handler-roles.js +66 -0
  10. package/src/definitions/path-grammar.js +11 -0
  11. package/src/definitions/router-api.js +149 -0
  12. package/src/diagnostics/codes.js +42 -0
  13. package/src/diagnostics/reporter.js +20 -0
  14. package/src/diagnostics.js +139 -0
  15. package/src/dispatch-table.js +23 -0
  16. package/src/entities/catalog.d.ts +7 -0
  17. package/src/entities/catalog.js +87 -0
  18. package/src/entities/contracts.d.ts +95 -0
  19. package/src/entities/contracts.js +122 -0
  20. package/src/entities/json-rpc.d.ts +27 -0
  21. package/src/entities/json-rpc.js +69 -0
  22. package/src/entities/runtime.d.ts +67 -0
  23. package/src/entities/runtime.js +288 -0
  24. package/src/events/contracts.js +456 -0
  25. package/src/execution-plan.js +42 -0
  26. package/src/grip/contracts.js +106 -0
  27. package/src/handler/backend-json-request-body.js +58 -0
  28. package/src/handler/beta-lifecycle-golden.js +97 -0
  29. package/src/handler/canonical-native-plan.js +143 -0
  30. package/src/handler/canonical-native-runtime.js +168 -0
  31. package/src/handler/canonical-runtime.js +13 -0
  32. package/src/handler/context.js +131 -0
  33. package/src/handler/ctx-contract.js +71 -0
  34. package/src/handler/doctor-readiness-aggregator.js +67 -0
  35. package/src/handler/effects.js +446 -0
  36. package/src/handler/io-lifecycle.js +134 -0
  37. package/src/handler/lifecycle-authoring-alignment.js +56 -0
  38. package/src/handler/lifecycle-readiness-aggregate.js +93 -0
  39. package/src/handler/reference-node-lifecycle-golden.js +73 -0
  40. package/src/handler/request-json-body.js +147 -0
  41. package/src/handler/runtime-api.js +471 -0
  42. package/src/handler/schema-decode-result.js +135 -0
  43. package/src/handler/schema-response-codec.js +141 -0
  44. package/src/handler/surface-contract.js +601 -0
  45. package/src/handler/types-contract.js +51 -0
  46. package/src/handler-table.js +28 -0
  47. package/src/host/backend-capabilities.js +24 -0
  48. package/src/host/capabilities.js +273 -0
  49. package/src/host/channel-broadcaster.js +60 -0
  50. package/src/host/json-body.js +80 -0
  51. package/src/host/request-result-headers.js +38 -0
  52. package/src/host/streaming-passthrough.js +90 -0
  53. package/src/host/wasm-host-abi.js +154 -0
  54. package/src/index.js +75 -0
  55. package/src/jwt/contracts.js +427 -0
  56. package/src/library/api-surface.js +99 -0
  57. package/src/library/contracts.js +273 -0
  58. package/src/library/manifest.js +317 -0
  59. package/src/library/second-package-owned-lowering.js +39 -0
  60. package/src/library/sidecars.js +147 -0
  61. package/src/logging.js +89 -0
  62. package/src/package/package-contract.js +975 -0
  63. package/src/package/package-contract.schema.json +303 -0
  64. package/src/package/runtime-pulse-live.js +100 -0
  65. package/src/path-table.js +12 -0
  66. package/src/path.js +275 -0
  67. package/src/project/config-factory.js +48 -0
  68. package/src/project/config-plan.js +409 -0
  69. package/src/project/config-runtime.js +46 -0
  70. package/src/project/javascript-application.js +212 -0
  71. package/src/project/javascript-core-capabilities.js +44 -0
  72. package/src/project/native-optimization.js +9 -0
  73. package/src/project/package-ownership.js +242 -0
  74. package/src/project/package-product-projection.js +171 -0
  75. package/src/project/reachable-graph-identity.js +219 -0
  76. package/src/project/reachable-graph-projections.js +279 -0
  77. package/src/project/reachable-graph-resolver.js +303 -0
  78. package/src/project/reachable-graph-v2.js +430 -0
  79. package/src/project/reachable-graph-v2.schema.json +285 -0
  80. package/src/project/reachable-graph.js +199 -0
  81. package/src/project/reachable-graph.schema.json +222 -0
  82. package/src/project/target-support-evidence.js +559 -0
  83. package/src/provider/canonical-provider.js +239 -0
  84. package/src/provider/final-wasm-policy.js +87 -0
  85. package/src/provider/toolchain.js +771 -0
  86. package/src/route-plan.js +43 -0
  87. package/src/s3/contracts.js +12 -0
  88. package/src/schema-json/compile.js +63 -0
  89. package/src/schema-json/contracts.js +10 -0
  90. package/src/schema-json/generic-parser.js +62 -0
  91. package/src/schema-json/registry.js +359 -0
  92. package/src/schema-json/semantic-trace.js +241 -0
  93. package/src/schema-json/v1.js +65 -0
  94. package/src/schema-json/v2.js +110 -0
  95. package/src/sha256.js +104 -0
  96. package/src/spine.js +381 -0
  97. package/src/stable-id.js +142 -0
@@ -0,0 +1,456 @@
1
+ 'use strict';
2
+
3
+ const { prefixedStableId, sha256Hex, stableStringify } = require('../stable-id.js');
4
+
5
+ const EVENT_CONTRACT_VERSION = 'pulse.events-contract.v1';
6
+ const EVENT_DECLARATION_VERSION = 'pulse.event-declaration.v1';
7
+ const EVENT_FRAME_VERSION = 'pulse.event-frame.v1';
8
+ const EVENT_CATALOG_VERSION = 'pulse.event-catalog.v1';
9
+ const EVENT_ADAPTER_VERSION = 'pulse.event-adapter.v1';
10
+ const EVENT_EXECUTION_RESULT_VERSION = 'pulse.event-execution-result.v1';
11
+ const EVENT_DIAGNOSTIC_VERSION = 'pulse.events-diagnostics.v1';
12
+ const EVENT_NATIVE_ABI_EXTENSION_VERSION = 'pulse.native-event-abi.v1';
13
+ const EVENT_CONTRACT_ID = 'pulse.events';
14
+
15
+ const EVENT_DEFAULT_LIMITS = Object.freeze({
16
+ maxTypeBytes: 128,
17
+ maxSchemaIdBytes: 256,
18
+ maxPayloadBytes: 65_536,
19
+ maxPayloadDepth: 32,
20
+ maxPayloadEntries: 4_096,
21
+ maxEvents: 256,
22
+ maxQueueDepth: 65_536,
23
+ maxErrorBytes: 4_096
24
+ });
25
+ const EVENT_LIMIT_KEYS = Object.freeze(Object.keys(EVENT_DEFAULT_LIMITS));
26
+
27
+ const EVENT_DIAGNOSTIC_CODES = Object.freeze({
28
+ LIMIT_INVALID: 'PULSEWASM_EVENTS_LIMIT_INVALID',
29
+ LIMIT_EXCEEDED: 'PULSEWASM_EVENTS_LIMIT_EXCEEDED',
30
+ TYPE_INVALID: 'PULSEWASM_EVENTS_TYPE_INVALID',
31
+ SCHEMA_ID_INVALID: 'PULSEWASM_EVENTS_SCHEMA_ID_INVALID',
32
+ DECLARATION_INVALID: 'PULSEWASM_EVENTS_DECLARATION_INVALID',
33
+ FRAME_INVALID: 'PULSEWASM_EVENTS_FRAME_INVALID',
34
+ PAYLOAD_REQUIRED: 'PULSEWASM_EVENTS_PAYLOAD_REQUIRED',
35
+ PAYLOAD_FORBIDDEN: 'PULSEWASM_EVENTS_PAYLOAD_FORBIDDEN',
36
+ PAYLOAD_INVALID: 'PULSEWASM_EVENTS_PAYLOAD_INVALID',
37
+ CATALOG_INVALID: 'PULSEWASM_EVENTS_CATALOG_INVALID',
38
+ TYPE_DUPLICATE: 'PULSEWASM_EVENTS_TYPE_DUPLICATE',
39
+ ADAPTER_INVALID: 'PULSEWASM_EVENTS_ADAPTER_INVALID',
40
+ EXECUTION_RESULT_INVALID: 'PULSEWASM_EVENTS_EXECUTION_RESULT_INVALID'
41
+ });
42
+
43
+ const EVENT_EXECUTION_STATUS = Object.freeze({
44
+ COMPLETED: 'completed',
45
+ FAILED: 'failed'
46
+ });
47
+
48
+ const EVENT_ADAPTER_SEMANTICS = Object.freeze({
49
+ acceptance: 'host-accepted',
50
+ deliveryGuarantee: 'none',
51
+ autoLoopback: false,
52
+ sameStackReentry: false,
53
+ queueDiscipline: 'fifo-per-declared-adapter',
54
+ executionIsolation: 'one-event-frame-per-execution'
55
+ });
56
+
57
+ const EVENT_COMPLETION_SEMANTICS = Object.freeze({
58
+ handlerResult: 'void',
59
+ completed: 'handler-and-owned-effects-completed',
60
+ failed: 'selection-validation-handler-or-owned-effect-failed',
61
+ responseValue: false,
62
+ providerMetadata: false
63
+ });
64
+
65
+ const EVENT_NATIVE_ABI_EXTENSION = Object.freeze({
66
+ version: EVENT_NATIVE_ABI_EXTENSION_VERSION,
67
+ abiVersion: 1,
68
+ conditional: true,
69
+ baseEntry: 'pulse_start',
70
+ imports: Object.freeze([]),
71
+ exports: Object.freeze([
72
+ Object.freeze({ name: 'pulse_event_abi_version', parameters: Object.freeze([]), result: 'i32' }),
73
+ Object.freeze({ name: 'pulse_event_start', parameters: Object.freeze(['i32', 'i32']), result: 'i32' })
74
+ ]),
75
+ arguments: Object.freeze({
76
+ runtimeId: 'non-negative artifact-local event catalog runtime ID',
77
+ payloadHandle: 'positive host-owned immutable schema-validated value handle; 0 means an explicit no-payload event'
78
+ }),
79
+ startStatus: Object.freeze({
80
+ complete: 0,
81
+ failed: -1,
82
+ invalidStartErrorCode: 1
83
+ }),
84
+ policy: Object.freeze({
85
+ httpOnlyArtifactIdentityUnchanged: true,
86
+ eventImportsAdded: false,
87
+ mixedArtifactsKeepHttpEntry: true,
88
+ hostValidatesFrameAndSchemaBeforeEntry: true,
89
+ singleActiveInvocationPerInstance: true
90
+ })
91
+ });
92
+
93
+ const EVENT_CALL_DISPOSITION = Object.freeze({
94
+ status: 'deferred',
95
+ publicSurfaceReserved: false,
96
+ compilerOpcodeReserved: false,
97
+ runtimeCapabilityReserved: false,
98
+ adapterOperationReserved: false,
99
+ reevaluateAfter: Object.freeze([
100
+ 'a real browser Worker host exists',
101
+ 'ordinary Entities lifecycle blockers are resolved'
102
+ ])
103
+ });
104
+
105
+ const SCHEMA_ID_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*(?:\.[A-Za-z][A-Za-z0-9_-]*)+$/;
106
+ const HANDLER_STABLE_ID_PATTERN = /^handler_[a-f0-9]{24}$/;
107
+
108
+ function eventContractError(code, message, detail = {}) {
109
+ const error = new TypeError(message);
110
+ error.name = 'EventContractError';
111
+ error.code = code;
112
+ error.detail = Object.freeze({ ...detail });
113
+ return error;
114
+ }
115
+
116
+ function plainObject(value) {
117
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
118
+ const prototype = Object.getPrototypeOf(value);
119
+ return prototype === Object.prototype || prototype === null;
120
+ }
121
+
122
+ function assertDataObject(value, field, code) {
123
+ if (!plainObject(value)) throw eventContractError(code, `${field} must be a plain object.`, { field });
124
+ if (Object.getOwnPropertySymbols(value).length > 0) throw eventContractError(code, `${field} must not contain symbol keys.`, { field });
125
+ for (const key of Object.keys(value)) {
126
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
127
+ if (!descriptor || !Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
128
+ throw eventContractError(code, `${field}.${key} must be an own data property.`, { field, key });
129
+ }
130
+ }
131
+ return value;
132
+ }
133
+
134
+ function assertKnownKeys(value, allowed, field, code) {
135
+ const unknown = Object.keys(value).filter((key) => !allowed.includes(key)).sort();
136
+ if (unknown.length > 0) throw eventContractError(code, `${field} contains unsupported fields: ${unknown.join(', ')}.`, { field, unknown });
137
+ }
138
+
139
+ function assertDataArray(value, field, code) {
140
+ if (!Array.isArray(value) || Object.getOwnPropertySymbols(value).length > 0) {
141
+ throw eventContractError(code, `${field} must be a data-only array.`, { field });
142
+ }
143
+ if (Object.keys(value).some((key) => !/^(?:0|[1-9][0-9]*)$/.test(key))) {
144
+ throw eventContractError(code, `${field} must not contain named properties.`, { field });
145
+ }
146
+ for (let index = 0; index < value.length; index += 1) {
147
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
148
+ if (!descriptor || !Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
149
+ throw eventContractError(code, `${field} must be dense and contain only data properties.`, { field, index });
150
+ }
151
+ }
152
+ return value;
153
+ }
154
+
155
+ function utf8ByteLength(value) {
156
+ return Buffer.byteLength(String(value), 'utf8');
157
+ }
158
+
159
+ function deepFreeze(value) {
160
+ if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
161
+ for (const child of Object.values(value)) deepFreeze(child);
162
+ return Object.freeze(value);
163
+ }
164
+
165
+ function normalizeEventLimits(input = {}) {
166
+ assertDataObject(input, 'limits', EVENT_DIAGNOSTIC_CODES.LIMIT_INVALID);
167
+ assertKnownKeys(input, EVENT_LIMIT_KEYS, 'limits', EVENT_DIAGNOSTIC_CODES.LIMIT_INVALID);
168
+ const output = {};
169
+ for (const key of EVENT_LIMIT_KEYS) {
170
+ const value = input[key] === undefined ? EVENT_DEFAULT_LIMITS[key] : Number(input[key]);
171
+ if (!Number.isSafeInteger(value) || value <= 0) {
172
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.LIMIT_INVALID, `limits.${key} must be a positive safe integer.`, { key, value });
173
+ }
174
+ output[key] = value;
175
+ }
176
+ return Object.freeze(output);
177
+ }
178
+
179
+ function resolvedLimits(input) {
180
+ return input === undefined || input === EVENT_DEFAULT_LIMITS ? EVENT_DEFAULT_LIMITS : normalizeEventLimits(input);
181
+ }
182
+
183
+ function normalizeEventType(value, limitsInput) {
184
+ const limits = resolvedLimits(limitsInput);
185
+ if (typeof value !== 'string' || value.length === 0) {
186
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.TYPE_INVALID, 'Event type must be a non-empty string.', { value });
187
+ }
188
+ const bytes = utf8ByteLength(value);
189
+ if (bytes > limits.maxTypeBytes) {
190
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.TYPE_INVALID, 'Event type exceeds its UTF-8 byte limit.', { bytes, maxBytes: limits.maxTypeBytes });
191
+ }
192
+ return value;
193
+ }
194
+
195
+ function normalizeEventSchemaId(value, limitsInput) {
196
+ const limits = resolvedLimits(limitsInput);
197
+ if (value === null) return null;
198
+ if (typeof value !== 'string' || !SCHEMA_ID_PATTERN.test(value) || utf8ByteLength(value) > limits.maxSchemaIdBytes) {
199
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.SCHEMA_ID_INVALID, 'Event schema ID must be a bounded dotted schema ID or null.', { value });
200
+ }
201
+ return value;
202
+ }
203
+
204
+ function cloneBoundedJson(input, options) {
205
+ const { field, code, maxDepth, maxEntries, maxBytes } = options;
206
+ let entries = 0;
207
+ const ancestors = new Set();
208
+
209
+ function visit(value, path, depth) {
210
+ if (depth > maxDepth) throw eventContractError(code, `${field} exceeds its nesting limit.`, { path, depth, maxDepth });
211
+ if (value === null || typeof value === 'string' || typeof value === 'boolean') return value;
212
+ if (typeof value === 'number') {
213
+ if (!Number.isFinite(value)) throw eventContractError(code, `${path} must be finite.`, { path });
214
+ return value;
215
+ }
216
+ if (typeof value !== 'object') throw eventContractError(code, `${path} must be JSON data.`, { path, kind: typeof value });
217
+ if (ancestors.has(value)) throw eventContractError(code, `${field} must not contain cycles.`, { path });
218
+ ancestors.add(value);
219
+ let output;
220
+ if (Array.isArray(value)) {
221
+ assertDataArray(value, path, code);
222
+ entries += value.length;
223
+ output = value.map((entry, index) => visit(entry, `${path}[${index}]`, depth + 1));
224
+ } else {
225
+ assertDataObject(value, path, code);
226
+ const keys = Object.keys(value).sort();
227
+ entries += keys.length;
228
+ output = Object.fromEntries(keys.map((key) => [key, visit(value[key], `${path}.${key}`, depth + 1)]));
229
+ }
230
+ ancestors.delete(value);
231
+ if (entries > maxEntries) throw eventContractError(code, `${field} exceeds its entry limit.`, { entries, maxEntries });
232
+ return output;
233
+ }
234
+
235
+ const normalized = deepFreeze(visit(input, field, 0));
236
+ const bytes = utf8ByteLength(JSON.stringify(normalized));
237
+ if (bytes > maxBytes) throw eventContractError(code, `${field} exceeds its UTF-8 JSON byte limit.`, { bytes, maxBytes });
238
+ return normalized;
239
+ }
240
+
241
+ function normalizeEventDeclaration(input, limitsInput) {
242
+ const limits = resolvedLimits(limitsInput);
243
+ assertDataObject(input, 'declaration', EVENT_DIAGNOSTIC_CODES.DECLARATION_INVALID);
244
+ assertKnownKeys(input, ['schema'], 'declaration', EVENT_DIAGNOSTIC_CODES.DECLARATION_INVALID);
245
+ if (!Object.prototype.hasOwnProperty.call(input, 'schema')) {
246
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.DECLARATION_INVALID, 'Event declaration requires an explicit schema field.');
247
+ }
248
+ return Object.freeze({
249
+ version: EVENT_DECLARATION_VERSION,
250
+ schemaId: normalizeEventSchemaId(input.schema, limits)
251
+ });
252
+ }
253
+
254
+ function normalizeEventFrame(input, limitsInput) {
255
+ const limits = resolvedLimits(limitsInput);
256
+ assertDataObject(input, 'frame', EVENT_DIAGNOSTIC_CODES.FRAME_INVALID);
257
+ assertKnownKeys(input, ['version', 'type', 'schemaId', 'payload'], 'frame', EVENT_DIAGNOSTIC_CODES.FRAME_INVALID);
258
+ if (input.version !== EVENT_FRAME_VERSION || !Object.prototype.hasOwnProperty.call(input, 'schemaId')) {
259
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.FRAME_INVALID, `Event frame requires ${EVENT_FRAME_VERSION}, type, and schemaId.`);
260
+ }
261
+ const type = normalizeEventType(input.type, limits);
262
+ const schemaId = normalizeEventSchemaId(input.schemaId, limits);
263
+ const hasPayload = Object.prototype.hasOwnProperty.call(input, 'payload');
264
+ if (schemaId === null && hasPayload) {
265
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.PAYLOAD_FORBIDDEN, 'No-payload event frames must omit payload.');
266
+ }
267
+ if (schemaId !== null && !hasPayload) {
268
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.PAYLOAD_REQUIRED, 'Schema-bound event frames require payload.');
269
+ }
270
+ return deepFreeze({
271
+ version: EVENT_FRAME_VERSION,
272
+ type,
273
+ schemaId,
274
+ ...(hasPayload ? {
275
+ payload: cloneBoundedJson(input.payload, {
276
+ field: 'frame.payload',
277
+ code: EVENT_DIAGNOSTIC_CODES.PAYLOAD_INVALID,
278
+ maxDepth: limits.maxPayloadDepth,
279
+ maxEntries: limits.maxPayloadEntries,
280
+ maxBytes: limits.maxPayloadBytes
281
+ })
282
+ } : {})
283
+ });
284
+ }
285
+
286
+ function createEventStableId(input, limitsInput) {
287
+ assertDataObject(input, 'eventIdentity', EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
288
+ assertKnownKeys(input, ['type', 'schemaId', 'handlerStableId'], 'eventIdentity', EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
289
+ const type = normalizeEventType(input.type, limitsInput);
290
+ const schemaId = normalizeEventSchemaId(input.schemaId, limitsInput);
291
+ const handlerStableId = String(input.handlerStableId || '');
292
+ if (!HANDLER_STABLE_ID_PATTERN.test(handlerStableId)) {
293
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, 'Event identity requires a canonical handler stable ID.', { handlerStableId });
294
+ }
295
+ return prefixedStableId('event', {
296
+ artifact: EVENT_CATALOG_VERSION,
297
+ type,
298
+ schemaId,
299
+ handlerStableId
300
+ });
301
+ }
302
+
303
+ function normalizePortableSource(input) {
304
+ assertDataObject(input, 'catalog.event.source', EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
305
+ assertKnownKeys(input, ['file', 'line', 'column'], 'catalog.event.source', EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
306
+ const file = typeof input.file === 'string' ? input.file.replace(/\\/g, '/') : '';
307
+ const line = Number(input.line);
308
+ const column = Number(input.column);
309
+ if (!file || file.startsWith('/') || /^[A-Za-z]:\//.test(file) || file.split('/').includes('..') || !Number.isSafeInteger(line) || line < 1 || !Number.isSafeInteger(column) || column < 0) {
310
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, 'Event source must be a portable relative file with a one-based line and zero-based column.', { file, line, column });
311
+ }
312
+ return Object.freeze({ file, line, column });
313
+ }
314
+
315
+ function normalizeTextSet(input, field) {
316
+ assertDataArray(input, field, EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
317
+ const values = input.map((value) => {
318
+ if (typeof value !== 'string' || value.length === 0 || utf8ByteLength(value) > 256) {
319
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, `${field} entries must be bounded non-empty strings.`, { value });
320
+ }
321
+ return value;
322
+ });
323
+ if (new Set(values).size !== values.length) throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, `${field} must not contain duplicates.`);
324
+ return Object.freeze(values.sort());
325
+ }
326
+
327
+ function normalizeEventEligibility(input) {
328
+ assertDataObject(input, 'catalog.event.eligibility', EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
329
+ assertKnownKeys(input, ['javascript', 'native'], 'catalog.event.eligibility', EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
330
+ if (typeof input.javascript !== 'boolean' || typeof input.native !== 'boolean') {
331
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, 'Event eligibility requires explicit JavaScript and Native booleans.');
332
+ }
333
+ return Object.freeze({ javascript: input.javascript, native: input.native });
334
+ }
335
+
336
+ function normalizeEventCatalog(input, limitsInput) {
337
+ const limits = resolvedLimits(limitsInput);
338
+ assertDataObject(input, 'catalog', EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
339
+ assertKnownKeys(input, ['version', 'contractId', 'events'], 'catalog', EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
340
+ if (input.version !== EVENT_CATALOG_VERSION || input.contractId !== EVENT_CONTRACT_ID || !Array.isArray(input.events)) {
341
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, `Event catalog requires ${EVENT_CATALOG_VERSION}, ${EVENT_CONTRACT_ID}, and an events array.`);
342
+ }
343
+ assertDataArray(input.events, 'catalog.events', EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
344
+ if (input.events.length > limits.maxEvents) throw eventContractError(EVENT_DIAGNOSTIC_CODES.LIMIT_EXCEEDED, 'Event catalog exceeds its registration limit.', { count: input.events.length, maxEvents: limits.maxEvents });
345
+ const types = new Set();
346
+ const stableIds = new Set();
347
+ const runtimeIds = new Set();
348
+ const events = input.events.map((event, index) => {
349
+ assertDataObject(event, `catalog.events[${index}]`, EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
350
+ assertKnownKeys(event, ['type', 'schemaId', 'stableId', 'runtimeId', 'handlerStableId', 'source', 'capabilities', 'packageOperations', 'eligibility', 'hostRequirements'], `catalog.events[${index}]`, EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID);
351
+ const type = normalizeEventType(event.type, limits);
352
+ if (types.has(type)) throw eventContractError(EVENT_DIAGNOSTIC_CODES.TYPE_DUPLICATE, `Event catalog repeats type ${JSON.stringify(type)}.`, { type });
353
+ types.add(type);
354
+ const schemaId = normalizeEventSchemaId(event.schemaId, limits);
355
+ const handlerStableId = String(event.handlerStableId || '');
356
+ if (!HANDLER_STABLE_ID_PATTERN.test(handlerStableId)) throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, 'Catalog event requires a canonical handler stable ID.', { handlerStableId });
357
+ const stableId = createEventStableId({ type, schemaId, handlerStableId }, limits);
358
+ if (event.stableId !== stableId || stableIds.has(stableId)) throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, 'Catalog event stable ID does not match its canonical registration identity.', { expected: stableId, actual: event.stableId });
359
+ stableIds.add(stableId);
360
+ const runtimeId = Number(event.runtimeId);
361
+ if (!Number.isSafeInteger(runtimeId) || runtimeId < 0 || runtimeId >= input.events.length || runtimeIds.has(runtimeId)) {
362
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, 'Catalog event runtime IDs must be unique contiguous non-negative integers.', { runtimeId });
363
+ }
364
+ runtimeIds.add(runtimeId);
365
+ return Object.freeze({
366
+ type,
367
+ schemaId,
368
+ stableId,
369
+ runtimeId,
370
+ handlerStableId,
371
+ source: normalizePortableSource(event.source),
372
+ capabilities: normalizeTextSet(event.capabilities, 'catalog.event.capabilities'),
373
+ packageOperations: normalizeTextSet(event.packageOperations, 'catalog.event.packageOperations'),
374
+ eligibility: normalizeEventEligibility(event.eligibility),
375
+ hostRequirements: normalizeTextSet(event.hostRequirements, 'catalog.event.hostRequirements')
376
+ });
377
+ }).sort((left, right) => left.runtimeId - right.runtimeId);
378
+ for (let index = 0; index < events.length; index += 1) {
379
+ if (events[index].runtimeId !== index) throw eventContractError(EVENT_DIAGNOSTIC_CODES.CATALOG_INVALID, 'Catalog event runtime IDs must form a contiguous source-order sequence.', { expected: index, actual: events[index].runtimeId });
380
+ }
381
+ const normalized = Object.freeze({ version: EVENT_CATALOG_VERSION, contractId: EVENT_CONTRACT_ID, events: Object.freeze(events) });
382
+ return Object.freeze({ ...normalized, catalogHash: sha256Hex(stableStringify(normalized)) });
383
+ }
384
+
385
+ function normalizeEventAdapter(input, limitsInput) {
386
+ const limits = resolvedLimits(limitsInput);
387
+ assertDataObject(input, 'adapter', EVENT_DIAGNOSTIC_CODES.ADAPTER_INVALID);
388
+ assertKnownKeys(input, ['version', 'id', 'maxQueueDepth', 'semantics'], 'adapter', EVENT_DIAGNOSTIC_CODES.ADAPTER_INVALID);
389
+ const id = typeof input.id === 'string' ? input.id : '';
390
+ const maxQueueDepth = Number(input.maxQueueDepth);
391
+ if (input.version !== EVENT_ADAPTER_VERSION || !id || utf8ByteLength(id) > 128 || !Number.isSafeInteger(maxQueueDepth) || maxQueueDepth <= 0 || maxQueueDepth > limits.maxQueueDepth) {
392
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.ADAPTER_INVALID, 'Event adapter requires a bounded ID and finite queue bound.', { id, maxQueueDepth });
393
+ }
394
+ assertDataObject(input.semantics, 'adapter.semantics', EVENT_DIAGNOSTIC_CODES.ADAPTER_INVALID);
395
+ assertKnownKeys(input.semantics, Object.keys(EVENT_ADAPTER_SEMANTICS), 'adapter.semantics', EVENT_DIAGNOSTIC_CODES.ADAPTER_INVALID);
396
+ if (Object.keys(EVENT_ADAPTER_SEMANTICS).some((key) => input.semantics[key] !== EVENT_ADAPTER_SEMANTICS[key])) {
397
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.ADAPTER_INVALID, 'Event adapter semantics must match the canonical host-acceptance contract.');
398
+ }
399
+ return deepFreeze({ version: EVENT_ADAPTER_VERSION, id, maxQueueDepth, semantics: EVENT_ADAPTER_SEMANTICS });
400
+ }
401
+
402
+ function normalizeEventExecutionResult(input, limitsInput) {
403
+ const limits = resolvedLimits(limitsInput);
404
+ assertDataObject(input, 'executionResult', EVENT_DIAGNOSTIC_CODES.EXECUTION_RESULT_INVALID);
405
+ assertKnownKeys(input, ['version', 'status', 'error'], 'executionResult', EVENT_DIAGNOSTIC_CODES.EXECUTION_RESULT_INVALID);
406
+ if (input.version !== EVENT_EXECUTION_RESULT_VERSION || !Object.values(EVENT_EXECUTION_STATUS).includes(input.status)) {
407
+ throw eventContractError(EVENT_DIAGNOSTIC_CODES.EXECUTION_RESULT_INVALID, `Event execution result requires ${EVENT_EXECUTION_RESULT_VERSION} and a supported status.`);
408
+ }
409
+ const hasError = Object.prototype.hasOwnProperty.call(input, 'error');
410
+ if (input.status === EVENT_EXECUTION_STATUS.COMPLETED && hasError) throw eventContractError(EVENT_DIAGNOSTIC_CODES.EXECUTION_RESULT_INVALID, 'Completed event execution must not include an error.');
411
+ if (input.status === EVENT_EXECUTION_STATUS.FAILED && !hasError) throw eventContractError(EVENT_DIAGNOSTIC_CODES.EXECUTION_RESULT_INVALID, 'Failed event execution requires an error.');
412
+ return deepFreeze({
413
+ version: EVENT_EXECUTION_RESULT_VERSION,
414
+ status: input.status,
415
+ ...(hasError ? {
416
+ error: cloneBoundedJson(input.error, {
417
+ field: 'executionResult.error',
418
+ code: EVENT_DIAGNOSTIC_CODES.EXECUTION_RESULT_INVALID,
419
+ maxDepth: limits.maxPayloadDepth,
420
+ maxEntries: limits.maxPayloadEntries,
421
+ maxBytes: limits.maxErrorBytes
422
+ })
423
+ } : {})
424
+ });
425
+ }
426
+
427
+ module.exports = Object.freeze({
428
+ EVENT_CONTRACT_VERSION,
429
+ EVENT_DECLARATION_VERSION,
430
+ EVENT_FRAME_VERSION,
431
+ EVENT_CATALOG_VERSION,
432
+ EVENT_ADAPTER_VERSION,
433
+ EVENT_EXECUTION_RESULT_VERSION,
434
+ EVENT_DIAGNOSTIC_VERSION,
435
+ EVENT_NATIVE_ABI_EXTENSION_VERSION,
436
+ EVENT_CONTRACT_ID,
437
+ EVENT_DEFAULT_LIMITS,
438
+ EVENT_LIMIT_KEYS,
439
+ EVENT_DIAGNOSTIC_CODES,
440
+ EVENT_EXECUTION_STATUS,
441
+ EVENT_ADAPTER_SEMANTICS,
442
+ EVENT_COMPLETION_SEMANTICS,
443
+ EVENT_NATIVE_ABI_EXTENSION,
444
+ EVENT_CALL_DISPOSITION,
445
+ eventContractError,
446
+ utf8ByteLength,
447
+ normalizeEventLimits,
448
+ normalizeEventType,
449
+ normalizeEventSchemaId,
450
+ normalizeEventDeclaration,
451
+ normalizeEventFrame,
452
+ createEventStableId,
453
+ normalizeEventCatalog,
454
+ normalizeEventAdapter,
455
+ normalizeEventExecutionResult
456
+ });
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ const EXECUTION_PLAN_VERSION = 'pulsewasm.execution-plan.v1';
4
+
5
+ const ENTRY_KIND_CODES = Object.freeze({
6
+ unknown: 0,
7
+ use: 1,
8
+ route: 2,
9
+ error: 3,
10
+ channel: 4,
11
+ lifecycle: 5,
12
+ mount: 6
13
+ });
14
+
15
+ const EXECUTION_POLICY = Object.freeze({
16
+ phase: '8E',
17
+ sourceOfTruth: 'router-tree.json + dispatch-table.json + path-table.json',
18
+ model: 'ordered entry scanner with static continuation indices',
19
+ next: Object.freeze({
20
+ normal: 'next() resumes normal routing at entry.nextIndex',
21
+ error: 'next(err) enters error mode at entry.nextIndex with activeError = err',
22
+ representation: 'static nextIndex / childStartIndex / parentContinueIndex integers, not JS closures'
23
+ }),
24
+ errors: Object.freeze({
25
+ mode: 'runtime parity ordered error scan',
26
+ transition: 'next(err) or host/runtime error enters error mode',
27
+ handlerNext: 'error next() clears activeError and resumes normal scan; error next(err2) continues error scan with err2',
28
+ noNext: 'error handler that returns no result and does not call next continues bubbling to later error entries'
29
+ }),
30
+ routeHandlers: Object.freeze({
31
+ terminal: false,
32
+ mayCallNext: true,
33
+ noNext: 'handler that returns no result and does not call next halts the scan'
34
+ }),
35
+ codegen: 'metadata artifact; generated harness may execute this plan, but Phase 8E still does not emit Wasm'
36
+ });
37
+
38
+ module.exports = {
39
+ EXECUTION_PLAN_VERSION,
40
+ EXECUTION_POLICY,
41
+ ENTRY_KIND_CODES
42
+ };
@@ -0,0 +1,106 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ PACKAGE_INTRINSIC_VERSION: GRIP_PACKAGE_INTRINSIC_VERSION
5
+ } = require('../package/package-contract.js');
6
+
7
+ const GRIP_CONTRACT_VERSION = 'pulsewasm.grip-contract.v2';
8
+ const GRIP_CONTRACT_ID = 'pulse.grip';
9
+ const GRIP_LOWERING_PLAN_VERSION = 'pulsewasm.grip-lowering-plan.v1';
10
+ const GRIP_LOWERING_PLAN_ARTIFACT = 'grip-lowering-plan.json';
11
+ const GRIP_PACKAGE_OWNED_LOWERING_PROOF_VERSION = 'pulsewasm.grip-package-owned-lowering-proof.v1';
12
+ const GRIP_PACKAGE_OWNED_LOWERING_PROOF_ARTIFACT = 'grip-package-owned-lowering-proof.json';
13
+ const GRIP_PACKAGE_OWNED_LOWERING_PROOF_PHASE = 54;
14
+ const GRIP_PACKAGE_OWNED_LOWERING_CONTRACT_ID = 'pulse.grip-package-owned-lowering';
15
+
16
+ const GRIP_ALLOWED_HOLD_MODES = Object.freeze(['stream', 'response']);
17
+ const GRIP_FACADE_SYMBOLS = Object.freeze(['broadcast', 'handoff', 'isWebSocket', 'subscribe']);
18
+ const GRIP_COMPATIBILITY_FACADE_SYMBOLS = Object.freeze(['hold', 'channel', 'publish']);
19
+ const GRIP_LOWERABLE_SUBPATH_SUFFIX = '/pulsewasm';
20
+ const GRIP_PACKAGE_INTRINSICS = Object.freeze({
21
+ isWebSocket: Object.freeze({ name: 'grip.is-websocket', compilerName: '__pulse_grip_is_websocket', valueKind: 'boolean', argumentIndexes: Object.freeze([]) }),
22
+ subscribe: Object.freeze({ name: 'grip.subscribe', compilerName: '__pulse_grip_subscribe', valueKind: 'pulse-result', argumentIndexes: Object.freeze([0, 1]) }),
23
+ handoff: Object.freeze({ name: 'grip.handoff', compilerName: '__pulse_grip_handoff', valueKind: 'pulse-result', argumentIndexes: Object.freeze([0]) })
24
+ });
25
+
26
+ const GRIP_DIAGNOSTIC_CODES = Object.freeze({
27
+ NON_LITERAL_HOLD_MODE: 'PULSEWASM_GRIP_NON_LITERAL_HOLD_MODE',
28
+ HOLD_MODE_UNSUPPORTED: 'PULSEWASM_GRIP_HOLD_MODE_UNSUPPORTED',
29
+ NON_LITERAL_CHANNEL: 'PULSEWASM_GRIP_NON_LITERAL_CHANNEL',
30
+ NON_LITERAL_MESSAGE: 'PULSEWASM_GRIP_NON_LITERAL_MESSAGE',
31
+ DYNAMIC_CHANNEL_LIST_UNSUPPORTED: 'PULSEWASM_GRIP_DYNAMIC_CHANNEL_LIST_UNSUPPORTED',
32
+ HANDLE_ESCAPE_UNSUPPORTED: 'PULSEWASM_GRIP_HANDLE_ESCAPE_UNSUPPORTED',
33
+ PROVIDER_RUNTIME_PLAN_ONLY: 'PULSEWASM_GRIP_PROVIDER_RUNTIME_PLAN_ONLY',
34
+ PACKAGE_MANIFEST_NOT_DISCOVERED: 'PULSEWASM_GRIP_PACKAGE_MANIFEST_NOT_DISCOVERED',
35
+ ARGUMENT_SHAPE_UNSUPPORTED: 'PULSEWASM_GRIP_ARGUMENT_SHAPE_UNSUPPORTED',
36
+ STATIC_OPTIONS_REQUIRED: 'PULSEWASM_GRIP_STATIC_OPTIONS_REQUIRED',
37
+ STATIC_MESSAGE_REQUIRED: 'PULSEWASM_GRIP_STATIC_MESSAGE_REQUIRED',
38
+ CHANNEL_INVALID: 'PULSEWASM_GRIP_CHANNEL_INVALID',
39
+ TIMEOUT_INVALID: 'PULSEWASM_GRIP_TIMEOUT_INVALID',
40
+ MODE_UNSUPPORTED: 'PULSEWASM_GRIP_MODE_UNSUPPORTED',
41
+ REQUEST_EXPRESSION_UNSUPPORTED: 'PULSEWASM_GRIP_REQUEST_EXPRESSION_UNSUPPORTED'
42
+ });
43
+
44
+ const GRIP_PACKAGE_OWNED_LOWERING_SCOPE = Object.freeze({
45
+ primaryPackage: '@pulse-compute/assets',
46
+ secondPackage: '@pulse-compute/grip',
47
+ firstContractId: 'pulse.assets',
48
+ secondContractId: GRIP_CONTRACT_ID,
49
+ betaQualityTarget: true,
50
+ productionCompletenessRequired: false
51
+ });
52
+
53
+ const GRIP_PACKAGE_OWNED_LOWERING_POLICY = Object.freeze({
54
+ packageOwnsManifest: true,
55
+ packageOwnsFacade: true,
56
+ packageOwnsCompilerBuilder: true,
57
+ packageOwnsSidecarDeclaration: true,
58
+ libraryKitOwnsGenericDiscovery: true,
59
+ compilerOwnsPackageMapping: false,
60
+ arbitraryThirdPartyLowererExecution: false,
61
+ trustedFirstPartyOnly: true,
62
+ providerRuntimeRequiredForThisProof: false,
63
+ assetsSpecificProtocolGeneralized: true
64
+ });
65
+
66
+ function gripProtocolExtension() {
67
+ return {
68
+ grip: {
69
+ version: GRIP_CONTRACT_VERSION,
70
+ contractId: GRIP_CONTRACT_ID,
71
+ allowedHoldModes: GRIP_ALLOWED_HOLD_MODES.slice(),
72
+ facadeSymbols: GRIP_FACADE_SYMBOLS.slice(),
73
+ compatibilityFacadeSymbols: GRIP_COMPATIBILITY_FACADE_SYMBOLS.slice(),
74
+ packageIntrinsicVersion: GRIP_PACKAGE_INTRINSIC_VERSION,
75
+ packageIntrinsics: { ...GRIP_PACKAGE_INTRINSICS },
76
+ diagnostics: { ...GRIP_DIAGNOSTIC_CODES }
77
+ },
78
+ policy: {
79
+ packageIdentityOwnedByManifest: true,
80
+ lowerableFacadeOwnedByPackage: true,
81
+ compilerBuilderOwnedByPackage: true,
82
+ runtimeProviderPlanOnly: true
83
+ }
84
+ };
85
+ }
86
+
87
+ module.exports = {
88
+ GRIP_CONTRACT_VERSION,
89
+ GRIP_CONTRACT_ID,
90
+ GRIP_LOWERING_PLAN_VERSION,
91
+ GRIP_LOWERING_PLAN_ARTIFACT,
92
+ GRIP_PACKAGE_OWNED_LOWERING_PROOF_VERSION,
93
+ GRIP_PACKAGE_OWNED_LOWERING_PROOF_ARTIFACT,
94
+ GRIP_PACKAGE_OWNED_LOWERING_PROOF_PHASE,
95
+ GRIP_PACKAGE_OWNED_LOWERING_CONTRACT_ID,
96
+ GRIP_ALLOWED_HOLD_MODES,
97
+ GRIP_FACADE_SYMBOLS,
98
+ GRIP_COMPATIBILITY_FACADE_SYMBOLS,
99
+ GRIP_LOWERABLE_SUBPATH_SUFFIX,
100
+ GRIP_PACKAGE_INTRINSIC_VERSION,
101
+ GRIP_PACKAGE_INTRINSICS,
102
+ GRIP_DIAGNOSTIC_CODES,
103
+ GRIP_PACKAGE_OWNED_LOWERING_SCOPE,
104
+ GRIP_PACKAGE_OWNED_LOWERING_POLICY,
105
+ gripProtocolExtension
106
+ };
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ const BACKEND_JSON_REQUEST_BODY_PLAN_VERSION = 'pulsewasm.backend-json-request-body-plan.v1';
4
+ const BACKEND_JSON_REQUEST_BODY_PLAN_PHASE = '43';
5
+ const BACKEND_JSON_REQUEST_BODY_PLAN_ARTIFACT = 'backend-json-request-body-plan.json';
6
+ const NODE_BACKEND_JSON_REQUEST_BODY_PROOF_VERSION = 'pulsewasm.node-backend-json-request-body-proof.v1';
7
+ const NODE_BACKEND_JSON_REQUEST_BODY_PROOF_PHASE = '43';
8
+ const NODE_BACKEND_JSON_REQUEST_BODY_PROOF_ARTIFACT = 'node-backend-json-request-body-proof.json';
9
+ const BACKEND_JSON_REQUEST_BODY_CONTRACT_ID = 'pulse.backend-json-request-body-lifecycle';
10
+
11
+ const BACKEND_JSON_REQUEST_BODY_SCOPE = Object.freeze({
12
+ provider: 'node',
13
+ compilerOrchestrationOnly: true,
14
+ providerOwnsOriginBehavior: true,
15
+ postJsonRequestBodyImplemented: true,
16
+ schemaEncodeRefRequired: true,
17
+ arbitraryObjectLowering: false,
18
+ automaticSchemaGeneration: false,
19
+ binaryRequestBody: false,
20
+ streamRequestBody: false,
21
+ multipartRequestBody: false,
22
+ asyncAwait: false,
23
+ promises: false,
24
+ asyncify: false
25
+ });
26
+
27
+ const BACKEND_JSON_REQUEST_BODY_POLICY = Object.freeze({
28
+ allowedSurface: 'ctx.fetch("backend", { method: "POST", json: ctx.schema.encode("Schema", ref) })',
29
+ allowedMethods: ['POST'],
30
+ allowedBodyModes: ['json'],
31
+ requiredBackendConfig: ['allowedMethods includes POST', 'requestBody includes json'],
32
+ acceptedValueRefs: ['request-json-decode-ref', 'schema-ref', 'generic-json-ref', 'primitive-ref'],
33
+ rejectedValues: ['object-literal', 'spread-object', 'class-instance', 'dynamic-schema-name', 'binary-body', 'stream-body', 'multipart-form-data']
34
+ });
35
+
36
+ const BACKEND_JSON_REQUEST_BODY_DIAGNOSTICS = Object.freeze({
37
+ backendMethodUnsupported: 'PULSEWASM_BACKEND_METHOD_UNSUPPORTED',
38
+ backendRequestBodyModeUnsupported: 'PULSEWASM_BACKEND_REQUEST_BODY_MODE_UNSUPPORTED',
39
+ schemaEncodeRefRequired: 'PULSEWASM_SCHEMA_ENCODE_REF_REQUIRED',
40
+ schemaEncodeDynamicSchemaUnsupported: 'PULSEWASM_SCHEMA_ENCODE_DYNAMIC_SCHEMA_UNSUPPORTED',
41
+ fetchJsonBodySchemaEncodeRequired: 'PULSEWASM_FETCH_JSON_BODY_SCHEMA_ENCODE_REQUIRED',
42
+ binaryBodyReserved: 'PULSEWASM_REQUEST_BODY_BINARY_RESERVED',
43
+ streamBodyReserved: 'PULSEWASM_REQUEST_BODY_STREAM_RESERVED',
44
+ multipartBodyReserved: 'PULSEWASM_REQUEST_BODY_MULTIPART_RESERVED'
45
+ });
46
+
47
+ module.exports = {
48
+ BACKEND_JSON_REQUEST_BODY_PLAN_VERSION,
49
+ BACKEND_JSON_REQUEST_BODY_PLAN_PHASE,
50
+ BACKEND_JSON_REQUEST_BODY_PLAN_ARTIFACT,
51
+ NODE_BACKEND_JSON_REQUEST_BODY_PROOF_VERSION,
52
+ NODE_BACKEND_JSON_REQUEST_BODY_PROOF_PHASE,
53
+ NODE_BACKEND_JSON_REQUEST_BODY_PROOF_ARTIFACT,
54
+ BACKEND_JSON_REQUEST_BODY_CONTRACT_ID,
55
+ BACKEND_JSON_REQUEST_BODY_SCOPE,
56
+ BACKEND_JSON_REQUEST_BODY_POLICY,
57
+ BACKEND_JSON_REQUEST_BODY_DIAGNOSTICS
58
+ };