@pulse-compute/wasm-compiler 1.0.0-beta.1 → 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.
package/README.md CHANGED
@@ -6,10 +6,11 @@
6
6
  > **Install directly:** No for application projects; use the pulse CLI.<br>
7
7
  > **Supported entry points:** `None for application authors.`<br>
8
8
  > **Stability:** Internal compiler interface; no application-author compatibility guarantee.<br>
9
+ > **npm:** [`@pulse-compute/wasm-compiler`](https://www.npmjs.com/package/@pulse-compute/wasm-compiler)<br>
9
10
  > **Canonical replacement:** `@pulse-compute/cli`<br>
10
- > **Canonical documentation:** [Package guide](https://pulsecompute.io/v1.0.0-beta.1/packages/implementation-packages/)
11
+ > **Canonical documentation:** [Package guide](https://pulsecompute.io/v1.0.0-beta.2/packages/implementation-packages/)
11
12
  >
12
- > This release-status block is generated from the synchronized `Pulse 1.0.0-beta.1` package policy.
13
+ > This release-status block is generated from the synchronized `Pulse 1.0.0-beta.2` package policy.
13
14
  <!-- pulse-package-status:end -->
14
15
 
15
16
  Whole-project compiler implementation used by the `pulse` workflow. Application projects should use `@pulse-compute/cli`, not import this package directly.
@@ -51,4 +52,4 @@ The package exports its root implementation plus focused compiler, CLI, extracto
51
52
 
52
53
  Compiler changes should be covered by focused static/lowering tests, canonical project inspection, provider-plan parity, packed-package discovery where relevant, and the release documentation gates.
53
54
 
54
- See the installed [implementation package guide](https://pulsecompute.io/v1.0.0-beta.1/packages/implementation-packages/) and [compilation concepts](https://pulsecompute.io/v1.0.0-beta.1/concepts/compilation-and-lowering/).
55
+ See the installed [implementation package guide](https://pulsecompute.io/v1.0.0-beta.2/packages/implementation-packages/) and [compilation concepts](https://pulsecompute.io/v1.0.0-beta.2/concepts/compilation-and-lowering/).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pulse-compute/wasm-compiler",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.2",
4
4
  "license": "Apache-2.0",
5
5
  "description": "PulseWasm compiler package inside the Pulse monorepo.",
6
6
  "type": "commonjs",
@@ -9,15 +9,15 @@
9
9
  "pulsewasm": "./bin/pulsewasm-extract.js"
10
10
  },
11
11
  "dependencies": {
12
- "@pulse-compute/provider-fastly": "1.0.0-beta.1",
13
- "@pulse-compute/provider-node": "1.0.0-beta.1",
14
- "@pulse-compute/wasm-build-support": "1.0.0-beta.1",
15
- "@pulse-compute/wasm-contracts": "1.0.0-beta.1",
16
- "@pulse-compute/wasm-guest-link": "1.0.0-beta.1",
17
- "@pulse-compute/wasm-host-runtime": "1.0.0-beta.1",
18
- "@pulse-compute/wasm-library-kit": "1.0.0-beta.1",
19
- "@pulse-compute/wasm-runtime-core-as": "1.0.0-beta.1",
20
- "@pulse-compute/wasm-schema-json": "1.0.0-beta.1",
12
+ "@pulse-compute/provider-fastly": "1.0.0-beta.2",
13
+ "@pulse-compute/provider-node": "1.0.0-beta.2",
14
+ "@pulse-compute/wasm-build-support": "1.0.0-beta.2",
15
+ "@pulse-compute/wasm-contracts": "1.0.0-beta.2",
16
+ "@pulse-compute/wasm-guest-link": "1.0.0-beta.2",
17
+ "@pulse-compute/wasm-host-runtime": "1.0.0-beta.2",
18
+ "@pulse-compute/wasm-library-kit": "1.0.0-beta.2",
19
+ "@pulse-compute/wasm-runtime-core-as": "1.0.0-beta.2",
20
+ "@pulse-compute/wasm-schema-json": "1.0.0-beta.2",
21
21
  "assemblyscript": "0.28.18",
22
22
  "json-as": "1.5.0",
23
23
  "typescript": "5.9.3"
@@ -58,7 +58,7 @@
58
58
  "url": "git+https://github.com/pulse-compute/pulse.git",
59
59
  "directory": "wasm/packages/compiler"
60
60
  },
61
- "homepage": "https://pulsecompute.io/v1.0.0-beta.1/packages/implementation-packages/",
61
+ "homepage": "https://pulsecompute.io/v1.0.0-beta.2/packages/implementation-packages/",
62
62
  "bugs": {
63
63
  "url": "https://github.com/pulse-compute/pulse/issues"
64
64
  },
@@ -52,9 +52,8 @@ function stableSourceName(file, options = {}) {
52
52
  return relative && !relative.startsWith('../') ? relative : path.basename(absolute);
53
53
  }
54
54
 
55
- function emitCanonicalProgramFromHandlerIr(ir) {
55
+ function emitCanonicalProgramFromHandlerIr(ir, options = {}) {
56
56
  const payload = payloadForCanonicalHandlerIr(ir);
57
- const emitted = emitCanonicalHandlerGenerator(payload.operationIr);
58
57
  const sourceFile = payload.sourceFile;
59
58
  const schemaBundle = payload.schemaBundle;
60
59
  const explicitParallelCount = ir.continuationSites.filter((site) => site.kind === 'parallel-group').length;
@@ -100,9 +99,23 @@ function emitCanonicalProgramFromHandlerIr(ir) {
100
99
  compilerPreludeHash: ir.compilerPreludeHash,
101
100
  userAuthoredAsync: ir.invariants.userAuthoredAsync,
102
101
  promiseSemantics: ir.invariants.promiseSemantics,
103
- asyncify: ir.invariants.asyncify
102
+ asyncify: ir.invariants.asyncify,
103
+ ...(options.target === 'javascript' ? { target: 'javascript', promiseSemantics: true } : {})
104
+ });
105
+
106
+ // JavaScript executes the original module graph through its provider. The
107
+ // normalized IR describes recognized Pulse behavior only; erased awaits and
108
+ // source-runtime imports must never become an executable generator.
109
+ if (options.target === 'javascript') return Object.freeze({
110
+ ok: true,
111
+ version: CANONICAL_API_COMPILER_VERSION,
112
+ target: 'javascript',
113
+ metadata,
114
+ schemaBundle,
115
+ diagnostics: Object.freeze([])
104
116
  });
105
117
 
118
+ const emitted = emitCanonicalHandlerGenerator(payload.operationIr);
106
119
  const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
107
120
  const generatorText = printer.printNode(ts.EmitHint.Unspecified, emitted.generator, sourceFile);
108
121
  const metadataSource = JSON.stringify(metadata, null, 2);
@@ -171,8 +184,16 @@ const PLAIN_HANDLER_IMPLEMENTATION = Object.freeze({
171
184
  emitCanonicalProgram: emitCanonicalProgramFromHandlerIr
172
185
  });
173
186
 
187
+ const JAVASCRIPT_HANDLER_INSPECTION = Object.freeze({
188
+ ...PLAIN_HANDLER_IMPLEMENTATION,
189
+ emitCanonicalProgram: (ir) => emitCanonicalProgramFromHandlerIr(ir, { target: 'javascript' })
190
+ });
191
+
174
192
  function compileCanonicalSource(sourceText, options = {}) {
175
- return executeCanonicalSourceSpine(sourceText, options, PLAIN_HANDLER_IMPLEMENTATION);
193
+ if (options.target !== undefined && !['native', 'javascript'].includes(options.target)) throw new TypeError('target must be native or javascript.');
194
+ return executeCanonicalSourceSpine(sourceText, options, options.target === 'javascript'
195
+ ? JAVASCRIPT_HANDLER_INSPECTION
196
+ : PLAIN_HANDLER_IMPLEMENTATION);
176
197
  }
177
198
 
178
199
  function compileCanonicalFile(file, options = {}) {
@@ -191,6 +212,9 @@ function loadCanonicalModule(compiled, options = {}) {
191
212
  }
192
213
 
193
214
  function writeCanonicalBuild(compiled, outDir, options = {}) {
215
+ if (!compiled || compiled.ok !== true || typeof compiled.generatedSource !== 'string') {
216
+ throw new TypeError('writeCanonicalBuild requires an executable canonical compilation; JavaScript projects use provider source packaging.');
217
+ }
194
218
  const target = path.resolve(outDir);
195
219
  fs.mkdirSync(target, { recursive: true });
196
220
  const handlerFile = path.join(target, options.handlerFile || 'canonical-handler.cjs');
@@ -222,6 +222,7 @@ function resultKindForEffect(site, decoder, continuation, resultMode) {
222
222
  if (site.kind === 'config.get' || site.kind === 'secret.get') return 'string-or-undefined';
223
223
  if (site.kind === 'kv.get') return 'json-or-undefined';
224
224
  if (site.kind === 'kv.put') return 'ack';
225
+ if (['kv.getVersioned', 'kv.insertIfAbsent', 'kv.compareAndSwap'].includes(site.kind)) return 'json';
225
226
  if (site.kind === 'event.emit') return 'ack';
226
227
  return 'unknown';
227
228
  }
@@ -1309,10 +1310,10 @@ function assertCanonicalNativePlan(plan) {
1309
1310
  fail('plan crypto realization evidence is invalid', { crypto: plan.crypto });
1310
1311
  } else {
1311
1312
  const knownRealizations = new Map(
1312
- cryptoContract.CRYPTO_REALIZATIONS.map((entry) => [entry.id, entry])
1313
+ cryptoContract.CRYPTO_REALIZATIONS.map((entry) => [`${entry.id}:${entry.algorithm}`, entry])
1313
1314
  );
1314
1315
  for (const entry of plan.crypto.algorithms) {
1315
- const known = entry && knownRealizations.get(entry.realization);
1316
+ const known = entry && knownRealizations.get(`${entry.realization}:${entry.algorithm}`);
1316
1317
  if (
1317
1318
  !known
1318
1319
  || known.algorithm !== entry.algorithm
@@ -304,7 +304,7 @@ function planCanonicalProjectCrypto(options, entryFile, recognizedRequirements =
304
304
  declaration: metadata.crypto && metadata.crypto.declaration,
305
305
  packageRequirements,
306
306
  targetDescriptor: options.packageTargetDescriptor,
307
- target: options.packageTarget || metadata.target || null,
307
+ target: options.target || options.packageTarget || metadata.target || null,
308
308
  profile,
309
309
  profileSelectionSource: selected && typeof selected === 'object'
310
310
  ? selected.source
@@ -324,7 +324,7 @@ function planCanonicalProjectCrypto(options, entryFile, recognizedRequirements =
324
324
  }
325
325
 
326
326
  function assertGraphPreflight(graphBuild, entryFile, options = {}) {
327
- const nativeEligibilityMode = options.nativeEligibilityMode || 'enforce';
327
+ const nativeEligibilityMode = options.nativeEligibilityMode || (options.target === 'javascript' ? 'record' : 'enforce');
328
328
  if (!['enforce', 'record'].includes(nativeEligibilityMode)) {
329
329
  throw new TypeError('nativeEligibilityMode must be enforce or record.');
330
330
  }
@@ -957,8 +957,10 @@ function attachPackageSchemaReferences(compiled, recognition) {
957
957
  return Object.freeze({
958
958
  ...compiled,
959
959
  metadata,
960
- generatedSource: replaceGeneratedMetadata(compiled.generatedSource, metadata, 'commonjs'),
961
- generatedEsmSource: replaceGeneratedMetadata(compiled.generatedEsmSource, metadata, 'esm')
960
+ ...(compiled.target !== 'javascript' ? {
961
+ generatedSource: replaceGeneratedMetadata(compiled.generatedSource, metadata, 'commonjs'),
962
+ generatedEsmSource: replaceGeneratedMetadata(compiled.generatedEsmSource, metadata, 'esm')
963
+ } : {})
962
964
  });
963
965
  }
964
966
 
@@ -1046,9 +1048,10 @@ function compileCanonicalProjectLegacy(entryFile, options = {}) {
1046
1048
  if (multiModule) {
1047
1049
  try {
1048
1050
  linkedProjectModules = root.kind === 'router'
1049
- ? linkProjectRouterModules(graphBuild, { rootDir })
1051
+ ? linkProjectRouterModules(graphBuild, { rootDir, target: options.target })
1050
1052
  : linkProjectPlainHandler(graphBuild, {
1051
1053
  rootDir,
1054
+ target: options.target,
1052
1055
  consumedRuntimeImports: managedHandlerRuntimeImportKeys(packageOperationRecognition.managedHandlers)
1053
1056
  });
1054
1057
  } catch (error) {
@@ -1199,6 +1202,9 @@ function compileCanonicalProjectLegacy(entryFile, options = {}) {
1199
1202
  }
1200
1203
 
1201
1204
  function compileCanonicalProject(entryFile, options = {}) {
1205
+ if (options.target !== undefined && !['native', 'javascript'].includes(options.target)) {
1206
+ throw new TypeError('target must be native or javascript.');
1207
+ }
1202
1208
  return executeCanonicalProjectSpine(entryFile, options, compileCanonicalProjectLegacy);
1203
1209
  }
1204
1210
 
@@ -563,7 +563,7 @@ function linkProjectRouterModules(graphBuild, options = {}) {
563
563
 
564
564
  const rootGlobalName = routerSymbols.get(`${root.module.path}:${root.localName}`);
565
565
  const ordered = orderLinkedRouters(routers, rootGlobalName);
566
- validateRuntimeProjectImports(context, consumedImports, diagnostics);
566
+ if (options.target !== 'javascript') validateRuntimeProjectImports(context, consumedImports, diagnostics);
567
567
  const combinedIr = Object.freeze({
568
568
  source: entryModule.path,
569
569
  routerIR: Object.freeze(ordered.routers),
@@ -652,7 +652,7 @@ function linkProjectPlainHandler(graphBuild, options = {}) {
652
652
  { resolvedKind: root && root.kind || 'unknown' }
653
653
  ));
654
654
  }
655
- validateRuntimeProjectImports(context, consumedImports, diagnostics);
655
+ if (options.target !== 'javascript') validateRuntimeProjectImports(context, consumedImports, diagnostics);
656
656
  if (diagnostics.some((entry) => entry.severity !== 'warning')) {
657
657
  throw new RouterModuleLinkError(`Project plain-handler linking failed with ${diagnostics.length} diagnostic(s).`, diagnostics, { entry: entryModule.path });
658
658
  }
@@ -6,6 +6,7 @@ const {
6
6
  } = require('@pulse-compute/wasm-contracts/handler/surface-contract');
7
7
  const {
8
8
  recognizeHandlerSurface,
9
+ extractKvNamespaceDeclaration,
9
10
  unwrapExpression
10
11
  } = require('./handler-surface-authority.js');
11
12
  const {
@@ -92,6 +93,7 @@ function normalizeManagedHandler(functionNode, options = {}) {
92
93
  const diagnostics = [];
93
94
  const warnings = [];
94
95
  const changes = [];
96
+ let kvAliases = new Map();
95
97
  const awaitedRoots = new WeakSet();
96
98
  const parallelMemberRoots = new WeakSet();
97
99
  const userAuthoredAsync = (functionNode.modifiers || []).some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword);
@@ -115,6 +117,7 @@ function normalizeManagedHandler(functionNode, options = {}) {
115
117
  function surfaceFor(node, position) {
116
118
  return recognizeHandlerSurface(node, {
117
119
  ctxName,
120
+ kvAliases,
118
121
  nextName,
119
122
  role: options.role,
120
123
  strict,
@@ -126,6 +129,15 @@ function normalizeManagedHandler(functionNode, options = {}) {
126
129
 
127
130
  const transformer = (context) => {
128
131
  function visit(node) {
132
+ if (ts.isBlock(node)) {
133
+ const inherited = kvAliases; kvAliases = new Map(inherited);
134
+ try { return ts.visitEachChild(node, visit, context); } finally { kvAliases = inherited; }
135
+ }
136
+ if (ts.isVariableStatement(node)) {
137
+ const namespace = extractKvNamespaceDeclaration(node, ctxName, { unwrap: true });
138
+ for (const declaration of node.declarationList.declarations) if (ts.isIdentifier(declaration.name)) kvAliases.delete(declaration.name.text);
139
+ if (namespace) kvAliases.set(namespace.variableName, namespace.store);
140
+ }
129
141
  if (node !== functionNode && ts.isFunctionLike(node)) {
130
142
  const nestedAsync = (node.modifiers || []).some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword);
131
143
  if (nestedAsync) diagnostics.push(createHandlerDiagnostic({
@@ -142,6 +154,10 @@ function normalizeManagedHandler(functionNode, options = {}) {
142
154
  const inner = unwrapExpression(node.expression);
143
155
  const surface = surfaceFor(inner, 'await-expression');
144
156
  if (!surface || surface.surfaceId === 'javascript.await' || surface.class === 'javascript-only') {
157
+ // The explicit JavaScript project path uses this normalized tree only
158
+ // for inspection. Its original async source executes through the
159
+ // application loader; Native compilation still rejects this boundary.
160
+ if (options.target === 'javascript') return ts.visitNode(node.expression, visit);
145
161
  diagnostics.push(createHandlerDiagnostic({
146
162
  frontend,
147
163
  issue: 'handler.await.native-unsupported',
@@ -119,6 +119,7 @@ function packageEffectSummary(packageEffects) {
119
119
  capability: effect.capability,
120
120
  result: effect.result,
121
121
  placement: effect.placement,
122
+ ...(effect.redaction ? { redaction: effect.redaction } : {}),
122
123
  range: effect.range
123
124
  })));
124
125
  }
@@ -61,10 +61,11 @@ function providerEffectExpression(factory, sourceFile, site, providerOperation)
61
61
  if (site.groupKey !== undefined) properties.push(literalProperty(factory, 'groupKey', stringLiteral(factory, site.groupKey)));
62
62
  if (providerOperation.kind === 'config.get' || providerOperation.kind === 'secret.get') {
63
63
  properties.push(literalProperty(factory, 'name', providerOperation.name));
64
- } else if (providerOperation.kind === 'kv.get' || providerOperation.kind === 'kv.put') {
64
+ } else if (providerOperation.providerKind === 'kv') {
65
65
  properties.push(literalProperty(factory, 'store', providerOperation.store));
66
66
  properties.push(literalProperty(factory, 'key', providerOperation.key));
67
- if (providerOperation.kind === 'kv.put') properties.push(literalProperty(factory, 'value', providerOperation.value));
67
+ if (providerOperation.generation) properties.push(literalProperty(factory, 'generation', providerOperation.generation));
68
+ if (providerOperation.value) properties.push(literalProperty(factory, 'value', providerOperation.value));
68
69
  } else if (providerOperation.kind === 'event.emit') {
69
70
  properties.push(literalProperty(factory, 'type', providerOperation.type));
70
71
  properties.push(literalProperty(factory, 'emission', providerOperation.emission));
@@ -979,6 +979,7 @@ function compileHandler(resolved, graphBuild, allResolved, diagnostics, packageR
979
979
  } else if (provider.providerKind === 'kv') {
980
980
  add('store', provider.store || provider.resource);
981
981
  add('key', provider.key);
982
+ add('generation', provider.generation);
982
983
  add('value', provider.value);
983
984
  } else if (provider.providerKind === 'event') {
984
985
  add('type', provider.type);
@@ -182,7 +182,7 @@ function extractProviderCall(expression, ctxName, kvAliases = new Map(), options
182
182
  }
183
183
  }
184
184
 
185
- if (['get', 'put'].includes(method)) {
185
+ if (['get', 'put', 'getVersioned', 'insertIfAbsent', 'compareAndSwap'].includes(method)) {
186
186
  let store;
187
187
  if (receiver && ts.isCallExpression(receiver) && isPropertyAccessNamed(receiver.expression, ctxName, 'kv', options) && receiver.arguments.length === 1) {
188
188
  store = receiver.arguments[0];
@@ -190,7 +190,9 @@ function extractProviderCall(expression, ctxName, kvAliases = new Map(), options
190
190
  store = kvAliases.get(receiver.text);
191
191
  }
192
192
  if (store) {
193
- const expected = method === 'get' ? 1 : 2;
193
+ if (['getVersioned', 'insertIfAbsent', 'compareAndSwap'].includes(method)
194
+ && !ts.isStringLiteral(store) && !ts.isNoSubstitutionTemplateLiteral(store)) return undefined;
195
+ const expected = method === 'compareAndSwap' ? 3 : ['get', 'getVersioned'].includes(method) ? 1 : 2;
194
196
  if (current.arguments.length === expected) {
195
197
  return Object.freeze({
196
198
  call: current,
@@ -202,7 +204,8 @@ function extractProviderCall(expression, ctxName, kvAliases = new Map(), options
202
204
  resource: store,
203
205
  store,
204
206
  key: current.arguments[0],
205
- value: current.arguments[1],
207
+ value: current.arguments[method === 'compareAndSwap' ? 2 : 1],
208
+ generation: method === 'compareAndSwap' ? current.arguments[1] : undefined,
206
209
  args: Object.freeze([...current.arguments])
207
210
  });
208
211
  }
@@ -375,6 +375,13 @@ function analyzeHandler(sourceFile, handler, ctxName, diagnostics, schemaBundleI
375
375
 
376
376
  function findCanonicalHandler(sourceFile, diagnostics, options = {}) {
377
377
  const allowedRuntimeImports = new Set([...ALLOWED_IMPORTS, ...(options.allowedRuntimeImports || []).map(String)]);
378
+ if (options.target === 'javascript') {
379
+ // The project graph owns import resolution and containment. These remain
380
+ // source-runtime imports, never lowerer grants.
381
+ for (const statement of sourceFile.statements) {
382
+ if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) allowedRuntimeImports.add(statement.moduleSpecifier.text);
383
+ }
384
+ }
378
385
  for (const statement of sourceFile.statements) {
379
386
  if (!ts.isImportDeclaration(statement)) continue;
380
387
  const moduleName = statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : '';
@@ -486,6 +493,7 @@ function preparePlainHandlerSource(sourceText, options = {}, recognition) {
486
493
  role: 'handler',
487
494
  strict: options.strict === true,
488
495
  frontend: 'canonical-source',
496
+ target: options.target,
489
497
  handlerAuthoring: options.handlerAuthoring,
490
498
  requireAsync: options.requireAsync === true,
491
499
  requireEffectAwait: options.requireEffectAwait === true,
@@ -193,6 +193,7 @@ function normalizeRouterHandler(topology, descriptor, recognition, classificatio
193
193
  role,
194
194
  strict: Boolean(topology.options && topology.options.strict === true),
195
195
  frontend: 'canonical-router',
196
+ target: topology.options && topology.options.target,
196
197
  handlerAuthoring: topology.options && topology.options.handlerAuthoring,
197
198
  requireAsync: topology.options && topology.options.requireAsync === true,
198
199
  requireEffectAwait: topology.options && topology.options.requireEffectAwait === true,
@@ -19,6 +19,7 @@ const { buildDispatchTable } = require('../dispatch-table.js');
19
19
  const { buildExecutionPlan } = require('../execution-plan.js');
20
20
  const { buildEventTopology } = require('../events/event-topology.js');
21
21
  const { analyzeEventEmitHandlers } = require('../events/event-emit.js');
22
+ const { ROUTER_API_DEFINITIONS } = require('../definitions/router-api.js');
22
23
 
23
24
  const ROUTER_TOPOLOGY_FRONTEND_VERSION = 'pulse.router-topology-frontend.v1';
24
25
  const CANONICAL_ROUTER_COMPILER_VERSION = 'pulse.canonical-router-compiler.v2';
@@ -28,7 +29,9 @@ const ROUTER_IMPORT = '@pulse-compute/runtime';
28
29
  const ROUTER_CLASS = 'Router';
29
30
  const PULSE_IMPORT = '@pulse-compute/pulse';
30
31
  const PULSE_CLASS = 'Pulse';
31
- const SUPPORTED_ROUTE_METHODS = new Set(['GET', 'HEAD', 'POST']);
32
+ const SUPPORTED_ROUTE_METHODS = new Set(ROUTER_API_DEFINITIONS
33
+ .filter((definition) => definition.kind === 'route')
34
+ .map((definition) => definition.method));
32
35
  const DISALLOWED_OPERATION_KINDS = new Map([
33
36
  ['lifecycle', 'realtime lifecycle handlers'],
34
37
  ['channel', 'realtime channel registration'],