@tinycloud/sdk-services 3.11.0 → 3.12.0-beta.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.
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 +60 -3
  14. package/dist/encryption/index.cjs.map +1 -1
  15. package/dist/encryption/index.d.cts +12 -22
  16. package/dist/encryption/index.d.ts +12 -22
  17. package/dist/encryption/index.js +60 -3
  18. package/dist/encryption/index.js.map +1 -1
  19. package/dist/encryption/named-keys.cjs +2 -0
  20. package/dist/encryption/named-keys.cjs.map +1 -1
  21. package/dist/encryption/named-keys.d.cts +2 -2
  22. package/dist/encryption/named-keys.d.ts +2 -2
  23. package/dist/encryption/named-keys.js +2 -0
  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 +260 -7
  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 +253 -7
  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 +34 -0
  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 +34 -0
  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-CSd0RYir.d.ts → types-DjAP8dve.d.cts} +4 -0
  68. package/dist/{types-CSd0RYir.d.cts → types-DjAP8dve.d.ts} +4 -0
  69. package/dist/{types-D4XbIfFJ.d.cts → types-XE4tyBLH.d.ts} +60 -3
  70. package/dist/{types-Bf91gup6.d.ts → types-cWtQmCCw.d.cts} +60 -3
  71. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -1,20 +1,20 @@
1
- import { g as ServiceError, f as Result, P as PermissionHint, c as IService, S as ServiceSession, I as IServiceContext, j as StorageQuotaInfo } from './types-CSd0RYir.cjs';
2
- export { k as ErrorCode, l as ErrorCodes, E as EventHandler, F as FetchFunction, d as FetchRequestInit, e as FetchResponse, m as InvocationFact, n as InvocationFacts, o as InvokeAnyEntry, b as InvokeAnyFunction, a as InvokeFunction, R as RetryPolicy, i as RetryStats, p as ServiceErrorEvent, h as ServiceHeaders, q as ServiceRequestEvent, r as ServiceResponseEvent, s as ServiceRetryEvent, T as TelemetryConfig, t as TelemetryEventHandler, u as TelemetryEvents, v as TelemetrySpanEvent, w as defaultRetryPolicy, x as err, y as ok, z as serviceError } from './types-CSd0RYir.cjs';
1
+ import { g as ServiceError, f as Result, P as PermissionHint, c as IService, S as ServiceSession, I as IServiceContext, j as StorageQuotaInfo } from './types-DjAP8dve.cjs';
2
+ export { k as ErrorCode, l as ErrorCodes, E as EventHandler, F as FetchFunction, d as FetchRequestInit, e as FetchResponse, m as InvocationFact, n as InvocationFacts, o as InvokeAnyEntry, b as InvokeAnyFunction, a as InvokeFunction, R as RetryPolicy, i as RetryStats, p as ServiceErrorEvent, h as ServiceHeaders, q as ServiceRequestEvent, r as ServiceResponseEvent, s as ServiceRetryEvent, T as TelemetryConfig, t as TelemetryEventHandler, u as TelemetryEvents, v as TelemetrySpanEvent, w as defaultRetryPolicy, x as err, y as ok, z as serviceError } from './types-DjAP8dve.cjs';
3
3
  import { z } from 'zod';
4
4
  export { ServiceContext, ServiceContextConfig } from './context.cjs';
5
+ import { D as DecryptCapabilityProof, R as RoutingFailure } from './types-cWtQmCCw.cjs';
6
+ export { B as BuildDecryptInvocationInput, a as BuiltDecryptInvocation, 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, g as DecryptInvocationFact, h as DecryptInvocationSigner, i as DecryptRequestBody, j as DecryptResponseBody, k as ENCRYPTION_SERVICE, l as ENCRYPTION_SERVICE_SHORT, m as ENVELOPE_VERSION, E as EncryptionCrypto, n as EncryptionError, o as EncryptionErrorInput, I as InlineEncryptedEnvelope, J as Json, N as NetworkDescriptor, p as NodeIdentityMismatchError, q as NodeNotRespondingError, P as PartialNodeWriteError, r as ReceiverKeyPair, s as ReceiverKeySigner, t as ResourceAccess, u as ResourceDestination, v as ResourceNotRoutedError, w as ResourceRoutingConfig, x as base64Decode, y as base64Encode, z as canonicalHashHex, A as canonicalizeEncryptionJson, F as createResourceRoutingFetch, G as encryptionError, H as hexDecode, K as hexEncode, L as routingFailure, M as utf8Decode, O as utf8Encode, Q as verifyResourceDestination } from './types-cWtQmCCw.cjs';
5
7
  export { RequestEvent, RequestLog, RequestLogReader, RequestService, RequestSink } from './telemetry/requestLog.cjs';
6
- import { B as BaseService } from './BaseService-O0iyuFLk.cjs';
7
- export { a as BaseServiceOptions, R as RequestSignal, S as ServiceConstructor, b as ServiceRegistration } from './BaseService-O0iyuFLk.cjs';
8
+ import { B as BaseService } from './BaseService-CdBkfPGE.cjs';
9
+ export { a as BaseServiceOptions, R as RequestSignal, S as ServiceConstructor, b as ServiceRegistration } from './BaseService-CdBkfPGE.cjs';
8
10
  import { IKVService } from './kv/index.cjs';
9
11
  export { IPrefixedKVService, KVService, PrefixedKVService } from './kv/index.cjs';
10
- export { A as AuthorityRefusal, C as CLEAR_PENDING_WARNING, av as DEFAULT_SIGNED_READ_URL_EXPIRY_MS, aw as KVAction, ax as KVActionType, ay as KVBatchPutItem, az as KVBatchPutOptions, aA as KVBatchPutResponse, aB as KVBatchReadResponse, aC as KVChange, aD as KVChangesAuthority, aE as KVChangesOptions, aF as KVChangesResponse, aG as KVCreateSignedReadUrlOptions, aH as KVDeleteOptions, aI as KVGetOptions, aJ as KVHeadOptions, aK as KVListOptions, b as KVListPage, aL as KVListResponse, aM as KVPutOptions, c as KVReadThrough, d as KVReplicaHandle, e as KVReplicaSpec, f as KVReplicaStorage, a as KVReplicationController, K as KVReplicationDeps, aN as KVResponse, aO as KVResponseHeaders, aP as KVServiceConfig, aQ as KVSignedReadUrlResponse, L as LocalGetResult, g as LocalListResult, h as LocalReadMeta, i as LocalReplicaStatus, j as LocalSyncResult, k as PendingWriteRecord, l as PendingWriteState, P as PendingWriteStore, m as PinnedKey, w as PurgeTarget, x as ReplicaAccountGate, y as ReplicaAdmitHook, z as ReplicaAuthorityState, B as ReplicaBrowserGateAccess, D as ReplicaBrowserGateSnapshot, E as ReplicaBrowserGateTx, F as ReplicaBrowserPageAdmission, G as ReplicaClock, H as ReplicaCoverage, I as ReplicaDeliveryDecision, J as ReplicaDenyInput, M as ReplicaDenyOutcome, N as ReplicaDevice, O as ReplicaEraseReport, Q as ReplicaGateAccess, S as ReplicaGateReason, T as ReplicaGateScope, U as ReplicaGateSnapshot, V as ReplicaGateTx, W as ReplicaGatedError, X as ReplicaGatedHandle, Y as ReplicaGatedSpec, Z as ReplicaGatedStorage, _ as ReplicaGrantInfo, $ as ReplicaGuardedStore, a0 as ReplicaInspectedStatus, a1 as ReplicaLifecycleGate, a2 as ReplicaLocalEraseOutcome, a3 as ReplicaPageAdmission, a4 as ReplicaPartitionEraser, a5 as ReplicaPartitionIndexEntry, a6 as ReplicaPeerCommit, a7 as ReplicaPrivateGateHash, a8 as ReplicaPurgeError, a9 as ReplicaPurgeFailedEvent, aa as ReplicaPurgeIntent, ab as ReplicaPurgeLocalCopyResult, ac as ReplicaPurgeTrigger, ad as ReplicaQuotaLedger, ae as ReplicaQuotaSpec, af as ReplicaSessionStamp, ag as ReplicaStampedReply, ah as ReplicaState, ai as ReplicaStatusEntry, aj as ReplicationAuthority, ak as ReplicationControl, al as ReplicationEvent, R as ReplicationIdentity, am as ReplicationOptions, an as ReplicationPurgeReport, ao as ReplicationReason, ap as ReplicationScheduler, aq as ResolvedReplicationOptions, ar as SaltedHash, as as canonicalReplicationIdentity, at as replicationIdentityKey, au as requiresSecretsOptIn } from './scope-DEgc9f-W.cjs';
12
+ export { A as AuthorityRefusal, C as CLEAR_PENDING_WARNING, av as DEFAULT_SIGNED_READ_URL_EXPIRY_MS, aw as KVAction, ax as KVActionType, ay as KVBatchPutItem, az as KVBatchPutOptions, aA as KVBatchPutResponse, aB as KVBatchReadResponse, aC as KVChange, aD as KVChangesAuthority, aE as KVChangesOptions, aF as KVChangesResponse, aG as KVCreateSignedReadUrlOptions, aH as KVDeleteOptions, aI as KVGetOptions, aJ as KVHeadOptions, aK as KVListOptions, b as KVListPage, aL as KVListResponse, aM as KVPutOptions, c as KVReadThrough, d as KVReplicaHandle, e as KVReplicaSpec, f as KVReplicaStorage, a as KVReplicationController, K as KVReplicationDeps, aN as KVResponse, aO as KVResponseHeaders, aP as KVServiceConfig, aQ as KVSignedReadUrlResponse, L as LocalGetResult, g as LocalListResult, h as LocalReadMeta, i as LocalReplicaStatus, j as LocalSyncResult, k as PendingWriteRecord, l as PendingWriteState, P as PendingWriteStore, m as PinnedKey, w as PurgeTarget, x as ReplicaAccountGate, y as ReplicaAdmitHook, z as ReplicaAuthorityState, B as ReplicaBrowserGateAccess, D as ReplicaBrowserGateSnapshot, E as ReplicaBrowserGateTx, F as ReplicaBrowserPageAdmission, G as ReplicaClock, H as ReplicaCoverage, I as ReplicaDeliveryDecision, J as ReplicaDenyInput, M as ReplicaDenyOutcome, N as ReplicaDevice, O as ReplicaEraseReport, Q as ReplicaGateAccess, S as ReplicaGateReason, T as ReplicaGateScope, U as ReplicaGateSnapshot, V as ReplicaGateTx, W as ReplicaGatedError, X as ReplicaGatedHandle, Y as ReplicaGatedSpec, Z as ReplicaGatedStorage, _ as ReplicaGrantInfo, $ as ReplicaGuardedStore, a0 as ReplicaInspectedStatus, a1 as ReplicaLifecycleGate, a2 as ReplicaLocalEraseOutcome, a3 as ReplicaPageAdmission, a4 as ReplicaPartitionEraser, a5 as ReplicaPartitionIndexEntry, a6 as ReplicaPeerCommit, a7 as ReplicaPrivateGateHash, a8 as ReplicaPurgeError, a9 as ReplicaPurgeFailedEvent, aa as ReplicaPurgeIntent, ab as ReplicaPurgeLocalCopyResult, ac as ReplicaPurgeTrigger, ad as ReplicaQuotaLedger, ae as ReplicaQuotaSpec, af as ReplicaSessionStamp, ag as ReplicaStampedReply, ah as ReplicaState, ai as ReplicaStatusEntry, aj as ReplicationAuthority, ak as ReplicationControl, al as ReplicationEvent, R as ReplicationIdentity, am as ReplicationOptions, an as ReplicationPurgeReport, ao as ReplicationReason, ap as ReplicationScheduler, aq as ResolvedReplicationOptions, ar as SaltedHash, as as canonicalReplicationIdentity, at as replicationIdentityKey, au as requiresSecretsOptIn } from './scope-DtcbyRKY.cjs';
11
13
  export { ClampConsentAnchor, ConsentDeadlineMs, EffectiveGrantExpiry, EffectiveGrantExpiryInput, MintRemainingMs, NeedsSilentRenewal, ReplicaConsentAnchor, ReplicaConsentSource, ReplicaGrantPolicy } from './kv/replication/grantPolicyTypes.cjs';
12
14
  export { DatabaseHandle, SQLMigrations, SQLService } from './sql/index.cjs';
13
- export { B as BatchOptions, a as BatchResponse, E as ExecuteOptions, b as ExecuteResponse, I as IDatabaseHandle, c as ISQLMigrations, d as ISQLService, Q as QueryOptions, e as QueryResponse, S as SQLAction, f as SQLActionType, g as SQLServiceConfig, h as SqlMigration, i as SqlMigrationApplyOptions, j as SqlMigrationApplyResponse, k as SqlStatement, l as SqlValue } from './ISQLService-BOgWzHLT.cjs';
14
- import { I as IHooksService, a as HooksServiceConfig, H as HookSubscription, S as SubscribeOptions, b as HookEvent, c as HookWebhookRegistration, d as HookWebhookRecord, e as HookWebhookListOptions, f as HookWebhookUnregisterOptions } from './IHooksService-4QNODVy6.cjs';
15
- export { g as HookServiceName, h as HookStreamEvent, i as HookStreamRetryConfig, j as HookWebhookScope } from './IHooksService-4QNODVy6.cjs';
16
- import { D as DecryptCapabilityProof } from './types-D4XbIfFJ.cjs';
17
- export { B as BuildDecryptInvocationInput, a as BuiltDecryptInvocation, 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, g as DecryptInvocationFact, h as DecryptInvocationSigner, i as DecryptRequestBody, j as DecryptResponseBody, k as ENCRYPTION_SERVICE, l as ENCRYPTION_SERVICE_SHORT, m as ENVELOPE_VERSION, E as EncryptionCrypto, n as EncryptionError, o as EncryptionErrorInput, I as InlineEncryptedEnvelope, J as Json, N as NetworkDescriptor, R as ReceiverKeyPair, p as ReceiverKeySigner, q as base64Decode, r as base64Encode, s as canonicalHashHex, t as canonicalizeEncryptionJson, u as encryptionError, v as hexDecode, w as hexEncode, x as utf8Decode, y as utf8Encode } from './types-D4XbIfFJ.cjs';
15
+ export { B as BatchOptions, a as BatchResponse, E as ExecuteOptions, b as ExecuteResponse, I as IDatabaseHandle, c as ISQLMigrations, d as ISQLService, Q as QueryOptions, e as QueryResponse, S as SQLAction, f as SQLActionType, g as SQLServiceConfig, h as SqlMigration, i as SqlMigrationApplyOptions, j as SqlMigrationApplyResponse, k as SqlStatement, l as SqlValue } from './ISQLService-C6nNpcls.cjs';
16
+ import { I as IHooksService, a as HooksServiceConfig, H as HookSubscription, S as SubscribeOptions, b as HookEvent, c as HookWebhookRegistration, d as HookWebhookRecord, e as HookWebhookListOptions, f as HookWebhookUnregisterOptions } from './IHooksService-C9p3stsB.cjs';
17
+ export { g as HookServiceName, h as HookStreamEvent, i as HookStreamRetryConfig, j as HookWebhookScope } from './IHooksService-C9p3stsB.cjs';
18
18
  import { IEncryptionService } from './encryption/index.cjs';
19
19
  export { BuildCanonicalDecryptRequestInput, BuildDecryptFactsInput, CanonicalDecryptRequest, DecryptEnvelopeOptions, DecryptTransport, DiscoverNetworkInput, DiscoveredNetwork, DiscoverySource, ENCRYPTION_NETWORK_URN_PREFIX, EncryptToNetworkInput, EncryptToNetworkOptions, EncryptToNetworkResult, EncryptionService, EncryptionServiceConfig, NETWORK_NAME_PATTERN, NetworkIdError, NodeDescriptorFetcher, ParsedEncryptionResource, ParsedNetworkId, RandomReceiverKeyInput, SignedReceiverKeyInput, VerifyDecryptResponseInput, WellKnownDescriptorFetcher, buildCanonicalDecryptRequest, buildDecryptAttenuation, buildDecryptFacts, buildDecryptInvocation, buildNetworkId, canonicalSignedResponse, checkDecryptInvocationInput, decryptEnvelopeWithKey, deriveSignedReceiverKey, discoverNetwork, encryptToNetwork, ensureNetworkUsableForDecrypt, generateRandomReceiverKey, isNetworkId, networkDiscoveryKey, openWrappedKey, parseEncryptionResource, parseNetworkId, validateEnvelope, verifyDecryptResponse } from './encryption/index.cjs';
20
20
  export { DecryptTransportResponseError } from '@tinycloud/sdk-services/internal/decrypt-transport-response-error';
@@ -1804,7 +1804,7 @@ type VaultNetworkReadResult<T> = {
1804
1804
  /**
1805
1805
  * Input types for creating vault errors (service field added automatically).
1806
1806
  */
1807
- type VaultErrorInput = {
1807
+ type VaultErrorInput = RoutingFailure | {
1808
1808
  code: "DECRYPTION_FAILED";
1809
1809
  message?: string;
1810
1810
  cause?: Error;
@@ -1982,7 +1982,7 @@ interface IDataVaultService extends IService {
1982
1982
  * @returns Result with the decrypted entry
1983
1983
  */
1984
1984
  get<T = unknown>(key: string, options?: VaultGetOptions<T>): Promise<Result<VaultEntry<T>, VaultError>>;
1985
- /** Read a network-encrypted value with safe, phase-classified failures. */
1985
+ /** Read with safe failure phases; typed routing failures reject instead of losing their code. */
1986
1986
  readNetworkEncrypted<T = unknown>(key: string, options?: VaultGetOptions<T>): Promise<VaultNetworkReadResult<T>>;
1987
1987
  /**
1988
1988
  * Delete an encrypted key.
@@ -2239,6 +2239,8 @@ declare class DataVaultService extends BaseService implements IDataVaultService
2239
2239
  * Unlike {@link getNetworkEncrypted}, this is intentionally message-free so
2240
2240
  * an operation layer can distinguish an authorized absence from a failed
2241
2241
  * read without receiving node, envelope, plaintext, or key material.
2242
+ * Typed routing failures reject unchanged rather than becoming an ordinary
2243
+ * read/decrypt failure; the operation boundary projects their safe code.
2242
2244
  */
2243
2245
  readNetworkEncrypted<T = unknown>(key: string, options?: VaultGetOptions<T>): Promise<VaultNetworkReadResult<T>>;
2244
2246
  private headNetworkEncrypted;
package/dist/index.d.ts CHANGED
@@ -1,20 +1,20 @@
1
- import { g as ServiceError, f as Result, P as PermissionHint, c as IService, S as ServiceSession, I as IServiceContext, j as StorageQuotaInfo } from './types-CSd0RYir.js';
2
- export { k as ErrorCode, l as ErrorCodes, E as EventHandler, F as FetchFunction, d as FetchRequestInit, e as FetchResponse, m as InvocationFact, n as InvocationFacts, o as InvokeAnyEntry, b as InvokeAnyFunction, a as InvokeFunction, R as RetryPolicy, i as RetryStats, p as ServiceErrorEvent, h as ServiceHeaders, q as ServiceRequestEvent, r as ServiceResponseEvent, s as ServiceRetryEvent, T as TelemetryConfig, t as TelemetryEventHandler, u as TelemetryEvents, v as TelemetrySpanEvent, w as defaultRetryPolicy, x as err, y as ok, z as serviceError } from './types-CSd0RYir.js';
1
+ import { g as ServiceError, f as Result, P as PermissionHint, c as IService, S as ServiceSession, I as IServiceContext, j as StorageQuotaInfo } from './types-DjAP8dve.js';
2
+ export { k as ErrorCode, l as ErrorCodes, E as EventHandler, F as FetchFunction, d as FetchRequestInit, e as FetchResponse, m as InvocationFact, n as InvocationFacts, o as InvokeAnyEntry, b as InvokeAnyFunction, a as InvokeFunction, R as RetryPolicy, i as RetryStats, p as ServiceErrorEvent, h as ServiceHeaders, q as ServiceRequestEvent, r as ServiceResponseEvent, s as ServiceRetryEvent, T as TelemetryConfig, t as TelemetryEventHandler, u as TelemetryEvents, v as TelemetrySpanEvent, w as defaultRetryPolicy, x as err, y as ok, z as serviceError } from './types-DjAP8dve.js';
3
3
  import { z } from 'zod';
4
4
  export { ServiceContext, ServiceContextConfig } from './context.js';
5
+ import { D as DecryptCapabilityProof, R as RoutingFailure } from './types-XE4tyBLH.js';
6
+ export { B as BuildDecryptInvocationInput, a as BuiltDecryptInvocation, 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, g as DecryptInvocationFact, h as DecryptInvocationSigner, i as DecryptRequestBody, j as DecryptResponseBody, k as ENCRYPTION_SERVICE, l as ENCRYPTION_SERVICE_SHORT, m as ENVELOPE_VERSION, E as EncryptionCrypto, n as EncryptionError, o as EncryptionErrorInput, I as InlineEncryptedEnvelope, J as Json, N as NetworkDescriptor, p as NodeIdentityMismatchError, q as NodeNotRespondingError, P as PartialNodeWriteError, r as ReceiverKeyPair, s as ReceiverKeySigner, t as ResourceAccess, u as ResourceDestination, v as ResourceNotRoutedError, w as ResourceRoutingConfig, x as base64Decode, y as base64Encode, z as canonicalHashHex, A as canonicalizeEncryptionJson, F as createResourceRoutingFetch, G as encryptionError, H as hexDecode, K as hexEncode, L as routingFailure, M as utf8Decode, O as utf8Encode, Q as verifyResourceDestination } from './types-XE4tyBLH.js';
5
7
  export { RequestEvent, RequestLog, RequestLogReader, RequestService, RequestSink } from './telemetry/requestLog.js';
6
- import { B as BaseService } from './BaseService-Ma2MwJAd.js';
7
- export { a as BaseServiceOptions, R as RequestSignal, S as ServiceConstructor, b as ServiceRegistration } from './BaseService-Ma2MwJAd.js';
8
+ import { B as BaseService } from './BaseService-BRDG69KR.js';
9
+ export { a as BaseServiceOptions, R as RequestSignal, S as ServiceConstructor, b as ServiceRegistration } from './BaseService-BRDG69KR.js';
8
10
  import { IKVService } from './kv/index.js';
9
11
  export { IPrefixedKVService, KVService, PrefixedKVService } from './kv/index.js';
10
- export { A as AuthorityRefusal, C as CLEAR_PENDING_WARNING, av as DEFAULT_SIGNED_READ_URL_EXPIRY_MS, aw as KVAction, ax as KVActionType, ay as KVBatchPutItem, az as KVBatchPutOptions, aA as KVBatchPutResponse, aB as KVBatchReadResponse, aC as KVChange, aD as KVChangesAuthority, aE as KVChangesOptions, aF as KVChangesResponse, aG as KVCreateSignedReadUrlOptions, aH as KVDeleteOptions, aI as KVGetOptions, aJ as KVHeadOptions, aK as KVListOptions, b as KVListPage, aL as KVListResponse, aM as KVPutOptions, c as KVReadThrough, d as KVReplicaHandle, e as KVReplicaSpec, f as KVReplicaStorage, a as KVReplicationController, K as KVReplicationDeps, aN as KVResponse, aO as KVResponseHeaders, aP as KVServiceConfig, aQ as KVSignedReadUrlResponse, L as LocalGetResult, g as LocalListResult, h as LocalReadMeta, i as LocalReplicaStatus, j as LocalSyncResult, k as PendingWriteRecord, l as PendingWriteState, P as PendingWriteStore, m as PinnedKey, w as PurgeTarget, x as ReplicaAccountGate, y as ReplicaAdmitHook, z as ReplicaAuthorityState, B as ReplicaBrowserGateAccess, D as ReplicaBrowserGateSnapshot, E as ReplicaBrowserGateTx, F as ReplicaBrowserPageAdmission, G as ReplicaClock, H as ReplicaCoverage, I as ReplicaDeliveryDecision, J as ReplicaDenyInput, M as ReplicaDenyOutcome, N as ReplicaDevice, O as ReplicaEraseReport, Q as ReplicaGateAccess, S as ReplicaGateReason, T as ReplicaGateScope, U as ReplicaGateSnapshot, V as ReplicaGateTx, W as ReplicaGatedError, X as ReplicaGatedHandle, Y as ReplicaGatedSpec, Z as ReplicaGatedStorage, _ as ReplicaGrantInfo, $ as ReplicaGuardedStore, a0 as ReplicaInspectedStatus, a1 as ReplicaLifecycleGate, a2 as ReplicaLocalEraseOutcome, a3 as ReplicaPageAdmission, a4 as ReplicaPartitionEraser, a5 as ReplicaPartitionIndexEntry, a6 as ReplicaPeerCommit, a7 as ReplicaPrivateGateHash, a8 as ReplicaPurgeError, a9 as ReplicaPurgeFailedEvent, aa as ReplicaPurgeIntent, ab as ReplicaPurgeLocalCopyResult, ac as ReplicaPurgeTrigger, ad as ReplicaQuotaLedger, ae as ReplicaQuotaSpec, af as ReplicaSessionStamp, ag as ReplicaStampedReply, ah as ReplicaState, ai as ReplicaStatusEntry, aj as ReplicationAuthority, ak as ReplicationControl, al as ReplicationEvent, R as ReplicationIdentity, am as ReplicationOptions, an as ReplicationPurgeReport, ao as ReplicationReason, ap as ReplicationScheduler, aq as ResolvedReplicationOptions, ar as SaltedHash, as as canonicalReplicationIdentity, at as replicationIdentityKey, au as requiresSecretsOptIn } from './scope-BZr0QwxX.js';
12
+ export { A as AuthorityRefusal, C as CLEAR_PENDING_WARNING, av as DEFAULT_SIGNED_READ_URL_EXPIRY_MS, aw as KVAction, ax as KVActionType, ay as KVBatchPutItem, az as KVBatchPutOptions, aA as KVBatchPutResponse, aB as KVBatchReadResponse, aC as KVChange, aD as KVChangesAuthority, aE as KVChangesOptions, aF as KVChangesResponse, aG as KVCreateSignedReadUrlOptions, aH as KVDeleteOptions, aI as KVGetOptions, aJ as KVHeadOptions, aK as KVListOptions, b as KVListPage, aL as KVListResponse, aM as KVPutOptions, c as KVReadThrough, d as KVReplicaHandle, e as KVReplicaSpec, f as KVReplicaStorage, a as KVReplicationController, K as KVReplicationDeps, aN as KVResponse, aO as KVResponseHeaders, aP as KVServiceConfig, aQ as KVSignedReadUrlResponse, L as LocalGetResult, g as LocalListResult, h as LocalReadMeta, i as LocalReplicaStatus, j as LocalSyncResult, k as PendingWriteRecord, l as PendingWriteState, P as PendingWriteStore, m as PinnedKey, w as PurgeTarget, x as ReplicaAccountGate, y as ReplicaAdmitHook, z as ReplicaAuthorityState, B as ReplicaBrowserGateAccess, D as ReplicaBrowserGateSnapshot, E as ReplicaBrowserGateTx, F as ReplicaBrowserPageAdmission, G as ReplicaClock, H as ReplicaCoverage, I as ReplicaDeliveryDecision, J as ReplicaDenyInput, M as ReplicaDenyOutcome, N as ReplicaDevice, O as ReplicaEraseReport, Q as ReplicaGateAccess, S as ReplicaGateReason, T as ReplicaGateScope, U as ReplicaGateSnapshot, V as ReplicaGateTx, W as ReplicaGatedError, X as ReplicaGatedHandle, Y as ReplicaGatedSpec, Z as ReplicaGatedStorage, _ as ReplicaGrantInfo, $ as ReplicaGuardedStore, a0 as ReplicaInspectedStatus, a1 as ReplicaLifecycleGate, a2 as ReplicaLocalEraseOutcome, a3 as ReplicaPageAdmission, a4 as ReplicaPartitionEraser, a5 as ReplicaPartitionIndexEntry, a6 as ReplicaPeerCommit, a7 as ReplicaPrivateGateHash, a8 as ReplicaPurgeError, a9 as ReplicaPurgeFailedEvent, aa as ReplicaPurgeIntent, ab as ReplicaPurgeLocalCopyResult, ac as ReplicaPurgeTrigger, ad as ReplicaQuotaLedger, ae as ReplicaQuotaSpec, af as ReplicaSessionStamp, ag as ReplicaStampedReply, ah as ReplicaState, ai as ReplicaStatusEntry, aj as ReplicationAuthority, ak as ReplicationControl, al as ReplicationEvent, R as ReplicationIdentity, am as ReplicationOptions, an as ReplicationPurgeReport, ao as ReplicationReason, ap as ReplicationScheduler, aq as ResolvedReplicationOptions, ar as SaltedHash, as as canonicalReplicationIdentity, at as replicationIdentityKey, au as requiresSecretsOptIn } from './scope-J20PQP3u.js';
11
13
  export { ClampConsentAnchor, ConsentDeadlineMs, EffectiveGrantExpiry, EffectiveGrantExpiryInput, MintRemainingMs, NeedsSilentRenewal, ReplicaConsentAnchor, ReplicaConsentSource, ReplicaGrantPolicy } from './kv/replication/grantPolicyTypes.js';
12
14
  export { DatabaseHandle, SQLMigrations, SQLService } from './sql/index.js';
13
- export { B as BatchOptions, a as BatchResponse, E as ExecuteOptions, b as ExecuteResponse, I as IDatabaseHandle, c as ISQLMigrations, d as ISQLService, Q as QueryOptions, e as QueryResponse, S as SQLAction, f as SQLActionType, g as SQLServiceConfig, h as SqlMigration, i as SqlMigrationApplyOptions, j as SqlMigrationApplyResponse, k as SqlStatement, l as SqlValue } from './ISQLService-Aly1CBsW.js';
14
- import { I as IHooksService, a as HooksServiceConfig, H as HookSubscription, S as SubscribeOptions, b as HookEvent, c as HookWebhookRegistration, d as HookWebhookRecord, e as HookWebhookListOptions, f as HookWebhookUnregisterOptions } from './IHooksService-CvTpJbQD.js';
15
- export { g as HookServiceName, h as HookStreamEvent, i as HookStreamRetryConfig, j as HookWebhookScope } from './IHooksService-CvTpJbQD.js';
16
- import { D as DecryptCapabilityProof } from './types-Bf91gup6.js';
17
- export { B as BuildDecryptInvocationInput, a as BuiltDecryptInvocation, 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, g as DecryptInvocationFact, h as DecryptInvocationSigner, i as DecryptRequestBody, j as DecryptResponseBody, k as ENCRYPTION_SERVICE, l as ENCRYPTION_SERVICE_SHORT, m as ENVELOPE_VERSION, E as EncryptionCrypto, n as EncryptionError, o as EncryptionErrorInput, I as InlineEncryptedEnvelope, J as Json, N as NetworkDescriptor, R as ReceiverKeyPair, p as ReceiverKeySigner, q as base64Decode, r as base64Encode, s as canonicalHashHex, t as canonicalizeEncryptionJson, u as encryptionError, v as hexDecode, w as hexEncode, x as utf8Decode, y as utf8Encode } from './types-Bf91gup6.js';
15
+ export { B as BatchOptions, a as BatchResponse, E as ExecuteOptions, b as ExecuteResponse, I as IDatabaseHandle, c as ISQLMigrations, d as ISQLService, Q as QueryOptions, e as QueryResponse, S as SQLAction, f as SQLActionType, g as SQLServiceConfig, h as SqlMigration, i as SqlMigrationApplyOptions, j as SqlMigrationApplyResponse, k as SqlStatement, l as SqlValue } from './ISQLService-B_4KcGA-.js';
16
+ import { I as IHooksService, a as HooksServiceConfig, H as HookSubscription, S as SubscribeOptions, b as HookEvent, c as HookWebhookRegistration, d as HookWebhookRecord, e as HookWebhookListOptions, f as HookWebhookUnregisterOptions } from './IHooksService-D6eyZat1.js';
17
+ export { g as HookServiceName, h as HookStreamEvent, i as HookStreamRetryConfig, j as HookWebhookScope } from './IHooksService-D6eyZat1.js';
18
18
  import { IEncryptionService } from './encryption/index.js';
19
19
  export { BuildCanonicalDecryptRequestInput, BuildDecryptFactsInput, CanonicalDecryptRequest, DecryptEnvelopeOptions, DecryptTransport, DiscoverNetworkInput, DiscoveredNetwork, DiscoverySource, ENCRYPTION_NETWORK_URN_PREFIX, EncryptToNetworkInput, EncryptToNetworkOptions, EncryptToNetworkResult, EncryptionService, EncryptionServiceConfig, NETWORK_NAME_PATTERN, NetworkIdError, NodeDescriptorFetcher, ParsedEncryptionResource, ParsedNetworkId, RandomReceiverKeyInput, SignedReceiverKeyInput, VerifyDecryptResponseInput, WellKnownDescriptorFetcher, buildCanonicalDecryptRequest, buildDecryptAttenuation, buildDecryptFacts, buildDecryptInvocation, buildNetworkId, canonicalSignedResponse, checkDecryptInvocationInput, decryptEnvelopeWithKey, deriveSignedReceiverKey, discoverNetwork, encryptToNetwork, ensureNetworkUsableForDecrypt, generateRandomReceiverKey, isNetworkId, networkDiscoveryKey, openWrappedKey, parseEncryptionResource, parseNetworkId, validateEnvelope, verifyDecryptResponse } from './encryption/index.js';
20
20
  export { DecryptTransportResponseError } from '@tinycloud/sdk-services/internal/decrypt-transport-response-error';
@@ -1804,7 +1804,7 @@ type VaultNetworkReadResult<T> = {
1804
1804
  /**
1805
1805
  * Input types for creating vault errors (service field added automatically).
1806
1806
  */
1807
- type VaultErrorInput = {
1807
+ type VaultErrorInput = RoutingFailure | {
1808
1808
  code: "DECRYPTION_FAILED";
1809
1809
  message?: string;
1810
1810
  cause?: Error;
@@ -1982,7 +1982,7 @@ interface IDataVaultService extends IService {
1982
1982
  * @returns Result with the decrypted entry
1983
1983
  */
1984
1984
  get<T = unknown>(key: string, options?: VaultGetOptions<T>): Promise<Result<VaultEntry<T>, VaultError>>;
1985
- /** Read a network-encrypted value with safe, phase-classified failures. */
1985
+ /** Read with safe failure phases; typed routing failures reject instead of losing their code. */
1986
1986
  readNetworkEncrypted<T = unknown>(key: string, options?: VaultGetOptions<T>): Promise<VaultNetworkReadResult<T>>;
1987
1987
  /**
1988
1988
  * Delete an encrypted key.
@@ -2239,6 +2239,8 @@ declare class DataVaultService extends BaseService implements IDataVaultService
2239
2239
  * Unlike {@link getNetworkEncrypted}, this is intentionally message-free so
2240
2240
  * an operation layer can distinguish an authorized absence from a failed
2241
2241
  * read without receiving node, envelope, plaintext, or key material.
2242
+ * Typed routing failures reject unchanged rather than becoming an ordinary
2243
+ * read/decrypt failure; the operation boundary projects their safe code.
2242
2244
  */
2243
2245
  readNetworkEncrypted<T = unknown>(key: string, options?: VaultGetOptions<T>): Promise<VaultNetworkReadResult<T>>;
2244
2246
  private headNetworkEncrypted;
package/dist/index.js CHANGED
@@ -10,6 +10,10 @@ var ErrorCodes = {
10
10
  /** HTTP 401: a delegation the cited one rests on was revoked. */
11
11
  AUTH_DELEGATION_ANCESTOR_REVOKED: "AUTH_DELEGATION_ANCESTOR_REVOKED",
12
12
  NETWORK_ERROR: "NETWORK_ERROR",
13
+ NODE_NOT_RESPONDING: "NODE_NOT_RESPONDING",
14
+ NODE_IDENTITY_MISMATCH: "NODE_IDENTITY_MISMATCH",
15
+ PARTIAL_NODE_WRITE: "PARTIAL_NODE_WRITE",
16
+ RESOURCE_NOT_ROUTED: "RESOURCE_NOT_ROUTED",
13
17
  TIMEOUT: "TIMEOUT",
14
18
  ABORTED: "ABORTED",
15
19
  INVALID_INPUT: "INVALID_INPUT",
@@ -784,6 +788,196 @@ function networkDiscoveryKey(name) {
784
788
  var ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;
785
789
  var NETWORK_NAME_PATTERN = NETWORK_NAME_RE;
786
790
 
791
+ // src/resourceRouting.ts
792
+ async function verifyResourceDestination(target, fetchFn) {
793
+ if (!target.nodeDid) return;
794
+ let info;
795
+ let keys;
796
+ try {
797
+ const signal = AbortSignal.timeout(5e3);
798
+ const responses = await Promise.all([
799
+ fetchFn(`${target.url}/info`, { signal, redirect: "error" }),
800
+ fetchFn(`${target.url}/.well-known/tinycloud/node-keys`, { signal, redirect: "error" })
801
+ ]);
802
+ if (responses.some((response) => response.status >= 500)) throw new NodeNotRespondingError([target.url]);
803
+ if (responses.some((response) => !response.ok)) throw new NodeIdentityMismatchError(target.url, target.nodeDid);
804
+ try {
805
+ [info, keys] = await Promise.all(responses.map((response) => response.json()));
806
+ } catch {
807
+ throw new NodeIdentityMismatchError(target.url, target.nodeDid);
808
+ }
809
+ } catch (error) {
810
+ if (error instanceof NodeIdentityMismatchError || error instanceof NodeNotRespondingError) throw error;
811
+ throw new NodeNotRespondingError([target.url], error);
812
+ }
813
+ const infoDid = typeof info === "object" && info !== null && "nodeId" in info && typeof info.nodeId === "string" ? info.nodeId : void 0;
814
+ const keysDid = typeof keys === "object" && keys !== null && "nodeDid" in keys && typeof keys.nodeDid === "string" ? keys.nodeDid : void 0;
815
+ if (infoDid !== target.nodeDid || keysDid !== target.nodeDid) {
816
+ throw new NodeIdentityMismatchError(target.url, target.nodeDid, infoDid !== target.nodeDid ? infoDid : keysDid);
817
+ }
818
+ }
819
+ var NodeNotRespondingError = class extends Error {
820
+ constructor(hosts, cause) {
821
+ super("The place your data is stored isn't responding right now. Please try again.");
822
+ this.hosts = hosts;
823
+ this.cause = cause;
824
+ this.code = "NODE_NOT_RESPONDING";
825
+ this.name = "NodeNotRespondingError";
826
+ }
827
+ };
828
+ var NodeIdentityMismatchError = class extends Error {
829
+ constructor(url, expectedDid, actualDid) {
830
+ super(`TinyCloud node identity does not match the registry at ${url}`);
831
+ this.url = url;
832
+ this.expectedDid = expectedDid;
833
+ this.actualDid = actualDid;
834
+ this.code = "NODE_IDENTITY_MISMATCH";
835
+ this.name = "NodeIdentityMismatchError";
836
+ }
837
+ };
838
+ var ResourceNotRoutedError = class extends Error {
839
+ constructor(resource) {
840
+ super(`No registered destination can serve ${resource}`);
841
+ this.resource = resource;
842
+ this.code = "RESOURCE_NOT_ROUTED";
843
+ this.name = "ResourceNotRoutedError";
844
+ }
845
+ };
846
+ var PartialNodeWriteError = class extends Error {
847
+ constructor(succeeded, failed) {
848
+ super("The write did not complete on every registered writable node.");
849
+ this.succeeded = succeeded;
850
+ this.failed = failed;
851
+ this.code = "PARTIAL_NODE_WRITE";
852
+ this.name = "PartialNodeWriteError";
853
+ }
854
+ };
855
+ var ROUTING_FAILURE_CODES = {
856
+ NODE_NOT_RESPONDING: true,
857
+ PARTIAL_NODE_WRITE: true,
858
+ NODE_IDENTITY_MISMATCH: true,
859
+ RESOURCE_NOT_ROUTED: true,
860
+ DECRYPTION_DEPENDENCY_UNAVAILABLE: true,
861
+ registry_unavailable: true,
862
+ node_not_found: true,
863
+ node_registry_entry_exists: true
864
+ };
865
+ function isRoutingFailureCode(code) {
866
+ return Object.prototype.hasOwnProperty.call(ROUTING_FAILURE_CODES, code);
867
+ }
868
+ function routingFailure(error) {
869
+ if (typeof error === "object" && error !== null && "code" in error && "message" in error && typeof error.code === "string" && typeof error.message === "string" && isRoutingFailureCode(error.code)) {
870
+ const candidate = "meta" in error ? error.meta : void 0;
871
+ let meta = typeof candidate === "object" && candidate !== null && !Array.isArray(candidate) ? candidate : void 0;
872
+ if (error.code === "NODE_NOT_RESPONDING" && "hosts" in error && Array.isArray(error.hosts)) {
873
+ meta = { ...meta, hosts: error.hosts };
874
+ } else if (error.code === "PARTIAL_NODE_WRITE" && "succeeded" in error && Array.isArray(error.succeeded) && "failed" in error && Array.isArray(error.failed)) {
875
+ meta = { ...meta, succeeded: error.succeeded, failed: error.failed };
876
+ }
877
+ return { code: error.code, message: error.message, ...error instanceof Error ? { cause: error } : {}, ...meta ? { meta } : {} };
878
+ }
879
+ return void 0;
880
+ }
881
+ function authorizationOf(headers) {
882
+ if (headers === void 0) return void 0;
883
+ return (Array.isArray(headers) ? headers : Object.entries(headers)).find(([name]) => name.toLowerCase() === "authorization")?.[1];
884
+ }
885
+ function invocationResources(authorization) {
886
+ const encoded = authorization.split(".")[1];
887
+ if (!encoded) throw new ResourceNotRoutedError("invalid invocation");
888
+ const payload = JSON.parse(atob(encoded.replace(/-/g, "+").replace(/_/g, "/")));
889
+ if (typeof payload !== "object" || payload === null || !("att" in payload) || typeof payload.att !== "object" || payload.att === null || Array.isArray(payload.att)) {
890
+ throw new ResourceNotRoutedError("invalid invocation attenuation");
891
+ }
892
+ const resources = [];
893
+ for (const [uri, abilities] of Object.entries(payload.att)) {
894
+ if (typeof abilities !== "object" || abilities === null || Array.isArray(abilities)) throw new ResourceNotRoutedError(uri);
895
+ for (const action of Object.keys(abilities)) {
896
+ const resource = uri.startsWith("tinycloud:") ? uri.split("/")[0] : uri;
897
+ if (!resource.startsWith("tinycloud:") && !resource.startsWith("urn:tinycloud:encryption:")) throw new ResourceNotRoutedError(uri);
898
+ const read2 = /^(tinycloud\.(kv\/(get|list|metadata|head|sync)|sql\/(read|export)|duckdb\/(read|describe|export)|capabilities\/read|space\/(list|info)|hooks\/list))$/.test(action);
899
+ const access = resource.startsWith("urn:tinycloud:encryption:") ? "encryption" : action === "tinycloud.space/host" ? "host" : read2 ? "read" : "write";
900
+ if (!resources.some((entry) => entry.resource === resource && entry.access === access)) resources.push({ resource, access });
901
+ }
902
+ }
903
+ if (resources.length === 0) throw new ResourceNotRoutedError("empty invocation");
904
+ return resources;
905
+ }
906
+ function createResourceRoutingFetch(fetchFn, routing) {
907
+ return async (url, init) => {
908
+ const parsed = new URL(url);
909
+ if (parsed.pathname !== "/invoke") return fetchFn(url, init);
910
+ const authorization = authorizationOf(init?.headers);
911
+ if (!authorization) throw new ResourceNotRoutedError("unsigned invocation");
912
+ const resources = invocationResources(authorization);
913
+ const routes = await Promise.all(resources.map(({ resource, access }) => routing.resolveResource(resource, access)));
914
+ if (routes.some((route) => route.length === 0)) throw new ResourceNotRoutedError(resources[routes.findIndex((route) => route.length === 0)].resource);
915
+ const write = resources.some(({ access }) => access === "write" || access === "host");
916
+ let targets = routes[0].filter((target) => routes.every((route) => route.some((other) => other.url === target.url && other.nodeDid === target.nodeDid)));
917
+ if (targets.length === 0 || write && routes.some((route) => route.length !== targets.length)) throw new ResourceNotRoutedError(resources.map(({ resource }) => resource).join(", "));
918
+ targets = targets.filter((target, index) => targets.findIndex((other) => other.url === target.url) === index);
919
+ const send = async (target) => {
920
+ init?.signal?.throwIfAborted();
921
+ if (routing.verifyDestination) await routing.verifyDestination(target);
922
+ else await verifyResourceDestination(target, fetchFn);
923
+ const signed = target.nodeDid ? await routing.bindAudience(authorization, target.nodeDid) : authorization;
924
+ const headers = (Array.isArray(init?.headers) ? init.headers : Object.entries(init?.headers ?? {})).filter(([name]) => name.toLowerCase() !== "authorization");
925
+ headers.push(["Authorization", signed]);
926
+ const timeout = AbortSignal.timeout(5e3);
927
+ const signal = init?.signal ? AbortSignal.any([init.signal, timeout]) : timeout;
928
+ try {
929
+ return await fetchFn(`${target.url}${parsed.pathname}${parsed.search}`, { ...init, headers, signal, redirect: "error" });
930
+ } catch (error) {
931
+ if (init?.signal?.aborted) throw error;
932
+ if (routingFailure(error)) throw error;
933
+ throw new NodeNotRespondingError([target.url], error);
934
+ }
935
+ };
936
+ if (!write) {
937
+ let response2;
938
+ let failure;
939
+ for (const target of targets) {
940
+ try {
941
+ response2 = await send(target);
942
+ if (response2.ok || response2.status !== 404) return response2;
943
+ } catch (error) {
944
+ if (!(error instanceof NodeNotRespondingError)) throw error;
945
+ failure = error;
946
+ }
947
+ }
948
+ if (failure) throw new NodeNotRespondingError(targets.map(({ url: url2 }) => url2), failure);
949
+ if (response2) return response2;
950
+ throw new NodeNotRespondingError(targets.map(({ url: url2 }) => url2), failure);
951
+ }
952
+ const succeeded = [];
953
+ const failed = [];
954
+ let response;
955
+ let failureResponse;
956
+ for (const target of targets) {
957
+ try {
958
+ const result = await send(target);
959
+ if (result.ok) {
960
+ succeeded.push(target.url);
961
+ response ?? (response = result);
962
+ } else {
963
+ failed.push({ url: target.url, status: result.status });
964
+ failureResponse ?? (failureResponse = result);
965
+ }
966
+ } catch (error) {
967
+ if (!routingFailure(error) && succeeded.length === 0) throw error;
968
+ failed.push({ url: target.url, cause: error });
969
+ }
970
+ }
971
+ if (failed.length > 0) {
972
+ if (succeeded.length > 0 || targets.length > 1) throw new PartialNodeWriteError(succeeded, failed);
973
+ if (failureResponse) return failureResponse;
974
+ if (failed[0]?.cause && !(failed[0].cause instanceof NodeNotRespondingError)) throw failed[0].cause;
975
+ throw new NodeNotRespondingError(targets.map(({ url: url2 }) => url2), failed[0]?.cause);
976
+ }
977
+ return response;
978
+ };
979
+ }
980
+
787
981
  // src/errors.ts
788
982
  function parsePermissionHint(value) {
789
983
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -1089,6 +1283,8 @@ function isStorageFullError(error) {
1089
1283
  return error?.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error?.code === ErrorCodes.STORAGE_LIMIT_REACHED;
1090
1284
  }
1091
1285
  function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
1286
+ const routing = routingFailure(error);
1287
+ if (routing) return { ...routing, service };
1092
1288
  if (error instanceof Error) {
1093
1289
  if (isRequestTimeoutError(error)) {
1094
1290
  return timeoutError(service, error.timeoutMs, error);
@@ -6030,6 +6226,8 @@ function defaultVaultMessage(input) {
6030
6226
  case "STORAGE_QUOTA_EXCEEDED":
6031
6227
  case "STORAGE_LIMIT_REACHED":
6032
6228
  return input.message;
6229
+ default:
6230
+ return input.message ?? input.code;
6033
6231
  }
6034
6232
  }
6035
6233
  function vaultError(input) {
@@ -6081,6 +6279,8 @@ function ifMatchWriteError(key, error) {
6081
6279
  });
6082
6280
  }
6083
6281
  function kvWriteError(context, error) {
6282
+ const routing = routingFailure(error);
6283
+ if (routing) return vaultError(routing);
6084
6284
  if (error.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error.code === ErrorCodes.STORAGE_LIMIT_REACHED) {
6085
6285
  return vaultError({ code: error.code, message: error.message, meta: error.meta });
6086
6286
  }
@@ -6387,6 +6587,8 @@ var DataVaultService = class extends BaseService {
6387
6587
  { aad, metadata }
6388
6588
  );
6389
6589
  if (!envelopeResult.ok) {
6590
+ const routing = routingFailure(envelopeResult.error);
6591
+ if (routing) return vaultError(routing);
6390
6592
  return vaultError({
6391
6593
  code: "STORAGE_ERROR",
6392
6594
  cause: new Error(envelopeResult.error.message)
@@ -6413,6 +6615,8 @@ var DataVaultService = class extends BaseService {
6413
6615
  }
6414
6616
  return { ok: true, data: void 0 };
6415
6617
  } catch (error) {
6618
+ const routing = routingFailure(error);
6619
+ if (routing) return vaultError(routing);
6416
6620
  return vaultError({
6417
6621
  code: "STORAGE_ERROR",
6418
6622
  cause: toError(error)
@@ -6439,6 +6643,8 @@ var DataVaultService = class extends BaseService {
6439
6643
  ...options?.source === void 0 ? {} : { source: options.source }
6440
6644
  });
6441
6645
  if (!valueResult.ok) {
6646
+ const routing = routingFailure(valueResult.error);
6647
+ if (routing) return vaultError(routing);
6442
6648
  return vaultError({ code: "KEY_NOT_FOUND", key });
6443
6649
  }
6444
6650
  const rawEnvelope = unwrapKVData(valueResult.data);
@@ -6459,6 +6665,8 @@ var DataVaultService = class extends BaseService {
6459
6665
  const proof = await this.decryptCapabilityProof();
6460
6666
  const plaintextResult = await config.service.decryptEnvelope(envelope, proof);
6461
6667
  if (!plaintextResult.ok) {
6668
+ const routing = routingFailure(plaintextResult.error);
6669
+ if (routing) return vaultError(routing);
6462
6670
  return vaultError({
6463
6671
  code: "DECRYPTION_FAILED",
6464
6672
  message: plaintextResult.error.message
@@ -6478,6 +6686,8 @@ var DataVaultService = class extends BaseService {
6478
6686
  data: { value, metadata, keyId, ...etag === void 0 ? {} : { etag } }
6479
6687
  };
6480
6688
  } catch (error) {
6689
+ const routing = routingFailure(error);
6690
+ if (routing) return vaultError(routing);
6481
6691
  return vaultError({
6482
6692
  code: "STORAGE_ERROR",
6483
6693
  cause: toError(error)
@@ -6490,6 +6700,8 @@ var DataVaultService = class extends BaseService {
6490
6700
  * Unlike {@link getNetworkEncrypted}, this is intentionally message-free so
6491
6701
  * an operation layer can distinguish an authorized absence from a failed
6492
6702
  * read without receiving node, envelope, plaintext, or key material.
6703
+ * Typed routing failures reject unchanged rather than becoming an ordinary
6704
+ * read/decrypt failure; the operation boundary projects their safe code.
6493
6705
  */
6494
6706
  async readNetworkEncrypted(key, options) {
6495
6707
  const config = this.networkEncryption;
@@ -6499,10 +6711,12 @@ var DataVaultService = class extends BaseService {
6499
6711
  let valueResult;
6500
6712
  try {
6501
6713
  valueResult = await this.tc.kv.get(`vault/${key}`, { raw: true, source: "network" });
6502
- } catch {
6714
+ } catch (error) {
6715
+ if (routingFailure(error)) throw error;
6503
6716
  return { status: "node_unreachable" };
6504
6717
  }
6505
6718
  if (!valueResult.ok) {
6719
+ if (routingFailure(valueResult.error)) throw valueResult.error;
6506
6720
  const permissionHint = parsePermissionHint(valueResult.error.meta?.permissionHint);
6507
6721
  if (valueResult.error.code === "AUTH_UNAUTHORIZED" && permissionHint !== void 0) {
6508
6722
  return { status: "permission_required", hint: permissionHint };
@@ -6510,7 +6724,7 @@ var DataVaultService = class extends BaseService {
6510
6724
  if ((valueResult.error.code === "NOT_FOUND" || valueResult.error.code === "KV_NOT_FOUND") && !hasHttpResponse(valueResult.error)) {
6511
6725
  return { status: "not_found" };
6512
6726
  }
6513
- if (valueResult.error.code === "NETWORK_ERROR" || valueResult.error.code === "TIMEOUT" || valueResult.error.code === "ABORTED") {
6727
+ if (valueResult.error.code === "NODE_NOT_RESPONDING" || valueResult.error.code === "NETWORK_ERROR" || valueResult.error.code === "TIMEOUT" || valueResult.error.code === "ABORTED") {
6514
6728
  return hasHttpResponse(valueResult.error) ? { status: "read_failed" } : { status: "node_unreachable" };
6515
6729
  }
6516
6730
  return { status: "read_failed" };
@@ -6532,10 +6746,12 @@ var DataVaultService = class extends BaseService {
6532
6746
  try {
6533
6747
  const proof = await this.decryptCapabilityProof();
6534
6748
  plaintextResult = await config.service.decryptEnvelope(envelope, proof);
6535
- } catch {
6749
+ } catch (error) {
6750
+ if (routingFailure(error)) throw error;
6536
6751
  return { status: "decrypt_failed" };
6537
6752
  }
6538
6753
  if (!plaintextResult.ok) {
6754
+ if (routingFailure(plaintextResult.error)) throw plaintextResult.error;
6539
6755
  const permissionHint = parsePermissionHint(
6540
6756
  plaintextResult.error.permissionHint
6541
6757
  );
@@ -6545,7 +6761,7 @@ var DataVaultService = class extends BaseService {
6545
6761
  if (plaintextResult.error.code === "INVALID_ENVELOPE") {
6546
6762
  return { status: "corrupt_envelope" };
6547
6763
  }
6548
- if (plaintextResult.error.code === "TRANSPORT_ERROR") {
6764
+ if (plaintextResult.error.code === "NODE_NOT_RESPONDING" || plaintextResult.error.code === "TRANSPORT_ERROR") {
6549
6765
  return { status: "node_unreachable" };
6550
6766
  }
6551
6767
  return { status: "decrypt_failed" };
@@ -7702,6 +7918,8 @@ function defaultEncryptionMessage(input) {
7702
7918
  return input.message ?? input.cause.message;
7703
7919
  case "INVALID_INPUT":
7704
7920
  return input.message;
7921
+ default:
7922
+ return input.message ?? input.code;
7705
7923
  }
7706
7924
  }
7707
7925
  function encryptionError(input) {
@@ -7766,6 +7984,8 @@ async function discoverNetwork(input) {
7766
7984
  return { ok: true, data: { descriptor: validated.data, source: "node" } };
7767
7985
  }
7768
7986
  } catch (err3) {
7987
+ const routing = routingFailure(err3);
7988
+ if (routing) return { ok: false, error: encryptionError(routing) };
7769
7989
  }
7770
7990
  }
7771
7991
  if (input.wellKnown !== void 0) {
@@ -7783,6 +8003,8 @@ async function discoverNetwork(input) {
7783
8003
  };
7784
8004
  }
7785
8005
  } catch (err3) {
8006
+ const routing = routingFailure(err3);
8007
+ if (routing) return { ok: false, error: encryptionError(routing) };
7786
8008
  }
7787
8009
  }
7788
8010
  return {
@@ -8367,6 +8589,14 @@ function encOk(data) {
8367
8589
  function encErr(error) {
8368
8590
  return { ok: false, error };
8369
8591
  }
8592
+ function decryptionError(input) {
8593
+ const unavailable = input.code === "NODE_NOT_RESPONDING" || input.code === "TRANSPORT_ERROR" && input.cause.name !== "AbortError";
8594
+ return encryptionError(unavailable ? {
8595
+ ...input,
8596
+ code: "DECRYPTION_DEPENDENCY_UNAVAILABLE",
8597
+ message: "The decryption service isn't responding right now. Please try again."
8598
+ } : input);
8599
+ }
8370
8600
  var EncryptionService = class extends BaseService {
8371
8601
  constructor(config) {
8372
8602
  super();
@@ -8414,6 +8644,8 @@ var EncryptionService = class extends BaseService {
8414
8644
  });
8415
8645
  return encOk(result.envelope);
8416
8646
  } catch (error) {
8647
+ const routing = routingFailure(error);
8648
+ if (routing) return encErr(encryptionError(routing));
8417
8649
  return encErr(
8418
8650
  encryptionError({
8419
8651
  code: "TRANSPORT_ERROR",
@@ -8440,12 +8672,12 @@ var EncryptionService = class extends BaseService {
8440
8672
  descriptor = options.descriptor;
8441
8673
  } else {
8442
8674
  const discovered = await this.discoverNetwork(envelope.networkId);
8443
- if (!discovered.ok) return discovered;
8675
+ if (!discovered.ok) return encErr(decryptionError(discovered.error));
8444
8676
  descriptor = discovered.data;
8445
8677
  }
8446
8678
  const usable = ensureNetworkUsableForDecrypt(descriptor);
8447
8679
  if (!usable.ok) return usable;
8448
- const targetNode = options?.targetNode ?? descriptor.members[0]?.nodeId;
8680
+ const targetNode = this._config.resolveTargetNode ? await this._config.resolveTargetNode(envelope.networkId) : options?.targetNode ?? descriptor.members[0]?.nodeId;
8449
8681
  if (targetNode === void 0) {
8450
8682
  return encErr(
8451
8683
  encryptionError({
@@ -8454,6 +8686,9 @@ var EncryptionService = class extends BaseService {
8454
8686
  })
8455
8687
  );
8456
8688
  }
8689
+ if (this._config.resolveTargetNode && (options?.targetNode !== void 0 && options.targetNode !== targetNode || !descriptor.members.some((member) => member.nodeId === targetNode))) {
8690
+ return encErr(encryptionError({ code: "INVALID_INPUT", message: "Encryption destination does not match the registry" }));
8691
+ }
8457
8692
  const receiverKey = generateRandomReceiverKey({ crypto: this.crypto });
8458
8693
  const receiverPublicKey = base64Encode(receiverKey.publicKey);
8459
8694
  const receiverPublicKeyHash = canonicalHashHex(
@@ -8512,6 +8747,8 @@ var EncryptionService = class extends BaseService {
8512
8747
  });
8513
8748
  this.assertActive();
8514
8749
  } catch (error) {
8750
+ const routing = routingFailure(error);
8751
+ if (routing) return encErr(decryptionError(routing));
8515
8752
  if (error instanceof DecryptTransportResponseError) {
8516
8753
  return encErr(
8517
8754
  encryptionError(
@@ -8528,7 +8765,7 @@ var EncryptionService = class extends BaseService {
8528
8765
  );
8529
8766
  }
8530
8767
  return encErr(
8531
- encryptionError({
8768
+ decryptionError({
8532
8769
  code: "TRANSPORT_ERROR",
8533
8770
  cause: toError2(error)
8534
8771
  })
@@ -8555,6 +8792,8 @@ var EncryptionService = class extends BaseService {
8555
8792
  );
8556
8793
  return encOk(plaintext);
8557
8794
  } catch (error) {
8795
+ const routing = routingFailure(error);
8796
+ if (routing) return encErr(decryptionError(routing));
8558
8797
  return encErr(
8559
8798
  encryptionError({
8560
8799
  code: "INVALID_RESPONSE",
@@ -8603,7 +8842,11 @@ export {
8603
8842
  MAX_SECRET_SCOPE_LENGTH,
8604
8843
  NETWORK_NAME_PATTERN,
8605
8844
  NetworkIdError,
8845
+ NodeIdentityMismatchError,
8846
+ NodeNotRespondingError,
8847
+ PartialNodeWriteError,
8606
8848
  PrefixedKVService,
8849
+ ResourceNotRoutedError,
8607
8850
  RetryPolicySchema,
8608
8851
  SECRET_NAME_RE,
8609
8852
  SECRET_SCOPE_RE,
@@ -8651,6 +8894,7 @@ export {
8651
8894
  checkDecryptInvocationInput,
8652
8895
  clearTinyCloudDebugLogs,
8653
8896
  createKVResponseSchema,
8897
+ createResourceRoutingFetch,
8654
8898
  createResultSchema,
8655
8899
  createVaultCrypto,
8656
8900
  decryptEnvelopeWithKey,
@@ -8693,6 +8937,7 @@ export {
8693
8937
  requiresSecretsOptIn,
8694
8938
  resolveSecretListPrefix,
8695
8939
  resolveSecretPath,
8940
+ routingFailure,
8696
8941
  serviceError,
8697
8942
  storageLimitReachedError,
8698
8943
  storageQuotaExceededError,
@@ -8713,6 +8958,7 @@ export {
8713
8958
  validateTelemetrySpanEvent,
8714
8959
  validatedCapabilityOf,
8715
8960
  verifyDecryptResponse,
8961
+ verifyResourceDestination,
8716
8962
  wrapError
8717
8963
  };
8718
8964
  //# sourceMappingURL=index.js.map