space-data-module-sdk 0.8.11 → 0.8.13

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 (40) hide show
  1. package/README.md +92 -0
  2. package/bin/space-data-module.js +85 -1
  3. package/docs/module-publication-standard.md +7 -3
  4. package/docs/propagator-abi.md +477 -0
  5. package/include/orbpro/orbpro_propagator_abi.h +312 -0
  6. package/package.json +7 -1
  7. package/schemas/PluginManifest.fbs +46 -1
  8. package/schemas/orbpro/Propagator.fbs +161 -3
  9. package/src/browser.js +11 -0
  10. package/src/bundle/index.js +1 -0
  11. package/src/bundle/sigdomain.js +22 -0
  12. package/src/capabilities.js +91 -0
  13. package/src/compliance/index.js +8 -0
  14. package/src/compliance/pluginCompliance.js +76 -32
  15. package/src/flow/flowCompiler.js +231 -3
  16. package/src/flow/flowRuntimeHost.js +26 -0
  17. package/src/flow/isomorphicFlowHost.js +8 -0
  18. package/src/generated/orbpro/manifest/plugin-family.d.ts +9 -1
  19. package/src/generated/orbpro/manifest/plugin-family.js +8 -0
  20. package/src/generated/orbpro/manifest/plugin-family.ts +8 -0
  21. package/src/generated/orbpro/propagator-abi.js +118 -0
  22. package/src/generated/orbpro/propagator-abi.ts +199 -0
  23. package/src/host/browserModuleHarness.js +26 -0
  24. package/src/host/isomorphicLoader.js +57 -11
  25. package/src/host/runtimeTargetGate.js +256 -0
  26. package/src/host/workerModuleHarness.js +7 -0
  27. package/src/index.d.ts +47 -0
  28. package/src/index.js +11 -0
  29. package/src/manifest/normalize.js +113 -4
  30. package/src/scaffold/copyTemplate.js +71 -0
  31. package/src/scaffold/index.js +150 -0
  32. package/src/scaffold/tokens.js +90 -0
  33. package/src/testing/parityBrowserRunner.js +11 -0
  34. package/src/testing/parityGate.js +287 -27
  35. package/templates/propagator-module/README.md +99 -0
  36. package/templates/propagator-module/build.js +103 -0
  37. package/templates/propagator-module/package.json +19 -0
  38. package/templates/propagator-module/plugin-manifest.json +66 -0
  39. package/templates/propagator-module/src/__MODULE_NAME_SNAKE__.cpp +450 -0
  40. package/templates/propagator-module/tests/module.build.test.mjs +103 -0
@@ -0,0 +1,118 @@
1
+ // ===========================================================================
2
+ // GENERATED FILE — DO NOT EDIT.
3
+ //
4
+ // Source of truth : schemas/orbpro/Propagator.fbs
5
+ // Generator : scripts/generate-propagator-abi.mjs
6
+ // Drift gate : scripts/check-propagator-abi.mjs (runs in `npm test`)
7
+ // Contract : docs/propagator-abi.md
8
+ //
9
+ // These constants exist so that no JavaScript consumer ever hard-codes a byte
10
+ // offset again. Read a state vector with ORBPRO_STATE_VECTOR.offsets.position,
11
+ // never with the literal 8.
12
+ // ===========================================================================
13
+
14
+ export const ReferenceFrame = Object.freeze({
15
+ TEME: 0,
16
+ J2000: 1,
17
+ ICRF: 2,
18
+ ECEF: 3,
19
+ MCI: 4,
20
+ MCMF: 5,
21
+ });
22
+
23
+ export const StateFlags = Object.freeze({
24
+ NONE: 0,
25
+ VALID: 1,
26
+ IN_ECLIPSE: 2,
27
+ DECAYED: 4,
28
+ MANEUVERING: 8,
29
+ EXTRAPOLATED: 16,
30
+ HAS_COVARIANCE: 32,
31
+ });
32
+
33
+ export const ORBPRO_STATE_VECTOR = Object.freeze({
34
+ name: "StateVector",
35
+ cName: "OrbProStateVector",
36
+ size: 64,
37
+ alignment: 8,
38
+ offsets: Object.freeze({
39
+ epoch: 0,
40
+ position: 8,
41
+ velocity: 32,
42
+ reference_frame: 56,
43
+ flags: 60,
44
+ }),
45
+ fields: Object.freeze({
46
+ epoch: Object.freeze({ offset: 0, size: 8, length: 1, view: "Float64" }),
47
+ position: Object.freeze({ offset: 8, size: 24, length: 3, view: "Float64" }),
48
+ velocity: Object.freeze({ offset: 32, size: 24, length: 3, view: "Float64" }),
49
+ reference_frame: Object.freeze({ offset: 56, size: 1, length: 1, view: "Uint8" }),
50
+ flags: Object.freeze({ offset: 60, size: 4, length: 1, view: "Uint32" }),
51
+ }),
52
+ });
53
+
54
+ export const ORBPRO_ORBITAL_ELEMENTS = Object.freeze({
55
+ name: "OrbitalElements",
56
+ cName: "OrbProOrbitalElements",
57
+ size: 64,
58
+ alignment: 8,
59
+ offsets: Object.freeze({
60
+ semi_major_axis: 0,
61
+ eccentricity: 8,
62
+ inclination: 16,
63
+ raan: 24,
64
+ arg_periapsis: 32,
65
+ true_anomaly: 40,
66
+ epoch: 48,
67
+ reserved: 56,
68
+ }),
69
+ fields: Object.freeze({
70
+ semi_major_axis: Object.freeze({ offset: 0, size: 8, length: 1, view: "Float64" }),
71
+ eccentricity: Object.freeze({ offset: 8, size: 8, length: 1, view: "Float64" }),
72
+ inclination: Object.freeze({ offset: 16, size: 8, length: 1, view: "Float64" }),
73
+ raan: Object.freeze({ offset: 24, size: 8, length: 1, view: "Float64" }),
74
+ arg_periapsis: Object.freeze({ offset: 32, size: 8, length: 1, view: "Float64" }),
75
+ true_anomaly: Object.freeze({ offset: 40, size: 8, length: 1, view: "Float64" }),
76
+ epoch: Object.freeze({ offset: 48, size: 8, length: 1, view: "Float64" }),
77
+ reserved: Object.freeze({ offset: 56, size: 8, length: 1, view: "Float64" }),
78
+ }),
79
+ });
80
+
81
+ export const ORBPRO_OMM_RECORD = Object.freeze({
82
+ name: "OMMRecord",
83
+ cName: "OrbProOMMRecord",
84
+ size: 88,
85
+ alignment: 8,
86
+ offsets: Object.freeze({
87
+ epoch_jd: 0,
88
+ mean_motion: 8,
89
+ eccentricity: 16,
90
+ inclination: 24,
91
+ ra_of_asc_node: 32,
92
+ arg_of_pericenter: 40,
93
+ mean_anomaly: 48,
94
+ bstar: 56,
95
+ mean_motion_dot: 64,
96
+ mean_motion_ddot: 72,
97
+ norad_cat_id: 80,
98
+ }),
99
+ fields: Object.freeze({
100
+ epoch_jd: Object.freeze({ offset: 0, size: 8, length: 1, view: "Float64" }),
101
+ mean_motion: Object.freeze({ offset: 8, size: 8, length: 1, view: "Float64" }),
102
+ eccentricity: Object.freeze({ offset: 16, size: 8, length: 1, view: "Float64" }),
103
+ inclination: Object.freeze({ offset: 24, size: 8, length: 1, view: "Float64" }),
104
+ ra_of_asc_node: Object.freeze({ offset: 32, size: 8, length: 1, view: "Float64" }),
105
+ arg_of_pericenter: Object.freeze({ offset: 40, size: 8, length: 1, view: "Float64" }),
106
+ mean_anomaly: Object.freeze({ offset: 48, size: 8, length: 1, view: "Float64" }),
107
+ bstar: Object.freeze({ offset: 56, size: 8, length: 1, view: "Float64" }),
108
+ mean_motion_dot: Object.freeze({ offset: 64, size: 8, length: 1, view: "Float64" }),
109
+ mean_motion_ddot: Object.freeze({ offset: 72, size: 8, length: 1, view: "Float64" }),
110
+ norad_cat_id: Object.freeze({ offset: 80, size: 4, length: 1, view: "Uint32" }),
111
+ }),
112
+ });
113
+
114
+ export const ORBPRO_PROPAGATOR_ABI = Object.freeze({
115
+ StateVector: ORBPRO_STATE_VECTOR,
116
+ OrbitalElements: ORBPRO_ORBITAL_ELEMENTS,
117
+ OMMRecord: ORBPRO_OMM_RECORD,
118
+ });
@@ -0,0 +1,199 @@
1
+ // ===========================================================================
2
+ // GENERATED FILE — DO NOT EDIT.
3
+ //
4
+ // Source of truth : schemas/orbpro/Propagator.fbs
5
+ // Generator : scripts/generate-propagator-abi.mjs
6
+ // Drift gate : scripts/check-propagator-abi.mjs (runs in `npm test`)
7
+ // Contract : docs/propagator-abi.md
8
+ //
9
+ // These constants exist so that no JavaScript consumer ever hard-codes a byte
10
+ // offset again. Read a state vector with ORBPRO_STATE_VECTOR.offsets.position,
11
+ // never with the literal 8.
12
+ // ===========================================================================
13
+
14
+
15
+ export enum ReferenceFrame {
16
+ TEME = 0,
17
+ J2000 = 1,
18
+ ICRF = 2,
19
+ ECEF = 3,
20
+ MCI = 4,
21
+ MCMF = 5,
22
+ }
23
+
24
+ /**
25
+ * StateVector.flags is a BITFIELD carrying any OR-combination of these, so it
26
+ * is declared `uint` on the struct rather than typed to this enum. The C
27
+ * enumerators are generated from here anyway — they are the contract.
28
+ */
29
+ export enum StateFlags {
30
+ NONE = 0,
31
+ VALID = 1,
32
+ IN_ECLIPSE = 2,
33
+ DECAYED = 4,
34
+ MANEUVERING = 8,
35
+ EXTRAPOLATED = 16,
36
+ HAS_COVARIANCE = 32,
37
+ }
38
+
39
+ /** One field's placement inside an ABI struct. */
40
+ export interface AbiField {
41
+ readonly offset: number;
42
+ readonly size: number;
43
+ /** Element count for array fields, 1 for scalars. */
44
+ readonly length: number;
45
+ /** DataView accessor suffix, e.g. "Float64" for getFloat64. */
46
+ readonly view: string;
47
+ }
48
+
49
+ /** One ABI struct's byte layout. */
50
+ export interface AbiStruct {
51
+ readonly name: string;
52
+ readonly cName: string;
53
+ readonly size: number;
54
+ readonly alignment: number;
55
+ readonly offsets: Readonly<Record<string, number>>;
56
+ readonly fields: Readonly<Record<string, AbiField>>;
57
+ }
58
+
59
+ /**
60
+ * Orbital state vector — 64 bytes, 8-byte aligned. Mirrors
61
+ * `OrbProStateVector` in orbpro-integration/sdk/include/orbpro_propagator.h
62
+ * byte for byte:
63
+ *
64
+ * 0 8 epoch (Julian date, float64)
65
+ * 8 24 position (METERS)
66
+ * 32 24 velocity (METERS/SECOND)
67
+ * 56 1 reference_frame (ubyte)
68
+ * 57 3 padding, MUST be zero
69
+ * 60 4 flags (uint32)
70
+ *
71
+ * NORMATIVE UNITS: position METERS, velocity METERS/SECOND. There is no km
72
+ * variant and no host-side conversion — the engine hands these straight to
73
+ * Cesium Cartesian3, whose unit is metres, and both shipped propagators emit
74
+ * meters. The C header used to declare `reference_frame` as a uint32 at
75
+ * offset 56, wire-identical to this ubyte+padding only by little-endian
76
+ * accident; it now declares ubyte + 3 reserved so the two agree by
77
+ * construction.
78
+ *
79
+ * Ruling: graph/findings/official-harness-shapes.md §4.1 / §4.2
80
+ */
81
+ export const ORBPRO_STATE_VECTOR: AbiStruct = {
82
+ name: "StateVector",
83
+ cName: "OrbProStateVector",
84
+ size: 64,
85
+ alignment: 8,
86
+ offsets: {
87
+ epoch: 0,
88
+ position: 8,
89
+ velocity: 32,
90
+ reference_frame: 56,
91
+ flags: 60,
92
+ },
93
+ fields: {
94
+ epoch: { offset: 0, size: 8, length: 1, view: "Float64" },
95
+ position: { offset: 8, size: 24, length: 3, view: "Float64" },
96
+ velocity: { offset: 32, size: 24, length: 3, view: "Float64" },
97
+ reference_frame: { offset: 56, size: 1, length: 1, view: "Uint8" },
98
+ flags: { offset: 60, size: 4, length: 1, view: "Uint32" },
99
+ },
100
+ } as const;
101
+
102
+ /**
103
+ * Keplerian orbital elements — the OPTIONAL initialization input accepted by
104
+ * `plugin_init_elements`. 64 bytes, 8-byte aligned.
105
+ *
106
+ * UNITS NOTE: `semi_major_axis` is KILOMETRES. That is deliberate and it is
107
+ * NOT an inconsistency with StateVector's metres: this is an INPUT element
108
+ * set, not an output state vector, and the two are different structs on
109
+ * different sides of the call. Do not "unify" them — see the normative units
110
+ * block in the generated C header.
111
+ */
112
+ export const ORBPRO_ORBITAL_ELEMENTS: AbiStruct = {
113
+ name: "OrbitalElements",
114
+ cName: "OrbProOrbitalElements",
115
+ size: 64,
116
+ alignment: 8,
117
+ offsets: {
118
+ semi_major_axis: 0,
119
+ eccentricity: 8,
120
+ inclination: 16,
121
+ raan: 24,
122
+ arg_periapsis: 32,
123
+ true_anomaly: 40,
124
+ epoch: 48,
125
+ reserved: 56,
126
+ },
127
+ fields: {
128
+ semi_major_axis: { offset: 0, size: 8, length: 1, view: "Float64" },
129
+ eccentricity: { offset: 8, size: 8, length: 1, view: "Float64" },
130
+ inclination: { offset: 16, size: 8, length: 1, view: "Float64" },
131
+ raan: { offset: 24, size: 8, length: 1, view: "Float64" },
132
+ arg_periapsis: { offset: 32, size: 8, length: 1, view: "Float64" },
133
+ true_anomaly: { offset: 40, size: 8, length: 1, view: "Float64" },
134
+ epoch: { offset: 48, size: 8, length: 1, view: "Float64" },
135
+ reserved: { offset: 56, size: 8, length: 1, view: "Float64" },
136
+ },
137
+ } as const;
138
+
139
+ /**
140
+ * Binary OMM record — the mean-element ingest struct. 88 bytes, 8-byte
141
+ * aligned.
142
+ *
143
+ * !! THIS STRUCT IS ALSO AN ON-DISK FORMAT !!
144
+ * -----------------------------------------------------------------------
145
+ * It crosses the ABI (`plugin_init_omm`, `plugin_entity_add_omm`) AND is
146
+ * persisted verbatim as a SQLite BLOB by the first-party SGP4 module
147
+ * (`sgp4_plugin.cpp`, `sqlite3_bind_blob(..., &omm, sizeof(OrbProOMMRecord), ...)`).
148
+ * Until W1.1 it carried NO size or offset lock anywhere in the stack, so the
149
+ * layout that every stored blob depends on was held only by the field order
150
+ * of one hand-written C struct in one module.
151
+ *
152
+ * The layout declared here is that layout, EXACTLY as it has been written to
153
+ * disk — the four trailing padding bytes at offset 84 included. This is a
154
+ * description of the wire as it already exists, not a redesign of it; the
155
+ * generated locks now pin it. Migrating the format is explicitly out of
156
+ * scope and would invalidate every stored blob.
157
+ *
158
+ * UNITS: angles in DEGREES, mean motion in REV/DAY, bstar in 1/earth-radii.
159
+ * These are the SDS $OMM units, carried through unconverted.
160
+ */
161
+ export const ORBPRO_OMM_RECORD: AbiStruct = {
162
+ name: "OMMRecord",
163
+ cName: "OrbProOMMRecord",
164
+ size: 88,
165
+ alignment: 8,
166
+ offsets: {
167
+ epoch_jd: 0,
168
+ mean_motion: 8,
169
+ eccentricity: 16,
170
+ inclination: 24,
171
+ ra_of_asc_node: 32,
172
+ arg_of_pericenter: 40,
173
+ mean_anomaly: 48,
174
+ bstar: 56,
175
+ mean_motion_dot: 64,
176
+ mean_motion_ddot: 72,
177
+ norad_cat_id: 80,
178
+ },
179
+ fields: {
180
+ epoch_jd: { offset: 0, size: 8, length: 1, view: "Float64" },
181
+ mean_motion: { offset: 8, size: 8, length: 1, view: "Float64" },
182
+ eccentricity: { offset: 16, size: 8, length: 1, view: "Float64" },
183
+ inclination: { offset: 24, size: 8, length: 1, view: "Float64" },
184
+ ra_of_asc_node: { offset: 32, size: 8, length: 1, view: "Float64" },
185
+ arg_of_pericenter: { offset: 40, size: 8, length: 1, view: "Float64" },
186
+ mean_anomaly: { offset: 48, size: 8, length: 1, view: "Float64" },
187
+ bstar: { offset: 56, size: 8, length: 1, view: "Float64" },
188
+ mean_motion_dot: { offset: 64, size: 8, length: 1, view: "Float64" },
189
+ mean_motion_ddot: { offset: 72, size: 8, length: 1, view: "Float64" },
190
+ norad_cat_id: { offset: 80, size: 4, length: 1, view: "Uint32" },
191
+ },
192
+ } as const;
193
+
194
+ /** Every ABI struct, keyed by its IDL name. */
195
+ export const ORBPRO_PROPAGATOR_ABI: Readonly<Record<string, AbiStruct>> = {
196
+ StateVector: ORBPRO_STATE_VECTOR,
197
+ OrbitalElements: ORBPRO_ORBITAL_ELEMENTS,
198
+ OMMRecord: ORBPRO_OMM_RECORD,
199
+ } as const;
@@ -49,6 +49,10 @@ import {
49
49
  resolveModuleSignaturePolicy,
50
50
  verifyModuleArtifact,
51
51
  } from "../bundle/signing.js";
52
+ import {
53
+ assertArtifactRuntimeTarget,
54
+ RuntimeTargetError,
55
+ } from "./runtimeTargetGate.js";
52
56
  // Artifact byte reduction is an ARTIFACT concern shared by all three runtimes,
53
57
  // so it lives on `space-data-module-sdk/bundle`. Re-exported here because a
54
58
  // caller loading a module in the browser needs it in the same breath.
@@ -259,6 +263,27 @@ function createImportedMemory(options = {}) {
259
263
  return new WebAssembly.Memory(descriptor);
260
264
  }
261
265
 
266
+ const BROWSER_RUNTIME_TARGET = "browser";
267
+
268
+ export { RuntimeTargetError };
269
+
270
+ /**
271
+ * TRI-RUNTIME ISOMORPHISM, ENFORCED AT THE DOOR.
272
+ *
273
+ * This harness IS the browser leg of the tri-runtime contract, wherever the
274
+ * JavaScript happens to be running — asking it to load an artifact that does
275
+ * not declare the browser is asking for a divergence. The shared gate in
276
+ * `runtimeTargetGate.js` does the work; both declarations are consulted and
277
+ * the artifact's own embedded record wins on conflict.
278
+ */
279
+ export function assertBrowserRuntimeTarget(wasmModule, manifest) {
280
+ assertArtifactRuntimeTarget({
281
+ wasmModule,
282
+ manifest,
283
+ leg: BROWSER_RUNTIME_TARGET,
284
+ });
285
+ }
286
+
262
287
  function resolveManifestSurface(manifest) {
263
288
  const surfaces = Array.isArray(manifest?.invokeSurfaces)
264
289
  ? manifest.invokeSurfaces
@@ -471,6 +496,7 @@ export async function createBrowserModuleHarness(options = {}) {
471
496
  ownedArtifactBytes = null;
472
497
  wasmSource = null;
473
498
  options.wasmSource = null;
499
+ assertBrowserRuntimeTarget(wasmModule, options.manifest);
474
500
  const moduleImports = WebAssembly.Module.imports(wasmModule);
475
501
  const needsHostBridge = moduleImports.some(
476
502
  (entry) => entry.module === DEFAULT_HOSTCALL_IMPORT_MODULE,
@@ -21,12 +21,14 @@
21
21
  import {
22
22
  createBrowserModuleHarness,
23
23
  toLoadableWasmBytes,
24
+ zeroWasmBytes,
24
25
  } from "./browserModuleHarness.js";
25
26
  import {
26
27
  resolveModuleSignaturePolicy,
27
28
  verifyModuleArtifact,
28
29
  } from "../bundle/signing.js";
29
30
  import { attachHostDispatch, inspectModule } from "./isomorphicLoaderCore.js";
31
+ import { assertArtifactRuntimeTarget } from "./runtimeTargetGate.js";
30
32
 
31
33
  export { inspectModule, attachHostDispatch };
32
34
 
@@ -203,21 +205,65 @@ export async function loadModule(options = {}) {
203
205
  );
204
206
  }
205
207
 
206
- if (signaturePolicy) {
208
+ const runtimeKind = options.runtimeKind ?? "wasmedge";
209
+
210
+ // ONE READ of the artifact, serving every question this function asks of the
211
+ // bytes: the signature, the runtime-target declaration, and the profile
212
+ // inspection below. Each of those used to open the file for itself. The
213
+ // plaintext buffer this function materialized is scrubbed the moment the
214
+ // last of them is answered, matching the browser harness's
215
+ // ownedArtifactBytes contract.
216
+ const runtimeHostRequested =
217
+ String(options.hostProfile ?? "").trim().toLowerCase() === "runtime-host" ||
218
+ Array.isArray(options.modules) ||
219
+ (typeof options.defaultModuleId === "string" &&
220
+ options.defaultModuleId.trim().length > 0);
221
+ // The profile inspection is the ONLY consumer here that needs a compiled
222
+ // module. The runtime-host path does not take it, and it must not start
223
+ // paying a V8 compile of the whole artifact on every load just because the
224
+ // runtime-target gate arrived — the gate reads a custom section, which is a
225
+ // byte-level question.
226
+ const needsCompiledModule =
227
+ runtimeKind === "wasmedge" &&
228
+ !runtimeHostRequested &&
229
+ !options.wasmEdgeRunnerBinary;
230
+ const needsBytes = Boolean(signaturePolicy) || runtimeKind === "wasmedge";
231
+ let artifactBytes = null;
232
+ let wasmModule = null;
233
+ let embeddedManifest = null;
234
+ if (needsBytes) {
207
235
  const { readFile } = await import("node:fs/promises");
208
- await verifyModuleArtifact(await readFile(source), signaturePolicy);
236
+ artifactBytes = new Uint8Array(await readFile(source));
237
+ if (signaturePolicy) {
238
+ await verifyModuleArtifact(artifactBytes, signaturePolicy);
239
+ }
240
+ if (runtimeKind === "wasmedge") {
241
+ const { locateEmbeddedPlgManifest } = await import(
242
+ "../compliance/index.js"
243
+ );
244
+ embeddedManifest =
245
+ locateEmbeddedPlgManifest(artifactBytes)?.decoded ?? null;
246
+ }
247
+ if (needsCompiledModule) {
248
+ wasmModule = await WebAssembly.compile(toLoadableWasmBytes(artifactBytes));
249
+ }
250
+ zeroWasmBytes(artifactBytes);
251
+ artifactBytes = null;
209
252
  }
210
253
 
211
- const runtimeKind = options.runtimeKind ?? "wasmedge";
212
254
  if (runtimeKind === "wasmedge") {
213
- const runtimeHostRequested =
214
- String(options.hostProfile ?? "").trim().toLowerCase() === "runtime-host" ||
215
- Array.isArray(options.modules) ||
216
- (typeof options.defaultModuleId === "string" &&
217
- options.defaultModuleId.trim().length > 0);
218
- if (!runtimeHostRequested && !options.wasmEdgeRunnerBinary) {
219
- const { readFile } = await import("node:fs/promises");
220
- const inspection = await inspectModule(await readFile(source));
255
+ // MIRROR OF THE BROWSER GATE. Enforcing the declaration on one leg only is
256
+ // itself a divergence between the legs: a `["browser"]`-only artifact
257
+ // handed to WasmEdge would run until it reached something WasmEdge does
258
+ // not serve, while the reverse case is refused at the door. Both legs read
259
+ // the same declaration and refuse the same way.
260
+ assertArtifactRuntimeTarget({
261
+ embeddedManifest,
262
+ manifest: options.manifest,
263
+ leg: "wasmedge",
264
+ });
265
+ if (needsCompiledModule) {
266
+ const inspection = await inspectModule(wasmModule);
221
267
  if (
222
268
  (inspection.profile === "standalone" || inspection.profile === "module-host-abi") &&
223
269
  inspection.exports.includes("_start")