agentleFS
Sign inSign up

chanfana / template

cloudflare/chanfana/template/AGENTS.md

A starter Cloudflare Worker using Chanfana (OpenAPI), Hono, D1, and Zod v4. This is a copyable template — users clone it and build on top. Tests use @cloudflare/vitest-pool-workers with a local miniflare D1 binding. Config: vitest.config.mts. Follow the same conventions as the parent chanfana library: - 2-space indent, double quotes, always semicolons - import type for type-only imports (verbatimModuleSyntax: true) - Classes: PascalCase — endpoint classes named after their action (TaskCreate, TaskList) - Named exports everywhere, no default exports (except…

AGENTS.md766 starsChanged 7 months ago
# AGENTS.md — Chanfana Template (Task API)

A starter Cloudflare Worker using Chanfana (OpenAPI), Hono, D1, and Zod v4. This is a copyable template — users clone it and build on top.

## Commands

```bash
npm run dev                # Start local dev server (http://localhost:8787)
npm test                   # Run integration tests via vitest-pool-workers
npm run deploy             # Deploy to Cloudflare
npm run db:migrate:local   # Apply D1 migrations locally
npm run db:migrate:remote  # Apply D1 migrations to production
```

Tests use `@cloudflare/vitest-pool-workers` with a local miniflare D1 binding. Config: `vitest.config.mts`.

## Project Layout

```
src/
  index.ts                 # Hono app, fromHono wrapper, route registration
  models/task.ts           # Zod schema + shared meta (tableName, primaryKeys)
  endpoints/
    taskCreate.ts          # POST   /api/tasks   — D1CreateEndpoint
    taskList.ts            # GET    /api/tasks   — D1ListEndpoint (filter, search, order)
    taskRead.ts            # GET    /api/tasks/:id — D1ReadEndpoint
    taskUpdate.ts          # PUT    /api/tasks/:id — D1UpdateEndpoint
    taskDelete.ts          # DELETE /api/tasks/:id — D1DeleteEndpoint
    hello.ts               # GET    /api/hello   — Custom OpenAPIRoute (non-D1 example)
test/
  tasks.test.ts            # Integration tests for all endpoints
migrations/
  0001_create_tasks/up.sql # D1 CREATE TABLE
wrangler.jsonc             # Worker config with D1 binding
```

## Code Style

Follow the same conventions as the parent chanfana library:
- 2-space indent, double quotes, always semicolons
- `import type` for type-only imports (`verbatimModuleSyntax: true`)
- Classes: `PascalCase` — endpoint classes named after their action (`TaskCreate`, `TaskList`)
- Named exports everywhere, no default exports (except the Hono app in `index.ts`)

## Zod v4 Rules (Critical)

All code must use Zod v4 syntax:
```typescript
// WRONG (v3)          → CORRECT (v4)
z.string().email()     → z.email()
z.string().uuid()      → z.uuid()
z.string().datetime()  → z.iso.datetime()
z.string().url()       → z.url()
z.nativeEnum(X)        → z.enum([...])
obj.strict()           → z.strictObject({...})
{ message: "..." }     → { error: "..." }
```

## How to Add a New Model

1. **Schema** — Create `src/models/<name>.ts` with a Zod object schema and a meta object:
   ```typescript
   import { z } from "zod";

   export const FooSchema = z.object({
     id: z.number().optional(),
     name: z.string(),
   });

   export const fooMeta = {
     model: {
       tableName: "foos" as const,
       schema: FooSchema,
       primaryKeys: ["id"] as const,
     },
   };
   ```

2. **Endpoints** — Create classes in `src/endpoints/` extending the D1 endpoints:
   ```typescript
   import { D1CreateEndpoint } from "chanfana";
   import { fooMeta } from "../models/foo";

   export class FooCreate extends D1CreateEndpoint {
     _meta = fooMeta;
   }
   ```

3. **Routes** — Register in `src/index.ts`:
   ```typescript
   router.post("/foos", FooCreate);
   ```

4. **Migration** — Add a SQL file in `migrations/0002_create_foos/up.sql`

5. **Tests** — Add tests in `test/` using the same pattern as `tasks.test.ts`

## D1 Endpoint Features

- `D1ListEndpoint` supports `filterFields`, `searchFields`, `orderByFields`, `defaultOrderBy`
- All D1 endpoints read the `DB` binding from `env` automatically (configurable via `dbName` property)
- Path params must match `primaryKeys` names (e.g., `/tasks/:id` with `primaryKeys: ["id"]`)
- Hooks: override `before()` / `after()` to transform data pre/post database operation

## Key Resources

- Chanfana docs: https://chanfana.pages.dev
- Chanfana source: https://github.com/cloudflare/chanfana
- Zod v4: https://zod.dev/v4
- Hono: https://hono.dev

Discussion

Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.

Posts are public.Sign in to post

No one has posted yet. Be the first.