Skip to content
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ When running a script, always check `package.json` scripts (root and per-package
Packages fall in two buckets:

- **Published packages** (have a `pkg/` directory) carry **two** READMEs:
- **`packages/<package>/pkg/README.md`** — public, user-facing. Ships to npm as part of `@ilbertt/<package>` (listed under `"files"` in `pkg/package.json`). This is what users see on the npm page. Covers install, usage, and public API. Must use the published name (`@ilbertt/...`), not the workspace name (`@repo/...`).
- **`packages/<package>/pkg/README.md`** — public, user-facing. Ships to npm as part of `@ilbertt/<package>` (listed under `"files"` in `pkg/package.json`). This is what users see on the npm page. Covers install, usage, and public API. Must use the published name (`@ilbertt/...`), not the workspace name (`@repo/...`). **All links must be absolute URLs** — relative paths and same-page `#anchor` links break on the npm page (e.g. link the examples as `https://github.com/ilbertt/apigen/tree/main/examples`, not `./examples`).
- **`packages/<package>/README.md`** — internal contributor doc. Covers source layout, dev scripts, and constraints. **Must link to `pkg/README.md`** and **must not duplicate install/usage** — when in doubt, the public README wins and the internal one points to it.
- **Internal-only packages** (no `pkg/`) may not need a README at all. Add one only when there's contributor-relevant context that isn't obvious from the source.

Expand Down
24 changes: 18 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,13 @@ npx apigen gen --database-url postgres://user:pw@localhost:5432/app --out src/ap
> npx apigen gen --migrations src/db/migrations --out src/api.gen.ts
> ```

Expose the tables you want, each with its own policy:
Now expose the tables you want, each with its own policy. The snippets below build up a single file.

**1. Expose a public relation.**

```ts
import postgres from 'postgres';
import { Apigen, relation } from './api.gen';

const db = postgres('postgres://...');

// A public, read-only catalog — no authorization needed.
const products = relation('products')
.select({
Expand All @@ -71,7 +70,11 @@ const products = relation('products')
return response;
},
});
```

**2. Add access policies to a private relation.**

```ts
// Private: every request is scoped to the caller's org.
const orders = relation('orders')
.select({
Expand All @@ -98,21 +101,30 @@ const orders = relation('orders')
},
});
// no .update / .delete → those operations return 403
```

**3. Mount and serve.**

```ts
import { db } from './your-db-client';

const app = new Apigen({ db }).use(products).use(orders);

// app.handle is a WinterTC (Request) => Response
// app.handle is a WinterTC (Request) => Response — mount it into any server
Bun.serve({ fetch: app.handle });
```

Send PostgREST-style requests:
**4. Send requests.**

```bash
# the exposed API is PostgREST-compatible
curl 'http://localhost:3000/products?select=title,price&order=price.desc'

curl -X POST http://localhost:3000/orders -H 'authorization: Bearer ...'
```

Requests are PostgREST-style — the same wire format the Supabase client and PostgREST tooling speak.

## Examples

| Example | What it shows |
Expand Down
Loading