@tinycloud/node-sdk 2.11.0 → 2.11.1-beta.0

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,4 +1,4 @@
1
1
  export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, AccountApplication, AccountApplicationListOptions, AccountApplicationRegisterOptions, AccountDelegation, AccountDelegationListOptions, AccountDelegationRevokeOptions, AccountIndexEnsureResult, AccountIndexRebuildResult, AccountIndexStatus, AccountIndexedReadOptions, AccountService, AccountServiceConfig, AccountSpace, AccountSpaceListOptions, AccountStatus, AutoApproveSpaceCreationHandler, AutoRejectStrategy, AutoSignStrategy, BatchOptions, BatchResponse, CallbackStrategy, CanonicalAddress, CanonicalParsedNetworkId, CapabilityEntry, CapabilityKeyRegistry, CapabilityKeyRegistryErrorCode, CapabilityKeyRegistryErrorCodes, CaveatedDelegationUnsupportedError, ClientSession, ColumnInfo, ComposeManifestOptions, ComposedManifestRequest, CreateDelegationParams, DEFAULT_MANIFEST_SPACE, DEFAULT_MANIFEST_VERSION, DEFAULT_SIGNED_READ_URL_EXPIRY_MS, DataVaultConfig, DataVaultService, DatabaseHandle, DelegateReceivedShareParams, DelegatedShareAccess, Delegation, DelegationChain, DelegationChainV2, DelegationDirection, DelegationError, DelegationErrorCode, DelegationErrorCodes, DelegationFilters, DelegationManager, DelegationManagerConfig, DelegationRecord, DelegationResult, DidCacheKeyOptions, DidEqualsOptions, 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, ISecretsService, ISessionManager, ISessionStorage, ISharingService, ISigner, ISpace, ISpaceCreationHandler, ISpaceScopedDelegations, ISpaceScopedSharing, ISpaceService, IUserAuthorization, IWasmBindings, IdentityParseError, IngestOptions, InvokeFunction, JWK, KVBatchReadResponse, KVCreateSignedReadUrlOptions, KVResponse, KVService, KVServiceConfig, KVSignedReadUrlResponse, KeyInfo, KeyProvider, KeyType, Manifest, ManifestDefaults, ManifestRegistryRecord, ManifestSecretActions, ManifestValidationError, OpenKeyCallbackStrategy, OpenKeySigningRequestBody, OpenKeySigningResponseBody, OpenKeySigningStrategyOptions, OwnerSharePolicyRegistrationReceipt, PermissionEntry, PermissionNotInManifestError, PersistedSessionData, PkhDidParts, PrefixedKVService, ProtocolMismatchError, QueryOptions, QueryResponse, ReceiveOptions, RegisterBatchSuccess, RegisterOwnerSharePolicyParams, ResolvedCapabilities, ResolvedDelegate, ResolvedSecretPath, ResourceCapability, SECRET_NAME_RE, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, SecretPayload, SecretScopeOptions, SecretsError, SecretsService, ServiceContext, ServiceContextConfig, ServiceSession, SessionExpiredError, ShareAccess, ShareLink, ShareLinkData, ShareSchema, SharingService, SharingServiceConfig, SignCallback, SignInOptions, SignRequest, SignResponse, SilentNotificationHandler, Space, SpaceAbilitiesMap, SpaceConfig, SpaceCreationContext, SpaceErrorCode, SpaceErrorCodes, SpaceInfo, SpaceOwnership, SpaceService, SpaceServiceConfig, SqlStatement, SqlValue, StoredDelegationChain, TableInfo, TelemetryConfig, TelemetryEventHandler, TinyCloud, TinyCloudConfig, TinyCloudDebugEnableOptions, TinyCloudDebugEvent, TinyCloudDebugLevel, TinyCloudDebugLogger, TinyCloudDebugTimer, TinyCloudSession, UnsupportedFeatureError, VAULT_PERMISSION_SERVICE, VaultCrypto, VaultEntry, VaultError, VaultGetOptions, VaultGrantOptions, VaultHeaders, VaultListOptions, VaultNetworkReadResult, VaultPublicSpaceKVActions, VaultPutOptions, VersionCheckError, ViewInfo, WasmVaultFunctions, addressStorageKey, buildSpaceUri, canonicalizeAddress, canonicalizeDid, canonicalizeDidUrl, canonicalizeNetworkId, canonicalizeSecretScope, checkNodeInfo, clearTinyCloudDebugLogs, composeManifestRequest, createCapabilityKeyRegistry, createOpenKeyCallbackSigningStrategy, createSharingService, createSpaceService, createVaultCrypto, defaultSpaceCreationHandler, didCacheKey, didEquals, disableTinyCloudDebug, enableTinyCloudDebug, expandActionShortNames, expandPermissionEntries, expandPermissionEntry, getTinyCloudDebugLogs, installTinyCloudDebugGlobals, isCapabilitySubset, isEvmAddress, loadManifest, makePkhSpaceId, makePublicSpaceId, parseCanonicalNetworkId, parseExpiry, parsePkhDid, parseSpaceUri, pkhDid, principalDid, principalDidEquals, resolveManifest, resolveSecretListPrefix, resolveSecretPath, resourceCapabilitiesToSpaceAbilitiesMap, tinyCloudDebugLogger, validateManifest } from '@tinycloud/sdk-core';
2
- export { e as BootstrapWarning, C as CreateOwnerDelegationParams, D as DelegateToOptions, f as DelegateToResult, g as DelegatedAccess, E as EnsureEncryptionNetworkOptions, F as FileSessionStorage, M as MemorySessionStorage, N as NodeEventEmitterStrategy, i as NodeUserAuthorization, j as NodeUserAuthorizationConfig, O as OwnerDelegationReceipt, P as PortableDelegation, l as RuntimePermissionGrantOptions, S as SecretPermissionHint, m as SecretReadInput, n as SecretReadResult, o as SignStrategy, T as TinyCloudNode, p as TinyCloudNodeConfig, U as UnsupportedSessionRestoreError, W as WasmKeyProvider, q as WasmKeyProviderConfig, s as createWasmKeyProvider, t as defaultSignStrategy, u as deserializeDelegation, w as serializeDelegation } from './core-Bq8TMY7Y.cjs';
2
+ export { e as BootstrapWarning, C as CompactRuntimeDelegationInput, f as CreateOwnerDelegationParams, D as DelegateToOptions, g as DelegateToResult, h as DelegatedAccess, E as EnsureEncryptionNetworkOptions, F as FileSessionStorage, M as MemorySessionStorage, N as NodeEventEmitterStrategy, j as NodeUserAuthorization, k as NodeUserAuthorizationConfig, O as OwnerDelegationReceipt, P as PortableDelegation, m as RuntimePermissionGrantOptions, S as SecretPermissionHint, n as SecretReadInput, o as SecretReadResult, p as SignStrategy, T as TinyCloudNode, q as TinyCloudNodeConfig, U as UnifiedOwnerRootInput, r as UnifiedOwnerRootReceipt, s as UnsupportedSessionRestoreError, V as ValidatedRuntimeDelegation, W as WasmKeyProvider, t as WasmKeyProviderConfig, u as activateCompactRuntimeDelegation, w as createWasmKeyProvider, x as defaultSignStrategy, y as deserializeDelegation, G as serializeDelegation } from './core-C6Czyr52.cjs';
3
3
  import 'events';
4
4
  import '@tinycloud/sdk-services';
package/dist/core.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, AccountApplication, AccountApplicationListOptions, AccountApplicationRegisterOptions, AccountDelegation, AccountDelegationListOptions, AccountDelegationRevokeOptions, AccountIndexEnsureResult, AccountIndexRebuildResult, AccountIndexStatus, AccountIndexedReadOptions, AccountService, AccountServiceConfig, AccountSpace, AccountSpaceListOptions, AccountStatus, AutoApproveSpaceCreationHandler, AutoRejectStrategy, AutoSignStrategy, BatchOptions, BatchResponse, CallbackStrategy, CanonicalAddress, CanonicalParsedNetworkId, CapabilityEntry, CapabilityKeyRegistry, CapabilityKeyRegistryErrorCode, CapabilityKeyRegistryErrorCodes, CaveatedDelegationUnsupportedError, ClientSession, ColumnInfo, ComposeManifestOptions, ComposedManifestRequest, CreateDelegationParams, DEFAULT_MANIFEST_SPACE, DEFAULT_MANIFEST_VERSION, DEFAULT_SIGNED_READ_URL_EXPIRY_MS, DataVaultConfig, DataVaultService, DatabaseHandle, DelegateReceivedShareParams, DelegatedShareAccess, Delegation, DelegationChain, DelegationChainV2, DelegationDirection, DelegationError, DelegationErrorCode, DelegationErrorCodes, DelegationFilters, DelegationManager, DelegationManagerConfig, DelegationRecord, DelegationResult, DidCacheKeyOptions, DidEqualsOptions, 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, ISecretsService, ISessionManager, ISessionStorage, ISharingService, ISigner, ISpace, ISpaceCreationHandler, ISpaceScopedDelegations, ISpaceScopedSharing, ISpaceService, IUserAuthorization, IWasmBindings, IdentityParseError, IngestOptions, InvokeFunction, JWK, KVBatchReadResponse, KVCreateSignedReadUrlOptions, KVResponse, KVService, KVServiceConfig, KVSignedReadUrlResponse, KeyInfo, KeyProvider, KeyType, Manifest, ManifestDefaults, ManifestRegistryRecord, ManifestSecretActions, ManifestValidationError, OpenKeyCallbackStrategy, OpenKeySigningRequestBody, OpenKeySigningResponseBody, OpenKeySigningStrategyOptions, OwnerSharePolicyRegistrationReceipt, PermissionEntry, PermissionNotInManifestError, PersistedSessionData, PkhDidParts, PrefixedKVService, ProtocolMismatchError, QueryOptions, QueryResponse, ReceiveOptions, RegisterBatchSuccess, RegisterOwnerSharePolicyParams, ResolvedCapabilities, ResolvedDelegate, ResolvedSecretPath, ResourceCapability, SECRET_NAME_RE, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, SecretPayload, SecretScopeOptions, SecretsError, SecretsService, ServiceContext, ServiceContextConfig, ServiceSession, SessionExpiredError, ShareAccess, ShareLink, ShareLinkData, ShareSchema, SharingService, SharingServiceConfig, SignCallback, SignInOptions, SignRequest, SignResponse, SilentNotificationHandler, Space, SpaceAbilitiesMap, SpaceConfig, SpaceCreationContext, SpaceErrorCode, SpaceErrorCodes, SpaceInfo, SpaceOwnership, SpaceService, SpaceServiceConfig, SqlStatement, SqlValue, StoredDelegationChain, TableInfo, TelemetryConfig, TelemetryEventHandler, TinyCloud, TinyCloudConfig, TinyCloudDebugEnableOptions, TinyCloudDebugEvent, TinyCloudDebugLevel, TinyCloudDebugLogger, TinyCloudDebugTimer, TinyCloudSession, UnsupportedFeatureError, VAULT_PERMISSION_SERVICE, VaultCrypto, VaultEntry, VaultError, VaultGetOptions, VaultGrantOptions, VaultHeaders, VaultListOptions, VaultNetworkReadResult, VaultPublicSpaceKVActions, VaultPutOptions, VersionCheckError, ViewInfo, WasmVaultFunctions, addressStorageKey, buildSpaceUri, canonicalizeAddress, canonicalizeDid, canonicalizeDidUrl, canonicalizeNetworkId, canonicalizeSecretScope, checkNodeInfo, clearTinyCloudDebugLogs, composeManifestRequest, createCapabilityKeyRegistry, createOpenKeyCallbackSigningStrategy, createSharingService, createSpaceService, createVaultCrypto, defaultSpaceCreationHandler, didCacheKey, didEquals, disableTinyCloudDebug, enableTinyCloudDebug, expandActionShortNames, expandPermissionEntries, expandPermissionEntry, getTinyCloudDebugLogs, installTinyCloudDebugGlobals, isCapabilitySubset, isEvmAddress, loadManifest, makePkhSpaceId, makePublicSpaceId, parseCanonicalNetworkId, parseExpiry, parsePkhDid, parseSpaceUri, pkhDid, principalDid, principalDidEquals, resolveManifest, resolveSecretListPrefix, resolveSecretPath, resourceCapabilitiesToSpaceAbilitiesMap, tinyCloudDebugLogger, validateManifest } from '@tinycloud/sdk-core';
2
- export { e as BootstrapWarning, C as CreateOwnerDelegationParams, D as DelegateToOptions, f as DelegateToResult, g as DelegatedAccess, E as EnsureEncryptionNetworkOptions, F as FileSessionStorage, M as MemorySessionStorage, N as NodeEventEmitterStrategy, i as NodeUserAuthorization, j as NodeUserAuthorizationConfig, O as OwnerDelegationReceipt, P as PortableDelegation, l as RuntimePermissionGrantOptions, S as SecretPermissionHint, m as SecretReadInput, n as SecretReadResult, o as SignStrategy, T as TinyCloudNode, p as TinyCloudNodeConfig, U as UnsupportedSessionRestoreError, W as WasmKeyProvider, q as WasmKeyProviderConfig, s as createWasmKeyProvider, t as defaultSignStrategy, u as deserializeDelegation, w as serializeDelegation } from './core-Bq8TMY7Y.js';
2
+ export { e as BootstrapWarning, C as CompactRuntimeDelegationInput, f as CreateOwnerDelegationParams, D as DelegateToOptions, g as DelegateToResult, h as DelegatedAccess, E as EnsureEncryptionNetworkOptions, F as FileSessionStorage, M as MemorySessionStorage, N as NodeEventEmitterStrategy, j as NodeUserAuthorization, k as NodeUserAuthorizationConfig, O as OwnerDelegationReceipt, P as PortableDelegation, m as RuntimePermissionGrantOptions, S as SecretPermissionHint, n as SecretReadInput, o as SecretReadResult, p as SignStrategy, T as TinyCloudNode, q as TinyCloudNodeConfig, U as UnifiedOwnerRootInput, r as UnifiedOwnerRootReceipt, s as UnsupportedSessionRestoreError, V as ValidatedRuntimeDelegation, W as WasmKeyProvider, t as WasmKeyProviderConfig, u as activateCompactRuntimeDelegation, w as createWasmKeyProvider, x as defaultSignStrategy, y as deserializeDelegation, G as serializeDelegation } from './core-C6Czyr52.js';
3
3
  import 'events';
4
4
  import '@tinycloud/sdk-services';
package/dist/core.js CHANGED
@@ -1714,7 +1714,8 @@ import {
1714
1714
  resolveSecretPath as resolveSecretPath2,
1715
1715
  validateOwnerSharePolicyRegistrationBytes,
1716
1716
  validateShareDeliveryAuthorizationBytes,
1717
- verifyEip191MessageSignature
1717
+ verifyEip191MessageSignature,
1718
+ signCompactUcanRootAuthorization
1718
1719
  } from "@tinycloud/sdk-core";
1719
1720
  import {
1720
1721
  parsePermissionHint
@@ -2182,6 +2183,18 @@ var ROOT_DELEGATION_ACTIONS = [
2182
2183
  DUCKDB2.ALL
2183
2184
  ];
2184
2185
  var DEFAULT_SESSION_EXPIRATION_MS = EXPIRY3.SESSION_MS;
2186
+ function unifiedRootAttenuation(capabilities) {
2187
+ const attenuation = {};
2188
+ for (const capability of capabilities) {
2189
+ if (attenuation[capability.resource] !== void 0) throw new Error("unified owner root contains a duplicate resource");
2190
+ attenuation[capability.resource] = capability.kind === "encryption" ? { [capability.action]: [{}] } : Object.fromEntries(capability.actions.map((action) => [action, [{
2191
+ type: "xyz.tinycloud.resource/selector",
2192
+ kind: capability.selector,
2193
+ value: capability.resource
2194
+ }]]));
2195
+ }
2196
+ return attenuation;
2197
+ }
2185
2198
  function decodeAuthorizationBytes(authorization) {
2186
2199
  const encoded = authorization.replace(/^Bearer /i, "");
2187
2200
  const match = /^([A-Za-z0-9_-]+)(={1,2})?$/.exec(encoded);
@@ -2561,6 +2574,8 @@ var _TinyCloudNode = class _TinyCloudNode {
2561
2574
  * hosting is confirmed against the session that was active at the time.
2562
2575
  */
2563
2576
  this.confirmedHostedSpaceIds = /* @__PURE__ */ new Set();
2577
+ /** Serializes account-registry writes for the active node instance. */
2578
+ this.accountRegistryTail = Promise.resolve();
2564
2579
  /**
2565
2580
  * True when the last signIn() detected an interactive signer and skipped
2566
2581
  * client-side bootstrap. Apps can read this to know whether bootstrap was
@@ -2957,6 +2972,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2957
2972
  "Cannot signIn() in session-only mode. Provide a privateKey in config to create your own space."
2958
2973
  );
2959
2974
  }
2975
+ await this.accountRegistryTail;
2960
2976
  await this.wasmBindings.ensureInitialized?.();
2961
2977
  this._address = canonicalizeAddress2(await this.signer.getAddress());
2962
2978
  this._chainId = await this.signer.getChainId();
@@ -3438,16 +3454,48 @@ var _TinyCloudNode = class _TinyCloudNode {
3438
3454
  }
3439
3455
  }
3440
3456
  scheduleAccountRegistrySync() {
3441
- void this.withAccountRegistryRetry(async () => {
3442
- void this.account.index.ensure();
3443
- await this.writeManifestRegistryRecords();
3444
- if (this.currentSessionCanListSpaces()) {
3445
- const spaces = await this.account.spaces.syncAccessible();
3446
- if (!spaces.ok) {
3447
- throw new Error(`Failed to sync account spaces: ${spaces.error.message}`);
3457
+ const session = this.currentTinyCloudSession();
3458
+ if (!session || this.pendingAccountRegistrySync?.session === session) {
3459
+ return;
3460
+ }
3461
+ const promise = this.enqueueAccountRegistryOperation(session, async () => {
3462
+ await this.withAccountRegistryRetry(async () => {
3463
+ if (this.currentTinyCloudSession() !== session) {
3464
+ return;
3465
+ }
3466
+ await this.account.index.ensure();
3467
+ if (this.currentTinyCloudSession() !== session) {
3468
+ return;
3469
+ }
3470
+ await this.writeManifestRegistryRecords();
3471
+ if (this.currentTinyCloudSession() !== session) {
3472
+ return;
3473
+ }
3474
+ if (this.currentSessionCanListSpaces()) {
3475
+ const spaces = await this.account.spaces.syncAccessible();
3476
+ if (!spaces.ok) {
3477
+ throw new Error(`Failed to sync account spaces: ${spaces.error.message}`);
3478
+ }
3448
3479
  }
3480
+ });
3481
+ });
3482
+ this.pendingAccountRegistrySync = { session, promise };
3483
+ const clearPendingSync = () => {
3484
+ if (this.pendingAccountRegistrySync?.promise === promise) {
3485
+ this.pendingAccountRegistrySync = void 0;
3486
+ }
3487
+ };
3488
+ void promise.then(clearPendingSync, clearPendingSync);
3489
+ }
3490
+ enqueueAccountRegistryOperation(session, task) {
3491
+ const operation = this.accountRegistryTail.then(async () => {
3492
+ if (this.currentTinyCloudSession() === session) {
3493
+ await task();
3449
3494
  }
3450
3495
  });
3496
+ this.accountRegistryTail = operation.catch(() => {
3497
+ });
3498
+ return operation;
3451
3499
  }
3452
3500
  /**
3453
3501
  * Whether the current primary session may invoke `tinycloud.space/list`.
@@ -3600,7 +3648,8 @@ var _TinyCloudNode = class _TinyCloudNode {
3600
3648
  * @returns The hosted space URI.
3601
3649
  */
3602
3650
  async hostOwnedSpace(name) {
3603
- if (!this.auth || !this.auth.tinyCloudSession) {
3651
+ const session = this.auth?.tinyCloudSession;
3652
+ if (!this.auth || !session) {
3604
3653
  throw new Error("Not signed in. Call signIn() first.");
3605
3654
  }
3606
3655
  const spaceId = this.ownedSpaceId(name);
@@ -3616,22 +3665,26 @@ var _TinyCloudNode = class _TinyCloudNode {
3616
3665
  }
3617
3666
  const activation = await activateSessionWithHost2(
3618
3667
  host,
3619
- this.auth.tinyCloudSession.delegationHeader
3668
+ session.delegationHeader
3620
3669
  );
3621
3670
  if (!activation.success || activation.skipped?.includes(spaceId)) {
3622
3671
  throw new Error(
3623
3672
  `Failed to activate session for owned space ${spaceId}: ${activation.error ?? "space was skipped"}`
3624
3673
  );
3625
3674
  }
3626
- void this.account.spaces.register({
3627
- spaceId,
3628
- name,
3629
- ownerDid: this.did,
3630
- type: "owned",
3631
- permissions: ["*"],
3632
- status: "active"
3633
- }).catch(() => {
3634
- });
3675
+ try {
3676
+ await this.enqueueAccountRegistryOperation(session, async () => {
3677
+ await this.account.spaces.register({
3678
+ spaceId,
3679
+ name,
3680
+ ownerDid: this.did,
3681
+ type: "owned",
3682
+ permissions: ["*"],
3683
+ status: "active"
3684
+ });
3685
+ });
3686
+ } catch {
3687
+ }
3635
3688
  return spaceId;
3636
3689
  }
3637
3690
  /**
@@ -3666,23 +3719,12 @@ var _TinyCloudNode = class _TinyCloudNode {
3666
3719
  if (!this.auth || !this.auth.tinyCloudSession) {
3667
3720
  throw new Error("Not signed in. Call signIn() first.");
3668
3721
  }
3722
+ await this.accountRegistryTail;
3669
3723
  const spaceId = this.ownedSpaceId(name);
3670
3724
  if (await this.isOwnedSpaceRegistered(spaceId)) {
3671
3725
  return spaceId;
3672
3726
  }
3673
- const hosted = await this.hostOwnedSpace(name);
3674
- try {
3675
- await this.account.spaces.register({
3676
- spaceId,
3677
- name,
3678
- ownerDid: this.did,
3679
- type: "owned",
3680
- permissions: ["*"],
3681
- status: "active"
3682
- });
3683
- } catch {
3684
- }
3685
- return hosted;
3727
+ return this.hostOwnedSpace(name);
3686
3728
  }
3687
3729
  /** Resolve and authenticate the owner encoded by an owned-space URI. */
3688
3730
  credentialSpaceOwnerDid(spaceId) {
@@ -4235,6 +4277,46 @@ var _TinyCloudNode = class _TinyCloudNode {
4235
4277
  if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
4236
4278
  return signBytesWithJwk(bytes, session.jwk);
4237
4279
  }
4280
+ /** Author a proofless Policy/v3 owner root with the authenticated holder key. */
4281
+ async createUnifiedOwnerRoot(input) {
4282
+ const ownerDid = this.credentialHolderDid;
4283
+ if (input.ownerDid !== ownerDid) throw new Error("unified owner root signer does not match owner DID");
4284
+ const facts = {
4285
+ role: input.role,
4286
+ mode: input.role === "policy-authority" ? "policy-source" : "conditional-mint",
4287
+ ownerDid,
4288
+ policyId: input.policyId,
4289
+ policyDigestHex: input.policyDigestHex,
4290
+ policyCid: input.policyCid,
4291
+ contentSourceDigestHex: input.contentSourceDigestHex,
4292
+ capabilityCeilingHashHex: input.capabilityCeilingHashHex,
4293
+ nativeProjectionHashHex: input.nativeProjectionHashHex,
4294
+ nodeAudience: input.nodeAudience,
4295
+ ...input.role === "policy-enforcement" ? { enforcerDid: input.audienceDid } : {}
4296
+ };
4297
+ const root = await signCompactUcanRootAuthorization({
4298
+ issuerDid: ownerDid,
4299
+ audienceDid: input.audienceDid,
4300
+ attenuation: unifiedRootAttenuation(input.capabilities),
4301
+ facts: [facts],
4302
+ notBefore: Math.floor(input.notBefore.getTime() / 1e3),
4303
+ expiresAt: Math.floor(input.expiresAt.getTime() / 1e3),
4304
+ nonce: base64UrlEncode(crypto.getRandomValues(new Uint8Array(16))),
4305
+ sign: (bytes) => this.signSessionBytes(bytes)
4306
+ });
4307
+ const kv = input.capabilities.find((capability) => capability.kind === "kv");
4308
+ const resource = kv?.resource ?? "";
4309
+ const marker = resource.indexOf("/kv/");
4310
+ return {
4311
+ cid: root.cid,
4312
+ delegationHeader: { Authorization: root.authorization },
4313
+ delegateDID: input.audienceDid,
4314
+ spaceId: marker === -1 ? "" : resource.slice("tinycloud://".length, marker),
4315
+ path: marker === -1 ? resource : resource.slice(marker + 4),
4316
+ actions: kv?.actions ?? [],
4317
+ expiry: input.expiresAt
4318
+ };
4319
+ }
4238
4320
  /** Apply only an already-enabled signing policy to the exact credential request. */
4239
4321
  async autoSignCredentialBytes(bytes) {
4240
4322
  const strategy = this.config.signStrategy;
@@ -7288,8 +7370,341 @@ import {
7288
7370
  // src/delegation.ts
7289
7371
  import {
7290
7372
  canonicalizeRecapCaveats as canonicalizeRecapCaveats2,
7373
+ decodeBase64Url,
7291
7374
  principalDidEquals as principalDidEquals3
7292
7375
  } from "@tinycloud/sdk-core";
7376
+ var SERVICE_BY_SHORT_NAME = {
7377
+ kv: "tinycloud.kv",
7378
+ sql: "tinycloud.sql",
7379
+ duckdb: "tinycloud.duckdb",
7380
+ hooks: "tinycloud.hooks"
7381
+ };
7382
+ function authorizationWithoutBearer(authorization) {
7383
+ return authorization.replace(/^Bearer /i, "");
7384
+ }
7385
+ function normalizedHost(host) {
7386
+ if (typeof host !== "string" || host.length === 0) {
7387
+ throw new Error("Validated runtime delegation requires a non-empty host.");
7388
+ }
7389
+ return host.replace(/\/+$/, "");
7390
+ }
7391
+ function didPrincipalsMatch(left, right) {
7392
+ try {
7393
+ return principalDidEquals3(left, right);
7394
+ } catch {
7395
+ return left === right;
7396
+ }
7397
+ }
7398
+ function compactUcanPayload(authorization) {
7399
+ const compact = authorizationWithoutBearer(authorization);
7400
+ const parts = compact.split(".");
7401
+ if (parts.length !== 3 || parts.some((part) => part.length === 0)) {
7402
+ throw new Error(
7403
+ "Validated runtime delegation requires a compact UCAN authorization so its signed authority can be derived."
7404
+ );
7405
+ }
7406
+ try {
7407
+ const payload = JSON.parse(
7408
+ new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64Url(parts[1]))
7409
+ );
7410
+ if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
7411
+ throw new Error("payload is not an object");
7412
+ }
7413
+ return payload;
7414
+ } catch {
7415
+ throw new Error(
7416
+ "Validated runtime delegation authorization has an invalid compact UCAN payload."
7417
+ );
7418
+ }
7419
+ }
7420
+ function canonicalPermissionEntries(permissions) {
7421
+ return permissions.map((permission) => ({
7422
+ ...permission,
7423
+ actions: [...permission.actions].sort()
7424
+ })).sort(
7425
+ (left, right) => left.service.localeCompare(right.service) || (left.space ?? "").localeCompare(right.space ?? "") || left.path.localeCompare(right.path) || left.actions.join("\0").localeCompare(right.actions.join("\0")) || canonicalizeRecapCaveats2(left.caveats).localeCompare(canonicalizeRecapCaveats2(right.caveats))
7426
+ );
7427
+ }
7428
+ function signedCaveats(value) {
7429
+ if (!Array.isArray(value) || value.some(
7430
+ (caveat) => caveat === null || typeof caveat !== "object" || Array.isArray(caveat)
7431
+ )) {
7432
+ throw new Error("Validated runtime delegation has malformed signed ReCap caveats.");
7433
+ }
7434
+ const cloned = JSON.parse(JSON.stringify(value));
7435
+ return canonicalizeRecapCaveats2(cloned) === canonicalizeRecapCaveats2(void 0) ? void 0 : cloned;
7436
+ }
7437
+ function groupedSignedEntries(service, space, path, abilities) {
7438
+ const groups = /* @__PURE__ */ new Map();
7439
+ for (const [action, rawCaveats] of Object.entries(abilities)) {
7440
+ const caveats = signedCaveats(rawCaveats);
7441
+ const identity = canonicalizeRecapCaveats2(caveats);
7442
+ const group = groups.get(identity) ?? { actions: [], caveats };
7443
+ group.actions.push(action);
7444
+ groups.set(identity, group);
7445
+ }
7446
+ return [...groups.values()].map((group) => ({
7447
+ service,
7448
+ ...space === void 0 ? {} : { space },
7449
+ path,
7450
+ actions: group.actions.sort(),
7451
+ ...group.caveats === void 0 ? {} : { caveats: group.caveats }
7452
+ }));
7453
+ }
7454
+ function signedAuthorityFromCompactUcan(authorization) {
7455
+ const payload = compactUcanPayload(authorization);
7456
+ if (typeof payload.aud !== "string" || payload.aud.length === 0) {
7457
+ throw new Error("Validated runtime delegation is missing a signed audience.");
7458
+ }
7459
+ if (typeof payload.iss !== "string" || payload.iss.length === 0) {
7460
+ throw new Error("Validated runtime delegation is missing a signed issuer.");
7461
+ }
7462
+ if (!Array.isArray(payload.prf) || payload.prf.some(
7463
+ (proof) => typeof proof !== "string" || proof.length === 0
7464
+ )) {
7465
+ throw new Error("Validated runtime delegation has malformed signed proofs.");
7466
+ }
7467
+ if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp)) {
7468
+ throw new Error("Validated runtime delegation is missing a signed expiry.");
7469
+ }
7470
+ const expiry = new Date(payload.exp * 1e3);
7471
+ if (Number.isNaN(expiry.getTime())) {
7472
+ throw new Error("Validated runtime delegation has an invalid signed expiry.");
7473
+ }
7474
+ if (payload.att === null || typeof payload.att !== "object" || Array.isArray(payload.att)) {
7475
+ throw new Error("Validated runtime delegation is missing a signed attenuation.");
7476
+ }
7477
+ const fact = Array.isArray(payload.fct) && payload.fct.length > 0 && payload.fct[0] !== null && typeof payload.fct[0] === "object" && !Array.isArray(payload.fct[0]) ? payload.fct[0] : void 0;
7478
+ const remainingRedelegationDepth = fact?.remainingRedelegationDepth;
7479
+ if (remainingRedelegationDepth !== void 0 && (!Number.isInteger(remainingRedelegationDepth) || remainingRedelegationDepth < 0 || remainingRedelegationDepth > 8)) {
7480
+ throw new Error("Validated runtime delegation has invalid signed redelegation depth.");
7481
+ }
7482
+ const permissions = [];
7483
+ for (const [resource, abilities] of Object.entries(payload.att)) {
7484
+ if (abilities === null || typeof abilities !== "object" || Array.isArray(abilities)) {
7485
+ throw new Error("Validated runtime delegation has an invalid signed attenuation.");
7486
+ }
7487
+ const abilityEntries = Object.entries(abilities);
7488
+ if (abilityEntries.length === 0) {
7489
+ throw new Error("Validated runtime delegation has an empty signed capability.");
7490
+ }
7491
+ if (resource.startsWith("urn:tinycloud:encryption:")) {
7492
+ permissions.push(...groupedSignedEntries(
7493
+ "tinycloud.encryption",
7494
+ void 0,
7495
+ resource,
7496
+ abilities
7497
+ ));
7498
+ continue;
7499
+ }
7500
+ const nativeMatch = /^(tinycloud:[^/]+)\/(kv|sql|duckdb|hooks)\/(.*)$/.exec(resource);
7501
+ const policyMatch = /^tinycloud:\/\/([^/]+)\/(kv|sql|duckdb|hooks)\/(.*)$/.exec(resource);
7502
+ const match = nativeMatch ?? policyMatch;
7503
+ if (!match) {
7504
+ throw new Error(
7505
+ `Validated runtime delegation has an unsupported signed resource '${resource}'.`
7506
+ );
7507
+ }
7508
+ const [, space, shortService, path] = match;
7509
+ const service = SERVICE_BY_SHORT_NAME[shortService];
7510
+ if (service === void 0) {
7511
+ throw new Error(
7512
+ `Validated runtime delegation has an unsupported signed service '${shortService}'.`
7513
+ );
7514
+ }
7515
+ permissions.push(...groupedSignedEntries(
7516
+ service,
7517
+ space,
7518
+ path,
7519
+ abilities
7520
+ ));
7521
+ }
7522
+ if (permissions.length === 0) {
7523
+ throw new Error("Validated runtime delegation has no signed capabilities.");
7524
+ }
7525
+ const canonicalPermissions = canonicalPermissionEntries(permissions);
7526
+ const canonicalResources = canonicalPermissions.map((permission) => ({
7527
+ service: permission.service === "tinycloud.encryption" ? "encryption" : permission.service.slice("tinycloud.".length),
7528
+ space: permission.service === "tinycloud.encryption" ? "encryption" : permission.space,
7529
+ path: permission.path,
7530
+ actions: [...permission.actions],
7531
+ ...permission.caveats === void 0 ? {} : { caveats: permission.caveats }
7532
+ }));
7533
+ return {
7534
+ issuer: payload.iss,
7535
+ audience: payload.aud,
7536
+ expiry,
7537
+ proofs: [...payload.prf],
7538
+ ...remainingRedelegationDepth === void 0 ? {} : { remainingRedelegationDepth },
7539
+ permissions: canonicalPermissions,
7540
+ resources: canonicalResources
7541
+ };
7542
+ }
7543
+ function canonicalResourcesFromPortableDelegation(delegation) {
7544
+ if (delegation.resources !== void 0 && delegation.resources.length > 0) {
7545
+ return delegation.resources.map((resource) => ({ ...resource, actions: [...resource.actions].sort() })).sort(
7546
+ (left, right) => left.service.localeCompare(right.service) || left.space.localeCompare(right.space) || left.path.localeCompare(right.path) || left.actions.join("\0").localeCompare(right.actions.join("\0")) || canonicalizeRecapCaveats2(left.caveats).localeCompare(canonicalizeRecapCaveats2(right.caveats))
7547
+ );
7548
+ }
7549
+ const byService = /* @__PURE__ */ new Map();
7550
+ for (const action of delegation.actions) {
7551
+ const [service] = action.split("/", 1);
7552
+ const shortService = service.replace(/^tinycloud\./, "");
7553
+ const values = byService.get(shortService) ?? [];
7554
+ values.push(action);
7555
+ byService.set(shortService, values);
7556
+ }
7557
+ return [...byService.entries()].map(([service, actions]) => ({
7558
+ service,
7559
+ space: service === "encryption" ? "encryption" : delegation.spaceId,
7560
+ path: delegation.path,
7561
+ actions: [...new Set(actions)].sort(),
7562
+ ...delegation.caveats === void 0 ? {} : { caveats: delegation.caveats }
7563
+ })).sort(
7564
+ (left, right) => left.service.localeCompare(right.service) || left.space.localeCompare(right.space) || left.path.localeCompare(right.path)
7565
+ );
7566
+ }
7567
+ function resourcesMatch(actual, expected) {
7568
+ const comparable = (resource) => ({
7569
+ ...resource,
7570
+ caveats: canonicalizeRecapCaveats2(resource.caveats)
7571
+ });
7572
+ return JSON.stringify(actual.map(comparable)) === JSON.stringify(expected.map(comparable));
7573
+ }
7574
+ async function activateValidatedRuntimeDelegation(node, delegation, options) {
7575
+ const host = normalizedHost(options.host);
7576
+ if (delegation.host !== void 0 && normalizedHost(delegation.host) !== host) {
7577
+ throw new Error(
7578
+ `Runtime delegation host '${delegation.host}' does not match expected host '${options.host}'.`
7579
+ );
7580
+ }
7581
+ if (!(delegation.expiry instanceof Date) || Number.isNaN(delegation.expiry.getTime())) {
7582
+ throw new Error("Runtime delegation has an invalid expiry.");
7583
+ }
7584
+ if (delegation.expiry.getTime() <= Date.now()) {
7585
+ throw new Error("Runtime delegation is expired.");
7586
+ }
7587
+ const authorization = delegation.delegationHeader?.Authorization;
7588
+ if (typeof authorization !== "string" || authorization.length === 0) {
7589
+ throw new Error("Runtime delegation is missing authorization bytes.");
7590
+ }
7591
+ const cid = node.computeDelegationCid(authorization);
7592
+ if (cid !== delegation.cid) {
7593
+ throw new Error("Runtime delegation CID does not match authorization bytes.");
7594
+ }
7595
+ const signed = signedAuthorityFromCompactUcan(authorization);
7596
+ if (signed.expiry.getTime() <= Date.now()) {
7597
+ throw new Error("Runtime delegation is expired.");
7598
+ }
7599
+ if (delegation.expiry.getTime() !== signed.expiry.getTime()) {
7600
+ throw new Error("Runtime delegation expiry does not match signed authority.");
7601
+ }
7602
+ if (!didPrincipalsMatch(signed.audience, node.sessionDid)) {
7603
+ throw new Error(
7604
+ `Runtime delegation targets ${signed.audience} but this session is ${node.sessionDid}.`
7605
+ );
7606
+ }
7607
+ if (!didPrincipalsMatch(delegation.delegateDID, signed.audience)) {
7608
+ throw new Error("Runtime delegation audience does not match signed authority.");
7609
+ }
7610
+ const declaredResources = canonicalResourcesFromPortableDelegation(delegation);
7611
+ if (!resourcesMatch(declaredResources, signed.resources)) {
7612
+ throw new Error("Runtime delegation resources do not match signed authority.");
7613
+ }
7614
+ const previouslyInstalled = node.getRuntimePermissionDelegations().find((candidate) => candidate.cid === cid);
7615
+ if (previouslyInstalled !== void 0 && previouslyInstalled.delegationHeader.Authorization !== authorization) {
7616
+ throw new Error(
7617
+ "A different authorization is already installed for this runtime delegation CID."
7618
+ );
7619
+ }
7620
+ const primary = signed.resources[0];
7621
+ const signedSpace = signed.permissions.find(
7622
+ (permission) => permission.service !== "tinycloud.encryption"
7623
+ )?.space;
7624
+ const installedCandidate = {
7625
+ cid,
7626
+ delegationHeader: { Authorization: authorization },
7627
+ ownerAddress: delegation.ownerAddress,
7628
+ chainId: delegation.chainId,
7629
+ delegatorDID: signed.issuer,
7630
+ ...signed.proofs.length === 1 ? { parentCid: signed.proofs[0] } : {},
7631
+ ...signed.remainingRedelegationDepth === void 0 ? {} : {
7632
+ allowSubDelegation: signed.remainingRedelegationDepth > 0,
7633
+ disableSubDelegation: signed.remainingRedelegationDepth === 0
7634
+ },
7635
+ authHeader: authorization,
7636
+ spaceId: signedSpace ?? delegation.spaceId,
7637
+ path: primary.path,
7638
+ actions: [...primary.actions],
7639
+ ...primary.caveats === void 0 ? {} : { caveats: primary.caveats },
7640
+ resources: signed.resources.map((resource) => ({
7641
+ ...resource,
7642
+ actions: [...resource.actions]
7643
+ })),
7644
+ expiry: new Date(signed.expiry),
7645
+ delegateDID: signed.audience,
7646
+ host
7647
+ };
7648
+ if (node.isSessionOnly === true && typeof node.did === "string" && principalDidEquals3(node.did, node.sessionDid) && typeof node.useDelegation === "function") {
7649
+ await node.useDelegation(installedCandidate);
7650
+ } else {
7651
+ await node.useRuntimeDelegation(installedCandidate);
7652
+ }
7653
+ const installed = node.getRuntimePermissionDelegations().find((candidate) => candidate.cid === cid);
7654
+ if (!installed) {
7655
+ throw new Error("Runtime delegation activation did not install the validated authority.");
7656
+ }
7657
+ if (installed.delegationHeader.Authorization !== authorization || !didPrincipalsMatch(installed.delegateDID, signed.audience) || installed.expiry.getTime() !== signed.expiry.getTime() || !resourcesMatch(
7658
+ canonicalResourcesFromPortableDelegation(installed),
7659
+ signed.resources
7660
+ ) || normalizedHost(installed.host ?? "") !== host) {
7661
+ throw new Error(
7662
+ "Runtime delegation activation installed authority that differs from the validated authority."
7663
+ );
7664
+ }
7665
+ return {
7666
+ cid,
7667
+ delegation: installed,
7668
+ effectivePermissions: signed.permissions,
7669
+ expiry: new Date(signed.expiry),
7670
+ audience: signed.audience,
7671
+ host: normalizedHost(installed.host ?? host)
7672
+ };
7673
+ }
7674
+ async function activateCompactRuntimeDelegation(node, input) {
7675
+ const authorization = input.authorization;
7676
+ const cid = node.computeDelegationCid(authorization);
7677
+ if (cid !== input.cid) {
7678
+ throw new Error("Compact runtime delegation CID does not match authorization bytes.");
7679
+ }
7680
+ const signed = signedAuthorityFromCompactUcan(authorization);
7681
+ const primary = signed.resources[0];
7682
+ const signedSpace = signed.permissions.find(
7683
+ (permission) => permission.service !== "tinycloud.encryption"
7684
+ )?.space;
7685
+ const delegation = {
7686
+ cid,
7687
+ delegationHeader: { Authorization: authorization },
7688
+ ownerAddress: input.ownerAddress,
7689
+ chainId: input.chainId,
7690
+ delegatorDID: signed.issuer,
7691
+ authHeader: authorization,
7692
+ spaceId: signedSpace ?? primary.space,
7693
+ path: primary.path,
7694
+ actions: [...primary.actions],
7695
+ ...primary.caveats === void 0 ? {} : { caveats: primary.caveats },
7696
+ resources: signed.resources.map((resource) => ({
7697
+ ...resource,
7698
+ actions: [...resource.actions]
7699
+ })),
7700
+ expiry: new Date(signed.expiry),
7701
+ delegateDID: signed.audience,
7702
+ host: normalizedHost(input.host)
7703
+ };
7704
+ return activateValidatedRuntimeDelegation(node, delegation, {
7705
+ host: input.host
7706
+ });
7707
+ }
7293
7708
  function serializeDelegation(delegation) {
7294
7709
  return JSON.stringify({
7295
7710
  ...delegation,
@@ -7404,6 +7819,7 @@ export {
7404
7819
  VaultPublicSpaceKVActions,
7405
7820
  VersionCheckError,
7406
7821
  WasmKeyProvider,
7822
+ activateCompactRuntimeDelegation,
7407
7823
  addressStorageKey,
7408
7824
  buildSpaceUri,
7409
7825
  canonicalizeAddress3 as canonicalizeAddress,