space-data-module-sdk 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +16 -23
  2. package/bin/space-data-module.js +5 -3
  3. package/package.json +2 -2
  4. package/src/AGENTS.md +1 -1
  5. package/src/bundle/AGENTS.md +6 -5
  6. package/src/bundle/codec.js +163 -48
  7. package/src/bundle/constants.js +1 -1
  8. package/src/bundle/wasm.js +22 -23
  9. package/src/compiler/compileModule.js +9 -1
  10. package/src/index.d.ts +1 -1
  11. package/src/transport/records.js +34 -3
  12. package/schemas/ModuleBundle.fbs +0 -108
  13. package/src/generated/orbpro/module/canonicalization-rule.d.ts +0 -48
  14. package/src/generated/orbpro/module/canonicalization-rule.js +0 -95
  15. package/src/generated/orbpro/module/canonicalization-rule.ts +0 -142
  16. package/src/generated/orbpro/module/module-bundle-entry-role.d.ts +0 -11
  17. package/src/generated/orbpro/module/module-bundle-entry-role.js +0 -14
  18. package/src/generated/orbpro/module/module-bundle-entry-role.ts +0 -15
  19. package/src/generated/orbpro/module/module-bundle-entry.d.ts +0 -97
  20. package/src/generated/orbpro/module/module-bundle-entry.js +0 -219
  21. package/src/generated/orbpro/module/module-bundle-entry.ts +0 -287
  22. package/src/generated/orbpro/module/module-bundle.d.ts +0 -86
  23. package/src/generated/orbpro/module/module-bundle.js +0 -213
  24. package/src/generated/orbpro/module/module-bundle.ts +0 -277
  25. package/src/generated/orbpro/module/module-payload-encoding.d.ts +0 -9
  26. package/src/generated/orbpro/module/module-payload-encoding.js +0 -12
  27. package/src/generated/orbpro/module/module-payload-encoding.ts +0 -13
  28. package/src/generated/orbpro/module.d.ts +0 -5
  29. package/src/generated/orbpro/module.js +0 -7
  30. package/src/generated/orbpro/module.ts +0 -9
package/README.md CHANGED
@@ -11,7 +11,7 @@ This repository is the source of truth for module-level concerns:
11
11
  - embedded manifest exports inside `.wasm` modules
12
12
  - standards-aware compliance and capability validation
13
13
  - module compilation and protection
14
- - the `sds.bundle` single-file container
14
+ - the REC+MBL 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
17
  - the canonical runtime-host model for append-only standards rows, host-managed
@@ -80,20 +80,21 @@ A compliant module built with this SDK is always a valid `.wasm` artifact with:
80
80
  - `plugin_alloc`
81
81
  - `plugin_free`
82
82
  - an exported `_start` entry when the artifact supports WASI command mode
83
- - optional `sds.bundle` custom-section payloads for:
83
+ - optional `MBL` bundle metadata carried in one appended SDS `REC` trailer for:
84
84
  - manifest bytes
85
85
  - resolved deployment plans and input bindings
86
86
  - deployment authorization
87
87
  - auxiliary FlatBuffer or raw payloads
88
- - optional appended SDS FlatBuffer publication records in a trailing `REC`
89
- container carrying:
88
+ - optional appended SDS FlatBuffer publication records in that same trailing
89
+ `REC` container carrying:
90
+ - `MBL` single-file bundle metadata
90
91
  - `PNM` digital-signature/publication metadata
91
92
  - `ENC` encrypted-delivery metadata
92
93
 
93
- Single-file bundling does not append arbitrary bytes to the end of the wasm
94
- module. The one-file module container is `sds.bundle`, stored as a standard
95
- wasm custom section. Appended bytes are reserved for SDS publication records
96
- such as `PNM` and `ENC`, wrapped in a trailing `REC` FlatBuffer collection.
94
+ Single-file bundling appends one SDS `REC` trailer to the end of the wasm
95
+ payload. That trailer carries an `MBL` record for the bundle contents and may
96
+ also carry `PNM` / `ENC` publication metadata when the artifact is signed or
97
+ encrypted.
97
98
 
98
99
  The module contract stays the same whether the artifact is loaded directly,
99
100
  wrapped in a deployment envelope, or shipped as one bundled `.wasm` file.
@@ -171,11 +172,8 @@ This repo currently includes:
171
172
 
172
173
  - the JavaScript reference implementation for manifest, compliance, auth,
173
174
  transport, bundle handling, and compilation
174
- - deterministic `sds.bundle` conformance vectors under
175
+ - deterministic REC+MBL conformance vectors under
175
176
  [`examples/single-file-bundle/vectors`](./examples/single-file-bundle/vectors)
176
- - non-JS bundle reference clients in
177
- [`examples/single-file-bundle/go`](./examples/single-file-bundle/go) and
178
- [`examples/single-file-bundle/python`](./examples/single-file-bundle/python)
179
177
  - reference Node and browser hosts plus the legacy sync `sdn_host` bridge for
180
178
  sync-safe guest hostcalls
181
179
 
@@ -385,20 +383,18 @@ This repo exposes that deployment surface from
385
383
 
386
384
  - validate resolved protocol installations
387
385
  - describe input and publication bindings by declared `interfaceId`
388
- - attach a deployment plan to `sds.bundle`
386
+ - attach a deployment plan to the bundle `MBL` record
389
387
 
390
388
  The full contract split is documented in
391
389
  [`docs/protocol-installation.md`](./docs/protocol-installation.md).
392
390
 
393
391
  ## Single-File Bundles
394
392
 
395
- `sds.bundle` keeps module delivery to one file without changing WebAssembly
396
- loadability for the runtime payload itself. The SDK writes the bundle as a
397
- standard custom section inside the wasm module. When the artifact is signed or
398
- encrypted for publication, SDS appends FlatBuffer publication records after the
399
- wasm bytes in a trailing `REC` container. Loaders must scan from the end,
400
- resolve `PNM` / `ENC`, strip or decrypt as needed, and only then hand the
401
- remaining raw wasm bytes to a runtime such as WasmEdge.
393
+ REC+MBL keeps module delivery to one file without changing the runtime payload
394
+ itself. The SDK appends one trailing `REC` container after the wasm bytes.
395
+ Loaders must scan from the end, resolve `MBL` / `PNM` / `ENC`, strip or decrypt
396
+ as needed, and only then hand the remaining raw wasm bytes to a runtime such as
397
+ WasmEdge.
402
398
 
403
399
  The reference path lives in
404
400
  [`examples/single-file-bundle`](./examples/single-file-bundle):
@@ -407,8 +403,6 @@ The reference path lives in
407
403
  bundled module
408
404
  - [`generate-vectors.mjs`](./examples/single-file-bundle/generate-vectors.mjs)
409
405
  regenerates the checked-in conformance vectors
410
- - the `go` and `python` directories show non-JS readers against the same
411
- bundle contract
412
406
 
413
407
  Standard bundle payloads now include the optional `deployment-plan` JSON entry
414
408
  for resolved protocol installations and producer input bindings.
@@ -419,7 +413,6 @@ Digital signature and encrypted-delivery metadata are publication-layer
419
413
  extensions, not a second module format. The canonical module is still:
420
414
 
421
415
  - valid `.wasm`
422
- - optionally carrying `sds.bundle` as a wasm custom section
423
416
  - optionally carrying one appended SDS `REC` trailer after the wasm bytes
424
417
 
425
418
  That trailing `REC` FlatBuffer is the standards-backed container for
@@ -6,13 +6,15 @@ import { readFile, writeFile } from "node:fs/promises";
6
6
 
7
7
  import {
8
8
  compileModuleFromSource,
9
- loadComplianceConfig,
10
9
  protectModuleArtifact,
10
+ } from "../src/compiler/index.js";
11
+ import {
12
+ loadComplianceConfig,
13
+ loadManifestFromFile,
11
14
  resolveManifestFiles,
12
15
  validateArtifactWithStandards,
13
16
  validateManifestWithStandards,
14
- loadManifestFromFile,
15
- } from "../src/index.js";
17
+ } from "../src/compliance/index.js";
16
18
  import { bytesToBase64 } from "../src/utils/encoding.js";
17
19
 
18
20
  async function main(argv) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "space-data-module-sdk",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
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",
@@ -72,7 +72,7 @@
72
72
  "flatsql": "^0.4.0",
73
73
  "hd-wallet-wasm": "1.6.0",
74
74
  "sdn-emception": "1.0.0",
75
- "spacedatastandards.org": "git+https://github.com/DigitalArsenal/spacedatastandards.org.git#c43c766bf4e8b18af125ed73b993e79c6ce20b24"
75
+ "spacedatastandards.org": "1.85.0"
76
76
  },
77
77
  "devDependencies": {
78
78
  "express": "^4.21.2"
package/src/AGENTS.md CHANGED
@@ -11,7 +11,7 @@ the SDK source, not a prompt to edit SDK internals by default.
11
11
  and `src/auth/AGENTS.md` provide narrower rules for those owners.
12
12
  - `src/compiler`: compile flow, manifest embedding, runtime targets, toolchains,
13
13
  and artifact layout.
14
- - `src/bundle`: `sds.bundle`, wasm custom sections, and vector compatibility.
14
+ - `src/bundle`: REC+MBL single-file packaging, wasm section handling, and vector compatibility.
15
15
  - `src/host`: Node host, browser shims, `sdn_host`, WasmEdge runners, and
16
16
  isomorphic loaders.
17
17
  - `src/runtime-host`: FlatSQL-backed runtime host, row/region identity, and
@@ -1,13 +1,14 @@
1
1
  # AGENTS
2
2
 
3
- This directory is the reference implementation for `sds.bundle` and wasm
4
- custom-section packaging.
3
+ This directory is the reference implementation for REC+MBL single-file module
4
+ packaging and wasm section handling.
5
5
 
6
6
  ## What Authors Should Use It For
7
7
 
8
- - `sds.bundle` is the single-file delivery format.
9
- - Put bundle data in a wasm custom section; do not append raw bytes after the
10
- wasm binary.
8
+ - Single-file delivery uses one appended `REC` trailer carrying an `MBL`
9
+ record.
10
+ - Keep the runtime payload canonical `.wasm`; publication/container metadata
11
+ lives in the REC trailer.
11
12
  - Use the public bundle helpers and CLI from this repo rather than inventing a
12
13
  custom one-file format.
13
14
 
@@ -2,13 +2,12 @@ import * as flatbuffers from "flatbuffers/mjs/flatbuffers.js";
2
2
 
3
3
  import {
4
4
  CanonicalizationRuleT,
5
- ModuleBundle,
5
+ MBL,
6
+ MBLT,
6
7
  ModuleBundleEntryRole,
7
8
  ModuleBundleEntryT,
8
- ModuleBundleT,
9
9
  ModulePayloadEncoding,
10
- } from "../generated/orbpro/module.js";
11
- import { FlatBufferTypeRefT } from "../generated/orbpro/stream/flat-buffer-type-ref.js";
10
+ } from "spacedatastandards.org/lib/js/MBL/main.js";
12
11
  import { canonicalBytes } from "../auth/canonicalize.js";
13
12
  import { toUint8Array as toBufferLikeUint8Array } from "../runtime/bufferLike.js";
14
13
  import {
@@ -16,10 +15,11 @@ import {
16
15
  DEFAULT_MANIFEST_EXPORT_SYMBOL,
17
16
  DEFAULT_MANIFEST_SIZE_SYMBOL,
18
17
  DEFAULT_MODULE_FORMAT,
19
- SDS_BUNDLE_SECTION_NAME,
20
18
  SDS_CUSTOM_SECTION_PREFIX,
19
+ SDS_MBL_CONTAINER_NAME,
21
20
  } from "./constants.js";
22
21
 
22
+ const textDecoder = new TextDecoder();
23
23
  const textEncoder = new TextEncoder();
24
24
 
25
25
  const ROLE_NAME_TO_ENUM = new Map([
@@ -66,6 +66,15 @@ function normalizeString(value, fallback = null) {
66
66
  return String(value);
67
67
  }
68
68
 
69
+ function firstDefined(...values) {
70
+ for (const value of values) {
71
+ if (value !== undefined) {
72
+ return value;
73
+ }
74
+ }
75
+ return undefined;
76
+ }
77
+
69
78
  function normalizePayloadWireFormat(value) {
70
79
  if (value === 1) {
71
80
  return "aligned-binary";
@@ -131,24 +140,47 @@ function normalizePayloadEncoding(value) {
131
140
  );
132
141
  }
133
142
 
134
- function normalizeTypeRef(value) {
135
- if (!value) {
143
+ function stringifyTypeRef(value) {
144
+ if (value === undefined || value === null) {
136
145
  return null;
137
146
  }
138
- if (value instanceof FlatBufferTypeRefT) {
147
+ if (typeof value === "string") {
139
148
  return value;
140
149
  }
141
- return new FlatBufferTypeRefT(
142
- normalizeString(value.schemaName),
143
- normalizeString(value.fileIdentifier),
144
- normalizeByteArray(value.schemaHash),
145
- Boolean(value.acceptsAnyFlatbuffer),
146
- normalizePayloadWireFormat(value.wireFormat),
147
- normalizeString(value.rootTypeName),
148
- normalizeUnsignedInteger(value.fixedStringLength),
149
- normalizeUnsignedInteger(value.byteLength),
150
- normalizeUnsignedInteger(value.requiredAlignment),
151
- );
150
+ const bytes = toBufferLikeUint8Array(value);
151
+ if (bytes) {
152
+ return textDecoder.decode(bytes);
153
+ }
154
+ return textDecoder.decode(canonicalBytes(value));
155
+ }
156
+
157
+ function parseTypeRef(value) {
158
+ if (value && typeof value === "object" && !Array.isArray(value)) {
159
+ return {
160
+ ...value,
161
+ wireFormat: normalizePayloadWireFormat(value.wireFormat),
162
+ fixedStringLength: normalizeUnsignedInteger(value.fixedStringLength),
163
+ byteLength: normalizeUnsignedInteger(value.byteLength),
164
+ requiredAlignment: normalizeUnsignedInteger(value.requiredAlignment),
165
+ };
166
+ }
167
+ const normalized = normalizeString(value);
168
+ if (!normalized) {
169
+ return null;
170
+ }
171
+ try {
172
+ const parsed = JSON.parse(normalized);
173
+ if (parsed && typeof parsed === "object") {
174
+ return {
175
+ ...parsed,
176
+ wireFormat: normalizePayloadWireFormat(parsed.wireFormat),
177
+ fixedStringLength: normalizeUnsignedInteger(parsed.fixedStringLength),
178
+ byteLength: normalizeUnsignedInteger(parsed.byteLength),
179
+ requiredAlignment: normalizeUnsignedInteger(parsed.requiredAlignment),
180
+ };
181
+ }
182
+ } catch {}
183
+ return normalized;
152
184
  }
153
185
 
154
186
  function normalizeCanonicalization(value = {}) {
@@ -161,7 +193,7 @@ function normalizeCanonicalization(value = {}) {
161
193
  value.strippedCustomSectionPrefix,
162
194
  SDS_CUSTOM_SECTION_PREFIX,
163
195
  ),
164
- normalizeString(value.bundleSectionName, SDS_BUNDLE_SECTION_NAME),
196
+ normalizeString(value.bundleSectionName, SDS_MBL_CONTAINER_NAME),
165
197
  normalizeString(value.hashAlgorithm, DEFAULT_HASH_ALGORITHM),
166
198
  );
167
199
  }
@@ -175,7 +207,7 @@ function normalizeEntry(value = {}) {
175
207
  normalizeString(value.entryId),
176
208
  normalizeRole(value.role),
177
209
  normalizeString(value.sectionName),
178
- normalizeTypeRef(value.typeRef),
210
+ stringifyTypeRef(value.typeRef),
179
211
  payloadEncoding,
180
212
  normalizeString(value.mediaType),
181
213
  Number(value.flags ?? 0),
@@ -185,38 +217,122 @@ function normalizeEntry(value = {}) {
185
217
  );
186
218
  }
187
219
 
220
+ function normalizeDecodedEntry(entry = {}) {
221
+ return {
222
+ entryId: firstDefined(entry.entryId, entry.entry_id) ?? null,
223
+ role: entry.role ?? ModuleBundleEntryRole.AUXILIARY,
224
+ sectionName: firstDefined(entry.sectionName, entry.section_name) ?? null,
225
+ typeRef: parseTypeRef(firstDefined(entry.typeRef, entry.type_ref)),
226
+ payloadEncoding:
227
+ firstDefined(entry.payloadEncoding, entry.payload_encoding) ??
228
+ ModulePayloadEncoding.RAW_BYTES,
229
+ mediaType: firstDefined(entry.mediaType, entry.media_type) ?? null,
230
+ flags: Number(entry.flags ?? 0),
231
+ sha256: normalizeByteArray(entry.sha256),
232
+ payload: normalizeByteArray(firstDefined(entry.payload, entry.PAYLOAD)),
233
+ description: entry.description ?? null,
234
+ };
235
+ }
236
+
237
+ function normalizeDecodedCanonicalization(canonicalization = null) {
238
+ if (!canonicalization || typeof canonicalization !== "object") {
239
+ return null;
240
+ }
241
+ return {
242
+ version: Number(canonicalization.version ?? 1),
243
+ strippedCustomSectionPrefix: normalizeString(
244
+ firstDefined(
245
+ canonicalization.strippedCustomSectionPrefix,
246
+ canonicalization.stripped_custom_section_prefix,
247
+ ),
248
+ SDS_CUSTOM_SECTION_PREFIX,
249
+ ),
250
+ bundleSectionName: normalizeString(
251
+ firstDefined(
252
+ canonicalization.bundleSectionName,
253
+ canonicalization.bundle_section_name,
254
+ ),
255
+ SDS_MBL_CONTAINER_NAME,
256
+ ),
257
+ hashAlgorithm: normalizeString(
258
+ firstDefined(
259
+ canonicalization.hashAlgorithm,
260
+ canonicalization.hash_algorithm,
261
+ ),
262
+ DEFAULT_HASH_ALGORITHM,
263
+ ),
264
+ };
265
+ }
266
+
267
+ function normalizeDecodedBundle(bundle = {}) {
268
+ return {
269
+ bundleVersion: Number(
270
+ firstDefined(bundle.bundleVersion, bundle.bundle_version) ?? 1,
271
+ ),
272
+ moduleFormat: normalizeString(
273
+ firstDefined(bundle.moduleFormat, bundle.module_format),
274
+ DEFAULT_MODULE_FORMAT,
275
+ ),
276
+ canonicalization: normalizeDecodedCanonicalization(bundle.canonicalization),
277
+ canonicalModuleHash: normalizeByteArray(
278
+ firstDefined(bundle.canonicalModuleHash, bundle.canonical_module_hash),
279
+ ),
280
+ manifestHash: normalizeByteArray(
281
+ firstDefined(bundle.manifestHash, bundle.manifest_hash),
282
+ ),
283
+ manifestExportSymbol: normalizeString(
284
+ firstDefined(bundle.manifestExportSymbol, bundle.manifest_export_symbol),
285
+ DEFAULT_MANIFEST_EXPORT_SYMBOL,
286
+ ),
287
+ manifestSizeSymbol: normalizeString(
288
+ firstDefined(bundle.manifestSizeSymbol, bundle.manifest_size_symbol),
289
+ DEFAULT_MANIFEST_SIZE_SYMBOL,
290
+ ),
291
+ entries: Array.isArray(bundle.entries)
292
+ ? bundle.entries.map(normalizeDecodedEntry)
293
+ : [],
294
+ };
295
+ }
296
+
297
+ export function moduleBundleTableFromObject(bundle = {}) {
298
+ return bundle instanceof MBLT
299
+ ? bundle
300
+ : new MBLT(
301
+ Number(bundle?.bundleVersion ?? 1),
302
+ normalizeString(bundle?.moduleFormat, DEFAULT_MODULE_FORMAT),
303
+ normalizeCanonicalization(bundle?.canonicalization),
304
+ normalizeByteArray(bundle?.canonicalModuleHash),
305
+ normalizeByteArray(bundle?.manifestHash),
306
+ normalizeString(
307
+ bundle?.manifestExportSymbol,
308
+ DEFAULT_MANIFEST_EXPORT_SYMBOL,
309
+ ),
310
+ normalizeString(
311
+ bundle?.manifestSizeSymbol,
312
+ DEFAULT_MANIFEST_SIZE_SYMBOL,
313
+ ),
314
+ Array.isArray(bundle?.entries)
315
+ ? bundle.entries.map(normalizeEntry)
316
+ : [],
317
+ );
318
+ }
319
+
188
320
  export function decodeModuleBundle(data) {
189
321
  const bb = toByteBuffer(data);
190
- if (!ModuleBundle.bufferHasIdentifier(bb)) {
322
+ if (!MBL.bufferHasIdentifier(bb)) {
191
323
  throw new Error("Module bundle buffer identifier mismatch.");
192
324
  }
193
- return ModuleBundle.getRootAsModuleBundle(bb).unpack();
325
+ return normalizeDecodedBundle(MBL.getRootAsMBL(bb).unpack());
326
+ }
327
+
328
+ export function decodeModuleBundleTable(table) {
329
+ return normalizeDecodedBundle(table?.unpack?.() ?? {});
194
330
  }
195
331
 
196
332
  export function encodeModuleBundle(bundle) {
197
- const value =
198
- bundle instanceof ModuleBundleT
199
- ? bundle
200
- : new ModuleBundleT(
201
- Number(bundle?.bundleVersion ?? 1),
202
- normalizeString(bundle?.moduleFormat, DEFAULT_MODULE_FORMAT),
203
- normalizeCanonicalization(bundle?.canonicalization),
204
- normalizeByteArray(bundle?.canonicalModuleHash),
205
- normalizeByteArray(bundle?.manifestHash),
206
- normalizeString(
207
- bundle?.manifestExportSymbol,
208
- DEFAULT_MANIFEST_EXPORT_SYMBOL,
209
- ),
210
- normalizeString(
211
- bundle?.manifestSizeSymbol,
212
- DEFAULT_MANIFEST_SIZE_SYMBOL,
213
- ),
214
- Array.isArray(bundle?.entries)
215
- ? bundle.entries.map(normalizeEntry)
216
- : [],
217
- );
333
+ const value = moduleBundleTableFromObject(bundle);
218
334
  const builder = new flatbuffers.Builder(1024);
219
- ModuleBundle.finishModuleBundleBuffer(builder, value.pack(builder));
335
+ MBL.finishMBLBuffer(builder, value.pack(builder));
220
336
  return builder.asUint8Array();
221
337
  }
222
338
 
@@ -259,10 +375,9 @@ export function findModuleBundleEntry(bundle, match) {
259
375
 
260
376
  export {
261
377
  CanonicalizationRuleT,
262
- FlatBufferTypeRefT,
263
- ModuleBundle,
378
+ MBL,
379
+ MBLT,
264
380
  ModuleBundleEntryRole,
265
381
  ModuleBundleEntryT,
266
- ModuleBundleT,
267
382
  ModulePayloadEncoding,
268
383
  };
@@ -1,5 +1,5 @@
1
1
  export const SDS_CUSTOM_SECTION_PREFIX = "sds.";
2
- export const SDS_BUNDLE_SECTION_NAME = "sds.bundle";
2
+ export const SDS_MBL_CONTAINER_NAME = "rec.mbl";
3
3
  export const DEFAULT_MODULE_FORMAT = "space-data-module";
4
4
  export const DEFAULT_HASH_ALGORITHM = "sha256";
5
5
  export const DEFAULT_MANIFEST_EXPORT_SYMBOL = "plugin_get_manifest_flatbuffer";
@@ -7,10 +7,10 @@ import { createDeploymentPlanBundleEntry } from "../deployment/index.js";
7
7
  import {
8
8
  DEFAULT_MANIFEST_EXPORT_SYMBOL,
9
9
  DEFAULT_MANIFEST_SIZE_SYMBOL,
10
- SDS_BUNDLE_SECTION_NAME,
11
10
  SDS_CUSTOM_SECTION_PREFIX,
12
11
  SDS_DEPLOYMENT_ENTRY_ID,
13
12
  SDS_DEPLOYMENT_SECTION_NAME,
13
+ SDS_MBL_CONTAINER_NAME,
14
14
  } from "./constants.js";
15
15
  import {
16
16
  decodeModuleBundle,
@@ -20,7 +20,11 @@ import {
20
20
  moduleBundleEncodingToName,
21
21
  moduleBundleRoleToName,
22
22
  } from "./codec.js";
23
- import { extractPublicationRecordCollection } from "../transport/records.js";
23
+ import {
24
+ appendPublicationRecordCollection,
25
+ encodePublicationRecordCollection,
26
+ extractPublicationRecordCollection,
27
+ } from "../transport/records.js";
24
28
 
25
29
  const textDecoder = new TextDecoder();
26
30
  const textEncoder = new TextEncoder();
@@ -392,7 +396,7 @@ export async function createSingleFileBundle(options = {}) {
392
396
  version: 1,
393
397
  strippedCustomSectionPrefix:
394
398
  options.customSectionPrefix ?? SDS_CUSTOM_SECTION_PREFIX,
395
- bundleSectionName: options.bundleSectionName ?? SDS_BUNDLE_SECTION_NAME,
399
+ bundleSectionName: options.bundleSectionName ?? SDS_MBL_CONTAINER_NAME,
396
400
  hashAlgorithm: "sha256",
397
401
  };
398
402
  const canonical = await computeCanonicalModuleHash(wasmBytes, {
@@ -415,10 +419,14 @@ export async function createSingleFileBundle(options = {}) {
415
419
  const baseWasmBytes = stripWasmCustomSections(wasmBytes, (section) =>
416
420
  section.name.startsWith(canonicalization.strippedCustomSectionPrefix),
417
421
  );
418
- const outputWasmBytes = appendWasmCustomSection(
422
+ const outputWasmBytes = appendPublicationRecordCollection(
419
423
  baseWasmBytes,
420
- canonicalization.bundleSectionName,
421
- bundleBytes,
424
+ encodePublicationRecordCollection({
425
+ version: protectedArtifact?.version,
426
+ mbl: bundle,
427
+ enc: protectedArtifact?.enc,
428
+ pnm: protectedArtifact?.pnm,
429
+ }),
422
430
  );
423
431
  return {
424
432
  bundle,
@@ -434,25 +442,16 @@ export async function createSingleFileBundle(options = {}) {
434
442
 
435
443
  export async function parseSingleFileBundle(bytes, options = {}) {
436
444
  const protectedArtifact = extractPublicationRecordCollection(bytes);
445
+ if (!protectedArtifact?.mbl) {
446
+ throw new Error("Missing required REC trailer containing an MBL record.");
447
+ }
437
448
  const wasmBytes = normalizeBytes(
438
- protectedArtifact?.payloadBytes ?? bytes,
449
+ protectedArtifact.payloadBytes,
439
450
  "wasm bytes",
440
451
  );
441
452
  const customSections = listWasmCustomSections(wasmBytes);
442
- const bundleSectionName = String(
443
- options.bundleSectionName ?? SDS_BUNDLE_SECTION_NAME,
444
- );
445
- const bundleSections = customSections.filter(
446
- (section) => section.name === bundleSectionName,
447
- );
448
- if (bundleSections.length === 0) {
449
- throw new Error(`Missing required custom section "${bundleSectionName}".`);
450
- }
451
- if (bundleSections.length > 1) {
452
- throw new Error(`Expected one "${bundleSectionName}" section, found ${bundleSections.length}.`);
453
- }
454
- const bundleBytes = bundleSections[0].dataBytes;
455
- const bundle = decodeModuleBundle(bundleBytes);
453
+ const bundle = protectedArtifact.mbl;
454
+ const bundleBytes = protectedArtifact.mblBytes ?? encodeModuleBundle(bundle);
456
455
  const prefix =
457
456
  bundle.canonicalization?.strippedCustomSectionPrefix ??
458
457
  SDS_CUSTOM_SECTION_PREFIX;
@@ -477,8 +476,8 @@ export async function parseSingleFileBundle(bytes, options = {}) {
477
476
  ) ?? null;
478
477
  return {
479
478
  wasmBytes,
480
- protectedArtifactBytes: protectedArtifact?.protectedBytes ?? null,
481
- publicationRecords: protectedArtifact ?? null,
479
+ protectedArtifactBytes: protectedArtifact.protectedBytes,
480
+ publicationRecords: protectedArtifact,
482
481
  bundleBytes,
483
482
  bundle,
484
483
  entries: parsedEntries,
@@ -894,6 +894,7 @@ export async function protectModuleArtifact(options = {}) {
894
894
  };
895
895
 
896
896
  let singleFileBundle = null;
897
+ let singleFileBundleRecords = null;
897
898
  if (options.singleFileBundle === true) {
898
899
  const additionalEntries = [
899
900
  ...(Array.isArray(options.bundleEntries) ? options.bundleEntries : []),
@@ -905,9 +906,13 @@ export async function protectModuleArtifact(options = {}) {
905
906
  authorization: signedAuthorization,
906
907
  entries: additionalEntries,
907
908
  });
909
+ singleFileBundleRecords = extractPublicationRecordCollection(
910
+ singleFileBundle.wasmBytes,
911
+ );
908
912
  }
909
913
 
910
- const bundleBytes = singleFileBundle?.wasmBytes ?? wasmBytes;
914
+ const bundleBytes = singleFileBundleRecords?.payloadBytes ?? wasmBytes;
915
+ const bundleRecord = singleFileBundleRecords?.mbl ?? null;
911
916
  let publicationNotice = null;
912
917
  let publicationRecordsBytes = null;
913
918
  let protectedArtifactBytes = null;
@@ -931,6 +936,7 @@ export async function protectModuleArtifact(options = {}) {
931
936
  signer,
932
937
  });
933
938
  publicationRecordsBytes = encodePublicationRecordCollection({
939
+ mbl: bundleRecord,
934
940
  enc: parsedEncryptedBase.enc,
935
941
  pnm: publicationNotice,
936
942
  });
@@ -943,6 +949,7 @@ export async function protectModuleArtifact(options = {}) {
943
949
  parsedProtectedBlob: {
944
950
  payloadBytes: parsedEncryptedBase.payloadBytes,
945
951
  recordCollectionBytes: publicationRecordsBytes,
952
+ mbl: bundleRecord,
946
953
  enc: parsedEncryptedBase.enc,
947
954
  pnm: publicationNotice,
948
955
  },
@@ -959,6 +966,7 @@ export async function protectModuleArtifact(options = {}) {
959
966
  signer,
960
967
  });
961
968
  publicationRecordsBytes = encodePublicationRecordCollection({
969
+ mbl: bundleRecord,
962
970
  pnm: publicationNotice,
963
971
  });
964
972
  protectedArtifactBytes = appendPublicationRecordCollection(
package/src/index.d.ts CHANGED
@@ -937,7 +937,7 @@ export function validateManifestAgainstStandardsCatalog(
937
937
 
938
938
  // --- Bundle ---
939
939
 
940
- export const SDS_BUNDLE_SECTION_NAME: string;
940
+ export const SDS_MBL_CONTAINER_NAME: string;
941
941
  export const DEFAULT_HASH_ALGORITHM: string;
942
942
  export const SDS_GUEST_LINK_OBJECT_ENTRY_ID: string;
943
943
  export const SDS_GUEST_LINK_METADATA_ENTRY_ID: string;