1# @fixtures/waku-durable-objects
2
3E2e fixture for `@alchemy.run/frontend-frameworks/waku` exercising a **framework site plus the
4user's own Durable Objects on the same worker** — the pattern alchemy's
5`Website.Vite` supports via its custom `main` entry, carried generically by
6framework-core's `DeployTarget.entry` (the user-entry seam; see
7`packages/frontend-frameworks/src/core/DeployTarget.ts` and the "user-entry seam"
8section of `packages/frontend-frameworks/src/core/README.md`).
9
10The app is a waku site (a dynamic page + a `/counter` API route) whose
11`src/worker-entry.ts` is the user's own worker entry: it wraps waku's emitted
12fetch handler via `virtual:waku/server-entry` and exports `class Counter`, a
13SQLite-backed Durable Object. `e2e.config.ts` declares the namespace
14(`durableObjectNamespaces` on the dev worker config, `durableObjects` on the
15miniflare preview config) and binds it with
16`DurableObjectNamespace.local({ binding: "COUNTER", className: "Counter" })`.
17
18## How the seam works
19
201. **User `main` precedence** — `target.cloudflare.worker.main`
21 (`./src/worker-entry.ts`, resolved against the project root) takes
22 precedence over waku's pinned rsc server entry
23 (`makeWakuPluginOptions` in `packages/waku/src/cloudflare.ts`). The
24 wrapped entry is bundled in the **rsc** environment (waku's entry
25 topology `{ entry: "rsc", children: ["ssr"] }` is unchanged).
262. **`virtual:waku/server-entry`** — the stable importable specifier for
27 waku's server handler (precedent: React Router's
28 `virtual:react-router/server-build`). Resolved by
29 `makeWakuServerEntryPlugin` to the installed
30 `<wakuDirectory>/dist/lib/vite-entries/entry.server.js`, whose default
31 export is the adapter's `ExportedHandler`, in dev and build alike.
323. **Entry-chunk selection** — the target surfaces the config's `main` as
33 the generic `DeployTarget.entry` carriage; the platform-neutral framework
34 half pins the built user-entry chunk as `serverModules[0]`
35 (framework-core's `selectEntryByFacade`), while waku's own
36 `server/index.js` remains an ordinary chunk the user entry imports.
374. **Dev** — the cloudflare vite plugin's module runner serves the wrapped
38 user entry, so the `Counter` class exists in dev too.
39
40## What the app exercises
41
42- SSR page (`/`) reading the Counter DO at request time (`data-testid=do-count`)
43- `/counter` API route: `POST` increments, `GET` reads — asserted to
44 increment **across requests**, proving DO instance identity on the same
45 worker (live + dev)
46- static asset (`/hello.txt`) still served alongside the custom entry
47- the `MESSAGE` Text binding through the wrapped handler (framework routes
48 unaffected by wrapping)
49
50## Commands
51
52```sh
53bun run dev # waku dev with the rsc environment in workerd (port 3110)
54bun run build # waku build -> dist/ + dist/build.json
55bun run preview # miniflare over dist/build.json
56bun run test # playwright e2e (live + dev)
57```