space-data-module-sdk 0.5.13 → 0.5.14
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 +0 -22
- package/package.json +1 -4
- package/src/compiler/flatcSupport.js +3 -47
- package/src/compliance/pluginCompliance.js +130 -0
- package/src/index.d.ts +1 -14
- package/src/invoke/codec.js +7 -9
- package/src/testing/index.d.ts +0 -109
- package/src/testing/index.js +0 -16
- package/src/transport/records.js +53 -47
- package/src/testing/buildWasmEdgeRunner.js +0 -214
- package/src/testing/moduleHarness.js +0 -62
- package/src/testing/native/wasmedge_emscripten_pthread_runner.c +0 -1001
- package/src/testing/processInvoke.js +0 -226
package/README.md
CHANGED
|
@@ -14,28 +14,11 @@ This repository is the source of truth for module-level concerns:
|
|
|
14
14
|
- the `sds.bundle` single-file container
|
|
15
15
|
- deployment authorization plus SDS publication records (`REC`, `PNM`, `ENC`)
|
|
16
16
|
- the first canonical module hostcall/import ABI surface
|
|
17
|
-
- shared module-level testing/runtime harnesses, including the WasmEdge
|
|
18
|
-
process runner used by package-level validation suites
|
|
19
17
|
|
|
20
18
|
<p align="center">
|
|
21
19
|
<img src="docs/architecture.svg" alt="Module architecture overview" width="820" />
|
|
22
20
|
</p>
|
|
23
21
|
|
|
24
|
-
## Shared Harness Ownership
|
|
25
|
-
|
|
26
|
-
This repo owns the generic module-side runtime harnesses used across the stack:
|
|
27
|
-
|
|
28
|
-
- `createModuleHarness(...)` for process and WasmEdge-backed module invocation
|
|
29
|
-
- `resolveModuleHarnessLaunchPlan(...)` for portable launch planning
|
|
30
|
-
- `buildWasmEdgeEmscriptenPthreadRunner(...)` plus the shared native runner
|
|
31
|
-
source and runner-level pthread smoke test
|
|
32
|
-
|
|
33
|
-
Flow-specific standalone harnessing lives in `sdn-flow`, which layers flow
|
|
34
|
-
enqueue/drain behavior on top of its compiled standalone runtime host. Package-
|
|
35
|
-
specific validation suites, including conjunction replay/V&V, are expected to
|
|
36
|
-
sit on top of these shared harnesses instead of defining their own runtime
|
|
37
|
-
process model.
|
|
38
|
-
|
|
39
22
|
## Module Artifact Model
|
|
40
23
|
|
|
41
24
|
A compliant module built with this SDK is always a valid `.wasm` artifact with:
|
|
@@ -195,11 +178,6 @@ semantics.
|
|
|
195
178
|
This repo now exposes a manifest-driven harness generator from
|
|
196
179
|
`space-data-module-sdk/testing` and two complementary integration suites:
|
|
197
180
|
|
|
198
|
-
- shared process-level helpers for command-surface runtimes:
|
|
199
|
-
- `createPluginInvokeProcessClient(...)`
|
|
200
|
-
- `resolveWasmEdgePluginLaunchPlan(...)`
|
|
201
|
-
- `buildWasmEdgeEmscriptenPthreadRunner(...)`
|
|
202
|
-
|
|
203
181
|
- `npm run test:runtime-matrix`
|
|
204
182
|
- cross-language runtime smoke across the same WASM in Node.js, Go, Python,
|
|
205
183
|
Rust, Java, C#, and Swift
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "space-data-module-sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.14",
|
|
4
4
|
"description": "Module SDK for building, validating, signing, and deploying WebAssembly modules on the Space Data Network.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
@@ -40,9 +40,6 @@
|
|
|
40
40
|
"schemas/",
|
|
41
41
|
"src/"
|
|
42
42
|
],
|
|
43
|
-
"publishConfig": {
|
|
44
|
-
"access": "public"
|
|
45
|
-
},
|
|
46
43
|
"scripts": {
|
|
47
44
|
"test": "node --test",
|
|
48
45
|
"test:host-surfaces": "node --test test/node-host.test.js test/host-abi.test.js",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { readFile
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
5
|
import { FlatcRunner } from "flatc-wasm";
|
|
@@ -18,48 +18,6 @@ function loadFlatcRunner() {
|
|
|
18
18
|
return flatcRunnerPromise;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const FLATBUFFERS_INCLUDE_ROOT_CANDIDATES = [
|
|
22
|
-
process.env.FLATBUFFERS_INCLUDE_DIR,
|
|
23
|
-
"/opt/homebrew/include",
|
|
24
|
-
"/usr/local/include",
|
|
25
|
-
"/usr/include",
|
|
26
|
-
].filter(Boolean);
|
|
27
|
-
|
|
28
|
-
async function findFlatbuffersIncludeRoot() {
|
|
29
|
-
for (const candidate of FLATBUFFERS_INCLUDE_ROOT_CANDIDATES) {
|
|
30
|
-
const headerPath = path.join(candidate, "flatbuffers", "flatbuffers.h");
|
|
31
|
-
try {
|
|
32
|
-
const headerStat = await stat(headerPath);
|
|
33
|
-
if (headerStat.isFile()) {
|
|
34
|
-
return candidate;
|
|
35
|
-
}
|
|
36
|
-
} catch {
|
|
37
|
-
// Try the next candidate.
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
throw new Error(
|
|
41
|
-
"Unable to locate the installed flatbuffers C++ headers. Set FLATBUFFERS_INCLUDE_DIR to the directory containing flatbuffers/flatbuffers.h.",
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function readDirectoryTree(rootDir, currentDir = rootDir) {
|
|
46
|
-
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
47
|
-
const files = [];
|
|
48
|
-
for (const entry of entries) {
|
|
49
|
-
const fullPath = path.join(currentDir, entry.name);
|
|
50
|
-
if (entry.isDirectory()) {
|
|
51
|
-
files.push(...(await readDirectoryTree(rootDir, fullPath)));
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (!entry.isFile()) {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
const relativePath = path.relative(rootDir, fullPath).split(path.sep).join("/");
|
|
58
|
-
files.push([`/${relativePath}`, await readFile(fullPath, "utf8")]);
|
|
59
|
-
}
|
|
60
|
-
return files;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
21
|
async function loadInvokeSchemaFiles() {
|
|
64
22
|
const filenames = [
|
|
65
23
|
"TypedArenaBuffer.fbs",
|
|
@@ -78,10 +36,8 @@ async function loadInvokeSchemaFiles() {
|
|
|
78
36
|
export async function getFlatbuffersCppRuntimeHeaders() {
|
|
79
37
|
if (!flatbuffersCppRuntimeHeadersPromise) {
|
|
80
38
|
flatbuffersCppRuntimeHeadersPromise = (async () => {
|
|
81
|
-
const
|
|
82
|
-
return
|
|
83
|
-
await readDirectoryTree(includeRoot, path.join(includeRoot, "flatbuffers")),
|
|
84
|
-
);
|
|
39
|
+
const flatc = await loadFlatcRunner();
|
|
40
|
+
return flatc.getEmbeddedRuntime("cpp");
|
|
85
41
|
})();
|
|
86
42
|
}
|
|
87
43
|
return flatbuffersCppRuntimeHeadersPromise;
|
|
@@ -167,6 +167,134 @@ function normalizePayloadWireFormatName(value) {
|
|
|
167
167
|
return null;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
function normalizedPluginFamilyName(value) {
|
|
171
|
+
if (!isNonEmptyString(value)) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
return value
|
|
175
|
+
.trim()
|
|
176
|
+
.toLowerCase()
|
|
177
|
+
.replace(/-/g, "_");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function typeSetHasDualWireFormats(typeSet) {
|
|
181
|
+
if (!Array.isArray(typeSet?.allowedTypes) || typeSet.allowedTypes.length === 0) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
let hasFlatbuffer = false;
|
|
185
|
+
let hasAlignedBinary = false;
|
|
186
|
+
for (const allowedType of typeSet.allowedTypes) {
|
|
187
|
+
const wireFormat = normalizePayloadWireFormatName(allowedType?.wireFormat);
|
|
188
|
+
if (wireFormat === "flatbuffer") {
|
|
189
|
+
hasFlatbuffer = true;
|
|
190
|
+
} else if (wireFormat === "aligned-binary") {
|
|
191
|
+
hasAlignedBinary = true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return hasFlatbuffer && hasAlignedBinary;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function validateCanonicalDualFormatPort(port, issues, location, methodId, portId) {
|
|
198
|
+
if (!port) {
|
|
199
|
+
pushIssue(
|
|
200
|
+
issues,
|
|
201
|
+
"error",
|
|
202
|
+
"propagator-missing-canonical-port",
|
|
203
|
+
`Canonical propagator method "${methodId}" must declare port "${portId}".`,
|
|
204
|
+
location,
|
|
205
|
+
);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (!Array.isArray(port.acceptedTypeSets) || port.acceptedTypeSets.length === 0) {
|
|
209
|
+
pushIssue(
|
|
210
|
+
issues,
|
|
211
|
+
"error",
|
|
212
|
+
"propagator-missing-canonical-port",
|
|
213
|
+
`Canonical propagator method "${methodId}" port "${portId}" must declare acceptedTypeSets.`,
|
|
214
|
+
`${location}.acceptedTypeSets`,
|
|
215
|
+
);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
port.acceptedTypeSets.forEach((typeSet, index) => {
|
|
219
|
+
if (!typeSetHasDualWireFormats(typeSet)) {
|
|
220
|
+
pushIssue(
|
|
221
|
+
issues,
|
|
222
|
+
"error",
|
|
223
|
+
"canonical-port-missing-dual-wire-format",
|
|
224
|
+
`Canonical propagator method "${methodId}" port "${portId}" acceptedTypeSet "${typeSet?.setId ?? index}" must accept both regular flatbuffer and aligned-binary payloads.`,
|
|
225
|
+
`${location}.acceptedTypeSets[${index}]`,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function validateCanonicalPropagatorContract(manifest, issues, sourceName) {
|
|
232
|
+
if (normalizedPluginFamilyName(manifest?.pluginFamily) !== "propagator") {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const methods = Array.isArray(manifest?.methods) ? manifest.methods : [];
|
|
237
|
+
const methodRequirements = [
|
|
238
|
+
{
|
|
239
|
+
methodId: "ingest_omm",
|
|
240
|
+
inputPorts: ["omm"],
|
|
241
|
+
outputPorts: [],
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
methodId: "describe_sources_batch",
|
|
245
|
+
inputPorts: ["request"],
|
|
246
|
+
outputPorts: ["result"],
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
methodId: "propagate_state",
|
|
250
|
+
inputPorts: ["request"],
|
|
251
|
+
outputPorts: ["state"],
|
|
252
|
+
},
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
for (const requirement of methodRequirements) {
|
|
256
|
+
const methodIndex = methods.findIndex(
|
|
257
|
+
(method) => method?.methodId === requirement.methodId,
|
|
258
|
+
);
|
|
259
|
+
if (methodIndex === -1) {
|
|
260
|
+
pushIssue(
|
|
261
|
+
issues,
|
|
262
|
+
"error",
|
|
263
|
+
"propagator-missing-canonical-method",
|
|
264
|
+
`Propagator plugins must declare canonical method "${requirement.methodId}".`,
|
|
265
|
+
`${sourceName}.methods`,
|
|
266
|
+
);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
const method = methods[methodIndex];
|
|
270
|
+
const location = `${sourceName}.methods[${methodIndex}]`;
|
|
271
|
+
for (const portId of requirement.inputPorts) {
|
|
272
|
+
const port = Array.isArray(method.inputPorts)
|
|
273
|
+
? method.inputPorts.find((entry) => entry?.portId === portId)
|
|
274
|
+
: null;
|
|
275
|
+
validateCanonicalDualFormatPort(
|
|
276
|
+
port,
|
|
277
|
+
issues,
|
|
278
|
+
`${location}.inputPorts`,
|
|
279
|
+
requirement.methodId,
|
|
280
|
+
portId,
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
for (const portId of requirement.outputPorts) {
|
|
284
|
+
const port = Array.isArray(method.outputPorts)
|
|
285
|
+
? method.outputPorts.find((entry) => entry?.portId === portId)
|
|
286
|
+
: null;
|
|
287
|
+
validateCanonicalDualFormatPort(
|
|
288
|
+
port,
|
|
289
|
+
issues,
|
|
290
|
+
`${location}.outputPorts`,
|
|
291
|
+
requirement.methodId,
|
|
292
|
+
portId,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
170
298
|
function validateStringField(issues, value, location, label) {
|
|
171
299
|
if (!isNonEmptyString(value)) {
|
|
172
300
|
pushIssue(issues, "error", "missing-string", `${label} must be a non-empty string.`, location);
|
|
@@ -1259,6 +1387,8 @@ export function validatePluginManifest(manifest, options = {}) {
|
|
|
1259
1387
|
}
|
|
1260
1388
|
});
|
|
1261
1389
|
|
|
1390
|
+
validateCanonicalPropagatorContract(manifest, issues, sourceName);
|
|
1391
|
+
|
|
1262
1392
|
if (manifest.timers !== undefined && !Array.isArray(manifest.timers)) {
|
|
1263
1393
|
pushIssue(
|
|
1264
1394
|
issues,
|
package/src/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type ProtocolRoleName = "handle" | "dial" | "both";
|
|
|
11
11
|
|
|
12
12
|
export interface PayloadTypeRef {
|
|
13
13
|
schemaName?: string;
|
|
14
|
-
fileIdentifier?: string;
|
|
14
|
+
fileIdentifier?: string | null;
|
|
15
15
|
schemaHash?: string | number[] | Uint8Array;
|
|
16
16
|
acceptsAnyFlatbuffer?: boolean;
|
|
17
17
|
wireFormat?: PayloadWireFormat;
|
|
@@ -662,25 +662,12 @@ export type {
|
|
|
662
662
|
HarnessInvokeScenario,
|
|
663
663
|
HarnessRawScenario,
|
|
664
664
|
ManifestHarnessPlan,
|
|
665
|
-
ModuleHarness,
|
|
666
|
-
ModuleHarnessRuntimeDescriptor,
|
|
667
|
-
PluginInvokeProcessClient,
|
|
668
|
-
PluginInvokeProcessLaunchPlan,
|
|
669
|
-
WasmEdgeRunnerBuildPlan,
|
|
670
665
|
} from "./testing/index.js";
|
|
671
666
|
|
|
672
667
|
export {
|
|
673
|
-
buildWasmEdgeEmscriptenPthreadRunner,
|
|
674
|
-
buildWasmEdgeSpawnEnv,
|
|
675
|
-
createModuleHarness,
|
|
676
|
-
createPluginInvokeProcessClient,
|
|
677
668
|
describeCapabilityRuntimeSurface,
|
|
678
669
|
generateManifestHarnessPlan,
|
|
679
670
|
materializeHarnessScenario,
|
|
680
|
-
resolveModuleHarnessLaunchPlan,
|
|
681
|
-
resolveWasmEdgeRunnerBuildPlan,
|
|
682
|
-
resolveWasmEdgeRunnerSourcePath,
|
|
683
|
-
resolveWasmEdgePluginLaunchPlan,
|
|
684
671
|
serializeHarnessPlan,
|
|
685
672
|
} from "./testing/index.js";
|
|
686
673
|
|
package/src/invoke/codec.js
CHANGED
|
@@ -12,7 +12,7 @@ import { InvokeSurface } from "../generated/orbpro/manifest/invoke-surface.js";
|
|
|
12
12
|
import { BufferMutability } from "../generated/orbpro/stream/buffer-mutability.js";
|
|
13
13
|
import { BufferOwnership } from "../generated/orbpro/stream/buffer-ownership.js";
|
|
14
14
|
import { FlatBufferTypeRefT } from "../generated/orbpro/stream/flat-buffer-type-ref.js";
|
|
15
|
-
import { TypedArenaBufferT } from "../generated/orbpro/stream/typed-arena-buffer.js";
|
|
15
|
+
import { TypedArenaBuffer, TypedArenaBufferT } from "../generated/orbpro/stream/typed-arena-buffer.js";
|
|
16
16
|
import { toUint8Array } from "../runtime/bufferLike.js";
|
|
17
17
|
|
|
18
18
|
function toByteBuffer(data) {
|
|
@@ -149,22 +149,20 @@ function normalizeArenaFrame(frame = {}, offset) {
|
|
|
149
149
|
|
|
150
150
|
function packArenaFrames(frames = []) {
|
|
151
151
|
const packedFrames = [];
|
|
152
|
-
const
|
|
152
|
+
const arena = [];
|
|
153
153
|
let offset = 0;
|
|
154
154
|
for (const frame of frames) {
|
|
155
155
|
const normalized = normalizeArenaFrame(frame, offset);
|
|
156
|
+
for (let index = 0; index < normalized.padding; index += 1) {
|
|
157
|
+
arena.push(0);
|
|
158
|
+
}
|
|
159
|
+
arena.push(...normalized.payload);
|
|
156
160
|
offset = normalized.buffer.offset + normalized.buffer.size;
|
|
157
161
|
packedFrames.push(normalized.buffer);
|
|
158
|
-
normalizedFrames.push(normalized);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const arena = new Uint8Array(offset);
|
|
162
|
-
for (const normalized of normalizedFrames) {
|
|
163
|
-
arena.set(normalized.payload, normalized.buffer.offset);
|
|
164
162
|
}
|
|
165
163
|
return {
|
|
166
164
|
frames: packedFrames,
|
|
167
|
-
arena,
|
|
165
|
+
arena: Uint8Array.from(arena),
|
|
168
166
|
};
|
|
169
167
|
}
|
|
170
168
|
|
package/src/testing/index.d.ts
CHANGED
|
@@ -57,69 +57,6 @@ export interface ManifestHarnessPlan {
|
|
|
57
57
|
scenarios: Array<HarnessInvokeScenario | HarnessRawScenario>;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export interface PluginInvokeProcessLaunchPlan {
|
|
61
|
-
command: string;
|
|
62
|
-
args: string[];
|
|
63
|
-
env?: Record<string, string | undefined>;
|
|
64
|
-
cwd?: string;
|
|
65
|
-
wasmPath?: string;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface PluginInvokeProcessClient {
|
|
69
|
-
launchPlan: PluginInvokeProcessLaunchPlan;
|
|
70
|
-
invokeRaw(requestBytes: Uint8Array | ArrayBuffer | ArrayBufferView): Promise<Uint8Array>;
|
|
71
|
-
invoke(request: {
|
|
72
|
-
methodId?: string | null;
|
|
73
|
-
inputs?: HarnessInputFrame[];
|
|
74
|
-
}): Promise<{
|
|
75
|
-
statusCode: number;
|
|
76
|
-
errorCode?: string | null;
|
|
77
|
-
errorMessage?: string | null;
|
|
78
|
-
outputs: HarnessInputFrame[];
|
|
79
|
-
}>;
|
|
80
|
-
destroy(): Promise<void>;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export interface ModuleHarnessRuntimeDescriptor {
|
|
84
|
-
kind?: "process" | "wasmedge";
|
|
85
|
-
launchPlan?: PluginInvokeProcessLaunchPlan;
|
|
86
|
-
command?: string;
|
|
87
|
-
args?: string[];
|
|
88
|
-
env?: Record<string, string | undefined>;
|
|
89
|
-
cwd?: string;
|
|
90
|
-
wasmPath?: string;
|
|
91
|
-
wasmEdgeBinary?: string;
|
|
92
|
-
wasmEdgeRunnerBinary?: string;
|
|
93
|
-
enableThreads?: boolean;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export interface ModuleHarness {
|
|
97
|
-
runtime: ModuleHarnessRuntimeDescriptor & { kind: "process" | "wasmedge" };
|
|
98
|
-
launchPlan: PluginInvokeProcessLaunchPlan;
|
|
99
|
-
invokeRaw(requestBytes: Uint8Array | ArrayBuffer | ArrayBufferView): Promise<Uint8Array>;
|
|
100
|
-
invoke(request: {
|
|
101
|
-
methodId?: string | null;
|
|
102
|
-
inputs?: HarnessInputFrame[];
|
|
103
|
-
}): Promise<{
|
|
104
|
-
statusCode: number;
|
|
105
|
-
errorCode?: string | null;
|
|
106
|
-
errorMessage?: string | null;
|
|
107
|
-
outputs: HarnessInputFrame[];
|
|
108
|
-
}>;
|
|
109
|
-
destroy(): Promise<void>;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export interface WasmEdgeRunnerBuildPlan {
|
|
113
|
-
runnerSourcePath: string;
|
|
114
|
-
requestedIncludeDir: string;
|
|
115
|
-
wasmedgeIncludeDir: string;
|
|
116
|
-
wasmedgeLibDir: string;
|
|
117
|
-
wasmedgeSharedLibraryPath: string;
|
|
118
|
-
outputPath: string;
|
|
119
|
-
compilerCommand: string;
|
|
120
|
-
compilerArgs: string[];
|
|
121
|
-
}
|
|
122
|
-
|
|
123
60
|
export function describeCapabilityRuntimeSurface(
|
|
124
61
|
capability: string,
|
|
125
62
|
): CapabilityRuntimeSurface;
|
|
@@ -147,49 +84,3 @@ export function materializeHarnessScenario(
|
|
|
147
84
|
};
|
|
148
85
|
|
|
149
86
|
export function serializeHarnessPlan(plan: ManifestHarnessPlan): unknown;
|
|
150
|
-
|
|
151
|
-
export function buildWasmEdgeSpawnEnv(
|
|
152
|
-
baseEnv?: Record<string, string | undefined>,
|
|
153
|
-
): Record<string, string | undefined>;
|
|
154
|
-
|
|
155
|
-
export function resolveWasmEdgePluginLaunchPlan(options: {
|
|
156
|
-
wasmPath: string;
|
|
157
|
-
wasmEdgeBinary?: string;
|
|
158
|
-
wasmEdgeRunnerBinary?: string;
|
|
159
|
-
enableThreads?: boolean;
|
|
160
|
-
invokeArgs?: string[];
|
|
161
|
-
env?: Record<string, string | undefined>;
|
|
162
|
-
}): PluginInvokeProcessLaunchPlan;
|
|
163
|
-
|
|
164
|
-
export function createPluginInvokeProcessClient(options: {
|
|
165
|
-
launchPlan?: PluginInvokeProcessLaunchPlan;
|
|
166
|
-
command?: string;
|
|
167
|
-
args?: string[];
|
|
168
|
-
env?: Record<string, string | undefined>;
|
|
169
|
-
cwd?: string;
|
|
170
|
-
}): Promise<PluginInvokeProcessClient>;
|
|
171
|
-
|
|
172
|
-
export function resolveModuleHarnessLaunchPlan(options: {
|
|
173
|
-
runtime?: ModuleHarnessRuntimeDescriptor;
|
|
174
|
-
} | ModuleHarnessRuntimeDescriptor): PluginInvokeProcessLaunchPlan;
|
|
175
|
-
|
|
176
|
-
export function createModuleHarness(options: {
|
|
177
|
-
runtime?: ModuleHarnessRuntimeDescriptor;
|
|
178
|
-
} | ModuleHarnessRuntimeDescriptor): Promise<ModuleHarness>;
|
|
179
|
-
|
|
180
|
-
export function resolveWasmEdgeRunnerSourcePath(): string;
|
|
181
|
-
|
|
182
|
-
export function resolveWasmEdgeRunnerBuildPlan(options: {
|
|
183
|
-
outputPath: string;
|
|
184
|
-
wasmedgeIncludeDir?: string;
|
|
185
|
-
wasmedgeLibDir?: string;
|
|
186
|
-
output?: string;
|
|
187
|
-
}): WasmEdgeRunnerBuildPlan;
|
|
188
|
-
|
|
189
|
-
export function buildWasmEdgeEmscriptenPthreadRunner(options: {
|
|
190
|
-
outputPath: string;
|
|
191
|
-
wasmedgeIncludeDir?: string;
|
|
192
|
-
wasmedgeLibDir?: string;
|
|
193
|
-
output?: string;
|
|
194
|
-
cwd?: string;
|
|
195
|
-
}): Promise<string>;
|
package/src/testing/index.js
CHANGED
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
import { Buffer } from "node:buffer";
|
|
2
|
-
|
|
3
1
|
import { encodePluginInvokeRequest } from "../invoke/codec.js";
|
|
4
2
|
import { normalizeInvokeSurfaces } from "../invoke/index.js";
|
|
5
3
|
import { selectPreferredPayloadTypeRef } from "../manifest/typeRefs.js";
|
|
6
|
-
export {
|
|
7
|
-
buildWasmEdgeSpawnEnv,
|
|
8
|
-
createPluginInvokeProcessClient,
|
|
9
|
-
resolveWasmEdgePluginLaunchPlan,
|
|
10
|
-
} from "./processInvoke.js";
|
|
11
|
-
export {
|
|
12
|
-
buildWasmEdgeEmscriptenPthreadRunner,
|
|
13
|
-
resolveWasmEdgeRunnerBuildPlan,
|
|
14
|
-
resolveWasmEdgeRunnerSourcePath,
|
|
15
|
-
} from "./buildWasmEdgeRunner.js";
|
|
16
|
-
export {
|
|
17
|
-
createModuleHarness,
|
|
18
|
-
resolveModuleHarnessLaunchPlan,
|
|
19
|
-
} from "./moduleHarness.js";
|
|
20
4
|
|
|
21
5
|
const CapabilitySurfaceMatrix = Object.freeze({
|
|
22
6
|
logging: Object.freeze({
|
package/src/transport/records.js
CHANGED
|
@@ -277,27 +277,7 @@ function validateEncTable(table, buffer, label) {
|
|
|
277
277
|
maxLength: 32,
|
|
278
278
|
});
|
|
279
279
|
assertOptionalStringField(buffer, tableMeta, 22, `${label} root type`);
|
|
280
|
-
const
|
|
281
|
-
const record = {
|
|
282
|
-
version: Number(table.VERSION()),
|
|
283
|
-
keyExchange:
|
|
284
|
-
KEY_EXCHANGE_NAME_BY_VALUE[table.KEY_EXCHANGE()] ??
|
|
285
|
-
String(table.KEY_EXCHANGE()),
|
|
286
|
-
symmetric:
|
|
287
|
-
SYMMETRIC_ALGO_NAME_BY_VALUE[table.SYMMETRIC()] ??
|
|
288
|
-
String(table.SYMMETRIC()),
|
|
289
|
-
keyDerivation:
|
|
290
|
-
KDF_NAME_BY_VALUE[table.KEY_DERIVATION()] ??
|
|
291
|
-
String(table.KEY_DERIVATION()),
|
|
292
|
-
ephemeralPublicKey: normalizeByteField(table.ephemeralPublicKeyArray()),
|
|
293
|
-
nonceStart: normalizeByteField(table.nonceStartArray()),
|
|
294
|
-
recipientKeyId: normalizeByteField(table.recipientKeyIdArray()),
|
|
295
|
-
context: normalizeStringField(table.CONTEXT()),
|
|
296
|
-
schemaHash: normalizeByteField(table.schemaHashArray()),
|
|
297
|
-
rootType: normalizeStringField(table.ROOT_TYPE()),
|
|
298
|
-
timestamp:
|
|
299
|
-
timestamp === undefined || timestamp === null ? 0 : Number(timestamp),
|
|
300
|
-
};
|
|
280
|
+
const record = normalizeEncTable(table.unpack());
|
|
301
281
|
if (!record.ephemeralPublicKey?.length) {
|
|
302
282
|
throw new Error(`${label} is missing the ephemeral public key.`);
|
|
303
283
|
}
|
|
@@ -336,17 +316,7 @@ function validatePnmTable(table, buffer, label) {
|
|
|
336
316
|
assertOptionalStringField(buffer, tableMeta, 16, `${label} timestamp signature`);
|
|
337
317
|
assertOptionalStringField(buffer, tableMeta, 18, `${label} signature type`);
|
|
338
318
|
assertOptionalStringField(buffer, tableMeta, 20, `${label} timestamp signature type`);
|
|
339
|
-
const record =
|
|
340
|
-
multiformatAddress: normalizeStringField(table.MULTIFORMAT_ADDRESS()),
|
|
341
|
-
publishTimestamp: normalizeStringField(table.PUBLISH_TIMESTAMP()),
|
|
342
|
-
cid: normalizeStringField(table.CID()),
|
|
343
|
-
fileName: normalizeStringField(table.FILE_NAME()),
|
|
344
|
-
fileId: normalizeStringField(table.FILE_ID()),
|
|
345
|
-
signature: normalizeStringField(table.SIGNATURE()),
|
|
346
|
-
timestampSignature: normalizeStringField(table.TIMESTAMP_SIGNATURE()),
|
|
347
|
-
signatureType: normalizeStringField(table.SIGNATURE_TYPE()),
|
|
348
|
-
timestampSignatureType: normalizeStringField(table.TIMESTAMP_SIGNATURE_TYPE()),
|
|
349
|
-
};
|
|
319
|
+
const record = normalizePnmTable(table.unpack());
|
|
350
320
|
if (
|
|
351
321
|
!record.multiformatAddress &&
|
|
352
322
|
!record.publishTimestamp &&
|
|
@@ -456,6 +426,48 @@ function pnmTableFromObject(record = {}) {
|
|
|
456
426
|
);
|
|
457
427
|
}
|
|
458
428
|
|
|
429
|
+
function normalizeEncTable(table) {
|
|
430
|
+
if (!table) {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
version: Number(table.VERSION ?? 1),
|
|
435
|
+
keyExchange:
|
|
436
|
+
KEY_EXCHANGE_NAME_BY_VALUE[table.KEY_EXCHANGE] ?? String(table.KEY_EXCHANGE),
|
|
437
|
+
symmetric:
|
|
438
|
+
SYMMETRIC_ALGO_NAME_BY_VALUE[table.SYMMETRIC] ?? String(table.SYMMETRIC),
|
|
439
|
+
keyDerivation:
|
|
440
|
+
KDF_NAME_BY_VALUE[table.KEY_DERIVATION] ?? String(table.KEY_DERIVATION),
|
|
441
|
+
ephemeralPublicKey: normalizeByteField(table.EPHEMERAL_PUBLIC_KEY),
|
|
442
|
+
nonceStart: normalizeByteField(table.NONCE_START),
|
|
443
|
+
recipientKeyId: normalizeByteField(table.RECIPIENT_KEY_ID),
|
|
444
|
+
context: normalizeStringField(table.CONTEXT),
|
|
445
|
+
schemaHash: normalizeByteField(table.SCHEMA_HASH),
|
|
446
|
+
rootType: normalizeStringField(table.ROOT_TYPE),
|
|
447
|
+
timestamp:
|
|
448
|
+
table.TIMESTAMP === undefined || table.TIMESTAMP === null
|
|
449
|
+
? 0
|
|
450
|
+
: Number(table.TIMESTAMP),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function normalizePnmTable(table) {
|
|
455
|
+
if (!table) {
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
return {
|
|
459
|
+
multiformatAddress: normalizeStringField(table.MULTIFORMAT_ADDRESS),
|
|
460
|
+
publishTimestamp: normalizeStringField(table.PUBLISH_TIMESTAMP),
|
|
461
|
+
cid: normalizeStringField(table.CID),
|
|
462
|
+
fileName: normalizeStringField(table.FILE_NAME),
|
|
463
|
+
fileId: normalizeStringField(table.FILE_ID),
|
|
464
|
+
signature: normalizeStringField(table.SIGNATURE),
|
|
465
|
+
timestampSignature: normalizeStringField(table.TIMESTAMP_SIGNATURE),
|
|
466
|
+
signatureType: normalizeStringField(table.SIGNATURE_TYPE),
|
|
467
|
+
timestampSignatureType: normalizeStringField(table.TIMESTAMP_SIGNATURE_TYPE),
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
459
471
|
function readFooterLength(bytes) {
|
|
460
472
|
const view = toUint8Array(bytes);
|
|
461
473
|
if (view.length < TRAILER_FOOTER_LENGTH) {
|
|
@@ -589,6 +601,7 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
589
601
|
if (recordTables.length === 0) {
|
|
590
602
|
throw new Error("REC trailer does not contain any records.");
|
|
591
603
|
}
|
|
604
|
+
const collection = collectionTable.unpack();
|
|
592
605
|
const records = [];
|
|
593
606
|
let enc = null;
|
|
594
607
|
let pnm = null;
|
|
@@ -609,18 +622,10 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
609
622
|
8,
|
|
610
623
|
`REC trailer record ${index} standard`,
|
|
611
624
|
);
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
? recordTable.valueType()
|
|
615
|
-
: typeof recordTable.value_type === "function"
|
|
616
|
-
? recordTable.value_type()
|
|
617
|
-
: (() => {
|
|
618
|
-
throw new TypeError(
|
|
619
|
-
"REC Record wrapper is missing both valueType() and value_type() accessors.",
|
|
620
|
-
);
|
|
621
|
-
})();
|
|
625
|
+
const unpackedRecord = collection.RECORDS[index];
|
|
626
|
+
const recordType = recordTable.value_type();
|
|
622
627
|
const standard =
|
|
623
|
-
normalizeStringField(
|
|
628
|
+
normalizeStringField(unpackedRecord?.standard) ??
|
|
624
629
|
STANDARD_BY_RECORD_TYPE[recordType] ??
|
|
625
630
|
null;
|
|
626
631
|
const expectedStandard =
|
|
@@ -639,7 +644,10 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
639
644
|
if (!valueMeta) {
|
|
640
645
|
throw new Error(`REC trailer record ${index} is missing a value.`);
|
|
641
646
|
}
|
|
642
|
-
let value =
|
|
647
|
+
let value =
|
|
648
|
+
standard === "ENC" || standard === "PNM"
|
|
649
|
+
? null
|
|
650
|
+
: unpackedRecord?.value ?? null;
|
|
643
651
|
if (standard === "ENC") {
|
|
644
652
|
const encTable = recordTable.value(new ENC());
|
|
645
653
|
if (!encTable) {
|
|
@@ -676,9 +684,7 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
676
684
|
});
|
|
677
685
|
}
|
|
678
686
|
return {
|
|
679
|
-
version:
|
|
680
|
-
normalizeStringField(collectionTable.version()) ??
|
|
681
|
-
DEFAULT_RECORD_COLLECTION_VERSION,
|
|
687
|
+
version: normalizeStringField(collection.version) ?? DEFAULT_RECORD_COLLECTION_VERSION,
|
|
682
688
|
records,
|
|
683
689
|
enc,
|
|
684
690
|
pnm,
|