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

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 (96) hide show
  1. package/README.md +34 -2
  2. package/package.json +123 -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 +637 -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 +146 -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 +52 -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 +594 -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 +235 -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/schema-json/compile.js +63 -0
  88. package/src/schema-json/contracts.js +10 -0
  89. package/src/schema-json/generic-parser.js +62 -0
  90. package/src/schema-json/registry.js +359 -0
  91. package/src/schema-json/semantic-trace.js +241 -0
  92. package/src/schema-json/v1.js +65 -0
  93. package/src/schema-json/v2.js +110 -0
  94. package/src/sha256.js +104 -0
  95. package/src/spine.js +381 -0
  96. package/src/stable-id.js +142 -0
@@ -0,0 +1,594 @@
1
+ 'use strict';
2
+
3
+ const HANDLER_SURFACE_CONTRACT_VERSION = 'pulse.handler-surface.v4';
4
+ const HANDLER_SURFACE_CONTRACT_ID = 'pulse.handler-surface';
5
+
6
+ const HANDLER_SURFACE_CLASSES = Object.freeze([
7
+ 'handler-wrapper',
8
+ 'sync',
9
+ 'effect',
10
+ 'terminal-transfer',
11
+ 'package-owned',
12
+ 'javascript-only'
13
+ ]);
14
+
15
+ const AWAIT_POLICIES = Object.freeze([
16
+ 'not-applicable',
17
+ 'forbidden',
18
+ 'synchronous-statement-only',
19
+ 'optional-redundant-warning',
20
+ 'required-when-consumed',
21
+ 'return-adopted-or-required',
22
+ 'manifest-owned',
23
+ 'native-boundary'
24
+ ]);
25
+
26
+ const HANDLER_AUTHORING_POLICY_VERSION = 'pulse.handler-authoring-policy.v1';
27
+ const HANDLER_AUTHORING_MODES = Object.freeze({
28
+ ASYNC_REQUIRED: 'async-required',
29
+ SYNCHRONOUS_COMPATIBILITY: 'synchronous-compatibility'
30
+ });
31
+
32
+ const HANDLER_SURFACE_DIAGNOSTICS = Object.freeze({
33
+ handlerAsyncRequired: 'PULSE_HANDLER_ASYNC_REQUIRED',
34
+ redundantSyncAwait: 'PULSE_AWAIT_SYNC_REDUNDANT',
35
+ logAwaitForbidden: 'PULSE_LOG_AWAIT_FORBIDDEN',
36
+ effectAwaitRequired: 'PULSE_EFFECT_AWAIT_REQUIRED',
37
+ nextTerminal: 'PULSE_ROUTER_NEXT_TERMINAL',
38
+ nativeAwaitUnsupported: 'PULSE_NATIVE_AWAIT_UNSUPPORTED',
39
+ schemaRequired: 'PULSE_SCHEMA_REQUIRED',
40
+ unsupportedSurface: 'PULSE_HANDLER_SURFACE_UNSUPPORTED'
41
+ });
42
+
43
+ function freezeList(values) {
44
+ return Object.freeze(Array.from(values || []));
45
+ }
46
+
47
+ function surface(definition) {
48
+ return Object.freeze({
49
+ ...definition,
50
+ publicForms: freezeList(definition.publicForms),
51
+ validPositions: freezeList(definition.validPositions),
52
+ targetSupport: Object.freeze({
53
+ javascript: definition.targetSupport?.javascript !== false,
54
+ native: definition.targetSupport?.native !== false
55
+ })
56
+ });
57
+ }
58
+
59
+ const HANDLER_SURFACE_DEFINITIONS = Object.freeze([
60
+ surface({
61
+ id: 'handler.managed-async-wrapper',
62
+ class: 'handler-wrapper',
63
+ canonicalOperation: 'handler.managed',
64
+ publicForms: ['async handler', 'async middleware', 'async error handler'],
65
+ awaitPolicy: 'not-applicable',
66
+ validPositions: ['declaration'],
67
+ targetSupport: { javascript: true, native: true },
68
+ nativeBehavior: 'erase-wrapper',
69
+ status: 'supported'
70
+ }),
71
+ surface({
72
+ id: 'router.next',
73
+ class: 'terminal-transfer',
74
+ canonicalOperation: 'router.transfer.normal-or-error',
75
+ publicForms: ['next()', 'next(error)'],
76
+ awaitPolicy: 'forbidden',
77
+ validPositions: ['return'],
78
+ targetSupport: { javascript: true, native: true },
79
+ nativeBehavior: 'emit-router-transfer',
80
+ status: 'existing'
81
+ }),
82
+ surface({
83
+ id: 'ctx.param',
84
+ class: 'sync',
85
+ canonicalOperation: 'context.param.string',
86
+ publicForms: ['ctx.param(name)'],
87
+ awaitPolicy: 'optional-redundant-warning',
88
+ validPositions: ['expression', 'return', 'condition'],
89
+ targetSupport: { javascript: true, native: true },
90
+ nativeBehavior: 'direct-context-lookup',
91
+ status: 'existing-alias-normalization'
92
+ }),
93
+ surface({
94
+ id: 'ctx.req.method',
95
+ class: 'sync',
96
+ canonicalOperation: 'context.request.method',
97
+ publicForms: ['ctx.req.method'],
98
+ awaitPolicy: 'optional-redundant-warning',
99
+ validPositions: ['expression', 'return', 'condition'],
100
+ targetSupport: { javascript: true, native: true },
101
+ nativeBehavior: 'direct-request-frame-lookup',
102
+ status: 'existing-alias-normalization'
103
+ }),
104
+ surface({
105
+ id: 'ctx.req.url',
106
+ class: 'sync',
107
+ canonicalOperation: 'context.request.url',
108
+ publicForms: ['ctx.req.url'],
109
+ awaitPolicy: 'optional-redundant-warning',
110
+ validPositions: ['expression', 'return', 'condition'],
111
+ targetSupport: { javascript: true, native: true },
112
+ nativeBehavior: 'direct-request-frame-lookup',
113
+ status: 'supported'
114
+ }),
115
+ surface({
116
+ id: 'ctx.req.path',
117
+ class: 'sync',
118
+ canonicalOperation: 'context.request.path',
119
+ publicForms: ['ctx.req.path'],
120
+ awaitPolicy: 'optional-redundant-warning',
121
+ validPositions: ['expression', 'return', 'condition'],
122
+ targetSupport: { javascript: true, native: true },
123
+ nativeBehavior: 'direct-request-frame-lookup',
124
+ status: 'existing-alias-normalization'
125
+ }),
126
+ surface({
127
+ id: 'ctx.req.header',
128
+ class: 'sync',
129
+ canonicalOperation: 'context.request.header.first',
130
+ publicForms: ['ctx.req.header(name)'],
131
+ awaitPolicy: 'optional-redundant-warning',
132
+ validPositions: ['expression', 'return', 'condition'],
133
+ targetSupport: { javascript: true, native: true },
134
+ nativeBehavior: 'direct-request-header-lookup',
135
+ status: 'existing-alias-normalization'
136
+ }),
137
+ surface({
138
+ id: 'ctx.req.headers',
139
+ class: 'sync',
140
+ canonicalOperation: 'context.request.headers.snapshot',
141
+ publicForms: ['ctx.req.headers'],
142
+ awaitPolicy: 'optional-redundant-warning',
143
+ validPositions: ['expression', 'return'],
144
+ targetSupport: { javascript: true, native: true },
145
+ nativeBehavior: 'immutable-request-header-snapshot',
146
+ status: 'supported'
147
+ }),
148
+ surface({
149
+ id: 'ctx.event.type',
150
+ class: 'sync',
151
+ canonicalOperation: 'context.event.type',
152
+ publicForms: ['ctx.event.type'],
153
+ awaitPolicy: 'optional-redundant-warning',
154
+ validPositions: ['expression', 'condition'],
155
+ targetSupport: { javascript: true, native: true },
156
+ nativeBehavior: 'compile-time exact event selection literal',
157
+ status: 'supported'
158
+ }),
159
+ surface({
160
+ id: 'ctx.event.payload',
161
+ class: 'sync',
162
+ canonicalOperation: 'context.event.payload',
163
+ publicForms: ['ctx.event.payload'],
164
+ awaitPolicy: 'optional-redundant-warning',
165
+ validPositions: ['expression', 'condition'],
166
+ targetSupport: { javascript: true, native: true },
167
+ nativeBehavior: 'host-owned immutable schema-validated value handle',
168
+ schemaPolicy: 'registration-owned',
169
+ status: 'supported'
170
+ }),
171
+ surface({
172
+ id: 'ctx.state.get',
173
+ class: 'sync',
174
+ canonicalOperation: 'context.state.get.string',
175
+ publicForms: ['ctx.state.get(key)'],
176
+ awaitPolicy: 'optional-redundant-warning',
177
+ validPositions: ['expression', 'return', 'condition'],
178
+ targetSupport: { javascript: true, native: true },
179
+ nativeBehavior: 'request-local-string-table-get',
180
+ status: 'restore-public-surface'
181
+ }),
182
+ surface({
183
+ id: 'ctx.state.set',
184
+ class: 'sync',
185
+ canonicalOperation: 'context.state.set.string',
186
+ publicForms: ['ctx.state.set(key, value)'],
187
+ awaitPolicy: 'optional-redundant-warning',
188
+ validPositions: ['statement'],
189
+ targetSupport: { javascript: true, native: true },
190
+ nativeBehavior: 'request-local-string-table-set',
191
+ status: 'restore-public-surface'
192
+ }),
193
+ ...['error', 'warn', 'info', 'debug'].map((level) => surface({
194
+ id: `ctx.log.${level}`,
195
+ class: 'sync',
196
+ canonicalOperation: `logging.${level}`,
197
+ publicForms: [`ctx.log.${level}(message)`],
198
+ awaitPolicy: 'synchronous-statement-only',
199
+ validPositions: ['statement'],
200
+ targetSupport: { javascript: true, native: true },
201
+ nativeBehavior: 'emit-synchronous-log-or-prune-by-resolved-reporting-level',
202
+ status: 'supported'
203
+ })),
204
+ surface({
205
+ id: 'ctx.json',
206
+ class: 'sync',
207
+ canonicalOperation: 'result.json',
208
+ publicForms: ['ctx.json(value, options?)'],
209
+ awaitPolicy: 'optional-redundant-warning',
210
+ validPositions: ['return'],
211
+ targetSupport: { javascript: true, native: true },
212
+ nativeBehavior: 'construct-canonical-result',
213
+ status: 'existing-alias-normalization'
214
+ }),
215
+ surface({
216
+ id: 'ctx.text',
217
+ class: 'sync',
218
+ canonicalOperation: 'result.text',
219
+ publicForms: ['ctx.text(value, options?)'],
220
+ awaitPolicy: 'optional-redundant-warning',
221
+ validPositions: ['return'],
222
+ targetSupport: { javascript: true, native: true },
223
+ nativeBehavior: 'construct-canonical-result',
224
+ status: 'existing-alias-normalization'
225
+ }),
226
+ surface({
227
+ id: 'ctx.response',
228
+ class: 'sync',
229
+ canonicalOperation: 'result.response',
230
+ publicForms: ['ctx.response(input?)'],
231
+ awaitPolicy: 'optional-redundant-warning',
232
+ validPositions: ['return'],
233
+ targetSupport: { javascript: true, native: true },
234
+ nativeBehavior: 'construct-canonical-result',
235
+ status: 'existing-alias-normalization'
236
+ }),
237
+ surface({
238
+ id: 'ctx.req.text',
239
+ class: 'effect',
240
+ canonicalOperation: 'effect.request-body.text',
241
+ publicForms: ['ctx.req.text()'],
242
+ awaitPolicy: 'required-when-consumed',
243
+ validPositions: ['await-expression', 'return'],
244
+ targetSupport: { javascript: true, native: true },
245
+ nativeBehavior: 'emit-effect-and-continuation',
246
+ status: 'supported'
247
+ }),
248
+ surface({
249
+ id: 'ctx.req.json.schema',
250
+ class: 'effect',
251
+ canonicalOperation: 'effect.request-body.json.schema',
252
+ publicForms: ["ctx.req.json<T>('schema.id')"],
253
+ awaitPolicy: 'required-when-consumed',
254
+ validPositions: ['await-expression', 'return'],
255
+ targetSupport: { javascript: true, native: true },
256
+ nativeBehavior: 'emit-body-effect-and-specialized-decode',
257
+ schemaPolicy: 'literal-schema-required',
258
+ status: 'supported'
259
+ }),
260
+ surface({
261
+ id: 'ctx.req.json.generic',
262
+ class: 'effect',
263
+ canonicalOperation: 'effect.request-body.json.generic',
264
+ publicForms: ['ctx.req.json<T>()'],
265
+ awaitPolicy: 'required-when-consumed',
266
+ validPositions: ['await-expression', 'return'],
267
+ targetSupport: { javascript: true, native: true },
268
+ nativeBehavior: 'emit-body-effect-and-generic-parser',
269
+ schemaPolicy: 'allowed-only-when-pulse-strict-false',
270
+ status: 'supported-when-nonstrict'
271
+ }),
272
+ surface({
273
+ id: 'ctx.parallel',
274
+ class: 'effect',
275
+ canonicalOperation: 'effect.group.parallel',
276
+ publicForms: ['ctx.parallel({ key: pulseEffect, ... })'],
277
+ awaitPolicy: 'required-when-consumed',
278
+ validPositions: ['await-expression'],
279
+ targetSupport: { javascript: true, native: true },
280
+ nativeBehavior: 'emit-explicit-effect-group-and-continuation',
281
+ shapePolicy: 'static-nonempty-object-literal-with-fixed-non-index-string-keys-and-pulse-effect-values',
282
+ status: 'supported'
283
+ }),
284
+ surface({
285
+ id: 'ctx.fetch.projected',
286
+ class: 'effect',
287
+ canonicalOperation: 'effect.backend-fetch.projected',
288
+ publicForms: ['ctx.fetch(url, init?).json<T>(schemaId?)', 'ctx.fetch(url, init?).text()'],
289
+ awaitPolicy: 'required-when-consumed',
290
+ validPositions: ['await-expression', 'return'],
291
+ targetSupport: { javascript: true, native: true },
292
+ nativeBehavior: 'emit-fetch-effect-projection-and-continuation',
293
+ status: 'supported'
294
+ }),
295
+ surface({
296
+ id: 'ctx.fetch.opaque-return',
297
+ class: 'effect',
298
+ canonicalOperation: 'effect.backend-fetch.opaque-return',
299
+ publicForms: ['return ctx.fetch(url, init?)'],
300
+ awaitPolicy: 'return-adopted-or-required',
301
+ validPositions: ['return', 'await-expression'],
302
+ targetSupport: { javascript: true, native: true },
303
+ nativeBehavior: 'emit-terminal-fetch-effect',
304
+ status: 'supported'
305
+ }),
306
+ surface({
307
+ id: 'ctx.config.get',
308
+ class: 'effect',
309
+ canonicalOperation: 'effect.binding.config.get',
310
+ publicForms: ['ctx.config.get(name)'],
311
+ awaitPolicy: 'required-when-consumed',
312
+ validPositions: ['await-expression', 'return'],
313
+ targetSupport: { javascript: true, native: true },
314
+ nativeBehavior: 'emit-config-binding-effect',
315
+ status: 'supported'
316
+ }),
317
+ surface({
318
+ id: 'ctx.secret.get',
319
+ class: 'effect',
320
+ canonicalOperation: 'effect.binding.secret.get',
321
+ publicForms: ['ctx.secret.get(name)'],
322
+ awaitPolicy: 'required-when-consumed',
323
+ validPositions: ['await-expression', 'return'],
324
+ targetSupport: { javascript: true, native: true },
325
+ nativeBehavior: 'emit-secret-binding-effect',
326
+ redaction: 'required',
327
+ status: 'supported'
328
+ }),
329
+ surface({
330
+ id: 'ctx.kv.get',
331
+ class: 'effect',
332
+ canonicalOperation: 'effect.kv.get',
333
+ publicForms: ["ctx.kv<T>('namespace').get(key)"],
334
+ awaitPolicy: 'required-when-consumed',
335
+ validPositions: ['await-expression', 'return'],
336
+ targetSupport: { javascript: true, native: true },
337
+ nativeBehavior: 'emit-kv-get-effect',
338
+ status: 'supported'
339
+ }),
340
+ surface({
341
+ id: 'ctx.kv.put',
342
+ class: 'effect',
343
+ canonicalOperation: 'effect.kv.put',
344
+ publicForms: ["ctx.kv<T>('namespace').put(key, value)"],
345
+ awaitPolicy: 'required-when-consumed',
346
+ validPositions: ['await-expression', 'return'],
347
+ targetSupport: { javascript: true, native: true },
348
+ nativeBehavior: 'emit-kv-put-effect',
349
+ status: 'supported'
350
+ }),
351
+ surface({
352
+ id: 'ctx.emit',
353
+ class: 'effect',
354
+ canonicalOperation: 'effect.event.emit',
355
+ publicForms: ["ctx.emit(type, { schema: schemaId, payload })", "ctx.emit(type, { schema: null })"],
356
+ awaitPolicy: 'required-when-consumed',
357
+ validPositions: ['await-expression', 'parallel-member'],
358
+ targetSupport: { javascript: true, native: true },
359
+ nativeBehavior: 'emit-canonical-event-effect-and-continuation',
360
+ schemaPolicy: 'literal-type-and-schema-required',
361
+ redaction: 'payload-required',
362
+ status: 'supported'
363
+ }),
364
+ surface({
365
+ id: 'package.operation',
366
+ class: 'package-owned',
367
+ canonicalOperation: 'package.operation',
368
+ publicForms: ['manifest-declared-package-operation'],
369
+ awaitPolicy: 'manifest-owned',
370
+ validPositions: ['manifest-declared'],
371
+ targetSupport: { javascript: true, native: true },
372
+ nativeBehavior: 'delegate-canonical-package-operation-to-trusted-lowerer',
373
+ status: 'existing-seam'
374
+ }),
375
+ surface({
376
+ id: 'javascript.await',
377
+ class: 'javascript-only',
378
+ canonicalOperation: 'javascript.await',
379
+ publicForms: ['await arbitraryLibraryCall()'],
380
+ awaitPolicy: 'native-boundary',
381
+ validPositions: ['await-expression'],
382
+ targetSupport: { javascript: true, native: false },
383
+ nativeBehavior: 'record-first-native-eligibility-boundary',
384
+ status: 'supported-diagnostic'
385
+ })
386
+ ]);
387
+
388
+ function buildHandlerSurfaceRegistry(definitions = HANDLER_SURFACE_DEFINITIONS) {
389
+ const byId = new Map();
390
+ const byCanonicalOperation = new Map();
391
+ for (const definition of definitions) {
392
+ if (!definition || typeof definition !== 'object') throw new TypeError('Handler surface definition must be an object.');
393
+ if (!definition.id || typeof definition.id !== 'string') throw new TypeError('Handler surface definition requires an id.');
394
+ if (!HANDLER_SURFACE_CLASSES.includes(definition.class)) throw new TypeError(`Handler surface ${definition.id} has unsupported class ${definition.class}.`);
395
+ if (!AWAIT_POLICIES.includes(definition.awaitPolicy)) throw new TypeError(`Handler surface ${definition.id} has unsupported await policy ${definition.awaitPolicy}.`);
396
+ if (byId.has(definition.id)) throw new TypeError(`Duplicate handler surface id: ${definition.id}`);
397
+ if (byCanonicalOperation.has(definition.canonicalOperation)) {
398
+ throw new TypeError(`Duplicate canonical handler operation: ${definition.canonicalOperation}`);
399
+ }
400
+ byId.set(definition.id, definition);
401
+ byCanonicalOperation.set(definition.canonicalOperation, definition);
402
+ }
403
+ return Object.freeze({
404
+ version: HANDLER_SURFACE_CONTRACT_VERSION,
405
+ contractId: HANDLER_SURFACE_CONTRACT_ID,
406
+ definitions: Object.freeze(Array.from(definitions)),
407
+ get(id) {
408
+ return byId.get(id);
409
+ },
410
+ getByCanonicalOperation(operation) {
411
+ return byCanonicalOperation.get(operation);
412
+ },
413
+ has(id) {
414
+ return byId.has(id);
415
+ }
416
+ });
417
+ }
418
+
419
+ const DEFAULT_HANDLER_SURFACE_REGISTRY = buildHandlerSurfaceRegistry();
420
+
421
+ function classifyHandlerSurface(surfaceId, options = {}) {
422
+ const definition = DEFAULT_HANDLER_SURFACE_REGISTRY.get(surfaceId);
423
+ if (!definition) {
424
+ return Object.freeze({
425
+ ok: false,
426
+ surfaceId,
427
+ classification: 'unsupported',
428
+ severity: 'error',
429
+ code: HANDLER_SURFACE_DIAGNOSTICS.unsupportedSurface,
430
+ message: `Unsupported Pulse handler surface: ${surfaceId}`
431
+ });
432
+ }
433
+
434
+ if (surfaceId === 'ctx.req.json.generic' && options.strict !== false) {
435
+ return Object.freeze({
436
+ ok: false,
437
+ surfaceId,
438
+ definition,
439
+ classification: definition.class,
440
+ severity: 'error',
441
+ code: HANDLER_SURFACE_DIAGNOSTICS.schemaRequired,
442
+ message: 'Schema-less request JSON requires pulse.strict to be false.'
443
+ });
444
+ }
445
+
446
+ return Object.freeze({
447
+ ok: true,
448
+ surfaceId,
449
+ definition,
450
+ classification: definition.class,
451
+ canonicalOperation: definition.canonicalOperation,
452
+ nativeEligible: definition.targetSupport.native
453
+ });
454
+ }
455
+
456
+ function classifyAwaitUse(surfaceId, options = {}) {
457
+ const classified = classifyHandlerSurface(surfaceId, options);
458
+ if (!classified.ok) return classified;
459
+ const definition = classified.definition;
460
+ const awaited = options.awaited === true;
461
+ const consumed = options.consumed !== false;
462
+ const position = options.position || (awaited ? 'await-expression' : 'expression');
463
+
464
+ if (definition.awaitPolicy === 'not-applicable') {
465
+ return Object.freeze({ ...classified, action: 'preserve-handler-shape', severity: 'none', code: null });
466
+ }
467
+ if (definition.awaitPolicy === 'forbidden') {
468
+ if (awaited || position !== 'return') {
469
+ return Object.freeze({
470
+ ...classified,
471
+ ok: false,
472
+ action: 'reject',
473
+ severity: 'error',
474
+ code: HANDLER_SURFACE_DIAGNOSTICS.nextTerminal,
475
+ message: 'next() is a terminal Router control transfer and must be returned directly.'
476
+ });
477
+ }
478
+ return Object.freeze({ ...classified, action: 'emit-terminal-transfer', severity: 'none', code: null });
479
+ }
480
+ if (definition.awaitPolicy === 'synchronous-statement-only') {
481
+ if (awaited || position !== 'statement') {
482
+ return Object.freeze({
483
+ ...classified,
484
+ ok: false,
485
+ action: 'reject',
486
+ severity: 'error',
487
+ code: HANDLER_SURFACE_DIAGNOSTICS.logAwaitForbidden,
488
+ message: `${surfaceId} is synchronous, returns void, and must be used as a standalone statement.`
489
+ });
490
+ }
491
+ return Object.freeze({ ...classified, action: 'lower-sync-statement', severity: 'none', code: null });
492
+ }
493
+ if (definition.awaitPolicy === 'optional-redundant-warning') {
494
+ if (awaited) {
495
+ return Object.freeze({
496
+ ...classified,
497
+ action: 'erase-await',
498
+ severity: 'warning',
499
+ code: HANDLER_SURFACE_DIAGNOSTICS.redundantSyncAwait,
500
+ message: `await is redundant for synchronous Pulse surface ${surfaceId}.`
501
+ });
502
+ }
503
+ return Object.freeze({ ...classified, action: 'lower-sync', severity: 'none', code: null });
504
+ }
505
+ if (definition.awaitPolicy === 'required-when-consumed') {
506
+ if (!awaited && consumed && position !== 'return') {
507
+ return Object.freeze({
508
+ ...classified,
509
+ ok: false,
510
+ action: 'reject',
511
+ severity: 'error',
512
+ code: HANDLER_SURFACE_DIAGNOSTICS.effectAwaitRequired,
513
+ message: `Pulse effect ${surfaceId} must be awaited before its value is consumed.`
514
+ });
515
+ }
516
+ return Object.freeze({
517
+ ...classified,
518
+ action: position === 'return' && !awaited ? 'lower-returned-effect' : 'lower-effect',
519
+ severity: 'none',
520
+ code: null
521
+ });
522
+ }
523
+ if (definition.awaitPolicy === 'return-adopted-or-required') {
524
+ if (!awaited && position !== 'return') {
525
+ return Object.freeze({
526
+ ...classified,
527
+ ok: false,
528
+ action: 'reject',
529
+ severity: 'error',
530
+ code: HANDLER_SURFACE_DIAGNOSTICS.effectAwaitRequired,
531
+ message: `Pulse effect ${surfaceId} must be awaited unless returned as the terminal handler result.`
532
+ });
533
+ }
534
+ return Object.freeze({
535
+ ...classified,
536
+ action: awaited ? 'lower-effect' : 'lower-terminal-effect',
537
+ severity: 'none',
538
+ code: null
539
+ });
540
+ }
541
+ if (definition.awaitPolicy === 'manifest-owned') {
542
+ return Object.freeze({ ...classified, action: 'delegate-to-package-contract', severity: 'none', code: null });
543
+ }
544
+ if (definition.awaitPolicy === 'native-boundary') {
545
+ return Object.freeze({
546
+ ...classified,
547
+ action: 'record-native-boundary',
548
+ severity: 'error-for-native',
549
+ code: HANDLER_SURFACE_DIAGNOSTICS.nativeAwaitUnsupported,
550
+ message: 'Native Pulse supports await only on recognized Pulse effects.'
551
+ });
552
+ }
553
+ throw new TypeError(`Unhandled await policy ${definition.awaitPolicy}.`);
554
+ }
555
+
556
+ function handlerSurfaceContract(definitions) {
557
+ return Object.freeze({
558
+ version: HANDLER_SURFACE_CONTRACT_VERSION,
559
+ contractId: HANDLER_SURFACE_CONTRACT_ID,
560
+ classes: HANDLER_SURFACE_CLASSES,
561
+ awaitPolicies: AWAIT_POLICIES,
562
+ diagnostics: HANDLER_SURFACE_DIAGNOSTICS,
563
+ definitions,
564
+ policies: Object.freeze({
565
+ managedHandlersAsyncShaped: true,
566
+ nativePromiseRuntime: false,
567
+ nativeAsyncify: false,
568
+ redundantSyncAwaitIsFatal: false,
569
+ arbitraryAwaitChangesTargetAutomatically: false,
570
+ authoredThrowSupported: false,
571
+ nextIsTerminal: true
572
+ })
573
+ });
574
+ }
575
+
576
+ function defaultHandlerSurfaceContract() {
577
+ return handlerSurfaceContract(HANDLER_SURFACE_DEFINITIONS);
578
+ }
579
+
580
+ module.exports = {
581
+ HANDLER_SURFACE_CONTRACT_VERSION,
582
+ HANDLER_AUTHORING_POLICY_VERSION,
583
+ HANDLER_AUTHORING_MODES,
584
+ HANDLER_SURFACE_CONTRACT_ID,
585
+ HANDLER_SURFACE_CLASSES,
586
+ AWAIT_POLICIES,
587
+ HANDLER_SURFACE_DIAGNOSTICS,
588
+ HANDLER_SURFACE_DEFINITIONS,
589
+ DEFAULT_HANDLER_SURFACE_REGISTRY,
590
+ buildHandlerSurfaceRegistry,
591
+ classifyHandlerSurface,
592
+ classifyAwaitUse,
593
+ defaultHandlerSurfaceContract
594
+ };
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ const { HANDLER_SURFACE_DEFINITIONS, HANDLER_SURFACE_CONTRACT_VERSION } = require('./surface-contract.js');
4
+
5
+ const HANDLER_TYPES_CONTRACT_VERSION = 'pulse.handler-types.v4';
6
+ const RUNTIME_AUTHORING_VERSION = 'pulse.runtime-authoring.v4';
7
+
8
+ function defaultHandlerTypesContract() {
9
+ return Object.freeze({
10
+ version: HANDLER_TYPES_CONTRACT_VERSION,
11
+ runtimeVersion: RUNTIME_AUTHORING_VERSION,
12
+ handlerSurfaceVersion: HANDLER_SURFACE_CONTRACT_VERSION,
13
+ surfaceCount: HANDLER_SURFACE_DEFINITIONS.length,
14
+ handlersAsyncShaped: true,
15
+ pulseEffectsPromiseCompatible: true,
16
+ routerNextTerminal: true,
17
+ ctxState: Object.freeze({
18
+ shape: 'execution-local-string-map',
19
+ get: 'string | undefined',
20
+ set: 'void'
21
+ }),
22
+ executionContexts: Object.freeze({
23
+ shared: Object.freeze(['state', 'log', 'fetch', 'parallel', 'config', 'secret', 'kv', 'emit']),
24
+ http: Object.freeze(['req', 'json', 'text', 'response']),
25
+ route: Object.freeze(['param']),
26
+ event: Object.freeze(['event.type', 'event.payload']),
27
+ emitPublished: true
28
+ }),
29
+ compiler: Object.freeze({
30
+ acceptsAsyncHandlers: true,
31
+ acceptsAwait: true,
32
+ acceptsEventHandlers: true,
33
+ eventEmitRecognition: true,
34
+ eventEmitNativeLowering: false,
35
+ awaitAuthority: 'ctx-surface-classification',
36
+ enablementWave: 'sprint1-wave2'
37
+ }),
38
+ native: Object.freeze({
39
+ runtimeChanged: true,
40
+ promiseRuntimeAdded: false,
41
+ asyncifyAdded: false,
42
+ eventEntryImplemented: false
43
+ })
44
+ });
45
+ }
46
+
47
+ module.exports = Object.freeze({
48
+ HANDLER_TYPES_CONTRACT_VERSION,
49
+ RUNTIME_AUTHORING_VERSION,
50
+ defaultHandlerTypesContract
51
+ });
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ const HANDLER_TABLE_VERSION = 'pulsewasm.handler-table.v1';
4
+ const HANDLER_STABLE_INPUT_VERSION = 'pulsewasm.handler-stable-input.v1';
5
+
6
+ const HANDLER_STABLE_ID_POLICY = Object.freeze({
7
+ algorithm: 'sha256',
8
+ prefix: 'handler',
9
+ input: 'file + kind + local/export name for declarations, loc for inline handlers, and sourceTextHash',
10
+ version: HANDLER_STABLE_INPUT_VERSION
11
+ });
12
+
13
+ const HANDLER_ID_POLICY = Object.freeze({
14
+ stable: HANDLER_STABLE_ID_POLICY
15
+ });
16
+
17
+ const HANDLER_TABLE_POLICY = Object.freeze({
18
+ version: HANDLER_TABLE_VERSION,
19
+ idPolicy: HANDLER_ID_POLICY
20
+ });
21
+
22
+ module.exports = {
23
+ HANDLER_TABLE_VERSION,
24
+ HANDLER_STABLE_INPUT_VERSION,
25
+ HANDLER_STABLE_ID_POLICY,
26
+ HANDLER_ID_POLICY,
27
+ HANDLER_TABLE_POLICY
28
+ };
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ const BACKEND_CAPABILITIES_VERSION = 'pulsewasm.backend-capabilities.v1';
4
+ const BACKEND_CAPABILITIES_PHASE = '10G';
5
+ const DEFAULT_BACKEND_TIMEOUT_MS = 1500;
6
+ const METHOD_NAMES = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']);
7
+
8
+ function normalizeBackendMethods(value) {
9
+ if (!Array.isArray(value)) return [];
10
+ return value.map((method) => String(method || '').toUpperCase()).filter(Boolean);
11
+ }
12
+
13
+ function isSupportedBackendMethod(method) {
14
+ return METHOD_NAMES.has(String(method || '').toUpperCase());
15
+ }
16
+
17
+ module.exports = {
18
+ BACKEND_CAPABILITIES_VERSION,
19
+ BACKEND_CAPABILITIES_PHASE,
20
+ DEFAULT_BACKEND_TIMEOUT_MS,
21
+ METHOD_NAMES,
22
+ normalizeBackendMethods,
23
+ isSupportedBackendMethod
24
+ };