@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,372 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ buildRouterHandlerIr
5
+ } = require('./handler-ir.js');
6
+ const {
7
+ createCanonicalHandlerIr
8
+ } = require('./canonical-handler-ir.js');
9
+ const {
10
+ emitCanonicalRouterHandlerBody
11
+ } = require('./handler-ir-emitter.js');
12
+ const {
13
+ CANONICAL_ROUTER_COMPILER_VERSION,
14
+ CANONICAL_ROUTER_AUTHORING_VERSION,
15
+ CANONICAL_ROUTER_EXECUTION_VERSION
16
+ } = require('./router-topology-frontend.js');
17
+ const {
18
+ ROUTER_CURSOR_IDENTIFIER: CURSOR,
19
+ ROUTER_MODE_IDENTIFIER: MODE,
20
+ ROUTER_ERROR_IDENTIFIER: ERROR
21
+ } = require('./router-control-contract.js');
22
+
23
+ function loadEventContracts() {
24
+ try { return require('@pulse-compute/wasm-contracts/events'); }
25
+ catch (error) {
26
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) return require('../../../contracts/src/events/contracts.js');
27
+ throw error;
28
+ }
29
+ }
30
+
31
+ const eventContracts = loadEventContracts();
32
+
33
+ const ROUTER_HANDLER_IR_BUNDLE_VERSION = 'pulse.router-handler-ir-bundle.v1';
34
+
35
+ function indent(text, spaces) {
36
+ const prefix = ' '.repeat(spaces);
37
+ return String(text).split('\n').map((line) => line ? `${prefix}${line}` : line).join('\n');
38
+ }
39
+
40
+ function handlerMetadata(frontend) {
41
+ return Object.freeze({
42
+ id: frontend.entry.handlerId,
43
+ name: frontend.descriptor.handler && frontend.descriptor.handler.name,
44
+ localName: frontend.descriptor.handler && frontend.descriptor.handler.localName,
45
+ role: frontend.role,
46
+ ctxParameter: frontend.signature.ctxName,
47
+ nextParameter: frontend.signature.nextName,
48
+ errorParameter: frontend.signature.errorName
49
+ });
50
+ }
51
+
52
+ function routerOwnership(frontend, generatedRange) {
53
+ const entry = frontend.entry;
54
+ const route = frontend.route;
55
+ const event = frontend.event;
56
+ return Object.freeze({
57
+ version: CANONICAL_ROUTER_AUTHORING_VERSION,
58
+ executionVersion: CANONICAL_ROUTER_EXECUTION_VERSION,
59
+ lane: frontend.role === 'event' ? 'event' : (frontend.role === 'error' ? 'error' : 'normal'),
60
+ entry: Object.freeze({
61
+ stableId: entry.stableId,
62
+ index: entry.index,
63
+ nextIndex: entry.nextIndex,
64
+ kind: entry.kind,
65
+ order: entry.order,
66
+ router: entry.router,
67
+ routerPath: entry.routerPath,
68
+ path: entry.path,
69
+ scoped: entry.scoped,
70
+ pattern: entry.pattern,
71
+ method: entry.method,
72
+ handlerId: entry.handlerId,
73
+ ...(entry.kind === 'event' ? {
74
+ plane: 'event',
75
+ eventStableId: entry.eventStableId,
76
+ eventRuntimeId: entry.eventRuntimeId,
77
+ eventType: entry.eventType,
78
+ eventSchemaId: entry.eventSchemaId
79
+ } : {}),
80
+ generatedRange
81
+ }),
82
+ route: route ? Object.freeze({
83
+ stableId: route.stableId,
84
+ runtimeId: route.runtimeId,
85
+ method: route.method,
86
+ path: route.path,
87
+ pathPattern: route.pathPattern,
88
+ params: Object.freeze([...(route.params || [])]),
89
+ handlerId: route.handler,
90
+ handlerName: route.handlerName,
91
+ sourceRouter: route.sourceRouter
92
+ }) : undefined,
93
+ event: event ? Object.freeze({
94
+ stableId: event.stableId,
95
+ runtimeId: event.runtimeId,
96
+ type: event.type,
97
+ schemaId: event.schemaId,
98
+ handlerStableId: event.handlerStableId
99
+ }) : undefined
100
+ });
101
+ }
102
+
103
+ function realizedEventTopology(topology, prepared) {
104
+ if (!topology.eventTopology || !topology.eventCatalog) return undefined;
105
+ const eventHandlers = new Map(prepared.handlers
106
+ .filter((handler) => handler.role === 'event')
107
+ .map((handler) => [handler.entry.eventStableId, handler]));
108
+ const catalog = eventContracts.normalizeEventCatalog({
109
+ version: topology.eventCatalog.version,
110
+ contractId: topology.eventCatalog.contractId,
111
+ events: topology.eventCatalog.events.map((event) => {
112
+ const handler = eventHandlers.get(event.stableId);
113
+ const capabilities = Object.freeze([...new Set([
114
+ ...(event.capabilities || []),
115
+ ...(handler && handler.analysis && handler.analysis.capabilities || [])
116
+ ])].sort());
117
+ const nativeSurfaces = !handler || !handler.surfaceFacts || handler.surfaceFacts.classification.facts.every((fact) => fact.nativeEligible !== false);
118
+ return {
119
+ type: event.type,
120
+ schemaId: event.schemaId,
121
+ stableId: event.stableId,
122
+ runtimeId: event.runtimeId,
123
+ handlerStableId: event.handlerStableId,
124
+ source: event.source,
125
+ capabilities,
126
+ packageOperations: event.packageOperations,
127
+ eligibility: {
128
+ javascript: event.eligibility.javascript,
129
+ native: event.eligibility.native && nativeSurfaces
130
+ },
131
+ hostRequirements: event.hostRequirements
132
+ };
133
+ })
134
+ });
135
+ return Object.freeze({ ...topology.eventTopology, catalog });
136
+ }
137
+
138
+ function emitCanonicalRouterFromHandlerIrs(prepared) {
139
+ if (!prepared || !prepared.topology || !Array.isArray(prepared.handlers)) {
140
+ throw new TypeError('emitCanonicalRouterFromHandlerIrs requires prepared Router handlers.');
141
+ }
142
+ const topology = prepared.topology;
143
+ const operationByEntry = new Map();
144
+ const emittedByEntry = new Map();
145
+ for (const handler of prepared.handlers) {
146
+ const operationIr = buildRouterHandlerIr(handler);
147
+ operationByEntry.set(handler.entry.stableId, operationIr);
148
+ emittedByEntry.set(handler.entry.stableId, emitCanonicalRouterHandlerBody(operationIr));
149
+ }
150
+
151
+ const header = topology.retainedDeclarations;
152
+ let synthetic = header ? `${header}\n\n` : '';
153
+ synthetic += 'export default function __pulse_router_entry(ctx) {\n';
154
+
155
+ const eventReachable = Boolean(topology.eventTopology && topology.eventCatalog && topology.eventCatalog.events.length > 0);
156
+ const eventTopology = realizedEventTopology(topology, prepared);
157
+ const eventCatalog = eventTopology && eventTopology.catalog;
158
+ const entryRecords = [];
159
+ const eventEntryRecords = [];
160
+ const generatedRangeByEntry = new Map();
161
+ if (eventReachable) {
162
+ for (const descriptor of topology.entries.filter((candidate) => candidate.entry.kind === 'event')) {
163
+ const { entry, event } = descriptor;
164
+ const emitted = emittedByEntry.get(entry.stableId);
165
+ const openingStart = synthetic.length;
166
+ synthetic += ` if (__pulse_event_runtime_id() === ${event.runtimeId}) {\n`;
167
+ const start = synthetic.length;
168
+ synthetic += event.eligibility.native
169
+ ? `${indent(emitted.sourceText, 4)}\n`
170
+ : ' return undefined;\n';
171
+ const end = synthetic.length;
172
+ const generatedRange = Object.freeze({ start, end });
173
+ synthetic += ' }\n';
174
+ generatedRangeByEntry.set(entry.stableId, generatedRange);
175
+ eventEntryRecords.push(Object.freeze({
176
+ ...entry,
177
+ plane: 'event',
178
+ eventStableId: event.stableId,
179
+ eventRuntimeId: event.runtimeId,
180
+ eventType: event.type,
181
+ eventSchemaId: event.schemaId,
182
+ generatedRange,
183
+ generatedBlockRange: Object.freeze({ start: openingStart, end: synthetic.length })
184
+ }));
185
+ }
186
+ }
187
+ synthetic += ` let ${CURSOR} = 0;\n`;
188
+ synthetic += ` let ${MODE} = 0;\n`;
189
+ synthetic += ` let ${ERROR} = undefined;\n`;
190
+
191
+ const routeRecordMap = new Map();
192
+ for (const descriptor of topology.entries) {
193
+ const { rawEntry, entry, route } = descriptor;
194
+ if (entry.kind === 'event') continue;
195
+ const openingStart = synthetic.length;
196
+ synthetic += ` if (${CURSOR} === ${entry.index}) {\n`;
197
+ let generatedRange;
198
+
199
+ if (entry.kind === 'mount') {
200
+ const pattern = rawEntry.pattern && rawEntry.pattern.normalized || `${rawEntry.path || '/'}/*`;
201
+ synthetic += ` if (${MODE} === 0 && __pulse_router_match(ctx.req.path, ${JSON.stringify(pattern)})) {\n`;
202
+ synthetic += ` ${CURSOR} = ${rawEntry.childStartIndex};\n`;
203
+ synthetic += ' } else {\n';
204
+ synthetic += ` ${CURSOR} = ${rawEntry.parentContinueIndex};\n`;
205
+ synthetic += ' }\n';
206
+ } else if (entry.kind === 'use' || entry.kind === 'route' || entry.kind === 'error') {
207
+ const emitted = emittedByEntry.get(entry.stableId);
208
+ const normalCondition = entry.kind === 'error' ? `${MODE} === 1` : `${MODE} === 0`;
209
+ let matchCondition = normalCondition;
210
+ if (entry.kind === 'use' && rawEntry.scoped) {
211
+ const pattern = rawEntry.pattern && rawEntry.pattern.normalized || `${rawEntry.path || '/'}/*`;
212
+ matchCondition += ` && __pulse_router_match(ctx.req.path, ${JSON.stringify(pattern)})`;
213
+ }
214
+ if (entry.kind === 'route') matchCondition += ` && ctx.req.method === ${JSON.stringify(entry.method)} && __pulse_router_match(ctx.req.path, ${JSON.stringify(entry.path)})`;
215
+ synthetic += ` if (${matchCondition}) {\n`;
216
+ const start = synthetic.length;
217
+ synthetic += `${indent(emitted.sourceText, 6)}\n`;
218
+ const end = synthetic.length;
219
+ generatedRange = Object.freeze({ start, end });
220
+ synthetic += ' } else {\n';
221
+ synthetic += ` ${CURSOR} = ${entry.nextIndex};\n`;
222
+ synthetic += ' }\n';
223
+ } else {
224
+ synthetic += ` ${CURSOR} = ${entry.nextIndex};\n`;
225
+ }
226
+ synthetic += ' }\n';
227
+
228
+ const record = Object.freeze({
229
+ ...entry,
230
+ ...(eventReachable ? { plane: 'http' } : {}),
231
+ generatedRange,
232
+ generatedBlockRange: Object.freeze({ start: openingStart, end: synthetic.length })
233
+ });
234
+ entryRecords.push(record);
235
+ if (generatedRange) generatedRangeByEntry.set(entry.stableId, generatedRange);
236
+ if (entry.kind === 'route' && route) routeRecordMap.set(route.stableId, Object.freeze({
237
+ order: route.order,
238
+ runtimeId: route.runtimeId,
239
+ stableId: route.stableId,
240
+ method: route.method,
241
+ path: route.path,
242
+ pathPattern: route.pathPattern,
243
+ params: Object.freeze([...(route.params || [])]),
244
+ handlerId: route.handler,
245
+ handlerName: route.handlerName,
246
+ sourceRouter: route.sourceRouter,
247
+ routerEntryStableId: entry.stableId,
248
+ routerEntryIndex: entry.index,
249
+ generatedRange
250
+ }));
251
+ }
252
+ entryRecords.push(...eventEntryRecords);
253
+ synthetic += ` if (${MODE} === 1) return ctx.text("Internal Server Error", { status: 500 });\n`;
254
+ synthetic += ' return ctx.text("Not Found", { status: 404 });\n';
255
+ synthetic += '}\n';
256
+
257
+ const handlerRecords = [];
258
+ for (const frontend of prepared.handlers) {
259
+ const operationIr = operationByEntry.get(frontend.entry.stableId);
260
+ const generatedRange = generatedRangeByEntry.get(frontend.entry.stableId);
261
+ const canonicalIr = createCanonicalHandlerIr({
262
+ frontend,
263
+ operationIr,
264
+ compilerVersion: CANONICAL_ROUTER_COMPILER_VERSION,
265
+ programVersion: CANONICAL_ROUTER_AUTHORING_VERSION,
266
+ runtimeProtocolVersion: CANONICAL_ROUTER_EXECUTION_VERSION,
267
+ options: {
268
+ authoringSourceText: frontend.sourceText,
269
+ loweredSourceText: emittedByEntry.get(frontend.entry.stableId).sourceText,
270
+ handlerMetadata: handlerMetadata(frontend),
271
+ routerMetadata: routerOwnership(frontend, generatedRange),
272
+ compilerOwnedCalls: topology.compilerOwnedCalls
273
+ },
274
+ surfaceFacts: frontend.surfaceFacts
275
+ });
276
+ handlerRecords.push(Object.freeze({
277
+ entryStableId: frontend.entry.stableId,
278
+ entryIndex: frontend.entry.index,
279
+ operationIr,
280
+ canonicalIr,
281
+ emitted: emittedByEntry.get(frontend.entry.stableId)
282
+ }));
283
+ }
284
+
285
+ const routeRecords = (topology.routePlan.routes || []).map((route) => routeRecordMap.get(route.stableId)).filter(Boolean);
286
+ const warnings = Object.freeze(prepared.handlers.flatMap((handler) => [...(handler.warnings || [])]));
287
+ const userAuthoredAsync = prepared.handlers.some((handler) => Boolean(handler.normalization && handler.normalization.userAuthoredAsync));
288
+ const normalization = Object.freeze({
289
+ handlerCount: prepared.handlers.length,
290
+ userAuthoredAsync,
291
+ awaitCount: prepared.handlers.reduce((total, handler) => total + Number(handler.normalization && handler.normalization.awaitCount || 0), 0),
292
+ effectAwaitCount: prepared.handlers.reduce((total, handler) => total + Number(handler.normalization && handler.normalization.effectAwaitCount || 0), 0),
293
+ syncAwaitCount: prepared.handlers.reduce((total, handler) => total + Number(handler.normalization && handler.normalization.syncAwaitCount || 0), 0)
294
+ });
295
+ const pulseApplication = topology.applicationKind === 'pulse';
296
+ const hasNormalizationEvidence = userAuthoredAsync
297
+ || normalization.awaitCount > 0
298
+ || normalization.effectAwaitCount > 0
299
+ || normalization.syncAwaitCount > 0;
300
+ const output = Object.freeze({
301
+ version: CANONICAL_ROUTER_COMPILER_VERSION,
302
+ authoringVersion: CANONICAL_ROUTER_AUTHORING_VERSION,
303
+ fileName: topology.fileName,
304
+ rootRouter: topology.rootName,
305
+ ...(pulseApplication ? {
306
+ applicationKind: 'pulse',
307
+ applicationConstructionMode: topology.applicationConstructionMode,
308
+ application: Object.freeze({ kind: 'pulse', constructionMode: topology.applicationConstructionMode })
309
+ } : {}),
310
+ sourceText: synthetic,
311
+ compilerPrelude: topology.compilerPrelude,
312
+ compilerOwnedCalls: topology.compilerOwnedCalls,
313
+ ...(userAuthoredAsync ? { userAuthoredAsync: true } : {}),
314
+ ...(hasNormalizationEvidence ? { normalization } : {}),
315
+ ...(warnings.length > 0 ? { warnings } : {}),
316
+ routePlan: topology.routePlan,
317
+ handlerTable: topology.handlerTable,
318
+ ...(topology.eventTopology ? {
319
+ eventTopology,
320
+ eventCatalog,
321
+ eventOutboundRequirements: topology.eventOutboundRequirements
322
+ } : {}),
323
+ routerTree: topology.routerTree,
324
+ executionPlan: topology.executionPlan,
325
+ metadata: Object.freeze({
326
+ version: CANONICAL_ROUTER_AUTHORING_VERSION,
327
+ entryRouter: topology.rootName,
328
+ routePlanVersion: topology.routePlan.version,
329
+ executionPlanVersion: topology.executionPlan.version,
330
+ executionVersion: CANONICAL_ROUTER_EXECUTION_VERSION,
331
+ ...(topology.eventTopology ? {
332
+ events: Object.freeze({
333
+ version: eventTopology.version,
334
+ catalogHash: eventCatalog.catalogHash,
335
+ count: eventCatalog.events.length,
336
+ handlerExecution: true,
337
+ nativeHandlerExecution: true,
338
+ javascriptArtifactHandlerExecution: false,
339
+ catalog: eventCatalog,
340
+ abi: eventContracts.EVENT_NATIVE_ABI_EXTENSION,
341
+ outboundRequirementsVersion: topology.eventOutboundRequirements.version
342
+ })
343
+ } : {}),
344
+ ...(pulseApplication ? { application: Object.freeze({ kind: 'pulse', constructionMode: topology.applicationConstructionMode }) } : {}),
345
+ ...(userAuthoredAsync ? { userAuthoredAsync: true } : {}),
346
+ ...(hasNormalizationEvidence ? { normalization } : {}),
347
+ ...(warnings.length > 0 ? { warnings } : {}),
348
+ semantics: Object.freeze({
349
+ nextIsTerminal: true,
350
+ onionResume: false,
351
+ normalExhaustionStatus: 404,
352
+ errorExhaustionStatus: 500,
353
+ explicitErrorTransfer: 'return next(error)'
354
+ }),
355
+ routes: Object.freeze(routeRecords),
356
+ entries: Object.freeze(entryRecords),
357
+ ...(eventReachable ? { applicationEntries: Object.freeze(entryRecords) } : {})
358
+ }),
359
+ diagnostics: Object.freeze([])
360
+ });
361
+
362
+ return Object.freeze({
363
+ version: ROUTER_HANDLER_IR_BUNDLE_VERSION,
364
+ output,
365
+ handlers: Object.freeze(handlerRecords)
366
+ });
367
+ }
368
+
369
+ module.exports = Object.freeze({
370
+ ROUTER_HANDLER_IR_BUNDLE_VERSION,
371
+ emitCanonicalRouterFromHandlerIrs
372
+ });