@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.
- package/README.md +53 -1
- package/bin/provider-proof-composition.js +34 -0
- package/bin/pulsewasm-extract.js +20 -0
- package/package.json +60 -5
- package/src/artifacts-dir.js +13 -0
- package/src/ast-json.js +52 -0
- package/src/build-manifest.js +354 -0
- package/src/canonical-api-compiler.js +269 -0
- package/src/canonical-native-compiler.js +411 -0
- package/src/canonical-native-plan.js +1478 -0
- package/src/canonical-project-compiler.js +1224 -0
- package/src/canonical-router-compiler.js +25 -0
- package/src/cli-intents.js +1235 -0
- package/src/cli.js +1927 -0
- package/src/codegen/assemblyscript-compile.js +3 -0
- package/src/codegen/assemblyscript-core.js +3 -0
- package/src/codegen/assemblyscript-shape.js +3 -0
- package/src/codegen/assemblyscript-wasm-smoke.js +3 -0
- package/src/codegen/backend-capabilities.js +3 -0
- package/src/codegen/channel-broadcaster.js +3 -0
- package/src/codegen/compiled-handlers.js +3 -0
- package/src/codegen/compiled-wasm-runtime.js +3 -0
- package/src/codegen/config-references.js +248 -0
- package/src/codegen/dispatch-ts.js +145 -0
- package/src/codegen/effect-composition.js +331 -0
- package/src/codegen/effect-runtime.js +418 -0
- package/src/codegen/execution-harness-ts.js +467 -0
- package/src/codegen/handler-bindings-ts.js +298 -0
- package/src/codegen/handler-library-contracts.js +3 -0
- package/src/codegen/host-capabilities.js +3 -0
- package/src/codegen/host-runtime-kernel.js +3 -0
- package/src/codegen/integrated-compiled-app.js +3 -0
- package/src/codegen/json-body.js +3 -0
- package/src/codegen/library-sidecars.js +3 -0
- package/src/codegen/local-harness-ts.js +453 -0
- package/src/codegen/pulse-wrapper.js +217 -0
- package/src/codegen/request-result-headers.js +3 -0
- package/src/codegen/schema-json-compile.js +3 -0
- package/src/codegen/schema-json-sidecar-v2.js +3 -0
- package/src/codegen/schema-json-sidecar.js +3 -0
- package/src/codegen/streaming-passthrough.js +3 -0
- package/src/codegen/wasm-host-abi.js +3 -0
- package/src/codegen/wasm-host-bridge.js +3 -0
- package/src/compiled-wasm-host-runtime-kv.js +3 -0
- package/src/config-resolver.js +813 -0
- package/src/crypto-requirement-planner.js +89 -0
- package/src/definitions/config-schema.js +14 -0
- package/src/definitions/handler-roles.js +14 -0
- package/src/definitions/path-grammar.js +14 -0
- package/src/definitions/router-api.js +14 -0
- package/src/diagnostics/codes.js +14 -0
- package/src/diagnostics/reporter.js +14 -0
- package/src/diagnostics.js +14 -0
- package/src/dispatch-table.js +400 -0
- package/src/events/event-emit.js +265 -0
- package/src/events/event-topology.js +127 -0
- package/src/execution-plan.js +463 -0
- package/src/extractor.js +2816 -0
- package/src/handler-eval.js +1154 -0
- package/src/handler-table.js +326 -0
- package/src/index.js +19 -0
- package/src/javascript-application-plan.js +181 -0
- package/src/kv-provider.js +3 -0
- package/src/path-table.js +60 -0
- package/src/path.js +14 -0
- package/src/patterns/config-define.js +30 -0
- package/src/patterns/dependency-call.js +18 -0
- package/src/patterns/env-lookup.js +13 -0
- package/src/patterns/handler-reference.js +29 -0
- package/src/patterns/path-literal.js +35 -0
- package/src/patterns/result.js +15 -0
- package/src/patterns/router-chain-call.js +50 -0
- package/src/patterns/router-construction.js +19 -0
- package/src/project/package-reachability.js +782 -0
- package/src/project/reachable-graph-builder.js +992 -0
- package/src/project/reachable-graph-contract.js +54 -0
- package/src/project/reachable-graph-implementation.js +36 -0
- package/src/project/router-module-linker.js +710 -0
- package/src/project-config-compiler.js +222 -0
- package/src/project-target-support.js +500 -0
- package/src/provider-toolchain.js +299 -0
- package/src/spine/async-surface-normalizer.js +328 -0
- package/src/spine/canonical-handler-ir.js +336 -0
- package/src/spine/canonical-native-module.js +87 -0
- package/src/spine/canonical-native-plan.js +89 -0
- package/src/spine/canonical-project.js +76 -0
- package/src/spine/canonical-router.js +155 -0
- package/src/spine/canonical-source.js +165 -0
- package/src/spine/diagnostic-authority.js +290 -0
- package/src/spine/equivalence.js +262 -0
- package/src/spine/guest-unit-stage.js +87 -0
- package/src/spine/handler-ir-emitter.js +455 -0
- package/src/spine/handler-ir-managed.js +1598 -0
- package/src/spine/handler-ir.js +797 -0
- package/src/spine/handler-surface-authority.js +588 -0
- package/src/spine/package-operation-seam.js +1015 -0
- package/src/spine/pipeline.js +202 -0
- package/src/spine/plain-handler-frontend.js +545 -0
- package/src/spine/provider-requirement-authority.js +208 -0
- package/src/spine/router-control-contract.js +17 -0
- package/src/spine/router-handler-frontend.js +514 -0
- package/src/spine/router-handler-ir.js +372 -0
- package/src/spine/router-topology-frontend.js +638 -0
- package/src/stable-id.js +14 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const vm = require('node:vm');
|
|
6
|
+
const ts = require('typescript');
|
|
7
|
+
const { executeCanonicalSourceSpine } = require('./spine/canonical-source.js');
|
|
8
|
+
const {
|
|
9
|
+
extractFetchChain,
|
|
10
|
+
extractProviderCall,
|
|
11
|
+
extractKvNamespaceDeclaration
|
|
12
|
+
} = require('./spine/handler-surface-authority.js');
|
|
13
|
+
const {
|
|
14
|
+
payloadForCanonicalHandlerIr
|
|
15
|
+
} = require('./spine/canonical-handler-ir.js');
|
|
16
|
+
const {
|
|
17
|
+
emitCanonicalHandlerGenerator
|
|
18
|
+
} = require('./spine/handler-ir-emitter.js');
|
|
19
|
+
const {
|
|
20
|
+
SUPPORTED_FETCH_DECODERS,
|
|
21
|
+
ALLOWED_IMPORTS,
|
|
22
|
+
CanonicalCompileError
|
|
23
|
+
} = require('./spine/plain-handler-frontend.js');
|
|
24
|
+
|
|
25
|
+
function loadCanonicalRuntimeContract() {
|
|
26
|
+
try { return require('@pulse-compute/wasm-contracts/handler/canonical-runtime'); }
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) return require('../../contracts/src/handler/canonical-runtime.js');
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const canonicalRuntimeContract = loadCanonicalRuntimeContract();
|
|
34
|
+
|
|
35
|
+
const CANONICAL_API_COMPILER_VERSION = 'pulse.canonical-api-compiler.v7';
|
|
36
|
+
|
|
37
|
+
function findSourceRoot(start) {
|
|
38
|
+
let current = path.resolve(start);
|
|
39
|
+
for (;;) {
|
|
40
|
+
if (fs.existsSync(path.join(current, 'package.json'))) return current;
|
|
41
|
+
const parent = path.dirname(current);
|
|
42
|
+
if (parent === current) return path.resolve(start);
|
|
43
|
+
current = parent;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function stableSourceName(file, options = {}) {
|
|
48
|
+
if (options.fileName) return String(options.fileName).replace(/\\/g, '/');
|
|
49
|
+
const absolute = path.resolve(file);
|
|
50
|
+
const root = path.resolve(options.rootDir || findSourceRoot(path.dirname(absolute)));
|
|
51
|
+
const relative = path.relative(root, absolute).replace(/\\/g, '/');
|
|
52
|
+
return relative && !relative.startsWith('../') ? relative : path.basename(absolute);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function emitCanonicalProgramFromHandlerIr(ir, options = {}) {
|
|
56
|
+
const payload = payloadForCanonicalHandlerIr(ir);
|
|
57
|
+
const sourceFile = payload.sourceFile;
|
|
58
|
+
const schemaBundle = payload.schemaBundle;
|
|
59
|
+
const explicitParallelCount = ir.continuationSites.filter((site) => site.kind === 'parallel-group').length;
|
|
60
|
+
const metadata = Object.freeze({
|
|
61
|
+
version: ir.programVersion,
|
|
62
|
+
compilerVersion: ir.compilerVersion,
|
|
63
|
+
runtimeProtocolVersion: ir.runtimeProtocolVersion,
|
|
64
|
+
file: ir.file,
|
|
65
|
+
sourceHash: ir.sourceHash,
|
|
66
|
+
loweredSourceHash: ir.loweredSourceHash,
|
|
67
|
+
projectSourceHash: ir.projectSourceHash,
|
|
68
|
+
handler: 'default',
|
|
69
|
+
ctxParameter: ir.handler.ctxParameter,
|
|
70
|
+
capabilities: ir.capabilities,
|
|
71
|
+
providerOperations: ir.providerOperations,
|
|
72
|
+
effectSites: ir.effectSites,
|
|
73
|
+
continuationSites: ir.continuationSites,
|
|
74
|
+
effectCount: ir.effectSites.length,
|
|
75
|
+
continuationCount: ir.continuationSites.length,
|
|
76
|
+
groupedContinuationCount: ir.continuationSites.filter((site) => site.kind === 'fetch-group' || site.kind === 'parallel-group').length,
|
|
77
|
+
...(explicitParallelCount > 0 ? { explicitParallelCount } : {}),
|
|
78
|
+
opaqueReturnCount: ir.continuationSites.filter((site) => site.kind === 'opaque-fetch-return').length,
|
|
79
|
+
schemaRegistry: ir.schema.registry,
|
|
80
|
+
schemaIds: ir.schema.ids,
|
|
81
|
+
responseCaseIds: ir.schema.responseCaseIds,
|
|
82
|
+
schemaSourceHash: ir.schema.sourceHash,
|
|
83
|
+
schemaRegistryHash: ir.schema.registryHash,
|
|
84
|
+
schemaCodecTableHash: ir.schema.codecTableHash,
|
|
85
|
+
schemaFullCodecRealization: ir.schema.fullCodecRealization,
|
|
86
|
+
schemaReferences: ir.schemaReferences,
|
|
87
|
+
schemaReferenceCount: ir.schemaReferences.length,
|
|
88
|
+
packageEffects: ir.packageEffects,
|
|
89
|
+
packageEffectCount: ir.packageEffects.length,
|
|
90
|
+
...(ir.json ? { json: ir.json } : {}),
|
|
91
|
+
...(ir.warnings ? { warnings: ir.warnings, warningCount: ir.warnings.length } : {}),
|
|
92
|
+
authoring: ir.authoring,
|
|
93
|
+
...(ir.application ? { application: ir.application } : {}),
|
|
94
|
+
...(ir.applicationEntries ? { applicationEntries: ir.applicationEntries } : {}),
|
|
95
|
+
...(ir.events ? { events: ir.events } : {}),
|
|
96
|
+
router: ir.router,
|
|
97
|
+
compilerOwnedCalls: ir.compilerOwnedCalls,
|
|
98
|
+
compilerOwnedIntrinsics: ir.compilerOwnedIntrinsics,
|
|
99
|
+
compilerPreludeHash: ir.compilerPreludeHash,
|
|
100
|
+
userAuthoredAsync: ir.invariants.userAuthoredAsync,
|
|
101
|
+
promiseSemantics: ir.invariants.promiseSemantics,
|
|
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([])
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const emitted = emitCanonicalHandlerGenerator(payload.operationIr);
|
|
119
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
120
|
+
const generatorText = printer.printNode(ts.EmitHint.Unspecified, emitted.generator, sourceFile);
|
|
121
|
+
const metadataSource = JSON.stringify(metadata, null, 2);
|
|
122
|
+
const generatedTypeScript = [
|
|
123
|
+
schemaBundle.declarationSource,
|
|
124
|
+
payload.compilerPrelude,
|
|
125
|
+
generatorText,
|
|
126
|
+
`const __pulse_metadata = ${metadataSource};`,
|
|
127
|
+
'module.exports = Object.freeze({',
|
|
128
|
+
` version: ${JSON.stringify(canonicalRuntimeContract.CANONICAL_PROGRAM_VERSION)},`,
|
|
129
|
+
' metadata: Object.freeze(__pulse_metadata),',
|
|
130
|
+
' schemaCodecs: __pulse_schema_codecs,',
|
|
131
|
+
' createHandler() { return __pulse_handler; }',
|
|
132
|
+
'});',
|
|
133
|
+
''
|
|
134
|
+
].join('\n');
|
|
135
|
+
const transpiled = ts.transpileModule(generatedTypeScript, {
|
|
136
|
+
fileName: `${ir.file}.generated.ts`,
|
|
137
|
+
compilerOptions: {
|
|
138
|
+
target: ts.ScriptTarget.ES2022,
|
|
139
|
+
module: ts.ModuleKind.CommonJS,
|
|
140
|
+
strict: true,
|
|
141
|
+
removeComments: false,
|
|
142
|
+
esModuleInterop: false
|
|
143
|
+
},
|
|
144
|
+
reportDiagnostics: true
|
|
145
|
+
});
|
|
146
|
+
const generatedSource = transpiled.outputText;
|
|
147
|
+
const generatedEsmTypeScript = [
|
|
148
|
+
schemaBundle.declarationSource,
|
|
149
|
+
payload.compilerPrelude,
|
|
150
|
+
generatorText,
|
|
151
|
+
`export const version = ${JSON.stringify(canonicalRuntimeContract.CANONICAL_PROGRAM_VERSION)};`,
|
|
152
|
+
`export const metadata = Object.freeze(${metadataSource});`,
|
|
153
|
+
'export const schemaCodecs = __pulse_schema_codecs;',
|
|
154
|
+
'export function createHandler() { return __pulse_handler; }',
|
|
155
|
+
''
|
|
156
|
+
].join('\n');
|
|
157
|
+
const esmTranspiled = ts.transpileModule(generatedEsmTypeScript, {
|
|
158
|
+
fileName: `${ir.file}.generated.mts`,
|
|
159
|
+
compilerOptions: {
|
|
160
|
+
target: ts.ScriptTarget.ES2022,
|
|
161
|
+
module: ts.ModuleKind.ES2022,
|
|
162
|
+
strict: true,
|
|
163
|
+
removeComments: false
|
|
164
|
+
},
|
|
165
|
+
reportDiagnostics: true
|
|
166
|
+
});
|
|
167
|
+
const generatedEsmSource = esmTranspiled.outputText;
|
|
168
|
+
|
|
169
|
+
return Object.freeze({
|
|
170
|
+
ok: true,
|
|
171
|
+
version: CANONICAL_API_COMPILER_VERSION,
|
|
172
|
+
metadata,
|
|
173
|
+
schemaBundle,
|
|
174
|
+
generatedSource,
|
|
175
|
+
generatedEsmSource,
|
|
176
|
+
diagnostics: Object.freeze([])
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const PLAIN_HANDLER_IMPLEMENTATION = Object.freeze({
|
|
181
|
+
compilerVersion: CANONICAL_API_COMPILER_VERSION,
|
|
182
|
+
programVersion: canonicalRuntimeContract.CANONICAL_PROGRAM_VERSION,
|
|
183
|
+
runtimeProtocolVersion: canonicalRuntimeContract.CANONICAL_RUNTIME_PROTOCOL_VERSION,
|
|
184
|
+
emitCanonicalProgram: emitCanonicalProgramFromHandlerIr
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const JAVASCRIPT_HANDLER_INSPECTION = Object.freeze({
|
|
188
|
+
...PLAIN_HANDLER_IMPLEMENTATION,
|
|
189
|
+
emitCanonicalProgram: (ir) => emitCanonicalProgramFromHandlerIr(ir, { target: 'javascript' })
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
function compileCanonicalSource(sourceText, options = {}) {
|
|
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);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function compileCanonicalFile(file, options = {}) {
|
|
200
|
+
const absolute = path.resolve(file);
|
|
201
|
+
return compileCanonicalSource(fs.readFileSync(absolute, 'utf8'), { ...options, fileName: stableSourceName(absolute, options) });
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function loadCanonicalModule(compiled, options = {}) {
|
|
205
|
+
if (!compiled || compiled.ok !== true || typeof compiled.generatedSource !== 'string') throw new TypeError('loadCanonicalModule requires a successful canonical compilation.');
|
|
206
|
+
const filename = options.fileName || `${compiled.metadata.file}.generated.cjs`;
|
|
207
|
+
const module = { exports: {} };
|
|
208
|
+
const script = new vm.Script(`(function(module, exports, require, __filename, __dirname) {\n${compiled.generatedSource}\n})`, { filename });
|
|
209
|
+
const fn = script.runInThisContext();
|
|
210
|
+
fn(module, module.exports, require, filename, path.dirname(filename));
|
|
211
|
+
return module.exports;
|
|
212
|
+
}
|
|
213
|
+
|
|
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
|
+
}
|
|
218
|
+
const target = path.resolve(outDir);
|
|
219
|
+
fs.mkdirSync(target, { recursive: true });
|
|
220
|
+
const handlerFile = path.join(target, options.handlerFile || 'canonical-handler.cjs');
|
|
221
|
+
const programFile = path.join(target, options.programFile || 'canonical-program.json');
|
|
222
|
+
const esmHandlerFile = options.esmHandlerFile ? path.join(target, options.esmHandlerFile) : undefined;
|
|
223
|
+
const schemaActive = Boolean(compiled.schemaBundle && compiled.schemaBundle.active);
|
|
224
|
+
const schemaRegistryFile = schemaActive ? path.join(target, options.schemaRegistryFile || 'schema-json-registry.json') : undefined;
|
|
225
|
+
const schemaCodecsFile = schemaActive ? path.join(target, options.schemaCodecsFile || 'schema-json-codecs.cjs') : undefined;
|
|
226
|
+
fs.writeFileSync(handlerFile, compiled.generatedSource);
|
|
227
|
+
if (esmHandlerFile) fs.writeFileSync(esmHandlerFile, compiled.generatedEsmSource);
|
|
228
|
+
if (schemaRegistryFile) fs.writeFileSync(schemaRegistryFile, `${JSON.stringify(compiled.schemaBundle.registry, null, 2)}\n`);
|
|
229
|
+
if (schemaCodecsFile) fs.writeFileSync(schemaCodecsFile, compiled.schemaBundle.moduleSource);
|
|
230
|
+
const packageInspectionArtifacts = Object.freeze((compiled.packageInspection && compiled.packageInspection.artifacts || []).map((artifact) => {
|
|
231
|
+
const relativeFile = String(artifact.file || '').replace(/\\/g, '/');
|
|
232
|
+
const artifactFile = path.resolve(target, relativeFile);
|
|
233
|
+
const relativeArtifact = path.relative(target, artifactFile);
|
|
234
|
+
if (!relativeFile || relativeArtifact.startsWith('..') || path.isAbsolute(relativeArtifact)) {
|
|
235
|
+
const error = new Error(`Package inspection artifact ${artifact.id || '<unknown>'} must remain inside the canonical build output.`);
|
|
236
|
+
error.code = 'PULSE_PACKAGE_INSPECTION_ARTIFACT_UNSAFE';
|
|
237
|
+
error.detail = Object.freeze({ id: artifact.id, file: relativeFile });
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
fs.mkdirSync(path.dirname(artifactFile), { recursive: true });
|
|
241
|
+
fs.writeFileSync(artifactFile, `${JSON.stringify(artifact.data, null, 2)}\n`);
|
|
242
|
+
return Object.freeze({ id: artifact.id, contractId: artifact.contractId, file: artifactFile });
|
|
243
|
+
}));
|
|
244
|
+
fs.writeFileSync(programFile, `${JSON.stringify({
|
|
245
|
+
...compiled.metadata,
|
|
246
|
+
generatedHandler: path.basename(handlerFile),
|
|
247
|
+
generatedEsmHandler: esmHandlerFile ? path.basename(esmHandlerFile) : undefined,
|
|
248
|
+
generatedSchemaRegistry: schemaRegistryFile ? path.basename(schemaRegistryFile) : undefined,
|
|
249
|
+
generatedSchemaCodecs: schemaCodecsFile ? path.basename(schemaCodecsFile) : undefined
|
|
250
|
+
}, null, 2)}\n`);
|
|
251
|
+
return Object.freeze({ outDir: target, handlerFile, esmHandlerFile, programFile, schemaRegistryFile, schemaCodecsFile, packageInspectionArtifacts, metadata: compiled.metadata });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
module.exports = {
|
|
255
|
+
CANONICAL_API_COMPILER_VERSION,
|
|
256
|
+
CANONICAL_PROGRAM_VERSION: canonicalRuntimeContract.CANONICAL_PROGRAM_VERSION,
|
|
257
|
+
CANONICAL_RUNTIME_PROTOCOL_VERSION: canonicalRuntimeContract.CANONICAL_RUNTIME_PROTOCOL_VERSION,
|
|
258
|
+
SUPPORTED_FETCH_DECODERS,
|
|
259
|
+
ALLOWED_IMPORTS,
|
|
260
|
+
CanonicalCompileError,
|
|
261
|
+
compileCanonicalSource,
|
|
262
|
+
compileCanonicalFile,
|
|
263
|
+
loadCanonicalModule,
|
|
264
|
+
writeCanonicalBuild,
|
|
265
|
+
extractFetchChain,
|
|
266
|
+
extractProviderCall,
|
|
267
|
+
extractKvNamespaceDeclaration,
|
|
268
|
+
stableSourceName
|
|
269
|
+
};
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const os = require('node:os');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const { spawnSync } = require('node:child_process');
|
|
8
|
+
const { executeCanonicalNativeModuleSpine } = require('./spine/canonical-native-module.js');
|
|
9
|
+
const {
|
|
10
|
+
packageLoweringForCanonicalNativePlan,
|
|
11
|
+
providerRequirementsForCanonicalNativePlan
|
|
12
|
+
} = require('./spine/canonical-native-plan.js');
|
|
13
|
+
const { packageOperationRecognitionFromEffects, lowerCanonicalPackageOperations } = require('./spine/package-operation-seam.js');
|
|
14
|
+
const { collectProviderRequirements, assertProviderRequirementsForPlan } = require('./spine/provider-requirement-authority.js');
|
|
15
|
+
const { realizeSelectedGuestUnits } = require('./spine/guest-unit-stage.js');
|
|
16
|
+
const {
|
|
17
|
+
PACKAGE_REALIZATION_ARTIFACT_SET_VERSION
|
|
18
|
+
} = require('@pulse-compute/wasm-contracts/package/package-contract');
|
|
19
|
+
|
|
20
|
+
function loadNativePlanCompiler() {
|
|
21
|
+
try { return require('@pulse-compute/wasm-compiler/canonical-native-plan'); }
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) return require('./canonical-native-plan.js');
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function loadRuntimeCore() {
|
|
29
|
+
try { return require('@pulse-compute/wasm-runtime-core-as/compiler/canonical-native'); }
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) return require('../../runtime-core-as/src/compiler/canonical-native.js');
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function loadRuntimeContract() {
|
|
37
|
+
try { return require('@pulse-compute/wasm-contracts/handler/canonical-native-runtime'); }
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) return require('../../contracts/src/handler/canonical-native-runtime.js');
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function loadEventContract() {
|
|
45
|
+
try { return require('@pulse-compute/wasm-contracts/events'); }
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) return require('../../contracts/src/events/contracts.js');
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function loadBuildSupport() {
|
|
53
|
+
try { return require('@pulse-compute/wasm-build-support/assemblyscript-compile'); }
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) return require('../../build-support/src/assemblyscript-compile.js');
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const nativePlanCompiler = loadNativePlanCompiler();
|
|
61
|
+
const runtimeCore = loadRuntimeCore();
|
|
62
|
+
const runtimeContract = loadRuntimeContract();
|
|
63
|
+
const eventContract = loadEventContract();
|
|
64
|
+
const { resolveAsc } = loadBuildSupport();
|
|
65
|
+
const { memoryAbi } = (() => {
|
|
66
|
+
try {
|
|
67
|
+
return require('@pulse-compute/wasm-guest-link');
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error && error.code === 'MODULE_NOT_FOUND') return require('../../wasm-guest-link/src/index.js');
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
})();
|
|
73
|
+
const {
|
|
74
|
+
appendAssemblyScriptOptimizationArgs,
|
|
75
|
+
resolveNativeOptimization
|
|
76
|
+
} = require('@pulse-compute/wasm-build-support/native-optimization');
|
|
77
|
+
|
|
78
|
+
class CanonicalNativeCompileError extends Error {
|
|
79
|
+
constructor(message, detail = {}) {
|
|
80
|
+
super(message);
|
|
81
|
+
this.name = 'CanonicalNativeCompileError';
|
|
82
|
+
this.code = 'PULSE_CANONICAL_NATIVE_COMPILE_FAILED';
|
|
83
|
+
this.detail = Object.freeze({ ...detail });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function sha256(value) {
|
|
88
|
+
return crypto.createHash('sha256').update(value).digest('hex');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function stableObject(value) {
|
|
92
|
+
if (Array.isArray(value)) return value.map(stableObject);
|
|
93
|
+
if (!value || typeof value !== 'object') return value;
|
|
94
|
+
const out = {};
|
|
95
|
+
for (const key of Object.keys(value).sort()) if (value[key] !== undefined) out[key] = stableObject(value[key]);
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function deepFreeze(value) {
|
|
100
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
|
|
101
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
102
|
+
return Object.freeze(value);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function stableStringify(value, space = 0) {
|
|
106
|
+
return JSON.stringify(stableObject(value), null, space);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function inspectCanonicalNativeWasm(input, options = {}) {
|
|
110
|
+
const bytes = Buffer.isBuffer(input) ? input : fs.readFileSync(path.resolve(input));
|
|
111
|
+
if (!WebAssembly.validate(bytes)) throw new CanonicalNativeCompileError('Generated canonical native Wasm is not valid WebAssembly.');
|
|
112
|
+
const module = new WebAssembly.Module(bytes);
|
|
113
|
+
const imports = WebAssembly.Module.imports(module).map((entry) => Object.freeze({ module: entry.module, name: entry.name, kind: entry.kind }));
|
|
114
|
+
const exports = WebAssembly.Module.exports(module).map((entry) => Object.freeze({ name: entry.name, kind: entry.kind }));
|
|
115
|
+
const unexpectedModules = [...new Set(imports.map((entry) => entry.module).filter((name) => !['pulse_host', 'env'].includes(name)))];
|
|
116
|
+
if (unexpectedModules.length > 0) throw new CanonicalNativeCompileError('Canonical native Wasm imports an unsupported module.', { unexpectedModules, imports });
|
|
117
|
+
|
|
118
|
+
const allowedPulseImports = new Set(runtimeContract.CANONICAL_NATIVE_IMPORT_NAMES);
|
|
119
|
+
const pulseImports = imports.filter((entry) => entry.module === 'pulse_host').map((entry) => entry.name).sort();
|
|
120
|
+
const unexpectedPulseImports = pulseImports.filter((name) => !allowedPulseImports.has(name));
|
|
121
|
+
if (unexpectedPulseImports.length > 0) {
|
|
122
|
+
throw new CanonicalNativeCompileError('Canonical native Wasm imports a function outside the versioned pulse_host ABI.', { unexpectedPulseImports, pulseImports });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const allowedEnvImports = new Set(runtimeContract.CANONICAL_NATIVE_ALLOWED_ENV_IMPORTS);
|
|
126
|
+
const unexpectedEnvImports = imports.filter((entry) => entry.module === 'env' && !allowedEnvImports.has(entry.name));
|
|
127
|
+
if (unexpectedEnvImports.length > 0) {
|
|
128
|
+
throw new CanonicalNativeCompileError('Canonical native Wasm imports an unsupported AssemblyScript environment function.', { unexpectedEnvImports });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const exportNames = new Set(exports.map((entry) => entry.name));
|
|
132
|
+
const missingExports = runtimeContract.CANONICAL_NATIVE_EXPORT_NAMES.filter((name) => !exportNames.has(name));
|
|
133
|
+
if (missingExports.length > 0) throw new CanonicalNativeCompileError('Canonical native Wasm is missing required ABI exports.', { missingExports, exports });
|
|
134
|
+
const plan = options.plan;
|
|
135
|
+
const eventReachable = Boolean(plan && plan.events && plan.events.catalog && plan.events.catalog.events.length > 0);
|
|
136
|
+
const eventExportNames = eventContract.EVENT_NATIVE_ABI_EXTENSION.exports.map((entry) => entry.name);
|
|
137
|
+
const presentEventExports = eventExportNames.filter((name) => exportNames.has(name));
|
|
138
|
+
if (eventReachable && presentEventExports.length !== eventExportNames.length) {
|
|
139
|
+
throw new CanonicalNativeCompileError('Event-reachable canonical native Wasm is missing its conditional event ABI exports.', {
|
|
140
|
+
missingEventExports: eventExportNames.filter((name) => !exportNames.has(name)),
|
|
141
|
+
exports
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (plan && !eventReachable && presentEventExports.length > 0) {
|
|
145
|
+
throw new CanonicalNativeCompileError('HTTP-only canonical native Wasm unexpectedly exposes the conditional event ABI.', { presentEventExports });
|
|
146
|
+
}
|
|
147
|
+
return Object.freeze({
|
|
148
|
+
valid: true,
|
|
149
|
+
bytes: bytes.length,
|
|
150
|
+
sha256: sha256(bytes),
|
|
151
|
+
magic: bytes.subarray(0, 8).toString('hex'),
|
|
152
|
+
imports: Object.freeze(imports),
|
|
153
|
+
exports: Object.freeze(exports),
|
|
154
|
+
importModules: Object.freeze([...new Set(imports.map((entry) => entry.module))].sort())
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function resolveProviderRequirements(plan) {
|
|
159
|
+
const attached = providerRequirementsForCanonicalNativePlan(plan);
|
|
160
|
+
if (attached) return attached;
|
|
161
|
+
const recognition = packageOperationRecognitionFromEffects((plan.packages && plan.packages.effects) || []);
|
|
162
|
+
return collectProviderRequirements(plan, lowerCanonicalPackageOperations(recognition));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function realizeCanonicalNativePlan(plan, options = {}, providerRequirements) {
|
|
166
|
+
try {
|
|
167
|
+
assertProviderRequirementsForPlan(providerRequirements, plan);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
throw new CanonicalNativeCompileError('Canonical native realization requires the matching provider-neutral requirement record.', {
|
|
170
|
+
causeCode: error && error.code,
|
|
171
|
+
cause: error && error.message,
|
|
172
|
+
causeDetail: error && error.detail
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
const validation = nativePlanCompiler.validateCanonicalNativePlan(plan);
|
|
176
|
+
const packageLowering = packageLoweringForCanonicalNativePlan(plan);
|
|
177
|
+
const realizationArtifacts = Object.freeze((packageLowering && packageLowering.realizationArtifacts || [])
|
|
178
|
+
.map((artifact) => deepFreeze(stableObject(artifact))));
|
|
179
|
+
const guestUnits = Object.freeze((packageLowering && packageLowering.guestUnits || [])
|
|
180
|
+
.map((unit) => deepFreeze(stableObject(unit))));
|
|
181
|
+
const cwd = path.resolve(options.cwd || process.cwd());
|
|
182
|
+
const compilerPackageRoot = path.resolve(__dirname, '..');
|
|
183
|
+
const asc = resolveAsc(cwd) || resolveAsc(compilerPackageRoot);
|
|
184
|
+
if (!asc) throw new CanonicalNativeCompileError('AssemblyScript compiler dependency was not found.', { cwd, remediation: 'Install the lockfile-pinned AssemblyScript dependency before compiling native Wasm.' });
|
|
185
|
+
const generated = runtimeCore.generateCanonicalNativeAssemblyScript(plan, options);
|
|
186
|
+
const schemaCodecsActive = generated.manifest.schemaCodecs && generated.manifest.schemaCodecs.active === true;
|
|
187
|
+
let jsonAs;
|
|
188
|
+
if (schemaCodecsActive) {
|
|
189
|
+
let transform;
|
|
190
|
+
try {
|
|
191
|
+
transform = require.resolve('json-as', { paths: [compilerPackageRoot, cwd] });
|
|
192
|
+
} catch (error) {
|
|
193
|
+
throw new CanonicalNativeCompileError('The lockfile-pinned json-as transform was not found for Native schema codec compilation.', {
|
|
194
|
+
cwd,
|
|
195
|
+
package: 'json-as',
|
|
196
|
+
version: '1.5.0',
|
|
197
|
+
cause: error && error.message
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
const packageRoot = path.resolve(transform, '..', '..', '..');
|
|
201
|
+
const dependencyRoot = path.dirname(packageRoot);
|
|
202
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
|
|
203
|
+
if (packageJson.version !== '1.5.0') {
|
|
204
|
+
throw new CanonicalNativeCompileError('Native schema codec compilation requires json-as 1.5.0 exactly.', {
|
|
205
|
+
expected: '1.5.0',
|
|
206
|
+
actual: packageJson.version,
|
|
207
|
+
packageRoot
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
jsonAs = Object.freeze({ transform, packageRoot, dependencyRoot, version: packageJson.version });
|
|
211
|
+
}
|
|
212
|
+
const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pulse-canonical-native-'));
|
|
213
|
+
const requestedOutDir = options.outDir ? path.resolve(options.outDir) : undefined;
|
|
214
|
+
const outputDir = requestedOutDir || stagingDir;
|
|
215
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
216
|
+
const sourceFile = path.join(stagingDir, 'canonical-native.as.ts');
|
|
217
|
+
const wasmFile = path.join(outputDir, options.wasmFile || 'canonical-native.wasm');
|
|
218
|
+
const watFile = path.join(outputDir, options.watFile || 'canonical-native.wat');
|
|
219
|
+
try {
|
|
220
|
+
fs.writeFileSync(sourceFile, generated.source, 'utf8');
|
|
221
|
+
// Compile from a stable, relative entry name so AssemblyScript's name section and
|
|
222
|
+
// text output do not capture the random staging directory.
|
|
223
|
+
const args = [
|
|
224
|
+
asc.script,
|
|
225
|
+
path.basename(sourceFile),
|
|
226
|
+
'--outFile', wasmFile,
|
|
227
|
+
'--textFile', watFile,
|
|
228
|
+
'--runtime', schemaCodecsActive ? 'incremental' : 'stub',
|
|
229
|
+
'--noAssert',
|
|
230
|
+
'--optimize'
|
|
231
|
+
];
|
|
232
|
+
const optimization = appendAssemblyScriptOptimizationArgs(args, options.nativeOptimization);
|
|
233
|
+
if (guestUnits.length > 0) {
|
|
234
|
+
args.push(
|
|
235
|
+
'--importMemory',
|
|
236
|
+
'--noExportMemory',
|
|
237
|
+
'--initialMemory', String(memoryAbi.minimumPages),
|
|
238
|
+
'--maximumMemory', String(memoryAbi.maximumPages),
|
|
239
|
+
'--memoryBase', String(memoryAbi.layout.primaryStatic.start)
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
if (schemaCodecsActive) {
|
|
243
|
+
args.push(
|
|
244
|
+
'--exportRuntime',
|
|
245
|
+
'--transform', jsonAs.transform,
|
|
246
|
+
'--path', path.join(compilerPackageRoot, 'node_modules'),
|
|
247
|
+
'--path', jsonAs.dependencyRoot
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
const startedAt = Date.now();
|
|
251
|
+
const result = spawnSync(asc.executable, args, {
|
|
252
|
+
cwd: stagingDir,
|
|
253
|
+
encoding: 'utf8',
|
|
254
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
255
|
+
timeout: Number(options.timeoutMs || 120000),
|
|
256
|
+
env: schemaCodecsActive
|
|
257
|
+
? { ...process.env, JSON_STRICT: 'true', JSON_USE_FAST_PATH: '0' }
|
|
258
|
+
: process.env
|
|
259
|
+
});
|
|
260
|
+
const durationMs = Date.now() - startedAt;
|
|
261
|
+
if (result.error || result.status !== 0 || !fs.existsSync(wasmFile)) {
|
|
262
|
+
throw new CanonicalNativeCompileError('AssemblyScript failed to compile the canonical native plan.', {
|
|
263
|
+
status: result.status,
|
|
264
|
+
signal: result.signal,
|
|
265
|
+
error: result.error && result.error.message,
|
|
266
|
+
stdout: String(result.stdout || '').slice(-12000),
|
|
267
|
+
stderr: String(result.stderr || '').slice(-12000),
|
|
268
|
+
source: generated.source,
|
|
269
|
+
durationMs
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return Object.freeze({
|
|
273
|
+
plan,
|
|
274
|
+
validation,
|
|
275
|
+
realizationArtifacts,
|
|
276
|
+
guestUnits,
|
|
277
|
+
generated,
|
|
278
|
+
wasm: fs.readFileSync(wasmFile),
|
|
279
|
+
wat: fs.existsSync(watFile) ? fs.readFileSync(watFile, 'utf8') : '',
|
|
280
|
+
assemblyScriptVersion: require(path.join(asc.packageRoot, 'package.json')).version,
|
|
281
|
+
jsonAsVersion: jsonAs && jsonAs.version,
|
|
282
|
+
optimization,
|
|
283
|
+
durationMs,
|
|
284
|
+
output: requestedOutDir ? Object.freeze({ outDir: outputDir, wasmFile, watFile }) : undefined
|
|
285
|
+
});
|
|
286
|
+
} finally {
|
|
287
|
+
fs.rmSync(stagingDir, { recursive: true, force: true });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function realizeCanonicalNativeGuestUnits(realization, plan, options = {}) {
|
|
292
|
+
return realizeSelectedGuestUnits(realization, realization.guestUnits, options);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function verifyCanonicalNativeRealization(realization) {
|
|
296
|
+
const inspection = inspectCanonicalNativeWasm(realization.wasm, { plan: realization.plan });
|
|
297
|
+
const artifactBytes = Buffer.from(stableStringify(realization.realizationArtifacts), 'utf8');
|
|
298
|
+
const packageRealizationArtifacts = Object.freeze({
|
|
299
|
+
version: PACKAGE_REALIZATION_ARTIFACT_SET_VERSION,
|
|
300
|
+
count: realization.realizationArtifacts.length,
|
|
301
|
+
ids: Object.freeze(realization.realizationArtifacts.map((artifact) => String(artifact.id)).sort()),
|
|
302
|
+
bytes: artifactBytes.length,
|
|
303
|
+
sha256: sha256(artifactBytes)
|
|
304
|
+
});
|
|
305
|
+
const manifest = Object.freeze({
|
|
306
|
+
...realization.generated.manifest,
|
|
307
|
+
compilerVersion: runtimeContract.CANONICAL_NATIVE_COMPILER_VERSION,
|
|
308
|
+
assemblyScript: Object.freeze({ package: 'assemblyscript', version: realization.assemblyScriptVersion }),
|
|
309
|
+
optimization: resolveNativeOptimization(realization.optimization),
|
|
310
|
+
jsonAs: realization.jsonAsVersion
|
|
311
|
+
? Object.freeze({ package: 'json-as', version: realization.jsonAsVersion, transform: true, strict: true })
|
|
312
|
+
: null,
|
|
313
|
+
wasm: Object.freeze({ bytes: inspection.bytes, sha256: inspection.sha256, magic: inspection.magic }),
|
|
314
|
+
wat: Object.freeze({ bytes: Buffer.byteLength(realization.wat), sha256: sha256(realization.wat) }),
|
|
315
|
+
importModules: inspection.importModules,
|
|
316
|
+
imports: inspection.imports,
|
|
317
|
+
exports: inspection.exports,
|
|
318
|
+
packageRealizationArtifacts,
|
|
319
|
+
...(realization.guestLink ? {
|
|
320
|
+
guestUnitPlan: realization.guestLink.plan,
|
|
321
|
+
guestLinkReport: realization.guestLink.report,
|
|
322
|
+
finalWasmAudit: realization.guestLink.audit,
|
|
323
|
+
providerPackaging: realization.guestLink.providerPackaging
|
|
324
|
+
} : {}),
|
|
325
|
+
policy: runtimeContract.CANONICAL_NATIVE_POLICY
|
|
326
|
+
});
|
|
327
|
+
return Object.freeze({
|
|
328
|
+
version: runtimeContract.CANONICAL_NATIVE_WASM_VERSION,
|
|
329
|
+
compilerVersion: runtimeContract.CANONICAL_NATIVE_COMPILER_VERSION,
|
|
330
|
+
plan: realization.plan,
|
|
331
|
+
validation: realization.validation,
|
|
332
|
+
generated: realization.generated,
|
|
333
|
+
source: realization.generated.source,
|
|
334
|
+
sourceHash: realization.generated.sourceHash,
|
|
335
|
+
realizationArtifacts: realization.realizationArtifacts,
|
|
336
|
+
guestUnits: realization.guestUnits,
|
|
337
|
+
guestLink: realization.guestLink,
|
|
338
|
+
wasm: realization.wasm,
|
|
339
|
+
wat: realization.wat,
|
|
340
|
+
inspection,
|
|
341
|
+
manifest,
|
|
342
|
+
durationMs: realization.durationMs,
|
|
343
|
+
output: realization.output
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function compileCanonicalNativePlan(plan, options = {}) {
|
|
348
|
+
return executeCanonicalNativeModuleSpine(plan, options, {
|
|
349
|
+
resolveProviderRequirements,
|
|
350
|
+
realize: realizeCanonicalNativePlan,
|
|
351
|
+
realizeGuests: realizeCanonicalNativeGuestUnits,
|
|
352
|
+
verify: verifyCanonicalNativeRealization
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function writeCanonicalNativeModule(compiled, outDir, options = {}) {
|
|
357
|
+
if (!compiled || !Buffer.isBuffer(compiled.wasm) || !compiled.manifest) throw new TypeError('writeCanonicalNativeModule requires a compiled canonical native module.');
|
|
358
|
+
const target = path.resolve(outDir);
|
|
359
|
+
fs.mkdirSync(target, { recursive: true });
|
|
360
|
+
const sourceFile = path.join(target, options.sourceFile || 'canonical-native.as.ts');
|
|
361
|
+
const wasmFile = path.join(target, options.wasmFile || 'canonical-native.wasm');
|
|
362
|
+
const watFile = path.join(target, options.watFile || 'canonical-native.wat');
|
|
363
|
+
const planFile = path.join(target, options.planFile || 'canonical-native-plan.json');
|
|
364
|
+
const manifestFile = path.join(target, options.manifestFile || 'canonical-native-manifest.json');
|
|
365
|
+
const realizationArtifactsFile = compiled.realizationArtifacts.length > 0
|
|
366
|
+
? path.join(target, options.realizationArtifactsFile || 'package-artifacts.json')
|
|
367
|
+
: undefined;
|
|
368
|
+
const guestUnitPlanFile = compiled.guestLink
|
|
369
|
+
? path.join(target, options.guestUnitPlanFile || 'guest-unit-plan.json')
|
|
370
|
+
: undefined;
|
|
371
|
+
const guestLinkReportFile = compiled.guestLink
|
|
372
|
+
? path.join(target, options.guestLinkReportFile || 'guest-link-report.json')
|
|
373
|
+
: undefined;
|
|
374
|
+
const finalWasmAuditFile = compiled.guestLink
|
|
375
|
+
? path.join(target, options.finalWasmAuditFile || 'final-wasm-audit.json')
|
|
376
|
+
: undefined;
|
|
377
|
+
fs.writeFileSync(sourceFile, compiled.source, 'utf8');
|
|
378
|
+
fs.writeFileSync(wasmFile, compiled.wasm);
|
|
379
|
+
fs.writeFileSync(watFile, compiled.wat, 'utf8');
|
|
380
|
+
fs.writeFileSync(planFile, `${nativePlanCompiler.stableStringify(compiled.plan, 2)}\n`, 'utf8');
|
|
381
|
+
fs.writeFileSync(manifestFile, `${stableStringify(compiled.manifest, 2)}\n`, 'utf8');
|
|
382
|
+
if (realizationArtifactsFile) {
|
|
383
|
+
fs.writeFileSync(realizationArtifactsFile, `${stableStringify(compiled.realizationArtifacts, 2)}\n`, 'utf8');
|
|
384
|
+
}
|
|
385
|
+
if (guestUnitPlanFile) fs.writeFileSync(guestUnitPlanFile, `${stableStringify(compiled.guestLink.plan, 2)}\n`, 'utf8');
|
|
386
|
+
if (guestLinkReportFile) fs.writeFileSync(guestLinkReportFile, `${stableStringify(compiled.guestLink.report, 2)}\n`, 'utf8');
|
|
387
|
+
if (finalWasmAuditFile) fs.writeFileSync(finalWasmAuditFile, `${stableStringify(compiled.guestLink.audit, 2)}\n`, 'utf8');
|
|
388
|
+
return Object.freeze({
|
|
389
|
+
target,
|
|
390
|
+
sourceFile,
|
|
391
|
+
wasmFile,
|
|
392
|
+
watFile,
|
|
393
|
+
planFile,
|
|
394
|
+
manifestFile,
|
|
395
|
+
realizationArtifactsFile,
|
|
396
|
+
guestUnitPlanFile,
|
|
397
|
+
guestLinkReportFile,
|
|
398
|
+
finalWasmAuditFile,
|
|
399
|
+
manifest: compiled.manifest
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
module.exports = Object.freeze({
|
|
404
|
+
CANONICAL_NATIVE_WASM_VERSION: runtimeContract.CANONICAL_NATIVE_WASM_VERSION,
|
|
405
|
+
CANONICAL_NATIVE_COMPILER_VERSION: runtimeContract.CANONICAL_NATIVE_COMPILER_VERSION,
|
|
406
|
+
CanonicalNativeCompileError,
|
|
407
|
+
compileCanonicalNativePlan,
|
|
408
|
+
inspectCanonicalNativeWasm,
|
|
409
|
+
writeCanonicalNativeModule,
|
|
410
|
+
stableStringify
|
|
411
|
+
});
|