diff --git a/core/blockstore/attachable-store.ts b/core/blockstore/attachable-store.ts index 42363e8ab..da38c5d84 100644 --- a/core/blockstore/attachable-store.ts +++ b/core/blockstore/attachable-store.ts @@ -248,6 +248,19 @@ function isLoadable(unknown: AttachedStores | Loadable): unknown is Loadable { return !!(unknown as Loadable).sthis && !!(unknown as Loadable).attachedStores; } +/** + * Create and attach store handles using either a single URI or explicit gateway URL parameters. + * + * Prepares a GatewayUrlsParam from `urlOrGup` (if a `CoerceURI` is provided it is used for all gateways), + * resolves the target AttachedStores from `arOrLoadable` (accepting either an AttachedStores or a Loadable), + * and calls `attach` to produce an Attached instance. + * + * @param urlOrGup - A single URI to use for all gateways or a `GatewayUrlsParam` that specifies per-gateway URLs. + * @param arOrLoadable - An AttachedStores instance or a Loadable whose `attachedStores` will be used. + * @param name - Optional attachment name; defaults to `"local"`. + * @returns The created Attached instance representing the attached stores configured with the provided gateway URLs. + * @throws Error if `urlOrGup` is not provided. + */ export async function createAttachedStores( urlOrGup: CoerceURI | GatewayUrlsParam, arOrLoadable: AttachedStores | Loadable, @@ -289,7 +302,7 @@ export async function createAttachedStores( } export class AttachedRemotesImpl implements AttachedStores { - private readonly _remotes = new KeyedResolvOnce(); + private _remotes = new KeyedResolvOnce(); readonly loadable: Loadable; // readonly attactedFileStore: DataStore; @@ -330,6 +343,17 @@ export class AttachedRemotesImpl implements AttachedStores { return new ActiveStoreImpl(this._local.stores as LocalDataAndMetaAndWalStore, this); } + /** + * Returns the local store if set, or undefined if already reset. + * Use this for safe access during teardown. + */ + localOrUndefined(): LocalActiveStore | undefined { + if (!this._local) { + return undefined; + } + return new ActiveStoreImpl(this._local.stores as LocalDataAndMetaAndWalStore, this); + } + activate(store: DataAndMetaStore | CoerceURI): ActiveStore { // console.log( // "activate", @@ -374,7 +398,7 @@ export class AttachedRemotesImpl implements AttachedStores { } // needed for React Statemanagement - readonly _keyedAttachable = new KeyedResolvOnce(); + private _keyedAttachable = new KeyedResolvOnce(); async attach(attachable: Attachable, onAttach: (at: Attached) => Promise): Promise { const keyed = attachable.configHash(this.loadable.blockstoreParent?.crdtParent?.ledgerParent); // console.log("attach-enter", keyed, this.loadable.blockstoreParent?.crdtParent?.ledgerParent?.name); @@ -465,4 +489,16 @@ export class AttachedRemotesImpl implements AttachedStores { }); return ret; } -} + + /** + * Reset remote attachments for teardown. + * Note: _local is intentionally NOT cleared here because async operations + * (meta stream handler, write queue) may still reference it during shutdown. + * The local store is properly cleaned up via detach(). + */ + reset(): void { + this._remotes = new KeyedResolvOnce(); + this._keyedAttachable = new KeyedResolvOnce(); + // Don't clear _local - async operations may still need it during shutdown + } +} \ No newline at end of file