| 1 | /** |
| 2 | * The USER's own worker entry — the nitro entry/exports seam. |
| 3 | * |
| 4 | * The deploy target maps the configured `main` onto `nitro.options.entry`, |
| 5 | * so nitro's rollup bundles THIS module as the worker entry: its exports are |
| 6 | * the 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 | import { DurableObject } from "cloudflare:workers"; |
| 12 | // The wrappable-handler seam: nitro's cloudflare_module runtime entry, |
| 13 | // importable by its public specifier (bundled with the same virtuals and |
| 14 | // aliases as nitro's own default entry). |
| 15 | import nitroHandler from "nitropack/presets/cloudflare/runtime/cloudflare-module"; |
| 16 | |
| 17 | /** A SQLite-backed Durable Object owned by the user app, not the framework. */ |
| 18 | export class Counter extends DurableObject { |
| 19 | #ensureTable() { |
| 20 | this.ctx.storage.sql.exec( |
| 21 | "CREATE TABLE IF NOT EXISTS counter (id INTEGER PRIMARY KEY, value INTEGER NOT NULL)", |
| 22 | ); |
| 23 | } |
| 24 | |
| 25 | async get(): Promise<number> { |
| 26 | this.#ensureTable(); |
| 27 | const rows = this.ctx.storage.sql |
| 28 | .exec("SELECT value FROM counter WHERE id = 0") |
| 29 | .toArray(); |
| 30 | return Number(rows[0]?.value ?? 0); |
| 31 | } |
| 32 | |
| 33 | async increment(): Promise<number> { |
| 34 | this.#ensureTable(); |
| 35 | const rows = this.ctx.storage.sql |
| 36 | .exec( |
| 37 | "INSERT INTO counter (id, value) VALUES (0, 1) ON CONFLICT (id) DO UPDATE SET value = value + 1 RETURNING value", |
| 38 | ) |
| 39 | .toArray(); |
| 40 | return Number(rows[0]!.value); |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | export default nitroHandler; |