UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

81 lines (71 loc) 3 kB
import { $atom, $inject, Alepha, z } from "alepha"; import { $action, AlephaServer } from "alepha/server"; import { describe, expect, it } from "vitest"; import { $cookie, AlephaServerCookies } from "../index.ts"; /** * Regression coverage for the cross-request contamination found in * `StateManager.register()`. * * `$cookie({ key: atom.key })` writes the raw cookie into the request's ALS * layer during `server:onRequest`, BEFORE anything ever reads the atom. So on * a request that carries the cookie, the atom's very first registration * happens inside a fork that already holds its key — and the app-level store * never received the declared default. Every later, cookie-LESS request then * resolved `undefined` (no fork value, no app value) instead of the default: * one user's cookied request permanently defined what every cookie-less user * saw. * * The atom is deliberately NOT declared with `$state(...)` here: it must * register lazily, from inside the request, which is exactly what the * framework's own `uiAtom` does during SSR. */ const themeAtom = $atom({ name: "test.cookie.binding.theme", schema: z.object({ theme: z.string() }), default: { theme: "light" }, }); class CookieBoundApp { protected readonly alepha = $inject(Alepha); theme = $cookie({ key: themeAtom.key, name: "test-cookie-binding-theme", schema: z.object({ theme: z.string() }), }); read = $action({ schema: { response: z.object({ theme: z.string() }), }, // Lazy: the atom is first registered here, inside the request. handler: () => ({ theme: this.alepha.store.get(themeAtom).theme }), }); } const alepha = Alepha.create().with(AlephaServer).with(AlephaServerCookies); const app = alepha.inject(CookieBoundApp); const cookieHeader = `test-cookie-binding-theme=${encodeURIComponent( JSON.stringify({ theme: "dark" }), )}`; describe("atom bound to a $cookie, first registered inside a request", () => { it("serves the default to a cookie-less request that follows a cookied one", async () => { // Request 1 — WITH the cookie. This is the request that registers the // atom, from inside a fork that already carries its key. const first = await app.read.fetch( {}, { key: "binding-with-cookie", request: { headers: { cookie: cookieHeader } }, }, ); expect(first.data.theme).toBe("dark"); // Request 2 — WITHOUT any cookie. Before the fix this resolved // `undefined` (the app store never got the default), which then blew up // as a TypeError on any direct `.theme` read. const second = await app.read.fetch( {}, { key: "binding-no-cookie", request: { headers: { cookie: "" } } }, ); expect(second.data.theme).toBe("light"); // The app-level store holds the declared DEFAULT — not `undefined`, and // not the first request's cookie value. expect(alepha.store.get(themeAtom, "app")).toEqual({ theme: "light" }); }); });