@pulse-compute/wasm-compiler 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 (104) hide show
  1. package/README.md +52 -1
  2. package/bin/provider-proof-composition.js +34 -0
  3. package/bin/pulsewasm-extract.js +20 -0
  4. package/package.json +60 -5
  5. package/src/artifacts-dir.js +13 -0
  6. package/src/ast-json.js +52 -0
  7. package/src/build-manifest.js +354 -0
  8. package/src/canonical-api-compiler.js +245 -0
  9. package/src/canonical-native-compiler.js +411 -0
  10. package/src/canonical-native-plan.js +1477 -0
  11. package/src/canonical-project-compiler.js +1218 -0
  12. package/src/canonical-router-compiler.js +25 -0
  13. package/src/cli-intents.js +1235 -0
  14. package/src/cli.js +1927 -0
  15. package/src/codegen/assemblyscript-compile.js +3 -0
  16. package/src/codegen/assemblyscript-core.js +3 -0
  17. package/src/codegen/assemblyscript-shape.js +3 -0
  18. package/src/codegen/assemblyscript-wasm-smoke.js +3 -0
  19. package/src/codegen/backend-capabilities.js +3 -0
  20. package/src/codegen/channel-broadcaster.js +3 -0
  21. package/src/codegen/compiled-handlers.js +3 -0
  22. package/src/codegen/compiled-wasm-runtime.js +3 -0
  23. package/src/codegen/config-references.js +248 -0
  24. package/src/codegen/dispatch-ts.js +145 -0
  25. package/src/codegen/effect-composition.js +331 -0
  26. package/src/codegen/effect-runtime.js +418 -0
  27. package/src/codegen/execution-harness-ts.js +467 -0
  28. package/src/codegen/handler-bindings-ts.js +298 -0
  29. package/src/codegen/handler-library-contracts.js +3 -0
  30. package/src/codegen/host-capabilities.js +3 -0
  31. package/src/codegen/host-runtime-kernel.js +3 -0
  32. package/src/codegen/integrated-compiled-app.js +3 -0
  33. package/src/codegen/json-body.js +3 -0
  34. package/src/codegen/library-sidecars.js +3 -0
  35. package/src/codegen/local-harness-ts.js +453 -0
  36. package/src/codegen/pulse-wrapper.js +217 -0
  37. package/src/codegen/request-result-headers.js +3 -0
  38. package/src/codegen/schema-json-compile.js +3 -0
  39. package/src/codegen/schema-json-sidecar-v2.js +3 -0
  40. package/src/codegen/schema-json-sidecar.js +3 -0
  41. package/src/codegen/streaming-passthrough.js +3 -0
  42. package/src/codegen/wasm-host-abi.js +3 -0
  43. package/src/codegen/wasm-host-bridge.js +3 -0
  44. package/src/compiled-wasm-host-runtime-kv.js +3 -0
  45. package/src/config-resolver.js +813 -0
  46. package/src/crypto-requirement-planner.js +89 -0
  47. package/src/definitions/config-schema.js +14 -0
  48. package/src/definitions/handler-roles.js +14 -0
  49. package/src/definitions/path-grammar.js +14 -0
  50. package/src/definitions/router-api.js +14 -0
  51. package/src/diagnostics/codes.js +14 -0
  52. package/src/diagnostics/reporter.js +14 -0
  53. package/src/diagnostics.js +14 -0
  54. package/src/dispatch-table.js +400 -0
  55. package/src/events/event-emit.js +265 -0
  56. package/src/events/event-topology.js +127 -0
  57. package/src/execution-plan.js +463 -0
  58. package/src/extractor.js +2816 -0
  59. package/src/handler-eval.js +1154 -0
  60. package/src/handler-table.js +326 -0
  61. package/src/index.js +19 -0
  62. package/src/javascript-application-plan.js +181 -0
  63. package/src/kv-provider.js +3 -0
  64. package/src/path-table.js +60 -0
  65. package/src/path.js +14 -0
  66. package/src/patterns/config-define.js +30 -0
  67. package/src/patterns/dependency-call.js +18 -0
  68. package/src/patterns/env-lookup.js +13 -0
  69. package/src/patterns/handler-reference.js +29 -0
  70. package/src/patterns/path-literal.js +35 -0
  71. package/src/patterns/result.js +15 -0
  72. package/src/patterns/router-chain-call.js +50 -0
  73. package/src/patterns/router-construction.js +19 -0
  74. package/src/project/package-reachability.js +782 -0
  75. package/src/project/reachable-graph-builder.js +992 -0
  76. package/src/project/reachable-graph-contract.js +54 -0
  77. package/src/project/reachable-graph-implementation.js +36 -0
  78. package/src/project/router-module-linker.js +710 -0
  79. package/src/project-config-compiler.js +222 -0
  80. package/src/project-target-support.js +500 -0
  81. package/src/provider-toolchain.js +299 -0
  82. package/src/spine/async-surface-normalizer.js +312 -0
  83. package/src/spine/canonical-handler-ir.js +335 -0
  84. package/src/spine/canonical-native-module.js +87 -0
  85. package/src/spine/canonical-native-plan.js +89 -0
  86. package/src/spine/canonical-project.js +76 -0
  87. package/src/spine/canonical-router.js +155 -0
  88. package/src/spine/canonical-source.js +165 -0
  89. package/src/spine/diagnostic-authority.js +290 -0
  90. package/src/spine/equivalence.js +262 -0
  91. package/src/spine/guest-unit-stage.js +87 -0
  92. package/src/spine/handler-ir-emitter.js +454 -0
  93. package/src/spine/handler-ir-managed.js +1597 -0
  94. package/src/spine/handler-ir.js +797 -0
  95. package/src/spine/handler-surface-authority.js +585 -0
  96. package/src/spine/package-operation-seam.js +1015 -0
  97. package/src/spine/pipeline.js +202 -0
  98. package/src/spine/plain-handler-frontend.js +537 -0
  99. package/src/spine/provider-requirement-authority.js +208 -0
  100. package/src/spine/router-control-contract.js +17 -0
  101. package/src/spine/router-handler-frontend.js +513 -0
  102. package/src/spine/router-handler-ir.js +372 -0
  103. package/src/spine/router-topology-frontend.js +635 -0
  104. package/src/stable-id.js +14 -0
@@ -0,0 +1,331 @@
1
+ 'use strict';
2
+
3
+ const { PACKAGE_VERSION, normalizeArtifact, normalizeDiagnostic } = require('../diagnostics.js');
4
+
5
+ const PHASE = '11G';
6
+ const EFFECT_COMPOSITION_VERSION = 'pulsewasm.effect-composition.v1';
7
+ const EFFECT_PLAN_CONTRACT_VERSION = 'pulsewasm.effect-plan-contract.v1';
8
+ const EFFECT_CONTINUATION_CONTRACT_VERSION = 'pulsewasm.effect-continuation-contract.v1';
9
+ const TIMEOUT_SCOPE_POLICY_VERSION = 'pulsewasm.timeout-scope-policy.v1';
10
+
11
+ const DEFAULT_TIMEOUTS = Object.freeze({
12
+ defaultMs: 5000,
13
+ hardMs: 30000,
14
+ effectDefaultMs: 5000,
15
+ schedulerResolutionMs: 10
16
+ });
17
+
18
+ const EFFECT_GROUP_STRATEGIES = Object.freeze({
19
+ all: { status: 'allowed-v1', meaning: 'Resolve all named effects, then invoke the continuation handler.' },
20
+ sequence: { status: 'reserved', meaning: 'Use named continuation handlers instead of implicit sequence graphs in v1.' },
21
+ race: { status: 'reserved', meaning: 'Race/first-result composition is reserved.' }
22
+ });
23
+
24
+ function positiveInt(value, fallback) {
25
+ const number = Number(value);
26
+ return Number.isFinite(number) && number > 0 && Math.floor(number) === number ? number : fallback;
27
+ }
28
+
29
+ function runtimeTimeouts(resolvedConfig) {
30
+ const runtime = resolvedConfig?.runtime || resolvedConfig?.config?.runtime || {};
31
+ const timeouts = runtime && typeof runtime === 'object' && !Array.isArray(runtime) ? runtime.timeouts || {} : {};
32
+ const hardMs = positiveInt(timeouts.hardMs, DEFAULT_TIMEOUTS.hardMs);
33
+ return {
34
+ defaultMs: Math.min(positiveInt(timeouts.defaultMs, DEFAULT_TIMEOUTS.defaultMs), hardMs),
35
+ hardMs,
36
+ effectDefaultMs: Math.min(positiveInt(timeouts.effectDefaultMs, DEFAULT_TIMEOUTS.effectDefaultMs), hardMs),
37
+ schedulerResolutionMs: positiveInt(timeouts.schedulerResolutionMs, DEFAULT_TIMEOUTS.schedulerResolutionMs),
38
+ source: timeouts && Object.keys(timeouts).length > 0 ? 'config' : 'pulse-default'
39
+ };
40
+ }
41
+
42
+ function makeDiagnostic(code, message, hint, details) {
43
+ return normalizeDiagnostic({
44
+ phase: 'effect-composition',
45
+ severity: 'error',
46
+ code,
47
+ message,
48
+ hint,
49
+ details,
50
+ loc: { file: '<effect-composition>' }
51
+ });
52
+ }
53
+
54
+ function scopeTimeoutSummary(executionPlan) {
55
+ const scopes = Array.isArray(executionPlan?.scopes) ? executionPlan.scopes : [];
56
+ const overrides = Array.isArray(executionPlan?.timeoutOverrides) ? executionPlan.timeoutOverrides : [];
57
+ return {
58
+ scopes: scopes.length,
59
+ scopesWithTimeout: scopes.filter((scope) => scope.timeout).length,
60
+ overrides: overrides.length,
61
+ appDefault: executionPlan?.timeoutPolicy?.appDefault,
62
+ overrideRouters: overrides.map((override) => ({
63
+ router: override.router,
64
+ routerPath: override.routerPath,
65
+ timeout: override.timeout
66
+ }))
67
+ };
68
+ }
69
+
70
+ function buildTimeoutScopePolicy({ generatedBy, resolvedConfig, executionPlan }) {
71
+ const appDefault = runtimeTimeouts(resolvedConfig);
72
+ return normalizeArtifact({
73
+ version: TIMEOUT_SCOPE_POLICY_VERSION,
74
+ generatedBy,
75
+ phase: PHASE,
76
+ status: 'locked',
77
+ policy: {
78
+ defaultsLiveInConfig: true,
79
+ pulseDefaultsWhenConfigOmitted: true,
80
+ scopeOverridesAreStaticMetadata: true,
81
+ timeoutIsNotMiddleware: true,
82
+ handlersNormallyDoNotInstrumentTimeouts: true,
83
+ hardDeadlineCannotBeExtended: true,
84
+ scopeMayTightenButNotExceedAppHardDeadline: true,
85
+ effectGroupTimeoutCappedByScopeHardDeadline: true,
86
+ clockSource: 'monotonic',
87
+ wallClockForDeadlines: false,
88
+ cpuPreemptionV1: false
89
+ },
90
+ defaults: appDefault,
91
+ inheritance: {
92
+ order: ['app default', 'router scope override', 'mounted child scope', 'effect group timeout'],
93
+ hardMsRule: 'effectiveHardMs = min(parentHardMs, scopeHardMs)',
94
+ omittedValueRule: 'omitted values inherit from parent/app defaults'
95
+ },
96
+ runtimeErrors: {
97
+ contextTimeout: { code: 'PULSEWASM_CONTEXT_TIMEOUT', statusCode: 504 },
98
+ effectTimeout: { code: 'PULSEWASM_EFFECT_TIMEOUT', statusCode: 504 },
99
+ requestTimeout: { code: 'PULSEWASM_REQUEST_TIMEOUT', statusCode: 408 },
100
+ contractViolation: { code: 'PULSEWASM_NO_RESULT', statusCode: 500 },
101
+ normalFallthrough: { statusCode: 404 }
102
+ },
103
+ executionPlan: scopeTimeoutSummary(executionPlan)
104
+ }, process.cwd());
105
+ }
106
+
107
+ function buildEffectPlanContract({ generatedBy }) {
108
+ return {
109
+ version: EFFECT_PLAN_CONTRACT_VERSION,
110
+ generatedBy,
111
+ phase: PHASE,
112
+ status: 'locked',
113
+ model: {
114
+ effectRefsOnly: true,
115
+ resolveBoundaryRequired: true,
116
+ effectGroupArtifact: 'effect-plan.json reserved for implementation phase',
117
+ promises: false,
118
+ asyncAwait: false,
119
+ microScheduler: false,
120
+ arbitraryCallbacks: false
121
+ },
122
+ allowedV1: {
123
+ groupStrategy: 'all',
124
+ failurePolicy: 'fail-fast',
125
+ effectGroupShape: 'static object literal with string-literal keys',
126
+ continuation: 'top-level named continuation handler',
127
+ timeout: 'optional bounded timeoutMs, capped by current scope hard deadline',
128
+ effects: [
129
+ { kind: 'sleep', status: 'first-proof-target', surface: 'ctx.sleep(ms)' },
130
+ { kind: 'backend-fetch', status: 'contracted-future', surface: 'ctx.fetch("backend", requestSpec)' },
131
+ { kind: 'body-read', status: 'contracted-future', surface: 'ctx.bodyText() / ctx.bodyJson() reserved' }
132
+ ]
133
+ },
134
+ explicitlyExcluded: {
135
+ assets: {
136
+ excludedFromV1EffectKinds: true,
137
+ classification: 'host-capability/payload-streaming-surface',
138
+ reason: 'Assets drag binary/streaming/cache/provider mechanics into the effect runtime too early.'
139
+ }
140
+ },
141
+ rejectedV1: [
142
+ 'ctx.fetch(callback)',
143
+ 'Promise.then/catch/finally',
144
+ 'async/await',
145
+ 'dynamic effect names',
146
+ 'dynamic backend keys',
147
+ 'dynamic request builders',
148
+ 'helper-built effect groups',
149
+ 'loop-generated effects',
150
+ 'race/collect policies',
151
+ 'inline callbacks with closure capture',
152
+ 'arbitrary nested effect graphs'
153
+ ],
154
+ reserved: [
155
+ 'inline continuation lifting',
156
+ 'collect failure policy',
157
+ 'race',
158
+ 'dependent effect graph optimization',
159
+ 'template path lowering with ctx.param(...)',
160
+ 'effect-plan.json implementation artifact'
161
+ ]
162
+ };
163
+ }
164
+
165
+ function buildEffectContinuationContract({ generatedBy }) {
166
+ return {
167
+ version: EFFECT_CONTINUATION_CONTRACT_VERSION,
168
+ generatedBy,
169
+ phase: PHASE,
170
+ status: 'locked',
171
+ continuationModel: {
172
+ namedContinuationHandlers: true,
173
+ continuationHandlersUseHandlerEvalJail: true,
174
+ continuationCapturesClosureState: false,
175
+ continuationStoresResultsByName: true,
176
+ effectResultAccess: ['ctx.resolved()', 'ctx.resolved("name")'],
177
+ failurePolicyDefault: 'fail-fast'
178
+ },
179
+ abiReserved: {
180
+ pulseEffectResult: 'pulse_effect_result(ctxRef, keyPtr, keyLen) -> EffectResultRef',
181
+ pulseEffectError: 'reserved-after-Pass-30',
182
+ pulseEffectHas: 'reserved-after-Pass-30'
183
+ },
184
+ staleResume: {
185
+ generationChecked: true,
186
+ contextMustExist: true,
187
+ effectMustBePending: true,
188
+ contextMustNotBeExpiredOrCleaned: true,
189
+ diagnostic: 'PULSEWASM_STALE_EFFECT_RESUME'
190
+ }
191
+ };
192
+ }
193
+
194
+ function markdownForEffectComposition(artifact, effectPlanContract, continuationContract, timeoutScopePolicy) {
195
+ const lines = [];
196
+ lines.push('# PulseWasm Phase 11G Effect Composition + Timeout Scope Contract');
197
+ lines.push('');
198
+ lines.push('## Status');
199
+ lines.push('Locked as a contract/artifact phase. No effect execution or compiled handler lowering is implemented here.');
200
+ lines.push('');
201
+ lines.push('## Core Rules');
202
+ lines.push('- `ctx.fetch(...)`, `ctx.sleep(...)`, and future body reads create effect refs; they do not perform work immediately.');
203
+ lines.push('- `ctx.resolve({ name: effectRef }, continuationHandler)` submits the effect group and defines the explicit continuation.');
204
+ lines.push('- `sleep` is the first proof target.');
205
+ lines.push('- assets are not a v1 core effect kind; they remain a host capability and future payload/streaming surface.');
206
+ lines.push('- timeouts are app defaults plus static router-scope metadata overrides.');
207
+ lines.push('');
208
+ lines.push('## Summary');
209
+ lines.push(`- allowed effect group strategy: ${artifact.summary.allowedStrategies.join(', ')}`);
210
+ lines.push(`- reserved strategies: ${artifact.summary.reservedStrategies.join(', ')}`);
211
+ lines.push(`- timeout scopes: ${timeoutScopePolicy.executionPlan.scopes}`);
212
+ lines.push(`- timeout overrides: ${timeoutScopePolicy.executionPlan.overrides}`);
213
+ lines.push(`- diagnostics: ${artifact.summary.diagnostics}`);
214
+ lines.push('');
215
+ lines.push('## Allowed v1 Shape');
216
+ lines.push('');
217
+ lines.push('```ts');
218
+ lines.push('function handler(ctx, next) {');
219
+ lines.push(' return ctx.resolve({');
220
+ lines.push(' wake: ctx.sleep(25)');
221
+ lines.push(' }, afterWake)');
222
+ lines.push('}');
223
+ lines.push('');
224
+ lines.push('function afterWake(ctx, next) {');
225
+ lines.push(' const wake = ctx.resolved("wake")');
226
+ lines.push(' return ctx.result.text(200, wake.text())');
227
+ lines.push('}');
228
+ lines.push('```');
229
+ lines.push('');
230
+ lines.push('## Rejected v1');
231
+ lines.push('');
232
+ for (const rejected of effectPlanContract.rejectedV1) lines.push(`- ${rejected}`);
233
+ lines.push('');
234
+ lines.push('## Timeout Scope');
235
+ lines.push('');
236
+ lines.push(`- defaultMs: ${timeoutScopePolicy.defaults.defaultMs}`);
237
+ lines.push(`- hardMs: ${timeoutScopePolicy.defaults.hardMs}`);
238
+ lines.push(`- effectDefaultMs: ${timeoutScopePolicy.defaults.effectDefaultMs}`);
239
+ lines.push(`- schedulerResolutionMs: ${timeoutScopePolicy.defaults.schedulerResolutionMs}`);
240
+ lines.push('');
241
+ return `${lines.join('\n')}\n`;
242
+ }
243
+
244
+ function buildEffectComposition(inputs = {}) {
245
+ const cwd = inputs.cwd || process.cwd();
246
+ const generatedBy = inputs.generatedBy || PACKAGE_VERSION;
247
+ const diagnostics = [];
248
+ const effectPlanContract = normalizeArtifact(buildEffectPlanContract({ generatedBy }), cwd);
249
+ const effectContinuationContract = normalizeArtifact(buildEffectContinuationContract({ generatedBy }), cwd);
250
+ const timeoutScopePolicy = normalizeArtifact(buildTimeoutScopePolicy({ generatedBy, resolvedConfig: inputs.resolvedConfig, executionPlan: inputs.executionPlan }), cwd);
251
+
252
+ const allowedStrategies = Object.entries(EFFECT_GROUP_STRATEGIES).filter(([, value]) => value.status === 'allowed-v1').map(([key]) => key);
253
+ const reservedStrategies = Object.entries(EFFECT_GROUP_STRATEGIES).filter(([, value]) => value.status !== 'allowed-v1').map(([key]) => key);
254
+ const effectKinds = effectPlanContract.allowedV1.effects.map((effect) => effect.kind);
255
+
256
+ if (effectKinds.includes('asset-read')) {
257
+ diagnostics.push(makeDiagnostic(
258
+ 'PULSEWASM_ASSET_EFFECT_KIND_FORBIDDEN',
259
+ 'Assets must not be registered as a v1 core effect kind.',
260
+ 'Treat assets as a reserved host capability/payload streaming surface instead.',
261
+ { effectKinds }
262
+ ));
263
+ }
264
+
265
+ const artifact = normalizeArtifact({
266
+ version: EFFECT_COMPOSITION_VERSION,
267
+ generatedBy,
268
+ phase: PHASE,
269
+ status: diagnostics.length === 0 ? 'ok' : 'error',
270
+ scope: {
271
+ contractOnly: true,
272
+ runtimeBehaviorChanged: false,
273
+ effectExecutionImplemented: false,
274
+ compiledHandlerLoweringImplemented: false,
275
+ routerTimeoutExtractionImplemented: true,
276
+ executionPlanTimeoutMetadataImplemented: true
277
+ },
278
+ policy: {
279
+ effectRefsDeclaredNotExecuted: true,
280
+ resolveBoundaryRequired: true,
281
+ explicitContinuations: true,
282
+ namedContinuationHandlers: true,
283
+ noPromises: true,
284
+ noAsyncAwait: true,
285
+ noMicroScheduler: true,
286
+ noCallbackInFetch: true,
287
+ failurePolicy: 'fail-fast',
288
+ assetsExcludedFromV1EffectKinds: true,
289
+ assetsReservedForHostCapabilityAndPayloadStreaming: true,
290
+ timeoutsFromMetadata: true
291
+ },
292
+ effectGroupStrategies: EFFECT_GROUP_STRATEGIES,
293
+ summary: {
294
+ allowedStrategies,
295
+ reservedStrategies,
296
+ effectKinds,
297
+ firstProofTarget: 'sleep',
298
+ timeoutScopes: timeoutScopePolicy.executionPlan.scopes,
299
+ timeoutOverrides: timeoutScopePolicy.executionPlan.overrides,
300
+ diagnostics: diagnostics.length,
301
+ readyFor12A: diagnostics.length === 0,
302
+ readyForEffectExecution: false,
303
+ readyForFastly: false
304
+ },
305
+ diagnostics
306
+ }, cwd);
307
+
308
+ const markdown = markdownForEffectComposition(artifact, effectPlanContract, effectContinuationContract, timeoutScopePolicy);
309
+ return {
310
+ artifact,
311
+ effectPlanContract,
312
+ effectContinuationContract,
313
+ timeoutScopePolicy,
314
+ diagnostics,
315
+ files: [{ file: 'generated/host/effect-composition.md', text: markdown }]
316
+ };
317
+ }
318
+
319
+ module.exports = {
320
+ PHASE,
321
+ EFFECT_COMPOSITION_VERSION,
322
+ EFFECT_PLAN_CONTRACT_VERSION,
323
+ EFFECT_CONTINUATION_CONTRACT_VERSION,
324
+ TIMEOUT_SCOPE_POLICY_VERSION,
325
+ EFFECT_GROUP_STRATEGIES,
326
+ DEFAULT_TIMEOUTS,
327
+ buildEffectComposition,
328
+ buildEffectPlanContract,
329
+ buildEffectContinuationContract,
330
+ buildTimeoutScopePolicy
331
+ };