@tinycloud/node-sdk 3.2.1-beta.0 → 3.2.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,7 +1,7 @@
1
1
  export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, AccountApplication, AccountApplicationListOptions, AccountApplicationRegisterOptions, AccountDelegation, AccountDelegationListOptions, AccountDelegationRevokeOptions, AccountIndexEnsureResult, AccountIndexRebuildResult, AccountIndexStatus, AccountIndexedReadOptions, AccountService, AccountServiceConfig, AccountSpace, AccountSpaceListOptions, AccountStatus, AuthorityRefusal, 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, KVListPage, KVReadThrough, KVReplicaHandle, KVReplicaSpec, KVReplicaStorage, KVReplicationController, KVReplicationDeps, KVResponse, KVService, KVServiceConfig, KVSignedReadUrlResponse, KeyInfo, KeyProvider, KeyType, LocalGetResult, LocalListResult, LocalReadMeta, LocalReplicaStatus, LocalSyncResult, Manifest, ManifestDefaults, ManifestRegistryRecord, ManifestSecretActions, ManifestValidationError, OpenKeyCallbackStrategy, OpenKeySigningRequestBody, OpenKeySigningResponseBody, OpenKeySigningStrategyOptions, ParsedSecretCatalogKey, PendingWriteRecord, PendingWriteState, PendingWriteStore, PermissionEntry, PermissionNotInManifestError, PersistedSessionData, PinnedKey, PkhDidParts, PrefixedKVService, ProtocolMismatchError, PurgeTarget, QueryOptions, QueryResponse, ReceiveOptions, RegisterBatchSuccess, RegisterPolicyV3Input, RegisterPolicyV3Receipt, ReplicaAuthorityState, ReplicaCoverage, ReplicaDevice, ReplicaGrantInfo, ReplicaState, ReplicaStatusEntry, ReplicationAuthority, ReplicationControl, ReplicationEvent, ReplicationIdentity, ReplicationOptions, ReplicationPurgeReport, ReplicationReason, ReplicationScheduler, ResolvedCapabilities, ResolvedDelegate, ResolvedReplicationOptions, ResolvedSecretPath, ResourceCapability, SECRET_NAME_RE, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, SecretCatalogEntry, 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, parseSecretCatalogKey, parseSpaceUri, pkhDid, principalDid, principalDidEquals, resolveManifest, resolveSecretListPrefix, resolveSecretPath, resourceCapabilitiesToSpaceAbilitiesMap, tinyCloudDebugLogger, validateManifest } from '@tinycloud/sdk-core';
2
2
  import { _ as __authority } from './authority-DDGtccBK.cjs';
3
3
  import { _ as __runtime } from './runtime-B5P5SRpC.cjs';
4
- 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, I as InvalidRestoredSessionError, M as MemorySessionStorage, N as NodeEventEmitterStrategy, j as NodeUserAuthorization, k as NodeUserAuthorizationConfig, O as OwnerDelegationReceipt, P as PortableDelegation, p as RuntimePermissionGrantOptions, S as SecretPermissionHint, q as SecretReadInput, r as SecretReadResult, t as SignStrategy, T as TinyCloudNode, u as TinyCloudNodeConfig, U as UnifiedOwnerRootInput, v as UnifiedOwnerRootReceipt, w as UnsupportedSessionRestoreError, V as ValidatedRuntimeDelegation, W as WasmKeyProvider, y as WasmKeyProviderConfig, z as activateCompactRuntimeDelegation, H as createWasmKeyProvider, J as defaultSignStrategy, K as deserializeDelegation, Q as serializeDelegation } from './WasmKeyProvider-6_YwgSkd.cjs';
4
+ 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, I as InvalidRestoredSessionError, M as MemorySessionStorage, N as NodeEventEmitterStrategy, j as NodeUserAuthorization, k as NodeUserAuthorizationConfig, O as OwnerDelegationReceipt, P as PortableDelegation, p as RuntimePermissionGrantOptions, S as SecretPermissionHint, q as SecretReadInput, r as SecretReadResult, t as SignStrategy, T as TinyCloudNode, u as TinyCloudNodeConfig, U as UnifiedOwnerRootInput, v as UnifiedOwnerRootReceipt, w as UnsupportedSessionRestoreError, V as ValidatedRuntimeDelegation, W as WasmKeyProvider, y as WasmKeyProviderConfig, z as activateCompactRuntimeDelegation, H as createWasmKeyProvider, J as defaultSignStrategy, K as deserializeDelegation, Q as serializeDelegation } from './WasmKeyProvider-DRlOpvpG.cjs';
5
5
  import '@tinycloud/sdk-services';
6
6
  import 'events';
7
7
 
package/dist/core.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, AccountApplication, AccountApplicationListOptions, AccountApplicationRegisterOptions, AccountDelegation, AccountDelegationListOptions, AccountDelegationRevokeOptions, AccountIndexEnsureResult, AccountIndexRebuildResult, AccountIndexStatus, AccountIndexedReadOptions, AccountService, AccountServiceConfig, AccountSpace, AccountSpaceListOptions, AccountStatus, AuthorityRefusal, 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, KVListPage, KVReadThrough, KVReplicaHandle, KVReplicaSpec, KVReplicaStorage, KVReplicationController, KVReplicationDeps, KVResponse, KVService, KVServiceConfig, KVSignedReadUrlResponse, KeyInfo, KeyProvider, KeyType, LocalGetResult, LocalListResult, LocalReadMeta, LocalReplicaStatus, LocalSyncResult, Manifest, ManifestDefaults, ManifestRegistryRecord, ManifestSecretActions, ManifestValidationError, OpenKeyCallbackStrategy, OpenKeySigningRequestBody, OpenKeySigningResponseBody, OpenKeySigningStrategyOptions, ParsedSecretCatalogKey, PendingWriteRecord, PendingWriteState, PendingWriteStore, PermissionEntry, PermissionNotInManifestError, PersistedSessionData, PinnedKey, PkhDidParts, PrefixedKVService, ProtocolMismatchError, PurgeTarget, QueryOptions, QueryResponse, ReceiveOptions, RegisterBatchSuccess, RegisterPolicyV3Input, RegisterPolicyV3Receipt, ReplicaAuthorityState, ReplicaCoverage, ReplicaDevice, ReplicaGrantInfo, ReplicaState, ReplicaStatusEntry, ReplicationAuthority, ReplicationControl, ReplicationEvent, ReplicationIdentity, ReplicationOptions, ReplicationPurgeReport, ReplicationReason, ReplicationScheduler, ResolvedCapabilities, ResolvedDelegate, ResolvedReplicationOptions, ResolvedSecretPath, ResourceCapability, SECRET_NAME_RE, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, SecretCatalogEntry, 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, parseSecretCatalogKey, parseSpaceUri, pkhDid, principalDid, principalDidEquals, resolveManifest, resolveSecretListPrefix, resolveSecretPath, resourceCapabilitiesToSpaceAbilitiesMap, tinyCloudDebugLogger, validateManifest } from '@tinycloud/sdk-core';
2
2
  import { _ as __authority } from './authority-DDGtccBK.js';
3
3
  import { _ as __runtime } from './runtime-B5P5SRpC.js';
4
- 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, I as InvalidRestoredSessionError, M as MemorySessionStorage, N as NodeEventEmitterStrategy, j as NodeUserAuthorization, k as NodeUserAuthorizationConfig, O as OwnerDelegationReceipt, P as PortableDelegation, p as RuntimePermissionGrantOptions, S as SecretPermissionHint, q as SecretReadInput, r as SecretReadResult, t as SignStrategy, T as TinyCloudNode, u as TinyCloudNodeConfig, U as UnifiedOwnerRootInput, v as UnifiedOwnerRootReceipt, w as UnsupportedSessionRestoreError, V as ValidatedRuntimeDelegation, W as WasmKeyProvider, y as WasmKeyProviderConfig, z as activateCompactRuntimeDelegation, H as createWasmKeyProvider, J as defaultSignStrategy, K as deserializeDelegation, Q as serializeDelegation } from './WasmKeyProvider-6_YwgSkd.js';
4
+ 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, I as InvalidRestoredSessionError, M as MemorySessionStorage, N as NodeEventEmitterStrategy, j as NodeUserAuthorization, k as NodeUserAuthorizationConfig, O as OwnerDelegationReceipt, P as PortableDelegation, p as RuntimePermissionGrantOptions, S as SecretPermissionHint, q as SecretReadInput, r as SecretReadResult, t as SignStrategy, T as TinyCloudNode, u as TinyCloudNodeConfig, U as UnifiedOwnerRootInput, v as UnifiedOwnerRootReceipt, w as UnsupportedSessionRestoreError, V as ValidatedRuntimeDelegation, W as WasmKeyProvider, y as WasmKeyProviderConfig, z as activateCompactRuntimeDelegation, H as createWasmKeyProvider, J as defaultSignStrategy, K as deserializeDelegation, Q as serializeDelegation } from './WasmKeyProvider-DRlOpvpG.js';
5
5
  import '@tinycloud/sdk-services';
6
6
  import 'events';
7
7
 
package/dist/core.js CHANGED
@@ -390,6 +390,11 @@ var NodeUserAuthorization = class {
390
390
  this._nodeFeatures = [];
391
391
  this._nodeFeaturesKnown = false;
392
392
  this._lastActivationSkippedSpaceIds = [];
393
+ /**
394
+ * Spaces the sign-in activation reported hosted. Only the first POST of a
395
+ * delegation lists them: the node answers a repeat with empty lists.
396
+ */
397
+ this._lastActivationActivatedSpaceIds = [];
393
398
  this.wasm = config.wasmBindings;
394
399
  this.signer = config.signer;
395
400
  this.signStrategy = config.signStrategy ?? defaultSignStrategy;
@@ -519,6 +524,7 @@ var NodeUserAuthorization = class {
519
524
  this._nodeInfoIdentity = void 0;
520
525
  this.tinycloudHosts = hosts && hosts.length > 0 ? [...hosts] : void 0;
521
526
  this._lastActivationSkippedSpaceIds = [];
527
+ this._lastActivationActivatedSpaceIds = [];
522
528
  if (!session) {
523
529
  this._session = void 0;
524
530
  this._tinyCloudSession = void 0;
@@ -613,6 +619,9 @@ var NodeUserAuthorization = class {
613
619
  get lastActivationSkippedSpaceIds() {
614
620
  return [...this._lastActivationSkippedSpaceIds];
615
621
  }
622
+ get lastActivationActivatedSpaceIds() {
623
+ return [...this._lastActivationActivatedSpaceIds];
624
+ }
616
625
  /**
617
626
  * Compute the `abilities` map the WASM `prepareSession` call should
618
627
  * see at sign-in time.
@@ -1108,8 +1117,10 @@ var NodeUserAuthorization = class {
1108
1117
  recordActivationSkippedSpaces(result, primarySpaceId) {
1109
1118
  if (result.success) {
1110
1119
  this._lastActivationSkippedSpaceIds = result.skipped ?? [];
1120
+ this._lastActivationActivatedSpaceIds = result.activated ?? [];
1111
1121
  return;
1112
1122
  }
1123
+ this._lastActivationActivatedSpaceIds = [];
1113
1124
  this._lastActivationSkippedSpaceIds = result.status === 404 ? [primarySpaceId] : [];
1114
1125
  }
1115
1126
  async createBootstrapSession(options) {
@@ -3456,10 +3467,26 @@ var _TinyCloudNode = class _TinyCloudNode {
3456
3467
  * hosting is confirmed against the session that was active at the time.
3457
3468
  */
3458
3469
  this.confirmedHostedSpaceIds = /* @__PURE__ */ new Set();
3470
+ /**
3471
+ * Owned space ids known to be hosted for the current session: the sign-in
3472
+ * activation listed them as `activated`, or this session hosted them. Unlike
3473
+ * {@link confirmedHostedSpaceIds}, nothing here is inferred from a space being
3474
+ * merely absent from `skipped`. Read by {@link ensureOwnedSpaceHosted}.
3475
+ */
3476
+ this.hostedOwnedSpaceIds = /* @__PURE__ */ new Set();
3477
+ /**
3478
+ * In-flight host delegations, so concurrent callers share one approval per
3479
+ * space. `waiters` counts callers still waiting; the request is cancelled
3480
+ * once every caller with a signal has aborted and none waits without one.
3481
+ */
3482
+ this.ownedSpaceHosts = /* @__PURE__ */ new Map();
3459
3483
  /** Serializes account-registry writes for the active node instance. */
3460
3484
  this.accountRegistryTail = Promise.resolve();
3461
- /** Bounds best-effort registry work on the sign-in critical path. */
3462
- this.accountRegistryDeadlineMs = 4e3;
3485
+ /**
3486
+ * Hang guard for the background registry sync. It is off the sign-in path,
3487
+ * so it must outlast a slow but healthy sync (9–18 s on prod 1.20.2, TC-998).
3488
+ */
3489
+ this.accountRegistryDeadlineMs = 3e4;
3463
3490
  /**
3464
3491
  * True when the last signIn() detected an interactive signer and skipped
3465
3492
  * client-side bootstrap. Apps can read this to know whether bootstrap was
@@ -4054,6 +4081,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4054
4081
  "Cannot signIn() in session-only mode. Provide a privateKey in config to create your own space."
4055
4082
  );
4056
4083
  }
4084
+ this.pendingAccountRegistrySync?.controller.abort();
4057
4085
  await this.accountRegistryTail;
4058
4086
  await this.wasmBindings.ensureInitialized?.();
4059
4087
  const address = canonicalizeAddress2(await this.signer.getAddress());
@@ -4074,8 +4102,13 @@ var _TinyCloudNode = class _TinyCloudNode {
4074
4102
  this._serviceContext = void 0;
4075
4103
  this.runtimePermissionGrants = [];
4076
4104
  this.confirmedHostedSpaceIds.clear();
4105
+ this.hostedOwnedSpaceIds.clear();
4077
4106
  await this.tc.signIn(options);
4107
+ this.cancelOwnedSpaceHosts();
4078
4108
  this.syncResolvedHostFromAuth();
4109
+ for (const spaceId of this.auth.lastActivationActivatedSpaceIds ?? []) {
4110
+ this.hostedOwnedSpaceIds.add(spaceId);
4111
+ }
4079
4112
  this.replicationDelegateSession = void 0;
4080
4113
  this.replicationScopeError = void 0;
4081
4114
  if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
@@ -4100,10 +4133,20 @@ var _TinyCloudNode = class _TinyCloudNode {
4100
4133
  }
4101
4134
  if (!bootstrapped) {
4102
4135
  this.scheduleAccountRegistrySync();
4103
- await this.accountRegistryTail;
4104
4136
  }
4105
4137
  this.notificationHandler.success("Successfully signed in");
4106
4138
  }
4139
+ /**
4140
+ * Wait for the account-registry sync that {@link signIn} starts in the
4141
+ * background (account index, this app's manifest record, space list).
4142
+ * Resolves once it has finished, failed or hit its hang guard; it never
4143
+ * rejects, and failures are logged as warnings. `signIn()` does not wait for
4144
+ * it, so call this only when you need the registry written, or before a first
4145
+ * write against a SQLite-backed node older than 1.20.2 (TC-899).
4146
+ */
4147
+ async waitForAccountRegistrySync() {
4148
+ await this.accountRegistryTail;
4149
+ }
4107
4150
  ownedSpaceId(name) {
4108
4151
  if (!this._address) {
4109
4152
  throw new Error("Cannot resolve owned space before sign-in");
@@ -4709,17 +4752,17 @@ var _TinyCloudNode = class _TinyCloudNode {
4709
4752
  clearTimeout(deadline);
4710
4753
  }
4711
4754
  });
4712
- this.pendingAccountRegistrySync = { session, promise };
4713
- const clearPendingSync = () => {
4755
+ this.pendingAccountRegistrySync = { session, promise, controller };
4756
+ const settle = () => {
4757
+ clearTimeout(deadline);
4714
4758
  if (this.pendingAccountRegistrySync?.promise === promise) {
4715
4759
  this.pendingAccountRegistrySync = void 0;
4716
4760
  }
4717
4761
  };
4718
- void promise.then(clearPendingSync, clearPendingSync);
4719
- void promise.then(
4720
- () => clearTimeout(deadline),
4721
- () => clearTimeout(deadline)
4722
- );
4762
+ void promise.then(settle, (error) => {
4763
+ settle();
4764
+ console.warn("TinyCloud account registry sync failed", error);
4765
+ });
4723
4766
  }
4724
4767
  enqueueAccountRegistryOperation(session, task) {
4725
4768
  const operation = this.accountRegistryTail.then(async () => {
@@ -4757,10 +4800,15 @@ var _TinyCloudNode = class _TinyCloudNode {
4757
4800
  }
4758
4801
  async withAccountRegistryRetry(task, signal) {
4759
4802
  const delays = [250, 1e3, 3e3];
4803
+ const stopped = (detail) => {
4804
+ if (signal.reason instanceof DOMException && signal.reason.name === "TimeoutError") {
4805
+ console.warn("TinyCloud account registry sync stopped: deadline exceeded", detail);
4806
+ }
4807
+ };
4760
4808
  let lastError;
4761
4809
  for (let attempt = 0; attempt < delays.length; attempt += 1) {
4762
4810
  if (signal.aborted) {
4763
- console.warn("TinyCloud account registry sync stopped: deadline exceeded", signal.reason);
4811
+ stopped(signal.reason);
4764
4812
  return;
4765
4813
  }
4766
4814
  try {
@@ -4768,7 +4816,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4768
4816
  return;
4769
4817
  } catch (error) {
4770
4818
  if (signal.aborted) {
4771
- console.warn("TinyCloud account registry sync stopped: deadline exceeded", error);
4819
+ stopped(error);
4772
4820
  return;
4773
4821
  }
4774
4822
  const verdict = authorizationVerdictOf(error);
@@ -4861,7 +4909,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4861
4909
  if (!session) {
4862
4910
  throw new Error("Owned space hosting requires an active session");
4863
4911
  }
4864
- if (this.confirmedHostedSpaceIds.has(spaceId)) {
4912
+ if (this.confirmedHostedSpaceIds.has(spaceId) || this.hostedOwnedSpaceIds.has(spaceId)) {
4865
4913
  return;
4866
4914
  }
4867
4915
  const host = this.hosts[0] ?? this.config.host;
@@ -4879,8 +4927,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4879
4927
  { cause: activation }
4880
4928
  );
4881
4929
  }
4882
- const authorization = this.auth;
4883
- const created = signal ? await authorization.hostOwnedSpaceResult(spaceId, void 0, signal) : await authorization.hostOwnedSpaceResult(spaceId);
4930
+ const created = await this.hostOwnedSpaceOnce(spaceId, signal);
4884
4931
  if (!created.success) {
4885
4932
  throw Object.assign(
4886
4933
  new Error(`Failed to create owned space ${spaceId}: ${describeHostFailure2(created)}`),
@@ -4897,7 +4944,10 @@ var _TinyCloudNode = class _TinyCloudNode {
4897
4944
  { cause: retry }
4898
4945
  );
4899
4946
  }
4900
- this.confirmedHostedSpaceIds.add(spaceId);
4947
+ if (this.auth.tinyCloudSession === session) {
4948
+ this.confirmedHostedSpaceIds.add(spaceId);
4949
+ this.hostedOwnedSpaceIds.add(spaceId);
4950
+ }
4901
4951
  }
4902
4952
  /**
4903
4953
  * Host one of this user's owned spaces by name (e.g. `"applications"`).
@@ -4929,7 +4979,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4929
4979
  if (!host) {
4930
4980
  throw new Error("Owned space hosting requires a TinyCloud host");
4931
4981
  }
4932
- const hosted = await this.auth.hostOwnedSpaceResult(spaceId);
4982
+ const hosted = await this.hostOwnedSpaceOnce(spaceId);
4933
4983
  if (!hosted.success) {
4934
4984
  throw Object.assign(
4935
4985
  new Error(`Failed to host owned space ${spaceId}: ${describeHostFailure2(hosted)}`),
@@ -4948,6 +4998,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4948
4998
  { cause: activation }
4949
4999
  );
4950
5000
  }
5001
+ if (this.auth?.tinyCloudSession === session) this.hostedOwnedSpaceIds.add(spaceId);
4951
5002
  try {
4952
5003
  await this.enqueueAccountRegistryOperation(session, async () => {
4953
5004
  await this.account.spaces.register({
@@ -4975,18 +5026,19 @@ var _TinyCloudNode = class _TinyCloudNode {
4975
5026
  * registered on the node.
4976
5027
  *
4977
5028
  * Calling this resolves `name` to the owner's owned-space URI
4978
- * (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`). It first consults the
4979
- * account-space spaces registry (`account/spaces/{space_id}`, the canonical
4980
- * KV source of truth, fronted by a best-effort SQLite index): if the space is
4981
- * already registered/hosted it returns the URI WITHOUT submitting a host
4982
- * delegation, avoiding a redundant host-SIWE signature prompt for owners who
4983
- * already use the space. Only when the space is absent — or the registry
4984
- * check fails for any reason (e.g. a cold SQLite index reporting
4985
- * `no such table: spaces`) — does it fall through to {@link hostOwnedSpace}.
4986
- *
4987
- * The registry check is purely an optimization: any failure falls back to
4988
- * hosting, and the host SIWE is idempotent server-side, so re-hosting an
4989
- * existing space remains a safe no-op. Must be called after {@link signIn}.
5029
+ * (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`). It returns WITHOUT
5030
+ * submitting a host delegation when the space is known to be hosted: the
5031
+ * sign-in activation listed it as `activated` (any space the session's recap
5032
+ * covers), this session already hosted it, or the account-space spaces
5033
+ * registry (`account/spaces/{space_id}`, the canonical KV source of truth,
5034
+ * fronted by a best-effort SQLite index) has its record. Otherwise it falls
5035
+ * through to {@link hostOwnedSpace}, which asks for a signature; a host
5036
+ * already in flight for the same space (e.g. from the background registry
5037
+ * sync) is shared rather than asked for twice.
5038
+ *
5039
+ * Hosting is still needed when the space really isn't hosted, or when the
5040
+ * session's recap doesn't cover it and the registry has no record; the host
5041
+ * SIWE is idempotent server-side. Must be called after {@link signIn}.
4990
5042
  *
4991
5043
  * @param name - The owned space name (e.g. `"secrets"`).
4992
5044
  * @returns The hosted owned-space URI.
@@ -4995,13 +5047,57 @@ var _TinyCloudNode = class _TinyCloudNode {
4995
5047
  if (!this.auth || !this.auth.tinyCloudSession) {
4996
5048
  throw new Error("Not signed in. Call signIn() first.");
4997
5049
  }
4998
- await this.accountRegistryTail;
4999
5050
  const spaceId = this.ownedSpaceId(name);
5000
- if (await this.isOwnedSpaceRegistered(spaceId)) {
5051
+ if (this.hostedOwnedSpaceIds.has(spaceId) || await this.isOwnedSpaceRegistered(spaceId)) {
5001
5052
  return spaceId;
5002
5053
  }
5003
5054
  return this.hostOwnedSpace(name);
5004
5055
  }
5056
+ /**
5057
+ * Submit the host delegation for an owned space, sharing one in-flight
5058
+ * request (and so one approval) between concurrent callers in this session,
5059
+ * such as the background registry sync and {@link ensureOwnedSpaceHosted}.
5060
+ * Each caller's `signal` releases only its own wait; the request itself is
5061
+ * cancelled once no caller is left waiting, or when the session is replaced
5062
+ * ({@link cancelOwnedSpaceHosts}), so a late approval is discarded.
5063
+ */
5064
+ hostOwnedSpaceOnce(spaceId, signal) {
5065
+ if (signal?.aborted) return Promise.reject(signal.reason);
5066
+ let entry = this.ownedSpaceHosts.get(spaceId);
5067
+ if (!entry) {
5068
+ const controller = new AbortController();
5069
+ const promise = this.auth.hostOwnedSpaceResult(spaceId, void 0, controller.signal);
5070
+ const created = { promise, controller, waiters: 0 };
5071
+ this.ownedSpaceHosts.set(spaceId, created);
5072
+ const forget = () => {
5073
+ if (this.ownedSpaceHosts.get(spaceId) === created) this.ownedSpaceHosts.delete(spaceId);
5074
+ };
5075
+ promise.then(forget, forget);
5076
+ entry = created;
5077
+ }
5078
+ if (!signal) {
5079
+ entry.waiters = Number.POSITIVE_INFINITY;
5080
+ return entry.promise;
5081
+ }
5082
+ entry.waiters += 1;
5083
+ const shared = entry;
5084
+ return new Promise((resolve, reject2) => {
5085
+ const onAbort = () => {
5086
+ reject2(signal.reason);
5087
+ shared.waiters -= 1;
5088
+ if (shared.waiters !== 0) return;
5089
+ shared.controller.abort(signal.reason);
5090
+ if (this.ownedSpaceHosts.get(spaceId) === shared) this.ownedSpaceHosts.delete(spaceId);
5091
+ };
5092
+ signal.addEventListener("abort", onAbort, { once: true });
5093
+ shared.promise.then(resolve, reject2).finally(() => signal.removeEventListener("abort", onAbort));
5094
+ });
5095
+ }
5096
+ /** Session replacement: cancel the replaced session's in-flight hosts and forget them. */
5097
+ cancelOwnedSpaceHosts() {
5098
+ for (const { controller } of this.ownedSpaceHosts.values()) controller.abort();
5099
+ this.ownedSpaceHosts.clear();
5100
+ }
5005
5101
  /** Resolve and authenticate the owner encoded by an owned-space URI. */
5006
5102
  credentialSpaceOwnerDid(spaceId) {
5007
5103
  const ownerDid = this.ownerDidFromSpaceId(spaceId);
@@ -5244,6 +5340,8 @@ var _TinyCloudNode = class _TinyCloudNode {
5244
5340
  sessionExpiry: stagedSessionExpiry,
5245
5341
  recap: stagedRecap
5246
5342
  });
5343
+ this.pendingAccountRegistrySync?.controller.abort();
5344
+ await this.accountRegistryTail;
5247
5345
  const oldGraph = this._serviceGraph;
5248
5346
  const oldCore = this.tc;
5249
5347
  this.sessionManager = stagedManager;
@@ -5277,6 +5375,8 @@ var _TinyCloudNode = class _TinyCloudNode {
5277
5375
  this._recapOperationsCache = stagedPrimary.cache;
5278
5376
  this.runtimePermissionGrants = stagedPrimary.grants;
5279
5377
  this.confirmedHostedSpaceIds.clear();
5378
+ this.hostedOwnedSpaceIds.clear();
5379
+ this.cancelOwnedSpaceHosts();
5280
5380
  this._restoredNodeFeatures = restoredNodeFeatures;
5281
5381
  if (this.auth) {
5282
5382
  this.auth.installRestoredSession(stagedManager, stagedTcSession, [stagedHost], restoredNodeFeatures);