1/**
2 * The USER's own worker entry — the nitro entry/exports seam.
3 *
4 * `NuxtProps.main` maps this module onto `nitro.options.entry`, so nitro's
5 * rollup bundles THIS module as the worker entry: its exports are the
6 * worker's exports. It wraps nitro's emitted cloudflare-module handler
7 * (every framework route, API route, and asset check still works) and
8 * ADDITIONALLY exports the `Counter` Durable Object class, which must live
9 * on the same worker for the `COUNTER` namespace binding to resolve.
10 *
11 * NOTE: like the rest of this fixture, the file is excluded from the
12 * alchemy test project's type-check (tsconfig.test.json) — it only
13 * compiles inside a nuxt build, where nitro provides the aliases.
14 */
15import { DurableObject } from "cloudflare:workers";
16// The wrappable-handler seam: nitro's cloudflare_module runtime entry,
17// importable by its public specifier (bundled with the same virtuals and
18// aliases as nitro's own default entry).
19import nitroHandler from "nitropack/presets/cloudflare/runtime/cloudflare-module";
20
21/** A SQLite-backed Durable Object owned by the user app, not the framework. */
22export class Counter extends DurableObject {
23 #ensureTable() {
24 this.ctx.storage.sql.exec(
25 "CREATE TABLE IF NOT EXISTS counter (id INTEGER PRIMARY KEY, value INTEGER NOT NULL)",
26 );
27 }
28
29 async get(): Promise<number> {
30 this.#ensureTable();
31 const rows = this.ctx.storage.sql
32 .exec("SELECT value FROM counter WHERE id = 0")
33 .toArray();
34 return Number(rows[0]?.value ?? 0);
35 }
36
37 async increment(): Promise<number> {
38 this.#ensureTable();
39 const rows = this.ctx.storage.sql
40 .exec(
41 "INSERT INTO counter (id, value) VALUES (0, 1) ON CONFLICT (id) DO UPDATE SET value = value + 1 RETURNING value",
42 )
43 .toArray();
44 return Number(rows[0]!.value);
45 }
46}
47
48export default nitroHandler;