@tinycloud/sdk-services 3.11.0-beta.2 → 3.12.0-beta.10

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 (71) hide show
  1. package/dist/{BaseService-Ma2MwJAd.d.ts → BaseService-BRDG69KR.d.ts} +1 -1
  2. package/dist/{BaseService-O0iyuFLk.d.cts → BaseService-CdBkfPGE.d.cts} +1 -1
  3. package/dist/{IHooksService-4QNODVy6.d.cts → IHooksService-C9p3stsB.d.cts} +1 -1
  4. package/dist/{IHooksService-CvTpJbQD.d.ts → IHooksService-D6eyZat1.d.ts} +1 -1
  5. package/dist/{ISQLService-Aly1CBsW.d.ts → ISQLService-B_4KcGA-.d.ts} +1 -1
  6. package/dist/{ISQLService-BOgWzHLT.d.cts → ISQLService-C6nNpcls.d.cts} +1 -1
  7. package/dist/context.cjs +4 -0
  8. package/dist/context.cjs.map +1 -1
  9. package/dist/context.d.cts +1 -1
  10. package/dist/context.d.ts +1 -1
  11. package/dist/context.js +4 -0
  12. package/dist/context.js.map +1 -1
  13. package/dist/encryption/index.cjs +276 -14
  14. package/dist/encryption/index.cjs.map +1 -1
  15. package/dist/encryption/index.d.cts +26 -28
  16. package/dist/encryption/index.d.ts +26 -28
  17. package/dist/encryption/index.js +268 -14
  18. package/dist/encryption/index.js.map +1 -1
  19. package/dist/encryption/named-keys.cjs +225 -14
  20. package/dist/encryption/named-keys.cjs.map +1 -1
  21. package/dist/encryption/named-keys.d.cts +7 -2
  22. package/dist/encryption/named-keys.d.ts +7 -2
  23. package/dist/encryption/named-keys.js +225 -14
  24. package/dist/encryption/named-keys.js.map +1 -1
  25. package/dist/encryption/resource.cjs.map +1 -1
  26. package/dist/encryption/resource.js.map +1 -1
  27. package/dist/feed/index.cjs +4 -0
  28. package/dist/feed/index.cjs.map +1 -1
  29. package/dist/feed/index.d.cts +3 -3
  30. package/dist/feed/index.d.ts +3 -3
  31. package/dist/feed/index.js +4 -0
  32. package/dist/feed/index.js.map +1 -1
  33. package/dist/index.cjs +509 -18
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +14 -12
  36. package/dist/index.d.ts +14 -12
  37. package/dist/index.js +499 -18
  38. package/dist/index.js.map +1 -1
  39. package/dist/internal/decrypt-transport-response-error.d.cts +1 -1
  40. package/dist/internal/decrypt-transport-response-error.d.ts +1 -1
  41. package/dist/kv/index.cjs +34 -0
  42. package/dist/kv/index.cjs.map +1 -1
  43. package/dist/kv/index.d.cts +4 -4
  44. package/dist/kv/index.d.ts +4 -4
  45. package/dist/kv/index.js +34 -0
  46. package/dist/kv/index.js.map +1 -1
  47. package/dist/kv/replication/index.cjs +39 -8
  48. package/dist/kv/replication/index.cjs.map +1 -1
  49. package/dist/kv/replication/index.d.cts +3 -3
  50. package/dist/kv/replication/index.d.ts +3 -3
  51. package/dist/kv/replication/index.js +38 -7
  52. package/dist/kv/replication/index.js.map +1 -1
  53. package/dist/{scope-DEgc9f-W.d.cts → scope-DtcbyRKY.d.cts} +1 -1
  54. package/dist/{scope-BZr0QwxX.d.ts → scope-J20PQP3u.d.ts} +1 -1
  55. package/dist/sql/index.cjs +36 -0
  56. package/dist/sql/index.cjs.map +1 -1
  57. package/dist/sql/index.d.cts +4 -4
  58. package/dist/sql/index.d.ts +4 -4
  59. package/dist/sql/index.js +36 -0
  60. package/dist/sql/index.js.map +1 -1
  61. package/dist/telemetry/requestLog.cjs +4 -0
  62. package/dist/telemetry/requestLog.cjs.map +1 -1
  63. package/dist/telemetry/requestLog.d.cts +1 -1
  64. package/dist/telemetry/requestLog.d.ts +1 -1
  65. package/dist/telemetry/requestLog.js +4 -0
  66. package/dist/telemetry/requestLog.js.map +1 -1
  67. package/dist/{types-D4XbIfFJ.d.cts → types-DfqNz9Nu.d.cts} +135 -6
  68. package/dist/{types-CSd0RYir.d.ts → types-DjAP8dve.d.cts} +4 -0
  69. package/dist/{types-CSd0RYir.d.cts → types-DjAP8dve.d.ts} +4 -0
  70. package/dist/{types-Bf91gup6.d.ts → types-Nvi_RckJ.d.ts} +135 -6
  71. package/package.json +4 -1
@@ -120,9 +120,9 @@ function base64Decode(s) {
120
120
  function utf8Encode(s) {
121
121
  return new TextEncoder().encode(s);
122
122
  }
123
- function canonicalHashHex(sha256, value) {
123
+ function canonicalHashHex(sha2562, value) {
124
124
  const canonical = canonicalize(value);
125
- return hexEncode(sha256(utf8Encode(canonical)));
125
+ return hexEncode(sha2562(utf8Encode(canonical)));
126
126
  }
127
127
 
128
128
  // src/encryption/networkId.ts
@@ -170,6 +170,26 @@ function parseNetworkId(networkId) {
170
170
  }
171
171
  return { networkId, ownerDid, name };
172
172
  }
173
+ function parseEncryptionResource(resource) {
174
+ const networkSeparator = resource.lastIndexOf(":");
175
+ const nameAndPath = resource.slice(networkSeparator + 1);
176
+ const pathSeparator = nameAndPath.indexOf("/");
177
+ const name = pathSeparator === -1 ? nameAndPath : nameAndPath.slice(0, pathSeparator);
178
+ const networkId = pathSeparator === -1 ? resource : `${resource.slice(0, networkSeparator + 1)}${name}`;
179
+ const parsed = parseNetworkId(networkId);
180
+ if (pathSeparator === -1) return parsed;
181
+ const keyPath = nameAndPath.slice(pathSeparator + 1);
182
+ const segments = keyPath.split("/");
183
+ const prefix = keyPath.endsWith("/");
184
+ if (keyPath.length === 0 || /[\u0000-\u001f\u007f\\]/.test(keyPath) || segments.some(
185
+ (segment, index) => segment === "." || segment === ".." || segment.length === 0 && !(prefix && index === segments.length - 1)
186
+ )) {
187
+ throw new NetworkIdError(
188
+ `encryption resource has an invalid keyPath (got ${JSON.stringify(resource)})`
189
+ );
190
+ }
191
+ return { ...parsed, keyPath };
192
+ }
173
193
  var ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;
174
194
 
175
195
  // src/encryption/receiverKey.ts
@@ -205,6 +225,8 @@ function defaultEncryptionMessage(input) {
205
225
  return input.message ?? input.cause.message;
206
226
  case "INVALID_INPUT":
207
227
  return input.message;
228
+ default:
229
+ return input.message ?? input.code;
208
230
  }
209
231
  }
210
232
  function encryptionError(input) {
@@ -215,6 +237,152 @@ function encryptionError(input) {
215
237
  };
216
238
  }
217
239
 
240
+ // src/encryption/keyWrap.ts
241
+ var import_aes = require("@noble/ciphers/aes");
242
+ var import_ed25519 = require("@noble/curves/ed25519");
243
+ var import_hkdf = require("@noble/hashes/hkdf");
244
+ var import_sha256 = require("@noble/hashes/sha256");
245
+ var import_utils = require("@noble/hashes/utils");
246
+ var KEY_WRAP_V2_ALG = "x25519-hkdf-aes256gcm/v2";
247
+ var MAGIC = utf8Encode("TCW2");
248
+ var INFO = utf8Encode("tinycloud.encryption.key-wrap/v2");
249
+ var MAX_HEADER = 65536;
250
+ function concat(...parts) {
251
+ const result = new Uint8Array(parts.reduce((length, part) => length + part.length, 0));
252
+ let offset = 0;
253
+ for (const part of parts) {
254
+ result.set(part, offset);
255
+ offset += part.length;
256
+ }
257
+ return result;
258
+ }
259
+ function equal(a, b) {
260
+ if (a.length !== b.length) return false;
261
+ let difference = 0;
262
+ for (let i = 0; i < a.length; i++) difference |= a[i] ^ b[i];
263
+ return difference === 0;
264
+ }
265
+ function decode32(value) {
266
+ if (typeof value !== "string") throw new Error("Invalid key wrap encoding");
267
+ const decoded = base64Decode(value);
268
+ if (decoded.length !== 32 || base64Encode(decoded) !== value) throw new Error("Invalid key wrap encoding");
269
+ return decoded;
270
+ }
271
+ function isWellFormed(value) {
272
+ for (let i = 0; i < value.length; i++) {
273
+ const unit = value.charCodeAt(i);
274
+ if (unit >= 55296 && unit <= 56319) {
275
+ const next = value.charCodeAt(++i);
276
+ if (!(next >= 56320 && next <= 57343)) return false;
277
+ } else if (unit >= 56320 && unit <= 57343) return false;
278
+ }
279
+ return true;
280
+ }
281
+ function validateContext(context) {
282
+ if (context.purpose !== "network-key" && context.purpose !== "receiver-key" || typeof context.networkId !== "string" || typeof context.keyPath !== "string" || !isWellFormed(context.networkId) || !isWellFormed(context.keyPath) || !Number.isSafeInteger(context.keyVersion) || context.keyVersion <= 0 || !context.metadata || typeof context.metadata !== "object" || Array.isArray(context.metadata) || Object.entries(context.metadata).some(([key, value]) => !isWellFormed(key) || typeof value !== "string" || !isWellFormed(value))) {
283
+ throw new Error("Invalid key wrap context");
284
+ }
285
+ if (context.networkId !== "") {
286
+ const resource = parseEncryptionResource(context.keyPath === "" ? context.networkId : `${context.networkId}/${context.keyPath}`);
287
+ if (resource.networkId !== context.networkId || (resource.keyPath ?? "") !== context.keyPath || context.keyPath.endsWith("/")) {
288
+ throw new Error("Invalid key wrap resource");
289
+ }
290
+ }
291
+ }
292
+ function isKeyWrapV2(wrapped) {
293
+ return wrapped.length >= 4 && MAGIC.every((byte, index) => wrapped[index] === byte);
294
+ }
295
+ function readKeyWrapV2(wrapped) {
296
+ if (!isKeyWrapV2(wrapped) || wrapped.length < 8) throw new Error("Invalid v2 key wrap frame");
297
+ const length = new DataView(wrapped.buffer, wrapped.byteOffset, wrapped.byteLength).getUint32(4);
298
+ if (length === 0 || length > MAX_HEADER || wrapped.length < 8 + length + 12 + 16) throw new Error("Invalid v2 key wrap length");
299
+ const bytes = wrapped.subarray(8, 8 + length);
300
+ const header = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
301
+ const fields = ["v", "alg", "kdf", "aead", "salt", "ephemeralPublicKey", "recipientPublicKey", "purpose", "networkId", "keyPath", "keyVersion", "metadata"].sort();
302
+ if (!header || typeof header !== "object" || Array.isArray(header) || Object.keys(header).sort().join(",") !== fields.join(",") || header.v !== 2 || header.alg !== KEY_WRAP_V2_ALG || header.kdf !== "hkdf-sha256" || header.aead !== "aes-256-gcm") {
303
+ throw new Error("Invalid v2 key wrap header");
304
+ }
305
+ validateContext(header);
306
+ decode32(header.salt);
307
+ decode32(header.ephemeralPublicKey);
308
+ decode32(header.recipientPublicKey);
309
+ if (!equal(bytes, utf8Encode(canonicalize({ ...header })))) throw new Error("Non-canonical v2 key wrap header");
310
+ const end = 8 + length;
311
+ return { header, aad: wrapped.subarray(0, end), nonce: wrapped.subarray(end, end + 12), ciphertext: wrapped.subarray(end + 12) };
312
+ }
313
+ function assertKeyWrapContext(header, expected) {
314
+ validateContext(expected);
315
+ for (const field of ["purpose", "networkId", "keyPath", "keyVersion"]) {
316
+ if (header[field] !== expected[field]) throw new Error("Key wrap context mismatch");
317
+ }
318
+ if (canonicalize(header.metadata) !== canonicalize(expected.metadata)) throw new Error("Key wrap metadata mismatch");
319
+ }
320
+ function deriveKey(secret, ephemeral, recipient, salt) {
321
+ const shared = import_ed25519.x25519.getSharedSecret(secret, ephemeral);
322
+ if (shared.every((byte) => byte === 0)) throw new Error("Invalid key agreement");
323
+ try {
324
+ return (0, import_hkdf.hkdf)(import_sha256.sha256, shared, salt, concat(INFO, ephemeral, recipient), 32);
325
+ } finally {
326
+ shared.fill(0);
327
+ }
328
+ }
329
+ function sealKeyV2(recipientPublicKey, plaintext, context) {
330
+ validateContext(context);
331
+ if (recipientPublicKey.length !== 32) throw new Error("Invalid recipient public key");
332
+ const secret = (0, import_utils.randomBytes)(32);
333
+ const ephemeral = import_ed25519.x25519.getPublicKey(secret);
334
+ const salt = (0, import_utils.randomBytes)(32);
335
+ const header = {
336
+ ...context,
337
+ v: 2,
338
+ alg: KEY_WRAP_V2_ALG,
339
+ kdf: "hkdf-sha256",
340
+ aead: "aes-256-gcm",
341
+ salt: base64Encode(salt),
342
+ ephemeralPublicKey: base64Encode(ephemeral),
343
+ recipientPublicKey: base64Encode(recipientPublicKey)
344
+ };
345
+ const bytes = utf8Encode(canonicalize({ ...header }));
346
+ if (bytes.length > MAX_HEADER) throw new Error("Key wrap header too large");
347
+ const prefix = new Uint8Array(8);
348
+ prefix.set(MAGIC);
349
+ new DataView(prefix.buffer).setUint32(4, bytes.length);
350
+ const aad = concat(prefix, bytes);
351
+ const nonce = (0, import_utils.randomBytes)(12);
352
+ let key;
353
+ try {
354
+ const shared = import_ed25519.x25519.getSharedSecret(secret, recipientPublicKey);
355
+ try {
356
+ if (shared.every((byte) => byte === 0)) throw new Error("Invalid key agreement");
357
+ key = (0, import_hkdf.hkdf)(import_sha256.sha256, shared, salt, concat(INFO, ephemeral, recipientPublicKey), 32);
358
+ } finally {
359
+ shared.fill(0);
360
+ }
361
+ return concat(aad, nonce, (0, import_aes.gcm)(key, nonce, aad).encrypt(plaintext));
362
+ } finally {
363
+ secret.fill(0);
364
+ key?.fill(0);
365
+ }
366
+ }
367
+ function openKeyV2(recipientPrivateKey, wrapped, expected) {
368
+ const { header, aad, nonce, ciphertext } = readKeyWrapV2(wrapped);
369
+ assertKeyWrapContext(header, expected);
370
+ const recipient = import_ed25519.x25519.getPublicKey(recipientPrivateKey);
371
+ if (!equal(recipient, decode32(header.recipientPublicKey))) throw new Error("Key wrap recipient mismatch");
372
+ const key = deriveKey(recipientPrivateKey, decode32(header.ephemeralPublicKey), recipient, decode32(header.salt));
373
+ try {
374
+ return (0, import_aes.gcm)(key, nonce, aad).decrypt(ciphertext);
375
+ } finally {
376
+ key.fill(0);
377
+ }
378
+ }
379
+ function assertKeyWrapAlgorithm(wrapped, alg, requireV2 = false) {
380
+ if (alg !== "x25519-aes256gcm/v1" && alg !== KEY_WRAP_V2_ALG) throw new Error("Unsupported key wrap algorithm");
381
+ if (requireV2 && alg !== KEY_WRAP_V2_ALG) throw new Error("V2 network key wrap required");
382
+ if (isKeyWrapV2(wrapped) !== (alg === KEY_WRAP_V2_ALG)) throw new Error("Key wrap algorithm mismatch");
383
+ if (alg === KEY_WRAP_V2_ALG) readKeyWrapV2(wrapped);
384
+ }
385
+
218
386
  // src/encryption/response.ts
219
387
  function canonicalSignedResponse(response) {
220
388
  const { nodeSignature: _drop, ...rest } = response;
@@ -258,7 +426,7 @@ function verifyDecryptResponse(input) {
258
426
  })
259
427
  };
260
428
  }
261
- if (response.alg !== request.alg) {
429
+ if (response.alg !== "x25519-aes256gcm/v1" && response.alg !== KEY_WRAP_V2_ALG) {
262
430
  return {
263
431
  ok: false,
264
432
  error: encryptionError({
@@ -315,7 +483,7 @@ function verifyDecryptResponse(input) {
315
483
  })
316
484
  };
317
485
  }
318
- if (facts.encryptedSymmetricKeyHash !== response.encryptedSymmetricKeyHash || facts.receiverPublicKeyHash !== response.receiverPublicKeyHash || facts.networkId !== response.networkId || facts.targetNode !== response.targetNode || facts.alg !== response.alg || facts.keyVersion !== response.keyVersion) {
486
+ if (facts.encryptedSymmetricKeyHash !== response.encryptedSymmetricKeyHash || facts.receiverPublicKeyHash !== response.receiverPublicKeyHash || facts.networkId !== response.networkId || facts.targetNode !== response.targetNode || facts.alg !== request.alg || facts.keyVersion !== response.keyVersion) {
319
487
  return {
320
488
  ok: false,
321
489
  error: encryptionError({
@@ -338,11 +506,31 @@ function verifyDecryptResponse(input) {
338
506
  }
339
507
  return { ok: true, data: response };
340
508
  }
341
- function openWrappedKey(crypto, receiverPrivateKey, response) {
509
+ function openWrappedKey(crypto, receiverPrivateKey, response, expected) {
342
510
  const wrapped = base64Decode(response.wrappedKey);
511
+ assertKeyWrapAlgorithm(wrapped, response.alg);
512
+ if (response.alg === KEY_WRAP_V2_ALG) {
513
+ if (!expected) throw new Error("V2 response requires expected key context");
514
+ return openKeyV2(receiverPrivateKey, wrapped, expected);
515
+ }
343
516
  return crypto.openWithReceiverKey(receiverPrivateKey, wrapped);
344
517
  }
345
518
 
519
+ // src/encryption/envelope.ts
520
+ function validateEnvelopeKeyWrap(envelope, requireKeyWrapV2 = false) {
521
+ const wrapped = base64Decode(envelope.encryptedSymmetricKey);
522
+ assertKeyWrapAlgorithm(wrapped, envelope.alg, requireKeyWrapV2);
523
+ if (envelope.alg === KEY_WRAP_V2_ALG) {
524
+ assertKeyWrapContext(readKeyWrapV2(wrapped).header, {
525
+ purpose: "network-key",
526
+ networkId: envelope.networkId,
527
+ keyPath: envelope.keyPath ?? "",
528
+ keyVersion: envelope.keyVersion,
529
+ metadata: envelope.metadata ?? {}
530
+ });
531
+ }
532
+ }
533
+
346
534
  // src/encryption/resource.ts
347
535
  var import_bootstrap = require("@tinycloud/bootstrap");
348
536
  var SEGMENT_SOURCE = "[a-z0-9][a-z0-9._-]{0,63}";
@@ -425,7 +613,7 @@ function assertPath(path, what) {
425
613
  );
426
614
  }
427
615
  }
428
- function parseEncryptionResource(uri) {
616
+ function parseEncryptionResource2(uri) {
429
617
  if (typeof uri !== "string" || !uri.startsWith(ENCRYPTION_NETWORK_URN_PREFIX)) {
430
618
  throw new EncryptionResourceError(
431
619
  "not_encryption_urn",
@@ -486,7 +674,7 @@ function canonicalNetworkId(networkId) {
486
674
  return parsed.networkId;
487
675
  }
488
676
  function parseBuilt(resource, networkId) {
489
- if (parseEncryptionResource(resource).networkId !== networkId) {
677
+ if (parseEncryptionResource2(resource).networkId !== networkId) {
490
678
  throw new EncryptionResourceError(
491
679
  "malformed",
492
680
  `built resource does not round-trip (got ${JSON.stringify(resource)})`
@@ -585,7 +773,7 @@ function mapNodeKeyError(status, text, context) {
585
773
  function requireKeyTarget(resource) {
586
774
  let parsed;
587
775
  try {
588
- parsed = parseEncryptionResource(resource);
776
+ parsed = parseEncryptionResource2(resource);
589
777
  } catch (error) {
590
778
  throw new NamedKeyError(
591
779
  "INVALID_KEY_TARGET",
@@ -887,16 +1075,21 @@ var NamedKeyClient = class {
887
1075
  const { crypto } = this.config;
888
1076
  const symmetricKey = crypto.randomBytes(32);
889
1077
  const ciphertext = crypto.authEncrypt(symmetricKey, plaintext, options?.aad);
890
- const wrapped = crypto.sealToNetworkKey(
891
- base64Decode(descriptor.publicEncryptionKey),
892
- symmetricKey
893
- );
1078
+ const keyWrapV2 = options?.keyWrapV2 ?? this.config.keyWrapV2 ?? false;
1079
+ const publicKey = base64Decode(descriptor.publicEncryptionKey);
1080
+ const wrapped = keyWrapV2 ? sealKeyV2(publicKey, symmetricKey, {
1081
+ purpose: "network-key",
1082
+ networkId: descriptor.networkId,
1083
+ keyPath: descriptor.keyPath,
1084
+ keyVersion: descriptor.keyVersion,
1085
+ metadata: options?.metadata ?? {}
1086
+ }) : crypto.sealToNetworkKey(publicKey, symmetricKey);
894
1087
  const encryptedSymmetricKey = base64Encode(wrapped);
895
1088
  return {
896
1089
  v: NAMED_KEY_ENVELOPE_VERSION,
897
1090
  networkId: descriptor.networkId,
898
1091
  keyPath: descriptor.keyPath,
899
- alg: descriptor.alg ?? DEFAULT_ENCRYPTION_ALG,
1092
+ alg: keyWrapV2 ? KEY_WRAP_V2_ALG : DEFAULT_ENCRYPTION_ALG,
900
1093
  keyVersion: descriptor.keyVersion,
901
1094
  encryptedSymmetricKey,
902
1095
  encryptedSymmetricKeyHash: canonicalHashHex(crypto.sha256, encryptedSymmetricKey),
@@ -941,6 +1134,13 @@ var NamedKeyClient = class {
941
1134
  return results;
942
1135
  }
943
1136
  async decryptRoot(envelope) {
1137
+ if (this.config.requireKeyWrapV2) {
1138
+ try {
1139
+ validateEnvelopeKeyWrap(envelope, true);
1140
+ } catch (error) {
1141
+ throw new NamedKeyError("INVALID_ENVELOPE", "Envelope key wrap context is invalid", { cause: error });
1142
+ }
1143
+ }
944
1144
  if (this.config.decryptRoot === void 0) {
945
1145
  throw new NamedKeyError("DECRYPT_FAILED", "no root-key decrypt path is configured");
946
1146
  }
@@ -977,6 +1177,11 @@ var NamedKeyClient = class {
977
1177
  "envelope.encryptedSymmetricKeyHash does not match encryptedSymmetricKey"
978
1178
  );
979
1179
  }
1180
+ try {
1181
+ validateEnvelopeKeyWrap(e, this.config.requireKeyWrapV2 ?? false);
1182
+ } catch (error) {
1183
+ throw new NamedKeyError("INVALID_ENVELOPE", "Envelope key wrap context is invalid", { cause: error });
1184
+ }
980
1185
  return e;
981
1186
  }
982
1187
  async decryptKey(envelope) {
@@ -1038,7 +1243,13 @@ var NamedKeyClient = class {
1038
1243
  if (!verified.ok) {
1039
1244
  throw new NamedKeyError("INVALID_RESPONSE", safeEcho(verified.error.message), { cause: verified.error });
1040
1245
  }
1041
- const symmetricKey = openWrappedKey(crypto, receiverKey.privateKey, verified.data);
1246
+ const symmetricKey = openWrappedKey(crypto, receiverKey.privateKey, verified.data, {
1247
+ purpose: "receiver-key",
1248
+ networkId: body.networkId,
1249
+ keyPath: body.keyPath,
1250
+ keyVersion: body.keyVersion,
1251
+ metadata: {}
1252
+ });
1042
1253
  try {
1043
1254
  return crypto.authDecrypt(
1044
1255
  symmetricKey,