@tinycloud/sdk-services 3.8.0-beta.1 → 3.8.0-beta.16

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.
@@ -1,7 +1,7 @@
1
1
  import { B as BaseService } from '../BaseService-D-29xShG.cjs';
2
2
  import { c as IService, h as Result } from '../types-DAOyIbXu.cjs';
3
- import { N as NetworkDescriptor, n as EncryptionError, I as InlineEncryptedEnvelope, D as DecryptCapabilityProof, j as DecryptResponseBody, E as EncryptionCrypto, h as DecryptInvocationSigner, p as ReceiverKeySigner, R as ReceiverKeyPair, i as DecryptRequestBody, g as DecryptInvocationFact, B as BuildDecryptInvocationInput, a as BuiltDecryptInvocation } from '../types-B_rbS4XE.cjs';
4
- export { C as CanonicalJson, b as DECRYPT_ACTION, c as DECRYPT_FACT_TYPE, d as DECRYPT_RESULT_TYPE, e as DEFAULT_ENCRYPTION_ALG, f as DEFAULT_KEY_VERSION, k as ENCRYPTION_SERVICE, l as ENCRYPTION_SERVICE_SHORT, m as ENVELOPE_VERSION, o as EncryptionErrorInput, J as Json, q as base64Decode, r as base64Encode, s as canonicalHashHex, t as canonicalize, u as encryptionError, v as hexDecode, w as hexEncode, x as utf8Decode, y as utf8Encode } from '../types-B_rbS4XE.cjs';
3
+ import { N as NetworkDescriptor, n as EncryptionError, I as InlineEncryptedEnvelope, D as DecryptCapabilityProof, j as DecryptResponseBody, E as EncryptionCrypto, h as DecryptInvocationSigner, p as ReceiverKeySigner, R as ReceiverKeyPair, i as DecryptRequestBody, g as DecryptInvocationFact, B as BuildDecryptInvocationInput, a as BuiltDecryptInvocation } from '../types-CBKrdtP8.cjs';
4
+ export { C as CanonicalJson, b as DECRYPT_ACTION, c as DECRYPT_FACT_TYPE, d as DECRYPT_RESULT_TYPE, e as DEFAULT_ENCRYPTION_ALG, f as DEFAULT_KEY_VERSION, k as ENCRYPTION_SERVICE, l as ENCRYPTION_SERVICE_SHORT, m as ENVELOPE_VERSION, o as EncryptionErrorInput, J as Json, q as base64Decode, r as base64Encode, s as canonicalHashHex, t as canonicalize, u as encryptionError, v as hexDecode, w as hexEncode, x as utf8Decode, y as utf8Encode } from '../types-CBKrdtP8.cjs';
5
5
  export { DecryptTransportResponseError } from '@tinycloud/sdk-services/internal/decrypt-transport-response-error';
6
6
 
7
7
  /**
@@ -85,6 +85,8 @@ declare function ensureNetworkUsableForDecrypt(descriptor: NetworkDescriptor): {
85
85
  */
86
86
 
87
87
  interface EncryptToNetworkOptions {
88
+ /** Exact named-key path to bind into the returned envelope. */
89
+ keyPath?: string;
88
90
  /** Optional associated authenticated data (bytes). */
89
91
  aad?: Uint8Array;
90
92
  /** Ciphersuite override. Defaults to the network's alg. */
@@ -217,6 +219,17 @@ declare class NetworkIdError extends Error {
217
219
  * malformed, or when the network name fails {@link NETWORK_NAME_RE}.
218
220
  */
219
221
  declare function parseNetworkId(networkId: string): ParsedNetworkId;
222
+ interface ParsedEncryptionResource extends ParsedNetworkId {
223
+ /** Named-key path, if the resource is scoped below a network. */
224
+ keyPath?: string;
225
+ }
226
+ /**
227
+ * Parse a network-root or named-key encryption resource.
228
+ *
229
+ * A trailing slash on keyPath denotes a prefix grant; empty and traversal
230
+ * segments are rejected so resource matching cannot escape the named path.
231
+ */
232
+ declare function parseEncryptionResource(resource: string): ParsedEncryptionResource;
220
233
  /**
221
234
  * Construct a network id URN from an owner DID and a network name.
222
235
  * Validates inputs and throws {@link NetworkIdError} on bad shape.
@@ -254,6 +267,8 @@ declare const NETWORK_NAME_PATTERN: RegExp;
254
267
  interface EncryptToNetworkInput {
255
268
  /** Target network id URN. */
256
269
  networkId: string;
270
+ /** Exact named-key path; omitted for a network-root key. */
271
+ keyPath?: string;
257
272
  /** Network public key bytes (already discovered). */
258
273
  networkPublicKey: Uint8Array;
259
274
  /** Payload bytes to encrypt. Callers serialize objects to bytes themselves. */
@@ -396,13 +411,10 @@ interface BuildDecryptFactsInput {
396
411
  */
397
412
  declare function buildDecryptFacts(input: BuildDecryptFactsInput): DecryptInvocationFact;
398
413
  /**
399
- * Recap-shaped attenuation for the decrypt invocation. The resource
400
- * key is the networkId URN; the ability is the long-form
401
- * `tinycloud.encryption/decrypt`. This is intentionally distinct from
402
- * the existing space-shaped invocation map so callers cannot
403
- * accidentally fake a space prefix.
414
+ * Attenuate decrypt to the network root for legacy envelopes or to the
415
+ * exact named-key leaf for path-scoped envelopes.
404
416
  */
405
- declare function buildDecryptAttenuation(networkId: string): Record<string, Record<string, Record<string, never>>>;
417
+ declare function buildDecryptAttenuation(networkId: string, keyPath?: string): Record<string, Record<string, Record<string, never>>>;
406
418
  /**
407
419
  * Validate a {@link BuildDecryptInvocationInput} payload — the body
408
420
  * shape, the facts bindings, and the audience contract — without
@@ -484,4 +496,4 @@ declare function verifyDecryptResponse(input: VerifyDecryptResponseInput): {
484
496
  */
485
497
  declare function openWrappedKey(crypto: EncryptionCrypto, receiverPrivateKey: Uint8Array, response: DecryptResponseBody): Uint8Array;
486
498
 
487
- export { type BuildCanonicalDecryptRequestInput, type BuildDecryptFactsInput, BuildDecryptInvocationInput, BuiltDecryptInvocation, type CanonicalDecryptRequest, DecryptCapabilityProof, type DecryptEnvelopeOptions, DecryptInvocationFact, DecryptInvocationSigner, DecryptRequestBody, DecryptResponseBody, type DecryptTransport, type DiscoverNetworkInput, type DiscoveredNetwork, type DiscoverySource, ENCRYPTION_NETWORK_URN_PREFIX, type EncryptToNetworkInput, type EncryptToNetworkOptions, type EncryptToNetworkResult, EncryptionCrypto, EncryptionError, EncryptionService, type EncryptionServiceConfig, type IEncryptionService, InlineEncryptedEnvelope, NETWORK_NAME_PATTERN, NetworkDescriptor, NetworkIdError, type NodeDescriptorFetcher, type ParsedNetworkId, type RandomReceiverKeyInput, ReceiverKeyPair, ReceiverKeySigner, type SignedReceiverKeyInput, type VerifyDecryptResponseInput, type WellKnownDescriptorFetcher, buildCanonicalDecryptRequest, buildDecryptAttenuation, buildDecryptFacts, buildDecryptInvocation, buildNetworkId, canonicalSignedResponse, checkDecryptInvocationInput, decryptEnvelopeWithKey, deriveSignedReceiverKey, discoverNetwork, encryptToNetwork, ensureNetworkUsableForDecrypt, generateRandomReceiverKey, isNetworkId, networkDiscoveryKey, openWrappedKey, parseNetworkId, validateEnvelope, verifyDecryptResponse };
499
+ export { type BuildCanonicalDecryptRequestInput, type BuildDecryptFactsInput, BuildDecryptInvocationInput, BuiltDecryptInvocation, type CanonicalDecryptRequest, DecryptCapabilityProof, type DecryptEnvelopeOptions, DecryptInvocationFact, DecryptInvocationSigner, DecryptRequestBody, DecryptResponseBody, type DecryptTransport, type DiscoverNetworkInput, type DiscoveredNetwork, type DiscoverySource, ENCRYPTION_NETWORK_URN_PREFIX, type EncryptToNetworkInput, type EncryptToNetworkOptions, type EncryptToNetworkResult, EncryptionCrypto, EncryptionError, EncryptionService, type EncryptionServiceConfig, type IEncryptionService, InlineEncryptedEnvelope, NETWORK_NAME_PATTERN, NetworkDescriptor, NetworkIdError, type NodeDescriptorFetcher, type ParsedEncryptionResource, type ParsedNetworkId, type RandomReceiverKeyInput, ReceiverKeyPair, ReceiverKeySigner, type SignedReceiverKeyInput, type VerifyDecryptResponseInput, type WellKnownDescriptorFetcher, buildCanonicalDecryptRequest, buildDecryptAttenuation, buildDecryptFacts, buildDecryptInvocation, buildNetworkId, canonicalSignedResponse, checkDecryptInvocationInput, decryptEnvelopeWithKey, deriveSignedReceiverKey, discoverNetwork, encryptToNetwork, ensureNetworkUsableForDecrypt, generateRandomReceiverKey, isNetworkId, networkDiscoveryKey, openWrappedKey, parseEncryptionResource, parseNetworkId, validateEnvelope, verifyDecryptResponse };
@@ -1,7 +1,7 @@
1
1
  import { B as BaseService } from '../BaseService-DO7vZ67k.js';
2
2
  import { c as IService, h as Result } from '../types-DAOyIbXu.js';
3
- import { N as NetworkDescriptor, n as EncryptionError, I as InlineEncryptedEnvelope, D as DecryptCapabilityProof, j as DecryptResponseBody, E as EncryptionCrypto, h as DecryptInvocationSigner, p as ReceiverKeySigner, R as ReceiverKeyPair, i as DecryptRequestBody, g as DecryptInvocationFact, B as BuildDecryptInvocationInput, a as BuiltDecryptInvocation } from '../types-BGRzS1ob.js';
4
- export { C as CanonicalJson, b as DECRYPT_ACTION, c as DECRYPT_FACT_TYPE, d as DECRYPT_RESULT_TYPE, e as DEFAULT_ENCRYPTION_ALG, f as DEFAULT_KEY_VERSION, k as ENCRYPTION_SERVICE, l as ENCRYPTION_SERVICE_SHORT, m as ENVELOPE_VERSION, o as EncryptionErrorInput, J as Json, q as base64Decode, r as base64Encode, s as canonicalHashHex, t as canonicalize, u as encryptionError, v as hexDecode, w as hexEncode, x as utf8Decode, y as utf8Encode } from '../types-BGRzS1ob.js';
3
+ import { N as NetworkDescriptor, n as EncryptionError, I as InlineEncryptedEnvelope, D as DecryptCapabilityProof, j as DecryptResponseBody, E as EncryptionCrypto, h as DecryptInvocationSigner, p as ReceiverKeySigner, R as ReceiverKeyPair, i as DecryptRequestBody, g as DecryptInvocationFact, B as BuildDecryptInvocationInput, a as BuiltDecryptInvocation } from '../types-DZBExWAf.js';
4
+ export { C as CanonicalJson, b as DECRYPT_ACTION, c as DECRYPT_FACT_TYPE, d as DECRYPT_RESULT_TYPE, e as DEFAULT_ENCRYPTION_ALG, f as DEFAULT_KEY_VERSION, k as ENCRYPTION_SERVICE, l as ENCRYPTION_SERVICE_SHORT, m as ENVELOPE_VERSION, o as EncryptionErrorInput, J as Json, q as base64Decode, r as base64Encode, s as canonicalHashHex, t as canonicalize, u as encryptionError, v as hexDecode, w as hexEncode, x as utf8Decode, y as utf8Encode } from '../types-DZBExWAf.js';
5
5
  export { DecryptTransportResponseError } from '@tinycloud/sdk-services/internal/decrypt-transport-response-error';
6
6
 
7
7
  /**
@@ -85,6 +85,8 @@ declare function ensureNetworkUsableForDecrypt(descriptor: NetworkDescriptor): {
85
85
  */
86
86
 
87
87
  interface EncryptToNetworkOptions {
88
+ /** Exact named-key path to bind into the returned envelope. */
89
+ keyPath?: string;
88
90
  /** Optional associated authenticated data (bytes). */
89
91
  aad?: Uint8Array;
90
92
  /** Ciphersuite override. Defaults to the network's alg. */
@@ -217,6 +219,17 @@ declare class NetworkIdError extends Error {
217
219
  * malformed, or when the network name fails {@link NETWORK_NAME_RE}.
218
220
  */
219
221
  declare function parseNetworkId(networkId: string): ParsedNetworkId;
222
+ interface ParsedEncryptionResource extends ParsedNetworkId {
223
+ /** Named-key path, if the resource is scoped below a network. */
224
+ keyPath?: string;
225
+ }
226
+ /**
227
+ * Parse a network-root or named-key encryption resource.
228
+ *
229
+ * A trailing slash on keyPath denotes a prefix grant; empty and traversal
230
+ * segments are rejected so resource matching cannot escape the named path.
231
+ */
232
+ declare function parseEncryptionResource(resource: string): ParsedEncryptionResource;
220
233
  /**
221
234
  * Construct a network id URN from an owner DID and a network name.
222
235
  * Validates inputs and throws {@link NetworkIdError} on bad shape.
@@ -254,6 +267,8 @@ declare const NETWORK_NAME_PATTERN: RegExp;
254
267
  interface EncryptToNetworkInput {
255
268
  /** Target network id URN. */
256
269
  networkId: string;
270
+ /** Exact named-key path; omitted for a network-root key. */
271
+ keyPath?: string;
257
272
  /** Network public key bytes (already discovered). */
258
273
  networkPublicKey: Uint8Array;
259
274
  /** Payload bytes to encrypt. Callers serialize objects to bytes themselves. */
@@ -396,13 +411,10 @@ interface BuildDecryptFactsInput {
396
411
  */
397
412
  declare function buildDecryptFacts(input: BuildDecryptFactsInput): DecryptInvocationFact;
398
413
  /**
399
- * Recap-shaped attenuation for the decrypt invocation. The resource
400
- * key is the networkId URN; the ability is the long-form
401
- * `tinycloud.encryption/decrypt`. This is intentionally distinct from
402
- * the existing space-shaped invocation map so callers cannot
403
- * accidentally fake a space prefix.
414
+ * Attenuate decrypt to the network root for legacy envelopes or to the
415
+ * exact named-key leaf for path-scoped envelopes.
404
416
  */
405
- declare function buildDecryptAttenuation(networkId: string): Record<string, Record<string, Record<string, never>>>;
417
+ declare function buildDecryptAttenuation(networkId: string, keyPath?: string): Record<string, Record<string, Record<string, never>>>;
406
418
  /**
407
419
  * Validate a {@link BuildDecryptInvocationInput} payload — the body
408
420
  * shape, the facts bindings, and the audience contract — without
@@ -484,4 +496,4 @@ declare function verifyDecryptResponse(input: VerifyDecryptResponseInput): {
484
496
  */
485
497
  declare function openWrappedKey(crypto: EncryptionCrypto, receiverPrivateKey: Uint8Array, response: DecryptResponseBody): Uint8Array;
486
498
 
487
- export { type BuildCanonicalDecryptRequestInput, type BuildDecryptFactsInput, BuildDecryptInvocationInput, BuiltDecryptInvocation, type CanonicalDecryptRequest, DecryptCapabilityProof, type DecryptEnvelopeOptions, DecryptInvocationFact, DecryptInvocationSigner, DecryptRequestBody, DecryptResponseBody, type DecryptTransport, type DiscoverNetworkInput, type DiscoveredNetwork, type DiscoverySource, ENCRYPTION_NETWORK_URN_PREFIX, type EncryptToNetworkInput, type EncryptToNetworkOptions, type EncryptToNetworkResult, EncryptionCrypto, EncryptionError, EncryptionService, type EncryptionServiceConfig, type IEncryptionService, InlineEncryptedEnvelope, NETWORK_NAME_PATTERN, NetworkDescriptor, NetworkIdError, type NodeDescriptorFetcher, type ParsedNetworkId, type RandomReceiverKeyInput, ReceiverKeyPair, ReceiverKeySigner, type SignedReceiverKeyInput, type VerifyDecryptResponseInput, type WellKnownDescriptorFetcher, buildCanonicalDecryptRequest, buildDecryptAttenuation, buildDecryptFacts, buildDecryptInvocation, buildNetworkId, canonicalSignedResponse, checkDecryptInvocationInput, decryptEnvelopeWithKey, deriveSignedReceiverKey, discoverNetwork, encryptToNetwork, ensureNetworkUsableForDecrypt, generateRandomReceiverKey, isNetworkId, networkDiscoveryKey, openWrappedKey, parseNetworkId, validateEnvelope, verifyDecryptResponse };
499
+ export { type BuildCanonicalDecryptRequestInput, type BuildDecryptFactsInput, BuildDecryptInvocationInput, BuiltDecryptInvocation, type CanonicalDecryptRequest, DecryptCapabilityProof, type DecryptEnvelopeOptions, DecryptInvocationFact, DecryptInvocationSigner, DecryptRequestBody, DecryptResponseBody, type DecryptTransport, type DiscoverNetworkInput, type DiscoveredNetwork, type DiscoverySource, ENCRYPTION_NETWORK_URN_PREFIX, type EncryptToNetworkInput, type EncryptToNetworkOptions, type EncryptToNetworkResult, EncryptionCrypto, EncryptionError, EncryptionService, type EncryptionServiceConfig, type IEncryptionService, InlineEncryptedEnvelope, NETWORK_NAME_PATTERN, NetworkDescriptor, NetworkIdError, type NodeDescriptorFetcher, type ParsedEncryptionResource, type ParsedNetworkId, type RandomReceiverKeyInput, ReceiverKeyPair, ReceiverKeySigner, type SignedReceiverKeyInput, type VerifyDecryptResponseInput, type WellKnownDescriptorFetcher, buildCanonicalDecryptRequest, buildDecryptAttenuation, buildDecryptFacts, buildDecryptInvocation, buildNetworkId, canonicalSignedResponse, checkDecryptInvocationInput, decryptEnvelopeWithKey, deriveSignedReceiverKey, discoverNetwork, encryptToNetwork, ensureNetworkUsableForDecrypt, generateRandomReceiverKey, isNetworkId, networkDiscoveryKey, openWrappedKey, parseEncryptionResource, parseNetworkId, validateEnvelope, verifyDecryptResponse };
@@ -135,6 +135,26 @@ function parseNetworkId(networkId) {
135
135
  }
136
136
  return { networkId, ownerDid, name };
137
137
  }
138
+ function parseEncryptionResource(resource) {
139
+ const networkSeparator = resource.lastIndexOf(":");
140
+ const nameAndPath = resource.slice(networkSeparator + 1);
141
+ const pathSeparator = nameAndPath.indexOf("/");
142
+ const name = pathSeparator === -1 ? nameAndPath : nameAndPath.slice(0, pathSeparator);
143
+ const networkId = pathSeparator === -1 ? resource : `${resource.slice(0, networkSeparator + 1)}${name}`;
144
+ const parsed = parseNetworkId(networkId);
145
+ if (pathSeparator === -1) return parsed;
146
+ const keyPath = nameAndPath.slice(pathSeparator + 1);
147
+ const segments = keyPath.split("/");
148
+ const prefix = keyPath.endsWith("/");
149
+ if (keyPath.length === 0 || /[\u0000-\u001f\u007f\\]/.test(keyPath) || segments.some(
150
+ (segment, index) => segment === "." || segment === ".." || segment.length === 0 && !(prefix && index === segments.length - 1)
151
+ )) {
152
+ throw new NetworkIdError(
153
+ `encryption resource has an invalid keyPath (got ${JSON.stringify(resource)})`
154
+ );
155
+ }
156
+ return { ...parsed, keyPath };
157
+ }
138
158
  function buildNetworkId(ownerDid, name) {
139
159
  if (typeof ownerDid !== "string" || !ownerDid.startsWith("did:")) {
140
160
  throw new NetworkIdError("ownerDid must be a DID");
@@ -847,7 +867,12 @@ function ensureNetworkUsableForDecrypt(descriptor) {
847
867
 
848
868
  // src/encryption/envelope.ts
849
869
  function encryptToNetwork(crypto, input) {
850
- parseNetworkId(input.networkId);
870
+ const parsedResource = parseEncryptionResource(
871
+ input.keyPath === void 0 ? input.networkId : `${input.networkId}/${input.keyPath}`
872
+ );
873
+ if (parsedResource.keyPath !== input.keyPath || input.keyPath?.endsWith("/")) {
874
+ throw new NetworkIdError("keyPath must name an exact encryption key");
875
+ }
851
876
  const alg = input.alg ?? DEFAULT_ENCRYPTION_ALG;
852
877
  const keyVersion = input.keyVersion ?? DEFAULT_KEY_VERSION;
853
878
  const symmetricKey = crypto.randomBytes(32);
@@ -861,6 +886,7 @@ function encryptToNetwork(crypto, input) {
861
886
  const envelope = {
862
887
  v: ENVELOPE_VERSION,
863
888
  networkId: input.networkId,
889
+ ...input.keyPath !== void 0 ? { keyPath: input.keyPath } : {},
864
890
  alg,
865
891
  keyVersion,
866
892
  encryptedSymmetricKey,
@@ -892,13 +918,24 @@ function validateEnvelope(crypto, envelope) {
892
918
  };
893
919
  }
894
920
  try {
895
- parseNetworkId(e.networkId);
921
+ if (parseEncryptionResource(e.networkId).keyPath !== void 0) {
922
+ throw new Error("networkId must identify the network root");
923
+ }
924
+ if (e.keyPath !== void 0) {
925
+ if (typeof e.keyPath !== "string") {
926
+ throw new Error("keyPath must be a string");
927
+ }
928
+ const parsed = parseEncryptionResource(`${e.networkId}/${e.keyPath}`);
929
+ if (parsed.keyPath !== e.keyPath || e.keyPath.endsWith("/")) {
930
+ throw new Error("keyPath must name an exact encryption key");
931
+ }
932
+ }
896
933
  } catch (err2) {
897
934
  return {
898
935
  ok: false,
899
936
  error: encryptionError({
900
937
  code: "INVALID_ENVELOPE",
901
- message: `envelope.networkId is malformed: ${err2 instanceof Error ? err2.message : String(err2)}`
938
+ message: `envelope encryption resource is malformed: ${err2 instanceof Error ? err2.message : String(err2)}`
902
939
  })
903
940
  };
904
941
  }
@@ -971,6 +1008,7 @@ function buildDecryptFacts(input) {
971
1008
  type: DECRYPT_FACT_TYPE,
972
1009
  targetNode: input.body.targetNode,
973
1010
  networkId: input.body.networkId,
1011
+ ...input.body.keyPath !== void 0 ? { keyPath: input.body.keyPath } : {},
974
1012
  bodyHash,
975
1013
  encryptedSymmetricKeyHash: input.encryptedSymmetricKeyHash,
976
1014
  receiverPublicKeyHash,
@@ -978,10 +1016,14 @@ function buildDecryptFacts(input) {
978
1016
  keyVersion: input.body.keyVersion
979
1017
  };
980
1018
  }
981
- function buildDecryptAttenuation(networkId) {
982
- parseNetworkId(networkId);
1019
+ function buildDecryptAttenuation(networkId, keyPath) {
1020
+ const resource = keyPath === void 0 ? networkId : `${networkId}/${keyPath}`;
1021
+ const parsed = parseEncryptionResource(resource);
1022
+ if (parsed.networkId !== networkId || parsed.keyPath !== keyPath || keyPath?.endsWith("/")) {
1023
+ throw new NetworkIdError("keyPath must name an exact encryption key");
1024
+ }
983
1025
  return {
984
- [networkId]: {
1026
+ [resource]: {
985
1027
  [DECRYPT_ACTION]: {}
986
1028
  }
987
1029
  };
@@ -1041,6 +1083,15 @@ function checkDecryptInvocationInput(crypto, input) {
1041
1083
  })
1042
1084
  };
1043
1085
  }
1086
+ if (input.facts.keyPath !== input.body.keyPath) {
1087
+ return {
1088
+ ok: false,
1089
+ error: encryptionError({
1090
+ code: "INVALID_INPUT",
1091
+ message: "facts.keyPath must equal body.keyPath"
1092
+ })
1093
+ };
1094
+ }
1044
1095
  if (input.facts.alg !== input.body.alg) {
1045
1096
  return {
1046
1097
  ok: false,
@@ -1078,7 +1129,9 @@ function checkDecryptInvocationInput(crypto, input) {
1078
1129
  };
1079
1130
  }
1080
1131
  try {
1081
- parseNetworkId(input.networkId);
1132
+ if (parseEncryptionResource(input.networkId).keyPath !== void 0) {
1133
+ throw new NetworkIdError("networkId must identify the network root");
1134
+ }
1082
1135
  } catch (err2) {
1083
1136
  return {
1084
1137
  ok: false,
@@ -1088,6 +1141,22 @@ function checkDecryptInvocationInput(crypto, input) {
1088
1141
  })
1089
1142
  };
1090
1143
  }
1144
+ try {
1145
+ const resource = parseEncryptionResource(
1146
+ input.body.keyPath === void 0 ? input.body.networkId : `${input.body.networkId}/${input.body.keyPath}`
1147
+ );
1148
+ if (resource.keyPath !== input.body.keyPath || input.body.keyPath?.endsWith("/")) {
1149
+ throw new NetworkIdError("keyPath must name an exact encryption key");
1150
+ }
1151
+ } catch (err2) {
1152
+ return {
1153
+ ok: false,
1154
+ error: encryptionError({
1155
+ code: "INVALID_INPUT",
1156
+ message: err2 instanceof Error ? err2.message : String(err2)
1157
+ })
1158
+ };
1159
+ }
1091
1160
  const canonicalBody = canonicalize(
1092
1161
  input.body
1093
1162
  );
@@ -1328,6 +1397,7 @@ var EncryptionService = class extends BaseService {
1328
1397
  // that spelling in the envelope so a later response can be compared
1329
1398
  // byte-for-byte (notably for checksummed did:pkh principals).
1330
1399
  networkId: descriptor.networkId,
1400
+ ...options?.keyPath !== void 0 ? { keyPath: options.keyPath } : {},
1331
1401
  networkPublicKey,
1332
1402
  plaintext,
1333
1403
  ...options?.aad !== void 0 ? { aad: options.aad } : {},
@@ -1387,6 +1457,7 @@ var EncryptionService = class extends BaseService {
1387
1457
  type: DECRYPT_FACT_TYPE,
1388
1458
  targetNode,
1389
1459
  networkId: envelope.networkId,
1460
+ ...envelope.keyPath !== void 0 ? { keyPath: envelope.keyPath } : {},
1390
1461
  alg: envelope.alg,
1391
1462
  keyVersion: envelope.keyVersion,
1392
1463
  encryptedSymmetricKey: envelope.encryptedSymmetricKey,
@@ -1530,6 +1601,7 @@ export {
1530
1601
  isNetworkId,
1531
1602
  networkDiscoveryKey,
1532
1603
  openWrappedKey,
1604
+ parseEncryptionResource,
1533
1605
  parseNetworkId,
1534
1606
  utf8Decode,
1535
1607
  utf8Encode,