space-data-module-sdk 0.5.9 → 0.5.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "space-data-module-sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.13",
|
|
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,6 +40,9 @@
|
|
|
40
40
|
"schemas/",
|
|
41
41
|
"src/"
|
|
42
42
|
],
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
43
46
|
"scripts": {
|
|
44
47
|
"test": "node --test",
|
|
45
48
|
"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 } from "node:fs/promises";
|
|
2
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
5
|
import { FlatcRunner } from "flatc-wasm";
|
|
@@ -18,6 +18,48 @@ 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
|
+
|
|
21
63
|
async function loadInvokeSchemaFiles() {
|
|
22
64
|
const filenames = [
|
|
23
65
|
"TypedArenaBuffer.fbs",
|
|
@@ -36,8 +78,10 @@ async function loadInvokeSchemaFiles() {
|
|
|
36
78
|
export async function getFlatbuffersCppRuntimeHeaders() {
|
|
37
79
|
if (!flatbuffersCppRuntimeHeadersPromise) {
|
|
38
80
|
flatbuffersCppRuntimeHeadersPromise = (async () => {
|
|
39
|
-
const
|
|
40
|
-
return
|
|
81
|
+
const includeRoot = await findFlatbuffersIncludeRoot();
|
|
82
|
+
return Object.fromEntries(
|
|
83
|
+
await readDirectoryTree(includeRoot, path.join(includeRoot, "flatbuffers")),
|
|
84
|
+
);
|
|
41
85
|
})();
|
|
42
86
|
}
|
|
43
87
|
return flatbuffersCppRuntimeHeadersPromise;
|
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/transport/records.js
CHANGED
|
@@ -277,7 +277,27 @@ function validateEncTable(table, buffer, label) {
|
|
|
277
277
|
maxLength: 32,
|
|
278
278
|
});
|
|
279
279
|
assertOptionalStringField(buffer, tableMeta, 22, `${label} root type`);
|
|
280
|
-
const
|
|
280
|
+
const timestamp = table.TIMESTAMP();
|
|
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
|
+
};
|
|
281
301
|
if (!record.ephemeralPublicKey?.length) {
|
|
282
302
|
throw new Error(`${label} is missing the ephemeral public key.`);
|
|
283
303
|
}
|
|
@@ -316,7 +336,17 @@ function validatePnmTable(table, buffer, label) {
|
|
|
316
336
|
assertOptionalStringField(buffer, tableMeta, 16, `${label} timestamp signature`);
|
|
317
337
|
assertOptionalStringField(buffer, tableMeta, 18, `${label} signature type`);
|
|
318
338
|
assertOptionalStringField(buffer, tableMeta, 20, `${label} timestamp signature type`);
|
|
319
|
-
const record =
|
|
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
|
+
};
|
|
320
350
|
if (
|
|
321
351
|
!record.multiformatAddress &&
|
|
322
352
|
!record.publishTimestamp &&
|
|
@@ -426,48 +456,6 @@ function pnmTableFromObject(record = {}) {
|
|
|
426
456
|
);
|
|
427
457
|
}
|
|
428
458
|
|
|
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
|
-
|
|
471
459
|
function readFooterLength(bytes) {
|
|
472
460
|
const view = toUint8Array(bytes);
|
|
473
461
|
if (view.length < TRAILER_FOOTER_LENGTH) {
|
|
@@ -601,7 +589,6 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
601
589
|
if (recordTables.length === 0) {
|
|
602
590
|
throw new Error("REC trailer does not contain any records.");
|
|
603
591
|
}
|
|
604
|
-
const collection = collectionTable.unpack();
|
|
605
592
|
const records = [];
|
|
606
593
|
let enc = null;
|
|
607
594
|
let pnm = null;
|
|
@@ -622,10 +609,18 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
622
609
|
8,
|
|
623
610
|
`REC trailer record ${index} standard`,
|
|
624
611
|
);
|
|
625
|
-
const
|
|
626
|
-
|
|
612
|
+
const recordType =
|
|
613
|
+
typeof recordTable.valueType === "function"
|
|
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
|
+
})();
|
|
627
622
|
const standard =
|
|
628
|
-
normalizeStringField(
|
|
623
|
+
normalizeStringField(recordTable.standard()) ??
|
|
629
624
|
STANDARD_BY_RECORD_TYPE[recordType] ??
|
|
630
625
|
null;
|
|
631
626
|
const expectedStandard =
|
|
@@ -644,10 +639,7 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
644
639
|
if (!valueMeta) {
|
|
645
640
|
throw new Error(`REC trailer record ${index} is missing a value.`);
|
|
646
641
|
}
|
|
647
|
-
let value =
|
|
648
|
-
standard === "ENC" || standard === "PNM"
|
|
649
|
-
? null
|
|
650
|
-
: unpackedRecord?.value ?? null;
|
|
642
|
+
let value = null;
|
|
651
643
|
if (standard === "ENC") {
|
|
652
644
|
const encTable = recordTable.value(new ENC());
|
|
653
645
|
if (!encTable) {
|
|
@@ -684,7 +676,9 @@ export function decodePublicationRecordCollection(bytes) {
|
|
|
684
676
|
});
|
|
685
677
|
}
|
|
686
678
|
return {
|
|
687
|
-
version:
|
|
679
|
+
version:
|
|
680
|
+
normalizeStringField(collectionTable.version()) ??
|
|
681
|
+
DEFAULT_RECORD_COLLECTION_VERSION,
|
|
688
682
|
records,
|
|
689
683
|
enc,
|
|
690
684
|
pnm,
|