@tinycloud/node-sdk 2.1.0-beta.0 → 2.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { ISessionStorage, PersistedSessionData, AutoSignStrategy, AutoRejectStrategy, CallbackStrategy, IUserAuthorization, ISigner, ISpaceCreationHandler, IWasmBindings, SiweConfig, ClientSession, TinyCloudSession, Extension, Delegation, IKVService, ISQLService, IDuckDbService, IHooksService, INotificationHandler, IENSResolver, IDataVaultService, ICapabilityKeyRegistry, DelegationManager, ISpaceService, ISharingService, CreateDelegationParams, DelegationResult, KeyProvider, ISessionManager, JWK } from '@tinycloud/sdk-core';
2
- export { AutoApproveSpaceCreationHandler, AutoRejectStrategy, AutoSignStrategy, BatchOptions, BatchResponse, CallbackStrategy, CapabilityEntry, CapabilityKeyRegistry, CapabilityKeyRegistryErrorCode, CapabilityKeyRegistryErrorCodes, ClientSession, ColumnInfo, CreateDelegationParams, DataVaultConfig, DataVaultService, DatabaseHandle, Delegation, DelegationChain, DelegationChainV2, DelegationDirection, DelegationError, DelegationErrorCode, DelegationErrorCodes, DelegationFilters, DelegationManager, DelegationManagerConfig, DelegationRecord, DelegationResult, DuckDbAction, DuckDbActionType, DuckDbBatchOptions, DuckDbBatchResponse, DuckDbDatabaseHandle, DuckDbExecuteOptions, DuckDbExecuteResponse, DuckDbOptions, DuckDbQueryOptions, DuckDbQueryResponse, DuckDbService, DuckDbServiceConfig, DuckDbStatement, DuckDbValue, EncodedShareData, ExecuteOptions, ExecuteResponse, Extension, FetchFunction, GenerateShareParams, ICapabilityKeyRegistry, IDataVaultService, IDatabaseHandle, IDuckDbDatabaseHandle, IDuckDbService, IENSResolver, IKVService, INotificationHandler, IPrefixedKVService, ISQLService, ISessionManager, ISessionStorage, ISharingService, ISigner, ISpace, ISpaceCreationHandler, ISpaceScopedDelegations, ISpaceScopedSharing, ISpaceService, IUserAuthorization, IWasmBindings, IngestOptions, InvokeFunction, JWK, KVResponse, KVService, KVServiceConfig, KeyInfo, KeyProvider, KeyType, PersistedSessionData, PrefixedKVService, ProtocolMismatchError, QueryOptions, QueryResponse, ReceiveOptions, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, ServiceContext, ServiceContextConfig, ServiceSession, ShareAccess, ShareLink, ShareLinkData, ShareSchema, SharingService, SharingServiceConfig, SignCallback, SignRequest, SignResponse, SilentNotificationHandler, Space, SpaceConfig, SpaceCreationContext, SpaceErrorCode, SpaceErrorCodes, SpaceInfo, SpaceOwnership, SpaceService, SpaceServiceConfig, SqlStatement, SqlValue, StoredDelegationChain, TableInfo, TinyCloud, TinyCloudConfig, TinyCloudSession, UnsupportedFeatureError, VaultCrypto, VaultEntry, VaultError, VaultGetOptions, VaultGrantOptions, VaultHeaders, VaultListOptions, VaultPublicSpaceKVActions, VaultPutOptions, VersionCheckError, ViewInfo, WasmVaultFunctions, buildSpaceUri, checkNodeInfo, createCapabilityKeyRegistry, createSharingService, createSpaceService, createVaultCrypto, defaultSpaceCreationHandler, makePublicSpaceId, parseSpaceUri } from '@tinycloud/sdk-core';
1
+ import { ISessionStorage, PersistedSessionData, AutoSignStrategy, AutoRejectStrategy, CallbackStrategy, IUserAuthorization, ISigner, ISpaceCreationHandler, IWasmBindings, SiweConfig, ClientSession, TinyCloudSession, Extension, Delegation, IKVService, ISQLService, IDuckDbService, IHooksService, INotificationHandler, IENSResolver, IDataVaultService, ICapabilityKeyRegistry, DelegationManager, ISpaceService, ISharingService, CreateDelegationParams, DelegationResult, PermissionEntry, KeyProvider, ISessionManager, JWK } from '@tinycloud/sdk-core';
2
+ export { AutoApproveSpaceCreationHandler, AutoRejectStrategy, AutoSignStrategy, BatchOptions, BatchResponse, CallbackStrategy, CapabilityEntry, CapabilityKeyRegistry, CapabilityKeyRegistryErrorCode, CapabilityKeyRegistryErrorCodes, ClientSession, ColumnInfo, CreateDelegationParams, DataVaultConfig, DataVaultService, DatabaseHandle, Delegation, DelegationChain, DelegationChainV2, DelegationDirection, DelegationError, DelegationErrorCode, DelegationErrorCodes, DelegationFilters, DelegationManager, DelegationManagerConfig, DelegationRecord, DelegationResult, DuckDbAction, DuckDbActionType, DuckDbBatchOptions, DuckDbBatchResponse, DuckDbDatabaseHandle, DuckDbExecuteOptions, DuckDbExecuteResponse, DuckDbOptions, DuckDbQueryOptions, DuckDbQueryResponse, DuckDbService, DuckDbServiceConfig, DuckDbStatement, DuckDbValue, EncodedShareData, ExecuteOptions, ExecuteResponse, Extension, FetchFunction, GenerateShareParams, ICapabilityKeyRegistry, IDataVaultService, IDatabaseHandle, IDuckDbDatabaseHandle, IDuckDbService, IENSResolver, IKVService, INotificationHandler, IPrefixedKVService, ISQLService, ISessionManager, ISessionStorage, ISharingService, ISigner, ISpace, ISpaceCreationHandler, ISpaceScopedDelegations, ISpaceScopedSharing, ISpaceService, IUserAuthorization, IWasmBindings, IngestOptions, InvokeFunction, JWK, KVResponse, KVService, KVServiceConfig, KeyInfo, KeyProvider, KeyType, Manifest, ManifestDefaults, ManifestDelegation, ManifestValidationError, PermissionEntry, PermissionNotInManifestError, PersistedSessionData, PrefixedKVService, ProtocolMismatchError, QueryOptions, QueryResponse, ReceiveOptions, ResolvedCapabilities, ResolvedDelegate, ResourceCapability, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, ServiceContext, ServiceContextConfig, ServiceSession, SessionExpiredError, ShareAccess, ShareLink, ShareLinkData, ShareSchema, SharingService, SharingServiceConfig, SignCallback, SignRequest, SignResponse, SilentNotificationHandler, Space, SpaceConfig, SpaceCreationContext, SpaceErrorCode, SpaceErrorCodes, SpaceInfo, SpaceOwnership, SpaceService, SpaceServiceConfig, SqlStatement, SqlValue, StoredDelegationChain, TableInfo, TinyCloud, TinyCloudConfig, TinyCloudSession, UnsupportedFeatureError, VaultCrypto, VaultEntry, VaultError, VaultGetOptions, VaultGrantOptions, VaultHeaders, VaultListOptions, VaultPublicSpaceKVActions, VaultPutOptions, VersionCheckError, ViewInfo, WasmVaultFunctions, buildSpaceUri, checkNodeInfo, createCapabilityKeyRegistry, createSharingService, createSpaceService, createVaultCrypto, defaultSpaceCreationHandler, expandActionShortNames, isCapabilitySubset, loadManifest, makePublicSpaceId, parseExpiry, parseSpaceUri, resolveManifest, validateManifest } from '@tinycloud/sdk-core';
3
3
  import { EventEmitter } from 'events';
4
4
  import { InvokeFunction } from '@tinycloud/sdk-services';
5
5
 
@@ -550,6 +550,35 @@ interface TinyCloudNodeConfig {
550
550
  /** Optional SIWE configuration overrides (e.g., nonce for server-provided nonces) */
551
551
  siweConfig?: SiweConfig;
552
552
  }
553
+ /**
554
+ * Options for {@link TinyCloudNode.delegateTo}.
555
+ *
556
+ * `expiry` accepts either an ms-format duration string (e.g. `"7d"`, `"1h"`)
557
+ * or a raw number of milliseconds. When omitted, the default is 1 hour.
558
+ *
559
+ * `forceWalletSign` bypasses the derivability check and sends the
560
+ * delegation through the legacy wallet-signed SIWE path, which always
561
+ * triggers a wallet prompt. Used for testing, for explicit wallet
562
+ * confirmation flows, and by the legacy `createDelegation` fallback.
563
+ */
564
+ interface DelegateToOptions {
565
+ /** Override expiry. ms-format string ("7d", "1h") or raw milliseconds. */
566
+ expiry?: string | number;
567
+ /** Force the wallet-signed SIWE path even if the caps are derivable. Default false. */
568
+ forceWalletSign?: boolean;
569
+ }
570
+ /**
571
+ * Result of {@link TinyCloudNode.delegateTo}.
572
+ *
573
+ * `prompted` indicates whether a wallet prompt was shown — `true` for the
574
+ * legacy wallet path (always), `false` for the session-key UCAN path (never).
575
+ * Callers wiring single-prompt sign-in flows use this to assert that their
576
+ * capability chain was derivable.
577
+ */
578
+ interface DelegateToResult {
579
+ delegation: PortableDelegation;
580
+ prompted: boolean;
581
+ }
553
582
  /**
554
583
  * High-level TinyCloud API for Node.js environments.
555
584
  *
@@ -977,6 +1006,58 @@ declare class TinyCloudNode {
977
1006
  * @returns Result containing boolean permission status
978
1007
  */
979
1008
  checkPermission(path: string, action: string): Promise<DelegationResult<boolean>>;
1009
+ /**
1010
+ * Safety margin before the session's own expiry at which {@link delegateTo}
1011
+ * will refuse to issue a derived delegation. Prevents issuing sub-delegations
1012
+ * that would be invalid by the time the recipient used them. Spec: 60 seconds.
1013
+ *
1014
+ * @internal
1015
+ */
1016
+ private static readonly SESSION_EXPIRY_SAFETY_MARGIN_MS;
1017
+ /**
1018
+ * Issue a delegation using the capability-chain flow.
1019
+ *
1020
+ * When the requested permissions are a subset of the current session's
1021
+ * recap, the delegation is signed by the session key via WASM — no wallet
1022
+ * prompt. When they are not, a {@link PermissionNotInManifestError} is
1023
+ * raised so the caller can trigger an escalation flow (e.g.
1024
+ * `TinyCloudWeb.requestPermissions`). Passing `forceWalletSign: true`
1025
+ * bypasses the derivability check and always uses the wallet-signed SIWE
1026
+ * path — used by the legacy `createDelegation` fallback and by callers
1027
+ * that want explicit wallet confirmation.
1028
+ *
1029
+ * Current limitation: exactly one {@link PermissionEntry} per call. For
1030
+ * multi-resource delegation, call `delegateTo` multiple times. This keeps
1031
+ * each delegation a single `(spaceId, path)` grant, which matches the
1032
+ * underlying `PortableDelegation` shape.
1033
+ *
1034
+ * @throws {@link SessionExpiredError} when there is no session or the
1035
+ * current session has expired (or will within the 60s safety margin).
1036
+ * @throws {@link PermissionNotInManifestError} when the requested entries
1037
+ * are not a subset of the granted session capabilities and
1038
+ * `forceWalletSign` is not set.
1039
+ */
1040
+ delegateTo(did: string, permissions: PermissionEntry[], options?: DelegateToOptions): Promise<DelegateToResult>;
1041
+ /**
1042
+ * Issue a delegation via the session-key UCAN WASM path.
1043
+ *
1044
+ * The caller has already verified the request is derivable from the
1045
+ * current session; we just need to shape the inputs for
1046
+ * {@link createDelegationWrapper}.
1047
+ *
1048
+ * @internal
1049
+ */
1050
+ private createDelegationViaWasmPath;
1051
+ /**
1052
+ * Issue a delegation via the legacy wallet-signed SIWE path for a single
1053
+ * {@link PermissionEntry}. Shares the implementation with the public
1054
+ * `createDelegation` method via {@link createDelegationWalletPath} so
1055
+ * both entry points hit exactly the same SIWE / signer / public-space
1056
+ * logic without mutual recursion.
1057
+ *
1058
+ * @internal
1059
+ */
1060
+ private createDelegationLegacyWalletPath;
980
1061
  /**
981
1062
  * Create a delegation from this user to another user.
982
1063
  *
@@ -1002,6 +1083,14 @@ declare class TinyCloudNode {
1002
1083
  /** Include a companion delegation for the user's public space (default: true) */
1003
1084
  includePublicSpace?: boolean;
1004
1085
  }): Promise<PortableDelegation>;
1086
+ /**
1087
+ * Legacy wallet-signed SIWE delegation path. Lifted from the original
1088
+ * `createDelegation` body verbatim so both the legacy public method and
1089
+ * `delegateTo({ forceWalletSign: true })` hit the same code.
1090
+ *
1091
+ * @internal
1092
+ */
1093
+ private createDelegationWalletPath;
1005
1094
  /**
1006
1095
  * Use a delegation received from another user.
1007
1096
  *
@@ -1148,4 +1237,4 @@ declare class WasmKeyProvider implements KeyProvider {
1148
1237
  */
1149
1238
  declare function createWasmKeyProvider(sessionManager: SessionManagerWithListing): WasmKeyProvider;
1150
1239
 
1151
- export { DelegatedAccess, FileSessionStorage, MemorySessionStorage, type NodeEventEmitterStrategy, NodeUserAuthorization, type NodeUserAuthorizationConfig, type PortableDelegation, type SignStrategy, TinyCloudNode, type TinyCloudNodeConfig, WasmKeyProvider, type WasmKeyProviderConfig, createWasmKeyProvider, defaultSignStrategy, deserializeDelegation, serializeDelegation };
1240
+ export { type DelegateToOptions, type DelegateToResult, DelegatedAccess, FileSessionStorage, MemorySessionStorage, type NodeEventEmitterStrategy, NodeUserAuthorization, type NodeUserAuthorizationConfig, type PortableDelegation, type SignStrategy, TinyCloudNode, type TinyCloudNodeConfig, WasmKeyProvider, type WasmKeyProviderConfig, createWasmKeyProvider, defaultSignStrategy, deserializeDelegation, serializeDelegation };
package/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { ISessionStorage, PersistedSessionData, AutoSignStrategy, AutoRejectStrategy, CallbackStrategy, IUserAuthorization, ISigner, ISpaceCreationHandler, IWasmBindings, SiweConfig, ClientSession, TinyCloudSession, Extension, Delegation, IKVService, ISQLService, IDuckDbService, IHooksService, INotificationHandler, IENSResolver, IDataVaultService, ICapabilityKeyRegistry, DelegationManager, ISpaceService, ISharingService, CreateDelegationParams, DelegationResult, KeyProvider, ISessionManager, JWK } from '@tinycloud/sdk-core';
2
- export { AutoApproveSpaceCreationHandler, AutoRejectStrategy, AutoSignStrategy, BatchOptions, BatchResponse, CallbackStrategy, CapabilityEntry, CapabilityKeyRegistry, CapabilityKeyRegistryErrorCode, CapabilityKeyRegistryErrorCodes, ClientSession, ColumnInfo, CreateDelegationParams, DataVaultConfig, DataVaultService, DatabaseHandle, Delegation, DelegationChain, DelegationChainV2, DelegationDirection, DelegationError, DelegationErrorCode, DelegationErrorCodes, DelegationFilters, DelegationManager, DelegationManagerConfig, DelegationRecord, DelegationResult, DuckDbAction, DuckDbActionType, DuckDbBatchOptions, DuckDbBatchResponse, DuckDbDatabaseHandle, DuckDbExecuteOptions, DuckDbExecuteResponse, DuckDbOptions, DuckDbQueryOptions, DuckDbQueryResponse, DuckDbService, DuckDbServiceConfig, DuckDbStatement, DuckDbValue, EncodedShareData, ExecuteOptions, ExecuteResponse, Extension, FetchFunction, GenerateShareParams, ICapabilityKeyRegistry, IDataVaultService, IDatabaseHandle, IDuckDbDatabaseHandle, IDuckDbService, IENSResolver, IKVService, INotificationHandler, IPrefixedKVService, ISQLService, ISessionManager, ISessionStorage, ISharingService, ISigner, ISpace, ISpaceCreationHandler, ISpaceScopedDelegations, ISpaceScopedSharing, ISpaceService, IUserAuthorization, IWasmBindings, IngestOptions, InvokeFunction, JWK, KVResponse, KVService, KVServiceConfig, KeyInfo, KeyProvider, KeyType, PersistedSessionData, PrefixedKVService, ProtocolMismatchError, QueryOptions, QueryResponse, ReceiveOptions, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, ServiceContext, ServiceContextConfig, ServiceSession, ShareAccess, ShareLink, ShareLinkData, ShareSchema, SharingService, SharingServiceConfig, SignCallback, SignRequest, SignResponse, SilentNotificationHandler, Space, SpaceConfig, SpaceCreationContext, SpaceErrorCode, SpaceErrorCodes, SpaceInfo, SpaceOwnership, SpaceService, SpaceServiceConfig, SqlStatement, SqlValue, StoredDelegationChain, TableInfo, TinyCloud, TinyCloudConfig, TinyCloudSession, UnsupportedFeatureError, VaultCrypto, VaultEntry, VaultError, VaultGetOptions, VaultGrantOptions, VaultHeaders, VaultListOptions, VaultPublicSpaceKVActions, VaultPutOptions, VersionCheckError, ViewInfo, WasmVaultFunctions, buildSpaceUri, checkNodeInfo, createCapabilityKeyRegistry, createSharingService, createSpaceService, createVaultCrypto, defaultSpaceCreationHandler, makePublicSpaceId, parseSpaceUri } from '@tinycloud/sdk-core';
1
+ import { ISessionStorage, PersistedSessionData, AutoSignStrategy, AutoRejectStrategy, CallbackStrategy, IUserAuthorization, ISigner, ISpaceCreationHandler, IWasmBindings, SiweConfig, ClientSession, TinyCloudSession, Extension, Delegation, IKVService, ISQLService, IDuckDbService, IHooksService, INotificationHandler, IENSResolver, IDataVaultService, ICapabilityKeyRegistry, DelegationManager, ISpaceService, ISharingService, CreateDelegationParams, DelegationResult, PermissionEntry, KeyProvider, ISessionManager, JWK } from '@tinycloud/sdk-core';
2
+ export { AutoApproveSpaceCreationHandler, AutoRejectStrategy, AutoSignStrategy, BatchOptions, BatchResponse, CallbackStrategy, CapabilityEntry, CapabilityKeyRegistry, CapabilityKeyRegistryErrorCode, CapabilityKeyRegistryErrorCodes, ClientSession, ColumnInfo, CreateDelegationParams, DataVaultConfig, DataVaultService, DatabaseHandle, Delegation, DelegationChain, DelegationChainV2, DelegationDirection, DelegationError, DelegationErrorCode, DelegationErrorCodes, DelegationFilters, DelegationManager, DelegationManagerConfig, DelegationRecord, DelegationResult, DuckDbAction, DuckDbActionType, DuckDbBatchOptions, DuckDbBatchResponse, DuckDbDatabaseHandle, DuckDbExecuteOptions, DuckDbExecuteResponse, DuckDbOptions, DuckDbQueryOptions, DuckDbQueryResponse, DuckDbService, DuckDbServiceConfig, DuckDbStatement, DuckDbValue, EncodedShareData, ExecuteOptions, ExecuteResponse, Extension, FetchFunction, GenerateShareParams, ICapabilityKeyRegistry, IDataVaultService, IDatabaseHandle, IDuckDbDatabaseHandle, IDuckDbService, IENSResolver, IKVService, INotificationHandler, IPrefixedKVService, ISQLService, ISessionManager, ISessionStorage, ISharingService, ISigner, ISpace, ISpaceCreationHandler, ISpaceScopedDelegations, ISpaceScopedSharing, ISpaceService, IUserAuthorization, IWasmBindings, IngestOptions, InvokeFunction, JWK, KVResponse, KVService, KVServiceConfig, KeyInfo, KeyProvider, KeyType, Manifest, ManifestDefaults, ManifestDelegation, ManifestValidationError, PermissionEntry, PermissionNotInManifestError, PersistedSessionData, PrefixedKVService, ProtocolMismatchError, QueryOptions, QueryResponse, ReceiveOptions, ResolvedCapabilities, ResolvedDelegate, ResourceCapability, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, ServiceContext, ServiceContextConfig, ServiceSession, SessionExpiredError, ShareAccess, ShareLink, ShareLinkData, ShareSchema, SharingService, SharingServiceConfig, SignCallback, SignRequest, SignResponse, SilentNotificationHandler, Space, SpaceConfig, SpaceCreationContext, SpaceErrorCode, SpaceErrorCodes, SpaceInfo, SpaceOwnership, SpaceService, SpaceServiceConfig, SqlStatement, SqlValue, StoredDelegationChain, TableInfo, TinyCloud, TinyCloudConfig, TinyCloudSession, UnsupportedFeatureError, VaultCrypto, VaultEntry, VaultError, VaultGetOptions, VaultGrantOptions, VaultHeaders, VaultListOptions, VaultPublicSpaceKVActions, VaultPutOptions, VersionCheckError, ViewInfo, WasmVaultFunctions, buildSpaceUri, checkNodeInfo, createCapabilityKeyRegistry, createSharingService, createSpaceService, createVaultCrypto, defaultSpaceCreationHandler, expandActionShortNames, isCapabilitySubset, loadManifest, makePublicSpaceId, parseExpiry, parseSpaceUri, resolveManifest, validateManifest } from '@tinycloud/sdk-core';
3
3
  import { EventEmitter } from 'events';
4
4
  import { InvokeFunction } from '@tinycloud/sdk-services';
5
5
 
@@ -550,6 +550,35 @@ interface TinyCloudNodeConfig {
550
550
  /** Optional SIWE configuration overrides (e.g., nonce for server-provided nonces) */
551
551
  siweConfig?: SiweConfig;
552
552
  }
553
+ /**
554
+ * Options for {@link TinyCloudNode.delegateTo}.
555
+ *
556
+ * `expiry` accepts either an ms-format duration string (e.g. `"7d"`, `"1h"`)
557
+ * or a raw number of milliseconds. When omitted, the default is 1 hour.
558
+ *
559
+ * `forceWalletSign` bypasses the derivability check and sends the
560
+ * delegation through the legacy wallet-signed SIWE path, which always
561
+ * triggers a wallet prompt. Used for testing, for explicit wallet
562
+ * confirmation flows, and by the legacy `createDelegation` fallback.
563
+ */
564
+ interface DelegateToOptions {
565
+ /** Override expiry. ms-format string ("7d", "1h") or raw milliseconds. */
566
+ expiry?: string | number;
567
+ /** Force the wallet-signed SIWE path even if the caps are derivable. Default false. */
568
+ forceWalletSign?: boolean;
569
+ }
570
+ /**
571
+ * Result of {@link TinyCloudNode.delegateTo}.
572
+ *
573
+ * `prompted` indicates whether a wallet prompt was shown — `true` for the
574
+ * legacy wallet path (always), `false` for the session-key UCAN path (never).
575
+ * Callers wiring single-prompt sign-in flows use this to assert that their
576
+ * capability chain was derivable.
577
+ */
578
+ interface DelegateToResult {
579
+ delegation: PortableDelegation;
580
+ prompted: boolean;
581
+ }
553
582
  /**
554
583
  * High-level TinyCloud API for Node.js environments.
555
584
  *
@@ -977,6 +1006,58 @@ declare class TinyCloudNode {
977
1006
  * @returns Result containing boolean permission status
978
1007
  */
979
1008
  checkPermission(path: string, action: string): Promise<DelegationResult<boolean>>;
1009
+ /**
1010
+ * Safety margin before the session's own expiry at which {@link delegateTo}
1011
+ * will refuse to issue a derived delegation. Prevents issuing sub-delegations
1012
+ * that would be invalid by the time the recipient used them. Spec: 60 seconds.
1013
+ *
1014
+ * @internal
1015
+ */
1016
+ private static readonly SESSION_EXPIRY_SAFETY_MARGIN_MS;
1017
+ /**
1018
+ * Issue a delegation using the capability-chain flow.
1019
+ *
1020
+ * When the requested permissions are a subset of the current session's
1021
+ * recap, the delegation is signed by the session key via WASM — no wallet
1022
+ * prompt. When they are not, a {@link PermissionNotInManifestError} is
1023
+ * raised so the caller can trigger an escalation flow (e.g.
1024
+ * `TinyCloudWeb.requestPermissions`). Passing `forceWalletSign: true`
1025
+ * bypasses the derivability check and always uses the wallet-signed SIWE
1026
+ * path — used by the legacy `createDelegation` fallback and by callers
1027
+ * that want explicit wallet confirmation.
1028
+ *
1029
+ * Current limitation: exactly one {@link PermissionEntry} per call. For
1030
+ * multi-resource delegation, call `delegateTo` multiple times. This keeps
1031
+ * each delegation a single `(spaceId, path)` grant, which matches the
1032
+ * underlying `PortableDelegation` shape.
1033
+ *
1034
+ * @throws {@link SessionExpiredError} when there is no session or the
1035
+ * current session has expired (or will within the 60s safety margin).
1036
+ * @throws {@link PermissionNotInManifestError} when the requested entries
1037
+ * are not a subset of the granted session capabilities and
1038
+ * `forceWalletSign` is not set.
1039
+ */
1040
+ delegateTo(did: string, permissions: PermissionEntry[], options?: DelegateToOptions): Promise<DelegateToResult>;
1041
+ /**
1042
+ * Issue a delegation via the session-key UCAN WASM path.
1043
+ *
1044
+ * The caller has already verified the request is derivable from the
1045
+ * current session; we just need to shape the inputs for
1046
+ * {@link createDelegationWrapper}.
1047
+ *
1048
+ * @internal
1049
+ */
1050
+ private createDelegationViaWasmPath;
1051
+ /**
1052
+ * Issue a delegation via the legacy wallet-signed SIWE path for a single
1053
+ * {@link PermissionEntry}. Shares the implementation with the public
1054
+ * `createDelegation` method via {@link createDelegationWalletPath} so
1055
+ * both entry points hit exactly the same SIWE / signer / public-space
1056
+ * logic without mutual recursion.
1057
+ *
1058
+ * @internal
1059
+ */
1060
+ private createDelegationLegacyWalletPath;
980
1061
  /**
981
1062
  * Create a delegation from this user to another user.
982
1063
  *
@@ -1002,6 +1083,14 @@ declare class TinyCloudNode {
1002
1083
  /** Include a companion delegation for the user's public space (default: true) */
1003
1084
  includePublicSpace?: boolean;
1004
1085
  }): Promise<PortableDelegation>;
1086
+ /**
1087
+ * Legacy wallet-signed SIWE delegation path. Lifted from the original
1088
+ * `createDelegation` body verbatim so both the legacy public method and
1089
+ * `delegateTo({ forceWalletSign: true })` hit the same code.
1090
+ *
1091
+ * @internal
1092
+ */
1093
+ private createDelegationWalletPath;
1005
1094
  /**
1006
1095
  * Use a delegation received from another user.
1007
1096
  *
@@ -1148,4 +1237,4 @@ declare class WasmKeyProvider implements KeyProvider {
1148
1237
  */
1149
1238
  declare function createWasmKeyProvider(sessionManager: SessionManagerWithListing): WasmKeyProvider;
1150
1239
 
1151
- export { DelegatedAccess, FileSessionStorage, MemorySessionStorage, type NodeEventEmitterStrategy, NodeUserAuthorization, type NodeUserAuthorizationConfig, type PortableDelegation, type SignStrategy, TinyCloudNode, type TinyCloudNodeConfig, WasmKeyProvider, type WasmKeyProviderConfig, createWasmKeyProvider, defaultSignStrategy, deserializeDelegation, serializeDelegation };
1240
+ export { type DelegateToOptions, type DelegateToResult, DelegatedAccess, FileSessionStorage, MemorySessionStorage, type NodeEventEmitterStrategy, NodeUserAuthorization, type NodeUserAuthorizationConfig, type PortableDelegation, type SignStrategy, TinyCloudNode, type TinyCloudNodeConfig, WasmKeyProvider, type WasmKeyProviderConfig, createWasmKeyProvider, defaultSignStrategy, deserializeDelegation, serializeDelegation };
package/dist/core.js CHANGED
@@ -820,7 +820,12 @@ import {
820
820
  CapabilityKeyRegistry,
821
821
  SharingService,
822
822
  UnsupportedFeatureError,
823
- makePublicSpaceId
823
+ makePublicSpaceId,
824
+ PermissionNotInManifestError,
825
+ SessionExpiredError,
826
+ expandActionShortNames,
827
+ isCapabilitySubset,
828
+ parseRecapCapabilities
824
829
  } from "@tinycloud/sdk-core";
825
830
 
826
831
  // src/DelegatedAccess.ts
@@ -982,9 +987,72 @@ function createWasmKeyProvider(sessionManager) {
982
987
  return new WasmKeyProvider({ sessionManager });
983
988
  }
984
989
 
990
+ // src/delegateToHelpers.ts
991
+ import {
992
+ parseExpiry,
993
+ SiweMessage
994
+ } from "@tinycloud/sdk-core";
995
+ function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
996
+ const byService = /* @__PURE__ */ new Map();
997
+ for (const a of actions) {
998
+ const slashIdx = a.indexOf("/");
999
+ if (slashIdx === -1) {
1000
+ continue;
1001
+ }
1002
+ const service = a.slice(0, slashIdx);
1003
+ if (!service.startsWith("tinycloud.")) {
1004
+ continue;
1005
+ }
1006
+ const list = byService.get(service);
1007
+ if (list === void 0) {
1008
+ byService.set(service, [a]);
1009
+ } else {
1010
+ list.push(a);
1011
+ }
1012
+ }
1013
+ const space = spaceIdOverride ?? "default";
1014
+ const entries = [];
1015
+ for (const [service, actionList] of byService) {
1016
+ entries.push({
1017
+ service,
1018
+ space,
1019
+ path,
1020
+ actions: actionList
1021
+ });
1022
+ }
1023
+ return entries;
1024
+ }
1025
+ function resolveExpiryMs(expiry) {
1026
+ if (expiry === void 0) {
1027
+ return 60 * 60 * 1e3;
1028
+ }
1029
+ if (typeof expiry === "number") {
1030
+ if (!Number.isFinite(expiry) || expiry <= 0) {
1031
+ throw new Error(
1032
+ `delegateTo expiry must be a positive finite number (got ${expiry})`
1033
+ );
1034
+ }
1035
+ return expiry;
1036
+ }
1037
+ return parseExpiry(expiry);
1038
+ }
1039
+ function extractSiweExpiration(siwe) {
1040
+ const parsed = new SiweMessage(siwe);
1041
+ if (parsed.expirationTime === void 0 || parsed.expirationTime === null) {
1042
+ return void 0;
1043
+ }
1044
+ const d = new Date(parsed.expirationTime);
1045
+ if (Number.isNaN(d.getTime())) {
1046
+ throw new Error(
1047
+ `Session SIWE has unparseable expirationTime: ${parsed.expirationTime}`
1048
+ );
1049
+ }
1050
+ return d;
1051
+ }
1052
+
985
1053
  // src/TinyCloudNode.ts
986
1054
  var DEFAULT_HOST = "https://node.tinycloud.xyz";
987
- var TinyCloudNode = class _TinyCloudNode {
1055
+ var _TinyCloudNode = class _TinyCloudNode {
988
1056
  /**
989
1057
  * Create a new TinyCloudNode instance.
990
1058
  *
@@ -2118,6 +2186,150 @@ var TinyCloudNode = class _TinyCloudNode {
2118
2186
  async checkPermission(path, action) {
2119
2187
  return this.delegationManager.checkPermission(path, action);
2120
2188
  }
2189
+ /**
2190
+ * Issue a delegation using the capability-chain flow.
2191
+ *
2192
+ * When the requested permissions are a subset of the current session's
2193
+ * recap, the delegation is signed by the session key via WASM — no wallet
2194
+ * prompt. When they are not, a {@link PermissionNotInManifestError} is
2195
+ * raised so the caller can trigger an escalation flow (e.g.
2196
+ * `TinyCloudWeb.requestPermissions`). Passing `forceWalletSign: true`
2197
+ * bypasses the derivability check and always uses the wallet-signed SIWE
2198
+ * path — used by the legacy `createDelegation` fallback and by callers
2199
+ * that want explicit wallet confirmation.
2200
+ *
2201
+ * Current limitation: exactly one {@link PermissionEntry} per call. For
2202
+ * multi-resource delegation, call `delegateTo` multiple times. This keeps
2203
+ * each delegation a single `(spaceId, path)` grant, which matches the
2204
+ * underlying `PortableDelegation` shape.
2205
+ *
2206
+ * @throws {@link SessionExpiredError} when there is no session or the
2207
+ * current session has expired (or will within the 60s safety margin).
2208
+ * @throws {@link PermissionNotInManifestError} when the requested entries
2209
+ * are not a subset of the granted session capabilities and
2210
+ * `forceWalletSign` is not set.
2211
+ */
2212
+ async delegateTo(did, permissions, options) {
2213
+ const session = this.auth?.tinyCloudSession;
2214
+ if (!session) {
2215
+ throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
2216
+ }
2217
+ const sessionExpiry = extractSiweExpiration(session.siwe);
2218
+ if (sessionExpiry !== void 0) {
2219
+ const now2 = Date.now();
2220
+ const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
2221
+ if (sessionExpiry.getTime() <= now2 + marginMs) {
2222
+ throw new SessionExpiredError(sessionExpiry);
2223
+ }
2224
+ }
2225
+ if (!Array.isArray(permissions) || permissions.length === 0) {
2226
+ throw new Error(
2227
+ "delegateTo requires a non-empty permissions array"
2228
+ );
2229
+ }
2230
+ if (permissions.length > 1) {
2231
+ throw new Error(
2232
+ "delegateTo currently supports one permission entry per call. Call delegateTo multiple times for multi-resource delegation."
2233
+ );
2234
+ }
2235
+ const entry = permissions[0];
2236
+ const expandedEntry = {
2237
+ ...entry,
2238
+ actions: expandActionShortNames(entry.service, entry.actions)
2239
+ };
2240
+ const now = /* @__PURE__ */ new Date();
2241
+ const expiryMs = resolveExpiryMs(options?.expiry);
2242
+ const expirationTime = new Date(now.getTime() + expiryMs);
2243
+ let effectiveExpiration = expirationTime;
2244
+ if (sessionExpiry !== void 0 && sessionExpiry < expirationTime) {
2245
+ effectiveExpiration = sessionExpiry;
2246
+ }
2247
+ if (options?.forceWalletSign) {
2248
+ const delegation2 = await this.createDelegationLegacyWalletPath(
2249
+ did,
2250
+ expandedEntry,
2251
+ effectiveExpiration
2252
+ );
2253
+ return { delegation: delegation2, prompted: true };
2254
+ }
2255
+ const granted = parseRecapCapabilities(
2256
+ (siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
2257
+ session.siwe
2258
+ );
2259
+ const requested = [expandedEntry];
2260
+ const { subset, missing } = isCapabilitySubset(requested, granted);
2261
+ if (!subset) {
2262
+ throw new PermissionNotInManifestError(missing, granted);
2263
+ }
2264
+ const delegation = await this.createDelegationViaWasmPath(
2265
+ did,
2266
+ expandedEntry,
2267
+ effectiveExpiration,
2268
+ session
2269
+ );
2270
+ return { delegation, prompted: false };
2271
+ }
2272
+ /**
2273
+ * Issue a delegation via the session-key UCAN WASM path.
2274
+ *
2275
+ * The caller has already verified the request is derivable from the
2276
+ * current session; we just need to shape the inputs for
2277
+ * {@link createDelegationWrapper}.
2278
+ *
2279
+ * @internal
2280
+ */
2281
+ async createDelegationViaWasmPath(did, entry, expirationTime, session) {
2282
+ const spaceId = entry.space === "default" ? session.spaceId : entry.space;
2283
+ const serviceSession = {
2284
+ delegationHeader: session.delegationHeader,
2285
+ delegationCid: session.delegationCid,
2286
+ jwk: session.jwk,
2287
+ spaceId,
2288
+ verificationMethod: session.verificationMethod
2289
+ };
2290
+ const expirationSecs = Math.floor(expirationTime.getTime() / 1e3);
2291
+ const result = this.createDelegationWrapper({
2292
+ session: serviceSession,
2293
+ delegateDID: did,
2294
+ spaceId,
2295
+ path: entry.path,
2296
+ actions: entry.actions,
2297
+ expirationSecs
2298
+ });
2299
+ return {
2300
+ cid: result.cid,
2301
+ delegationHeader: { Authorization: `Bearer ${result.delegation}` },
2302
+ spaceId,
2303
+ path: entry.path,
2304
+ actions: entry.actions,
2305
+ disableSubDelegation: false,
2306
+ expiry: result.expiry,
2307
+ delegateDID: did,
2308
+ ownerAddress: session.address,
2309
+ chainId: session.chainId,
2310
+ host: this.config.host
2311
+ };
2312
+ }
2313
+ /**
2314
+ * Issue a delegation via the legacy wallet-signed SIWE path for a single
2315
+ * {@link PermissionEntry}. Shares the implementation with the public
2316
+ * `createDelegation` method via {@link createDelegationWalletPath} so
2317
+ * both entry points hit exactly the same SIWE / signer / public-space
2318
+ * logic without mutual recursion.
2319
+ *
2320
+ * @internal
2321
+ */
2322
+ async createDelegationLegacyWalletPath(delegateDID, entry, expirationTime) {
2323
+ const spaceIdOverride = entry.space === "default" ? void 0 : entry.space;
2324
+ return this.createDelegationWalletPath({
2325
+ path: entry.path,
2326
+ actions: entry.actions,
2327
+ delegateDID,
2328
+ includePublicSpace: true,
2329
+ expiryMs: Math.max(0, expirationTime.getTime() - Date.now()),
2330
+ spaceIdOverride
2331
+ });
2332
+ }
2121
2333
  /**
2122
2334
  * Create a delegation from this user to another user.
2123
2335
  *
@@ -2128,6 +2340,51 @@ var TinyCloudNode = class _TinyCloudNode {
2128
2340
  * @returns A portable delegation that can be sent to the recipient
2129
2341
  */
2130
2342
  async createDelegation(params) {
2343
+ if (!this.signer) {
2344
+ throw new Error("Cannot createDelegation() in session-only mode. Requires wallet mode.");
2345
+ }
2346
+ if (!this.auth?.tinyCloudSession) {
2347
+ throw new Error("Not signed in. Call signIn() first.");
2348
+ }
2349
+ let resolvedDelegateDID = params.delegateDID;
2350
+ if (resolvedDelegateDID.endsWith(".eth") && this.config.ensResolver) {
2351
+ const address = await this.config.ensResolver.resolveAddress(resolvedDelegateDID);
2352
+ if (!address) throw new Error(`Could not resolve ENS name: ${resolvedDelegateDID}`);
2353
+ resolvedDelegateDID = `did:pkh:eip155:1:${address}`;
2354
+ }
2355
+ const entries = legacyParamsToPermissionEntries(
2356
+ params.actions,
2357
+ params.path,
2358
+ params.spaceIdOverride
2359
+ );
2360
+ if (entries.length === 1) {
2361
+ try {
2362
+ const result = await this.delegateTo(
2363
+ resolvedDelegateDID,
2364
+ [entries[0]],
2365
+ params.expiryMs !== void 0 ? { expiry: params.expiryMs } : void 0
2366
+ );
2367
+ return result.delegation;
2368
+ } catch (err) {
2369
+ if (err instanceof PermissionNotInManifestError) {
2370
+ } else {
2371
+ throw err;
2372
+ }
2373
+ }
2374
+ }
2375
+ return this.createDelegationWalletPath({
2376
+ ...params,
2377
+ delegateDID: resolvedDelegateDID
2378
+ });
2379
+ }
2380
+ /**
2381
+ * Legacy wallet-signed SIWE delegation path. Lifted from the original
2382
+ * `createDelegation` body verbatim so both the legacy public method and
2383
+ * `delegateTo({ forceWalletSign: true })` hit the same code.
2384
+ *
2385
+ * @internal
2386
+ */
2387
+ async createDelegationWalletPath(params) {
2131
2388
  if (!this.signer) {
2132
2389
  throw new Error("Cannot createDelegation() in session-only mode. Requires wallet mode.");
2133
2390
  }
@@ -2135,11 +2392,6 @@ var TinyCloudNode = class _TinyCloudNode {
2135
2392
  if (!session) {
2136
2393
  throw new Error("Not signed in. Call signIn() first.");
2137
2394
  }
2138
- if (params.delegateDID.endsWith(".eth") && this.config.ensResolver) {
2139
- const address = await this.config.ensResolver.resolveAddress(params.delegateDID);
2140
- if (!address) throw new Error(`Could not resolve ENS name: ${params.delegateDID}`);
2141
- params = { ...params, delegateDID: `did:pkh:eip155:1:${address}` };
2142
- }
2143
2395
  const abilities = {};
2144
2396
  const kvActions = params.actions.filter((a) => a.startsWith("tinycloud.kv/"));
2145
2397
  const sqlActions = params.actions.filter((a) => a.startsWith("tinycloud.sql/"));
@@ -2427,6 +2679,31 @@ var TinyCloudNode = class _TinyCloudNode {
2427
2679
  };
2428
2680
  }
2429
2681
  };
2682
+ // ===========================================================================
2683
+ // Capability-chain delegation (spec: .claude/specs/capability-chain.md)
2684
+ // ===========================================================================
2685
+ /**
2686
+ * Safety margin before the session's own expiry at which {@link delegateTo}
2687
+ * will refuse to issue a derived delegation. Prevents issuing sub-delegations
2688
+ * that would be invalid by the time the recipient used them. Spec: 60 seconds.
2689
+ *
2690
+ * @internal
2691
+ */
2692
+ _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS = 6e4;
2693
+ var TinyCloudNode = _TinyCloudNode;
2694
+
2695
+ // src/core.ts
2696
+ import {
2697
+ PermissionNotInManifestError as PermissionNotInManifestError2,
2698
+ SessionExpiredError as SessionExpiredError2,
2699
+ ManifestValidationError,
2700
+ resolveManifest,
2701
+ validateManifest,
2702
+ loadManifest,
2703
+ isCapabilitySubset as isCapabilitySubset2,
2704
+ expandActionShortNames as expandActionShortNames2,
2705
+ parseExpiry as parseExpiry2
2706
+ } from "@tinycloud/sdk-core";
2430
2707
 
2431
2708
  // src/delegation.ts
2432
2709
  function serializeDelegation(delegation) {
@@ -2490,13 +2767,16 @@ export {
2490
2767
  DuckDbService3 as DuckDbService,
2491
2768
  FileSessionStorage,
2492
2769
  KVService3 as KVService,
2770
+ ManifestValidationError,
2493
2771
  MemorySessionStorage,
2494
2772
  NodeUserAuthorization,
2773
+ PermissionNotInManifestError2 as PermissionNotInManifestError,
2495
2774
  PrefixedKVService,
2496
2775
  ProtocolMismatchError,
2497
2776
  SQLAction,
2498
2777
  SQLService3 as SQLService,
2499
2778
  ServiceContext3 as ServiceContext,
2779
+ SessionExpiredError2 as SessionExpiredError,
2500
2780
  SharingService2 as SharingService,
2501
2781
  SilentNotificationHandler2 as SilentNotificationHandler,
2502
2782
  Space,
@@ -2519,8 +2799,14 @@ export {
2519
2799
  defaultSignStrategy,
2520
2800
  defaultSpaceCreationHandler,
2521
2801
  deserializeDelegation,
2802
+ expandActionShortNames2 as expandActionShortNames,
2803
+ isCapabilitySubset2 as isCapabilitySubset,
2804
+ loadManifest,
2522
2805
  makePublicSpaceId2 as makePublicSpaceId,
2806
+ parseExpiry2 as parseExpiry,
2523
2807
  parseSpaceUri,
2524
- serializeDelegation
2808
+ resolveManifest,
2809
+ serializeDelegation,
2810
+ validateManifest
2525
2811
  };
2526
2812
  //# sourceMappingURL=core.js.map