@tinycloud/sdk-core 2.11.0-beta.3 → 2.11.0-beta.5

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/index.d.cts CHANGED
@@ -2487,6 +2487,13 @@ interface AccountSpace {
2487
2487
  updatedAt?: string;
2488
2488
  expiresAt?: Date;
2489
2489
  }
2490
+ interface RegisterBatchSuccess {
2491
+ spaces: AccountSpace[];
2492
+ /** Present iff the batch write failed ambiguously and per-space
2493
+ * reconciliation recovered it. The original batch error verbatim, so
2494
+ * callers can record the degradation structurally (TC-361). */
2495
+ recoveredFromBatchError?: ServiceError;
2496
+ }
2490
2497
  interface AccountDelegation {
2491
2498
  cid: string;
2492
2499
  direction: "granted" | "received";
@@ -2591,6 +2598,17 @@ declare class AccountService {
2591
2598
  list: (options?: AccountSpaceListOptions) => Promise<Result<AccountSpace[]>>;
2592
2599
  get: (spaceId: string) => Promise<Result<AccountSpace>>;
2593
2600
  register: (space: SpaceInfo | AccountSpace) => Promise<Result<AccountSpace>>;
2601
+ /**
2602
+ * Register multiple spaces in one KV batch write + one multi-row index
2603
+ * write, instead of one `register()` round trip per space (TC-373).
2604
+ *
2605
+ * The stored records are computed exactly once and reused for both the
2606
+ * batch attempt and any reconciliation below, so a fallback never mints a
2607
+ * fresh timestamp for a space that already has a written record — a
2608
+ * second `spaceRecordFromInput` call would produce a new content hash and
2609
+ * leave the first attempt's blocks orphaned.
2610
+ */
2611
+ registerBatch: (spaces: readonly (SpaceInfo | AccountSpace)[]) => Promise<Result<RegisterBatchSuccess>>;
2594
2612
  syncAccessible: () => Promise<Result<AccountSpace[]>>;
2595
2613
  remove: (spaceId: string) => Promise<Result<void>>;
2596
2614
  };
@@ -2623,6 +2641,16 @@ declare class AccountService {
2623
2641
  private deleteApplicationIndex;
2624
2642
  private upsertSpaceIndexQuietly;
2625
2643
  private upsertSpaceIndex;
2644
+ private upsertSpacesIndexQuietly;
2645
+ /**
2646
+ * Upsert multiple space index rows in ONE multi-row `INSERT OR REPLACE`
2647
+ * statement (TC-373), rather than one statement per space. This matters
2648
+ * because `IDatabaseHandle.batch()` executes its statement list as a plain
2649
+ * loop, not a single database transaction — an N-statement batch is not
2650
+ * atomic. A single multi-row INSERT is one SQLite statement, so it applies
2651
+ * atomically: all rows or none.
2652
+ */
2653
+ private upsertSpacesIndex;
2626
2654
  private deleteSpaceIndexQuietly;
2627
2655
  private deleteSpaceIndex;
2628
2656
  private resolveSpace;
@@ -2776,7 +2804,7 @@ interface LocationRecord extends LocationRecordPayload {
2776
2804
  type LocationSource = "explicit" | "local-loopback" | "local-link" | "blockchain" | "centralized" | "fallback";
2777
2805
  declare const DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL = "https://registry.tinycloud.xyz";
2778
2806
  declare const DEFAULT_TINYCLOUD_FALLBACK_HOST = "https://node.tinycloud.xyz";
2779
- /** Default local loopback node URL probed before registry/fallback resolution. */
2807
+ /** Conventional local loopback node URL. Probed only when explicitly configured. */
2780
2808
  declare const DEFAULT_LOCAL_NODE_URL = "http://127.0.0.1:8000";
2781
2809
  /** Probe timeout for the local loopback candidate. No retries. */
2782
2810
  declare const LOCAL_LOOPBACK_PROBE_TIMEOUT_MS = 250;
@@ -2863,7 +2891,7 @@ interface DiscoverLocalTinyCloudNodeOptions {
2863
2891
  subject?: string;
2864
2892
  /** Enable local-node auto-discovery. Default true. */
2865
2893
  autoDiscoverLocalNode?: boolean;
2866
- /** Local loopback node URL to probe. Default http://127.0.0.1:8000. */
2894
+ /** Local loopback node URL to probe. Omit to avoid probing loopback. */
2867
2895
  localNodeUrl?: string;
2868
2896
  /** Known `*.local.tinycloud.link` subdomain name, probed directly. */
2869
2897
  localLinkName?: string;
@@ -2897,12 +2925,12 @@ interface ResolveTinyCloudHostsOptions {
2897
2925
  /** Verify centralized/blockchain record signatures. Default true. */
2898
2926
  verifyRecords?: boolean;
2899
2927
  /**
2900
- * Probe for a locally-running TinyCloud node before falling back to
2901
- * registry/hosted resolution. Default true. Setting false restores the
2902
- * exact pre-TC-106 resolution order (registry → fallback).
2928
+ * Probe configured and registered local TinyCloud node endpoints before
2929
+ * falling back to registry/hosted resolution. Default true. The loopback
2930
+ * URL is probed only when `localNodeUrl` is explicitly configured.
2903
2931
  */
2904
2932
  autoDiscoverLocalNode?: boolean;
2905
- /** Local loopback node URL to probe. Default http://127.0.0.1:8000. */
2933
+ /** Local loopback node URL to probe. Omit to avoid probing loopback. */
2906
2934
  localNodeUrl?: string;
2907
2935
  /** Known `*.local.tinycloud.link` subdomain name, probed directly. */
2908
2936
  localLinkName?: string;
@@ -2988,4 +3016,4 @@ declare const EXPIRY: {
2988
3016
  declare const DEFAULT_SIGNED_READ_URL_EXPIRY_MS: number;
2989
3017
  type ExpiryTier = keyof typeof EXPIRY;
2990
3018
 
2991
- export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, type AbilitiesMap, type AccountApplication, type AccountApplicationListOptions, type AccountApplicationRegisterOptions, type AccountDelegation, type AccountDelegationListOptions, AccountDelegationPage, AccountDelegationQueryOptions, type AccountDelegationRevokeOptions, type AccountIndexEnsureResult, type AccountIndexRebuildResult, type AccountIndexStatus, type AccountIndexedReadOptions, AccountService, type AccountServiceConfig, type AccountSpace, type AccountSpaceListOptions, type AccountStatus, AutoApproveSpaceCreationHandler, type AutoRejectStrategy, type AutoSignStrategy, type Bytes, type CallbackStrategy, type CanonicalAddress, type CanonicalParsedNetworkId, CaveatedDelegationUnsupportedError, type ClientSession, ClientSessionSchema, CloudLocationResolutionError, type ComposeManifestOptions, type ComposedManifestRequest, type CreateDelegationFunction, CreateDelegationParams, DEFAULT_DEFAULTS, DEFAULT_EXPIRY, DEFAULT_KNOWLEDGE_ROOT, DEFAULT_LOCAL_NODE_PIN_STORAGE_KEY, DEFAULT_LOCAL_NODE_URL, DEFAULT_MANIFEST_SPACE, DEFAULT_MANIFEST_VERSION, DEFAULT_SIGNED_READ_URL_EXPIRY_MS, DEFAULT_TINYCLOUD_FALLBACK_HOST, DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL, Delegation, DelegationManager, DelegationRevocationReceipt, type DidCacheKeyOptions, type DidEqualsOptions, type DiscoverLocalTinyCloudNodeOptions, type DiscoveredLocalTinyCloudNode, ENCRYPTION_MANIFEST_SPACE, ENCRYPTION_PERMISSION_SERVICE, EXPIRY, type EnsData, EnsDataSchema, type EventEmitterStrategy, type ExpiryTier, type Extension, GenerateShareParams, ICapabilityKeyRegistry, type IENSResolver, type INotificationHandler, type ISessionManager, type ISessionStorage, ISharingService, type ISigner, type ISpace, type ISpaceCreationHandler, type ISpaceScopedDelegations, type ISpaceScopedSharing, type ISpaceService, type IUserAuthorization, type IWasmBindings, IdentityParseError, LOCAL_LINK_HOST_SUFFIX, LOCAL_LINK_PROBE_TIMEOUT_MS, LOCAL_LOOPBACK_PROBE_TIMEOUT_MS, type LocalNodeIdentityStore, type LocationCandidate, type LocationCandidateInput, type LocationRecord, type LocationRecordPayload, type LocationRecordSigner, LocationRecordValidationError, type LocationResolutionAttempt, type LocationSource, type Manifest, type ManifestDefaults, type ManifestKnowledge, type ManifestRegistryRecord, type ManifestSecretActions, ManifestValidationError, type NodeInfo, type OpenKeyCallbackStrategy, type OpenKeySigningRequestBody, type OpenKeySigningResponseBody, type OpenKeySigningStrategyOptions, type ParseRecapFromSiwe, type PartialSiweMessage, type PermissionEntry, PermissionNotInManifestError, type PersistedSessionData, type PersistedSessionProof, type PersistedTinyCloudSession, type PkhDidParts, ProtocolMismatchError, type ResolveCloudLocationOptions, type ResolveTinyCloudHostsOptions, type ResolvedCapabilities, type ResolvedCloudLocation, type ResolvedDelegate, type ResolvedTinyCloudHosts, type ResourceCapability, SECRETS_SPACE, SERVICE_LONG_TO_SHORT, SERVICE_SHORT_TO_LONG, type ServerHost, SessionExpiredError, ShareLink, type SignCallback, type SignInOptions, type SignRequest, type SignResponse, type SignStrategy, SilentNotificationHandler, type SiweConfig, SiweConfigSchema, Space, type SpaceAbilitiesMap, type SpaceConfig, type SpaceCreationContext, type SpaceDelegationParams, type SpaceErrorCode, SpaceErrorCodes, type SpaceHostResult, SpaceInfo, SpaceService, type SpaceServiceConfig, type SubsetCheckResult, TinyCloud, type TinyCloudConfig, type TinyCloudSession, UnsupportedFeatureError, type UserAuthorizationConfig, VAULT_PERMISSION_SERVICE, type ValidatedPersistedSessionProof, type ValidationError, VersionCheckError, type WasmRecapEntry, type WebStorageLike, actionContains, activateSessionWithHost, addressStorageKey, applyPrefix, buildSpaceUri, canonicalLocationPayload, canonicalizeAddress, canonicalizeDid, canonicalizeDidUrl, canonicalizeNetworkId, canonicalizeRecapCaveats, checkNodeInfo, composeManifestRequest, createInMemoryLocalNodeIdentityStore, createLocalStorageLocalNodeIdentityStore, createOpenKeyCallbackSigningStrategy, createSpaceService, defaultSignStrategy, defaultSpaceCreationHandler, didCacheKey, didEquals, discoverLocalTinyCloudNode, expandActionShortNames, expandPermissionEntries, expandPermissionEntry, fetchLocationRecord, fetchPeerId, httpUrlToMultiaddr, isCapabilitySubset, isEvmAddress, loadManifest, locationPayloadForRecord, makePkhSpaceId, makePublicSpaceId, manifestAbilitiesUnion, multiaddrToHttpUrl, normalizeDefaults, parseCanonicalNetworkId, parseExpiry, parsePkhDid, parseRecapCapabilities, parseSpaceUri, pkhDid, principalDid, principalDidEquals, recapCaveatsEqual, resolveCloudLocation, resolveManifest, resolveManifestKnowledgeRoot, resolveTinyCloudHosts, resourceCapabilitiesToAbilitiesMap, resourceCapabilitiesToSpaceAbilitiesMap, signLocationRecord, submitHostDelegation, validateClientSession, validateLocationRecord, validateLocationRecordPayload, validateManifest, validatePersistedSessionData, verifyDidKeyEd25519Signature, verifyLocationRecord };
3019
+ export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, type AbilitiesMap, type AccountApplication, type AccountApplicationListOptions, type AccountApplicationRegisterOptions, type AccountDelegation, type AccountDelegationListOptions, AccountDelegationPage, AccountDelegationQueryOptions, type AccountDelegationRevokeOptions, type AccountIndexEnsureResult, type AccountIndexRebuildResult, type AccountIndexStatus, type AccountIndexedReadOptions, AccountService, type AccountServiceConfig, type AccountSpace, type AccountSpaceListOptions, type AccountStatus, AutoApproveSpaceCreationHandler, type AutoRejectStrategy, type AutoSignStrategy, type Bytes, type CallbackStrategy, type CanonicalAddress, type CanonicalParsedNetworkId, CaveatedDelegationUnsupportedError, type ClientSession, ClientSessionSchema, CloudLocationResolutionError, type ComposeManifestOptions, type ComposedManifestRequest, type CreateDelegationFunction, CreateDelegationParams, DEFAULT_DEFAULTS, DEFAULT_EXPIRY, DEFAULT_KNOWLEDGE_ROOT, DEFAULT_LOCAL_NODE_PIN_STORAGE_KEY, DEFAULT_LOCAL_NODE_URL, DEFAULT_MANIFEST_SPACE, DEFAULT_MANIFEST_VERSION, DEFAULT_SIGNED_READ_URL_EXPIRY_MS, DEFAULT_TINYCLOUD_FALLBACK_HOST, DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL, Delegation, DelegationManager, DelegationRevocationReceipt, type DidCacheKeyOptions, type DidEqualsOptions, type DiscoverLocalTinyCloudNodeOptions, type DiscoveredLocalTinyCloudNode, ENCRYPTION_MANIFEST_SPACE, ENCRYPTION_PERMISSION_SERVICE, EXPIRY, type EnsData, EnsDataSchema, type EventEmitterStrategy, type ExpiryTier, type Extension, GenerateShareParams, ICapabilityKeyRegistry, type IENSResolver, type INotificationHandler, type ISessionManager, type ISessionStorage, ISharingService, type ISigner, type ISpace, type ISpaceCreationHandler, type ISpaceScopedDelegations, type ISpaceScopedSharing, type ISpaceService, type IUserAuthorization, type IWasmBindings, IdentityParseError, LOCAL_LINK_HOST_SUFFIX, LOCAL_LINK_PROBE_TIMEOUT_MS, LOCAL_LOOPBACK_PROBE_TIMEOUT_MS, type LocalNodeIdentityStore, type LocationCandidate, type LocationCandidateInput, type LocationRecord, type LocationRecordPayload, type LocationRecordSigner, LocationRecordValidationError, type LocationResolutionAttempt, type LocationSource, type Manifest, type ManifestDefaults, type ManifestKnowledge, type ManifestRegistryRecord, type ManifestSecretActions, ManifestValidationError, type NodeInfo, type OpenKeyCallbackStrategy, type OpenKeySigningRequestBody, type OpenKeySigningResponseBody, type OpenKeySigningStrategyOptions, type ParseRecapFromSiwe, type PartialSiweMessage, type PermissionEntry, PermissionNotInManifestError, type PersistedSessionData, type PersistedSessionProof, type PersistedTinyCloudSession, type PkhDidParts, ProtocolMismatchError, type RegisterBatchSuccess, type ResolveCloudLocationOptions, type ResolveTinyCloudHostsOptions, type ResolvedCapabilities, type ResolvedCloudLocation, type ResolvedDelegate, type ResolvedTinyCloudHosts, type ResourceCapability, SECRETS_SPACE, SERVICE_LONG_TO_SHORT, SERVICE_SHORT_TO_LONG, type ServerHost, SessionExpiredError, ShareLink, type SignCallback, type SignInOptions, type SignRequest, type SignResponse, type SignStrategy, SilentNotificationHandler, type SiweConfig, SiweConfigSchema, Space, type SpaceAbilitiesMap, type SpaceConfig, type SpaceCreationContext, type SpaceDelegationParams, type SpaceErrorCode, SpaceErrorCodes, type SpaceHostResult, SpaceInfo, SpaceService, type SpaceServiceConfig, type SubsetCheckResult, TinyCloud, type TinyCloudConfig, type TinyCloudSession, UnsupportedFeatureError, type UserAuthorizationConfig, VAULT_PERMISSION_SERVICE, type ValidatedPersistedSessionProof, type ValidationError, VersionCheckError, type WasmRecapEntry, type WebStorageLike, actionContains, activateSessionWithHost, addressStorageKey, applyPrefix, buildSpaceUri, canonicalLocationPayload, canonicalizeAddress, canonicalizeDid, canonicalizeDidUrl, canonicalizeNetworkId, canonicalizeRecapCaveats, checkNodeInfo, composeManifestRequest, createInMemoryLocalNodeIdentityStore, createLocalStorageLocalNodeIdentityStore, createOpenKeyCallbackSigningStrategy, createSpaceService, defaultSignStrategy, defaultSpaceCreationHandler, didCacheKey, didEquals, discoverLocalTinyCloudNode, expandActionShortNames, expandPermissionEntries, expandPermissionEntry, fetchLocationRecord, fetchPeerId, httpUrlToMultiaddr, isCapabilitySubset, isEvmAddress, loadManifest, locationPayloadForRecord, makePkhSpaceId, makePublicSpaceId, manifestAbilitiesUnion, multiaddrToHttpUrl, normalizeDefaults, parseCanonicalNetworkId, parseExpiry, parsePkhDid, parseRecapCapabilities, parseSpaceUri, pkhDid, principalDid, principalDidEquals, recapCaveatsEqual, resolveCloudLocation, resolveManifest, resolveManifestKnowledgeRoot, resolveTinyCloudHosts, resourceCapabilitiesToAbilitiesMap, resourceCapabilitiesToSpaceAbilitiesMap, signLocationRecord, submitHostDelegation, validateClientSession, validateLocationRecord, validateLocationRecordPayload, validateManifest, validatePersistedSessionData, verifyDidKeyEd25519Signature, verifyLocationRecord };
package/dist/index.d.ts CHANGED
@@ -2487,6 +2487,13 @@ interface AccountSpace {
2487
2487
  updatedAt?: string;
2488
2488
  expiresAt?: Date;
2489
2489
  }
2490
+ interface RegisterBatchSuccess {
2491
+ spaces: AccountSpace[];
2492
+ /** Present iff the batch write failed ambiguously and per-space
2493
+ * reconciliation recovered it. The original batch error verbatim, so
2494
+ * callers can record the degradation structurally (TC-361). */
2495
+ recoveredFromBatchError?: ServiceError;
2496
+ }
2490
2497
  interface AccountDelegation {
2491
2498
  cid: string;
2492
2499
  direction: "granted" | "received";
@@ -2591,6 +2598,17 @@ declare class AccountService {
2591
2598
  list: (options?: AccountSpaceListOptions) => Promise<Result<AccountSpace[]>>;
2592
2599
  get: (spaceId: string) => Promise<Result<AccountSpace>>;
2593
2600
  register: (space: SpaceInfo | AccountSpace) => Promise<Result<AccountSpace>>;
2601
+ /**
2602
+ * Register multiple spaces in one KV batch write + one multi-row index
2603
+ * write, instead of one `register()` round trip per space (TC-373).
2604
+ *
2605
+ * The stored records are computed exactly once and reused for both the
2606
+ * batch attempt and any reconciliation below, so a fallback never mints a
2607
+ * fresh timestamp for a space that already has a written record — a
2608
+ * second `spaceRecordFromInput` call would produce a new content hash and
2609
+ * leave the first attempt's blocks orphaned.
2610
+ */
2611
+ registerBatch: (spaces: readonly (SpaceInfo | AccountSpace)[]) => Promise<Result<RegisterBatchSuccess>>;
2594
2612
  syncAccessible: () => Promise<Result<AccountSpace[]>>;
2595
2613
  remove: (spaceId: string) => Promise<Result<void>>;
2596
2614
  };
@@ -2623,6 +2641,16 @@ declare class AccountService {
2623
2641
  private deleteApplicationIndex;
2624
2642
  private upsertSpaceIndexQuietly;
2625
2643
  private upsertSpaceIndex;
2644
+ private upsertSpacesIndexQuietly;
2645
+ /**
2646
+ * Upsert multiple space index rows in ONE multi-row `INSERT OR REPLACE`
2647
+ * statement (TC-373), rather than one statement per space. This matters
2648
+ * because `IDatabaseHandle.batch()` executes its statement list as a plain
2649
+ * loop, not a single database transaction — an N-statement batch is not
2650
+ * atomic. A single multi-row INSERT is one SQLite statement, so it applies
2651
+ * atomically: all rows or none.
2652
+ */
2653
+ private upsertSpacesIndex;
2626
2654
  private deleteSpaceIndexQuietly;
2627
2655
  private deleteSpaceIndex;
2628
2656
  private resolveSpace;
@@ -2776,7 +2804,7 @@ interface LocationRecord extends LocationRecordPayload {
2776
2804
  type LocationSource = "explicit" | "local-loopback" | "local-link" | "blockchain" | "centralized" | "fallback";
2777
2805
  declare const DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL = "https://registry.tinycloud.xyz";
2778
2806
  declare const DEFAULT_TINYCLOUD_FALLBACK_HOST = "https://node.tinycloud.xyz";
2779
- /** Default local loopback node URL probed before registry/fallback resolution. */
2807
+ /** Conventional local loopback node URL. Probed only when explicitly configured. */
2780
2808
  declare const DEFAULT_LOCAL_NODE_URL = "http://127.0.0.1:8000";
2781
2809
  /** Probe timeout for the local loopback candidate. No retries. */
2782
2810
  declare const LOCAL_LOOPBACK_PROBE_TIMEOUT_MS = 250;
@@ -2863,7 +2891,7 @@ interface DiscoverLocalTinyCloudNodeOptions {
2863
2891
  subject?: string;
2864
2892
  /** Enable local-node auto-discovery. Default true. */
2865
2893
  autoDiscoverLocalNode?: boolean;
2866
- /** Local loopback node URL to probe. Default http://127.0.0.1:8000. */
2894
+ /** Local loopback node URL to probe. Omit to avoid probing loopback. */
2867
2895
  localNodeUrl?: string;
2868
2896
  /** Known `*.local.tinycloud.link` subdomain name, probed directly. */
2869
2897
  localLinkName?: string;
@@ -2897,12 +2925,12 @@ interface ResolveTinyCloudHostsOptions {
2897
2925
  /** Verify centralized/blockchain record signatures. Default true. */
2898
2926
  verifyRecords?: boolean;
2899
2927
  /**
2900
- * Probe for a locally-running TinyCloud node before falling back to
2901
- * registry/hosted resolution. Default true. Setting false restores the
2902
- * exact pre-TC-106 resolution order (registry → fallback).
2928
+ * Probe configured and registered local TinyCloud node endpoints before
2929
+ * falling back to registry/hosted resolution. Default true. The loopback
2930
+ * URL is probed only when `localNodeUrl` is explicitly configured.
2903
2931
  */
2904
2932
  autoDiscoverLocalNode?: boolean;
2905
- /** Local loopback node URL to probe. Default http://127.0.0.1:8000. */
2933
+ /** Local loopback node URL to probe. Omit to avoid probing loopback. */
2906
2934
  localNodeUrl?: string;
2907
2935
  /** Known `*.local.tinycloud.link` subdomain name, probed directly. */
2908
2936
  localLinkName?: string;
@@ -2988,4 +3016,4 @@ declare const EXPIRY: {
2988
3016
  declare const DEFAULT_SIGNED_READ_URL_EXPIRY_MS: number;
2989
3017
  type ExpiryTier = keyof typeof EXPIRY;
2990
3018
 
2991
- export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, type AbilitiesMap, type AccountApplication, type AccountApplicationListOptions, type AccountApplicationRegisterOptions, type AccountDelegation, type AccountDelegationListOptions, AccountDelegationPage, AccountDelegationQueryOptions, type AccountDelegationRevokeOptions, type AccountIndexEnsureResult, type AccountIndexRebuildResult, type AccountIndexStatus, type AccountIndexedReadOptions, AccountService, type AccountServiceConfig, type AccountSpace, type AccountSpaceListOptions, type AccountStatus, AutoApproveSpaceCreationHandler, type AutoRejectStrategy, type AutoSignStrategy, type Bytes, type CallbackStrategy, type CanonicalAddress, type CanonicalParsedNetworkId, CaveatedDelegationUnsupportedError, type ClientSession, ClientSessionSchema, CloudLocationResolutionError, type ComposeManifestOptions, type ComposedManifestRequest, type CreateDelegationFunction, CreateDelegationParams, DEFAULT_DEFAULTS, DEFAULT_EXPIRY, DEFAULT_KNOWLEDGE_ROOT, DEFAULT_LOCAL_NODE_PIN_STORAGE_KEY, DEFAULT_LOCAL_NODE_URL, DEFAULT_MANIFEST_SPACE, DEFAULT_MANIFEST_VERSION, DEFAULT_SIGNED_READ_URL_EXPIRY_MS, DEFAULT_TINYCLOUD_FALLBACK_HOST, DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL, Delegation, DelegationManager, DelegationRevocationReceipt, type DidCacheKeyOptions, type DidEqualsOptions, type DiscoverLocalTinyCloudNodeOptions, type DiscoveredLocalTinyCloudNode, ENCRYPTION_MANIFEST_SPACE, ENCRYPTION_PERMISSION_SERVICE, EXPIRY, type EnsData, EnsDataSchema, type EventEmitterStrategy, type ExpiryTier, type Extension, GenerateShareParams, ICapabilityKeyRegistry, type IENSResolver, type INotificationHandler, type ISessionManager, type ISessionStorage, ISharingService, type ISigner, type ISpace, type ISpaceCreationHandler, type ISpaceScopedDelegations, type ISpaceScopedSharing, type ISpaceService, type IUserAuthorization, type IWasmBindings, IdentityParseError, LOCAL_LINK_HOST_SUFFIX, LOCAL_LINK_PROBE_TIMEOUT_MS, LOCAL_LOOPBACK_PROBE_TIMEOUT_MS, type LocalNodeIdentityStore, type LocationCandidate, type LocationCandidateInput, type LocationRecord, type LocationRecordPayload, type LocationRecordSigner, LocationRecordValidationError, type LocationResolutionAttempt, type LocationSource, type Manifest, type ManifestDefaults, type ManifestKnowledge, type ManifestRegistryRecord, type ManifestSecretActions, ManifestValidationError, type NodeInfo, type OpenKeyCallbackStrategy, type OpenKeySigningRequestBody, type OpenKeySigningResponseBody, type OpenKeySigningStrategyOptions, type ParseRecapFromSiwe, type PartialSiweMessage, type PermissionEntry, PermissionNotInManifestError, type PersistedSessionData, type PersistedSessionProof, type PersistedTinyCloudSession, type PkhDidParts, ProtocolMismatchError, type ResolveCloudLocationOptions, type ResolveTinyCloudHostsOptions, type ResolvedCapabilities, type ResolvedCloudLocation, type ResolvedDelegate, type ResolvedTinyCloudHosts, type ResourceCapability, SECRETS_SPACE, SERVICE_LONG_TO_SHORT, SERVICE_SHORT_TO_LONG, type ServerHost, SessionExpiredError, ShareLink, type SignCallback, type SignInOptions, type SignRequest, type SignResponse, type SignStrategy, SilentNotificationHandler, type SiweConfig, SiweConfigSchema, Space, type SpaceAbilitiesMap, type SpaceConfig, type SpaceCreationContext, type SpaceDelegationParams, type SpaceErrorCode, SpaceErrorCodes, type SpaceHostResult, SpaceInfo, SpaceService, type SpaceServiceConfig, type SubsetCheckResult, TinyCloud, type TinyCloudConfig, type TinyCloudSession, UnsupportedFeatureError, type UserAuthorizationConfig, VAULT_PERMISSION_SERVICE, type ValidatedPersistedSessionProof, type ValidationError, VersionCheckError, type WasmRecapEntry, type WebStorageLike, actionContains, activateSessionWithHost, addressStorageKey, applyPrefix, buildSpaceUri, canonicalLocationPayload, canonicalizeAddress, canonicalizeDid, canonicalizeDidUrl, canonicalizeNetworkId, canonicalizeRecapCaveats, checkNodeInfo, composeManifestRequest, createInMemoryLocalNodeIdentityStore, createLocalStorageLocalNodeIdentityStore, createOpenKeyCallbackSigningStrategy, createSpaceService, defaultSignStrategy, defaultSpaceCreationHandler, didCacheKey, didEquals, discoverLocalTinyCloudNode, expandActionShortNames, expandPermissionEntries, expandPermissionEntry, fetchLocationRecord, fetchPeerId, httpUrlToMultiaddr, isCapabilitySubset, isEvmAddress, loadManifest, locationPayloadForRecord, makePkhSpaceId, makePublicSpaceId, manifestAbilitiesUnion, multiaddrToHttpUrl, normalizeDefaults, parseCanonicalNetworkId, parseExpiry, parsePkhDid, parseRecapCapabilities, parseSpaceUri, pkhDid, principalDid, principalDidEquals, recapCaveatsEqual, resolveCloudLocation, resolveManifest, resolveManifestKnowledgeRoot, resolveTinyCloudHosts, resourceCapabilitiesToAbilitiesMap, resourceCapabilitiesToSpaceAbilitiesMap, signLocationRecord, submitHostDelegation, validateClientSession, validateLocationRecord, validateLocationRecordPayload, validateManifest, validatePersistedSessionData, verifyDidKeyEd25519Signature, verifyLocationRecord };
3019
+ export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, type AbilitiesMap, type AccountApplication, type AccountApplicationListOptions, type AccountApplicationRegisterOptions, type AccountDelegation, type AccountDelegationListOptions, AccountDelegationPage, AccountDelegationQueryOptions, type AccountDelegationRevokeOptions, type AccountIndexEnsureResult, type AccountIndexRebuildResult, type AccountIndexStatus, type AccountIndexedReadOptions, AccountService, type AccountServiceConfig, type AccountSpace, type AccountSpaceListOptions, type AccountStatus, AutoApproveSpaceCreationHandler, type AutoRejectStrategy, type AutoSignStrategy, type Bytes, type CallbackStrategy, type CanonicalAddress, type CanonicalParsedNetworkId, CaveatedDelegationUnsupportedError, type ClientSession, ClientSessionSchema, CloudLocationResolutionError, type ComposeManifestOptions, type ComposedManifestRequest, type CreateDelegationFunction, CreateDelegationParams, DEFAULT_DEFAULTS, DEFAULT_EXPIRY, DEFAULT_KNOWLEDGE_ROOT, DEFAULT_LOCAL_NODE_PIN_STORAGE_KEY, DEFAULT_LOCAL_NODE_URL, DEFAULT_MANIFEST_SPACE, DEFAULT_MANIFEST_VERSION, DEFAULT_SIGNED_READ_URL_EXPIRY_MS, DEFAULT_TINYCLOUD_FALLBACK_HOST, DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL, Delegation, DelegationManager, DelegationRevocationReceipt, type DidCacheKeyOptions, type DidEqualsOptions, type DiscoverLocalTinyCloudNodeOptions, type DiscoveredLocalTinyCloudNode, ENCRYPTION_MANIFEST_SPACE, ENCRYPTION_PERMISSION_SERVICE, EXPIRY, type EnsData, EnsDataSchema, type EventEmitterStrategy, type ExpiryTier, type Extension, GenerateShareParams, ICapabilityKeyRegistry, type IENSResolver, type INotificationHandler, type ISessionManager, type ISessionStorage, ISharingService, type ISigner, type ISpace, type ISpaceCreationHandler, type ISpaceScopedDelegations, type ISpaceScopedSharing, type ISpaceService, type IUserAuthorization, type IWasmBindings, IdentityParseError, LOCAL_LINK_HOST_SUFFIX, LOCAL_LINK_PROBE_TIMEOUT_MS, LOCAL_LOOPBACK_PROBE_TIMEOUT_MS, type LocalNodeIdentityStore, type LocationCandidate, type LocationCandidateInput, type LocationRecord, type LocationRecordPayload, type LocationRecordSigner, LocationRecordValidationError, type LocationResolutionAttempt, type LocationSource, type Manifest, type ManifestDefaults, type ManifestKnowledge, type ManifestRegistryRecord, type ManifestSecretActions, ManifestValidationError, type NodeInfo, type OpenKeyCallbackStrategy, type OpenKeySigningRequestBody, type OpenKeySigningResponseBody, type OpenKeySigningStrategyOptions, type ParseRecapFromSiwe, type PartialSiweMessage, type PermissionEntry, PermissionNotInManifestError, type PersistedSessionData, type PersistedSessionProof, type PersistedTinyCloudSession, type PkhDidParts, ProtocolMismatchError, type RegisterBatchSuccess, type ResolveCloudLocationOptions, type ResolveTinyCloudHostsOptions, type ResolvedCapabilities, type ResolvedCloudLocation, type ResolvedDelegate, type ResolvedTinyCloudHosts, type ResourceCapability, SECRETS_SPACE, SERVICE_LONG_TO_SHORT, SERVICE_SHORT_TO_LONG, type ServerHost, SessionExpiredError, ShareLink, type SignCallback, type SignInOptions, type SignRequest, type SignResponse, type SignStrategy, SilentNotificationHandler, type SiweConfig, SiweConfigSchema, Space, type SpaceAbilitiesMap, type SpaceConfig, type SpaceCreationContext, type SpaceDelegationParams, type SpaceErrorCode, SpaceErrorCodes, type SpaceHostResult, SpaceInfo, SpaceService, type SpaceServiceConfig, type SubsetCheckResult, TinyCloud, type TinyCloudConfig, type TinyCloudSession, UnsupportedFeatureError, type UserAuthorizationConfig, VAULT_PERMISSION_SERVICE, type ValidatedPersistedSessionProof, type ValidationError, VersionCheckError, type WasmRecapEntry, type WebStorageLike, actionContains, activateSessionWithHost, addressStorageKey, applyPrefix, buildSpaceUri, canonicalLocationPayload, canonicalizeAddress, canonicalizeDid, canonicalizeDidUrl, canonicalizeNetworkId, canonicalizeRecapCaveats, checkNodeInfo, composeManifestRequest, createInMemoryLocalNodeIdentityStore, createLocalStorageLocalNodeIdentityStore, createOpenKeyCallbackSigningStrategy, createSpaceService, defaultSignStrategy, defaultSpaceCreationHandler, didCacheKey, didEquals, discoverLocalTinyCloudNode, expandActionShortNames, expandPermissionEntries, expandPermissionEntry, fetchLocationRecord, fetchPeerId, httpUrlToMultiaddr, isCapabilitySubset, isEvmAddress, loadManifest, locationPayloadForRecord, makePkhSpaceId, makePublicSpaceId, manifestAbilitiesUnion, multiaddrToHttpUrl, normalizeDefaults, parseCanonicalNetworkId, parseExpiry, parsePkhDid, parseRecapCapabilities, parseSpaceUri, pkhDid, principalDid, principalDidEquals, recapCaveatsEqual, resolveCloudLocation, resolveManifest, resolveManifestKnowledgeRoot, resolveTinyCloudHosts, resourceCapabilitiesToAbilitiesMap, resourceCapabilitiesToSpaceAbilitiesMap, signLocationRecord, submitHostDelegation, validateClientSession, validateLocationRecord, validateLocationRecordPayload, validateManifest, validatePersistedSessionData, verifyDidKeyEd25519Signature, verifyLocationRecord };
package/dist/index.js CHANGED
@@ -11793,7 +11793,8 @@ var TinyCloud = class _TinyCloud {
11793
11793
  import {
11794
11794
  err as err3,
11795
11795
  ok as ok3,
11796
- serviceError as serviceError3
11796
+ serviceError as serviceError3,
11797
+ ErrorCodes as ErrorCodes3
11797
11798
  } from "@tinycloud/sdk-services";
11798
11799
  import { ACCOUNT_INDEX_SCHEMA } from "@tinycloud/bootstrap";
11799
11800
  var SERVICE_NAME2 = "account";
@@ -11945,6 +11946,60 @@ var AccountService = class {
11945
11946
  await this.upsertSpaceIndexQuietly(registered);
11946
11947
  return ok3(registered);
11947
11948
  },
11949
+ /**
11950
+ * Register multiple spaces in one KV batch write + one multi-row index
11951
+ * write, instead of one `register()` round trip per space (TC-373).
11952
+ *
11953
+ * The stored records are computed exactly once and reused for both the
11954
+ * batch attempt and any reconciliation below, so a fallback never mints a
11955
+ * fresh timestamp for a space that already has a written record — a
11956
+ * second `spaceRecordFromInput` call would produce a new content hash and
11957
+ * leave the first attempt's blocks orphaned.
11958
+ */
11959
+ registerBatch: async (spaces) => {
11960
+ if (spaces.length === 0) return ok3({ spaces: [] });
11961
+ await this.config.ensureAccountSpaceHosted?.();
11962
+ const kvResult = this.accountKV();
11963
+ if (!kvResult.ok) return kvResult;
11964
+ const stored = spaces.map((space) => spaceRecordFromInput(space));
11965
+ const registered = stored.map(
11966
+ (record) => spaceFromRecord(spaceKey(record.space_id), record)
11967
+ );
11968
+ const items = stored.map((record) => ({
11969
+ key: spaceKey(record.space_id),
11970
+ value: record
11971
+ }));
11972
+ const batchResult = await kvResult.data.batchPut(items);
11973
+ if (batchResult.ok) {
11974
+ await this.upsertSpacesIndexQuietly(registered);
11975
+ return ok3({ spaces: registered });
11976
+ }
11977
+ if (!isAmbiguousBatchFailure(batchResult.error)) {
11978
+ return accountErr(batchResult.error);
11979
+ }
11980
+ const reconcileFailures = [];
11981
+ for (const record of stored) {
11982
+ const written = await kvResult.data.put(spaceKey(record.space_id), record);
11983
+ if (!written.ok) {
11984
+ reconcileFailures.push(`${record.space_id}: ${written.error.message}`);
11985
+ }
11986
+ }
11987
+ if (reconcileFailures.length > 0) {
11988
+ return err3(
11989
+ serviceError3(
11990
+ "KV_BATCH_RECONCILE_FAILED",
11991
+ `KV batch write for ${items.length} space(s) failed ambiguously (${batchResult.error.message}) and per-space reconciliation also failed for: ${reconcileFailures.join("; ")}`,
11992
+ SERVICE_NAME2,
11993
+ { cause: batchResult.error.cause, meta: { originalError: batchResult.error } }
11994
+ )
11995
+ );
11996
+ }
11997
+ console.warn(
11998
+ `[AccountService] KV batch write for ${items.length} space(s) returned an ambiguous error and was reconciled via per-space fallback. Original error: ${batchResult.error.message}`
11999
+ );
12000
+ await this.upsertSpacesIndexQuietly(registered);
12001
+ return ok3({ spaces: registered, recoveredFromBatchError: batchResult.error });
12002
+ },
11948
12003
  syncAccessible: async () => {
11949
12004
  const listed = await this.config.getSpaces().list();
11950
12005
  if (!listed.ok) return accountErr(listed.error);
@@ -12331,6 +12386,47 @@ var AccountService = class {
12331
12386
  if (!written.ok) return accountErr(written.error);
12332
12387
  return ok3(void 0);
12333
12388
  }
12389
+ async upsertSpacesIndexQuietly(spaces) {
12390
+ await ignoreIndexFailure(() => this.upsertSpacesIndex(spaces));
12391
+ }
12392
+ /**
12393
+ * Upsert multiple space index rows in ONE multi-row `INSERT OR REPLACE`
12394
+ * statement (TC-373), rather than one statement per space. This matters
12395
+ * because `IDatabaseHandle.batch()` executes its statement list as a plain
12396
+ * loop, not a single database transaction — an N-statement batch is not
12397
+ * atomic. A single multi-row INSERT is one SQLite statement, so it applies
12398
+ * atomically: all rows or none.
12399
+ */
12400
+ async upsertSpacesIndex(spaces) {
12401
+ if (spaces.length === 0) return ok3(void 0);
12402
+ const dbResult = this.accountDb();
12403
+ if (!dbResult.ok) return ok3(void 0);
12404
+ const schema = await this.ensureAccountIndex(dbResult.data);
12405
+ if (!schema.ok) return schema;
12406
+ const placeholders = spaces.map(() => "(?, ?, ?, ?, ?, ?, ?, ?, ?)").join(", ");
12407
+ const params = spaces.flatMap((space) => {
12408
+ const updatedAt = space.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
12409
+ return [
12410
+ space.spaceId,
12411
+ space.name,
12412
+ space.ownerDid,
12413
+ space.type,
12414
+ JSON.stringify(space.permissions),
12415
+ space.status,
12416
+ space.registeredAt ?? updatedAt,
12417
+ updatedAt,
12418
+ space.expiresAt?.toISOString() ?? null
12419
+ ];
12420
+ });
12421
+ const written = await dbResult.data.batch([
12422
+ {
12423
+ sql: `INSERT OR REPLACE INTO spaces (space_id, name, owner_did, type, permissions_json, status, registered_at, updated_at, expires_at) VALUES ${placeholders}`,
12424
+ params
12425
+ }
12426
+ ]);
12427
+ if (!written.ok) return accountErr(written.error);
12428
+ return ok3(void 0);
12429
+ }
12334
12430
  async deleteSpaceIndexQuietly(spaceId) {
12335
12431
  await ignoreIndexFailure(() => this.deleteSpaceIndex(spaceId));
12336
12432
  }
@@ -12657,6 +12753,17 @@ function accountErr(error) {
12657
12753
  function isMissingIndexError(error) {
12658
12754
  return /no such table:/i.test(error.message);
12659
12755
  }
12756
+ var AMBIGUOUS_WRITE_STATUSES = /* @__PURE__ */ new Set([500, 502, 503, 504, 520, 522, 524]);
12757
+ function isAmbiguousBatchFailure(error) {
12758
+ if (error.code === ErrorCodes3.NETWORK_ERROR || error.code === ErrorCodes3.TIMEOUT) {
12759
+ return error.meta?.requestMayHaveDispatched === true;
12760
+ }
12761
+ if (error.code === ErrorCodes3.KV_WRITE_FAILED) {
12762
+ const status = error.meta?.status;
12763
+ return typeof status === "number" && AMBIGUOUS_WRITE_STATUSES.has(status);
12764
+ }
12765
+ return false;
12766
+ }
12660
12767
  async function ignoreIndexFailure(task) {
12661
12768
  try {
12662
12769
  await task();
@@ -12672,7 +12779,7 @@ import {
12672
12779
  ok as ok5,
12673
12780
  err as err5,
12674
12781
  serviceError as serviceError5,
12675
- ErrorCodes as ErrorCodes3,
12782
+ ErrorCodes as ErrorCodes4,
12676
12783
  TinyCloudDebugLogger,
12677
12784
  tinyCloudDebugLogger,
12678
12785
  enableTinyCloudDebug,
@@ -15132,13 +15239,14 @@ async function discoverLocalTinyCloudNode(options2 = {}) {
15132
15239
  }
15133
15240
  const fetchFn = options2.fetch ?? globalThis.fetch;
15134
15241
  const identityStore = options2.identityStore ?? defaultLocalNodeIdentityStore;
15135
- const staticCandidates = [
15136
- {
15242
+ const staticCandidates = [];
15243
+ if (options2.localNodeUrl) {
15244
+ staticCandidates.push({
15137
15245
  source: "local-loopback",
15138
- url: options2.localNodeUrl ?? DEFAULT_LOCAL_NODE_URL,
15246
+ url: options2.localNodeUrl,
15139
15247
  timeoutMs: LOCAL_LOOPBACK_PROBE_TIMEOUT_MS
15140
- }
15141
- ];
15248
+ });
15249
+ }
15142
15250
  if (options2.localLinkName) {
15143
15251
  if (isValidDnsLabel(options2.localLinkName)) {
15144
15252
  staticCandidates.push({
@@ -15591,7 +15699,7 @@ export {
15591
15699
  EXPIRY,
15592
15700
  EncryptionService,
15593
15701
  EnsDataSchema,
15594
- ErrorCodes3 as ErrorCodes,
15702
+ ErrorCodes4 as ErrorCodes,
15595
15703
  HOLDER_KEY_BINDING_PRESENTATION_SCHEMA,
15596
15704
  HOOKS,
15597
15705
  HooksService2 as HooksService,