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.
- package/README.md +92 -0
- package/bin/space-data-module.js +85 -1
- package/docs/module-publication-standard.md +7 -3
- package/docs/propagator-abi.md +477 -0
- package/include/orbpro/orbpro_propagator_abi.h +312 -0
- package/package.json +7 -1
- package/schemas/PluginManifest.fbs +46 -1
- package/schemas/orbpro/Propagator.fbs +161 -3
- package/src/browser.js +11 -0
- package/src/bundle/index.js +1 -0
- package/src/bundle/sigdomain.js +22 -0
- package/src/capabilities.js +91 -0
- package/src/compliance/index.js +8 -0
- package/src/compliance/pluginCompliance.js +76 -32
- package/src/flow/flowCompiler.js +231 -3
- package/src/flow/flowRuntimeHost.js +26 -0
- package/src/flow/isomorphicFlowHost.js +8 -0
- package/src/generated/orbpro/manifest/plugin-family.d.ts +9 -1
- package/src/generated/orbpro/manifest/plugin-family.js +8 -0
- package/src/generated/orbpro/manifest/plugin-family.ts +8 -0
- package/src/generated/orbpro/propagator-abi.js +118 -0
- package/src/generated/orbpro/propagator-abi.ts +199 -0
- package/src/host/browserModuleHarness.js +26 -0
- package/src/host/isomorphicLoader.js +57 -11
- package/src/host/runtimeTargetGate.js +256 -0
- package/src/host/workerModuleHarness.js +7 -0
- package/src/index.d.ts +47 -0
- package/src/index.js +11 -0
- package/src/manifest/normalize.js +113 -4
- package/src/scaffold/copyTemplate.js +71 -0
- package/src/scaffold/index.js +150 -0
- package/src/scaffold/tokens.js +90 -0
- package/src/testing/parityBrowserRunner.js +11 -0
- package/src/testing/parityGate.js +287 -27
- package/templates/propagator-module/README.md +99 -0
- package/templates/propagator-module/build.js +103 -0
- package/templates/propagator-module/package.json +19 -0
- package/templates/propagator-module/plugin-manifest.json +66 -0
- package/templates/propagator-module/src/__MODULE_NAME_SNAKE__.cpp +450 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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")
|