@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,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
+ };
@@ -0,0 +1,273 @@
1
+ 'use strict';
2
+
3
+ const HOST_CAPABILITIES_VERSION = 'pulsewasm.host-capabilities.v1';
4
+ const WASI_PROVIDER_MAP_VERSION = 'pulsewasm.wasi-provider-map.v1';
5
+ const CAPABILITY_PROVIDER_REPORT_VERSION = 'pulsewasm.capability-provider-report.v1';
6
+ const HOST_CAPABILITY_CONTRACT_VERSION = 'pulsewasm.host-capability-contract.v1';
7
+
8
+ const CAPABILITY_DEFINITIONS = [
9
+ {
10
+ capability: 'headers',
11
+ category: 'request-result',
12
+ status: 'implemented',
13
+ provider: { kind: 'host-runtime', name: 'pulse-host-headers' },
14
+ effectRuntimeRequired: false,
15
+ publicHandlerSurface: true,
16
+ notes: 'Ordered multi-value request/response headers are already exposed through the host ABI.'
17
+ },
18
+ {
19
+ capability: 'result',
20
+ category: 'request-result',
21
+ status: 'implemented',
22
+ provider: { kind: 'host-runtime', name: 'pulse-result-builders' },
23
+ effectRuntimeRequired: false,
24
+ publicHandlerSurface: true,
25
+ notes: 'Text, JSON text, and empty result builders are available; binary remains reserved.'
26
+ },
27
+ {
28
+ capability: 'params',
29
+ category: 'routing',
30
+ status: 'implemented',
31
+ provider: { kind: 'routing-core', name: 'pulse-params-view' },
32
+ effectRuntimeRequired: false,
33
+ publicHandlerSurface: true,
34
+ notes: 'Params are backed by compiled path metadata and request-path slices.'
35
+ },
36
+ {
37
+ capability: 'state',
38
+ category: 'runtime',
39
+ status: 'implemented-proof',
40
+ provider: { kind: 'host-runtime', name: 'pulse-state-adapter' },
41
+ effectRuntimeRequired: false,
42
+ publicHandlerSurface: true,
43
+ notes: 'Node/local proof uses a Map-backed state adapter; production storage remains replaceable.'
44
+ },
45
+ {
46
+ capability: 'error',
47
+ category: 'runtime',
48
+ status: 'implemented',
49
+ provider: { kind: 'host-runtime', name: 'pulse-error-refs' },
50
+ effectRuntimeRequired: false,
51
+ publicHandlerSurface: true,
52
+ notes: 'Structured error refs with code, message, statusCode, and optional cause.'
53
+ },
54
+ {
55
+ capability: 'lifecycle',
56
+ category: 'runtime',
57
+ status: 'implemented',
58
+ provider: { kind: 'execution-plan', name: 'pulse-lifecycle-dispatch' },
59
+ effectRuntimeRequired: false,
60
+ publicHandlerSurface: true,
61
+ notes: 'Connect/disconnect lifecycle hooks are explicit host runtime entrypoints.'
62
+ },
63
+ {
64
+ capability: 'channel',
65
+ category: 'routing-control',
66
+ status: 'implemented',
67
+ provider: { kind: 'routing-core', name: 'pulse-channel-resolution' },
68
+ effectRuntimeRequired: false,
69
+ publicHandlerSurface: true,
70
+ notes: 'Static and handler-produced channels normalize to an ordered channel list surface.'
71
+ },
72
+ {
73
+ capability: 'broadcaster',
74
+ category: 'routing-control',
75
+ status: 'implemented-proof',
76
+ provider: { kind: 'host-adapter', name: 'pulse-broadcaster-adaptor' },
77
+ effectRuntimeRequired: false,
78
+ publicHandlerSurface: false,
79
+ notes: 'Broadcaster is an injected host adapter. Missing broadcaster fails explicitly when channels resolve.'
80
+ },
81
+ {
82
+ capability: 'body',
83
+ category: 'payload',
84
+ status: 'contract-implemented-lazy-text',
85
+ provider: { kind: 'host-runtime', name: 'pulse-body-adaptor' },
86
+ effectRuntimeRequired: false,
87
+ publicHandlerSurface: true,
88
+ notes: 'Body access is explicit and lazy. Streaming/binary body is reserved.'
89
+ },
90
+ {
91
+ capability: 'json',
92
+ category: 'payload',
93
+ status: 'contract-implemented-generic-default',
94
+ provider: { kind: 'payload-runtime', name: 'pulse-json-adaptor' },
95
+ effectRuntimeRequired: false,
96
+ publicHandlerSurface: true,
97
+ notes: 'Generic JSON is the ergonomic default; schema JSON sidecars are a future optimization lane.'
98
+ },
99
+ {
100
+ capability: 'clock',
101
+ category: 'time',
102
+ status: 'provider-mapped-not-wired',
103
+ provider: { kind: 'wasi-provider', name: 'wasi:clocks', role: 'preferred monotonic deadline/sleep provider' },
104
+ providerFallback: { kind: 'host-adapter', name: 'pulse-host-clock', role: 'Node/local proof fallback until WASI/component wiring exists' },
105
+ effectRuntimeRequired: false,
106
+ publicHandlerSurface: false,
107
+ notes: 'Pulse exposes clock/deadline capability; WASI is a provider, not app ergonomics.'
108
+ },
109
+ {
110
+ capability: 'assets',
111
+ category: 'resource',
112
+ status: 'reserved-host-capability-payload-streaming-required',
113
+ provider: { kind: 'host-adapter', name: 'pulse-assets-provider' },
114
+ providerCandidates: [
115
+ { kind: 'host-adapter', name: 'static-file-provider' },
116
+ { kind: 'host-adapter', name: 'object-store-provider' }
117
+ ],
118
+ effectRuntimeRequired: false,
119
+ publicHandlerSurface: true,
120
+ notes: 'Assets are a reserved host capability/adaptor surface. They are not a v1 core effect kind; streaming/binary payload mechanics remain a future payload ABI.'
121
+ },
122
+ {
123
+ capability: 'backend-fetch',
124
+ category: 'network-effect',
125
+ status: 'reserved-effect-runtime-required',
126
+ provider: { kind: 'host-effect', name: 'pulse-backend-fetch-effect' },
127
+ providerCandidates: [
128
+ { kind: 'host-adapter', name: 'declared-backend-http-client' },
129
+ { kind: 'wasi-provider', name: 'wasi:http', role: 'candidate provider once component/HTTP wiring is explicit' }
130
+ ],
131
+ effectRuntimeRequired: true,
132
+ publicHandlerSurface: true,
133
+ notes: 'ctx.fetch is declared and visible, but Wasm execution awaits the effect runtime.'
134
+ },
135
+ {
136
+ capability: 'timer',
137
+ category: 'time-effect',
138
+ status: 'reserved-effect-runtime-required',
139
+ provider: { kind: 'wasi-provider', name: 'wasi:clocks', role: 'preferred monotonic sleep/deadline provider' },
140
+ providerFallback: { kind: 'host-adapter', name: 'pulse-host-scheduler' },
141
+ effectRuntimeRequired: true,
142
+ publicHandlerSurface: true,
143
+ notes: 'Sleep/timeouts are explicit effects, not language async.'
144
+ }
145
+ ];
146
+
147
+ const PROVIDER_DEFINITIONS = [
148
+ {
149
+ id: 'pulse-host-headers',
150
+ kind: 'host-runtime',
151
+ capabilities: ['headers'],
152
+ status: 'implemented',
153
+ publicAppApi: false
154
+ },
155
+ {
156
+ id: 'pulse-result-builders',
157
+ kind: 'host-runtime',
158
+ capabilities: ['result'],
159
+ status: 'implemented',
160
+ publicAppApi: false
161
+ },
162
+ {
163
+ id: 'pulse-params-view',
164
+ kind: 'routing-core',
165
+ capabilities: ['params'],
166
+ status: 'implemented',
167
+ publicAppApi: false
168
+ },
169
+ {
170
+ id: 'pulse-state-adapter',
171
+ kind: 'host-runtime',
172
+ capabilities: ['state'],
173
+ status: 'implemented-proof',
174
+ publicAppApi: false
175
+ },
176
+ {
177
+ id: 'pulse-error-refs',
178
+ kind: 'host-runtime',
179
+ capabilities: ['error'],
180
+ status: 'implemented',
181
+ publicAppApi: false
182
+ },
183
+ {
184
+ id: 'pulse-lifecycle-dispatch',
185
+ kind: 'execution-plan',
186
+ capabilities: ['lifecycle'],
187
+ status: 'implemented',
188
+ publicAppApi: false
189
+ },
190
+ {
191
+ id: 'pulse-channel-resolution',
192
+ kind: 'routing-core',
193
+ capabilities: ['channel'],
194
+ status: 'implemented',
195
+ publicAppApi: false
196
+ },
197
+ {
198
+ id: 'pulse-broadcaster-adaptor',
199
+ kind: 'host-adapter',
200
+ capabilities: ['broadcaster'],
201
+ status: 'implemented-proof',
202
+ publicAppApi: false
203
+ },
204
+ {
205
+ id: 'pulse-body-adaptor',
206
+ kind: 'host-runtime',
207
+ capabilities: ['body'],
208
+ status: 'contract-implemented-lazy-text',
209
+ publicAppApi: false
210
+ },
211
+ {
212
+ id: 'pulse-json-adaptor',
213
+ kind: 'payload-runtime',
214
+ capabilities: ['json'],
215
+ status: 'contract-implemented-generic-default',
216
+ publicAppApi: false
217
+ },
218
+ {
219
+ id: 'wasi:clocks',
220
+ kind: 'wasi-provider',
221
+ capabilities: ['clock', 'timer'],
222
+ status: 'mapped-not-wired',
223
+ publicAppApi: false,
224
+ role: 'monotonic deadlines/sleep provider; wall-clock only for timestamps if explicitly needed'
225
+ },
226
+ {
227
+ id: 'pulse-assets-provider',
228
+ kind: 'host-adapter',
229
+ capabilities: ['assets'],
230
+ status: 'reserved-host-capability-payload-streaming-required',
231
+ publicAppApi: false
232
+ },
233
+ {
234
+ id: 'pulse-backend-fetch-effect',
235
+ kind: 'host-effect',
236
+ capabilities: ['backend-fetch'],
237
+ status: 'reserved-effect-runtime-required',
238
+ publicAppApi: false
239
+ },
240
+ {
241
+ id: 'wasi:http',
242
+ kind: 'wasi-provider-candidate',
243
+ capabilities: ['backend-fetch', 'body'],
244
+ status: 'candidate-only-not-default',
245
+ publicAppApi: false,
246
+ role: 'future provider candidate; not a handler-facing API and not wired in Phase 11E'
247
+ }
248
+ ];
249
+
250
+ function knownHostCapabilities() {
251
+ return CAPABILITY_DEFINITIONS.map((capability) => capability.capability).sort();
252
+ }
253
+
254
+ function isKnownHostCapability(name) {
255
+ return knownHostCapabilities().includes(name);
256
+ }
257
+
258
+ function providerForCapability(name) {
259
+ const capability = CAPABILITY_DEFINITIONS.find((entry) => entry.capability === name);
260
+ return capability && capability.provider ? capability.provider : null;
261
+ }
262
+
263
+ module.exports = {
264
+ HOST_CAPABILITIES_VERSION,
265
+ WASI_PROVIDER_MAP_VERSION,
266
+ CAPABILITY_PROVIDER_REPORT_VERSION,
267
+ HOST_CAPABILITY_CONTRACT_VERSION,
268
+ CAPABILITY_DEFINITIONS,
269
+ PROVIDER_DEFINITIONS,
270
+ knownHostCapabilities,
271
+ isKnownHostCapability,
272
+ providerForCapability
273
+ };
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+
3
+ const CHANNEL_BROADCASTER_VERSION = 'pulsewasm.channel-broadcaster.v1';
4
+ const CHANNEL_BROADCASTER_PHASE = '10E';
5
+
6
+ const CHANNEL_ABI_EXPORTS = Object.freeze([
7
+ 'pulse_channel_count(channelsRef) -> i32',
8
+ 'pulse_channel_ref_at(channelsRef, index) -> StringRef',
9
+ 'pulse_string_ptr(stringRef) -> i32',
10
+ 'pulse_string_len(stringRef) -> i32'
11
+ ]);
12
+
13
+ const CHANNEL_MISSING_HANDLER_CODE = 'PULSEWASM_CHANNEL_HANDLER_MISSING';
14
+ const CHANNEL_INVALID_RESULT_CODE = 'PULSEWASM_CHANNEL_RESULT_INVALID';
15
+ const BROADCASTER_MISSING_CODE = 'PULSEWASM_BROADCASTER_MISSING';
16
+
17
+ function channelAbiContract() {
18
+ return {
19
+ handlerSignature: 'ChannelHandler = (ctxRef: i32) -> ChannelsRef(i32)',
20
+ channelsRef: 'opaque i32 reference to an ordered channel list; 0 means no channels',
21
+ ordered: true,
22
+ repeatedAllowed: true,
23
+ emptyListBehavior: 'equivalent to 0 / no broadcaster call',
24
+ exports: CHANNEL_ABI_EXPORTS.slice(),
25
+ staticChannelLowering: 'static string channels lower to a ChannelsRef with one StringRef entry',
26
+ handlerChannelLowering: 'handler channel slots invoke ChannelHandler and normalize its ChannelsRef return',
27
+ validation: {
28
+ missingChannelHandler: CHANNEL_MISSING_HANDLER_CODE,
29
+ invalidChannelResult: CHANNEL_INVALID_RESULT_CODE
30
+ }
31
+ };
32
+ }
33
+
34
+ function broadcasterImportContract(options = {}) {
35
+ return {
36
+ module: 'pulsewasm_broadcaster',
37
+ name: 'broadcast',
38
+ signature: '(channelsRef: i32, ctxRef: i32) -> ErrorRef(i32)',
39
+ returnPolicy: '0 = ok; non-zero = ErrorRef and dispatch/result fail with that error',
40
+ requiredWhenChannelsResolve: Boolean(options.requiredWhenChannelsResolve),
41
+ missingFailure: {
42
+ code: BROADCASTER_MISSING_CODE,
43
+ message: 'Channel routing resolved channels, but no broadcaster adaptor was provided.',
44
+ statusCode: 500
45
+ },
46
+ failureBehavior: 'non-zero ErrorRef becomes active error/result failure at adaptor boundary',
47
+ sideEffects: 'adaptor-defined; may attach GRIP/Fanout broadcaster behavior later'
48
+ };
49
+ }
50
+
51
+ module.exports = {
52
+ CHANNEL_BROADCASTER_VERSION,
53
+ CHANNEL_BROADCASTER_PHASE,
54
+ CHANNEL_ABI_EXPORTS,
55
+ CHANNEL_MISSING_HANDLER_CODE,
56
+ CHANNEL_INVALID_RESULT_CODE,
57
+ BROADCASTER_MISSING_CODE,
58
+ channelAbiContract,
59
+ broadcasterImportContract
60
+ };
@@ -0,0 +1,80 @@
1
+ 'use strict';
2
+
3
+ const JSON_BODY_VERSION = 'pulsewasm.json-body.v1';
4
+ const JSON_BODY_PHASE = '10F';
5
+ const DEPLOYMENT_POSTURE_VERSION = 'pulsewasm.deployment-posture.v1';
6
+
7
+ const JSON_TARGETS = new Set(['generic', 'schema', 'none', 'auto', 'parser']);
8
+ const ENGINE_TARGETS = new Set(['wasm', 'js']);
9
+ const DEFAULT_JSON_MAX_BYTES = 1_048_576;
10
+
11
+ const JSON_ABI_EXPORTS = Object.freeze([
12
+ 'pulse_request_body_text(ctxRef) -> StringRef',
13
+ 'pulse_request_body_len(ctxRef) -> i32',
14
+ 'pulse_request_json_parse(ctxRef) -> JsonParseResultRef',
15
+ 'pulse_json_result_ok(resultRef) -> i32',
16
+ 'pulse_json_result_value(resultRef) -> JsonValueRef',
17
+ 'pulse_json_result_error(resultRef) -> ErrorRef',
18
+ 'pulse_json_kind(valueRef) -> i32',
19
+ 'pulse_json_object_has(valueRef, keyPtr, keyLen) -> i32',
20
+ 'pulse_json_object_get(valueRef, keyPtr, keyLen) -> JsonValueRef',
21
+ 'pulse_json_array_len(valueRef) -> i32',
22
+ 'pulse_json_array_get(valueRef, index) -> JsonValueRef',
23
+ 'pulse_json_as_string(valueRef) -> StringRef',
24
+ 'pulse_json_as_f64(valueRef) -> f64',
25
+ 'pulse_json_as_bool(valueRef) -> i32',
26
+ 'pulse_result_json_text(ctxRef, statusCode, jsonPtr, jsonLen) -> void'
27
+ ]);
28
+
29
+ function plainObject(value) {
30
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
31
+ }
32
+
33
+ function selectRuntimeEngine(config) {
34
+ const runtime = plainObject(config.runtime);
35
+ const explicit = typeof runtime.engine === 'string' && runtime.engine !== '';
36
+ if (explicit) return { engine: runtime.engine, source: 'config.runtime.engine', explicit: true };
37
+ if (typeof config.target === 'string' && config.target === 'js') return { engine: 'js', source: 'config.target', explicit: false };
38
+ return { engine: 'wasm', source: config.target ? 'default-from-non-js-target' : 'default', explicit: false };
39
+ }
40
+
41
+ function selectJsonConfig(config) {
42
+ const runtime = plainObject(config.runtime);
43
+ const payload = plainObject(runtime.payload);
44
+ const json = plainObject(payload.json || config.json);
45
+ const explicitTarget = typeof json.target === 'string' && json.target !== '';
46
+ const target = explicitTarget ? json.target : 'generic';
47
+ const maxBytes = json.maxBytes === undefined || json.maxBytes === null ? DEFAULT_JSON_MAX_BYTES : Number(json.maxBytes);
48
+ return {
49
+ raw: json,
50
+ target,
51
+ explicitTarget,
52
+ targetSource: explicitTarget ? 'runtime.payload.json.target' : 'default',
53
+ maxBytes,
54
+ maxBytesSource: json.maxBytes === undefined || json.maxBytes === null ? 'default' : 'runtime.payload.json.maxBytes',
55
+ schemas: Array.isArray(json.schemas) ? json.schemas : [],
56
+ parser: typeof json.parser === 'string' && json.parser ? json.parser : undefined
57
+ };
58
+ }
59
+
60
+ function isSupportedJsonTarget(target) {
61
+ return JSON_TARGETS.has(target);
62
+ }
63
+
64
+ function isSupportedRuntimeEngine(engine) {
65
+ return ENGINE_TARGETS.has(engine);
66
+ }
67
+
68
+ module.exports = {
69
+ JSON_BODY_VERSION,
70
+ JSON_BODY_PHASE,
71
+ DEPLOYMENT_POSTURE_VERSION,
72
+ JSON_TARGETS,
73
+ ENGINE_TARGETS,
74
+ DEFAULT_JSON_MAX_BYTES,
75
+ JSON_ABI_EXPORTS,
76
+ selectRuntimeEngine,
77
+ selectJsonConfig,
78
+ isSupportedJsonTarget,
79
+ isSupportedRuntimeEngine
80
+ };
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+
3
+ const REQUEST_RESULT_HEADERS_VERSION = 'pulsewasm.request-result-headers.v2';
4
+ const REQUEST_RESULT_HEADERS_PHASE = '12D';
5
+
6
+ const HEADER_ABI_EXPORTS = Object.freeze([
7
+ 'pulse_request_header_first(ctxRef, namePtr, nameLen) -> StringRef',
8
+ 'pulse_request_header_count(ctxRef, namePtr, nameLen) -> i32',
9
+ 'pulse_request_header_at(ctxRef, namePtr, nameLen, index) -> StringRef',
10
+ 'pulse_response_header_set(ctxRef, namePtr, nameLen, valuePtr, valueLen) -> void',
11
+ 'pulse_response_header_append(ctxRef, namePtr, nameLen, valuePtr, valueLen) -> void',
12
+ 'pulse_response_header_delete(ctxRef, namePtr, nameLen) -> void',
13
+ 'pulse_result_header_count() -> i32',
14
+ 'pulse_result_header_name_ptr(index) -> i32',
15
+ 'pulse_result_header_name_len(index) -> i32',
16
+ 'pulse_result_header_value_ptr(index) -> i32',
17
+ 'pulse_result_header_value_len(index) -> i32',
18
+ 'pulse_result_header_mode(index) -> i32',
19
+ 'pulse_result_header_delete_count() -> i32',
20
+ 'pulse_result_header_delete_name_ptr(index) -> i32',
21
+ 'pulse_result_header_delete_name_len(index) -> i32'
22
+ ]);
23
+
24
+ function handlerVisibleHeaderAbiExports() {
25
+ return HEADER_ABI_EXPORTS.slice(0, 6);
26
+ }
27
+
28
+ function hostResultHeaderAbiExports() {
29
+ return HEADER_ABI_EXPORTS.slice(6);
30
+ }
31
+
32
+ module.exports = {
33
+ REQUEST_RESULT_HEADERS_VERSION,
34
+ REQUEST_RESULT_HEADERS_PHASE,
35
+ HEADER_ABI_EXPORTS,
36
+ handlerVisibleHeaderAbiExports,
37
+ hostResultHeaderAbiExports
38
+ };
@@ -0,0 +1,90 @@
1
+ 'use strict';
2
+
3
+ const { RESULT_KINDS } = require('./wasm-host-abi.js');
4
+
5
+ const STREAMING_PASSTHROUGH_VERSION = 'pulsewasm.streaming-passthrough.v1';
6
+ const STREAM_RESULT_ABI_VERSION = 'pulsewasm.stream-result-abi.v1';
7
+ const RESPONSE_PASSTHROUGH_POLICY_VERSION = 'pulsewasm.response-passthrough-policy.v1';
8
+ const STREAMING_PHASE = '12D';
9
+ const STREAMING_SMOKE_VERSION = 'pulsewasm.streaming-passthrough-smoke.v1';
10
+
11
+ const STREAM_RESULT_ABI_EXPORTS = Object.freeze([
12
+ 'pulse_result_from_response(ctxRef, responseRef) -> void',
13
+ 'pulse_result_stream(ctxRef, statusCode, streamRef) -> void',
14
+ 'pulse_result_stream_ref() -> HostStreamRef',
15
+ 'pulse_result_response_ref() -> HostResponseRef'
16
+ ]);
17
+
18
+ const RESPONSE_HEADER_MERGE_RULES = Object.freeze([
19
+ 'Preserve backend/platform response headers by default.',
20
+ 'Apply response header delete operations first by ASCII case-insensitive name.',
21
+ 'Apply response header set operations as overrides by ASCII case-insensitive name.',
22
+ 'Apply response header append operations as ordered additions.',
23
+ 'Preserve repeated headers such as Grip-Channel.'
24
+ ]);
25
+
26
+ function streamResultAbiFields(options = {}) {
27
+ return {
28
+ sourceWasmHostAbiVersion: options.sourceWasmHostAbiVersion,
29
+ policy: {
30
+ phase: STREAMING_PHASE,
31
+ status: 'locked-contract-and-local-proof',
32
+ resultBinaryReserved: true,
33
+ resultStreamImplemented: true,
34
+ wasmOwnsBytes: false,
35
+ hostOwnsStream: true
36
+ },
37
+ resultKinds: RESULT_KINDS,
38
+ refs: {
39
+ HostResponseRef: 'opaque i32/usize owned by host; valid for active request/result lifetime only',
40
+ HostStreamRef: 'opaque i32/usize owned by host; valid for active request/result lifetime only'
41
+ },
42
+ exports: STREAM_RESULT_ABI_EXPORTS.slice(),
43
+ hostResultShape: {
44
+ kind: 'stream',
45
+ status: 'backend response status or explicit stream status',
46
+ headers: 'ordered repeated headers after pass-through merge',
47
+ bodyStream: 'host-owned stream / platform response body handle',
48
+ body: 'undefined; bytes are not copied through Wasm'
49
+ }
50
+ };
51
+ }
52
+
53
+ function responsePassthroughPolicyFields() {
54
+ return {
55
+ policy: {
56
+ phase: STREAMING_PHASE,
57
+ hostOwnsStream: true,
58
+ headerMergeIsOrdered: true,
59
+ platformBindings: false,
60
+ assetSemantics: false
61
+ },
62
+ headerMergeRules: RESPONSE_HEADER_MERGE_RULES.slice(),
63
+ streamOwnership: {
64
+ owner: 'host',
65
+ wasmRepresentation: 'opaque ref only',
66
+ hostCopiesBytesIntoWasm: false,
67
+ resultExtraction: 'host maps ref back to host stream/response and copies no body bytes',
68
+ lifetime: 'active request/result lifetime'
69
+ },
70
+ failureAndCancellation: {
71
+ beforeResponseStarts: 'normal Pulse error/result path',
72
+ afterResponseStarts: 'host/platform transport policy',
73
+ clientDisconnect: 'host cancels stream if platform supports cancellation',
74
+ contextExpiresBeforeStreamStarts: '504 PULSEWASM_CONTEXT_TIMEOUT',
75
+ contextExpiresAfterStreamStarts: 'host/platform policy'
76
+ }
77
+ };
78
+ }
79
+
80
+ module.exports = {
81
+ STREAMING_PASSTHROUGH_VERSION,
82
+ STREAM_RESULT_ABI_VERSION,
83
+ RESPONSE_PASSTHROUGH_POLICY_VERSION,
84
+ STREAMING_PHASE,
85
+ STREAMING_SMOKE_VERSION,
86
+ STREAM_RESULT_ABI_EXPORTS,
87
+ RESPONSE_HEADER_MERGE_RULES,
88
+ streamResultAbiFields,
89
+ responsePassthroughPolicyFields
90
+ };