space-data-module-sdk 0.3.1 → 0.5.3

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.
@@ -4,12 +4,14 @@ import {
4
4
  getWasmExportNamesFromFile,
5
5
  loadManifestFromFile,
6
6
  loadComplianceConfig,
7
- RecommendedCapabilityIds,
8
- StandaloneWasiCapabilityIds,
9
7
  resolveManifestFiles,
10
8
  validatePluginArtifact,
11
9
  validatePluginManifest,
12
10
  } from "./pluginCompliance.js";
11
+ import {
12
+ RecommendedCapabilityIds,
13
+ StandaloneWasiCapabilityIds,
14
+ } from "../capabilities.js";
13
15
  import { validateManifestAgainstStandardsCatalog } from "../standards/index.js";
14
16
 
15
17
  function mergeReport(baseReport, issues) {
@@ -12,53 +12,10 @@ import {
12
12
  ProtocolTransportKind,
13
13
  RuntimeTarget,
14
14
  } from "../runtime/constants.js";
15
-
16
- export const RecommendedCapabilityIds = Object.freeze([
17
- "clock",
18
- "random",
19
- "logging",
20
- "timers",
21
- "schedule_cron",
22
- "http",
23
- "tls",
24
- "websocket",
25
- "mqtt",
26
- "tcp",
27
- "udp",
28
- "network",
29
- "filesystem",
30
- "pipe",
31
- "pubsub",
32
- "protocol_handle",
33
- "protocol_dial",
34
- "database",
35
- "storage_adapter",
36
- "storage_query",
37
- "storage_write",
38
- "context_read",
39
- "context_write",
40
- "process_exec",
41
- "crypto_hash",
42
- "crypto_sign",
43
- "crypto_verify",
44
- "crypto_encrypt",
45
- "crypto_decrypt",
46
- "crypto_key_agreement",
47
- "crypto_kdf",
48
- "wallet_sign",
49
- "ipfs",
50
- "scene_access",
51
- "entity_access",
52
- "render_hooks",
53
- ]);
54
-
55
- export const StandaloneWasiCapabilityIds = Object.freeze([
56
- "logging",
57
- "clock",
58
- "random",
59
- "filesystem",
60
- "pipe",
61
- ]);
15
+ import {
16
+ RecommendedCapabilityIds,
17
+ StandaloneWasiCapabilityIds,
18
+ } from "../capabilities.js";
62
19
 
63
20
  const RecommendedCapabilitySet = new Set(RecommendedCapabilityIds);
64
21
  const StandaloneWasiCapabilitySet = new Set(StandaloneWasiCapabilityIds);
package/src/index.d.ts CHANGED
@@ -380,14 +380,69 @@ export interface X25519Keypair {
380
380
  privateKey: Uint8Array;
381
381
  }
382
382
 
383
+ export interface EncRecord {
384
+ version: number;
385
+ keyExchange: string;
386
+ symmetric: string;
387
+ keyDerivation: string;
388
+ ephemeralPublicKey: Uint8Array | null;
389
+ nonceStart: Uint8Array | null;
390
+ recipientKeyId: Uint8Array | null;
391
+ context: string | null;
392
+ schemaHash: Uint8Array | null;
393
+ rootType: string | null;
394
+ timestamp: number;
395
+ }
396
+
397
+ export interface PublicationNotice {
398
+ multiformatAddress: string | null;
399
+ publishTimestamp: string | null;
400
+ cid: string | null;
401
+ fileName: string | null;
402
+ fileId: string | null;
403
+ signature: string | null;
404
+ timestampSignature: string | null;
405
+ signatureType: string | null;
406
+ timestampSignatureType: string | null;
407
+ }
408
+
409
+ export interface PublicationRecordEntry {
410
+ standard: string | null;
411
+ recordType: number;
412
+ value: EncRecord | PublicationNotice | unknown;
413
+ }
414
+
415
+ export interface PublicationRecordCollection {
416
+ version: string;
417
+ records: PublicationRecordEntry[];
418
+ enc: EncRecord | null;
419
+ pnm: PublicationNotice | null;
420
+ recordCollectionBytes: Uint8Array;
421
+ }
422
+
423
+ export interface ExtractedPublicationRecordCollection
424
+ extends PublicationRecordCollection {
425
+ payloadBytes: Uint8Array;
426
+ protectedBytes: Uint8Array;
427
+ footerBytes: Uint8Array;
428
+ footerMagic: string;
429
+ recordCollectionLength: number;
430
+ }
431
+
383
432
  export interface EncryptedEnvelope {
384
433
  version: number;
385
434
  scheme: string;
386
435
  context: string;
387
- senderPublicKeyBase64: string;
388
- saltBase64: string;
389
- ivBase64: string;
390
- ciphertextBase64: string;
436
+ protectedBlobBase64?: string | null;
437
+ recordCollectionBase64?: string | null;
438
+ ciphertextBase64?: string | null;
439
+ senderPublicKeyBase64?: string | null;
440
+ nonceStartBase64?: string | null;
441
+ recipientKeyIdBase64?: string | null;
442
+ encRecordBase64?: string | null;
443
+ pnmRecordBase64?: string | null;
444
+ saltBase64?: string | null;
445
+ ivBase64?: string | null;
391
446
  }
392
447
 
393
448
  export function generateX25519Keypair(): Promise<X25519Keypair>;
@@ -397,8 +452,16 @@ export function encryptBytesForRecipient(options: {
397
452
  recipientPublicKey: Uint8Array | string;
398
453
  context?: string;
399
454
  senderKeyPair?: X25519Keypair;
455
+ recipientKeyId?: Uint8Array | ArrayBuffer | string | null;
456
+ schemaHash?: Uint8Array | ArrayBuffer | string | null;
457
+ rootType?: string | null;
400
458
  }): Promise<EncryptedEnvelope>;
401
459
 
460
+ export function decryptProtectedBytes(options: {
461
+ protectedBytes: Uint8Array | ArrayBuffer;
462
+ recipientPrivateKey: Uint8Array | string;
463
+ }): Promise<Uint8Array>;
464
+
402
465
  export function decryptBytesFromEnvelope(options: {
403
466
  envelope: EncryptedEnvelope;
404
467
  recipientPrivateKey: Uint8Array | string;
@@ -416,6 +479,78 @@ export function decryptJsonFromEnvelope(options: {
416
479
  recipientPrivateKey: Uint8Array | string;
417
480
  }): Promise<unknown>;
418
481
 
482
+ export function decryptPublicationRecordCollection(options: {
483
+ protectedBytes: Uint8Array | ArrayBuffer;
484
+ recipientPrivateKey: Uint8Array | string;
485
+ }): Promise<{
486
+ payloadBytes: Uint8Array;
487
+ decryptedBytes: Uint8Array;
488
+ publication: ExtractedPublicationRecordCollection | null;
489
+ }>;
490
+
491
+ export const TRAILER_MAGIC_TEXT: string;
492
+ export const TRAILER_FOOTER_LENGTH: number;
493
+
494
+ export function createCidV1Raw(
495
+ payloadBytes: Uint8Array | ArrayBuffer,
496
+ ): Promise<string>;
497
+
498
+ export function encodeEncRecord(record?: Partial<EncRecord>): Uint8Array;
499
+ export function decodeEncRecord(
500
+ bytes: Uint8Array | ArrayBuffer | ArrayBufferView,
501
+ ): EncRecord;
502
+ export function encodePnmRecord(
503
+ record?: Partial<PublicationNotice>,
504
+ ): Uint8Array;
505
+ export function decodePnmRecord(
506
+ bytes: Uint8Array | ArrayBuffer | ArrayBufferView,
507
+ ): PublicationNotice;
508
+ export function encodePublicationRecordCollection(options: {
509
+ version?: string;
510
+ enc?: Partial<EncRecord> | null;
511
+ pnm?: Partial<PublicationNotice> | null;
512
+ }): Uint8Array;
513
+ export function decodePublicationRecordCollection(
514
+ bytes: Uint8Array | ArrayBuffer | ArrayBufferView,
515
+ ): PublicationRecordCollection;
516
+ export function appendPublicationRecordCollection(
517
+ payloadBytes: Uint8Array | ArrayBuffer,
518
+ recordCollectionBytes: Uint8Array | ArrayBuffer,
519
+ ): Uint8Array;
520
+ export function extractPublicationRecordCollection(
521
+ bytes: Uint8Array | ArrayBuffer | ArrayBufferView,
522
+ ): ExtractedPublicationRecordCollection | null;
523
+ export function stripPublicationRecordCollection(
524
+ bytes: Uint8Array | ArrayBuffer | ArrayBufferView,
525
+ ): Uint8Array;
526
+ export function createPublicationNotice(options: {
527
+ payloadBytes: Uint8Array | ArrayBuffer;
528
+ cid?: string | null;
529
+ publishTimestamp?: string | null;
530
+ publishTimestampMs?: number;
531
+ fileName?: string | null;
532
+ fileId?: string | null;
533
+ artifactId?: string | null;
534
+ programId?: string | null;
535
+ multiformatAddress?: string | null;
536
+ signature?: string | null;
537
+ timestampSignature?: string | null;
538
+ signatureType?: string | null;
539
+ timestampSignatureType?: string | null;
540
+ signer?: Signer | null;
541
+ }): Promise<PublicationNotice>;
542
+ export function createEncryptedEnvelopePayload(options: {
543
+ protectedBlobBytes: Uint8Array | ArrayBuffer;
544
+ parsedProtectedBlob?: ExtractedPublicationRecordCollection | null;
545
+ enc?: EncRecord | null;
546
+ context?: string | null;
547
+ scheme?: string | null;
548
+ version?: number;
549
+ }): EncryptedEnvelope;
550
+ export function decodeProtectedBlobBase64(
551
+ base64: string,
552
+ ): ExtractedPublicationRecordCollection | null;
553
+
419
554
  // --- Compiler ---
420
555
 
421
556
  export interface CompilationResult {
@@ -424,10 +559,19 @@ export interface CompilationResult {
424
559
  outputPath: string | null;
425
560
  tempDir: string | null;
426
561
  wasmBytes: Uint8Array;
562
+ guestLink: GuestLinkArtifact | null;
427
563
  manifestWarnings: string[];
428
564
  report: ComplianceReport;
429
565
  }
430
566
 
567
+ export interface GuestLinkArtifact {
568
+ format: "wasm-object";
569
+ language: string;
570
+ symbolPrefix: string;
571
+ methodSymbols: Record<string, string>;
572
+ objectBytes: Uint8Array;
573
+ }
574
+
431
575
  export interface ProtectedArtifact {
432
576
  mnemonic: string;
433
577
  signingPublicKeyHex: string;
@@ -444,6 +588,10 @@ export interface ProtectedArtifact {
444
588
  manifestHashHex: string;
445
589
  authorization: SignedEnvelope;
446
590
  };
591
+ publicationNotice: PublicationNotice | null;
592
+ publicationRecordsBytes: Uint8Array | null;
593
+ protectedArtifactBytes: Uint8Array;
594
+ protectedArtifactBase64: string;
447
595
  encrypted: boolean;
448
596
  encryptedEnvelope: EncryptedEnvelope | null;
449
597
  singleFileBundle: { wasmBytes: Uint8Array } | null;
@@ -473,7 +621,8 @@ export function protectModuleArtifact(options: {
473
621
  targetUrl?: string;
474
622
  capabilities?: string[];
475
623
  singleFileBundle?: boolean;
476
- bundleEntries?: Record<string, unknown>;
624
+ bundleEntries?: Array<Record<string, unknown>>;
625
+ guestLink?: GuestLinkArtifact | null;
477
626
  }): Promise<ProtectedArtifact>;
478
627
 
479
628
  export function createRecipientKeypairHex(): Promise<{
@@ -567,6 +716,10 @@ export function validateManifestAgainstStandardsCatalog(
567
716
 
568
717
  export const SDS_BUNDLE_SECTION_NAME: string;
569
718
  export const DEFAULT_HASH_ALGORITHM: string;
719
+ export const SDS_GUEST_LINK_OBJECT_ENTRY_ID: string;
720
+ export const SDS_GUEST_LINK_METADATA_ENTRY_ID: string;
721
+ export const SDS_GUEST_LINK_SECTION_NAME: string;
722
+ export const SDS_GUEST_LINK_MEDIA_TYPE: string;
570
723
 
571
724
  export function createSingleFileBundle(options: {
572
725
  wasmBytes: Uint8Array;
@@ -577,9 +730,24 @@ export function createSingleFileBundle(options: {
577
730
  entries?: Array<Record<string, unknown>>;
578
731
  }): Promise<{ wasmBytes: Uint8Array }>;
579
732
 
733
+ export interface ParsedSingleFileBundle {
734
+ wasmBytes: Uint8Array;
735
+ protectedArtifactBytes: Uint8Array | null;
736
+ publicationRecords: ExtractedPublicationRecordCollection | null;
737
+ bundleBytes: Uint8Array;
738
+ bundle: unknown;
739
+ entries: Array<Record<string, unknown>>;
740
+ manifest: PluginManifest | null;
741
+ deploymentPlan: ModuleDeploymentPlan | null;
742
+ customSections: Array<Record<string, unknown>>;
743
+ canonicalWasmBytes: Uint8Array;
744
+ canonicalModuleHash: Uint8Array;
745
+ canonicalModuleHashHex: string;
746
+ }
747
+
580
748
  export function parseSingleFileBundle(
581
749
  wasmBytes: Uint8Array,
582
- ): unknown;
750
+ ): Promise<ParsedSingleFileBundle>;
583
751
 
584
752
  export function parseWasmModuleSections(
585
753
  bytes: Uint8Array,
package/src/index.js CHANGED
@@ -4,6 +4,7 @@ export * from "./auth/index.js";
4
4
  export * from "./transport/index.js";
5
5
  export * from "./compiler/index.js";
6
6
  export * from "./bundle/index.js";
7
+ export * from "./capabilities.js";
7
8
  export * from "./standards/index.js";
8
9
  export * from "./host/index.js";
9
10
  export * from "./invoke/index.js";
@@ -0,0 +1,15 @@
1
+ export * from "../generated/orbpro/manifest.js";
2
+ export { PayloadWireFormat } from "../generated/orbpro/stream/payload-wire-format.js";
3
+ export {
4
+ FlatBufferTypeRefT,
5
+ FlatBufferTypeRefT as PayloadTypeRef,
6
+ } from "../generated/orbpro/stream/flat-buffer-type-ref.js";
7
+ export { decodePluginManifest, encodePluginManifest } from "./codec.js";
8
+ export { toEmbeddedPluginManifest } from "./normalize.js";
9
+ export {
10
+ clonePayloadTypeRef,
11
+ getPayloadTypeWireFormat,
12
+ normalizePayloadWireFormatName,
13
+ payloadTypeRefsMatch,
14
+ selectPreferredPayloadTypeRef,
15
+ } from "./typeRefs.js";
@@ -1,4 +1,6 @@
1
1
  export {
2
+ decryptProtectedBytes,
3
+ decryptPublicationRecordCollection,
2
4
  decryptBytesFromEnvelope,
3
5
  decryptJsonFromEnvelope,
4
6
  encryptBytesForRecipient,
@@ -6,3 +8,20 @@ export {
6
8
  generateX25519Keypair,
7
9
  } from "./pki.js";
8
10
 
11
+ export {
12
+ appendPublicationRecordCollection,
13
+ createCidV1Raw,
14
+ createEncryptedEnvelopePayload,
15
+ createPublicationNotice,
16
+ decodeEncRecord,
17
+ decodePnmRecord,
18
+ decodeProtectedBlobBase64,
19
+ decodePublicationRecordCollection,
20
+ encodeEncRecord,
21
+ encodePnmRecord,
22
+ encodePublicationRecordCollection,
23
+ extractPublicationRecordCollection,
24
+ stripPublicationRecordCollection,
25
+ TRAILER_FOOTER_LENGTH,
26
+ TRAILER_MAGIC_TEXT,
27
+ } from "./records.js";
@@ -6,6 +6,8 @@ import {
6
6
  toUint8Array,
7
7
  } from "../utils/encoding.js";
8
8
  import {
9
+ aesCtrDecrypt,
10
+ aesCtrEncrypt,
9
11
  aesGcmDecrypt,
10
12
  aesGcmEncrypt,
11
13
  hkdfBytes,
@@ -13,6 +15,13 @@ import {
13
15
  x25519PublicKey,
14
16
  x25519SharedSecret,
15
17
  } from "../utils/wasmCrypto.js";
18
+ import {
19
+ appendPublicationRecordCollection,
20
+ createEncryptedEnvelopePayload,
21
+ decodeEncRecord,
22
+ encodePublicationRecordCollection,
23
+ extractPublicationRecordCollection,
24
+ } from "./records.js";
16
25
 
17
26
  function normalizePublicKey(value) {
18
27
  if (typeof value === "string") {
@@ -53,15 +62,12 @@ export async function generateX25519Keypair() {
53
62
  };
54
63
  }
55
64
 
56
- export async function encryptBytesForRecipient({
65
+ async function encryptBytesLegacy({
57
66
  plaintext,
58
67
  recipientPublicKey,
59
68
  context = "space-data-module-sdk/package",
60
69
  senderKeyPair = null,
61
70
  } = {}) {
62
- if (!recipientPublicKey) {
63
- throw new Error("encryptBytesForRecipient requires recipientPublicKey.");
64
- }
65
71
  const sender = senderKeyPair ?? (await generateX25519Keypair());
66
72
  const salt = await randomBytes(32);
67
73
  const iv = await randomBytes(12);
@@ -89,6 +95,77 @@ export async function encryptBytesForRecipient({
89
95
  };
90
96
  }
91
97
 
98
+ export async function decryptProtectedBytes({
99
+ protectedBytes,
100
+ recipientPrivateKey,
101
+ } = {}) {
102
+ const parsed = extractPublicationRecordCollection(protectedBytes);
103
+ if (!parsed?.enc) {
104
+ return toUint8Array(protectedBytes);
105
+ }
106
+ const sharedSecret = await deriveSharedSecret(
107
+ recipientPrivateKey,
108
+ parsed.enc.ephemeralPublicKey,
109
+ );
110
+ const aesKey = await deriveAesKey(
111
+ sharedSecret,
112
+ new Uint8Array(0),
113
+ parsed.enc.context ?? "",
114
+ );
115
+ return aesCtrDecrypt(aesKey, parsed.payloadBytes, parsed.enc.nonceStart);
116
+ }
117
+
118
+ export async function encryptBytesForRecipient({
119
+ plaintext,
120
+ recipientPublicKey,
121
+ context = "space-data-module-sdk/package",
122
+ senderKeyPair = null,
123
+ recipientKeyId = null,
124
+ schemaHash = null,
125
+ rootType = null,
126
+ } = {}) {
127
+ if (!recipientPublicKey) {
128
+ throw new Error("encryptBytesForRecipient requires recipientPublicKey.");
129
+ }
130
+ const sender = senderKeyPair ?? (await generateX25519Keypair());
131
+ const nonceStart = await randomBytes(12);
132
+ const sharedSecret = await deriveSharedSecret(
133
+ sender.privateKey,
134
+ recipientPublicKey,
135
+ );
136
+ const aesKey = await deriveAesKey(sharedSecret, new Uint8Array(0), context);
137
+ const ciphertext = await aesCtrEncrypt(aesKey, toUint8Array(plaintext), nonceStart);
138
+ const enc = {
139
+ version: 1,
140
+ keyExchange: "X25519",
141
+ symmetric: "AES_256_CTR",
142
+ keyDerivation: "HKDF_SHA256",
143
+ ephemeralPublicKey: sender.publicKey,
144
+ nonceStart,
145
+ recipientKeyId,
146
+ context,
147
+ schemaHash,
148
+ rootType,
149
+ timestamp: Date.now(),
150
+ };
151
+ const recordCollectionBytes = encodePublicationRecordCollection({ enc });
152
+ const protectedBlobBytes = appendPublicationRecordCollection(
153
+ ciphertext,
154
+ recordCollectionBytes,
155
+ );
156
+ return createEncryptedEnvelopePayload({
157
+ protectedBlobBytes,
158
+ parsedProtectedBlob: {
159
+ payloadBytes: ciphertext,
160
+ recordCollectionBytes,
161
+ enc,
162
+ pnm: null,
163
+ },
164
+ enc,
165
+ context,
166
+ });
167
+ }
168
+
92
169
  export async function decryptBytesFromEnvelope({
93
170
  envelope,
94
171
  recipientPrivateKey,
@@ -98,6 +175,29 @@ export async function decryptBytesFromEnvelope({
98
175
  "decryptBytesFromEnvelope requires envelope and recipientPrivateKey.",
99
176
  );
100
177
  }
178
+ if (envelope.protectedBlobBase64) {
179
+ return decryptProtectedBytes({
180
+ protectedBytes: base64ToBytes(envelope.protectedBlobBase64),
181
+ recipientPrivateKey,
182
+ });
183
+ }
184
+ if (envelope.ciphertextBase64 && envelope.encRecordBase64) {
185
+ const enc = decodeEncRecord(base64ToBytes(envelope.encRecordBase64));
186
+ const sharedSecret = await deriveSharedSecret(
187
+ recipientPrivateKey,
188
+ enc.ephemeralPublicKey,
189
+ );
190
+ const aesKey = await deriveAesKey(
191
+ sharedSecret,
192
+ new Uint8Array(0),
193
+ enc.context ?? envelope.context ?? "",
194
+ );
195
+ return aesCtrDecrypt(
196
+ aesKey,
197
+ base64ToBytes(envelope.ciphertextBase64),
198
+ enc.nonceStart,
199
+ );
200
+ }
101
201
  const sharedSecret = await deriveSharedSecret(
102
202
  recipientPrivateKey,
103
203
  base64ToBytes(envelope.senderPublicKeyBase64),
@@ -133,3 +233,24 @@ export async function decryptJsonFromEnvelope(options = {}) {
133
233
  return JSON.parse(new TextDecoder().decode(bytes));
134
234
  }
135
235
 
236
+ export async function decryptPublicationRecordCollection({
237
+ protectedBytes,
238
+ recipientPrivateKey,
239
+ } = {}) {
240
+ const parsed = extractPublicationRecordCollection(protectedBytes);
241
+ if (!parsed) {
242
+ return {
243
+ payloadBytes: toUint8Array(protectedBytes),
244
+ decryptedBytes: toUint8Array(protectedBytes),
245
+ publication: null,
246
+ };
247
+ }
248
+ const decryptedBytes = parsed.enc
249
+ ? await decryptProtectedBytes({ protectedBytes, recipientPrivateKey })
250
+ : parsed.payloadBytes;
251
+ return {
252
+ payloadBytes: parsed.payloadBytes,
253
+ decryptedBytes,
254
+ publication: parsed,
255
+ };
256
+ }