diff --git a/.changeset/odd-ties-clap.md b/.changeset/odd-ties-clap.md new file mode 100644 index 00000000..b44ca7ad --- /dev/null +++ b/.changeset/odd-ties-clap.md @@ -0,0 +1,5 @@ +--- +"@zarrita/storage": patch +--- + +Enable creation of ReferenceStore via non-async functions. diff --git a/packages/storage/__tests__/ref.test.ts b/packages/storage/__tests__/ref.test.ts new file mode 100644 index 00000000..a30cf1c8 --- /dev/null +++ b/packages/storage/__tests__/ref.test.ts @@ -0,0 +1,44 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +import ReferenceStore from "../src/ref.js"; + +describe("ReferenceStore", () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("store creation is not async", async () => { + let spec = Promise.resolve({ + version: 1, + refs: { + ".zgroup": '{"zarr_format":2}', + ".zattrs": '{"encoding-type":"anndat…oding-version":"0.1.0"}', + }, + }); + let store = ReferenceStore.fromSpec(spec); + let bytes = await store.get("/.zgroup"); + expect(bytes).toBeInstanceOf(Uint8Array); + expect(JSON.parse(new TextDecoder().decode(bytes))).toMatchInlineSnapshot(` + { + "zarr_format": 2, + } + `); + }); + it("store creation can still accept a non-promise", async () => { + let spec = { + version: 1, + refs: { + ".zgroup": '{"zarr_format":2}', + ".zattrs": '{"encoding-type":"anndat…oding-version":"0.1.0"}', + }, + }; + let store = ReferenceStore.fromSpec(spec); + let bytes = await store.get("/.zgroup"); + expect(bytes).toBeInstanceOf(Uint8Array); + expect(JSON.parse(new TextDecoder().decode(bytes))).toMatchInlineSnapshot(` + { + "zarr_format": 2, + } + `); + }); +}); diff --git a/packages/storage/src/ref.ts b/packages/storage/src/ref.ts index f48b9a51..ca1f860b 100644 --- a/packages/storage/src/ref.ts +++ b/packages/storage/src/ref.ts @@ -40,15 +40,15 @@ interface ReferenceStoreOptions { /** @experimental */ class ReferenceStore implements AsyncReadable { - #refs: Map; + #refs: Promise>; #opts: ReferenceStoreOptions; #overrides: RequestInit; constructor( - refs: Map, + refs: Promise> | Map, opts: ReferenceStoreOptions = {}, ) { - this.#refs = refs; + this.#refs = Promise.resolve(refs); this.#opts = opts; this.#overrides = opts.overrides || {}; } @@ -57,7 +57,7 @@ class ReferenceStore implements AsyncReadable { key: AbsolutePath, opts: RequestInit = {}, ): Promise { - let ref = this.#refs.get(strip_prefix(key)); + let ref = (await this.#refs).get(strip_prefix(key)); if (!ref) return; @@ -91,19 +91,19 @@ class ReferenceStore implements AsyncReadable { } static fromSpec( - spec: Record, + spec: Promise> | Record, opts?: ReferenceStoreOptions, ): ReferenceStore { // @ts-expect-error - TS doesn't like the type of `parse` - let refs = parse(spec); + let refs = Promise.resolve(spec).then((spec) => parse(spec)); return new ReferenceStore(refs, opts); } - static async fromUrl( + static fromUrl( url: string | URL, opts?: ReferenceStoreOptions, - ): Promise { - let spec = await fetch(url, opts?.overrides).then((res) => res.json()); + ): ReferenceStore { + let spec = fetch(url, opts?.overrides).then((res) => res.json()); return ReferenceStore.fromSpec(spec, opts); } }