space-data-module-sdk 0.5.10 → 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 -1
- package/src/compliance/pluginCompliance.js +131 -1
- package/src/index.d.ts +1 -14
- package/src/invoke/codec.js +7 -9
- package/src/manifest/typeRefs.js +49 -12
- package/src/testing/index.d.ts +0 -109
- package/src/testing/index.js +0 -16
- package/src/transport/records.js +52 -37
- 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
|
@@ -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);
|
|
@@ -366,7 +494,7 @@ function validateAllowedType(type, issues, location) {
|
|
|
366
494
|
"Allowed type fixedStringLength",
|
|
367
495
|
{ min: 0 },
|
|
368
496
|
);
|
|
369
|
-
|
|
497
|
+
validateOptionalIntegerField(
|
|
370
498
|
issues,
|
|
371
499
|
type.byteLength,
|
|
372
500
|
`${location}.byteLength`,
|
|
@@ -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/manifest/typeRefs.js
CHANGED
|
@@ -1,31 +1,62 @@
|
|
|
1
1
|
function cloneSchemaHash(value) {
|
|
2
2
|
if (value instanceof Uint8Array) {
|
|
3
|
-
return new Uint8Array(value);
|
|
3
|
+
return value.byteLength > 0 ? new Uint8Array(value) : undefined;
|
|
4
4
|
}
|
|
5
5
|
if (Array.isArray(value)) {
|
|
6
|
-
return [...value];
|
|
6
|
+
return value.length > 0 ? [...value] : undefined;
|
|
7
7
|
}
|
|
8
8
|
return value ?? undefined;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
function normalizeNullableString(value) {
|
|
12
|
+
if (value === undefined || value === null) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const normalized = String(value).trim();
|
|
16
|
+
return normalized.length > 0 ? normalized : null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function normalizeAlignedMetadataScalar(value) {
|
|
20
|
+
if (value === undefined || value === null || value === "") {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const numeric = Number(value);
|
|
24
|
+
if (Number.isFinite(numeric)) {
|
|
25
|
+
return numeric === 0 ? undefined : numeric;
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
export function clonePayloadTypeRef(value = null) {
|
|
12
31
|
if (!value || typeof value !== "object") {
|
|
13
|
-
return { acceptsAnyFlatbuffer: true };
|
|
32
|
+
return { acceptsAnyFlatbuffer: true, fileIdentifier: null };
|
|
14
33
|
}
|
|
15
34
|
return {
|
|
16
|
-
schemaName:
|
|
17
|
-
|
|
35
|
+
schemaName: normalizeNullableString(
|
|
36
|
+
value.schemaName ?? value.schema_name,
|
|
37
|
+
),
|
|
38
|
+
fileIdentifier: normalizeNullableString(
|
|
39
|
+
value.fileIdentifier ?? value.file_identifier,
|
|
40
|
+
),
|
|
18
41
|
schemaHash: cloneSchemaHash(value.schemaHash ?? value.schema_hash),
|
|
19
42
|
acceptsAnyFlatbuffer: Boolean(
|
|
20
43
|
value.acceptsAnyFlatbuffer ?? value.accepts_any_flatbuffer ?? false,
|
|
21
44
|
),
|
|
22
|
-
wireFormat:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
45
|
+
wireFormat: normalizePayloadWireFormatName(
|
|
46
|
+
value.wireFormat ?? value.wire_format,
|
|
47
|
+
),
|
|
48
|
+
rootTypeName: normalizeNullableString(
|
|
49
|
+
value.rootTypeName ?? value.root_type_name,
|
|
50
|
+
),
|
|
51
|
+
fixedStringLength: normalizeAlignedMetadataScalar(
|
|
52
|
+
value.fixedStringLength ?? value.fixed_string_length,
|
|
53
|
+
),
|
|
54
|
+
byteLength: normalizeAlignedMetadataScalar(
|
|
55
|
+
value.byteLength ?? value.byte_length,
|
|
56
|
+
),
|
|
57
|
+
requiredAlignment: normalizeAlignedMetadataScalar(
|
|
58
|
+
value.requiredAlignment ?? value.required_alignment,
|
|
59
|
+
),
|
|
29
60
|
};
|
|
30
61
|
}
|
|
31
62
|
|
|
@@ -33,6 +64,12 @@ export function normalizePayloadWireFormatName(value) {
|
|
|
33
64
|
if (value === undefined || value === null || value === "") {
|
|
34
65
|
return null;
|
|
35
66
|
}
|
|
67
|
+
if (value === 1 || value === "1") {
|
|
68
|
+
return "aligned-binary";
|
|
69
|
+
}
|
|
70
|
+
if (value === 0 || value === "0") {
|
|
71
|
+
return "flatbuffer";
|
|
72
|
+
}
|
|
36
73
|
const normalized = String(value).trim().toLowerCase().replace(/_/g, "-");
|
|
37
74
|
if (normalized === "aligned-binary") {
|
|
38
75
|
return "aligned-binary";
|
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,9 +622,10 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
609
622
|
8,
|
|
610
623
|
`REC trailer record ${index} standard`,
|
|
611
624
|
);
|
|
625
|
+
const unpackedRecord = collection.RECORDS[index];
|
|
612
626
|
const recordType = recordTable.value_type();
|
|
613
627
|
const standard =
|
|
614
|
-
normalizeStringField(
|
|
628
|
+
normalizeStringField(unpackedRecord?.standard) ??
|
|
615
629
|
STANDARD_BY_RECORD_TYPE[recordType] ??
|
|
616
630
|
null;
|
|
617
631
|
const expectedStandard =
|
|
@@ -630,7 +644,10 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
630
644
|
if (!valueMeta) {
|
|
631
645
|
throw new Error(`REC trailer record ${index} is missing a value.`);
|
|
632
646
|
}
|
|
633
|
-
let value =
|
|
647
|
+
let value =
|
|
648
|
+
standard === "ENC" || standard === "PNM"
|
|
649
|
+
? null
|
|
650
|
+
: unpackedRecord?.value ?? null;
|
|
634
651
|
if (standard === "ENC") {
|
|
635
652
|
const encTable = recordTable.value(new ENC());
|
|
636
653
|
if (!encTable) {
|
|
@@ -667,9 +684,7 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
667
684
|
});
|
|
668
685
|
}
|
|
669
686
|
return {
|
|
670
|
-
version:
|
|
671
|
-
normalizeStringField(collectionTable.version()) ??
|
|
672
|
-
DEFAULT_RECORD_COLLECTION_VERSION,
|
|
687
|
+
version: normalizeStringField(collection.version) ?? DEFAULT_RECORD_COLLECTION_VERSION,
|
|
673
688
|
records,
|
|
674
689
|
enc,
|
|
675
690
|
pnm,
|