@pulse-compute/wasm-compiler 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 (104) hide show
  1. package/README.md +53 -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 +269 -0
  9. package/src/canonical-native-compiler.js +411 -0
  10. package/src/canonical-native-plan.js +1478 -0
  11. package/src/canonical-project-compiler.js +1224 -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 +328 -0
  83. package/src/spine/canonical-handler-ir.js +336 -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 +455 -0
  93. package/src/spine/handler-ir-managed.js +1598 -0
  94. package/src/spine/handler-ir.js +797 -0
  95. package/src/spine/handler-surface-authority.js +588 -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 +545 -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 +514 -0
  102. package/src/spine/router-handler-ir.js +372 -0
  103. package/src/spine/router-topology-frontend.js +638 -0
  104. package/src/stable-id.js +14 -0
@@ -0,0 +1,2816 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const ts = require('typescript');
6
+ const { astToJson } = require('./ast-json.js');
7
+ const {
8
+ PACKAGE_VERSION,
9
+ DIAGNOSTICS_VERSION,
10
+ diagnostic,
11
+ ExtractionError,
12
+ normalizeArtifact,
13
+ sourceLoc,
14
+ stableFileName
15
+ } = require('./diagnostics.js');
16
+ const {
17
+ createRouteIdMap,
18
+ createRouteStableId,
19
+ buildRouteStableInput,
20
+ sourceTextHash
21
+ } = require('./stable-id.js');
22
+ const { buildHandlerTable } = require('./handler-table.js');
23
+ const { buildHandlerEval } = require('./handler-eval.js');
24
+ const { buildPathTable } = require('./path-table.js');
25
+ const { buildDispatchTable } = require('./dispatch-table.js');
26
+ const { buildExecutionPlan } = require('./execution-plan.js');
27
+ const { ROUTE_ID_POLICY, ROUTE_PLAN_VERSION } = loadContractsRoutePlan();
28
+ const EVENTS = loadContractsEvents();
29
+ const { buildTypeScriptDispatch } = require('./codegen/dispatch-ts.js');
30
+ const { buildTypeScriptHandlerBindings } = require('./codegen/handler-bindings-ts.js');
31
+ const { buildTypeScriptExecutionHarness } = require('./codegen/execution-harness-ts.js');
32
+ const {
33
+ buildAssemblyScriptShape,
34
+ buildAssemblyScriptCore,
35
+ buildAssemblyScriptWasmSmoke,
36
+ buildCompiledUserHandlers,
37
+ buildIntegratedCompiledApp,
38
+ buildRouteHandlerEffectPlan,
39
+ buildRouteHandlerContextLoweringPlan,
40
+ buildHandlerIoLifecyclePlan,
41
+ buildRequestJsonBodyPlan,
42
+ buildSchemaDecodeResultPlan,
43
+ buildSchemaResponseCodecPlan,
44
+ buildBackendJsonRequestBodyPlan
45
+ } = require('@pulse-compute/wasm-runtime-core-as/compiler');
46
+ const { buildTypeScriptLocalHarness } = require('./codegen/local-harness-ts.js');
47
+ const { buildAssemblyScriptCompileSmoke } = require('@pulse-compute/wasm-build-support/assemblyscript-compile');
48
+ const {
49
+ buildWasmHostAbi,
50
+ buildWasmHostBridge,
51
+ buildRequestResultHeaders,
52
+ buildChannelBroadcaster,
53
+ buildJsonBodyAbi,
54
+ buildDeploymentPosture,
55
+ buildBackendCapabilities,
56
+ buildHostRuntimeKernel,
57
+ buildStreamingPassthrough,
58
+ buildCompiledWasmRuntime
59
+ } = require('@pulse-compute/wasm-host-runtime/compiler');
60
+ const {
61
+ buildHandlerLibraryContracts,
62
+ buildHostCapabilities,
63
+ buildLibrarySidecarConsumption,
64
+ buildAssetsLoweringPlan,
65
+ buildAssetsCompiledWasmSidecarPlan,
66
+ buildAssetsSidecarCompileLinkProof,
67
+ discoverLowerableLibraryManifests
68
+ } = require('@pulse-compute/wasm-library-kit/compiler');
69
+ const { buildEffectRuntime } = require('./codegen/effect-runtime.js');
70
+ const { buildEffectComposition } = require('./codegen/effect-composition.js');
71
+ const { buildSchemaJsonSidecar, buildSchemaJsonCompile, buildSchemaJsonGenericParser, compileNeeded, genericParserNeeded } = require('@pulse-compute/wasm-schema-json/compiler');
72
+ const { buildPulseWrapperIntegration } = require('./codegen/pulse-wrapper.js');
73
+ const {
74
+ DEFAULT_ROUTER_API_REGISTRY,
75
+ SUPPORTED_METHODS,
76
+ ROUTE_METHODS,
77
+ arityDisplay,
78
+ buildRouterApiRegistry,
79
+ signatureForArity
80
+ } = require('./definitions/router-api.js');
81
+ const { DIAGNOSTIC_CODES } = require('./diagnostics/codes.js');
82
+ const { isInlineFunction: patternIsInlineFunction, classifyHandlerReference, classifyChannelReference } = require('./patterns/handler-reference.js');
83
+ const { isRouterNewExpression: patternIsRouterNewExpression, isDirectRouterDeclarationInitializer: patternIsDirectRouterDeclarationInitializer } = require('./patterns/router-construction.js');
84
+ const { unwindRouterCallChain, isOutermostCallInChain } = require('./patterns/router-chain-call.js');
85
+ const {
86
+ PATH_GRAMMAR_VERSION,
87
+ PATH_POLICY,
88
+ compileRoutePath,
89
+ extractParams,
90
+ joinPaths,
91
+ joinScopedPrefix,
92
+ normalizeRoutePath,
93
+ publicPathPattern,
94
+ scopedPathMatchDetails,
95
+ stripScopedWildcard,
96
+ validatePath
97
+ } = require('./path.js');
98
+
99
+ function loadContractsRoutePlan() {
100
+ try {
101
+ return require('@pulse-compute/wasm-contracts/route-plan');
102
+ } catch (error) {
103
+ if (error && error.code === 'MODULE_NOT_FOUND' && String(error.message).includes('@pulse-compute/wasm-contracts')) {
104
+ return require('../../contracts/src/route-plan.js');
105
+ }
106
+ throw error;
107
+ }
108
+ }
109
+
110
+ function loadContractsEvents() {
111
+ try {
112
+ return require('@pulse-compute/wasm-contracts/events');
113
+ } catch (error) {
114
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code) && String(error.message).includes('@pulse-compute/wasm-contracts')) {
115
+ return require('../../contracts/src/events/contracts.js');
116
+ }
117
+ throw error;
118
+ }
119
+ }
120
+
121
+ function scriptKindForFile(filePath) {
122
+ const ext = path.extname(filePath).toLowerCase();
123
+ if (ext === '.ts' || ext === '.mts' || ext === '.cts') return ts.ScriptKind.TS;
124
+ if (ext === '.tsx') return ts.ScriptKind.TSX;
125
+ if (ext === '.jsx') return ts.ScriptKind.JSX;
126
+ return ts.ScriptKind.JS;
127
+ }
128
+
129
+ function readSourceFile(filePath) {
130
+ const abs = path.resolve(filePath);
131
+ const text = fs.readFileSync(abs, 'utf8');
132
+ return ts.createSourceFile(abs, text, ts.ScriptTarget.Latest, true, scriptKindForFile(abs));
133
+ }
134
+
135
+ function refToString(ref) {
136
+ if (!ref) return undefined;
137
+ if (ref.kind === 'handler') return ref.id;
138
+ if (ref.kind === 'identifier' || ref.kind === 'inline' || ref.kind === 'ref' || ref.kind === 'static') return ref.value;
139
+ return String(ref.value ?? ref.id ?? '');
140
+ }
141
+
142
+ function refToName(ref) {
143
+ if (!ref) return undefined;
144
+ if (ref.kind === 'handler') return ref.name;
145
+ if (ref.kind === 'identifier' || ref.kind === 'inline' || ref.kind === 'ref' || ref.kind === 'static') return ref.value;
146
+ return String(ref.value ?? ref.name ?? '');
147
+ }
148
+
149
+ function isStringLiteralLike(node) {
150
+ return ts.isStringLiteral(node) || node.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral;
151
+ }
152
+
153
+ function literalText(node) {
154
+ return node.text;
155
+ }
156
+
157
+ function nodeText(sourceFile, node) {
158
+ return node.getText(sourceFile).trim();
159
+ }
160
+
161
+ function isInlineFunction(node) {
162
+ return patternIsInlineFunction(ts, node);
163
+ }
164
+
165
+ function hasModifier(node, kind) {
166
+ return Boolean(node.modifiers && node.modifiers.some((modifier) => modifier.kind === kind));
167
+ }
168
+
169
+ function isExportedNode(node) {
170
+ return hasModifier(node, ts.SyntaxKind.ExportKeyword);
171
+ }
172
+
173
+ function parameterName(sourceFile, parameter) {
174
+ if (ts.isIdentifier(parameter.name)) return parameter.name.text;
175
+ return nodeText(sourceFile, parameter.name);
176
+ }
177
+
178
+ function describeFunctionSignature(sourceFile, node) {
179
+ const params = Array.from(node.parameters || []).map((parameter) => parameterName(sourceFile, parameter));
180
+ const nonIdentifierParams = Array.from(node.parameters || [])
181
+ .filter((parameter) => !ts.isIdentifier(parameter.name))
182
+ .map((parameter) => nodeText(sourceFile, parameter.name));
183
+ const returnType = node.type ? node.type.getText(sourceFile) : undefined;
184
+ return {
185
+ async: hasModifier(node, ts.SyntaxKind.AsyncKeyword),
186
+ generator: Boolean(node.asteriskToken),
187
+ paramCount: params.length,
188
+ params,
189
+ nonIdentifierParams,
190
+ returnType,
191
+ returnsPromise: Boolean(returnType && /\bPromise\b/.test(returnType))
192
+ };
193
+ }
194
+
195
+ function declarationHandlerKind(init) {
196
+ if (ts.isArrowFunction(init)) return 'const-arrow';
197
+ if (ts.isFunctionExpression(init)) return 'const-function-expression';
198
+ return 'unknown';
199
+ }
200
+
201
+ function unwrapExpression(node) {
202
+ let current = node;
203
+ while (
204
+ current &&
205
+ (ts.isParenthesizedExpression(current) ||
206
+ ts.isAsExpression(current) ||
207
+ ts.isSatisfiesExpression?.(current) ||
208
+ ts.isNonNullExpression(current) ||
209
+ ts.isTypeAssertionExpression(current))
210
+ ) {
211
+ current = current.expression;
212
+ }
213
+ return current;
214
+ }
215
+
216
+ function parseDiagnostics(sourceFile) {
217
+ const diagnostics = [];
218
+ for (const parseDiag of sourceFile.parseDiagnostics || []) {
219
+ const start = parseDiag.start ?? 0;
220
+ const end = start + (parseDiag.length ?? 0);
221
+ const startLC = sourceFile.getLineAndCharacterOfPosition(start);
222
+ const endLC = sourceFile.getLineAndCharacterOfPosition(end);
223
+ diagnostics.push({
224
+ phase: 'parse',
225
+ code: 'PULSEWASM_PARSE_ERROR',
226
+ message: ts.flattenDiagnosticMessageText(parseDiag.messageText, '\n'),
227
+ hint: 'Fix syntax before PulseWasm extraction can continue.',
228
+ loc: {
229
+ file: sourceFile.fileName,
230
+ start: { line: startLC.line + 1, column: startLC.character + 1, offset: start },
231
+ end: { line: endLC.line + 1, column: endLC.character + 1, offset: end }
232
+ }
233
+ });
234
+ }
235
+ return diagnostics;
236
+ }
237
+
238
+ function unwrapReferenceExpression(node) {
239
+ const wrappers = [];
240
+ let current = node;
241
+ while (current) {
242
+ if (ts.isParenthesizedExpression(current)) wrappers.push('parentheses');
243
+ else if (ts.isAsExpression(current)) wrappers.push('as-cast');
244
+ else if (ts.isTypeAssertionExpression(current)) wrappers.push('type-assertion');
245
+ else if (ts.isSatisfiesExpression?.(current)) wrappers.push('satisfies');
246
+ else if (ts.isNonNullExpression(current)) wrappers.push('non-null');
247
+ else break;
248
+ current = current.expression;
249
+ }
250
+ return { expression: current, wrappers };
251
+ }
252
+
253
+ function parseHandlerRef(sourceFile, node, diagnostics, phase = 'extract') {
254
+ const unwrapped = unwrapReferenceExpression(node);
255
+ const classified = classifyHandlerReference(ts, unwrapped.expression);
256
+ if (classified.status === 'match' && classified.value.kind === 'identifier') {
257
+ return { kind: 'identifier', value: classified.value.name, ...(unwrapped.wrappers.length > 0 ? { wrappers: unwrapped.wrappers } : {}), loc: sourceLoc(sourceFile, node) };
258
+ }
259
+ if (classified.status === 'match' && classified.value.kind === 'inline') {
260
+ const value = nodeText(sourceFile, unwrapped.expression);
261
+ return {
262
+ kind: 'inline',
263
+ value,
264
+ inlineKind: classified.value.inlineKind,
265
+ ...(unwrapped.wrappers.length > 0 ? { wrappers: unwrapped.wrappers } : {}),
266
+ sourceTextHash: sourceTextHash(value),
267
+ signature: describeFunctionSignature(sourceFile, unwrapped.expression),
268
+ loc: sourceLoc(sourceFile, node)
269
+ };
270
+ }
271
+ diagnostics.push(
272
+ diagnostic(
273
+ sourceFile,
274
+ node,
275
+ DIAGNOSTIC_CODES.UNSUPPORTED_HANDLER,
276
+ 'Unsupported handler expression. PulseWasm v1 accepts direct identifier handlers and inline function expressions only.',
277
+ 'Use handlerName, function (...) { ... }, or (...) => { ... }.',
278
+ { phase }
279
+ )
280
+ );
281
+ return { kind: 'unsupported', value: nodeText(sourceFile, node), loc: sourceLoc(sourceFile, node) };
282
+ }
283
+
284
+ function parseChannelRef(sourceFile, node, diagnostics, phase = 'extract') {
285
+ const classified = classifyChannelReference(ts, node, (innerTs, innerNode) => isStringLiteralLike(innerNode));
286
+ if (classified.status === 'match' && classified.value.kind === 'static') {
287
+ return { kind: 'static', value: classified.value.value, loc: sourceLoc(sourceFile, node) };
288
+ }
289
+ if (classified.status === 'match' && classified.value.kind === 'identifier') {
290
+ return { kind: 'ref', value: classified.value.name, loc: sourceLoc(sourceFile, node) };
291
+ }
292
+ if (classified.status === 'match' && classified.value.kind === 'inline') {
293
+ const value = nodeText(sourceFile, node);
294
+ return {
295
+ kind: 'inline',
296
+ value,
297
+ inlineKind: classified.value.inlineKind,
298
+ sourceTextHash: sourceTextHash(value),
299
+ signature: describeFunctionSignature(sourceFile, node),
300
+ loc: sourceLoc(sourceFile, node)
301
+ };
302
+ }
303
+ diagnostics.push(
304
+ diagnostic(
305
+ sourceFile,
306
+ node,
307
+ DIAGNOSTIC_CODES.UNSUPPORTED_CHANNEL,
308
+ 'Unsupported channel expression. PulseWasm v1 accepts string literals, identifiers, and inline functions only.',
309
+ 'Use .channel("name"), .channel(channelFactory), or .channel((ctx) => "name").',
310
+ { phase }
311
+ )
312
+ );
313
+ return { kind: 'ref', value: nodeText(sourceFile, node), unsupported: true, loc: sourceLoc(sourceFile, node) };
314
+ }
315
+
316
+
317
+ function propertyNameTextForObject(sourceFile, nameNode, diagnostics, node) {
318
+ if (ts.isIdentifier(nameNode) || isStringLiteralLike(nameNode) || ts.isNumericLiteral(nameNode)) return nameNode.text;
319
+ diagnostics.push(
320
+ diagnostic(
321
+ sourceFile,
322
+ nameNode,
323
+ 'PULSEWASM_TIMEOUT_COMPUTED_KEY',
324
+ 'Computed timeout option keys are not supported in PulseWasm scope timeout metadata.',
325
+ 'Use static timeout keys such as defaultMs, hardMs, effectDefaultMs, and schedulerResolutionMs.',
326
+ { phase: 'extract' }
327
+ )
328
+ );
329
+ return nodeText(sourceFile, nameNode || node);
330
+ }
331
+
332
+ function parseTimeoutLiteral(sourceFile, node, diagnostics, phase = 'extract') {
333
+ const expr = unwrapExpression(node);
334
+ if (!ts.isObjectLiteralExpression(expr)) {
335
+ diagnostics.push(
336
+ diagnostic(
337
+ sourceFile,
338
+ node,
339
+ 'PULSEWASM_TIMEOUT_DYNAMIC',
340
+ 'Router .timeout(...) requires a static object literal in PulseWasm v1.',
341
+ 'Use .timeout({ defaultMs: 5000, hardMs: 30000, effectDefaultMs: 5000 }).',
342
+ { phase }
343
+ )
344
+ );
345
+ return { unsupported: true, source: nodeText(sourceFile, node), loc: sourceLoc(sourceFile, node) };
346
+ }
347
+
348
+ const allowed = new Set(['defaultMs', 'hardMs', 'effectDefaultMs', 'schedulerResolutionMs']);
349
+ const config = { loc: sourceLoc(sourceFile, node) };
350
+ for (const prop of expr.properties) {
351
+ if (ts.isSpreadAssignment(prop)) {
352
+ diagnostics.push(
353
+ diagnostic(
354
+ sourceFile,
355
+ prop,
356
+ 'PULSEWASM_TIMEOUT_SPREAD_UNSUPPORTED',
357
+ 'Object spread is not supported in router .timeout(...) metadata.',
358
+ 'Write timeout metadata as a direct object literal.',
359
+ { phase }
360
+ )
361
+ );
362
+ continue;
363
+ }
364
+ if (!ts.isPropertyAssignment(prop)) {
365
+ diagnostics.push(
366
+ diagnostic(
367
+ sourceFile,
368
+ prop,
369
+ 'PULSEWASM_TIMEOUT_PROPERTY_UNSUPPORTED',
370
+ 'Only plain property assignments are supported in router .timeout(...) metadata.',
371
+ 'Use .timeout({ defaultMs: 5000 }).',
372
+ { phase }
373
+ )
374
+ );
375
+ continue;
376
+ }
377
+ const key = propertyNameTextForObject(sourceFile, prop.name, diagnostics, prop);
378
+ if (!allowed.has(key)) {
379
+ diagnostics.push(
380
+ diagnostic(
381
+ sourceFile,
382
+ prop.name,
383
+ 'PULSEWASM_TIMEOUT_OPTION_UNSUPPORTED',
384
+ `Unsupported router timeout option ${JSON.stringify(key)}.`,
385
+ 'Allowed timeout options: defaultMs, hardMs, effectDefaultMs, schedulerResolutionMs.',
386
+ { phase }
387
+ )
388
+ );
389
+ continue;
390
+ }
391
+ const valueExpr = unwrapExpression(prop.initializer);
392
+ if (!ts.isNumericLiteral(valueExpr)) {
393
+ diagnostics.push(
394
+ diagnostic(
395
+ sourceFile,
396
+ prop.initializer,
397
+ 'PULSEWASM_TIMEOUT_VALUE_UNSUPPORTED',
398
+ `Router timeout option ${key} must be a positive integer literal.`,
399
+ 'Use a numeric literal such as 5000.',
400
+ { phase }
401
+ )
402
+ );
403
+ continue;
404
+ }
405
+ const value = Number(valueExpr.text);
406
+ if (!Number.isFinite(value) || value <= 0 || Math.floor(value) !== value) {
407
+ diagnostics.push(
408
+ diagnostic(
409
+ sourceFile,
410
+ prop.initializer,
411
+ 'PULSEWASM_TIMEOUT_VALUE_INVALID',
412
+ `Router timeout option ${key} must be a positive integer number of milliseconds.`,
413
+ 'Use a positive integer such as 5000.',
414
+ { phase }
415
+ )
416
+ );
417
+ continue;
418
+ }
419
+ config[key] = value;
420
+ }
421
+ return config;
422
+ }
423
+
424
+ function parsePathLiteral(sourceFile, node, diagnostics, usage, phase = 'extract') {
425
+ if (!isStringLiteralLike(node)) {
426
+ diagnostics.push(
427
+ diagnostic(
428
+ sourceFile,
429
+ node,
430
+ DIAGNOSTIC_CODES.DYNAMIC_PATH,
431
+ `Dynamic ${usage} paths are not supported in PulseWasm v1.`,
432
+ 'Use a string literal path such as "/compute/:id".',
433
+ { phase }
434
+ )
435
+ );
436
+ return nodeText(sourceFile, node);
437
+ }
438
+
439
+ const raw = literalText(node);
440
+ try {
441
+ const { normalized } = validatePath(raw, { allowWildcard: true });
442
+ return normalized;
443
+ } catch (error) {
444
+ diagnostics.push(
445
+ diagnostic(
446
+ sourceFile,
447
+ node,
448
+ DIAGNOSTIC_CODES.INVALID_PATH,
449
+ error.message,
450
+ 'Allowed grammar: literal segments, :param segments, and at most one trailing * segment.',
451
+ { phase }
452
+ )
453
+ );
454
+ return normalizeRoutePath(raw);
455
+ }
456
+ }
457
+
458
+ function parseEventTypeLiteral(sourceFile, node, diagnostics) {
459
+ if (!isStringLiteralLike(node)) {
460
+ diagnostics.push(diagnostic(
461
+ sourceFile,
462
+ node,
463
+ EVENTS.EVENT_DIAGNOSTIC_CODES.TYPE_INVALID,
464
+ 'Pulse.on event types must be direct string literals.',
465
+ 'Use app.on("namespace.event", { schema: "events.Payload" }, handler).',
466
+ { phase: 'extract' }
467
+ ));
468
+ return nodeText(sourceFile, node);
469
+ }
470
+ const value = literalText(node);
471
+ try {
472
+ return EVENTS.normalizeEventType(value);
473
+ } catch (error) {
474
+ diagnostics.push(diagnostic(
475
+ sourceFile,
476
+ node,
477
+ error.code || EVENTS.EVENT_DIAGNOSTIC_CODES.TYPE_INVALID,
478
+ error.message,
479
+ 'Use a non-empty event type within the canonical UTF-8 byte limit.',
480
+ { phase: 'extract' }
481
+ ));
482
+ return value;
483
+ }
484
+ }
485
+
486
+ function parseEventDeclarationLiteral(sourceFile, node, diagnostics) {
487
+ const expression = unwrapExpression(node);
488
+ let schema;
489
+ let valid = true;
490
+ if (!ts.isObjectLiteralExpression(expression) || expression.properties.length !== 1) {
491
+ valid = false;
492
+ } else {
493
+ const property = expression.properties[0];
494
+ const staticName = property && ts.isPropertyAssignment(property)
495
+ && (ts.isIdentifier(property.name) || isStringLiteralLike(property.name))
496
+ ? property.name.text
497
+ : undefined;
498
+ if (staticName !== 'schema') valid = false;
499
+ else {
500
+ const value = unwrapExpression(property.initializer);
501
+ if (value.kind === ts.SyntaxKind.NullKeyword) schema = null;
502
+ else if (isStringLiteralLike(value)) schema = literalText(value);
503
+ else valid = false;
504
+ }
505
+ }
506
+ if (!valid) {
507
+ diagnostics.push(diagnostic(
508
+ sourceFile,
509
+ node,
510
+ EVENTS.EVENT_DIAGNOSTIC_CODES.DECLARATION_INVALID,
511
+ 'Pulse.on declarations must be direct object literals containing exactly one literal schema field.',
512
+ 'Use { schema: "events.Payload" } or { schema: null } without spreads, computed keys, or aliases.',
513
+ { phase: 'extract' }
514
+ ));
515
+ return { version: EVENTS.EVENT_DECLARATION_VERSION, schemaId: undefined, unsupported: true };
516
+ }
517
+ try {
518
+ return EVENTS.normalizeEventDeclaration({ schema });
519
+ } catch (error) {
520
+ diagnostics.push(diagnostic(
521
+ sourceFile,
522
+ node,
523
+ error.code || EVENTS.EVENT_DIAGNOSTIC_CODES.DECLARATION_INVALID,
524
+ error.message,
525
+ 'Use a bounded dotted schema ID or explicit null.',
526
+ { phase: 'extract' }
527
+ ));
528
+ return { version: EVENTS.EVENT_DECLARATION_VERSION, schemaId: schema, unsupported: true };
529
+ }
530
+ }
531
+
532
+ function parseEventOperation(sourceFile, step, diagnostics) {
533
+ const { args, node, order, statementOrder } = step;
534
+ const loc = sourceLoc(sourceFile, node);
535
+ if (args.length !== 3) {
536
+ diagnostics.push(diagnostic(
537
+ sourceFile,
538
+ node,
539
+ 'PULSEWASM_EVENTS_SIGNATURE_UNSUPPORTED',
540
+ `Pulse.on() expects exactly 3 arguments, got ${args.length}.`,
541
+ 'Use app.on(type, { schema }, handler).',
542
+ { phase: 'extract' }
543
+ ));
544
+ return { kind: 'event', order, statementOrder, loc, unsupported: true };
545
+ }
546
+ return {
547
+ kind: 'event',
548
+ order,
549
+ statementOrder,
550
+ loc,
551
+ type: parseEventTypeLiteral(sourceFile, args[0], diagnostics),
552
+ declaration: parseEventDeclarationLiteral(sourceFile, args[1], diagnostics),
553
+ handler: parseHandlerRef(sourceFile, args[2], diagnostics, 'extract-event')
554
+ };
555
+ }
556
+
557
+ function isRouterNewExpression(init) {
558
+ return patternIsRouterNewExpression(ts, init, (_ts, node) => unwrapExpression(node));
559
+ }
560
+
561
+ function isDirectRouterDeclarationInitializer(node) {
562
+ return patternIsDirectRouterDeclarationInitializer(ts, node);
563
+ }
564
+
565
+ function indexSourceFile(sourceFile, options = {}) {
566
+ const cwd = options.cwd || process.cwd();
567
+ const diagnostics = [];
568
+ const routers = new Map();
569
+ const handlers = new Map();
570
+ let routerOrder = 0;
571
+ let handlerOrder = 0;
572
+
573
+ function addHandler(name, declarationNode, functionNode, kind) {
574
+ const sourceText = nodeText(sourceFile, functionNode || declarationNode);
575
+ const exportCarrier = declarationNode.parent && ts.isVariableStatement(declarationNode.parent)
576
+ ? declarationNode.parent
577
+ : declarationNode;
578
+ const exportName = isExportedNode(exportCarrier) ? name : undefined;
579
+ handlers.set(name, {
580
+ symbolId: name,
581
+ name,
582
+ localName: name,
583
+ exportName,
584
+ order: handlerOrder++,
585
+ kind,
586
+ file: stableFileName(sourceFile.fileName, cwd),
587
+ loc: sourceLoc(sourceFile, declarationNode),
588
+ functionLoc: sourceLoc(sourceFile, functionNode || declarationNode),
589
+ sourceTextHash: sourceTextHash(sourceText),
590
+ signature: describeFunctionSignature(sourceFile, functionNode || declarationNode)
591
+ });
592
+ }
593
+
594
+ ts.forEachChild(sourceFile, (statement) => {
595
+ if (ts.isFunctionDeclaration(statement) && statement.name) {
596
+ addHandler(statement.name.text, statement, statement, 'function-declaration');
597
+ return;
598
+ }
599
+
600
+ if (!ts.isVariableStatement(statement)) return;
601
+ for (const declaration of statement.declarationList.declarations) {
602
+ if (!ts.isIdentifier(declaration.name)) continue;
603
+ const name = declaration.name.text;
604
+ const init = declaration.initializer;
605
+ if (!init) continue;
606
+ if (isRouterNewExpression(init)) {
607
+ const construction = unwrapExpression(init);
608
+ routers.set(name, {
609
+ name,
610
+ order: routerOrder++,
611
+ applicationKind: construction && ts.isNewExpression(construction) && ts.isIdentifier(construction.expression) && construction.expression.text === 'Pulse' ? 'pulse' : 'router',
612
+ file: stableFileName(sourceFile.fileName, cwd),
613
+ initLoc: sourceLoc(sourceFile, declaration)
614
+ });
615
+ continue;
616
+ }
617
+ if (ts.isArrowFunction(init) || ts.isFunctionExpression(init)) {
618
+ addHandler(name, declaration, init, declarationHandlerKind(init));
619
+ }
620
+ }
621
+ });
622
+
623
+ function walk(node) {
624
+ if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && ['Router', 'Pulse'].includes(node.expression.text) && !isDirectRouterDeclarationInitializer(node)) {
625
+ diagnostics.push(
626
+ diagnostic(
627
+ sourceFile,
628
+ node,
629
+ DIAGNOSTIC_CODES.UNSUPPORTED_ROUTER_CONSTRUCTION,
630
+ 'Router or Pulse construction must be assigned directly to a top-level application variable.',
631
+ 'Use `const app = new Pulse({ auto: true })` for the project root or `const child = new Router()` for mounted routers.',
632
+ { phase: 'index' }
633
+ )
634
+ );
635
+ }
636
+ ts.forEachChild(node, walk);
637
+ }
638
+ walk(sourceFile);
639
+
640
+ return {
641
+ routers,
642
+ handlers,
643
+ diagnostics,
644
+ artifact: {
645
+ version: 'pulsewasm.symbol-index.v1',
646
+ generatedBy: PACKAGE_VERSION,
647
+ source: stableFileName(sourceFile.fileName, cwd),
648
+ routers: Array.from(routers.values()),
649
+ handlers: Array.from(handlers.values())
650
+ }
651
+ };
652
+ }
653
+
654
+ function unwindCallChain(sourceFile, expr, diagnostics) {
655
+ return unwindRouterCallChain(ts, sourceFile, expr, diagnostics, diagnostic);
656
+ }
657
+
658
+ function parseRouterOperation(sourceFile, step, diagnostics, options = {}) {
659
+ const apiRegistry = options.apiRegistry || (options.routerApiDefinitions ? buildRouterApiRegistry(options.routerApiDefinitions) : DEFAULT_ROUTER_API_REGISTRY);
660
+ const { method, args, node, order, statementOrder } = step;
661
+ const loc = sourceLoc(sourceFile, node);
662
+ const definition = apiRegistry.get(method);
663
+
664
+ function base(kind) {
665
+ return { kind, order, statementOrder, loc };
666
+ }
667
+
668
+ function arityMatches() {
669
+ if (!definition) return false;
670
+ if (!definition.allowedArities.includes(args.length)) {
671
+ diagnostics.push(
672
+ diagnostic(
673
+ sourceFile,
674
+ node,
675
+ DIAGNOSTIC_CODES.ARITY,
676
+ `.${method}() expects ${arityDisplay(definition)} argument(s), got ${args.length}.`,
677
+ 'Use only the supported PulseWasm v1 route authoring subset.',
678
+ { phase: 'extract' }
679
+ )
680
+ );
681
+ return false;
682
+ }
683
+ return true;
684
+ }
685
+
686
+ if (method === 'on' && (options.applicationKind === 'pulse' || args.length === 3)) {
687
+ return parseEventOperation(sourceFile, step, diagnostics);
688
+ }
689
+
690
+ if (!definition) {
691
+ diagnostics.push(
692
+ diagnostic(
693
+ sourceFile,
694
+ step.nameNode,
695
+ DIAGNOSTIC_CODES.UNSUPPORTED_ROUTER_METHOD,
696
+ `Unsupported router method .${method}().`,
697
+ `Supported methods: ${apiRegistry.supportedMethodNames().map((name) => `.${name}()`).join(', ')}.`,
698
+ { phase: 'extract' }
699
+ )
700
+ );
701
+ return { ...base('unsupported'), method };
702
+ }
703
+
704
+ if (!arityMatches()) return { ...base('unsupported'), method };
705
+ const signature = signatureForArity(definition, args.length) || {};
706
+
707
+ if (definition.kind === 'route') {
708
+ return {
709
+ ...base(definition.opKind),
710
+ method: definition.method,
711
+ route: true,
712
+ path: parsePathLiteral(sourceFile, args[signature.pathArg], diagnostics, 'route'),
713
+ handler: parseHandlerRef(sourceFile, args[signature.handlerArg], diagnostics)
714
+ };
715
+ }
716
+
717
+ if (definition.kind === 'mount') {
718
+ const routerArg = args[signature.routerArg];
719
+ const unwrappedRouter = unwrapReferenceExpression(routerArg);
720
+ if (!ts.isIdentifier(unwrappedRouter.expression)) {
721
+ diagnostics.push(
722
+ diagnostic(
723
+ sourceFile,
724
+ routerArg,
725
+ DIAGNOSTIC_CODES.UNSUPPORTED_MOUNT_TARGET,
726
+ 'Mounted routers must be direct router variable references, optionally wrapped by parentheses, a cast, non-null assertion, or satisfies expression.',
727
+ 'Use app.mount("/prefix", childRouter).',
728
+ { phase: 'extract' }
729
+ )
730
+ );
731
+ }
732
+ return {
733
+ ...base(definition.opKind),
734
+ path: stripScopedWildcard(parsePathLiteral(sourceFile, args[signature.pathArg], diagnostics, 'mount')),
735
+ router: ts.isIdentifier(unwrappedRouter.expression) ? unwrappedRouter.expression.text : nodeText(sourceFile, routerArg),
736
+ ...(unwrappedRouter.wrappers.length > 0 ? { routerWrappers: unwrappedRouter.wrappers } : {})
737
+ };
738
+ }
739
+
740
+ if (definition.kind === 'middleware') {
741
+ const op = { ...base(definition.opKind) };
742
+ if (signature.pathArg !== undefined) {
743
+ op.path = stripScopedWildcard(parsePathLiteral(sourceFile, args[signature.pathArg], diagnostics, 'middleware'));
744
+ }
745
+ op.handler = parseHandlerRef(sourceFile, args[signature.handlerArg], diagnostics);
746
+ return op;
747
+ }
748
+
749
+ if (definition.kind === 'channel') {
750
+ return {
751
+ ...base(definition.opKind),
752
+ value: parseChannelRef(sourceFile, args[signature.valueArg], diagnostics)
753
+ };
754
+ }
755
+
756
+ if (definition.kind === 'lifecycle') {
757
+ const eventArg = args[signature.eventArg];
758
+ if (!isStringLiteralLike(eventArg) || !(definition.allowedEvents || []).includes(literalText(eventArg))) {
759
+ diagnostics.push(
760
+ diagnostic(
761
+ sourceFile,
762
+ eventArg,
763
+ DIAGNOSTIC_CODES.UNSUPPORTED_LIFECYCLE,
764
+ 'Only .on("connect", handler) and .on("disconnect", handler) are supported in PulseWasm v1.',
765
+ `Use a literal lifecycle event: ${(definition.allowedEvents || []).map((event) => JSON.stringify(event)).join(' or ')}.`,
766
+ { phase: 'extract' }
767
+ )
768
+ );
769
+ }
770
+ return {
771
+ ...base(definition.opKind),
772
+ event: isStringLiteralLike(eventArg) ? literalText(eventArg) : nodeText(sourceFile, eventArg),
773
+ handler: parseHandlerRef(sourceFile, args[signature.handlerArg], diagnostics)
774
+ };
775
+ }
776
+
777
+
778
+ if (definition.kind === 'timeout') {
779
+ return {
780
+ ...base(definition.opKind),
781
+ value: parseTimeoutLiteral(sourceFile, args[signature.valueArg], diagnostics)
782
+ };
783
+ }
784
+
785
+ if (definition.kind === 'error') {
786
+ return {
787
+ ...base(definition.opKind),
788
+ handler: parseHandlerRef(sourceFile, args[signature.handlerArg], diagnostics)
789
+ };
790
+ }
791
+
792
+ return { ...base('unsupported'), method };
793
+ }
794
+
795
+ function extractRouterOperations(sourceFile, routerMap, options = {}) {
796
+ const apiRegistry = options.apiRegistry || (options.routerApiDefinitions ? buildRouterApiRegistry(options.routerApiDefinitions) : DEFAULT_ROUTER_API_REGISTRY);
797
+ const diagnostics = [];
798
+ const opsByRouter = new Map();
799
+ for (const name of routerMap.keys()) opsByRouter.set(name, []);
800
+ const acceptedOutermostCalls = new Set();
801
+ const routerAliases = new Map();
802
+ let aliasesChanged = true;
803
+ while (aliasesChanged) {
804
+ aliasesChanged = false;
805
+ for (const statement of sourceFile.statements) {
806
+ if (!ts.isVariableStatement(statement)) continue;
807
+ for (const declaration of statement.declarationList.declarations) {
808
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue;
809
+ const value = unwrapExpression(declaration.initializer);
810
+ if (!ts.isIdentifier(value)) continue;
811
+ const target = routerMap.has(value.text) ? value.text : routerAliases.get(value.text);
812
+ if (target && !routerAliases.has(declaration.name.text)) {
813
+ routerAliases.set(declaration.name.text, target);
814
+ aliasesChanged = true;
815
+ }
816
+ }
817
+ }
818
+ }
819
+ let statementOrder = 0;
820
+ let operationOrder = 0;
821
+
822
+ for (const statement of sourceFile.statements) {
823
+ if (!ts.isExpressionStatement(statement)) continue;
824
+ const chain = unwindCallChain(sourceFile, statement.expression, diagnostics);
825
+ if (!chain || !routerMap.has(chain.root)) continue;
826
+ acceptedOutermostCalls.add(statement.expression);
827
+ const routerOps = opsByRouter.get(chain.root);
828
+ const router = routerMap.get(chain.root);
829
+ const currentStatementOrder = statementOrder++;
830
+ for (const step of chain.steps) {
831
+ routerOps.push(parseRouterOperation(sourceFile, { ...step, order: operationOrder++, statementOrder: currentStatementOrder }, diagnostics, {
832
+ apiRegistry,
833
+ applicationKind: router && router.applicationKind
834
+ }));
835
+ }
836
+ }
837
+
838
+ function walk(node) {
839
+ if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isIdentifier(node.left) && routerMap.has(node.left.text)) {
840
+ diagnostics.push(
841
+ diagnostic(
842
+ sourceFile,
843
+ node,
844
+ DIAGNOSTIC_CODES.ROUTER_REASSIGNMENT,
845
+ `Router variable "${node.left.text}" is reassigned. Reassigning router variables is unsupported in PulseWasm v1.`,
846
+ 'Declare each router once and register routes through direct chained calls.',
847
+ { phase: 'extract' }
848
+ )
849
+ );
850
+ }
851
+
852
+ if (ts.isCallExpression(node) && isOutermostCallInChain(ts, node)) {
853
+ const chain = unwindCallChain(sourceFile, node, []);
854
+ if (chain && routerMap.has(chain.root) && !acceptedOutermostCalls.has(node)) {
855
+ const eventRegistration = chain.steps.some((step) => step.method === 'on' && (routerMap.get(chain.root)?.applicationKind === 'pulse' || step.args.length === 3));
856
+ diagnostics.push(
857
+ diagnostic(
858
+ sourceFile,
859
+ node,
860
+ eventRegistration ? 'PULSEWASM_EVENTS_REGISTRATION_HIDDEN' : DIAGNOSTIC_CODES.DYNAMIC_ROUTE_REGISTRATION,
861
+ eventRegistration
862
+ ? 'Pulse event registrations must be visible as top-level expression statements on the application root.'
863
+ : 'Router registration calls must be top-level expression statements in PulseWasm v1.',
864
+ eventRegistration
865
+ ? 'Move Pulse.on declarations out of conditionals, loops, helper functions, and nested blocks.'
866
+ : 'Move route declarations out of conditionals, loops, helper functions, and nested blocks.',
867
+ { phase: 'extract' }
868
+ )
869
+ );
870
+ } else if (chain && routerAliases.has(chain.root) && chain.steps.some((step) => step.method === 'on' && step.args.length === 3)) {
871
+ diagnostics.push(diagnostic(
872
+ sourceFile,
873
+ node,
874
+ 'PULSEWASM_EVENTS_REGISTRATION_HIDDEN',
875
+ 'Pulse event registrations must use the directly declared application root identifier.',
876
+ 'Register the event with app.on(type, { schema }, handler) on the top-level Pulse root.',
877
+ { phase: 'extract' }
878
+ ));
879
+ }
880
+ }
881
+
882
+ if (ts.isVariableDeclaration(node) && node.initializer) {
883
+ const value = unwrapExpression(node.initializer);
884
+ if (ts.isPropertyAccessExpression(value)
885
+ && value.name.text === 'on'
886
+ && ts.isIdentifier(value.expression)
887
+ && (routerMap.has(value.expression.text) || routerAliases.has(value.expression.text))) {
888
+ diagnostics.push(diagnostic(
889
+ sourceFile,
890
+ node,
891
+ 'PULSEWASM_EVENTS_REGISTRATION_HIDDEN',
892
+ 'Pulse.on cannot be extracted, aliased, rebound, or invoked indirectly.',
893
+ 'Declare each event with a direct top-level app.on(type, { schema }, handler) call.',
894
+ { phase: 'extract' }
895
+ ));
896
+ }
897
+ }
898
+
899
+ ts.forEachChild(node, walk);
900
+ }
901
+ walk(sourceFile);
902
+
903
+ return {
904
+ opsByRouter,
905
+ diagnostics,
906
+ summary: {
907
+ routersWithOps: Array.from(opsByRouter.entries()).filter(([, ops]) => ops.length > 0).length,
908
+ operations: operationOrder,
909
+ statements: statementOrder
910
+ }
911
+ };
912
+ }
913
+
914
+ function buildRouterIR(sourceFile, options = {}) {
915
+ const cwd = options.cwd || process.cwd();
916
+ const index = indexSourceFile(sourceFile, options);
917
+ const extraction = extractRouterOperations(sourceFile, index.routers, options);
918
+
919
+ const routerIR = Array.from(index.routers.values()).map((router) => ({
920
+ name: router.name,
921
+ order: router.order,
922
+ file: router.file,
923
+ initLoc: router.initLoc,
924
+ ops: extraction.opsByRouter.get(router.name) || []
925
+ }));
926
+
927
+ const handlerIR = Array.from(index.handlers.values());
928
+ return {
929
+ source: stableFileName(sourceFile.fileName, cwd),
930
+ routerIR,
931
+ handlerIR,
932
+ symbolIndex: index.artifact,
933
+ diagnostics: [...index.diagnostics, ...extraction.diagnostics],
934
+ summary: {
935
+ routers: routerIR.length,
936
+ handlers: handlerIR.length,
937
+ operations: extraction.summary.operations,
938
+ routersWithOps: extraction.summary.routersWithOps,
939
+ statements: extraction.summary.statements
940
+ }
941
+ };
942
+ }
943
+
944
+ function validateIR(ir) {
945
+ const diagnostics = [...ir.diagnostics];
946
+ const routerNames = new Set(ir.routerIR.map((router) => router.name));
947
+
948
+ for (const router of ir.routerIR) {
949
+ for (const op of router.ops) {
950
+ if (op.kind === 'mount' && !routerNames.has(op.router)) {
951
+ diagnostics.push({
952
+ phase: 'validate',
953
+ code: 'PULSEWASM_UNKNOWN_MOUNT_TARGET',
954
+ message: `Router "${router.name}" mounts unknown router "${op.router}".`,
955
+ hint: 'Mounted routers must be declared as direct new Router() variables in the same source file.',
956
+ loc: op.loc
957
+ });
958
+ }
959
+ if (op.kind === 'unsupported') {
960
+ diagnostics.push({
961
+ phase: 'validate',
962
+ code: 'PULSEWASM_UNSUPPORTED_OPERATION',
963
+ message: `Unsupported router operation .${op.method || '<unknown>'}().`,
964
+ hint: 'Use only the supported PulseWasm v1 route authoring subset.',
965
+ loc: op.loc
966
+ });
967
+ }
968
+ }
969
+ }
970
+
971
+ return diagnostics;
972
+ }
973
+
974
+
975
+ function cloneIR(ir) {
976
+ return {
977
+ ...ir,
978
+ routerIR: (ir.routerIR || []).map((router) => ({
979
+ ...router,
980
+ ops: (router.ops || []).map((op) => ({ ...op }))
981
+ })),
982
+ handlerIR: [...(ir.handlerIR || [])],
983
+ diagnostics: [...(ir.diagnostics || [])],
984
+ summary: { ...(ir.summary || {}) }
985
+ };
986
+ }
987
+
988
+ function pathUsageForOp(op) {
989
+ if (!op || !op.path) return undefined;
990
+ if (op.route || ROUTE_METHODS.has(op.kind)) return 'route';
991
+ if (op.kind === 'mount') return 'mount';
992
+ if (op.kind === 'use') return 'middleware';
993
+ return undefined;
994
+ }
995
+
996
+ function normalizePathIR(ir, options = {}) {
997
+ const diagnostics = [];
998
+ const normalizedIR = cloneIR(ir);
999
+ let paths = 0;
1000
+ let scopedPaths = 0;
1001
+ let wildcardPaths = 0;
1002
+
1003
+ for (const router of normalizedIR.routerIR || []) {
1004
+ for (const op of router.ops || []) {
1005
+ const usage = pathUsageForOp(op);
1006
+ if (!usage) continue;
1007
+ paths += 1;
1008
+ const scoped = usage === 'mount' || usage === 'middleware';
1009
+ if (scoped) scopedPaths += 1;
1010
+ try {
1011
+ const compiled = compileRoutePath(op.path, {
1012
+ scoped,
1013
+ allowWildcard: true
1014
+ });
1015
+ if (compiled.wildcard) wildcardPaths += 1;
1016
+ op.pathPattern = publicPathPattern(compiled);
1017
+ op.pathGrammarVersion = PATH_GRAMMAR_VERSION;
1018
+ op.path = scoped ? stripScopedWildcard(compiled.normalized) : compiled.normalized;
1019
+ } catch (error) {
1020
+ diagnostics.push({
1021
+ pass: 'path-normalize',
1022
+ code: DIAGNOSTIC_CODES.INVALID_PATH,
1023
+ severity: 'error',
1024
+ message: error.message,
1025
+ hint: 'Allowed grammar: literal segments, :param segments, and at most one unnamed trailing * segment.',
1026
+ loc: op.loc
1027
+ });
1028
+ }
1029
+ }
1030
+ }
1031
+
1032
+ return {
1033
+ ir: normalizedIR,
1034
+ diagnostics,
1035
+ summary: {
1036
+ paths,
1037
+ scopedPaths,
1038
+ wildcardPaths,
1039
+ grammarVersion: PATH_GRAMMAR_VERSION
1040
+ }
1041
+ };
1042
+ }
1043
+
1044
+ function resolveRouterTreeFromIR(ir, rootName) {
1045
+ const routers = new Map(ir.routerIR.map((router) => [router.name, router]));
1046
+ const visiting = new Set();
1047
+ const visited = new Set();
1048
+
1049
+ function build(name, stack = []) {
1050
+ const router = routers.get(name);
1051
+ if (!router) {
1052
+ throw new ExtractionError({
1053
+ phase: 'resolve',
1054
+ code: 'PULSEWASM_UNKNOWN_ROOT_ROUTER',
1055
+ message: `Unknown root router "${name}".`,
1056
+ hint: `Available routers: ${Array.from(routers.keys()).join(', ') || '<none>'}`,
1057
+ loc: { file: '<route-extractor>' }
1058
+ });
1059
+ }
1060
+ if (visiting.has(name)) {
1061
+ throw new ExtractionError({
1062
+ phase: 'resolve',
1063
+ code: 'PULSEWASM_MOUNT_CYCLE',
1064
+ message: `Mount cycle detected: ${[...stack, name].join(' -> ')}.`,
1065
+ hint: 'PulseWasm v1 requires an acyclic router mount tree.',
1066
+ loc: router.initLoc
1067
+ });
1068
+ }
1069
+
1070
+ visiting.add(name);
1071
+ const children = [];
1072
+ for (const op of router.ops) {
1073
+ if (op.kind === 'mount') {
1074
+ children.push({
1075
+ order: op.order,
1076
+ mountPath: op.path,
1077
+ router: build(op.router, [...stack, name]),
1078
+ loc: op.loc
1079
+ });
1080
+ }
1081
+ }
1082
+ visiting.delete(name);
1083
+ visited.add(name);
1084
+
1085
+ return {
1086
+ name: router.name,
1087
+ order: router.order,
1088
+ file: router.file,
1089
+ initLoc: router.initLoc,
1090
+ ops: router.ops,
1091
+ children
1092
+ };
1093
+ }
1094
+
1095
+ const tree = build(rootName);
1096
+ return { tree, visitedRouters: Array.from(visited) };
1097
+ }
1098
+
1099
+ function resolveRouterTree(ir, rootName, options = {}) {
1100
+ const cwd = options.cwd || process.cwd();
1101
+ const resolved = resolveRouterTreeFromIR(ir, rootName);
1102
+ return {
1103
+ version: 'pulsewasm.router-tree.v1',
1104
+ generatedBy: PACKAGE_VERSION,
1105
+ source: ir.source,
1106
+ entryRouter: rootName,
1107
+ visitedRouters: resolved.visitedRouters,
1108
+ tree: normalizeArtifact(resolved.tree, cwd)
1109
+ };
1110
+ }
1111
+
1112
+ function cloneAccumulator(acc) {
1113
+ return {
1114
+ pathPrefix: acc.pathPrefix,
1115
+ middleware: [...acc.middleware],
1116
+ scopedMiddleware: [...acc.scopedMiddleware],
1117
+ errorHandlers: [...acc.errorHandlers],
1118
+ connectHandlers: [...acc.connectHandlers],
1119
+ disconnectHandlers: [...acc.disconnectHandlers],
1120
+ channel: acc.channel ? { ...acc.channel } : undefined
1121
+ };
1122
+ }
1123
+
1124
+ function flattenRouterTree(tree, options = {}) {
1125
+ const root = tree.tree || tree;
1126
+ const routes = [];
1127
+ const diagnostics = options.diagnostics || [];
1128
+ const routerByName = new Map();
1129
+
1130
+ function collect(node) {
1131
+ routerByName.set(node.name, node);
1132
+ for (const child of node.children || []) collect(child.router);
1133
+ }
1134
+ collect(root);
1135
+
1136
+ function scopedMiddlewareMatchesForRoute(absolutePath, acc) {
1137
+ const matches = [];
1138
+ for (const entry of acc.scopedMiddleware) {
1139
+ let details;
1140
+ try {
1141
+ details = scopedPathMatchDetails(absolutePath, entry.path);
1142
+ } catch (error) {
1143
+ diagnostics.push({
1144
+ pass: 'flatten',
1145
+ code: 'PULSEWASM_INVALID_SCOPED_MIDDLEWARE_PATH',
1146
+ severity: 'error',
1147
+ message: error.message,
1148
+ hint: 'Path-scoped middleware must use the same strict PulseWasm path grammar as routes.',
1149
+ loc: entry.loc
1150
+ });
1151
+ continue;
1152
+ }
1153
+
1154
+ for (const detail of details.diagnostics || []) {
1155
+ diagnostics.push({
1156
+ pass: 'flatten',
1157
+ code: detail.code,
1158
+ severity: 'error',
1159
+ message: detail.message,
1160
+ hint: detail.hint,
1161
+ loc: entry.loc
1162
+ });
1163
+ }
1164
+
1165
+ if (!details.matches) continue;
1166
+ const compiled = compileRoutePath(entry.path, { scoped: true, allowWildcard: true });
1167
+ matches.push({
1168
+ path: entry.path,
1169
+ pattern: publicPathPattern(compiled),
1170
+ captures: details.captures || [],
1171
+ handler: entry.handler,
1172
+ loc: entry.loc
1173
+ });
1174
+ }
1175
+ return matches;
1176
+ }
1177
+
1178
+ function emitRoute(op, acc, routerName) {
1179
+ const absolutePath = joinPaths(acc.pathPrefix, op.path);
1180
+ let compiled;
1181
+ try {
1182
+ compiled = compileRoutePath(absolutePath, { allowWildcard: true });
1183
+ } catch (error) {
1184
+ diagnostics.push({
1185
+ pass: 'flatten',
1186
+ code: 'PULSEWASM_INVALID_FLATTENED_PATH',
1187
+ severity: 'error',
1188
+ message: error.message,
1189
+ hint: 'Mounted route paths must flatten into the strict PulseWasm path grammar.',
1190
+ loc: op.loc
1191
+ });
1192
+ return;
1193
+ }
1194
+
1195
+ const scopedMatches = scopedMiddlewareMatchesForRoute(absolutePath, acc);
1196
+ const scopedRefs = scopedMatches.map((entry) => entry.handler);
1197
+ const allMiddlewareRefs = [...acc.middleware, ...scopedRefs].filter(Boolean);
1198
+ const params = compiled.params;
1199
+ const pathPattern = publicPathPattern(compiled);
1200
+ const method = op.method || op.kind.toUpperCase();
1201
+ const runtimeId = routes.length;
1202
+ const stableInput = buildRouteStableInput({
1203
+ method,
1204
+ path: absolutePath,
1205
+ params,
1206
+ middleware: allMiddlewareRefs,
1207
+ errorHandlers: acc.errorHandlers,
1208
+ connectHandlers: acc.connectHandlers,
1209
+ disconnectHandlers: acc.disconnectHandlers,
1210
+ handler: op.handler,
1211
+ channel: acc.channel
1212
+ });
1213
+ const plan = {
1214
+ id: runtimeId,
1215
+ runtimeId,
1216
+ stableId: createRouteStableId({
1217
+ method,
1218
+ path: absolutePath,
1219
+ params,
1220
+ middleware: allMiddlewareRefs,
1221
+ errorHandlers: acc.errorHandlers,
1222
+ connectHandlers: acc.connectHandlers,
1223
+ disconnectHandlers: acc.disconnectHandlers,
1224
+ handler: op.handler,
1225
+ channel: acc.channel
1226
+ }),
1227
+ stableInput,
1228
+ order: op.order,
1229
+ sourceRouter: routerName,
1230
+ method,
1231
+ path: absolutePath,
1232
+ pathPattern,
1233
+ params,
1234
+ scopedMiddleware: scopedMatches.map((entry) => ({
1235
+ path: entry.path,
1236
+ pattern: entry.pattern,
1237
+ captures: entry.captures,
1238
+ handler: refToString(entry.handler),
1239
+ handlerName: refToName(entry.handler),
1240
+ loc: entry.loc
1241
+ })),
1242
+ middleware: allMiddlewareRefs.map(refToString).filter(Boolean),
1243
+ middlewareNames: allMiddlewareRefs.map(refToName).filter(Boolean),
1244
+ errorHandlers: acc.errorHandlers.map(refToString).filter(Boolean),
1245
+ errorHandlerNames: acc.errorHandlers.map(refToName).filter(Boolean),
1246
+ connectHandlers: acc.connectHandlers.map(refToString).filter(Boolean),
1247
+ connectHandlerNames: acc.connectHandlers.map(refToName).filter(Boolean),
1248
+ disconnectHandlers: acc.disconnectHandlers.map(refToString).filter(Boolean),
1249
+ disconnectHandlerNames: acc.disconnectHandlers.map(refToName).filter(Boolean),
1250
+ handler: refToString(op.handler),
1251
+ handlerName: refToName(op.handler),
1252
+ loc: op.loc
1253
+ };
1254
+ if (acc.channel) {
1255
+ plan.channel = acc.channel.kind === 'handler'
1256
+ ? { kind: 'handler', value: acc.channel.id, name: acc.channel.name }
1257
+ : { kind: acc.channel.kind, value: acc.channel.value };
1258
+ }
1259
+ routes.push(plan);
1260
+ }
1261
+
1262
+ function walk(node, incomingAcc) {
1263
+ const acc = cloneAccumulator(incomingAcc);
1264
+
1265
+ for (const op of node.ops || []) {
1266
+ switch (op.kind) {
1267
+ case 'use': {
1268
+ if (op.path) {
1269
+ acc.scopedMiddleware.push({
1270
+ path: joinScopedPrefix(acc.pathPrefix, op.path),
1271
+ handler: op.handler,
1272
+ loc: op.loc
1273
+ });
1274
+ } else {
1275
+ acc.middleware.push(op.handler);
1276
+ }
1277
+ break;
1278
+ }
1279
+ case 'error': {
1280
+ acc.errorHandlers.push(op.handler);
1281
+ break;
1282
+ }
1283
+ case 'lifecycle': {
1284
+ if (op.event === 'connect') acc.connectHandlers.push(op.handler);
1285
+ else if (op.event === 'disconnect') acc.disconnectHandlers.push(op.handler);
1286
+ break;
1287
+ }
1288
+ case 'channel': {
1289
+ acc.channel = op.value;
1290
+ break;
1291
+ }
1292
+ case 'get':
1293
+ case 'post': {
1294
+ emitRoute(op, acc, node.name);
1295
+ break;
1296
+ }
1297
+ case 'mount': {
1298
+ const child = routerByName.get(op.router);
1299
+ if (!child) break;
1300
+ const childAcc = cloneAccumulator(acc);
1301
+ childAcc.pathPrefix = joinScopedPrefix(acc.pathPrefix, op.path);
1302
+ walk(child, childAcc);
1303
+ break;
1304
+ }
1305
+ default:
1306
+ if (op.route || ROUTE_METHODS.has(op.kind)) {
1307
+ emitRoute(op, acc, node.name);
1308
+ }
1309
+ break;
1310
+ }
1311
+ }
1312
+ }
1313
+
1314
+ walk(root, {
1315
+ pathPrefix: '/',
1316
+ middleware: [],
1317
+ scopedMiddleware: [],
1318
+ errorHandlers: [],
1319
+ connectHandlers: [],
1320
+ disconnectHandlers: [],
1321
+ channel: undefined
1322
+ });
1323
+
1324
+ return routes;
1325
+ }
1326
+
1327
+ function createRoutePlanResult(ir, routerTreeArtifact, rootName, sourceFile, options = {}) {
1328
+ const cwd = options.cwd || process.cwd();
1329
+ const diagnostics = [];
1330
+ const routes = flattenRouterTree(routerTreeArtifact, { ...options, diagnostics });
1331
+ const routePlan = normalizeArtifact(
1332
+ {
1333
+ version: ROUTE_PLAN_VERSION,
1334
+ generatedBy: PACKAGE_VERSION,
1335
+ source: stableFileName(sourceFile.fileName, cwd),
1336
+ entryRouter: rootName,
1337
+ pathPolicy: PATH_POLICY,
1338
+ idPolicy: ROUTE_ID_POLICY,
1339
+ routes
1340
+ },
1341
+ cwd
1342
+ );
1343
+ return { routePlan, diagnostics };
1344
+ }
1345
+
1346
+ function createRoutePlan(ir, routerTreeArtifact, rootName, sourceFile, options = {}) {
1347
+ return createRoutePlanResult(ir, routerTreeArtifact, rootName, sourceFile, options).routePlan;
1348
+ }
1349
+
1350
+ function extractionSummary({ sourceFile, ir, routerTree, routePlan, handlerTable, handlerEval, dispatchTable, executionPlan, handlerBindings, executionHarness, localHarness, assemblyScriptShape, assemblyScriptCore, assemblyScriptCompile, assemblyScriptWasmSmoke, wasmHostAbi, wasmHostBridge, requestResultHeaders, channelBroadcaster, jsonBody, backendCapabilities, deploymentPosture, hostRuntimeKernel, nodeAdapter, streamingPassthrough, handlerLibraryContracts, assetsLoweringPlan, assetsSidecarCompileLinkProof, assetsCompiledWasmSidecarPlan, nodeAssetsProviderProof, nodeCompiledWasmAssetsLifecycleProof, fastlyAssetsProviderProof, fastlyAssetsPackageOutParityProof, routeHandlerEffectPlan, nodeRouteHandlerEffectProof, fastlyRouteHandlerEffectProof, fastlyLifecycleParityProof, routeHandlerContextLoweringPlan, handlerIoLifecyclePlan, requestJsonBodyPlan, schemaDecodeResultPlan, schemaResponseCodecPlan, backendJsonRequestBodyPlan, nodeRequestJsonBodyProof, nodeSchemaDecodeResultProof, nodeSchemaResponseCodecProof, hostCapabilities, effectRuntime, effectComposition, compiledHandlers, schemaJsonCompile, schemaJsonGenericParser, schemaJsonSidecar, librarySidecars, integratedCompiledApp, compiledWasmRuntime, pulseWrapper, fastlyReadiness, fastlyHostcallBinding, fastlyAdapter, fastlyCommandEntry, dispatchTs, includeAst, cwd }) {
1351
+ return {
1352
+ source: stableFileName(sourceFile.fileName, cwd || process.cwd()),
1353
+ routers: ir.routerIR.length,
1354
+ handlerDeclarations: ir.handlerIR.length,
1355
+ handlers: handlerTable ? handlerTable.handlers.length : ir.handlerIR.length,
1356
+ handlerEval: handlerEval ? handlerEval.summary : undefined,
1357
+ operations: ir.summary.operations,
1358
+ visitedRouters: routerTree.visitedRouters.length,
1359
+ routes: routePlan.routes.length,
1360
+ dispatch: dispatchTable ? dispatchTable.summary : undefined,
1361
+ executionPlan: executionPlan ? executionPlan.summary : undefined,
1362
+ handlerBindings: handlerBindings ? handlerBindings.artifact.summary : undefined,
1363
+ executionHarness: executionHarness ? executionHarness.artifact.summary : undefined,
1364
+ localHarness: localHarness ? localHarness.artifact.summary : undefined,
1365
+ assemblyScriptShape: assemblyScriptShape ? assemblyScriptShape.artifact.summary : undefined,
1366
+ assemblyScriptCore: assemblyScriptCore ? assemblyScriptCore.artifact.summary : undefined,
1367
+ assemblyScriptCompile: assemblyScriptCompile ? assemblyScriptCompile.artifact.summary : undefined,
1368
+ assemblyScriptWasmSmoke: assemblyScriptWasmSmoke ? assemblyScriptWasmSmoke.artifact.summary : undefined,
1369
+ wasmHostAbi: wasmHostAbi ? wasmHostAbi.artifact.summary : undefined,
1370
+ wasmHostBridge: wasmHostBridge ? wasmHostBridge.artifact.summary : undefined,
1371
+ requestResultHeaders: requestResultHeaders ? requestResultHeaders.artifact.summary : undefined,
1372
+ channelBroadcaster: channelBroadcaster ? channelBroadcaster.artifact.summary : undefined,
1373
+ jsonBody: jsonBody ? jsonBody.artifact.summary : undefined,
1374
+ backendCapabilities: backendCapabilities ? backendCapabilities.artifact.summary : undefined,
1375
+ deploymentPosture: deploymentPosture ? deploymentPosture.artifact.summary : undefined,
1376
+ hostRuntimeKernel: hostRuntimeKernel ? hostRuntimeKernel.artifact.summary : undefined,
1377
+ nodeAdapter: nodeAdapter ? nodeAdapter.artifact.summary : undefined,
1378
+ streamingPassthrough: streamingPassthrough ? streamingPassthrough.artifact.summary : undefined,
1379
+ handlerLibraryContracts: handlerLibraryContracts ? handlerLibraryContracts.artifact.summary : undefined,
1380
+ assetsLoweringPlan: assetsLoweringPlan ? assetsLoweringPlan.artifact.summary : undefined,
1381
+ assetsCompiledWasmSidecarPlan: assetsCompiledWasmSidecarPlan ? assetsCompiledWasmSidecarPlan.artifact.summary : undefined,
1382
+ assetsSidecarCompileLinkProof: assetsSidecarCompileLinkProof ? assetsSidecarCompileLinkProof.artifact.summary : undefined,
1383
+ nodeAssetsProviderProof: nodeAssetsProviderProof ? nodeAssetsProviderProof.artifact.summary : undefined,
1384
+ nodeCompiledWasmAssetsLifecycleProof: nodeCompiledWasmAssetsLifecycleProof ? nodeCompiledWasmAssetsLifecycleProof.artifact.summary : undefined,
1385
+ fastlyAssetsProviderProof: fastlyAssetsProviderProof ? fastlyAssetsProviderProof.artifact.summary : undefined,
1386
+ fastlyAssetsPackageOutParityProof: fastlyAssetsPackageOutParityProof ? fastlyAssetsPackageOutParityProof.artifact.summary : undefined,
1387
+ routeHandlerEffectPlan: routeHandlerEffectPlan ? routeHandlerEffectPlan.artifact.summary : undefined,
1388
+ nodeRouteHandlerEffectProof: nodeRouteHandlerEffectProof ? nodeRouteHandlerEffectProof.artifact.summary : undefined,
1389
+ fastlyRouteHandlerEffectProof: fastlyRouteHandlerEffectProof ? fastlyRouteHandlerEffectProof.artifact.summary : undefined,
1390
+ fastlyLifecycleParityProof: fastlyLifecycleParityProof ? fastlyLifecycleParityProof.artifact.summary : undefined,
1391
+ routeHandlerContextLoweringPlan: routeHandlerContextLoweringPlan ? routeHandlerContextLoweringPlan.artifact.summary : undefined,
1392
+ handlerIoLifecyclePlan: handlerIoLifecyclePlan ? handlerIoLifecyclePlan.artifact.summary : undefined,
1393
+ requestJsonBodyPlan: requestJsonBodyPlan ? requestJsonBodyPlan.artifact.summary : undefined,
1394
+ nodeRequestJsonBodyProof: nodeRequestJsonBodyProof ? nodeRequestJsonBodyProof.artifact.summary : undefined,
1395
+ schemaDecodeResultPlan: schemaDecodeResultPlan ? schemaDecodeResultPlan.artifact.summary : undefined,
1396
+ schemaResponseCodecPlan: schemaResponseCodecPlan ? schemaResponseCodecPlan.artifact.summary : undefined,
1397
+ backendJsonRequestBodyPlan: backendJsonRequestBodyPlan ? backendJsonRequestBodyPlan.artifact.summary : undefined,
1398
+ nodeSchemaDecodeResultProof: nodeSchemaDecodeResultProof ? nodeSchemaDecodeResultProof.artifact.summary : undefined,
1399
+ nodeSchemaResponseCodecProof: nodeSchemaResponseCodecProof ? nodeSchemaResponseCodecProof.artifact.summary : undefined,
1400
+ hostCapabilities: hostCapabilities ? hostCapabilities.artifact.summary : undefined,
1401
+ effectRuntime: effectRuntime ? effectRuntime.artifact.summary : undefined,
1402
+ effectComposition: effectComposition ? effectComposition.artifact.summary : undefined,
1403
+ compiledHandlers: compiledHandlers ? compiledHandlers.artifact.summary : undefined,
1404
+ schemaJsonCompile: schemaJsonCompile ? schemaJsonCompile.artifact.summary : undefined,
1405
+ schemaJsonGenericParser: schemaJsonGenericParser ? schemaJsonGenericParser.artifact.summary : undefined,
1406
+ schemaJsonSidecar: schemaJsonSidecar ? schemaJsonSidecar.artifact.summary : undefined,
1407
+ librarySidecars: librarySidecars ? librarySidecars.artifact.summary : undefined,
1408
+ integratedCompiledApp: integratedCompiledApp ? integratedCompiledApp.artifact.summary : undefined,
1409
+ compiledWasmRuntime: compiledWasmRuntime ? compiledWasmRuntime.artifact.summary : undefined,
1410
+ pulseWrapper: pulseWrapper ? pulseWrapper.artifact.summary : undefined,
1411
+ fastlyReadiness: fastlyReadiness ? fastlyReadiness.artifact.summary : undefined,
1412
+ fastlyHostcallBinding: fastlyHostcallBinding ? fastlyHostcallBinding.artifact.summary : undefined,
1413
+ fastlyAdapter: fastlyAdapter ? fastlyAdapter.artifact.summary : undefined,
1414
+ fastlyCommandEntry: fastlyCommandEntry ? fastlyCommandEntry.artifact.summary : undefined,
1415
+ dispatchTs: dispatchTs ? dispatchTs.manifest.summary : undefined,
1416
+ astIncluded: Boolean(includeAst)
1417
+ };
1418
+ }
1419
+
1420
+ function makePass(name, status, summary = {}) {
1421
+ return { name, status, summary };
1422
+ }
1423
+
1424
+ function lowerableFacadeAllowances(manifestRecords = []) {
1425
+ const allowedImports = [];
1426
+ const allowedImportCalls = [];
1427
+ const allowedImportMemberCalls = [];
1428
+ for (const record of manifestRecords || []) {
1429
+ const manifest = record && record.manifest ? record.manifest : record;
1430
+ if (!manifest || !manifest.lowerableSubpath) continue;
1431
+ allowedImports.push(manifest.lowerableSubpath);
1432
+ const facade = manifest.facade || {};
1433
+ const namespace = facade.namespace || manifest.namespace;
1434
+ for (const symbol of facade.symbols || []) {
1435
+ allowedImportCalls.push(`${manifest.lowerableSubpath}:${symbol}`);
1436
+ if (namespace) allowedImportMemberCalls.push(`${manifest.lowerableSubpath}:${namespace}.${symbol}`);
1437
+ allowedImportMemberCalls.push(`${manifest.lowerableSubpath}:default.${symbol}`);
1438
+ }
1439
+ }
1440
+ return { allowedImports, allowedImportCalls, allowedImportMemberCalls };
1441
+ }
1442
+
1443
+ function extractFromSourceFile(sourceFile, options = {}) {
1444
+ options = { ...options };
1445
+ const providerProofs = options.providerProofs && typeof options.providerProofs === 'object'
1446
+ ? options.providerProofs
1447
+ : Object.freeze({});
1448
+ function providerProof(name) {
1449
+ const proof = providerProofs[name];
1450
+ if (typeof proof !== 'function') {
1451
+ throw new TypeError(`Pulse legacy provider proof ${name} requires an explicit CLI/testing composition root.`);
1452
+ }
1453
+ return proof;
1454
+ }
1455
+ const buildNodeAdapter = (...args) => providerProof('buildNodeAdapter')(...args);
1456
+ const buildNodeAssetsProviderProof = (...args) => providerProof('buildNodeAssetsProviderProof')(...args);
1457
+ const buildNodeCompiledWasmAssetsLifecycleProof = (...args) => providerProof('buildNodeCompiledWasmAssetsLifecycleProof')(...args);
1458
+ const buildNodeRouteHandlerEffectProof = (...args) => providerProof('buildNodeRouteHandlerEffectProof')(...args);
1459
+ const buildNodeRequestJsonBodyProof = (...args) => providerProof('buildNodeRequestJsonBodyProof')(...args);
1460
+ const buildNodeSchemaDecodeResultProof = (...args) => providerProof('buildNodeSchemaDecodeResultProof')(...args);
1461
+ const buildNodeSchemaResponseCodecProof = (...args) => providerProof('buildNodeSchemaResponseCodecProof')(...args);
1462
+ const buildFastlyReadiness = (...args) => providerProof('buildFastlyReadiness')(...args);
1463
+ const buildFastlyHostcallBinding = (...args) => providerProof('buildFastlyHostcallBinding')(...args);
1464
+ const buildFastlyStreamHeaderAdapter = (...args) => providerProof('buildFastlyStreamHeaderAdapter')(...args);
1465
+ const buildFastlyCommandEntry = (...args) => providerProof('buildFastlyCommandEntry')(...args);
1466
+ const buildFastlyAssetsProviderProof = (...args) => providerProof('buildFastlyAssetsProviderProof')(...args);
1467
+ const buildFastlyAssetsPackageOutParityProof = (...args) => providerProof('buildFastlyAssetsPackageOutParityProof')(...args);
1468
+ const buildFastlyRouteHandlerEffectProof = (...args) => providerProof('buildFastlyRouteHandlerEffectProof')(...args);
1469
+ const buildFastlyLifecycleParityProof = (...args) => providerProof('buildFastlyLifecycleParityProof')(...args);
1470
+ if (options.emitStreamingPassthrough) {
1471
+ options.emitNodeAdapter = true;
1472
+ options.emitHostRuntimeKernel = true;
1473
+ options.emitWasmHostBridge = true;
1474
+ options.emitWasmHostAbi = true;
1475
+ options.emitRequestResultHeaders = true;
1476
+ }
1477
+ if (options.emitCompiledHandlers) {
1478
+ options.emitAssemblyScriptCore = true;
1479
+ options.emitAssemblyScriptShape = true;
1480
+ options.emitRouteHandlerContextLoweringPlan = true;
1481
+ }
1482
+ if (options.emitLibrarySidecars) {
1483
+ options.emitHandlerLibraryContracts = true;
1484
+ }
1485
+ if (options.emitNodeAssetsProviderProof) {
1486
+ options.emitAssetsLoweringPlan = true;
1487
+ }
1488
+ if (options.emitNodeRouteHandlerEffectProof) {
1489
+ options.emitRouteHandlerEffectPlan = true;
1490
+ options.emitRouteHandlerContextLoweringPlan = true;
1491
+ options.emitEffectComposition = true;
1492
+ options.emitEffectRuntime = true;
1493
+ }
1494
+ if (options.emitFastlyRouteHandlerEffectProof) {
1495
+ options.emitRouteHandlerEffectPlan = true;
1496
+ options.emitRouteHandlerContextLoweringPlan = true;
1497
+ options.emitEffectComposition = true;
1498
+ options.emitEffectRuntime = true;
1499
+ }
1500
+ if (options.emitFastlyLifecycleParityProof) {
1501
+ options.emitRouteHandlerEffectPlan = true;
1502
+ options.emitRouteHandlerContextLoweringPlan = true;
1503
+ options.emitHandlerIoLifecyclePlan = true;
1504
+ options.emitBackendJsonRequestBodyPlan = true;
1505
+ options.emitEffectComposition = true;
1506
+ options.emitEffectRuntime = true;
1507
+ }
1508
+ if (options.emitFastlyAssetsProviderProof) {
1509
+ options.emitAssetsLoweringPlan = true;
1510
+ }
1511
+ if (options.emitAssetsLoweringPlan) {
1512
+ options.emitHandlerLibraryContracts = true;
1513
+ }
1514
+ if (options.emitSchemaJsonSidecar) {
1515
+ options.emitJsonBody = true;
1516
+ options.emitWasmHostAbi = true;
1517
+ }
1518
+ if (options.emitBackendJsonRequestBodyPlan) {
1519
+ options.emitRouteHandlerEffectPlan = true;
1520
+ options.emitRequestJsonBodyPlan = true;
1521
+ options.emitSchemaResponseCodecPlan = true;
1522
+ }
1523
+ if (options.emitNodeBackendJsonRequestBodyProof) {
1524
+ options.emitBackendJsonRequestBodyPlan = true;
1525
+ }
1526
+ if (options.emitHandlerIoLifecyclePlan) {
1527
+ options.emitRouteHandlerContextLoweringPlan = true;
1528
+ options.emitRouteHandlerEffectPlan = true;
1529
+ }
1530
+
1531
+ if (options.emitRouteHandlerEffectPlan) {
1532
+ options.emitEffectComposition = true;
1533
+ options.emitEffectRuntime = true;
1534
+ }
1535
+ if (options.emitEffectComposition) {
1536
+ options.emitEffectRuntime = true;
1537
+ }
1538
+ if (options.emitFastlyAdapter) {
1539
+ options.emitFastlyHostcallBinding = true;
1540
+ }
1541
+ if (options.emitFastlyHostcallBinding) {
1542
+ options.emitFastlyReadiness = true;
1543
+ }
1544
+ if (options.emitFastlyReadiness) {
1545
+ options.emitPulseWrapper = true;
1546
+ options.emitHostCapabilities = true;
1547
+ options.emitEffectComposition = true;
1548
+ options.emitEffectRuntime = true;
1549
+ options.emitBackendCapabilities = true;
1550
+ }
1551
+
1552
+ if (options.emitPulseWrapper) {
1553
+ options.emitCompiledWasmRuntime = true;
1554
+ }
1555
+
1556
+ if (options.emitEffectRuntime) {
1557
+ options.emitHostCapabilities = true;
1558
+ }
1559
+
1560
+ if (options.emitHostCapabilities) {
1561
+ options.emitHandlerLibraryContracts = true;
1562
+ }
1563
+
1564
+ if (options.emitNodeAdapter) {
1565
+ options.emitHostRuntimeKernel = true;
1566
+ }
1567
+
1568
+ if (options.emitHostRuntimeKernel) {
1569
+ options.emitWasmHostBridge = true;
1570
+ options.emitWasmHostAbi = true;
1571
+ options.emitAssemblyScriptCore = true;
1572
+ options.emitAssemblyScriptShape = true;
1573
+ options.emitJsonBody = true;
1574
+ options.emitRequestResultHeaders = true;
1575
+ options.emitChannelBroadcaster = true;
1576
+ options.emitBackendCapabilities = true;
1577
+ }
1578
+
1579
+ if (options.emitJsonBody) {
1580
+ options.emitRequestResultHeaders = true;
1581
+ options.emitWasmHostAbi = true;
1582
+ }
1583
+
1584
+ if (options.emitChannelBroadcaster) {
1585
+ options.emitRequestResultHeaders = true;
1586
+ options.emitWasmHostAbi = true;
1587
+ }
1588
+
1589
+ if (options.emitRequestResultHeaders) {
1590
+ options.emitWasmHostAbi = true;
1591
+ }
1592
+
1593
+ if (options.emitWasmHostBridge) {
1594
+ options.emitWasmHostAbi = true;
1595
+ options.emitAssemblyScriptCore = true;
1596
+ options.emitAssemblyScriptShape = true;
1597
+ }
1598
+
1599
+ if (options.emitWasmSmoke) {
1600
+ options.emitAssemblyScriptCompile = true;
1601
+ options.emitAssemblyScriptCore = true;
1602
+ options.emitAssemblyScriptShape = true;
1603
+ }
1604
+
1605
+ if (options.emitAssemblyScriptCompile) {
1606
+ options.emitAssemblyScriptCore = true;
1607
+ options.emitAssemblyScriptShape = true;
1608
+ }
1609
+
1610
+ if (options.emitLocalHarness) {
1611
+ options.emitExecutionHarness = true;
1612
+ options.emitHandlerBindings = true;
1613
+ options.emitDispatchTs = true;
1614
+ options.emitAssemblyScriptCore = true;
1615
+ options.emitAssemblyScriptShape = true;
1616
+ }
1617
+ const cwd = options.cwd || process.cwd();
1618
+ const passes = [];
1619
+ const source = sourceFile.fileName;
1620
+
1621
+ const parseDiags = parseDiagnostics(sourceFile);
1622
+ passes.push(makePass('parse', parseDiags.length === 0 ? 'ok' : 'error', { diagnostics: parseDiags.length }));
1623
+ if (parseDiags.length > 0) {
1624
+ throw new ExtractionError(parseDiags, { passes, source });
1625
+ }
1626
+
1627
+ const ir = buildRouterIR(sourceFile, options);
1628
+ const indexDiagnostics = ir.diagnostics.filter((diag) => (diag.phase || diag.pass) === 'index');
1629
+ const extractDiagnostics = ir.diagnostics.filter((diag) => (diag.phase || diag.pass) !== 'index');
1630
+ passes.push(makePass('index', indexDiagnostics.length === 0 ? 'ok' : 'error', {
1631
+ routers: ir.routerIR.length,
1632
+ handlers: ir.handlerIR.length,
1633
+ diagnostics: indexDiagnostics.length
1634
+ }));
1635
+ passes.push(makePass('extract', extractDiagnostics.length === 0 ? 'ok' : 'error', {
1636
+ operations: ir.summary.operations,
1637
+ routersWithOps: ir.summary.routersWithOps,
1638
+ diagnostics: extractDiagnostics.length
1639
+ }));
1640
+
1641
+ const validationDiagnostics = validateIR(ir);
1642
+ passes.push(makePass('validate', validationDiagnostics.length === 0 ? 'ok' : 'error', { diagnostics: validationDiagnostics.length }));
1643
+ if (validationDiagnostics.length > 0) {
1644
+ throw new ExtractionError(validationDiagnostics, { passes, source, summary: ir.summary });
1645
+ }
1646
+
1647
+ const pathNormalization = normalizePathIR(ir, { cwd });
1648
+ passes.push(makePass('path-normalize', pathNormalization.diagnostics.length === 0 ? 'ok' : 'error', {
1649
+ ...pathNormalization.summary,
1650
+ diagnostics: pathNormalization.diagnostics.length
1651
+ }));
1652
+ if (pathNormalization.diagnostics.length > 0) {
1653
+ throw new ExtractionError(pathNormalization.diagnostics, { passes, source, summary: ir.summary });
1654
+ }
1655
+ const normalizedIR = pathNormalization.ir;
1656
+
1657
+ const handlerResolution = buildHandlerTable(normalizedIR, { cwd });
1658
+ passes.push(makePass('handler-table', handlerResolution.diagnostics.length === 0 ? 'ok' : 'error', {
1659
+ handlers: handlerResolution.handlerTable.handlers.length,
1660
+ diagnostics: handlerResolution.diagnostics.length
1661
+ }));
1662
+ if (handlerResolution.diagnostics.length > 0) {
1663
+ throw new ExtractionError(handlerResolution.diagnostics, { passes, source, summary: ir.summary });
1664
+ }
1665
+ const resolvedIR = handlerResolution.resolvedIR;
1666
+
1667
+ const lowerableManifestRecords = options.emitAssetsLoweringPlan
1668
+ ? discoverLowerableLibraryManifests({ cwd, workspaceRoot: options.workspaceRoot })
1669
+ : [];
1670
+ const handlerEvaluationAllowances = lowerableFacadeAllowances(lowerableManifestRecords);
1671
+ const handlerEvaluation = buildHandlerEval(sourceFile, handlerResolution.handlerTable, {
1672
+ cwd,
1673
+ allowedImports: handlerEvaluationAllowances.allowedImports,
1674
+ allowedImportCalls: handlerEvaluationAllowances.allowedImportCalls,
1675
+ allowedImportMemberCalls: handlerEvaluationAllowances.allowedImportMemberCalls
1676
+ });
1677
+ passes.push(makePass('handler-eval', handlerEvaluation.diagnostics.length === 0 ? 'ok' : 'error', {
1678
+ handlers: handlerEvaluation.handlerEval.handlers.length,
1679
+ dependencies: handlerEvaluation.handlerEval.summary.dependencies,
1680
+ diagnostics: handlerEvaluation.diagnostics.length
1681
+ }));
1682
+ if (handlerEvaluation.diagnostics.length > 0) {
1683
+ throw new ExtractionError(handlerEvaluation.diagnostics, { passes, source, summary: ir.summary });
1684
+ }
1685
+
1686
+ const rootName = options.root || (resolvedIR.routerIR[0] && resolvedIR.routerIR[0].name);
1687
+ if (!rootName) {
1688
+ const diagnostics = [{
1689
+ phase: 'resolve',
1690
+ code: 'PULSEWASM_NO_ROUTER',
1691
+ message: 'No direct `new Router()` declaration was found.',
1692
+ hint: 'Declare a router with `const app = new Router()`.',
1693
+ loc: { file: sourceFile.fileName }
1694
+ }];
1695
+ passes.push(makePass('resolve', 'error', { diagnostics: diagnostics.length }));
1696
+ throw new ExtractionError(diagnostics, { passes, source, summary: ir.summary });
1697
+ }
1698
+
1699
+ let routerTree;
1700
+ try {
1701
+ routerTree = resolveRouterTree(resolvedIR, rootName, options);
1702
+ passes.push(makePass('resolve', 'ok', {
1703
+ entryRouter: rootName,
1704
+ visitedRouters: routerTree.visitedRouters.length
1705
+ }));
1706
+ } catch (error) {
1707
+ if (error instanceof ExtractionError) {
1708
+ const diagnostics = error.diagnostics.map((diag) => ({ ...diag, phase: diag.phase || 'resolve' }));
1709
+ passes.push(makePass('resolve', 'error', { diagnostics: diagnostics.length }));
1710
+ throw new ExtractionError(diagnostics, { passes, source, summary: ir.summary });
1711
+ }
1712
+ throw error;
1713
+ }
1714
+
1715
+ const routePlanResult = createRoutePlanResult(resolvedIR, routerTree, rootName, sourceFile, options);
1716
+ const routePlan = routePlanResult.routePlan;
1717
+ passes.push(makePass('flatten', routePlanResult.diagnostics.length === 0 ? 'ok' : 'error', {
1718
+ routes: routePlan.routes.length,
1719
+ diagnostics: routePlanResult.diagnostics.length
1720
+ }));
1721
+ if (routePlanResult.diagnostics.length > 0) {
1722
+ throw new ExtractionError(routePlanResult.diagnostics, { passes, source, summary: ir.summary });
1723
+ }
1724
+ const routeIdMap = normalizeArtifact(createRouteIdMap(routePlan, { cwd, generatedBy: PACKAGE_VERSION }), cwd);
1725
+ const pathTable = buildPathTable(routePlan, { cwd, generatedBy: PACKAGE_VERSION });
1726
+ const dispatchResult = buildDispatchTable(routePlan, handlerResolution.handlerTable, handlerEvaluation.handlerEval, pathTable, { cwd, generatedBy: PACKAGE_VERSION });
1727
+ const dispatchTable = dispatchResult.dispatchTable;
1728
+ passes.push(makePass('stable-ids', 'ok', {
1729
+ routes: routePlan.routes.length,
1730
+ stableIds: routeIdMap.summary.stableIds,
1731
+ runtimeIds: routeIdMap.summary.runtimeIds
1732
+ }));
1733
+ passes.push(makePass('path-table', 'ok', pathTable.summary));
1734
+ passes.push(makePass('dispatch-table', dispatchResult.diagnostics.length === 0 ? 'ok' : 'error', dispatchTable.summary));
1735
+ if (dispatchResult.diagnostics.length > 0) {
1736
+ throw new ExtractionError(dispatchResult.diagnostics, { passes, source, summary: ir.summary });
1737
+ }
1738
+
1739
+ const executionPlanResult = buildExecutionPlan(routerTree, dispatchTable, { cwd, generatedBy: PACKAGE_VERSION, resolvedConfig: options.resolvedConfig });
1740
+ const executionPlan = executionPlanResult.executionPlan;
1741
+ passes.push(makePass('execution-plan', executionPlanResult.diagnostics.length === 0 ? 'ok' : 'error', executionPlan.summary));
1742
+ if (executionPlanResult.diagnostics.length > 0) {
1743
+ throw new ExtractionError(executionPlanResult.diagnostics, { passes, source, summary: ir.summary });
1744
+ }
1745
+
1746
+ let assemblyScriptShape;
1747
+ if (options.emitAssemblyScriptShape || options.emitAssemblyScriptCore) {
1748
+ assemblyScriptShape = buildAssemblyScriptShape(dispatchTable, {
1749
+ cwd,
1750
+ generatedBy: PACKAGE_VERSION,
1751
+ executionPlan
1752
+ });
1753
+ passes.push(makePass('assemblyscript-shape', assemblyScriptShape.diagnostics.length === 0 ? 'ok' : 'error', assemblyScriptShape.artifact.summary));
1754
+ if (assemblyScriptShape.diagnostics.length > 0) {
1755
+ throw new ExtractionError(assemblyScriptShape.diagnostics, { passes, source, summary: ir.summary });
1756
+ }
1757
+ }
1758
+
1759
+ let assemblyScriptCore;
1760
+ if (options.emitAssemblyScriptCore) {
1761
+ assemblyScriptCore = buildAssemblyScriptCore(dispatchTable, {
1762
+ cwd,
1763
+ generatedBy: PACKAGE_VERSION,
1764
+ executionPlan,
1765
+ assemblyScriptShape
1766
+ });
1767
+ passes.push(makePass('assemblyscript-core', assemblyScriptCore.diagnostics.length === 0 ? 'ok' : 'error', assemblyScriptCore.artifact.summary));
1768
+ if (assemblyScriptCore.diagnostics.length > 0) {
1769
+ throw new ExtractionError(assemblyScriptCore.diagnostics, { passes, source, summary: ir.summary });
1770
+ }
1771
+ }
1772
+
1773
+ let assemblyScriptCompile;
1774
+ if (options.emitAssemblyScriptCompile) {
1775
+ assemblyScriptCompile = buildAssemblyScriptCompileSmoke(assemblyScriptShape, assemblyScriptCore, {
1776
+ cwd,
1777
+ generatedBy: PACKAGE_VERSION,
1778
+ outDir: options.outDir
1779
+ });
1780
+ passes.push(makePass('assemblyscript-compile', assemblyScriptCompile.diagnostics.length === 0 ? 'ok' : 'error', assemblyScriptCompile.artifact.summary));
1781
+ if (assemblyScriptCompile.diagnostics.length > 0) {
1782
+ throw new ExtractionError(assemblyScriptCompile.diagnostics, { passes, source, summary: ir.summary });
1783
+ }
1784
+ }
1785
+
1786
+ let assemblyScriptWasmSmoke;
1787
+ if (options.emitWasmSmoke) {
1788
+ assemblyScriptWasmSmoke = buildAssemblyScriptWasmSmoke(assemblyScriptShape, assemblyScriptCore, assemblyScriptCompile, {
1789
+ cwd,
1790
+ generatedBy: PACKAGE_VERSION,
1791
+ outDir: options.outDir
1792
+ });
1793
+ passes.push(makePass('assemblyscript-wasm-smoke', assemblyScriptWasmSmoke.diagnostics.length === 0 ? 'ok' : 'error', assemblyScriptWasmSmoke.artifact.summary));
1794
+ if (assemblyScriptWasmSmoke.diagnostics.length > 0) {
1795
+ throw new ExtractionError(assemblyScriptWasmSmoke.diagnostics, { passes, source, summary: ir.summary });
1796
+ }
1797
+ }
1798
+
1799
+ let handlerBindings;
1800
+ if (options.emitHandlerBindings || options.emitExecutionHarness) {
1801
+ handlerBindings = buildTypeScriptHandlerBindings(dispatchTable, handlerResolution.handlerTable, {
1802
+ cwd,
1803
+ outDir: options.outDir,
1804
+ generatedBy: PACKAGE_VERSION
1805
+ });
1806
+ passes.push(makePass('handler-bindings', handlerBindings.diagnostics.length === 0 ? 'ok' : 'error', handlerBindings.artifact.summary));
1807
+ if (handlerBindings.diagnostics.length > 0) {
1808
+ throw new ExtractionError(handlerBindings.diagnostics, { passes, source, summary: ir.summary });
1809
+ }
1810
+ }
1811
+
1812
+ let executionHarness;
1813
+ if (options.emitExecutionHarness) {
1814
+ executionHarness = buildTypeScriptExecutionHarness(dispatchTable, handlerBindings, {
1815
+ cwd,
1816
+ generatedBy: PACKAGE_VERSION,
1817
+ executionPlan
1818
+ });
1819
+ passes.push(makePass('execution-harness', executionHarness.diagnostics.length === 0 ? 'ok' : 'error', executionHarness.artifact.summary));
1820
+ if (executionHarness.diagnostics.length > 0) {
1821
+ throw new ExtractionError(executionHarness.diagnostics, { passes, source, summary: ir.summary });
1822
+ }
1823
+ }
1824
+
1825
+ let localHarness;
1826
+ if (options.emitLocalHarness) {
1827
+ localHarness = buildTypeScriptLocalHarness(dispatchTable, handlerBindings, executionHarness, {
1828
+ cwd,
1829
+ generatedBy: PACKAGE_VERSION,
1830
+ executionPlan
1831
+ });
1832
+ passes.push(makePass('local-harness', localHarness.diagnostics.length === 0 ? 'ok' : 'error', localHarness.artifact.summary));
1833
+ if (localHarness.diagnostics.length > 0) {
1834
+ throw new ExtractionError(localHarness.diagnostics, { passes, source, summary: ir.summary });
1835
+ }
1836
+ }
1837
+
1838
+ let wasmHostAbi;
1839
+ if (options.emitWasmHostAbi) {
1840
+ wasmHostAbi = buildWasmHostAbi(dispatchTable, executionPlan, {
1841
+ cwd,
1842
+ generatedBy: PACKAGE_VERSION
1843
+ });
1844
+ passes.push(makePass('wasm-host-abi', wasmHostAbi.diagnostics.length === 0 ? 'ok' : 'error', wasmHostAbi.artifact.summary));
1845
+ if (wasmHostAbi.diagnostics.length > 0) {
1846
+ throw new ExtractionError(wasmHostAbi.diagnostics, { passes, source, summary: ir.summary });
1847
+ }
1848
+ }
1849
+
1850
+ let wasmHostBridge;
1851
+ if (options.emitWasmHostBridge) {
1852
+ wasmHostBridge = buildWasmHostBridge(assemblyScriptShape, assemblyScriptCore, wasmHostAbi, {
1853
+ cwd,
1854
+ generatedBy: PACKAGE_VERSION,
1855
+ outDir: options.outDir
1856
+ });
1857
+ passes.push(makePass('wasm-host-bridge', wasmHostBridge.diagnostics.length === 0 ? 'ok' : 'error', wasmHostBridge.artifact.summary));
1858
+ if (wasmHostBridge.diagnostics.length > 0) {
1859
+ throw new ExtractionError(wasmHostBridge.diagnostics, { passes, source, summary: ir.summary });
1860
+ }
1861
+ }
1862
+
1863
+ let requestResultHeaders;
1864
+ if (options.emitRequestResultHeaders) {
1865
+ requestResultHeaders = buildRequestResultHeaders(dispatchTable, executionPlan, {
1866
+ cwd,
1867
+ generatedBy: PACKAGE_VERSION,
1868
+ wasmHostAbi,
1869
+ wasmHostBridge
1870
+ });
1871
+ passes.push(makePass('request-result-headers', requestResultHeaders.diagnostics.length === 0 ? 'ok' : 'error', requestResultHeaders.artifact.summary));
1872
+ if (requestResultHeaders.diagnostics.length > 0) {
1873
+ throw new ExtractionError(requestResultHeaders.diagnostics, { passes, source, summary: ir.summary });
1874
+ }
1875
+ }
1876
+
1877
+ let channelBroadcaster;
1878
+ if (options.emitJsonBody) {
1879
+ options.emitRequestResultHeaders = true;
1880
+ options.emitWasmHostAbi = true;
1881
+ }
1882
+
1883
+ if (options.emitChannelBroadcaster) {
1884
+ channelBroadcaster = buildChannelBroadcaster(dispatchTable, executionPlan, {
1885
+ cwd,
1886
+ generatedBy: PACKAGE_VERSION,
1887
+ wasmHostAbi,
1888
+ wasmHostBridge,
1889
+ requestResultHeaders
1890
+ });
1891
+ passes.push(makePass('channel-broadcaster', channelBroadcaster.diagnostics.length === 0 ? 'ok' : 'error', channelBroadcaster.artifact.summary));
1892
+ if (channelBroadcaster.diagnostics.length > 0) {
1893
+ throw new ExtractionError(channelBroadcaster.diagnostics, { passes, source, summary: ir.summary });
1894
+ }
1895
+ }
1896
+
1897
+ let jsonBody;
1898
+ let backendCapabilities;
1899
+ let deploymentPosture;
1900
+ if (options.emitBackendCapabilities) {
1901
+ backendCapabilities = buildBackendCapabilities(dispatchTable, executionPlan, handlerEvaluation.handlerEval, {
1902
+ cwd,
1903
+ generatedBy: PACKAGE_VERSION,
1904
+ resolvedConfig: options.resolvedConfig
1905
+ });
1906
+ passes.push(makePass('backend-capabilities', backendCapabilities.diagnostics.length === 0 ? 'ok' : 'error', backendCapabilities.artifact.summary));
1907
+ if (backendCapabilities.diagnostics.length > 0) {
1908
+ throw new ExtractionError(backendCapabilities.diagnostics, { passes, source, summary: ir.summary });
1909
+ }
1910
+ }
1911
+
1912
+ if (options.emitJsonBody) {
1913
+ jsonBody = buildJsonBodyAbi(dispatchTable, executionPlan, {
1914
+ cwd,
1915
+ generatedBy: PACKAGE_VERSION,
1916
+ wasmHostAbi,
1917
+ requestResultHeaders,
1918
+ resolvedConfig: options.resolvedConfig
1919
+ });
1920
+ passes.push(makePass('json-body', jsonBody.diagnostics.length === 0 ? 'ok' : 'error', jsonBody.artifact.summary));
1921
+ if (jsonBody.diagnostics.length > 0) {
1922
+ throw new ExtractionError(jsonBody.diagnostics, { passes, source, summary: ir.summary });
1923
+ }
1924
+
1925
+ deploymentPosture = buildDeploymentPosture(dispatchTable, executionPlan, {
1926
+ cwd,
1927
+ generatedBy: PACKAGE_VERSION,
1928
+ resolvedConfig: options.resolvedConfig,
1929
+ jsonBody,
1930
+ backendCapabilities
1931
+ });
1932
+ passes.push(makePass('deployment-posture', deploymentPosture.diagnostics.length === 0 ? 'ok' : 'error', deploymentPosture.artifact.summary));
1933
+ if (deploymentPosture.diagnostics.length > 0) {
1934
+ throw new ExtractionError(deploymentPosture.diagnostics, { passes, source, summary: ir.summary });
1935
+ }
1936
+ } else if (options.emitBackendCapabilities) {
1937
+ deploymentPosture = buildDeploymentPosture(dispatchTable, executionPlan, {
1938
+ cwd,
1939
+ generatedBy: PACKAGE_VERSION,
1940
+ resolvedConfig: options.resolvedConfig,
1941
+ backendCapabilities
1942
+ });
1943
+ passes.push(makePass('deployment-posture', deploymentPosture.diagnostics.length === 0 ? 'ok' : 'error', deploymentPosture.artifact.summary));
1944
+ if (deploymentPosture.diagnostics.length > 0) {
1945
+ throw new ExtractionError(deploymentPosture.diagnostics, { passes, source, summary: ir.summary });
1946
+ }
1947
+ }
1948
+
1949
+ let hostRuntimeKernel;
1950
+ if (options.emitHostRuntimeKernel) {
1951
+ hostRuntimeKernel = buildHostRuntimeKernel(wasmHostAbi, wasmHostBridge, deploymentPosture, {
1952
+ cwd,
1953
+ generatedBy: PACKAGE_VERSION,
1954
+ outDir: options.outDir
1955
+ });
1956
+ passes.push(makePass('host-runtime-kernel', hostRuntimeKernel.diagnostics.length === 0 ? 'ok' : 'error', hostRuntimeKernel.artifact.summary));
1957
+ if (hostRuntimeKernel.diagnostics.length > 0) {
1958
+ throw new ExtractionError(hostRuntimeKernel.diagnostics, { passes, source, summary: ir.summary });
1959
+ }
1960
+ }
1961
+
1962
+
1963
+ let nodeAdapter;
1964
+ if (options.emitNodeAdapter) {
1965
+ nodeAdapter = buildNodeAdapter(hostRuntimeKernel, wasmHostAbi, deploymentPosture, {
1966
+ cwd,
1967
+ generatedBy: PACKAGE_VERSION,
1968
+ outDir: options.outDir
1969
+ });
1970
+ passes.push(makePass('node-adapter', nodeAdapter.diagnostics.length === 0 ? 'ok' : 'error', nodeAdapter.artifact.summary));
1971
+ if (nodeAdapter.diagnostics.length > 0) {
1972
+ throw new ExtractionError(nodeAdapter.diagnostics, { passes, source, summary: ir.summary });
1973
+ }
1974
+ }
1975
+
1976
+ let streamingPassthrough;
1977
+ if (options.emitStreamingPassthrough) {
1978
+ streamingPassthrough = buildStreamingPassthrough({ wasmHostAbi, wasmHostBridge, hostRuntimeKernel, nodeAdapter, requestResultHeaders }, {
1979
+ cwd,
1980
+ generatedBy: PACKAGE_VERSION,
1981
+ outDir: options.outDir,
1982
+ deploymentPosture
1983
+ });
1984
+ passes.push(makePass('streaming-passthrough', streamingPassthrough.diagnostics.length === 0 ? 'ok' : 'error', streamingPassthrough.artifact.summary));
1985
+ if (streamingPassthrough.diagnostics.length > 0) {
1986
+ throw new ExtractionError(streamingPassthrough.diagnostics, { passes, source, summary: ir.summary });
1987
+ }
1988
+ }
1989
+
1990
+ let handlerLibraryContracts;
1991
+ if (options.emitHandlerLibraryContracts) {
1992
+ handlerLibraryContracts = buildHandlerLibraryContracts({
1993
+ cwd,
1994
+ generatedBy: PACKAGE_VERSION,
1995
+ dispatchTable,
1996
+ executionPlan,
1997
+ handlerTable: handlerResolution.handlerTable,
1998
+ handlerEval: handlerEvaluation.handlerEval,
1999
+ resolvedConfig: options.resolvedConfig
2000
+ });
2001
+ passes.push(makePass('handler-library-contracts', handlerLibraryContracts.diagnostics.length === 0 ? 'ok' : 'error', handlerLibraryContracts.artifact.summary));
2002
+ if (handlerLibraryContracts.diagnostics.length > 0) {
2003
+ throw new ExtractionError(handlerLibraryContracts.diagnostics, { passes, source, summary: ir.summary });
2004
+ }
2005
+ }
2006
+
2007
+ let assetsLoweringPlan;
2008
+ if (options.emitAssetsLoweringPlan) {
2009
+ assetsLoweringPlan = buildAssetsLoweringPlan({
2010
+ cwd,
2011
+ generatedBy: PACKAGE_VERSION,
2012
+ sourceFile,
2013
+ manifestRecords: lowerableManifestRecords,
2014
+ routePlan,
2015
+ executionPlan,
2016
+ handlerTable: handlerResolution.handlerTable,
2017
+ handlerEval: handlerEvaluation.handlerEval,
2018
+ handlerLibraryContracts,
2019
+ resolvedConfig: options.resolvedConfig,
2020
+ typescript: ts
2021
+ });
2022
+ const assetsLoweringPlanErrors = assetsLoweringPlan.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2023
+ passes.push(makePass('assets-lowering-plan', assetsLoweringPlanErrors.length === 0 ? 'ok' : 'error', assetsLoweringPlan.artifact.summary));
2024
+ if (assetsLoweringPlanErrors.length > 0) {
2025
+ throw new ExtractionError(assetsLoweringPlanErrors, { passes, source, summary: ir.summary });
2026
+ }
2027
+ }
2028
+
2029
+ let assetsCompiledWasmSidecarPlan;
2030
+ if (options.emitAssetsCompiledWasmSidecarPlan) {
2031
+ assetsCompiledWasmSidecarPlan = buildAssetsCompiledWasmSidecarPlan({
2032
+ cwd,
2033
+ generatedBy: PACKAGE_VERSION,
2034
+ sourceFile,
2035
+ manifestRecords: lowerableManifestRecords,
2036
+ assetsLoweringPlan,
2037
+ handlerLibraryContracts,
2038
+ resolvedConfig: options.resolvedConfig,
2039
+ typescript: ts
2040
+ });
2041
+ const assetsCompiledWasmSidecarPlanErrors = assetsCompiledWasmSidecarPlan.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2042
+ passes.push(makePass('assets-compiled-wasm-sidecar-plan', assetsCompiledWasmSidecarPlanErrors.length === 0 ? 'ok' : 'error', assetsCompiledWasmSidecarPlan.artifact.summary));
2043
+ if (assetsCompiledWasmSidecarPlanErrors.length > 0) {
2044
+ throw new ExtractionError(assetsCompiledWasmSidecarPlanErrors, { passes, source, summary: ir.summary });
2045
+ }
2046
+ }
2047
+
2048
+ let assetsSidecarCompileLinkProof;
2049
+ if (options.emitAssetsSidecarCompileLinkProof) {
2050
+ assetsSidecarCompileLinkProof = buildAssetsSidecarCompileLinkProof({
2051
+ cwd,
2052
+ generatedBy: PACKAGE_VERSION,
2053
+ sourceFile,
2054
+ manifestRecords: lowerableManifestRecords,
2055
+ assetsLoweringPlan,
2056
+ assetsCompiledWasmSidecarPlan,
2057
+ handlerLibraryContracts,
2058
+ resolvedConfig: options.resolvedConfig,
2059
+ typescript: ts
2060
+ });
2061
+ const assetsSidecarCompileLinkProofErrors = assetsSidecarCompileLinkProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2062
+ passes.push(makePass('assets-sidecar-compile-link-proof', assetsSidecarCompileLinkProofErrors.length === 0 ? 'ok' : 'error', assetsSidecarCompileLinkProof.artifact.summary));
2063
+ if (assetsSidecarCompileLinkProofErrors.length > 0) {
2064
+ throw new ExtractionError(assetsSidecarCompileLinkProofErrors, { passes, source, summary: ir.summary });
2065
+ }
2066
+ }
2067
+
2068
+ let nodeAssetsProviderProof;
2069
+ if (options.emitNodeAssetsProviderProof) {
2070
+ nodeAssetsProviderProof = buildNodeAssetsProviderProof({
2071
+ cwd,
2072
+ generatedBy: PACKAGE_VERSION,
2073
+ assetsLoweringPlan,
2074
+ resolvedConfig: options.resolvedConfig
2075
+ });
2076
+ const nodeAssetsProviderProofErrors = nodeAssetsProviderProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2077
+ passes.push(makePass('node-assets-provider-proof', nodeAssetsProviderProofErrors.length === 0 ? 'ok' : 'error', nodeAssetsProviderProof.artifact.summary));
2078
+ if (nodeAssetsProviderProofErrors.length > 0) {
2079
+ throw new ExtractionError(nodeAssetsProviderProofErrors, { passes, source, summary: ir.summary });
2080
+ }
2081
+ }
2082
+
2083
+ let nodeCompiledWasmAssetsLifecycleProof;
2084
+ if (options.emitNodeCompiledWasmAssetsLifecycleProof) {
2085
+ nodeCompiledWasmAssetsLifecycleProof = buildNodeCompiledWasmAssetsLifecycleProof({
2086
+ cwd,
2087
+ generatedBy: PACKAGE_VERSION,
2088
+ assetsLoweringPlan,
2089
+ assetsCompiledWasmSidecarPlan,
2090
+ resolvedConfig: options.resolvedConfig,
2091
+ configRoot: options.configRoot || options.resolvedConfigDir || options.configDir || options.entryDir || cwd
2092
+ });
2093
+ const nodeCompiledWasmAssetsLifecycleProofErrors = nodeCompiledWasmAssetsLifecycleProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2094
+ passes.push(makePass('node-compiled-wasm-assets-lifecycle-proof', nodeCompiledWasmAssetsLifecycleProofErrors.length === 0 ? 'ok' : 'error', nodeCompiledWasmAssetsLifecycleProof.artifact.summary));
2095
+ if (nodeCompiledWasmAssetsLifecycleProofErrors.length > 0) {
2096
+ throw new ExtractionError(nodeCompiledWasmAssetsLifecycleProofErrors, { passes, source, summary: ir.summary });
2097
+ }
2098
+ }
2099
+
2100
+ let hostCapabilities;
2101
+ if (options.emitHostCapabilities) {
2102
+ hostCapabilities = buildHostCapabilities({
2103
+ cwd,
2104
+ generatedBy: PACKAGE_VERSION,
2105
+ handlerLibraryContracts,
2106
+ requestResultHeaders,
2107
+ channelBroadcaster,
2108
+ jsonBody,
2109
+ backendCapabilities,
2110
+ wasmHostAbi,
2111
+ resolvedConfig: options.resolvedConfig
2112
+ });
2113
+ passes.push(makePass('host-capabilities', hostCapabilities.diagnostics.length === 0 ? 'ok' : 'error', hostCapabilities.artifact.summary));
2114
+ if (hostCapabilities.diagnostics.length > 0) {
2115
+ throw new ExtractionError(hostCapabilities.diagnostics, { passes, source, summary: ir.summary });
2116
+ }
2117
+ }
2118
+
2119
+ let effectRuntime;
2120
+ if (options.emitEffectRuntime) {
2121
+ effectRuntime = buildEffectRuntime({
2122
+ cwd,
2123
+ generatedBy: PACKAGE_VERSION,
2124
+ hostCapabilities,
2125
+ backendCapabilities,
2126
+ jsonBody,
2127
+ resolvedConfig: options.resolvedConfig
2128
+ });
2129
+ passes.push(makePass('effect-runtime', effectRuntime.diagnostics.length === 0 ? 'ok' : 'error', effectRuntime.artifact.summary));
2130
+ if (effectRuntime.diagnostics.length > 0) {
2131
+ throw new ExtractionError(effectRuntime.diagnostics, { passes, source, summary: ir.summary });
2132
+ }
2133
+ }
2134
+
2135
+ let effectComposition;
2136
+ if (options.emitEffectComposition) {
2137
+ effectComposition = buildEffectComposition({
2138
+ cwd,
2139
+ generatedBy: PACKAGE_VERSION,
2140
+ effectRuntime,
2141
+ hostCapabilities,
2142
+ executionPlan,
2143
+ resolvedConfig: options.resolvedConfig
2144
+ });
2145
+ passes.push(makePass('effect-composition', effectComposition.diagnostics.length === 0 ? 'ok' : 'error', effectComposition.artifact.summary));
2146
+ if (effectComposition.diagnostics.length > 0) {
2147
+ throw new ExtractionError(effectComposition.diagnostics, { passes, source, summary: ir.summary });
2148
+ }
2149
+ }
2150
+
2151
+ let routeHandlerEffectPlan;
2152
+ if (options.emitRouteHandlerEffectPlan) {
2153
+ routeHandlerEffectPlan = buildRouteHandlerEffectPlan(sourceFile, routePlan, handlerResolution.handlerTable, {
2154
+ cwd,
2155
+ generatedBy: PACKAGE_VERSION,
2156
+ executionPlan,
2157
+ effectComposition,
2158
+ resolvedConfig: options.resolvedConfig
2159
+ });
2160
+ passes.push(makePass('route-handler-effects', routeHandlerEffectPlan.diagnostics.length === 0 ? 'ok' : 'error', routeHandlerEffectPlan.artifact.summary));
2161
+ if (routeHandlerEffectPlan.diagnostics.length > 0) {
2162
+ throw new ExtractionError(routeHandlerEffectPlan.diagnostics, { passes, source, summary: ir.summary });
2163
+ }
2164
+ }
2165
+
2166
+
2167
+ let nodeRouteHandlerEffectProof;
2168
+ if (options.emitNodeRouteHandlerEffectProof) {
2169
+ nodeRouteHandlerEffectProof = buildNodeRouteHandlerEffectProof({
2170
+ cwd,
2171
+ generatedBy: PACKAGE_VERSION,
2172
+ routeHandlerEffectPlan,
2173
+ resolvedConfig: options.resolvedConfig
2174
+ });
2175
+ const nodeRouteHandlerEffectProofErrors = nodeRouteHandlerEffectProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2176
+ passes.push(makePass('node-route-handler-effect-proof', nodeRouteHandlerEffectProofErrors.length === 0 ? 'ok' : 'error', nodeRouteHandlerEffectProof.artifact.summary));
2177
+ if (nodeRouteHandlerEffectProofErrors.length > 0) {
2178
+ throw new ExtractionError(nodeRouteHandlerEffectProofErrors, { passes, source, summary: ir.summary });
2179
+ }
2180
+ }
2181
+
2182
+
2183
+ let fastlyRouteHandlerEffectProof;
2184
+ if (options.emitFastlyRouteHandlerEffectProof) {
2185
+ fastlyRouteHandlerEffectProof = buildFastlyRouteHandlerEffectProof({
2186
+ cwd,
2187
+ generatedBy: PACKAGE_VERSION,
2188
+ routeHandlerEffectPlan,
2189
+ resolvedConfig: options.resolvedConfig
2190
+ });
2191
+ const fastlyRouteHandlerEffectProofErrors = fastlyRouteHandlerEffectProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2192
+ passes.push(makePass('fastly-route-handler-effect-proof', fastlyRouteHandlerEffectProofErrors.length === 0 ? 'ok' : 'error', fastlyRouteHandlerEffectProof.artifact.summary));
2193
+ if (fastlyRouteHandlerEffectProofErrors.length > 0) {
2194
+ throw new ExtractionError(fastlyRouteHandlerEffectProofErrors, { passes, source, summary: ir.summary });
2195
+ }
2196
+ }
2197
+
2198
+ let routeHandlerContextLoweringPlan;
2199
+ if (options.emitRouteHandlerContextLoweringPlan) {
2200
+ routeHandlerContextLoweringPlan = buildRouteHandlerContextLoweringPlan(sourceFile, routePlan, handlerResolution.handlerTable, {
2201
+ cwd,
2202
+ generatedBy: PACKAGE_VERSION,
2203
+ executionPlan,
2204
+ routeHandlerEffectPlan,
2205
+ resolvedConfig: options.resolvedConfig
2206
+ });
2207
+ const routeHandlerContextErrors = routeHandlerContextLoweringPlan.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2208
+ passes.push(makePass('route-handler-context-lowering', routeHandlerContextErrors.length === 0 ? 'ok' : 'error', routeHandlerContextLoweringPlan.artifact.summary));
2209
+ if (routeHandlerContextErrors.length > 0) {
2210
+ throw new ExtractionError(routeHandlerContextErrors, { passes, source, summary: ir.summary });
2211
+ }
2212
+ }
2213
+
2214
+ let schemaJsonCompile;
2215
+ const shouldCompileSchemaJson = Boolean(options.emitSchemaJsonCompile) || compileNeeded(options.resolvedConfig || {});
2216
+ let schemaResolvedConfig = options.resolvedConfig;
2217
+ if (shouldCompileSchemaJson) {
2218
+ schemaJsonCompile = buildSchemaJsonCompile({ cwd, generatedBy: PACKAGE_VERSION, resolvedConfig: options.resolvedConfig });
2219
+ passes.push(makePass('schema-json-compile', schemaJsonCompile.diagnostics.length === 0 ? 'ok' : 'error', schemaJsonCompile.artifact.summary));
2220
+ if (schemaJsonCompile.diagnostics.length > 0) {
2221
+ throw new ExtractionError(schemaJsonCompile.diagnostics, { passes, source, summary: ir.summary });
2222
+ }
2223
+ schemaResolvedConfig = schemaJsonCompile.compiledConfig;
2224
+ }
2225
+
2226
+ let schemaJsonGenericParser;
2227
+ const shouldUseGenericSchemaJsonParser = Boolean(options.emitSchemaJsonGenericParser) || (Boolean(options.emitSchemaJsonSidecar) && genericParserNeeded(schemaResolvedConfig || {}));
2228
+ if (shouldUseGenericSchemaJsonParser) {
2229
+ schemaJsonGenericParser = buildSchemaJsonGenericParser(dispatchTable, executionPlan, {
2230
+ cwd,
2231
+ generatedBy: PACKAGE_VERSION,
2232
+ outDir: options.outDir,
2233
+ resolvedConfig: schemaResolvedConfig,
2234
+ forceGenericParser: Boolean(options.emitSchemaJsonGenericParser)
2235
+ });
2236
+ passes.push(makePass('schema-json-generic-parser', schemaJsonGenericParser.diagnostics.length === 0 ? 'ok' : 'error', schemaJsonGenericParser.artifact.summary));
2237
+ if (schemaJsonGenericParser.diagnostics.length > 0) {
2238
+ throw new ExtractionError(schemaJsonGenericParser.diagnostics, { passes, source, summary: ir.summary });
2239
+ }
2240
+ }
2241
+
2242
+ let schemaJsonSidecar;
2243
+ if (options.emitSchemaJsonSidecar && !schemaJsonGenericParser) {
2244
+ schemaJsonSidecar = buildSchemaJsonSidecar(dispatchTable, executionPlan, {
2245
+ cwd,
2246
+ generatedBy: PACKAGE_VERSION,
2247
+ outDir: options.outDir,
2248
+ resolvedConfig: schemaResolvedConfig
2249
+ });
2250
+ passes.push(makePass('schema-json-sidecar', schemaJsonSidecar.diagnostics.length === 0 ? 'ok' : 'error', schemaJsonSidecar.artifact.summary));
2251
+ if (schemaJsonSidecar.diagnostics.length > 0) {
2252
+ throw new ExtractionError(schemaJsonSidecar.diagnostics, { passes, source, summary: ir.summary });
2253
+ }
2254
+ }
2255
+
2256
+ let requestJsonBodyPlan;
2257
+ if (options.emitRequestJsonBodyPlan) {
2258
+ requestJsonBodyPlan = buildRequestJsonBodyPlan(sourceFile, routePlan, handlerResolution.handlerTable, {
2259
+ cwd,
2260
+ generatedBy: PACKAGE_VERSION,
2261
+ resolvedConfig: schemaResolvedConfig || options.resolvedConfig,
2262
+ schemaJsonCompile,
2263
+ schemaJsonGenericParser,
2264
+ schemaJsonSidecar
2265
+ });
2266
+ const requestJsonBodyErrors = requestJsonBodyPlan.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2267
+ passes.push(makePass('request-json-body', requestJsonBodyErrors.length === 0 ? 'ok' : 'error', requestJsonBodyPlan.artifact.summary));
2268
+ if (requestJsonBodyErrors.length > 0) {
2269
+ throw new ExtractionError(requestJsonBodyErrors, { passes, source, summary: ir.summary });
2270
+ }
2271
+ }
2272
+
2273
+ let schemaDecodeResultPlan;
2274
+ if (options.emitSchemaDecodeResultPlan) {
2275
+ schemaDecodeResultPlan = buildSchemaDecodeResultPlan({
2276
+ cwd,
2277
+ generatedBy: PACKAGE_VERSION,
2278
+ resolvedConfig: schemaResolvedConfig || options.resolvedConfig,
2279
+ requestJsonBodyPlan,
2280
+ schemaJsonCompile,
2281
+ schemaJsonGenericParser,
2282
+ schemaJsonSidecar
2283
+ });
2284
+ const schemaDecodeResultErrors = schemaDecodeResultPlan.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2285
+ passes.push(makePass('schema-decode-result', schemaDecodeResultErrors.length === 0 ? 'ok' : 'error', schemaDecodeResultPlan.artifact.summary));
2286
+ if (schemaDecodeResultErrors.length > 0) {
2287
+ throw new ExtractionError(schemaDecodeResultErrors, { passes, source, summary: ir.summary });
2288
+ }
2289
+ }
2290
+
2291
+ let schemaResponseCodecPlan;
2292
+ if (options.emitSchemaResponseCodecPlan) {
2293
+ schemaResponseCodecPlan = buildSchemaResponseCodecPlan(sourceFile, routePlan, handlerResolution.handlerTable, {
2294
+ cwd,
2295
+ generatedBy: PACKAGE_VERSION,
2296
+ resolvedConfig: schemaResolvedConfig || options.resolvedConfig,
2297
+ routeHandlerEffectPlan,
2298
+ requestJsonBodyPlan,
2299
+ schemaDecodeResultPlan,
2300
+ schemaJsonCompile,
2301
+ schemaJsonGenericParser,
2302
+ schemaJsonSidecar
2303
+ });
2304
+ const schemaResponseCodecErrors = schemaResponseCodecPlan.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2305
+ passes.push(makePass('schema-response-codec', schemaResponseCodecErrors.length === 0 ? 'ok' : 'error', schemaResponseCodecPlan.artifact.summary));
2306
+ if (schemaResponseCodecErrors.length > 0) {
2307
+ throw new ExtractionError(schemaResponseCodecErrors, { passes, source, summary: ir.summary });
2308
+ }
2309
+ }
2310
+
2311
+ let backendJsonRequestBodyPlan;
2312
+ if (options.emitBackendJsonRequestBodyPlan) {
2313
+ backendJsonRequestBodyPlan = buildBackendJsonRequestBodyPlan({
2314
+ cwd,
2315
+ generatedBy: PACKAGE_VERSION,
2316
+ routeHandlerEffectPlan,
2317
+ requestJsonBodyPlan,
2318
+ resolvedConfig: schemaResolvedConfig || options.resolvedConfig
2319
+ });
2320
+ const backendJsonRequestBodyErrors = backendJsonRequestBodyPlan.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2321
+ passes.push(makePass('backend-json-request-body', backendJsonRequestBodyErrors.length === 0 ? 'ok' : 'error', backendJsonRequestBodyPlan.artifact.summary));
2322
+ if (backendJsonRequestBodyErrors.length > 0) {
2323
+ throw new ExtractionError(backendJsonRequestBodyErrors, { passes, source, summary: ir.summary });
2324
+ }
2325
+ }
2326
+
2327
+ let handlerIoLifecyclePlan;
2328
+ if (options.emitHandlerIoLifecyclePlan) {
2329
+ handlerIoLifecyclePlan = buildHandlerIoLifecyclePlan(sourceFile, routePlan, handlerResolution.handlerTable, {
2330
+ cwd,
2331
+ generatedBy: PACKAGE_VERSION,
2332
+ resolvedConfig: schemaResolvedConfig || options.resolvedConfig,
2333
+ routeHandlerContextLoweringPlan,
2334
+ routeHandlerEffectPlan,
2335
+ nodeRouteHandlerEffectProof,
2336
+ fastlyRouteHandlerEffectProof,
2337
+ schemaJsonCompile,
2338
+ requestJsonBodyPlan,
2339
+ schemaDecodeResultPlan,
2340
+ schemaResponseCodecPlan,
2341
+ schemaJsonGenericParser,
2342
+ schemaJsonSidecar
2343
+ });
2344
+ const handlerIoLifecycleErrors = handlerIoLifecyclePlan.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2345
+ passes.push(makePass('handler-io-lifecycle', handlerIoLifecycleErrors.length === 0 ? 'ok' : 'error', handlerIoLifecyclePlan.artifact.summary));
2346
+ if (handlerIoLifecycleErrors.length > 0) {
2347
+ throw new ExtractionError(handlerIoLifecycleErrors, { passes, source, summary: ir.summary });
2348
+ }
2349
+ }
2350
+
2351
+ let fastlyLifecycleParityProof;
2352
+ if (options.emitFastlyLifecycleParityProof) {
2353
+ fastlyLifecycleParityProof = buildFastlyLifecycleParityProof({
2354
+ cwd,
2355
+ generatedBy: PACKAGE_VERSION,
2356
+ routeHandlerEffectPlan,
2357
+ handlerIoLifecyclePlan,
2358
+ backendJsonRequestBodyPlan,
2359
+ resolvedConfig: schemaResolvedConfig || options.resolvedConfig,
2360
+ mode: 'cli-fastly-lifecycle-parity-proof'
2361
+ });
2362
+ const fastlyLifecycleParityErrors = fastlyLifecycleParityProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2363
+ passes.push(makePass('fastly-lifecycle-parity-proof', fastlyLifecycleParityErrors.length === 0 ? 'ok' : 'error', fastlyLifecycleParityProof.artifact.summary));
2364
+ if (fastlyLifecycleParityErrors.length > 0) {
2365
+ throw new ExtractionError(fastlyLifecycleParityErrors, { passes, source, summary: ir.summary });
2366
+ }
2367
+ }
2368
+
2369
+ let librarySidecars;
2370
+ if (options.emitLibrarySidecars) {
2371
+ librarySidecars = buildLibrarySidecarConsumption({
2372
+ cwd,
2373
+ generatedBy: PACKAGE_VERSION,
2374
+ outDir: options.outDir,
2375
+ executionPlan,
2376
+ handlerLibraryContracts
2377
+ });
2378
+ passes.push(makePass('library-sidecars', librarySidecars.diagnostics.length === 0 ? 'ok' : 'error', librarySidecars.artifact.summary));
2379
+ if (librarySidecars.diagnostics.length > 0) {
2380
+ throw new ExtractionError(librarySidecars.diagnostics, { passes, source, summary: ir.summary });
2381
+ }
2382
+ }
2383
+
2384
+ let compiledHandlers;
2385
+ if (options.emitCompiledHandlers) {
2386
+ compiledHandlers = buildCompiledUserHandlers(sourceFile, handlerResolution.handlerTable, handlerEvaluation.handlerEval, dispatchTable, assemblyScriptShape, assemblyScriptCore, {
2387
+ cwd,
2388
+ generatedBy: PACKAGE_VERSION,
2389
+ outDir: options.outDir,
2390
+ routeHandlerEffectPlan,
2391
+ requestJsonBodyPlan
2392
+ });
2393
+ passes.push(makePass('compiled-handlers', compiledHandlers.diagnostics.length === 0 ? 'ok' : 'error', compiledHandlers.artifact.summary));
2394
+ if (compiledHandlers.diagnostics.length > 0) {
2395
+ throw new ExtractionError(compiledHandlers.diagnostics, { passes, source, summary: ir.summary });
2396
+ }
2397
+ }
2398
+
2399
+ let nodeRequestJsonBodyProof;
2400
+ if (options.emitNodeRequestJsonBodyProof) {
2401
+ nodeRequestJsonBodyProof = buildNodeRequestJsonBodyProof({
2402
+ cwd,
2403
+ outDir: options.outDir,
2404
+ generatedBy: PACKAGE_VERSION,
2405
+ requestJsonBodyPlan,
2406
+ compiledHandlers,
2407
+ resolvedConfig: schemaResolvedConfig || options.resolvedConfig,
2408
+ mode: 'compiled-wasm-request-json-body-proof'
2409
+ });
2410
+ const nodeRequestJsonBodyProofErrors = nodeRequestJsonBodyProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2411
+ passes.push(makePass('node-request-json-body-proof', nodeRequestJsonBodyProofErrors.length === 0 ? 'ok' : 'error', nodeRequestJsonBodyProof.artifact.summary));
2412
+ if (nodeRequestJsonBodyProofErrors.length > 0) {
2413
+ throw new ExtractionError(nodeRequestJsonBodyProofErrors, { passes, source, summary: ir.summary });
2414
+ }
2415
+ }
2416
+
2417
+ let nodeSchemaDecodeResultProof;
2418
+ if (options.emitNodeSchemaDecodeResultProof) {
2419
+ nodeSchemaDecodeResultProof = buildNodeSchemaDecodeResultProof({
2420
+ cwd,
2421
+ outDir: options.outDir,
2422
+ generatedBy: PACKAGE_VERSION,
2423
+ schemaDecodeResultPlan,
2424
+ requestJsonBodyPlan,
2425
+ compiledHandlers,
2426
+ resolvedConfig: schemaResolvedConfig || options.resolvedConfig,
2427
+ mode: 'compiled-wasm-schema-decode-result-proof'
2428
+ });
2429
+ const nodeSchemaDecodeResultProofErrors = nodeSchemaDecodeResultProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2430
+ passes.push(makePass('node-schema-decode-result-proof', nodeSchemaDecodeResultProofErrors.length === 0 ? 'ok' : 'error', nodeSchemaDecodeResultProof.artifact.summary));
2431
+ if (nodeSchemaDecodeResultProofErrors.length > 0) {
2432
+ throw new ExtractionError(nodeSchemaDecodeResultProofErrors, { passes, source, summary: ir.summary });
2433
+ }
2434
+ }
2435
+
2436
+ let nodeSchemaResponseCodecProof;
2437
+ if (options.emitNodeSchemaResponseCodecProof) {
2438
+ nodeSchemaResponseCodecProof = buildNodeSchemaResponseCodecProof({
2439
+ cwd,
2440
+ outDir: options.outDir,
2441
+ generatedBy: PACKAGE_VERSION,
2442
+ schemaResponseCodecPlan,
2443
+ requestJsonBodyPlan,
2444
+ schemaDecodeResultPlan,
2445
+ compiledHandlers,
2446
+ resolvedConfig: schemaResolvedConfig || options.resolvedConfig,
2447
+ mode: 'compiled-wasm-schema-response-codec-proof'
2448
+ });
2449
+ const nodeSchemaResponseCodecProofErrors = nodeSchemaResponseCodecProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2450
+ passes.push(makePass('node-schema-response-codec-proof', nodeSchemaResponseCodecProofErrors.length === 0 ? 'ok' : 'error', nodeSchemaResponseCodecProof.artifact.summary));
2451
+ if (nodeSchemaResponseCodecProofErrors.length > 0) {
2452
+ throw new ExtractionError(nodeSchemaResponseCodecProofErrors, { passes, source, summary: ir.summary });
2453
+ }
2454
+ }
2455
+
2456
+ let integratedCompiledApp;
2457
+ if (options.emitIntegratedCompiledApp) {
2458
+ integratedCompiledApp = buildIntegratedCompiledApp({ assemblyScriptShape, assemblyScriptCore, schemaJsonSidecar, librarySidecars, streamingPassthrough, dispatchTable }, { cwd, generatedBy: PACKAGE_VERSION, outDir: options.outDir });
2459
+ passes.push(makePass('integrated-compiled-app', integratedCompiledApp.diagnostics.length === 0 ? 'ok' : 'error', integratedCompiledApp.artifact.summary));
2460
+ if (integratedCompiledApp.diagnostics.length > 0) {
2461
+ throw new ExtractionError(integratedCompiledApp.diagnostics, { passes, source, summary: ir.summary });
2462
+ }
2463
+ }
2464
+
2465
+ let compiledWasmRuntime;
2466
+ if (options.emitCompiledWasmRuntime) {
2467
+ compiledWasmRuntime = buildCompiledWasmRuntime({ assemblyScriptShape, assemblyScriptCore, schemaJsonSidecar, librarySidecars }, { cwd, generatedBy: PACKAGE_VERSION, outDir: options.outDir, dispatchTable });
2468
+ passes.push(makePass('compiled-wasm-runtime', compiledWasmRuntime.diagnostics.length === 0 ? 'ok' : 'error', compiledWasmRuntime.artifact.summary));
2469
+ if (compiledWasmRuntime.diagnostics.length > 0) {
2470
+ throw new ExtractionError(compiledWasmRuntime.diagnostics, { passes, source, summary: ir.summary });
2471
+ }
2472
+ }
2473
+
2474
+ let pulseWrapper;
2475
+ if (options.emitPulseWrapper) {
2476
+ pulseWrapper = buildPulseWrapperIntegration({ compiledWasmRuntime, deploymentPosture }, { cwd, generatedBy: PACKAGE_VERSION, outDir: options.outDir, resolvedConfig: options.resolvedConfig });
2477
+ passes.push(makePass('pulse-wrapper', pulseWrapper.diagnostics.length === 0 ? 'ok' : 'error', pulseWrapper.artifact.summary));
2478
+ if (pulseWrapper.diagnostics.length > 0) {
2479
+ throw new ExtractionError(pulseWrapper.diagnostics, { passes, source, summary: ir.summary });
2480
+ }
2481
+ }
2482
+
2483
+ let fastlyReadiness;
2484
+ if (options.emitFastlyReadiness) {
2485
+ fastlyReadiness = buildFastlyReadiness({
2486
+ pulseWrapper,
2487
+ compiledWasmRuntime,
2488
+ hostCapabilities,
2489
+ streamingPassthrough,
2490
+ wasmHostAbi,
2491
+ nodeAdapter,
2492
+ backendCapabilities,
2493
+ channelBroadcaster,
2494
+ deploymentPosture,
2495
+ effectRuntime,
2496
+ effectComposition,
2497
+ schemaJsonSidecar,
2498
+ librarySidecars
2499
+ }, { cwd, generatedBy: PACKAGE_VERSION, outDir: options.outDir, resolvedConfig: options.resolvedConfig });
2500
+ passes.push(makePass('fastly-readiness', fastlyReadiness.diagnostics.length === 0 ? 'ok' : 'error', fastlyReadiness.artifact.summary));
2501
+ if (fastlyReadiness.diagnostics.length > 0) {
2502
+ throw new ExtractionError(fastlyReadiness.diagnostics, { passes, source, summary: ir.summary });
2503
+ }
2504
+ }
2505
+
2506
+ let fastlyHostcallBinding;
2507
+ if (options.emitFastlyHostcallBinding) {
2508
+ fastlyHostcallBinding = buildFastlyHostcallBinding({
2509
+ fastlyReadiness,
2510
+ compiledWasmRuntime,
2511
+ hostCapabilities,
2512
+ streamingPassthrough,
2513
+ wasmHostAbi,
2514
+ backendCapabilities,
2515
+ deploymentPosture
2516
+ }, { cwd, generatedBy: PACKAGE_VERSION, outDir: options.outDir, resolvedConfig: options.resolvedConfig });
2517
+ passes.push(makePass('fastly-hostcall-binding', fastlyHostcallBinding.diagnostics.length === 0 ? 'ok' : 'error', fastlyHostcallBinding.artifact.summary));
2518
+ if (fastlyHostcallBinding.diagnostics.length > 0) {
2519
+ throw new ExtractionError(fastlyHostcallBinding.diagnostics, { passes, source, summary: ir.summary });
2520
+ }
2521
+ }
2522
+
2523
+ let fastlyAdapter;
2524
+ if (options.emitFastlyAdapter) {
2525
+ fastlyAdapter = buildFastlyStreamHeaderAdapter({
2526
+ compiledWasmRuntime,
2527
+ fastlyHostcallBinding,
2528
+ fastlyReadiness,
2529
+ streamingPassthrough,
2530
+ wasmHostAbi
2531
+ }, { cwd, generatedBy: PACKAGE_VERSION, outDir: options.outDir, resolvedConfig: options.resolvedConfig });
2532
+ passes.push(makePass('fastly-adapter', fastlyAdapter.diagnostics.length === 0 ? 'ok' : 'error', fastlyAdapter.artifact.summary));
2533
+ if (fastlyAdapter.diagnostics.length > 0) {
2534
+ throw new ExtractionError(fastlyAdapter.diagnostics, { passes, source, summary: ir.summary });
2535
+ }
2536
+ }
2537
+
2538
+ let fastlyCommandEntry;
2539
+ if (options.emitFastlyCommandEntry) {
2540
+ fastlyCommandEntry = buildFastlyCommandEntry({ fastlyAdapter, fastlyHostcallBinding }, { cwd, generatedBy: PACKAGE_VERSION, outDir: options.outDir, resolvedConfig: options.resolvedConfig });
2541
+ passes.push(makePass('fastly-command-entry', fastlyCommandEntry.diagnostics.length === 0 ? 'ok' : 'error', fastlyCommandEntry.artifact.summary));
2542
+ if (fastlyCommandEntry.diagnostics.length > 0) {
2543
+ throw new ExtractionError(fastlyCommandEntry.diagnostics, { passes, source, summary: ir.summary });
2544
+ }
2545
+ }
2546
+
2547
+ let fastlyAssetsProviderProof;
2548
+ if (options.emitFastlyAssetsProviderProof) {
2549
+ fastlyAssetsProviderProof = buildFastlyAssetsProviderProof({
2550
+ cwd,
2551
+ generatedBy: PACKAGE_VERSION,
2552
+ assetsLoweringPlan,
2553
+ resolvedConfig: options.resolvedConfig,
2554
+ fastlyHostcallBinding,
2555
+ fastlyAdapter,
2556
+ requestResultHeaders,
2557
+ streamingPassthrough,
2558
+ wasmHostAbi
2559
+ });
2560
+ const fastlyAssetsProviderProofErrors = fastlyAssetsProviderProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2561
+ passes.push(makePass('fastly-assets-provider-proof', fastlyAssetsProviderProofErrors.length === 0 ? 'ok' : 'error', fastlyAssetsProviderProof.artifact.summary));
2562
+ if (fastlyAssetsProviderProofErrors.length > 0) {
2563
+ throw new ExtractionError(fastlyAssetsProviderProofErrors, { passes, source, summary: ir.summary });
2564
+ }
2565
+ }
2566
+
2567
+
2568
+ let fastlyAssetsPackageOutParityProof;
2569
+ if (options.emitFastlyAssetsPackageOutParityProof) {
2570
+ fastlyAssetsPackageOutParityProof = buildFastlyAssetsPackageOutParityProof({
2571
+ cwd,
2572
+ generatedBy: PACKAGE_VERSION,
2573
+ assetsLoweringPlan,
2574
+ assetsCompiledWasmSidecarPlan,
2575
+ fastlyAssetsProviderProof,
2576
+ resolvedConfig: options.resolvedConfig,
2577
+ fastlyHostcallBinding,
2578
+ fastlyAdapter,
2579
+ requestResultHeaders,
2580
+ streamingPassthrough,
2581
+ wasmHostAbi
2582
+ });
2583
+ const fastlyAssetsPackageOutParityProofErrors = fastlyAssetsPackageOutParityProof.diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
2584
+ passes.push(makePass('fastly-assets-package-out-parity-proof', fastlyAssetsPackageOutParityProofErrors.length === 0 ? 'ok' : 'error', fastlyAssetsPackageOutParityProof.artifact.summary));
2585
+ if (fastlyAssetsPackageOutParityProofErrors.length > 0) {
2586
+ throw new ExtractionError(fastlyAssetsPackageOutParityProofErrors, { passes, source, summary: ir.summary });
2587
+ }
2588
+ }
2589
+
2590
+ let dispatchTs;
2591
+ if (options.emitDispatchTs || options.emitHandlerBindings || options.emitExecutionHarness || options.emitLocalHarness) {
2592
+ dispatchTs = buildTypeScriptDispatch(dispatchTable, { cwd, generatedBy: PACKAGE_VERSION, handlerBindings, executionHarness, localHarness });
2593
+ passes.push(makePass('dispatch-ts', dispatchTs.diagnostics.length === 0 ? 'ok' : 'error', dispatchTs.manifest.summary));
2594
+ if (dispatchTs.diagnostics.length > 0) {
2595
+ throw new ExtractionError(dispatchTs.diagnostics, { passes, source, summary: ir.summary });
2596
+ }
2597
+ }
2598
+
2599
+ const emittedArtifacts = ['symbol-index.json', 'handler-table.json', 'handler-eval.json', 'path-table.json', 'dispatch-table.json', 'execution-plan.json', 'router-ir.json', 'router-tree.json', 'route-plan.json', 'route-id-map.json', 'diagnostics.json']
2600
+ .concat((options.emitAssemblyScriptShape || options.emitAssemblyScriptCore) ? ['assemblyscript-shape.json', 'generated/as/manifest.json', 'generated/as/types.as.ts', 'generated/as/route-table.as.ts', 'generated/as/dispatch-shape.as.ts', 'generated/as/index.as.ts'] : [])
2601
+ .concat(options.emitAssemblyScriptCore ? ['assemblyscript-core.json', 'assemblyscript-handlers.json', 'generated/as/runtime-path.as.ts', 'generated/as/handler-slots.as.ts', 'generated/as/runtime-core.as.ts', 'generated/as/index.as.ts'] : [])
2602
+ .concat(options.emitAssemblyScriptCompile ? ['assemblyscript-compile.json', 'generated/as-smoke/pulsewasm-smoke.wasm', 'generated/as-smoke/pulsewasm-smoke.wat'] : [])
2603
+ .concat(options.emitWasmSmoke ? ['assemblyscript-wasm-smoke.json', 'generated/as-smoke/smoke-runner.as.ts', 'generated/wasm-smoke/pulsewasm-local-smoke.wasm', 'generated/wasm-smoke/pulsewasm-local-smoke.wat'] : [])
2604
+ .concat(options.emitWasmHostAbi ? ['wasm-host-abi.json', 'generated/host/wasm-host-abi.md'] : [])
2605
+ .concat(options.emitWasmHostBridge ? ['wasm-host-bridge.json', 'generated/host-bridge/host-bridge-runner.as.ts', 'generated/wasm-bridge/pulsewasm-host-bridge.wasm', 'generated/wasm-bridge/pulsewasm-host-bridge.wat'] : [])
2606
+ .concat(options.emitRequestResultHeaders ? ['request-result-headers.json', 'generated/host/request-result-headers.md'] : [])
2607
+ .concat(options.emitChannelBroadcaster ? ['channel-broadcaster.json', 'generated/host/channel-broadcaster.md'] : [])
2608
+ .concat(options.emitJsonBody ? ['json-body.json', 'deployment-posture.json', 'generated/host/json-body.md'] : [])
2609
+ .concat(options.emitBackendCapabilities ? ['backend-capabilities.json', 'generated/host/backend-capabilities.md'].concat(options.emitJsonBody ? [] : ['deployment-posture.json']) : [])
2610
+ .concat(options.emitHostRuntimeKernel ? ['host-runtime-kernel.json', 'generated/host/host-runtime-kernel.cjs'] : [])
2611
+ .concat(options.emitNodeAdapter ? ['node-adapter.json', 'generated/node/node-adapter.cjs'] : [])
2612
+ .concat(options.emitHandlerLibraryContracts ? ['handler-library-contracts.json', 'handler-execution-modes.json', 'library-contract-schema.json', 'library-capabilities.json', 'library-compatibility-report.json', 'generated/host/handler-library-contracts.md'] : [])
2613
+ .concat(options.emitAssetsLoweringPlan ? ['assets-lowering-plan.json'] : [])
2614
+ .concat(options.emitAssetsCompiledWasmSidecarPlan ? ['assets-compiled-wasm-sidecar-plan.json'] : [])
2615
+ .concat(options.emitAssetsSidecarCompileLinkProof ? ['assets-sidecar-compile-link-proof.json'] : [])
2616
+ .concat(options.emitNodeAssetsProviderProof ? ['node-assets-provider-proof.json'] : [])
2617
+ .concat(options.emitNodeCompiledWasmAssetsLifecycleProof ? ['node-compiled-wasm-assets-lifecycle-proof.json'] : [])
2618
+ .concat(options.emitFastlyAssetsProviderProof ? ['fastly-assets-provider-proof.json'] : [])
2619
+ .concat(options.emitFastlyAssetsPackageOutParityProof ? ['fastly-assets-package-out-parity-proof.json'] : [])
2620
+ .concat(options.emitRouteHandlerEffectPlan ? ['route-handler-effect-plan.json'] : [])
2621
+ .concat(options.emitNodeRouteHandlerEffectProof ? ['node-route-handler-effect-proof.json'] : [])
2622
+ .concat(options.emitFastlyRouteHandlerEffectProof ? ['fastly-route-handler-effect-proof.json'] : [])
2623
+ .concat(options.emitFastlyLifecycleParityProof ? ['fastly-lifecycle-parity-proof.json'] : [])
2624
+ .concat(options.emitRouteHandlerContextLoweringPlan ? ['route-handler-context-lowering-plan.json'] : [])
2625
+ .concat(options.emitHandlerIoLifecyclePlan ? ['handler-io-lifecycle-plan.json'] : [])
2626
+ .concat(options.emitRequestJsonBodyPlan ? ['request-json-body-plan.json'] : [])
2627
+ .concat(options.emitSchemaDecodeResultPlan ? ['schema-decode-result-plan.json'] : [])
2628
+ .concat(options.emitNodeRequestJsonBodyProof ? ['node-request-json-body-proof.json'] : [])
2629
+ .concat(options.emitNodeSchemaDecodeResultProof ? ['node-schema-decode-result-proof.json'] : [])
2630
+ .concat(options.emitHostCapabilities ? ['host-capabilities.json', 'host-capability-contract.json', 'wasi-provider-map.json', 'capability-provider-report.json', 'generated/host/host-capabilities.md'] : [])
2631
+ .concat(options.emitEffectRuntime ? ['effect-runtime.json', 'effect-runtime-contract.json', 'effect-kind-registry.json', 'effect-resume-protocol.json', 'effect-timeout-policy.json', 'generated/host/effect-runtime.md'] : [])
2632
+ .concat(options.emitEffectComposition ? ['effect-composition.json', 'effect-plan-contract.json', 'effect-continuation-contract.json', 'timeout-scope-policy.json', 'generated/host/effect-composition.md'] : [])
2633
+ .concat(schemaJsonCompile ? ['schema-json-compile.json', 'schema-json-compile-smoke.json', 'generated/host/schema-json-compile.md'] : [])
2634
+ .concat(schemaJsonGenericParser ? ['schema-json-generic-parser.json', 'schema-json-generic-parser-plan.json', 'schema-json-generic-parser-abi.json', 'schema-json-generic-parser-smoke.json', 'schema-json-plan.json', 'schema-json-parser-report.json', 'schema-json-registry.json', 'schema-json-sidecar-abi.json', 'schema-json-body-policy.json', 'generated/as/schema-json/generic/as-json-parser.as.ts', 'generated/as-smoke/schema-json-generic-parser-smoke-runner.as.ts', 'generated/schema-json-generic-parser/pulsewasm-schema-json-generic-parser.wasm', 'generated/schema-json-generic-parser/pulsewasm-schema-json-generic-parser.wat', 'generated/host/schema-json-generic-parser.md'] : [])
2635
+ .concat(options.emitSchemaJsonSidecar && !schemaJsonGenericParser ? ['schema-json-sidecar.json', 'schema-json-plan.json', 'schema-json-parser-report.json', 'schema-json-registry.json', 'schema-json-sidecar-abi.json', 'schema-json-body-policy.json', 'schema-json-smoke.json', 'generated/as/schema-json/app/create-user-body.as.ts', 'generated/as/schema-json/auth/login-body.as.ts', 'generated/as-smoke/schema-json-smoke-runner.as.ts', 'generated/schema-json/pulsewasm-schema-json.wasm', 'generated/schema-json/pulsewasm-schema-json.wat', 'generated/host/schema-json-sidecar.md'] : [])
2636
+ .concat(options.emitLibrarySidecars ? ['library-sidecar-consumption.json', 'api-surface.json', 'ctx-extension-scope-map.json', 'lifecycle-ordering.json', 'library-sidecar-smoke.json', 'generated/as/library-sidecars/test-extension.as.ts', 'generated/as-smoke/library-sidecar-smoke-runner.as.ts', 'generated/library-sidecars/pulsewasm-library-sidecar.wasm', 'generated/library-sidecars/pulsewasm-library-sidecar.wat', 'generated/host/library-sidecar-consumption.md'] : [])
2637
+ .concat(options.emitStreamingPassthrough ? ['streaming-passthrough.json', 'stream-result-abi.json', 'response-passthrough-policy.json', 'streaming-passthrough-smoke.json', 'generated/host/streaming-passthrough.md'] : [])
2638
+ .concat(options.emitCompiledHandlers ? ['compiled-handler-plan.json', 'handler-lowering-report.json', 'compiled-handler-hardening.json', 'compiled-handler-smoke.json', 'generated/as/user-handlers.as.ts', 'generated/as/handler-slots.as.ts', 'generated/as-smoke/compiled-handler-smoke-runner.as.ts', 'generated/compiled-handlers/pulsewasm-compiled-handlers.wasm', 'generated/compiled-handlers/pulsewasm-compiled-handlers.wat'] : [])
2639
+ .concat(options.emitIntegratedCompiledApp ? ['integrated-compiled-app.json', 'integrated-link-report.json', 'integrated-compiled-app-smoke.json', 'generated/as/user-handlers.as.ts', 'generated/as/handler-slots.as.ts', 'generated/as-smoke/integrated-compiled-app-smoke-runner.as.ts', 'generated/integrated-compiled-app/pulsewasm-integrated-compiled-app.wasm', 'generated/integrated-compiled-app/pulsewasm-integrated-compiled-app.wat', 'generated/host/integrated-compiled-app.md'] : [])
2640
+ .concat(options.emitCompiledWasmRuntime ? ['compiled-wasm-runtime.json', 'compiled-wasm-host-runtime.json', 'compiled-wasm-node-adapter.json', 'compiled-wasm-runtime-smoke.json', 'generated/as/user-handlers.as.ts', 'generated/as/handler-slots.as.ts', 'generated/host-bridge/compiled-host-bridge-runner.as.ts', 'generated/compiled-wasm-runtime/pulsewasm-compiled-runtime.wasm', 'generated/host/compiled-wasm-host-runtime.cjs', 'generated/node/compiled-wasm-node-adapter.cjs', 'generated/host/compiled-wasm-runtime.md'] : [])
2641
+ .concat(options.emitPulseWrapper ? ['wrapper-integration.json', 'pulse-build-output.json', 'pulse-dev-runtime.json', 'generated/pulse/pulse-wrapper.cjs', 'generated/host/pulse-wrapper-integration.md'] : [])
2642
+ .concat(options.emitFastlyReadiness ? ['fastly-readiness.json', 'fastly-sdk-audit.json', 'fastly-hostcall-map.json', 'fastly-capability-map.json', 'fastly-packaging-plan.json', 'fastly-risk-report.json', 'fastly-adapter-plan.json', 'generated/host/fastly-readiness.md'] : [])
2643
+ .concat(options.emitFastlyHostcallBinding ? ['fastly-hostcall-binding-contract.json', 'fastly-hostcall-modules.json', 'fastly-ref-lifecycle.json', 'fastly-stream-binding-plan.json', 'fastly-pack-inputs.json', 'fastly-binding-risk-report.json', 'generated/host/fastly-hostcall-binding-contract.md'] : [])
2644
+ .concat(options.emitFastlyAdapter ? ['fastly-adapter.json', 'fastly-stream-header-adapter.json', 'fastly-local-smoke.json', 'fastly-packaging-smoke.json', 'fastly-deployment-readiness.json', 'generated/fastly/fastly-adapter.cjs', 'generated/fastly/fastly.toml', 'generated/fastly/README.md', 'generated/fastly/pulsewasm-compute.wasm', 'generated/host/fastly-stream-header-adapter.md'] : [])
2645
+ .concat(options.emitFastlyCommandEntry ? ['fastly-command-entry.json', 'fastly-start-export-audit.json', 'fastly-command-import-audit.json', 'fastly-serve-gate.json', 'fastly-command-smoke.json', 'generated/fastly/fastly-entry.as.ts', 'generated/fastly/fastly.toml', 'generated/fastly/README.md', 'generated/fastly/pulsewasm-compute.wasm', 'generated/host/fastly-command-entry.md'] : [])
2646
+ .concat((options.emitHandlerBindings || options.emitExecutionHarness) ? ['handler-bindings.json'] : [])
2647
+ .concat(options.emitExecutionHarness ? ['execution-harness.json'] : [])
2648
+ .concat(options.emitLocalHarness ? ['local-harness.json'] : [])
2649
+ .concat(options.includeAst ? ['ast.json'] : [])
2650
+ .concat(dispatchTs ? ['generated/manifest.json', 'generated/types.ts', 'generated/route-table.ts', 'generated/dispatch.ts'] : [])
2651
+ .concat((options.emitHandlerBindings || options.emitExecutionHarness) ? ['generated/handler-slots.ts'] : [])
2652
+ .concat(options.emitExecutionHarness ? ['generated/execution-plan.ts', 'generated/execution-harness.ts'] : [])
2653
+ .concat(options.emitLocalHarness ? ['generated/local-harness.ts'] : [])
2654
+ .concat(dispatchTs ? ['generated/index.ts'] : []);
2655
+ passes.push(makePass('emit', 'ok', {
2656
+ artifacts: emittedArtifacts
2657
+ }));
2658
+
2659
+ const summary = extractionSummary({ sourceFile, ir: resolvedIR, routerTree, routePlan, handlerTable: handlerResolution.handlerTable, handlerEval: handlerEvaluation.handlerEval, dispatchTable, executionPlan, handlerBindings, executionHarness, localHarness, assemblyScriptShape, assemblyScriptCore, assemblyScriptCompile, assemblyScriptWasmSmoke, wasmHostAbi, wasmHostBridge, requestResultHeaders, channelBroadcaster, jsonBody, backendCapabilities, deploymentPosture, hostRuntimeKernel, nodeAdapter, streamingPassthrough, handlerLibraryContracts, assetsLoweringPlan, assetsSidecarCompileLinkProof, assetsCompiledWasmSidecarPlan, nodeAssetsProviderProof, nodeCompiledWasmAssetsLifecycleProof, fastlyAssetsProviderProof, fastlyAssetsPackageOutParityProof, routeHandlerEffectPlan, nodeRouteHandlerEffectProof, fastlyRouteHandlerEffectProof, fastlyLifecycleParityProof, routeHandlerContextLoweringPlan, handlerIoLifecyclePlan, requestJsonBodyPlan, schemaDecodeResultPlan, schemaResponseCodecPlan, backendJsonRequestBodyPlan, nodeRequestJsonBodyProof, nodeSchemaDecodeResultProof, nodeSchemaResponseCodecProof, hostCapabilities, effectRuntime, effectComposition, compiledHandlers, schemaJsonCompile, schemaJsonGenericParser, schemaJsonSidecar, librarySidecars, integratedCompiledApp, compiledWasmRuntime, pulseWrapper, fastlyReadiness, fastlyHostcallBinding, fastlyAdapter, fastlyCommandEntry, dispatchTs, includeAst: options.includeAst, cwd });
2660
+ const diagnosticsArtifact = {
2661
+ version: DIAGNOSTICS_VERSION,
2662
+ generatedBy: PACKAGE_VERSION,
2663
+ source: stableFileName(sourceFile.fileName, cwd),
2664
+ status: 'ok',
2665
+ diagnostics: [],
2666
+ passes: normalizeArtifact(passes, cwd),
2667
+ summary: normalizeArtifact(summary, cwd)
2668
+ };
2669
+
2670
+ return {
2671
+ sourceFile,
2672
+ symbolIndex: normalizeArtifact(ir.symbolIndex, cwd),
2673
+ ast: options.includeAst
2674
+ ? normalizeArtifact({
2675
+ version: 'pulsewasm.ast.v1',
2676
+ generatedBy: PACKAGE_VERSION,
2677
+ source: stableFileName(sourceFile.fileName, cwd),
2678
+ ast: astToJson(ts, sourceFile)
2679
+ }, cwd)
2680
+ : undefined,
2681
+ routerIR: normalizeArtifact({
2682
+ version: 'pulsewasm.router-ir.v1',
2683
+ generatedBy: PACKAGE_VERSION,
2684
+ source: stableFileName(sourceFile.fileName, cwd),
2685
+ routers: resolvedIR.routerIR,
2686
+ handlerDeclarations: ir.handlerIR,
2687
+ handlers: handlerResolution.handlerTable.handlers
2688
+ }, cwd),
2689
+ routerTree,
2690
+ handlerTable: handlerResolution.handlerTable,
2691
+ handlerEval: handlerEvaluation.handlerEval,
2692
+ pathTable,
2693
+ dispatchTable,
2694
+ executionPlan,
2695
+ handlerBindings,
2696
+ executionHarness,
2697
+ localHarness,
2698
+ assemblyScriptShape,
2699
+ assemblyScriptCore,
2700
+ assemblyScriptCompile,
2701
+ assemblyScriptWasmSmoke,
2702
+ wasmHostAbi,
2703
+ wasmHostBridge,
2704
+ requestResultHeaders,
2705
+ channelBroadcaster,
2706
+ jsonBody,
2707
+ backendCapabilities,
2708
+ deploymentPosture,
2709
+ hostRuntimeKernel,
2710
+ nodeAdapter,
2711
+ streamingPassthrough,
2712
+ integratedCompiledApp,
2713
+ compiledWasmRuntime,
2714
+ pulseWrapper,
2715
+ fastlyReadiness,
2716
+ fastlyHostcallBinding,
2717
+ fastlyAdapter,
2718
+ fastlyCommandEntry,
2719
+ handlerLibraryContracts,
2720
+ assetsLoweringPlan,
2721
+ assetsCompiledWasmSidecarPlan,
2722
+ assetsSidecarCompileLinkProof,
2723
+ nodeAssetsProviderProof,
2724
+ nodeCompiledWasmAssetsLifecycleProof,
2725
+ fastlyAssetsProviderProof,
2726
+ fastlyAssetsPackageOutParityProof,
2727
+ routeHandlerEffectPlan,
2728
+ nodeRouteHandlerEffectProof,
2729
+ fastlyRouteHandlerEffectProof,
2730
+ fastlyLifecycleParityProof,
2731
+ routeHandlerContextLoweringPlan,
2732
+ handlerIoLifecyclePlan,
2733
+ requestJsonBodyPlan,
2734
+ nodeRequestJsonBodyProof,
2735
+ schemaDecodeResultPlan,
2736
+ schemaResponseCodecPlan,
2737
+ backendJsonRequestBodyPlan,
2738
+ nodeSchemaDecodeResultProof,
2739
+ nodeSchemaResponseCodecProof,
2740
+ hostCapabilities,
2741
+ effectRuntime,
2742
+ effectComposition,
2743
+ compiledHandlers,
2744
+ schemaJsonCompile,
2745
+ schemaJsonGenericParser,
2746
+ schemaJsonSidecar,
2747
+ librarySidecars,
2748
+ integratedCompiledApp,
2749
+ compiledWasmRuntime,
2750
+ dispatchTs,
2751
+ routePlan,
2752
+ routeIdMap,
2753
+ diagnostics: diagnosticsArtifact,
2754
+ passes,
2755
+ summary
2756
+ };
2757
+ }
2758
+
2759
+ function extractFromFile(filePath, options = {}) {
2760
+ const sourceFile = readSourceFile(filePath);
2761
+ return extractFromSourceFile(sourceFile, options);
2762
+ }
2763
+
2764
+ module.exports = {
2765
+ SUPPORTED_METHODS,
2766
+ ROUTE_METHODS,
2767
+ ROUTE_ID_POLICY,
2768
+ ROUTE_PLAN_VERSION,
2769
+ DEFAULT_ROUTER_API_REGISTRY,
2770
+ buildRouterApiRegistry,
2771
+ extractFromFile,
2772
+ extractFromSourceFile,
2773
+ flattenRouterTree,
2774
+ createRoutePlan,
2775
+ createRoutePlanResult,
2776
+ createRouteIdMap,
2777
+ buildDispatchTable,
2778
+ buildExecutionPlan,
2779
+ buildTypeScriptDispatch,
2780
+ buildTypeScriptHandlerBindings,
2781
+ buildAssemblyScriptCore,
2782
+ buildAssemblyScriptCompileSmoke,
2783
+ buildAssemblyScriptWasmSmoke,
2784
+ buildWasmHostAbi,
2785
+ buildWasmHostBridge,
2786
+ buildHostRuntimeKernel,
2787
+ buildHostCapabilities,
2788
+ buildEffectRuntime,
2789
+ buildEffectComposition,
2790
+ buildRouteHandlerEffectPlan,
2791
+ buildRouteHandlerContextLoweringPlan,
2792
+ buildHandlerIoLifecyclePlan,
2793
+ buildSchemaResponseCodecPlan,
2794
+ buildBackendJsonRequestBodyPlan,
2795
+ buildCompiledUserHandlers,
2796
+ buildSchemaJsonCompile,
2797
+ buildSchemaJsonGenericParser,
2798
+ buildSchemaJsonSidecar,
2799
+ buildLibrarySidecarConsumption,
2800
+ buildIntegratedCompiledApp,
2801
+ buildChannelBroadcaster,
2802
+ buildJsonBodyAbi,
2803
+ buildDeploymentPosture,
2804
+ buildTypeScriptLocalHarness,
2805
+ resolveRouterTree,
2806
+ resolveRouterTreeFromIR,
2807
+ buildRouterIR,
2808
+ indexSourceFile,
2809
+ extractRouterOperations,
2810
+ parseRouterOperation,
2811
+ validateIR,
2812
+ normalizePathIR,
2813
+ parseDiagnostics,
2814
+ readSourceFile,
2815
+ refToString
2816
+ };