@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,265 @@
1
+ 'use strict';
2
+
3
+ const ts = require('typescript');
4
+ const { prefixedStableId } = require('@pulse-compute/wasm-contracts/stable-id');
5
+ const { stableFileName } = require('../diagnostics.js');
6
+ const { createCanonicalDiagnostic } = require('../spine/diagnostic-authority.js');
7
+ const {
8
+ extractEventEmitCall,
9
+ extractParallelCall,
10
+ unwrapExpression
11
+ } = require('../spine/handler-surface-authority.js');
12
+
13
+ function loadEventContracts() {
14
+ try {
15
+ return require('@pulse-compute/wasm-contracts/events');
16
+ } catch (error) {
17
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) {
18
+ return require('../../../contracts/src/events/contracts.js');
19
+ }
20
+ throw error;
21
+ }
22
+ }
23
+
24
+ const events = loadEventContracts();
25
+ const EVENT_EMIT_CALLSITE_VERSION = 'pulse.event-emit-callsite.v1';
26
+ const EVENT_EMIT_ANALYSIS_VERSION = 'pulse.event-emit-analysis.v1';
27
+
28
+ function diagnostic(sourceFile, node, code, message, detail = {}) {
29
+ return createCanonicalDiagnostic({
30
+ frontend: 'canonical-router',
31
+ sourceFile,
32
+ node,
33
+ code,
34
+ message,
35
+ detail: Object.freeze({ ...detail, automaticFallback: false })
36
+ });
37
+ }
38
+
39
+ function propertyName(node) {
40
+ if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
41
+ return undefined;
42
+ }
43
+
44
+ function sourceFor(sourceFile, node, cwd) {
45
+ const offset = node.getStart(sourceFile);
46
+ const point = sourceFile.getLineAndCharacterOfPosition(offset);
47
+ return Object.freeze({
48
+ file: String(stableFileName(sourceFile.fileName, cwd) || '').replace(/\\/g, '/'),
49
+ line: point.line + 1,
50
+ column: point.character
51
+ });
52
+ }
53
+
54
+ function emitPlacement(call, ctxName) {
55
+ let root = call;
56
+ let parent = root.parent;
57
+ while (parent && (
58
+ ts.isParenthesizedExpression(parent)
59
+ || ts.isAsExpression(parent)
60
+ || ts.isSatisfiesExpression?.(parent)
61
+ || ts.isNonNullExpression(parent)
62
+ || ts.isTypeAssertionExpression(parent)
63
+ )) {
64
+ root = parent;
65
+ parent = root.parent;
66
+ }
67
+ if (parent && ts.isAwaitExpression(parent)) return Object.freeze({ awaited: true, grouped: false });
68
+ if (parent && ts.isPropertyAssignment(parent) && unwrapExpression(parent.initializer) === call) {
69
+ const record = parent.parent;
70
+ const parallel = record && ts.isObjectLiteralExpression(record)
71
+ ? extractParallelCall(record.parent, ctxName, { unwrap: true })
72
+ : undefined;
73
+ if (parallel && parallel.record === record) {
74
+ let parallelRoot = parallel.call;
75
+ let parallelParent = parallelRoot.parent;
76
+ while (parallelParent && (
77
+ ts.isParenthesizedExpression(parallelParent)
78
+ || ts.isAsExpression(parallelParent)
79
+ || ts.isSatisfiesExpression?.(parallelParent)
80
+ || ts.isNonNullExpression(parallelParent)
81
+ || ts.isTypeAssertionExpression(parallelParent)
82
+ )) {
83
+ parallelRoot = parallelParent;
84
+ parallelParent = parallelRoot.parent;
85
+ }
86
+ return Object.freeze({
87
+ awaited: Boolean(parallelParent && ts.isAwaitExpression(parallelParent)),
88
+ grouped: true,
89
+ groupKey: propertyName(parent.name)
90
+ });
91
+ }
92
+ }
93
+ return Object.freeze({ awaited: false, grouped: false });
94
+ }
95
+
96
+ function parseEmitCall(emit, sourceFile, handler, ctxName, options, diagnostics) {
97
+ const call = emit.call;
98
+ if (emit.argumentCount !== 2) {
99
+ diagnostics.push(diagnostic(sourceFile, call, 'PULSEWASM_EVENTS_EMIT_ARITY', 'ctx.emit requires exactly an event type and one schema declaration/payload object.'));
100
+ return undefined;
101
+ }
102
+ const typeNode = unwrapExpression(emit.type);
103
+ if (!typeNode || (!ts.isStringLiteral(typeNode) && !ts.isNoSubstitutionTemplateLiteral(typeNode))) {
104
+ diagnostics.push(diagnostic(sourceFile, emit.type || call, 'PULSEWASM_EVENTS_EMIT_TYPE_STATIC_REQUIRED', 'ctx.emit event types must be direct string literals.'));
105
+ return undefined;
106
+ }
107
+ let type;
108
+ try {
109
+ type = events.normalizeEventType(typeNode.text);
110
+ } catch (error) {
111
+ diagnostics.push(diagnostic(sourceFile, typeNode, error.code || 'PULSEWASM_EVENTS_TYPE_INVALID', error.message));
112
+ return undefined;
113
+ }
114
+
115
+ const eventNode = unwrapExpression(emit.event);
116
+ if (!eventNode || !ts.isObjectLiteralExpression(eventNode)) {
117
+ diagnostics.push(diagnostic(sourceFile, emit.event || call, 'PULSEWASM_EVENTS_EMIT_DECLARATION_STATIC_REQUIRED', 'ctx.emit requires one direct object literal containing schema and its conditional payload.'));
118
+ return undefined;
119
+ }
120
+ const properties = new Map();
121
+ let valid = true;
122
+ for (const property of eventNode.properties) {
123
+ if (!ts.isPropertyAssignment(property)) {
124
+ diagnostics.push(diagnostic(sourceFile, property, 'PULSEWASM_EVENTS_EMIT_PROPERTY_STATIC_REQUIRED', 'ctx.emit accepts only ordinary schema and payload property assignments.'));
125
+ valid = false;
126
+ continue;
127
+ }
128
+ const name = propertyName(property.name);
129
+ if (name !== 'schema' && name !== 'payload') {
130
+ diagnostics.push(diagnostic(sourceFile, property.name, 'PULSEWASM_EVENTS_EMIT_FIELD_UNSUPPORTED', `ctx.emit does not support field ${JSON.stringify(name || property.name.getText(sourceFile))}.`));
131
+ valid = false;
132
+ continue;
133
+ }
134
+ if (properties.has(name)) {
135
+ diagnostics.push(diagnostic(sourceFile, property.name, 'PULSEWASM_EVENTS_EMIT_FIELD_DUPLICATE', `ctx.emit field ${JSON.stringify(name)} is duplicated.`));
136
+ valid = false;
137
+ continue;
138
+ }
139
+ properties.set(name, property.initializer);
140
+ }
141
+ if (!properties.has('schema')) {
142
+ diagnostics.push(diagnostic(sourceFile, eventNode, 'PULSEWASM_EVENTS_EMIT_SCHEMA_REQUIRED', 'ctx.emit requires an explicit literal schema field.'));
143
+ valid = false;
144
+ }
145
+ if (!valid) return undefined;
146
+
147
+ const schemaNode = unwrapExpression(properties.get('schema'));
148
+ let schemaId;
149
+ if (schemaNode && schemaNode.kind === ts.SyntaxKind.NullKeyword) schemaId = null;
150
+ else if (schemaNode && (ts.isStringLiteral(schemaNode) || ts.isNoSubstitutionTemplateLiteral(schemaNode))) schemaId = schemaNode.text;
151
+ else {
152
+ diagnostics.push(diagnostic(sourceFile, schemaNode || eventNode, 'PULSEWASM_EVENTS_EMIT_SCHEMA_STATIC_REQUIRED', 'ctx.emit schema must be a direct dotted schema ID literal or null.'));
153
+ return undefined;
154
+ }
155
+ try {
156
+ schemaId = events.normalizeEventSchemaId(schemaId);
157
+ } catch (error) {
158
+ diagnostics.push(diagnostic(sourceFile, schemaNode, error.code || 'PULSEWASM_EVENTS_SCHEMA_ID_INVALID', error.message));
159
+ return undefined;
160
+ }
161
+ const hasPayload = properties.has('payload');
162
+ if (schemaId === null && hasPayload) {
163
+ diagnostics.push(diagnostic(sourceFile, properties.get('payload'), 'PULSEWASM_EVENTS_EMIT_PAYLOAD_FORBIDDEN', 'ctx.emit no-payload events must omit payload.'));
164
+ return undefined;
165
+ }
166
+ if (schemaId !== null && !hasPayload) {
167
+ diagnostics.push(diagnostic(sourceFile, eventNode, 'PULSEWASM_EVENTS_EMIT_PAYLOAD_REQUIRED', 'ctx.emit schema-bound events require payload.'));
168
+ return undefined;
169
+ }
170
+ if (schemaId !== null && !options.schemaIds.has(schemaId)) {
171
+ diagnostics.push(diagnostic(sourceFile, schemaNode, 'PULSEWASM_EVENTS_EMIT_SCHEMA_UNRESOLVED', `ctx.emit schema ${JSON.stringify(schemaId)} is not present in the compiled project schema registry.`, { schemaId }));
172
+ return undefined;
173
+ }
174
+
175
+ const placement = emitPlacement(call, ctxName);
176
+ if (!placement.awaited) {
177
+ diagnostics.push(diagnostic(sourceFile, call, 'PULSE_EFFECT_AWAIT_REQUIRED', 'Pulse effect ctx.emit must be awaited directly or through an awaited ctx.parallel group.', { surfaceId: 'ctx.emit' }));
178
+ return undefined;
179
+ }
180
+ if (placement.grouped && placement.groupKey === undefined) {
181
+ diagnostics.push(diagnostic(sourceFile, call, 'PULSE_PARALLEL_KEY_STATIC_REQUIRED', 'A ctx.emit parallel member requires a static identifier or string-literal key.'));
182
+ return undefined;
183
+ }
184
+
185
+ const source = sourceFor(sourceFile, call, options.cwd);
186
+ const stableId = prefixedStableId('emit', {
187
+ version: EVENT_EMIT_CALLSITE_VERSION,
188
+ type,
189
+ schemaId,
190
+ handlerStableId: handler.id,
191
+ source
192
+ });
193
+ return Object.freeze({
194
+ version: EVENT_EMIT_CALLSITE_VERSION,
195
+ stableId,
196
+ type,
197
+ schemaId,
198
+ handlerStableId: handler.id,
199
+ ownerRoles: Object.freeze([...(handler.roles || [])].sort()),
200
+ source,
201
+ capability: 'event.emit',
202
+ grouped: placement.grouped,
203
+ ...(placement.grouped ? { groupKey: placement.groupKey } : {})
204
+ });
205
+ }
206
+
207
+ function analyzeEventEmitHandlers(handlerTable, options = {}) {
208
+ const diagnostics = [];
209
+ const callsites = [];
210
+ const schemaIds = new Set((options.schemaIds || []).map(String));
211
+ const handlers = [...(handlerTable && handlerTable.handlers || [])]
212
+ .sort((left, right) => Number(left.order) - Number(right.order) || left.id.localeCompare(right.id));
213
+ for (const handler of handlers) {
214
+ const functionNode = typeof options.functionNodeForHandler === 'function'
215
+ ? options.functionNodeForHandler(handler)
216
+ : undefined;
217
+ const sourceFile = typeof options.sourceFileForHandler === 'function'
218
+ ? options.sourceFileForHandler(handler)
219
+ : functionNode && functionNode.getSourceFile();
220
+ if (!functionNode || !sourceFile) continue;
221
+ const parameters = functionNode.parameters || [];
222
+ const eventOrHttpRole = (handler.roles || []).some((role) => role !== 'error' && role !== 'error-middleware');
223
+ const ctxParameter = parameters[eventOrHttpRole ? 0 : 1];
224
+ const ctxName = ctxParameter && ts.isIdentifier(ctxParameter.name) ? ctxParameter.name.text : 'ctx';
225
+
226
+ function visit(node, root = false) {
227
+ if (!root && ts.isFunctionLike(node)) return;
228
+ if (ts.isCallExpression(node)) {
229
+ const emit = extractEventEmitCall(node, ctxName, { unwrap: true });
230
+ if (emit) {
231
+ const callsite = parseEmitCall(emit, sourceFile, handler, ctxName, {
232
+ cwd: options.cwd || process.cwd(),
233
+ schemaIds
234
+ }, diagnostics);
235
+ if (callsite) callsites.push(callsite);
236
+ return;
237
+ }
238
+ }
239
+ ts.forEachChild(node, (child) => visit(child, false));
240
+ }
241
+ if (functionNode.body) visit(functionNode.body, true);
242
+ }
243
+ callsites.sort((left, right) => left.source.file.localeCompare(right.source.file)
244
+ || left.source.line - right.source.line
245
+ || left.source.column - right.source.column
246
+ || left.stableId.localeCompare(right.stableId));
247
+ return Object.freeze({
248
+ version: EVENT_EMIT_ANALYSIS_VERSION,
249
+ callsites: Object.freeze(callsites),
250
+ diagnostics: Object.freeze(diagnostics),
251
+ summary: Object.freeze({
252
+ callsites: callsites.length,
253
+ schemaBound: callsites.filter((entry) => entry.schemaId !== null).length,
254
+ noPayload: callsites.filter((entry) => entry.schemaId === null).length,
255
+ grouped: callsites.filter((entry) => entry.grouped).length,
256
+ handlers: new Set(callsites.map((entry) => entry.handlerStableId)).size
257
+ })
258
+ });
259
+ }
260
+
261
+ module.exports = Object.freeze({
262
+ EVENT_EMIT_CALLSITE_VERSION,
263
+ EVENT_EMIT_ANALYSIS_VERSION,
264
+ analyzeEventEmitHandlers
265
+ });
@@ -0,0 +1,127 @@
1
+ 'use strict';
2
+
3
+ const { stableFileName } = require('../diagnostics.js');
4
+
5
+ function loadEventContracts() {
6
+ try {
7
+ return require('@pulse-compute/wasm-contracts/events');
8
+ } catch (error) {
9
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code) && String(error.message).includes('@pulse-compute/wasm-contracts')) {
10
+ return require('../../../contracts/src/events/contracts.js');
11
+ }
12
+ throw error;
13
+ }
14
+ }
15
+
16
+ const events = loadEventContracts();
17
+ const EVENT_TOPOLOGY_VERSION = 'pulse.event-topology.v1';
18
+ const EVENT_OUTBOUND_REQUIREMENTS_VERSION = 'pulse.event-outbound-requirements.v1';
19
+
20
+ function deepFreeze(value) {
21
+ if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
22
+ for (const child of Object.values(value)) deepFreeze(child);
23
+ return Object.freeze(value);
24
+ }
25
+
26
+ function portableSource(op, cwd) {
27
+ const loc = op && op.loc || {};
28
+ const start = loc.start || {};
29
+ return Object.freeze({
30
+ file: String(stableFileName(loc.file, cwd) || '').replace(/\\/g, '/'),
31
+ line: Number(start.line || 1),
32
+ column: Math.max(0, Number(start.column || 1) - 1)
33
+ });
34
+ }
35
+
36
+ function buildEventTopology(eventIr, handlerTable, options = {}) {
37
+ const registrations = [...(eventIr || [])].sort((left, right) => Number(left.order) - Number(right.order));
38
+ const handlers = new Map((handlerTable && handlerTable.handlers || []).map((handler) => [handler.id, handler]));
39
+ const emitAnalysis = options.emitAnalysis || Object.freeze({
40
+ version: 'pulse.event-emit-analysis.v1',
41
+ callsites: Object.freeze([]),
42
+ summary: Object.freeze({ callsites: 0, schemaBound: 0, noPayload: 0, grouped: 0, handlers: 0 })
43
+ });
44
+ const emitCallsitesByHandler = new Map();
45
+ for (const callsite of emitAnalysis.callsites || []) {
46
+ if (!emitCallsitesByHandler.has(callsite.handlerStableId)) emitCallsitesByHandler.set(callsite.handlerStableId, []);
47
+ emitCallsitesByHandler.get(callsite.handlerStableId).push(callsite);
48
+ }
49
+ const catalog = events.normalizeEventCatalog({
50
+ version: events.EVENT_CATALOG_VERSION,
51
+ contractId: events.EVENT_CONTRACT_ID,
52
+ events: registrations.map((registration, runtimeId) => {
53
+ const handlerStableId = registration.handler && registration.handler.id;
54
+ const handler = handlers.get(handlerStableId);
55
+ if (!handler || !handler.roles.includes('event')) {
56
+ throw new TypeError(`Unable to resolve canonical event handler identity for ${JSON.stringify(registration.type)}.`);
57
+ }
58
+ const schemaId = registration.declaration.schemaId;
59
+ const handlerEmitCallsites = emitCallsitesByHandler.get(handlerStableId) || [];
60
+ return {
61
+ type: registration.type,
62
+ schemaId,
63
+ stableId: events.createEventStableId({ type: registration.type, schemaId, handlerStableId }),
64
+ runtimeId,
65
+ handlerStableId,
66
+ source: portableSource(registration, options.cwd || process.cwd()),
67
+ capabilities: handlerEmitCallsites.length > 0 ? ['event.emit'] : [],
68
+ packageOperations: [],
69
+ eligibility: { javascript: false, native: true },
70
+ hostRequirements: handlerEmitCallsites.length > 0 ? ['event.ingress', 'event.emit'] : ['event.ingress']
71
+ };
72
+ })
73
+ });
74
+ const emits = (emitAnalysis.callsites || []).length > 0;
75
+ const outboundRequirements = deepFreeze({
76
+ version: EVENT_OUTBOUND_REQUIREMENTS_VERSION,
77
+ status: 'implemented-node-javascript-and-native',
78
+ operation: 'emit',
79
+ analysisVersion: emitAnalysis.version,
80
+ callsites: emitAnalysis.callsites || [],
81
+ summary: emitAnalysis.summary,
82
+ capabilities: emits ? ['event.emit'] : [],
83
+ packageOperations: [],
84
+ hostRequirements: emits ? ['event.emit'] : [],
85
+ policy: {
86
+ sourceRecognition: true,
87
+ effectLowering: true,
88
+ execution: true,
89
+ javascriptExecution: true,
90
+ nativeEffectLowering: true,
91
+ nativeExecution: true,
92
+ providerSupportChanged: true,
93
+ automaticLoopback: false
94
+ }
95
+ });
96
+ return deepFreeze({
97
+ version: EVENT_TOPOLOGY_VERSION,
98
+ contractId: events.EVENT_CONTRACT_ID,
99
+ catalog,
100
+ outboundRequirements,
101
+ summary: {
102
+ events: catalog.events.length,
103
+ schemaBound: catalog.events.filter((event) => event.schemaId !== null).length,
104
+ noPayload: catalog.events.filter((event) => event.schemaId === null).length,
105
+ handlers: new Set(catalog.events.map((event) => event.handlerStableId)).size,
106
+ emitCallsites: emitAnalysis.summary.callsites
107
+ },
108
+ policy: {
109
+ rootPulseOnly: true,
110
+ staticallyKnown: true,
111
+ uniqueTypeOwnership: true,
112
+ handlerExecution: true,
113
+ nativeHandlerExecution: true,
114
+ javascriptArtifactHandlerExecution: false,
115
+ outboundJavascriptExecution: true,
116
+ outboundNativeExecution: true,
117
+ eventRoutesAreHttpRoutes: false,
118
+ providerSupportChanged: true
119
+ }
120
+ });
121
+ }
122
+
123
+ module.exports = Object.freeze({
124
+ EVENT_TOPOLOGY_VERSION,
125
+ EVENT_OUTBOUND_REQUIREMENTS_VERSION,
126
+ buildEventTopology
127
+ });