@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,155 @@
1
+ 'use strict';
2
+
3
+ const { defineCompilerSpineSegment, definePhaseAdapter } = require('./pipeline.js');
4
+ const {
5
+ inspectCanonicalRouterSurfaces,
6
+ classifyCanonicalRouterSurfaces
7
+ } = require('./handler-surface-authority.js');
8
+ const {
9
+ prepareCanonicalRouterTopology
10
+ } = require('./router-topology-frontend.js');
11
+ const {
12
+ prepareCanonicalRouterHandlers
13
+ } = require('./router-handler-frontend.js');
14
+ const {
15
+ emitCanonicalRouterFromHandlerIrs
16
+ } = require('./router-handler-ir.js');
17
+
18
+ const traces = new WeakMap();
19
+ const handlerIrBundles = new WeakMap();
20
+ const surfaceFacts = new WeakMap();
21
+ const topologies = new WeakMap();
22
+
23
+ const CANONICAL_ROUTER_SPINE = defineCompilerSpineSegment({
24
+ id: 'pulse.compiler.canonical-router.v1',
25
+ phases: [
26
+ 'root-extraction',
27
+ 'surface-recognition',
28
+ 'surface-normalization',
29
+ 'semantic-classification',
30
+ 'contract-validation',
31
+ 'canonical-ir'
32
+ ],
33
+ adapters: [
34
+ definePhaseAdapter({
35
+ id: 'pulse.router.root-extraction',
36
+ phase: 'root-extraction',
37
+ mode: 'router-topology-frontend',
38
+ inputKind: 'router-source-request',
39
+ outputKind: 'canonical-router-topology',
40
+ run({ value }) {
41
+ return prepareCanonicalRouterTopology(value.sourceText, value.options || {});
42
+ }
43
+ }),
44
+ definePhaseAdapter({
45
+ id: 'pulse.shared.router.surface-recognition',
46
+ phase: 'surface-recognition',
47
+ mode: 'shared-router-surface-recognition',
48
+ inputKind: 'canonical-router-topology',
49
+ outputKind: 'recognized-canonical-router',
50
+ run({ value }) {
51
+ return Object.freeze({
52
+ topology: value,
53
+ recognition: inspectCanonicalRouterSurfaces(value, value.options || {})
54
+ });
55
+ }
56
+ }),
57
+ definePhaseAdapter({
58
+ id: 'pulse.shared.router.surface-normalization',
59
+ phase: 'surface-normalization',
60
+ mode: 'behavior-preserving-router-normalization-boundary',
61
+ inputKind: 'recognized-canonical-router',
62
+ outputKind: 'normalized-canonical-router',
63
+ run({ value }) {
64
+ return Object.freeze({
65
+ ...value,
66
+ normalization: Object.freeze({ changed: false, behaviorChangeAllowed: false })
67
+ });
68
+ }
69
+ }),
70
+ definePhaseAdapter({
71
+ id: 'pulse.shared.router.semantic-classification',
72
+ phase: 'semantic-classification',
73
+ mode: 'shared-router-semantic-classification',
74
+ inputKind: 'normalized-canonical-router',
75
+ outputKind: 'classified-canonical-router',
76
+ run({ value }) {
77
+ return Object.freeze({
78
+ ...value,
79
+ classification: classifyCanonicalRouterSurfaces(value.recognition, value.topology.options || {})
80
+ });
81
+ }
82
+ }),
83
+ definePhaseAdapter({
84
+ id: 'pulse.router.handler.contract-validation',
85
+ phase: 'contract-validation',
86
+ mode: 'router-handler-frontend-validation',
87
+ inputKind: 'classified-canonical-router',
88
+ outputKind: 'validated-router-handlers',
89
+ run({ value }) {
90
+ const prepared = prepareCanonicalRouterHandlers(value.topology, value.recognition, value.classification);
91
+ return Object.freeze({ ...value, prepared });
92
+ }
93
+ }),
94
+ definePhaseAdapter({
95
+ id: 'pulse.shared.router.canonical-handler-ir',
96
+ phase: 'canonical-ir',
97
+ mode: 'shared-router-handler-ir',
98
+ inputKind: 'validated-router-handlers',
99
+ outputKind: 'canonical-router-handler-ir-bundle',
100
+ run({ value }) {
101
+ return Object.freeze({
102
+ ...emitCanonicalRouterFromHandlerIrs(value.prepared),
103
+ recognition: value.recognition,
104
+ classification: value.classification,
105
+ normalization: value.normalization,
106
+ topology: value.topology,
107
+ validation: value.prepared.validation
108
+ });
109
+ }
110
+ })
111
+ ]
112
+ });
113
+
114
+ function executeCanonicalRouterSpine(sourceText, options = {}) {
115
+ const result = CANONICAL_ROUTER_SPINE.run(Object.freeze({ sourceText, options }));
116
+ const bundle = result.output;
117
+ const output = bundle.output;
118
+ if (output && typeof output === 'object') {
119
+ traces.set(output, result.trace);
120
+ handlerIrBundles.set(output, bundle.handlers);
121
+ surfaceFacts.set(output, Object.freeze({
122
+ recognition: bundle.recognition,
123
+ classification: bundle.classification,
124
+ normalization: bundle.normalization,
125
+ validation: bundle.validation
126
+ }));
127
+ topologies.set(output, bundle.topology);
128
+ }
129
+ return output;
130
+ }
131
+
132
+ function traceForCanonicalRouterOutput(output) {
133
+ return output && typeof output === 'object' ? traces.get(output) : undefined;
134
+ }
135
+
136
+ function handlerIrsForCanonicalRouterOutput(output) {
137
+ return output && typeof output === 'object' ? handlerIrBundles.get(output) : undefined;
138
+ }
139
+
140
+ function surfaceFactsForCanonicalRouterOutput(output) {
141
+ return output && typeof output === 'object' ? surfaceFacts.get(output) : undefined;
142
+ }
143
+
144
+ function topologyForCanonicalRouterOutput(output) {
145
+ return output && typeof output === 'object' ? topologies.get(output) : undefined;
146
+ }
147
+
148
+ module.exports = Object.freeze({
149
+ CANONICAL_ROUTER_SPINE,
150
+ executeCanonicalRouterSpine,
151
+ traceForCanonicalRouterOutput,
152
+ handlerIrsForCanonicalRouterOutput,
153
+ surfaceFactsForCanonicalRouterOutput,
154
+ topologyForCanonicalRouterOutput
155
+ });
@@ -0,0 +1,165 @@
1
+ 'use strict';
2
+
3
+ const { defineCompilerSpineSegment, definePhaseAdapter } = require('./pipeline.js');
4
+ const {
5
+ inspectCanonicalSourceSurfaces,
6
+ classifyCanonicalSourceSurfaces
7
+ } = require('./handler-surface-authority.js');
8
+ const {
9
+ preparePlainHandlerSource,
10
+ assertPlainHandlerDiagnostics
11
+ } = require('./plain-handler-frontend.js');
12
+ const {
13
+ buildPlainHandlerIr
14
+ } = require('./handler-ir.js');
15
+ const {
16
+ createCanonicalHandlerIr,
17
+ payloadForCanonicalHandlerIr
18
+ } = require('./canonical-handler-ir.js');
19
+
20
+ const traces = new WeakMap();
21
+ const handlerIrs = new WeakMap();
22
+
23
+ const CANONICAL_SOURCE_SPINE = defineCompilerSpineSegment({
24
+ id: 'pulse.compiler.canonical-source.v1',
25
+ phases: [
26
+ 'surface-recognition',
27
+ 'surface-normalization',
28
+ 'semantic-classification',
29
+ 'contract-validation',
30
+ 'canonical-ir'
31
+ ],
32
+ adapters: [
33
+ definePhaseAdapter({
34
+ id: 'pulse.shared.canonical-source.surface-recognition',
35
+ phase: 'surface-recognition',
36
+ mode: 'shared-surface-recognition',
37
+ inputKind: 'canonical-source-request',
38
+ outputKind: 'recognized-canonical-source-request',
39
+ run({ value, context }) {
40
+ return Object.freeze({
41
+ request: value,
42
+ recognition: context.inspectSurfaces(value.sourceText, value.options || {})
43
+ });
44
+ }
45
+ }),
46
+ definePhaseAdapter({
47
+ id: 'pulse.shared.canonical-source.surface-normalization',
48
+ phase: 'surface-normalization',
49
+ mode: 'behavior-preserving-normalization-boundary',
50
+ inputKind: 'recognized-canonical-source-request',
51
+ outputKind: 'normalized-canonical-source-request',
52
+ run({ value }) {
53
+ return Object.freeze({ ...value, normalization: Object.freeze({ changed: false }) });
54
+ }
55
+ }),
56
+ definePhaseAdapter({
57
+ id: 'pulse.shared.canonical-source.semantic-classification',
58
+ phase: 'semantic-classification',
59
+ mode: 'shared-semantic-classification',
60
+ inputKind: 'normalized-canonical-source-request',
61
+ outputKind: 'classified-canonical-source-request',
62
+ run({ value, context }) {
63
+ return Object.freeze({
64
+ ...value,
65
+ classification: context.classifySurfaces(value.recognition, value.request.options || {})
66
+ });
67
+ }
68
+ }),
69
+ definePhaseAdapter({
70
+ id: 'pulse.plain-handler.canonical-source.contract-validation',
71
+ phase: 'contract-validation',
72
+ mode: 'plain-handler-frontend-validation',
73
+ inputKind: 'classified-canonical-source-request',
74
+ outputKind: 'validated-canonical-handler-source',
75
+ run({ value }) {
76
+ const frontend = preparePlainHandlerSource(value.request.sourceText, value.request.options || {}, value.recognition);
77
+ return Object.freeze({
78
+ ...value,
79
+ frontend,
80
+ validation: Object.freeze({
81
+ authority: 'plain-handler-frontend',
82
+ frontendVersion: frontend.version,
83
+ recognitionAstReused: frontend.reusedRecognitionAst,
84
+ behaviorChangeAllowed: false
85
+ })
86
+ });
87
+ }
88
+ }),
89
+ definePhaseAdapter({
90
+ id: 'pulse.shared.canonical-source.canonical-handler-ir',
91
+ phase: 'canonical-ir',
92
+ mode: 'shared-canonical-handler-ir',
93
+ inputKind: 'validated-canonical-handler-source',
94
+ outputKind: 'canonical-handler-ir',
95
+ run({ value, context }) {
96
+ const operationIr = buildPlainHandlerIr(value.frontend, value.request.options || {});
97
+ assertPlainHandlerDiagnostics(value.frontend);
98
+ return createCanonicalHandlerIr({
99
+ frontend: value.frontend,
100
+ operationIr,
101
+ options: value.request.options || {},
102
+ compilerVersion: context.compilerVersion,
103
+ programVersion: context.programVersion,
104
+ runtimeProtocolVersion: context.runtimeProtocolVersion,
105
+ surfaceFacts: Object.freeze({
106
+ recognition: value.recognition,
107
+ classification: value.classification,
108
+ normalization: value.frontend.normalization || value.normalization,
109
+ validation: value.validation
110
+ })
111
+ });
112
+ }
113
+ })
114
+ ]
115
+ });
116
+
117
+ function executeCanonicalSourceSpine(sourceText, options, implementation) {
118
+ if (!implementation || typeof implementation !== 'object') {
119
+ throw new TypeError('executeCanonicalSourceSpine requires a canonical-source implementation object.');
120
+ }
121
+ for (const name of ['compilerVersion', 'programVersion', 'runtimeProtocolVersion']) {
122
+ if (typeof implementation[name] !== 'string' || implementation[name].length === 0) {
123
+ throw new TypeError(`executeCanonicalSourceSpine requires ${name}.`);
124
+ }
125
+ }
126
+ if (typeof implementation.emitCanonicalProgram !== 'function') {
127
+ throw new TypeError('executeCanonicalSourceSpine requires emitCanonicalProgram.');
128
+ }
129
+ const result = CANONICAL_SOURCE_SPINE.run(Object.freeze({ sourceText, options }), {
130
+ compilerVersion: implementation.compilerVersion,
131
+ programVersion: implementation.programVersion,
132
+ runtimeProtocolVersion: implementation.runtimeProtocolVersion,
133
+ inspectSurfaces: inspectCanonicalSourceSurfaces,
134
+ classifySurfaces: classifyCanonicalSourceSurfaces
135
+ });
136
+ const output = implementation.emitCanonicalProgram(result.output);
137
+ if (output && typeof output === 'object') {
138
+ traces.set(output, result.trace);
139
+ handlerIrs.set(output, result.output);
140
+ }
141
+ return output;
142
+ }
143
+
144
+ function traceForCanonicalSourceOutput(output) {
145
+ return output && typeof output === 'object' ? traces.get(output) : undefined;
146
+ }
147
+
148
+ function handlerIrForCanonicalSourceOutput(output) {
149
+ return output && typeof output === 'object' ? handlerIrs.get(output) : undefined;
150
+ }
151
+
152
+ function surfaceFactsForCanonicalSourceOutput(output) {
153
+ const ir = handlerIrForCanonicalSourceOutput(output);
154
+ if (!ir) return undefined;
155
+ const payload = payloadForCanonicalHandlerIr(ir);
156
+ return payload && payload.surfaceFacts;
157
+ }
158
+
159
+ module.exports = Object.freeze({
160
+ CANONICAL_SOURCE_SPINE,
161
+ executeCanonicalSourceSpine,
162
+ traceForCanonicalSourceOutput,
163
+ handlerIrForCanonicalSourceOutput,
164
+ surfaceFactsForCanonicalSourceOutput
165
+ });
@@ -0,0 +1,290 @@
1
+ 'use strict';
2
+
3
+ const DIAGNOSTIC_AUTHORITY_VERSION = 'pulse.compiler-handler-diagnostics.v1';
4
+
5
+ const FRONTENDS = Object.freeze({
6
+ 'canonical-source': Object.freeze({ kind: 'CanonicalCompileDiagnostic' }),
7
+ 'canonical-router': Object.freeze({ kind: 'CanonicalRouterCompileDiagnostic' })
8
+ });
9
+
10
+ function message(value) {
11
+ return typeof value === 'function' ? value : () => String(value);
12
+ }
13
+
14
+ function descriptor(definition) {
15
+ return Object.freeze({
16
+ ...definition,
17
+ message: message(definition.message)
18
+ });
19
+ }
20
+
21
+ const HANDLER_DIAGNOSTIC_CATALOG = Object.freeze({
22
+ 'handler.async.required': Object.freeze({
23
+ 'canonical-source': descriptor({
24
+ code: 'PULSE_HANDLER_ASYNC_REQUIRED',
25
+ message: ({ role }) => `Managed Pulse ${role || 'handler'} must be declared async. Native lowering erases the wrapper and does not include a Promise runtime.`
26
+ }),
27
+ 'canonical-router': descriptor({
28
+ code: 'PULSE_HANDLER_ASYNC_REQUIRED',
29
+ message: ({ role }) => `Managed Pulse ${role || 'handler'} must be declared async. Native lowering erases the wrapper and does not include a Promise runtime.`
30
+ })
31
+ }),
32
+ 'handler.async.unsupported': Object.freeze({
33
+ 'canonical-source': descriptor({
34
+ code: 'PULSE_CANONICAL_ASYNC_HANDLER_UNSUPPORTED',
35
+ message: 'Canonical handlers are synchronous user functions; the compiler owns suspension.'
36
+ }),
37
+ 'canonical-router': descriptor({
38
+ code: 'PULSE_CANONICAL_ROUTER_ASYNC_HANDLER_UNSUPPORTED',
39
+ message: 'Router handlers are synchronous authoring functions; the compiler owns suspension.'
40
+ })
41
+ }),
42
+ 'handler.await.unsupported': Object.freeze({
43
+ 'canonical-source': descriptor({
44
+ code: 'PULSE_CANONICAL_AWAIT_UNSUPPORTED',
45
+ message: 'Canonical handlers do not expose await/Promise semantics.'
46
+ })
47
+ }),
48
+ 'handler.async-function.unsupported': Object.freeze({
49
+ 'canonical-source': descriptor({
50
+ code: 'PULSE_CANONICAL_ASYNC_FUNCTION_UNSUPPORTED',
51
+ message: 'Async functions are not available inside canonical handlers; the compiler owns suspension.'
52
+ })
53
+ }),
54
+ 'handler.await.native-unsupported': Object.freeze({
55
+ 'canonical-source': descriptor({
56
+ code: 'PULSE_NATIVE_AWAIT_UNSUPPORTED',
57
+ message: ({ expression }) => `Native Pulse supports await only on trusted Pulse effects; ${expression || 'this expression'} is not lowerable.`
58
+ }),
59
+ 'canonical-router': descriptor({
60
+ code: 'PULSE_NATIVE_AWAIT_UNSUPPORTED',
61
+ message: ({ expression }) => `Native Pulse supports await only on trusted Pulse effects; ${expression || 'this expression'} is not lowerable.`
62
+ })
63
+ }),
64
+ 'handler.nested-async-function.unsupported': Object.freeze({
65
+ 'canonical-source': descriptor({
66
+ code: 'PULSE_CANONICAL_NESTED_ASYNC_FUNCTION_UNSUPPORTED',
67
+ message: 'Nested async functions are outside managed Pulse handler lowering.'
68
+ }),
69
+ 'canonical-router': descriptor({
70
+ code: 'PULSE_CANONICAL_ROUTER_NESTED_ASYNC_FUNCTION_UNSUPPORTED',
71
+ message: 'Nested async functions are outside managed Pulse Router handler lowering.'
72
+ })
73
+ }),
74
+ 'handler.promise.unsupported': Object.freeze({
75
+ 'canonical-source': descriptor({
76
+ code: 'PULSE_CANONICAL_PROMISE_UNSUPPORTED',
77
+ message: ({ construction }) => construction
78
+ ? 'Canonical handlers do not expose Promise construction.'
79
+ : 'Canonical handlers do not expose Promise APIs.'
80
+ })
81
+ }),
82
+ 'handler.context-identifier.required': Object.freeze({
83
+ 'canonical-source': descriptor({
84
+ code: 'PULSE_CANONICAL_CTX_IDENTIFIER_REQUIRED',
85
+ message: 'The ctx parameter must be a simple identifier.'
86
+ })
87
+ }),
88
+ 'handler.generator.unsupported': Object.freeze({
89
+ 'canonical-source': descriptor({
90
+ code: 'PULSE_CANONICAL_GENERATOR_HANDLER_UNSUPPORTED',
91
+ message: 'Generator handlers are outside the canonical handler subset.'
92
+ }),
93
+ 'canonical-router': descriptor({
94
+ code: 'PULSE_CANONICAL_ROUTER_GENERATOR_HANDLER_UNSUPPORTED',
95
+ message: 'Generator Router handlers are outside the canonical Router subset.'
96
+ })
97
+ }),
98
+ 'handler.signature.invalid': Object.freeze({
99
+ 'canonical-router': descriptor({
100
+ code: 'PULSE_CANONICAL_ROUTER_HANDLER_SIGNATURE',
101
+ message: ({ role, expected }) => `Canonical ${role} handlers must use ${expected}.`
102
+ })
103
+ }),
104
+ 'handler.nested-function.unsupported': Object.freeze({
105
+ 'canonical-router': descriptor({
106
+ code: 'PULSE_CANONICAL_ROUTER_NESTED_FUNCTION_UNSUPPORTED',
107
+ message: 'Nested functions are outside terminal Router handler lowering. Move helper logic into straight-line handler code.'
108
+ })
109
+ }),
110
+ 'handler.throw.unsupported': Object.freeze({
111
+ 'canonical-router': descriptor({
112
+ code: 'PULSE_CANONICAL_ROUTER_THROW_UNSUPPORTED',
113
+ message: 'Use terminal return next(error) to enter the Router error lane; throw is not part of canonical Router middleware.'
114
+ })
115
+ }),
116
+ 'router.next.not-terminal': Object.freeze({
117
+ 'canonical-router': descriptor({
118
+ code: 'PULSE_CANONICAL_ROUTER_NEXT_NOT_TERMINAL',
119
+ message: ({ reference }) => reference
120
+ ? 'The next control-transfer function may only appear in terminal return next() or return next(error).'
121
+ : 'next() is a terminal Router control transfer and must be used as return next(). The current handler never resumes afterward.'
122
+ })
123
+ }),
124
+ 'router.next.arity': Object.freeze({
125
+ 'canonical-router': descriptor({
126
+ code: 'PULSE_CANONICAL_ROUTER_NEXT_ARITY',
127
+ message: 'next() accepts zero arguments for normal transfer or one error value for error-lane transfer.'
128
+ })
129
+ }),
130
+ 'router.error.shadowed': Object.freeze({
131
+ 'canonical-router': descriptor({
132
+ code: 'PULSE_CANONICAL_ROUTER_ERROR_SHADOWED',
133
+ message: ({ errorName }) => `Error middleware may not shadow its ${errorName} parameter.`
134
+ })
135
+ }),
136
+ 'context.param.outside-route': Object.freeze({
137
+ 'canonical-router': descriptor({
138
+ code: 'PULSE_CANONICAL_ROUTER_PARAM_OUTSIDE_ROUTE',
139
+ message: 'ctx.param() is available only inside a matched route handler.'
140
+ })
141
+ }),
142
+ 'context.param.arity': Object.freeze({
143
+ 'canonical-router': descriptor({
144
+ code: 'PULSE_CANONICAL_ROUTER_PARAM_ARITY',
145
+ message: 'ctx.param() requires exactly one static parameter name.'
146
+ })
147
+ }),
148
+ 'context.param.dynamic': Object.freeze({
149
+ 'canonical-router': descriptor({
150
+ code: 'PULSE_CANONICAL_ROUTER_PARAM_DYNAMIC',
151
+ message: 'ctx.param() requires a string literal parameter name.'
152
+ })
153
+ }),
154
+ 'context.param.unknown': Object.freeze({
155
+ 'canonical-router': descriptor({
156
+ code: 'PULSE_CANONICAL_ROUTER_PARAM_UNKNOWN',
157
+ message: ({ route, name }) => `Route ${route} does not declare parameter ${JSON.stringify(name)}.`
158
+ })
159
+ }),
160
+ 'context.resolve.retired': Object.freeze({
161
+ 'canonical-router': descriptor({
162
+ code: 'PULSE_CANONICAL_ROUTER_RESOLVE_RETIRED',
163
+ message: 'ctx.resolve is not part of canonical Router authoring. Effects are inferred by the canonical compiler.'
164
+ })
165
+ }),
166
+ 'context.resolved.retired': Object.freeze({
167
+ 'canonical-router': descriptor({
168
+ code: 'PULSE_CANONICAL_ROUTER_RESOLVED_RETIRED',
169
+ message: 'ctx.resolved is not part of canonical Router authoring.'
170
+ })
171
+ }),
172
+ 'handler.unreachable-after-terminal': Object.freeze({
173
+ 'canonical-router': descriptor({
174
+ code: 'PULSE_CANONICAL_ROUTER_UNREACHABLE_AFTER_TERMINAL',
175
+ message: 'Statements after a terminal response or next() transfer are unreachable.'
176
+ })
177
+ }),
178
+ 'handler.return-value.required': Object.freeze({
179
+ 'canonical-router': descriptor({
180
+ code: 'PULSE_CANONICAL_ROUTER_RETURN_VALUE_REQUIRED',
181
+ message: 'Router handlers must return a Pulse response or terminal next() transfer.'
182
+ })
183
+ }),
184
+ 'handler.fallthrough': Object.freeze({
185
+ 'canonical-router': descriptor({
186
+ code: 'PULSE_CANONICAL_ROUTER_HANDLER_FALLTHROUGH',
187
+ message: ({ role }) => `Canonical ${role} handlers must return a Pulse response or terminal next() transfer on every path.`
188
+ })
189
+ }),
190
+ 'effect.fetch.position': Object.freeze({
191
+ 'canonical-source': descriptor({
192
+ code: 'PULSE_CANONICAL_FETCH_POSITION_UNSUPPORTED',
193
+ message: 'ctx.fetch must initialize a local variable, appear in a consecutive independent fetch group, or be returned directly for opaque pass-through.'
194
+ })
195
+ }),
196
+ 'effect.fetch.value-return': Object.freeze({
197
+ 'canonical-source': descriptor({
198
+ code: 'PULSE_CANONICAL_FETCH_VALUE_RETURN_UNSUPPORTED',
199
+ message: 'Return a Pulse response, not a decoded fetch body value. Wrap decoded data with ctx.json or ctx.text.'
200
+ })
201
+ }),
202
+ 'effect.provider.position': Object.freeze({
203
+ 'canonical-source': descriptor({
204
+ code: 'PULSE_CANONICAL_PROVIDER_EFFECT_POSITION_UNSUPPORTED',
205
+ message: ({ kind }) => `${kind} must initialize a local variable or, for kv.put, appear as a standalone statement so the compiler can own suspension.`
206
+ })
207
+ }),
208
+ 'effect.package.position': Object.freeze({
209
+ 'canonical-source': descriptor({
210
+ code: 'PULSE_CANONICAL_PACKAGE_EFFECT_POSITION_UNSUPPORTED',
211
+ message: ({ kind, placement }) => placement === 'statement'
212
+ ? `${kind} was not declared as a standalone package effect.`
213
+ : `${kind} must be returned directly from the handler branch.`
214
+ })
215
+ })
216
+ });
217
+
218
+ function positionFor(sourceFile, node) {
219
+ const target = node || sourceFile;
220
+ const offset = target && typeof target.getStart === 'function' ? target.getStart(sourceFile) : 0;
221
+ const point = sourceFile.getLineAndCharacterOfPosition(offset);
222
+ return Object.freeze({ line: point.line + 1, column: point.character + 1, offset });
223
+ }
224
+
225
+ function createCanonicalDiagnostic(options) {
226
+ const frontend = FRONTENDS[options.frontend];
227
+ if (!frontend) throw new TypeError(`Unknown canonical diagnostic frontend: ${options.frontend}`);
228
+ const sourceFile = options.sourceFile;
229
+ if (!sourceFile || typeof sourceFile.getLineAndCharacterOfPosition !== 'function') {
230
+ throw new TypeError('Canonical diagnostics require a TypeScript SourceFile.');
231
+ }
232
+ return Object.freeze({
233
+ code: String(options.code),
234
+ kind: frontend.kind,
235
+ severity: String(options.severity || 'error'),
236
+ message: String(options.message),
237
+ file: sourceFile.fileName,
238
+ position: positionFor(sourceFile, options.node || sourceFile),
239
+ detail: Object.freeze({ ...(options.detail || {}) })
240
+ });
241
+ }
242
+
243
+ function createHandlerDiagnostic(options) {
244
+ const byFrontend = HANDLER_DIAGNOSTIC_CATALOG[options.issue];
245
+ const definition = byFrontend && byFrontend[options.frontend];
246
+ if (!definition) {
247
+ throw new TypeError(`Unknown handler diagnostic issue ${options.issue} for ${options.frontend}.`);
248
+ }
249
+ return createCanonicalDiagnostic({
250
+ frontend: options.frontend,
251
+ sourceFile: options.sourceFile,
252
+ node: options.node,
253
+ code: definition.code,
254
+ message: definition.message(Object.freeze({ ...(options.values || {}) })),
255
+ severity: options.severity || 'error',
256
+ detail: options.detail || {}
257
+ });
258
+ }
259
+
260
+ function adaptRouterDiagnostic(sourceFile, entry) {
261
+ const start = entry && entry.loc && entry.loc.start;
262
+ return Object.freeze({
263
+ code: String(entry.code || 'PULSE_CANONICAL_ROUTER_EXTRACT_FAILED'),
264
+ kind: FRONTENDS['canonical-router'].kind,
265
+ severity: String(entry.severity || 'error'),
266
+ message: String(entry.message || 'Router extraction failed.'),
267
+ file: entry && entry.loc && entry.loc.file ? String(entry.loc.file) : sourceFile.fileName,
268
+ position: start
269
+ ? Object.freeze({ line: start.line, column: start.column, offset: start.offset })
270
+ : positionFor(sourceFile, sourceFile),
271
+ detail: Object.freeze({ phase: entry.phase || entry.pass, hint: entry.hint })
272
+ });
273
+ }
274
+
275
+ function diagnosticCatalogSnapshot() {
276
+ return Object.freeze(Object.fromEntries(Object.entries(HANDLER_DIAGNOSTIC_CATALOG).map(([issue, frontends]) => [
277
+ issue,
278
+ Object.freeze(Object.fromEntries(Object.entries(frontends).map(([frontend, definition]) => [frontend, definition.code])))
279
+ ])));
280
+ }
281
+
282
+ module.exports = Object.freeze({
283
+ DIAGNOSTIC_AUTHORITY_VERSION,
284
+ HANDLER_DIAGNOSTIC_CATALOG,
285
+ positionFor,
286
+ createCanonicalDiagnostic,
287
+ createHandlerDiagnostic,
288
+ adaptRouterDiagnostic,
289
+ diagnosticCatalogSnapshot
290
+ });