import { expect, test } from "bun:test"; import { createStoreContainer, defineStore } from "../src/index.ts"; const CounterStore = defineStore({ name: "CounterStore", kind: "global" as const, createSharedState: () => ({ count: 0 }), createClientState: () => ({ viewport: 0 }), createServerState: () => ({ secret: "server-only" }), computed: { doubled: (state: Readonly<{ count: number }>) => state.count * 2 }, actions: { increment: [ { runtime: "client" as const, handler: ({ state }: any, amount = 1) => { state.count += amount; }, }, { runtime: "server" as const, handler: ({ state }: any, amount = 1) => { state.count += amount * 2; }, }, ], }, }); test("isolates request-scoped server stores and excludes server state", async () => { const first = createStoreContainer({ runtime: "server", request: {} }); const second = createStoreContainer({ runtime: "server", request: {} }); const a = await first.use(CounterStore); const b = await second.use(CounterStore); await a.increment(2); expect(a.count).toBe(4); expect(a.doubled).toBe(8); expect(b.count).toBe(0); expect(first.serialize()).toEqual({ CounterStore: { count: 4 } }); }); test("store state is readonly outside actions and supports snapshots/reset", async () => { const container = createStoreContainer({ runtime: "client" }); const store = await container.use(CounterStore); expect(() => { (store.state as any).count = 5; }).toThrow("WRN-STORE-READONLY"); await store.increment(3); expect(store.snapshot().count).toBe(3); store.reset(); expect(store.count).toBe(0); }); test("HMR preserves compatible state and resets incompatible fields", async () => { const container = createStoreContainer({ runtime: "client" }); const store = await container.use(CounterStore); await store.increment(2); const result = await container.hotUpdate( defineStore({ ...CounterStore, createSharedState: () => ({ count: 0, added: true }), } as any), ); expect(result.preserved).toContain("count"); }); test("store lifecycle hooks may update state and page stores dispose cleanly", async () => { const calls: string[] = []; const LifecycleStore = defineStore({ name: "LifecycleStore", kind: "page" as const, createSharedState: () => ({ ready: false }), lifecycle: { clientInit: async ({ state }: any) => { calls.push("clientInit"); state.ready = true; }, dispose: async ({ state }: any) => { calls.push("dispose"); state.ready = false; }, }, }); const container = createStoreContainer({ runtime: "client", routeId: "/one" }); const store = await container.use(LifecycleStore); expect(store.ready).toBe(true); await container.disposePageStores(); expect(calls).toEqual(["clientInit", "dispose"]); });