space-data-module-sdk 0.6.0 → 0.6.1

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 (65) hide show
  1. package/README.md +15 -2
  2. package/package.json +1 -1
  3. package/schemas/orbpro/BaseTypes.fbs +7 -0
  4. package/schemas/orbpro/CatalogQueryBase.fbs +8 -0
  5. package/schemas/orbpro/CatalogQueryRequest.fbs +14 -0
  6. package/schemas/orbpro/CatalogQueryResult.fbs +17 -0
  7. package/schemas/orbpro/EntityMetadata.fbs +53 -0
  8. package/schemas/orbpro/EntityStandardsLink.fbs +18 -0
  9. package/schemas/orbpro/Plugin.fbs +8 -0
  10. package/schemas/orbpro/Propagator.fbs +89 -0
  11. package/schemas/orbpro/StandardsRecordIndex.fbs +15 -0
  12. package/src/generated/orbpro/entity/entity-kind.js +15 -0
  13. package/src/generated/orbpro/entity/entity-kind.ts +15 -0
  14. package/src/generated/orbpro/entity/entity-metadata.js +322 -0
  15. package/src/generated/orbpro/entity/entity-metadata.ts +426 -0
  16. package/src/generated/orbpro/entity/entity-standards-link.js +143 -0
  17. package/src/generated/orbpro/entity/entity-standards-link.ts +183 -0
  18. package/src/generated/orbpro/entity/standards-record-index.js +115 -0
  19. package/src/generated/orbpro/entity/standards-record-index.ts +147 -0
  20. package/src/generated/orbpro/entity.js +10 -0
  21. package/src/generated/orbpro/entity.ts +5 -0
  22. package/src/generated/orbpro/plugin/raw-data-payload.js +79 -0
  23. package/src/generated/orbpro/plugin/raw-data-payload.ts +92 -0
  24. package/src/generated/orbpro/plugin.js +4 -0
  25. package/src/generated/orbpro/plugin.ts +5 -0
  26. package/src/generated/orbpro/propagator/propagator-describe-sources-batch-request.js +79 -0
  27. package/src/generated/orbpro/propagator/propagator-describe-sources-batch-request.ts +95 -0
  28. package/src/generated/orbpro/propagator/propagator-describe-sources-batch-result.js +70 -0
  29. package/src/generated/orbpro/propagator/propagator-describe-sources-batch-result.ts +78 -0
  30. package/src/generated/orbpro/propagator/propagator-sample-trajectory-states-request.js +97 -0
  31. package/src/generated/orbpro/propagator/propagator-sample-trajectory-states-request.ts +117 -0
  32. package/src/generated/orbpro/propagator/propagator-sample-trajectory-states-result.js +140 -0
  33. package/src/generated/orbpro/propagator/propagator-sample-trajectory-states-result.ts +175 -0
  34. package/src/generated/orbpro/propagator/propagator-source-description.js +208 -0
  35. package/src/generated/orbpro/propagator/propagator-source-description.ts +257 -0
  36. package/src/generated/orbpro/propagator/propagator-source-kind.js +8 -0
  37. package/src/generated/orbpro/propagator/propagator-source-kind.ts +8 -0
  38. package/src/generated/orbpro/propagator/reference-frame.js +12 -0
  39. package/src/generated/orbpro/propagator/reference-frame.ts +12 -0
  40. package/src/generated/orbpro/propagator/state-flags.js +13 -0
  41. package/src/generated/orbpro/propagator/state-flags.ts +13 -0
  42. package/src/generated/orbpro/propagator/state-vector.js +55 -0
  43. package/src/generated/orbpro/propagator/state-vector.ts +61 -0
  44. package/src/generated/orbpro/propagator.js +20 -0
  45. package/src/generated/orbpro/propagator.ts +13 -0
  46. package/src/generated/orbpro/query/catalog-query-kind.js +10 -0
  47. package/src/generated/orbpro/query/catalog-query-kind.ts +10 -0
  48. package/src/generated/orbpro/query/catalog-query-request.js +89 -0
  49. package/src/generated/orbpro/query/catalog-query-request.ts +105 -0
  50. package/src/generated/orbpro/query/catalog-query-result.js +145 -0
  51. package/src/generated/orbpro/query/catalog-query-result.ts +179 -0
  52. package/src/generated/orbpro/query.js +8 -0
  53. package/src/generated/orbpro/query.ts +4 -0
  54. package/src/generated/orbpro/vec3.js +39 -0
  55. package/src/generated/orbpro/vec3.ts +40 -0
  56. package/src/host/abi.js +158 -0
  57. package/src/host/browserEdgeShims.js +17 -4
  58. package/src/host/browserHost.js +260 -48
  59. package/src/host/isomorphicLoader.js +3 -2
  60. package/src/host/nodeHost.js +168 -71
  61. package/src/index.d.ts +99 -3
  62. package/src/runtime-host/index.js +34 -0
  63. package/src/testing/browserModuleHarness.js +16 -3
  64. package/src/testing/index.d.ts +1 -0
  65. package/src/testing/index.js +5 -4
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import { RuntimeTarget } from "../runtime/constants.js";
9
+ import { toUint8Array } from "../utils/encoding.js";
9
10
  import {
10
11
  parseCronExpression,
11
12
  matchesCronExpression,
@@ -28,8 +29,13 @@ export const BrowserHostSupportedCapabilities = Object.freeze([
28
29
  "context_read",
29
30
  "context_write",
30
31
  "crypto_hash",
32
+ "crypto_sign",
33
+ "crypto_verify",
31
34
  "crypto_encrypt",
32
35
  "crypto_decrypt",
36
+ "crypto_key_agreement",
37
+ "crypto_kdf",
38
+ "wallet_sign",
33
39
  "logging",
34
40
  ]);
35
41
 
@@ -60,9 +66,13 @@ export const BrowserHostSupportedOperations = Object.freeze([
60
66
  "filesystem.stat",
61
67
  "filesystem.rename",
62
68
  "ipfs.invoke",
69
+ "ipfs.add",
70
+ "ipfs.cat",
63
71
  "protocol_handle.register",
64
72
  "protocol_handle.unregister",
65
73
  "protocol_dial.dial",
74
+ "protocol.request",
75
+ "keyslot.get",
66
76
  "context.get",
67
77
  "context.set",
68
78
  "context.delete",
@@ -70,8 +80,15 @@ export const BrowserHostSupportedOperations = Object.freeze([
70
80
  "context.listScopes",
71
81
  "crypto.sha256",
72
82
  "crypto.sha512",
83
+ "crypto.hkdf",
73
84
  "crypto.aesGcmEncrypt",
74
85
  "crypto.aesGcmDecrypt",
86
+ "crypto.x25519.generateKeypair",
87
+ "crypto.x25519.publicKey",
88
+ "crypto.x25519.sharedSecret",
89
+ "crypto.ed25519.publicKeyFromSeed",
90
+ "crypto.ed25519.sign",
91
+ "crypto.ed25519.verify",
75
92
  ]);
76
93
 
77
94
  export class BrowserHostCapabilityError extends Error {
@@ -108,6 +125,41 @@ function normalizeBrowserNetworkTransport(params = {}) {
108
125
  );
109
126
  }
110
127
 
128
+ function resolveCapabilityAdapters(options = {}) {
129
+ const adapters =
130
+ options.capabilityAdapters && typeof options.capabilityAdapters === "object"
131
+ ? options.capabilityAdapters
132
+ : {};
133
+ return {
134
+ filesystem: options.filesystem ?? adapters.filesystem ?? null,
135
+ network: options.network ?? adapters.network ?? null,
136
+ ipfs: options.ipfs ?? adapters.ipfs ?? null,
137
+ walletSign:
138
+ options.walletSign ??
139
+ adapters.walletSign ??
140
+ adapters.wallet_sign ??
141
+ adapters.keyslot ??
142
+ null,
143
+ protocolHandle:
144
+ options.protocolHandle ??
145
+ adapters.protocolHandle ??
146
+ adapters.protocol_handle ??
147
+ null,
148
+ protocolDial:
149
+ options.protocolDial ??
150
+ adapters.protocolDial ??
151
+ adapters.protocol_dial ??
152
+ null,
153
+ };
154
+ }
155
+
156
+ function normalizeCryptoBytes(value) {
157
+ if (typeof value === "string") {
158
+ return new TextEncoder().encode(value);
159
+ }
160
+ return toUint8Array(value);
161
+ }
162
+
111
163
  async function invokeAdapterMethod(adapter, methodName, params, label) {
112
164
  if (!adapter || typeof adapter !== "object") {
113
165
  throw new Error(`${label} adapter is not configured for this host.`);
@@ -126,6 +178,7 @@ async function invokeAdapterMethod(adapter, methodName, params, label) {
126
178
  export class BrowserHost {
127
179
  constructor(options = {}) {
128
180
  this.runtimeTarget = RuntimeTarget.BROWSER;
181
+ const capabilityAdapters = resolveCapabilityAdapters(options);
129
182
 
130
183
  const granted = options.capabilities
131
184
  ? new Set(options.capabilities)
@@ -136,12 +189,15 @@ export class BrowserHost {
136
189
  WebSocket: options.WebSocket ?? options.edgeShims?.WebSocket,
137
190
  crypto: options.crypto ?? options.edgeShims?.crypto,
138
191
  performance: options.performance ?? options.edgeShims?.performance,
139
- network: options.network ?? options.edgeShims?.network,
140
- ipfs: options.ipfs ?? options.edgeShims?.ipfs,
192
+ capabilityAdapters,
193
+ network: capabilityAdapters.network ?? options.edgeShims?.network,
194
+ ipfs: capabilityAdapters.ipfs ?? options.edgeShims?.ipfs,
141
195
  protocolHandle:
142
- options.protocolHandle ?? options.edgeShims?.protocolHandle,
143
- protocolDial: options.protocolDial ?? options.edgeShims?.protocolDial,
144
- filesystem: options.filesystem ?? options.edgeShims?.filesystem,
196
+ capabilityAdapters.protocolHandle ?? options.edgeShims?.protocolHandle,
197
+ protocolDial:
198
+ capabilityAdapters.protocolDial ?? options.edgeShims?.protocolDial,
199
+ filesystem:
200
+ capabilityAdapters.filesystem ?? options.edgeShims?.filesystem,
145
201
  filesystemRoot: options.filesystemRoot ?? options.edgeShims?.filesystemRoot,
146
202
  });
147
203
  const performanceApi = edgeShims.performance ?? {
@@ -149,11 +205,13 @@ export class BrowserHost {
149
205
  timeOrigin: 0,
150
206
  };
151
207
  const cryptoApi = edgeShims.crypto;
208
+ const wasmWallet = options.wasmWallet ?? null;
152
209
  const fetchImpl = edgeShims.fetch;
153
210
  const WebSocketImpl = edgeShims.WebSocket;
154
211
  const filesystem = edgeShims.filesystem;
155
212
  const networkAdapter = edgeShims.network;
156
213
  const ipfsAdapter = edgeShims.ipfs;
214
+ const walletSignAdapter = capabilityAdapters.walletSign;
157
215
  const protocolHandleAdapter = edgeShims.protocolHandle;
158
216
  const protocolDialAdapter = edgeShims.protocolDial;
159
217
 
@@ -303,18 +361,18 @@ export class BrowserHost {
303
361
  this.#assertCapability("network", "network.request");
304
362
  const transport = normalizeBrowserNetworkTransport(params);
305
363
  const request = params.request ?? params;
306
- if (transport === "http") {
307
- return this.http.request(request);
308
- }
309
- if (transport === "websocket") {
310
- return this.websocket.exchange(request);
311
- }
312
364
  if (networkAdapter) {
313
365
  return invokeAdapterMethod(networkAdapter, "request", {
314
366
  ...request,
315
367
  transport,
316
368
  }, "network");
317
369
  }
370
+ if (transport === "http") {
371
+ return this.http.request(request);
372
+ }
373
+ if (transport === "websocket") {
374
+ return this.websocket.exchange(request);
375
+ }
318
376
  throw new Error(
319
377
  `Browser host does not support network transport "${transport}".`,
320
378
  );
@@ -330,6 +388,14 @@ export class BrowserHost {
330
388
  }
331
389
  return invokeAdapterMethod(ipfsAdapter, operation, params, "ipfs");
332
390
  },
391
+ add: async (params = {}) => {
392
+ this.#assertCapability("ipfs", "ipfs.add");
393
+ return invokeAdapterMethod(ipfsAdapter, "add", params, "ipfs");
394
+ },
395
+ cat: async (params = {}) => {
396
+ this.#assertCapability("ipfs", "ipfs.cat");
397
+ return invokeAdapterMethod(ipfsAdapter, "cat", params, "ipfs");
398
+ },
333
399
  });
334
400
 
335
401
  this.protocolHandle = Object.freeze({
@@ -363,6 +429,22 @@ export class BrowserHost {
363
429
  "protocol_dial",
364
430
  );
365
431
  },
432
+ request: async (params = {}) => {
433
+ this.#assertCapability("protocol_dial", "protocol.request");
434
+ return invokeAdapterMethod(
435
+ protocolDialAdapter,
436
+ "request",
437
+ params,
438
+ "protocol_dial",
439
+ );
440
+ },
441
+ });
442
+
443
+ this.keyslot = Object.freeze({
444
+ get: async (params = {}) => {
445
+ this.#assertCapability("wallet_sign", "keyslot.get");
446
+ return invokeAdapterMethod(walletSignAdapter, "get", params, "wallet_sign");
447
+ },
366
448
  });
367
449
 
368
450
  this.context = Object.freeze({
@@ -393,60 +475,161 @@ export class BrowserHost {
393
475
  });
394
476
 
395
477
  this.crypto = Object.freeze({
396
- sha256: async (data) => {
478
+ sha256: (data) => {
397
479
  this.#assertCapability("crypto_hash", "crypto.sha256");
398
- if (!cryptoApi?.subtle) {
399
- throw new Error("No Web Crypto subtle implementation is available.");
480
+ if (!wasmWallet?.utils?.sha256) {
481
+ throw new Error("Browser host crypto.sha256 requires a preloaded wasmWallet.");
400
482
  }
401
- const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
402
- return new Uint8Array(await cryptoApi.subtle.digest("SHA-256", bytes));
483
+ return new Uint8Array(wasmWallet.utils.sha256(normalizeCryptoBytes(data)));
403
484
  },
404
- sha512: async (data) => {
485
+ sha512: (data) => {
405
486
  this.#assertCapability("crypto_hash", "crypto.sha512");
406
- if (!cryptoApi?.subtle) {
407
- throw new Error("No Web Crypto subtle implementation is available.");
487
+ if (!wasmWallet?.utils?.sha512) {
488
+ throw new Error("Browser host crypto.sha512 requires a preloaded wasmWallet.");
408
489
  }
409
- const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
410
- return new Uint8Array(await cryptoApi.subtle.digest("SHA-512", bytes));
490
+ return new Uint8Array(wasmWallet.utils.sha512(normalizeCryptoBytes(data)));
411
491
  },
412
- aesGcmEncrypt: async (params) => {
413
- this.#assertCapability("crypto_encrypt", "crypto.aesGcmEncrypt");
414
- if (!cryptoApi?.subtle || !cryptoApi?.getRandomValues) {
415
- throw new Error("No Web Crypto implementation is available.");
492
+ hkdf: (params = {}) => {
493
+ this.#assertCapability("crypto_kdf", "crypto.hkdf");
494
+ if (!wasmWallet?.utils?.hkdf) {
495
+ throw new Error("Browser host crypto.hkdf requires a preloaded wasmWallet.");
416
496
  }
417
- const key = await cryptoApi.subtle.importKey(
418
- "raw",
419
- params.key,
420
- { name: "AES-GCM" },
421
- false,
422
- ["encrypt"],
497
+ return new Uint8Array(
498
+ wasmWallet.utils.hkdf(
499
+ toUint8Array(params.ikm),
500
+ toUint8Array(params.salt),
501
+ params.info === undefined || params.info === null
502
+ ? new Uint8Array()
503
+ : toUint8Array(params.info),
504
+ Number(params.length ?? 0),
505
+ ),
423
506
  );
424
- const iv = params.iv ?? cryptoApi.getRandomValues(new Uint8Array(12));
425
- const ciphertext = new Uint8Array(
426
- await cryptoApi.subtle.encrypt({ name: "AES-GCM", iv }, key, params.plaintext),
507
+ },
508
+ aesGcmEncrypt: (params = {}) => {
509
+ this.#assertCapability("crypto_encrypt", "crypto.aesGcmEncrypt");
510
+ if (!wasmWallet?.utils?.aesGcm?.encrypt) {
511
+ throw new Error(
512
+ "Browser host crypto.aesGcmEncrypt requires a preloaded wasmWallet.",
513
+ );
514
+ }
515
+ const iv =
516
+ params.iv === undefined || params.iv === null
517
+ ? new Uint8Array(wasmWallet.utils.getRandomBytes(12))
518
+ : toUint8Array(params.iv);
519
+ const result = wasmWallet.utils.aesGcm.encrypt(
520
+ toUint8Array(params.key),
521
+ toUint8Array(params.plaintext),
522
+ iv,
523
+ params.aad === undefined || params.aad === null
524
+ ? undefined
525
+ : toUint8Array(params.aad),
427
526
  );
428
- return { ciphertext, iv };
527
+ return {
528
+ ciphertext: new Uint8Array(result.ciphertext),
529
+ tag: new Uint8Array(result.tag),
530
+ iv,
531
+ };
429
532
  },
430
- aesGcmDecrypt: async (params) => {
533
+ aesGcmDecrypt: (params = {}) => {
431
534
  this.#assertCapability("crypto_decrypt", "crypto.aesGcmDecrypt");
432
- if (!cryptoApi?.subtle) {
433
- throw new Error("No Web Crypto subtle implementation is available.");
535
+ if (!wasmWallet?.utils?.aesGcm?.decrypt) {
536
+ throw new Error(
537
+ "Browser host crypto.aesGcmDecrypt requires a preloaded wasmWallet.",
538
+ );
539
+ }
540
+ return new Uint8Array(
541
+ wasmWallet.utils.aesGcm.decrypt(
542
+ toUint8Array(params.key),
543
+ toUint8Array(params.ciphertext),
544
+ toUint8Array(params.tag),
545
+ toUint8Array(params.iv),
546
+ params.aad === undefined || params.aad === null
547
+ ? undefined
548
+ : toUint8Array(params.aad),
549
+ ),
550
+ );
551
+ },
552
+ generateX25519Keypair: () => {
553
+ this.#assertCapability(
554
+ "crypto_key_agreement",
555
+ "crypto.x25519.generateKeypair",
556
+ );
557
+ if (!wasmWallet?.curves?.x25519 || !wasmWallet?.utils?.getRandomBytes) {
558
+ throw new Error(
559
+ "Browser host crypto.x25519.generateKeypair requires a preloaded wasmWallet.",
560
+ );
561
+ }
562
+ const privateKey = new Uint8Array(wasmWallet.utils.getRandomBytes(32));
563
+ const publicKey = new Uint8Array(
564
+ wasmWallet.curves.x25519.publicKey(privateKey),
565
+ );
566
+ return { privateKey, publicKey };
567
+ },
568
+ x25519PublicKey: (privateKey) => {
569
+ this.#assertCapability("crypto_key_agreement", "crypto.x25519.publicKey");
570
+ if (!wasmWallet?.curves?.x25519?.publicKey) {
571
+ throw new Error(
572
+ "Browser host crypto.x25519.publicKey requires a preloaded wasmWallet.",
573
+ );
434
574
  }
435
- const key = await cryptoApi.subtle.importKey(
436
- "raw",
437
- params.key,
438
- { name: "AES-GCM" },
439
- false,
440
- ["decrypt"],
575
+ return new Uint8Array(
576
+ wasmWallet.curves.x25519.publicKey(toUint8Array(privateKey)),
441
577
  );
578
+ },
579
+ x25519SharedSecret: (privateKey, publicKey) => {
580
+ this.#assertCapability("crypto_key_agreement", "crypto.x25519.sharedSecret");
581
+ if (!wasmWallet?.curves?.x25519?.ecdh) {
582
+ throw new Error(
583
+ "Browser host crypto.x25519.sharedSecret requires a preloaded wasmWallet.",
584
+ );
585
+ }
442
586
  return new Uint8Array(
443
- await cryptoApi.subtle.decrypt(
444
- { name: "AES-GCM", iv: params.iv },
445
- key,
446
- params.ciphertext,
587
+ wasmWallet.curves.x25519.ecdh(
588
+ toUint8Array(privateKey),
589
+ toUint8Array(publicKey),
447
590
  ),
448
591
  );
449
592
  },
593
+ ed25519: Object.freeze({
594
+ publicKeyFromSeed: (seed) => {
595
+ this.#assertCapability("crypto_sign", "crypto.ed25519.publicKeyFromSeed");
596
+ if (!wasmWallet?.curves?.ed25519?.publicKeyFromSeed) {
597
+ throw new Error(
598
+ "Browser host crypto.ed25519.publicKeyFromSeed requires a preloaded wasmWallet.",
599
+ );
600
+ }
601
+ return new Uint8Array(
602
+ wasmWallet.curves.ed25519.publicKeyFromSeed(toUint8Array(seed)),
603
+ );
604
+ },
605
+ sign: (message, seed) => {
606
+ this.#assertCapability("crypto_sign", "crypto.ed25519.sign");
607
+ if (!wasmWallet?.curves?.ed25519?.sign) {
608
+ throw new Error(
609
+ "Browser host crypto.ed25519.sign requires a preloaded wasmWallet.",
610
+ );
611
+ }
612
+ return new Uint8Array(
613
+ wasmWallet.curves.ed25519.sign(
614
+ toUint8Array(message),
615
+ toUint8Array(seed),
616
+ ),
617
+ );
618
+ },
619
+ verify: (message, signature, publicKey) => {
620
+ this.#assertCapability("crypto_verify", "crypto.ed25519.verify");
621
+ if (!wasmWallet?.curves?.ed25519?.verify) {
622
+ throw new Error(
623
+ "Browser host crypto.ed25519.verify requires a preloaded wasmWallet.",
624
+ );
625
+ }
626
+ return wasmWallet.curves.ed25519.verify(
627
+ toUint8Array(message),
628
+ toUint8Array(signature),
629
+ toUint8Array(publicKey),
630
+ );
631
+ },
632
+ }),
450
633
  });
451
634
 
452
635
  this.filesystem = Object.freeze({
@@ -579,12 +762,20 @@ export class BrowserHost {
579
762
  return this.filesystem.rename(params.fromPath, params.toPath);
580
763
  case "ipfs.invoke":
581
764
  return this.ipfs.invoke(params);
765
+ case "ipfs.add":
766
+ return this.ipfs.add(params);
767
+ case "ipfs.cat":
768
+ return this.ipfs.cat(params);
582
769
  case "protocol_handle.register":
583
770
  return this.protocolHandle.register(params);
584
771
  case "protocol_handle.unregister":
585
772
  return this.protocolHandle.unregister(params);
586
773
  case "protocol_dial.dial":
587
774
  return this.protocolDial.dial(params);
775
+ case "protocol.request":
776
+ return this.protocolDial.request(params);
777
+ case "keyslot.get":
778
+ return this.keyslot.get(params);
588
779
  case "context.get":
589
780
  return this.context.get(params.scope, params.key);
590
781
  case "context.set":
@@ -599,10 +790,31 @@ export class BrowserHost {
599
790
  return this.crypto.sha256(params.value ?? params.bytes);
600
791
  case "crypto.sha512":
601
792
  return this.crypto.sha512(params.value ?? params.bytes);
793
+ case "crypto.hkdf":
794
+ return this.crypto.hkdf(params);
602
795
  case "crypto.aesGcmEncrypt":
603
796
  return this.crypto.aesGcmEncrypt(params);
604
797
  case "crypto.aesGcmDecrypt":
605
798
  return this.crypto.aesGcmDecrypt(params);
799
+ case "crypto.x25519.generateKeypair":
800
+ return this.crypto.generateX25519Keypair();
801
+ case "crypto.x25519.publicKey":
802
+ return this.crypto.x25519PublicKey(params.privateKey);
803
+ case "crypto.x25519.sharedSecret":
804
+ return this.crypto.x25519SharedSecret(
805
+ params.privateKey,
806
+ params.publicKey,
807
+ );
808
+ case "crypto.ed25519.publicKeyFromSeed":
809
+ return this.crypto.ed25519.publicKeyFromSeed(params.seed);
810
+ case "crypto.ed25519.sign":
811
+ return this.crypto.ed25519.sign(params.message, params.seed);
812
+ case "crypto.ed25519.verify":
813
+ return this.crypto.ed25519.verify(
814
+ params.message,
815
+ params.signature,
816
+ params.publicKey,
817
+ );
606
818
  default:
607
819
  throw new Error(`Unknown browser host operation "${normalized}".`);
608
820
  }
@@ -13,7 +13,7 @@ import {
13
13
  createBrowserModuleHarness,
14
14
  detectArtifactProfile,
15
15
  } from "../testing/browserModuleHarness.js";
16
- import { dispatchHostOperation } from "./abi.js";
16
+ import { createAsyncHostDispatcher } from "./abi.js";
17
17
 
18
18
  const isBrowser =
19
19
  typeof globalThis.window !== "undefined" &&
@@ -23,11 +23,12 @@ function attachHostDispatch(harness, host) {
23
23
  if (!host || typeof host !== "object") {
24
24
  return harness;
25
25
  }
26
+ const dispatchHost = createAsyncHostDispatcher(host);
26
27
  return {
27
28
  ...harness,
28
29
  host,
29
30
  async callHost(operation, params = {}) {
30
- return dispatchHostOperation(host, operation, params);
31
+ return dispatchHost(operation, params);
31
32
  },
32
33
  };
33
34
  }