space-data-module-sdk 0.8.1 → 0.8.2

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 CHANGED
@@ -410,11 +410,22 @@ for resolved protocol installations and producer input bindings.
410
410
  ## Publication Protection Extensions
411
411
 
412
412
  Digital signature and encrypted-delivery metadata are publication-layer
413
- extensions, not a second module format. The canonical module is still:
413
+ extensions. The canonical runtime module is still:
414
414
 
415
415
  - valid `.wasm`
416
416
  - optionally carrying one appended SDS `REC` trailer after the wasm bytes
417
417
 
418
+ The same-file protected delivery layout is:
419
+
420
+ ```text
421
+ protected-payload-bytes || REC-flatbuffer-bytes || uint32le(REC length) || "$REC"
422
+ ```
423
+
424
+ For signed-only delivery, the protected payload bytes are the wasm bytes. For
425
+ encrypted binary delivery, the protected payload bytes are ciphertext and the
426
+ appended `REC` trailer carries `ENC` so a loader can decrypt them back to the
427
+ canonical wasm before runtime startup.
428
+
418
429
  That trailing `REC` FlatBuffer is the standards-backed container for
419
430
  publication records:
420
431
 
@@ -435,7 +446,7 @@ The loader contract is always:
435
446
  FlatBuffers from `spacedatastandards.org`.
436
447
  4. Resolve `PNM` for signature/publication metadata.
437
448
  5. Resolve `ENC` if the delivery was encrypted.
438
- 6. Strip the trailer or decrypt the protected payload.
449
+ 6. Strip the trailer or decrypt the protected payload bytes.
439
450
  7. Hand the remaining raw wasm bytes to the runtime.
440
451
 
441
452
  Aligned-binary payloads are a separate invoke-ABI optimization. They do not
@@ -547,9 +558,12 @@ npx space-data-module check --manifest ./manifest.json --wasm ./dist/isomorphic/
547
558
  # Compile C/C++ source and embed the manifest
548
559
  npx space-data-module compile --manifest ./manifest.json --source ./src/module.c --out ./dist/isomorphic/module.wasm
549
560
 
550
- # Sign and encrypt a deployment payload
561
+ # Sign a deployment payload and print JSON metadata
551
562
  npx space-data-module protect --manifest ./manifest.json --wasm ./dist/isomorphic/module.wasm --json
552
563
 
564
+ # Emit an encrypted binary with an appended REC trailer
565
+ npx space-data-module protect --manifest ./manifest.json --wasm ./dist/isomorphic/module.wasm --recipient-public-key <hex> --out ./dist/module.wasm.enc
566
+
553
567
  # Emit a single-file bundled wasm
554
568
  npx space-data-module protect --manifest ./manifest.json --wasm ./dist/isomorphic/module.wasm --single-file-bundle --out ./dist/module.bundle.wasm
555
569
  ```
@@ -106,6 +106,7 @@ function printUsage() {
106
106
  space-data-module check --manifest ./manifest.json --wasm ./dist/module.wasm
107
107
  space-data-module compile --manifest ./manifest.json --source ./src/module.c --out ./dist/module.wasm
108
108
  space-data-module protect --manifest ./manifest.json --wasm ./dist/module.wasm --json
109
+ space-data-module protect --manifest ./manifest.json --wasm ./dist/module.wasm --recipient-public-key <hex> --out ./dist/module.wasm.enc
109
110
  space-data-module protect --manifest ./manifest.json --wasm ./dist/module.wasm --single-file-bundle --out ./dist/module.bundle.wasm
110
111
  `);
111
112
  }
@@ -213,9 +214,6 @@ async function runProtect(argv) {
213
214
  if (!options.manifestPath || !options.wasmPath) {
214
215
  throw new Error("protect requires --manifest and --wasm.");
215
216
  }
216
- if (options.outputPath && options.singleFileBundle !== true) {
217
- throw new Error("protect only supports --out together with --single-file-bundle.");
218
- }
219
217
  const manifest = await loadManifestFromFile(options.manifestPath);
220
218
  const wasmBytes = new Uint8Array(await readFile(options.wasmPath));
221
219
  const result = await protectModuleArtifact({
@@ -225,8 +223,11 @@ async function runProtect(argv) {
225
223
  mnemonic: options.mnemonic,
226
224
  singleFileBundle: options.singleFileBundle,
227
225
  });
228
- if (options.singleFileBundle && options.outputPath && result.bundledWasmBytes) {
229
- await writeFile(options.outputPath, result.bundledWasmBytes);
226
+ if (options.outputPath) {
227
+ await writeFile(
228
+ options.outputPath,
229
+ result.bundledWasmBytes ?? result.protectedArtifactBytes,
230
+ );
230
231
  }
231
232
  if (options.json) {
232
233
  console.log(JSON.stringify(result, null, 2));
@@ -235,7 +236,8 @@ async function runProtect(argv) {
235
236
  console.log(`signingPublicKeyHex=${result.signingPublicKeyHex}`);
236
237
  console.log(`encrypted=${result.encrypted}`);
237
238
  console.log(`wasmBase64Length=${bytesToBase64(wasmBytes).length}`);
238
- if (result.bundledWasmBytes) {
239
+ console.log(`protectedArtifactBytes=${result.protectedArtifactBytes.length}`);
240
+ if (options.singleFileBundle && result.bundledWasmBytes) {
239
241
  console.log(`singleFileBundle=true`);
240
242
  console.log(`bundledWasmBytes=${result.bundledWasmBytes.length}`);
241
243
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "space-data-module-sdk",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
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",
@@ -11,6 +11,7 @@ import {
11
11
  import { normalizeInvokeSurfaceName } from "../invoke/codec.js";
12
12
  import { toUint8Array } from "../runtime/bufferLike.js";
13
13
  import { toEmbeddedPluginManifest } from "./normalize.js";
14
+ import { decodePlgManifest, isPlgManifestBuffer } from "./plgCodec.js";
14
15
 
15
16
  function toByteBuffer(data) {
16
17
  if (data instanceof flatbuffers.ByteBuffer) {
@@ -107,7 +108,79 @@ function normalizeDecodedMethod(method = {}) {
107
108
  };
108
109
  }
109
110
 
111
+ function typeRefFromSchemaName(schemaName) {
112
+ return typeof schemaName === "string" && schemaName.length > 0
113
+ ? { schemaName }
114
+ : null;
115
+ }
116
+
117
+ function portFromSchemaName(schemaName, index, direction) {
118
+ const typeRef = typeRefFromSchemaName(schemaName);
119
+ if (!typeRef) {
120
+ return null;
121
+ }
122
+ return {
123
+ portId: `${direction}-${index + 1}`,
124
+ acceptedTypeSets: [
125
+ {
126
+ setId: schemaName,
127
+ allowedTypes: [typeRef],
128
+ },
129
+ ],
130
+ minStreams: 0,
131
+ maxStreams: 1,
132
+ required: false,
133
+ };
134
+ }
135
+
136
+ function methodFromPlgEntry(entry = {}) {
137
+ const methodId = entry.name;
138
+ if (typeof methodId !== "string" || methodId.length === 0) {
139
+ return null;
140
+ }
141
+ const inputPorts = Array.isArray(entry.inputSchemas)
142
+ ? entry.inputSchemas
143
+ .map((schemaName, index) => portFromSchemaName(schemaName, index, "input"))
144
+ .filter(Boolean)
145
+ : [];
146
+ const outputPort = portFromSchemaName(entry.outputSchema, 0, "output");
147
+ return {
148
+ methodId,
149
+ displayName: methodId,
150
+ description: entry.description,
151
+ inputPorts,
152
+ outputPorts: outputPort ? [outputPort] : [],
153
+ maxBatch: 1,
154
+ drainPolicy: "single-shot",
155
+ };
156
+ }
157
+
158
+ function normalizeDecodedPlgManifest(manifest = {}) {
159
+ const methods = Array.isArray(manifest.entryFunctions)
160
+ ? manifest.entryFunctions.map((entry) => methodFromPlgEntry(entry)).filter(Boolean)
161
+ : [];
162
+ return {
163
+ ...manifest,
164
+ methods,
165
+ capabilities: Array.isArray(manifest.capabilities)
166
+ ? manifest.capabilities
167
+ : [],
168
+ invokeSurfaces: Array.isArray(manifest.invokeSurfaces)
169
+ ? manifest.invokeSurfaces
170
+ .map((value) => normalizeInvokeSurfaceName(value))
171
+ .filter(Boolean)
172
+ : [],
173
+ runtimeTargets: Array.isArray(manifest.runtimeTargets)
174
+ ? manifest.runtimeTargets
175
+ : [],
176
+ };
177
+ }
178
+
110
179
  export function decodePluginManifest(data) {
180
+ const bytes = toUint8Array(data);
181
+ if (bytes && isPlgManifestBuffer(bytes)) {
182
+ return normalizeDecodedPlgManifest(decodePlgManifest(bytes));
183
+ }
111
184
  const bb = toByteBuffer(data);
112
185
  if (!PluginManifest.bufferHasIdentifier(bb)) {
113
186
  throw new Error("Plugin manifest buffer identifier mismatch.");
@@ -682,6 +682,14 @@ static void register_env_host_functions(
682
682
  WasmEdge_ValTypeGenI32(),
683
683
  WasmEdge_ValTypeGenI32(),
684
684
  WasmEdge_ValTypeGenI32()};
685
+ const WasmEdge_ValType seven_i32_params[7] = {
686
+ WasmEdge_ValTypeGenI32(),
687
+ WasmEdge_ValTypeGenI32(),
688
+ WasmEdge_ValTypeGenI32(),
689
+ WasmEdge_ValTypeGenI32(),
690
+ WasmEdge_ValTypeGenI32(),
691
+ WasmEdge_ValTypeGenI32(),
692
+ WasmEdge_ValTypeGenI32()};
685
693
  const WasmEdge_ValType f64_return[1] = {WasmEdge_ValTypeGenF64()};
686
694
  const WasmEdge_ValType i32_return[1] = {WasmEdge_ValTypeGenI32()};
687
695
 
@@ -735,8 +743,14 @@ static void register_env_host_functions(
735
743
  "_emscripten_receive_on_main_thread_js",
736
744
  stub_receive_on_main_thread,
737
745
  runner,
738
- receive_on_main_thread_param_len == 4 ? four_i32_params : five_i32_params,
739
- receive_on_main_thread_param_len == 4 ? 4 : 5,
746
+ receive_on_main_thread_param_len == 4
747
+ ? four_i32_params
748
+ : receive_on_main_thread_param_len == 7
749
+ ? seven_i32_params
750
+ : five_i32_params,
751
+ receive_on_main_thread_param_len == 4
752
+ ? 4
753
+ : receive_on_main_thread_param_len == 7 ? 7 : 5,
740
754
  f64_return,
741
755
  1);
742
756
  add_host_func(
@@ -3072,7 +3086,7 @@ int main(int argc, char **argv) {
3072
3086
  &runner,
3073
3087
  import_config.receive_on_main_thread_param_len == 4
3074
3088
  ? 4
3075
- : 5,
3089
+ : import_config.receive_on_main_thread_param_len == 7 ? 7 : 5,
3076
3090
  import_config.notify_mailbox_postmessage_param_len == 3
3077
3091
  ? 3
3078
3092
  : 2);