# Pathrule Pattern: Node + TypeScript API (Hono) (1.0.0)
# ::pathrule:package:node-ts-api-hono

### [RULE] Chain routes and export AppType for RPC  (path: /src/routes)
<!-- scope: folder | priority: high | strict -->

The Hono RPC client only sees routes that are part of a single chained expression. Break the chain and `hc<AppType>` resolves responses to `unknown`.

- Define handlers by chaining directly off `new Hono()` (for example `const app = new Hono().get(...).post(...)`); do not assign `app` then call `app.get(...)` on later lines.
- Mount sub-apps inline with `.route('/books', books)` inside the same chain, never as a standalone `app.route(...)` statement.
- Export the route tree as a type with `export type AppType = typeof routes` and import it where you build the client.
- Skip Rails-style controller files; write handlers right after the path so path-param and validator types infer. If you must split, use `factory.createHandlers()`.

---

### [RULE] Validate every input and centralize errors  (path: /src)
<!-- scope: folder | priority: high | strict -->

Untyped `c.req.json()` and raw query params are untrusted input. Every handler reads validated data, and every failure returns one consistent shape.

- Validate `json`, `query`, `param`, `form`, and `header` targets with `zValidator` or the multi-library `sValidator` (`@hono/standard-validator`), then read with `c.req.valid('json')`.
- Return a 400 with a structured body from the validator hook on `!result.success`; do not let invalid data reach business logic.
- Throw `HTTPException` for expected failures (`new HTTPException(404, { message })`) instead of returning ad-hoc error objects.
- Register a single `app.onError((err, c) => ...)` that serializes `HTTPException` via `err.getResponse()` and maps everything else to a 500 without leaking stack traces.

---

### [MEMORY] Hono baseline: versions, runtime, and app wiring  (path: /src)

This API runs Hono v4 (4.12.x line) on Node 22 LTS with TypeScript 5.4+, which the route-param type inference depends on.

- Serve on Node with `@hono/node-server`'s `serve({ fetch: app.fetch, port })`; the same `app` deploys unchanged to Workers, Deno, or Bun because Hono targets Web Standards.
- Keep `src/index.ts` thin: create the root app, attach global middleware (`logger`, `cors`, `secureHeaders`), mount feature routers via chained `.route()`, then `export default app` plus `export type AppType`.
- Use `c.json()`, `c.text()`, and typed `c.var`/context variables instead of mutating Node req/res directly.
- Order middleware deliberately: auth and validation run before handlers; `onError` and `notFound` are registered once on the root app.

---

### [MEMORY] Typed RPC client usage  (path: /src/client)

The frontend and internal callers talk to the API through Hono's RPC client, which derives request and response types straight from `AppType` with no codegen step.

- Build the client with `import { hc } from 'hono/client'` and `const client = hc<AppType>(baseUrl)`; types come from the exported server type, so import it as `import type { AppType }`.
- Call endpoints as method chains, for example `await client.books[':id'].$get({ param: { id } })`, then `await res.json()` is fully typed from the handler's `c.json()` return.
- If responses come back as `unknown`, the cause is almost always a server route mounted outside the chain, not a client bug; fix the chaining on the server.
- For large apps, compile the client type once with `hc<AppType>` and re-export it to cut editor type-checking cost (`hcWithType` pattern).

---

### [SKILL] node-ts-api-hono-review  (path: /)

---
name: node-ts-api-hono-review
description: Review checklist for Node + TypeScript Hono API changes. Run before merging any route, validator, or client change to keep RPC types, validation, and error handling consistent.
---

# Node + TypeScript API (Hono) review

- [ ] Routes are defined as a single chained expression (`new Hono().get(...).post(...)`), not reassigned line by line.
- [ ] Sub-apps are mounted inline with `.route()` inside the chain, and `export type AppType = typeof routes` is present.
- [ ] Every handler reads input via `c.req.valid(...)` behind a `zValidator`/`sValidator`, never raw `c.req.json()` or query params.
- [ ] Validator failure paths return a structured 400; no invalid data reaches business logic.
- [ ] Expected failures throw `HTTPException`; a single `app.onError` serializes errors and hides stack traces on 500.
- [ ] Global middleware (`logger`, `cors`, `secureHeaders`) and `notFound` are registered once on the root app in the right order.
- [ ] Pinned to Hono v4 on Node 22 LTS with TypeScript 5.4+; Node entry uses `@hono/node-server` `serve()`.
- [ ] RPC client uses `hc<AppType>` with `import type`, and responses type-check (no `unknown` leaks).
