···7788## Defining a label
991010-Create a file in `server/` that exports `defineLabels()` with a `definition` and an `evaluate` function:
1010+Create a file in `server/` that exports `defineLabel()` with a `definition` and an `evaluate` function:
11111212```typescript
1313// server/labels/explicit.ts
1414-import { defineLabels } from '$hatk'
1414+import { defineLabel } from '$hatk'
15151616const EXPLICIT_PATTERNS = [/\(explicit\)/i, /\[explicit\]/i, /\bexplicit version\b/i]
17171818-export default defineLabels({
1818+export default defineLabel({
1919 definition: {
2020 identifier: 'explicit',
2121 severity: 'inform',
···4455**Goal:** Consolidate all server-side code (feeds, xrpc, hooks, labels, og, setup) into a single `server/` directory scanned by export type, with Vite SSR HMR for handler code.
6677-**Architecture:** A new `scanner.ts` module recursively walks `server/`, imports each file, inspects default exports for type tags (`__type: 'feed' | 'query' | 'procedure' | ...`), and routes them to existing subsystem registration. The Vite plugin replaces the `tsx watch` child process with `ssrLoadModule()` for true HMR. Define functions that don't exist yet (`defineSetup`, `defineHook`, `defineLabels`, `defineOG`) are added as thin typed wrappers.
77+**Architecture:** A new `scanner.ts` module recursively walks `server/`, imports each file, inspects default exports for type tags (`__type: 'feed' | 'query' | 'procedure' | ...`), and routes them to existing subsystem registration. The Vite plugin replaces the `tsx watch` child process with `ssrLoadModule()` for true HMR. Define functions that don't exist yet (`defineSetup`, `defineHook`, `defineLabel`, `defineOG`) are added as thin typed wrappers.
8899**Tech Stack:** TypeScript, Vite SSR API (`ssrLoadModule`), existing hatk subsystems
1010···62626363---
64646565-### Task 2: Create defineSetup, defineHook, defineLabels, defineOG
6565+### Task 2: Create defineSetup, defineHook, defineLabel, defineOG
66666767New thin define functions for handler types that currently use raw exports.
68686969**Files:**
7070- Modify: `packages/hatk/src/setup.ts` (add `defineSetup`)
7171- Modify: `packages/hatk/src/hooks.ts` (add `defineHook`)
7272-- Modify: `packages/hatk/src/labels.ts` (add `defineLabels`)
7272+- Modify: `packages/hatk/src/labels.ts` (add `defineLabel`)
7373- Modify: `packages/hatk/src/opengraph.ts` (add `defineOG`)
74747575**Step 1: Add `defineSetup` to setup.ts**
···9494}
9595```
96969797-**Step 3: Add `defineLabels` to labels.ts**
9797+**Step 3: Add `defineLabel` to labels.ts**
98989999First read the `LabelDefinition` type from `config.ts`. Add after the `LabelRuleContext` interface (after line 48):
100100···104104 evaluate?: (ctx: LabelRuleContext) => Promise<string[]>
105105}
106106107107-export function defineLabels(module: LabelModule) {
107107+export function defineLabel(module: LabelModule) {
108108 return { __type: 'labels' as const, ...module }
109109}
110110```
···131131132132```bash
133133git add packages/hatk/src/setup.ts packages/hatk/src/hooks.ts packages/hatk/src/labels.ts packages/hatk/src/opengraph.ts
134134-git commit -m "feat: add defineSetup, defineHook, defineLabels, defineOG"
134134+git commit -m "feat: add defineSetup, defineHook, defineLabel, defineOG"
135135```
136136137137---
···541541542542### Task 7: Export new define functions from package
543543544544-Users need to import `defineSetup`, `defineHook`, `defineLabels`, `defineOG` from the hatk package.
544544+Users need to import `defineSetup`, `defineHook`, `defineLabel`, `defineOG` from the hatk package.
545545546546**Files:**
547547- Modify: `packages/hatk/package.json` (add exports if needed)
···554554```typescript
555555out += `export { defineSetup } from '@hatk/hatk/setup'\n`
556556out += `export { defineHook } from '@hatk/hatk/hooks'\n`
557557-out += `export { defineLabels } from '@hatk/hatk/labels'\n`
557557+out += `export { defineLabel } from '@hatk/hatk/labels'\n`
558558out += `export { defineOG } from '@hatk/hatk/opengraph'\n`
559559```
560560
···334334**Files:**
335335- Modify: `docs/site/guides/labels.md`
336336337337-Brief. Show `defineLabels()` with `evaluate()`. Source from actual label files if they exist in templates, otherwise from CLI scaffolding output.
337337+Brief. Show `defineLabel()` with `evaluate()`. Source from actual label files if they exist in templates, otherwise from CLI scaffolding output.
338338339339**Step 1: Read current page and find examples**
340340**Step 2: Rewrite the page**
···1919| `defineFeed(name, opts)` | Feed generator | handler + hydrator |
2020| `defineHook(event, opts)` | Lifecycle hook | event name (e.g. `'on-login'`) |
2121| `defineSetup(fn)` | Boot-time setup | runs before server starts |
2222-| `defineLabels(defs)` | Label definitions | array of label configs |
2222+| `defineLabel(defs)` | Label definitions | array of label configs |
2323| `defineOG(path, fn)` | OpenGraph image | route path, returns JSX |
24242525**Execution order:** Setup scripts run first (boot), then all other handlers register. During dev, handler files get Vite SSR HMR — edits reload instantly without restarting the database or indexer.
···113113114114**2. Vite SSR integration** — Replace the `tsx watch` spawn in the Vite plugin with Vite's `ssrLoadModule()` for handler files. The hatk core runtime (database, indexer, OAuth) boots once and stays alive. Handler modules get loaded/reloaded through Vite's module graph, giving us HMR for free.
115115116116-**3. Define functions** — `defineQuery`, `defineProcedure`, `defineFeed`, `defineHook`, `defineSetup`, `defineLabels`, `defineOG` all export from `@hatk/hatk`. Each returns a typed descriptor object that the scanner knows how to register. The define functions themselves are thin — they just tag the config with a type and return it.
116116+**3. Define functions** — `defineQuery`, `defineProcedure`, `defineFeed`, `defineHook`, `defineSetup`, `defineLabel`, `defineOG` all export from `@hatk/hatk`. Each returns a typed descriptor object that the scanner knows how to register. The define functions themselves are thin — they just tag the config with a type and return it.
117117118118**4. Build output** — `vite build` produces a server entry point alongside static assets. The entry point imports the scanned handlers and boots the hatk runtime. Production runs with `node dist/server.js`.
119119
···122122123123**Seeds** — `seed()` helper with `createAccount`, `createRecord`, `uploadBlob`. Complete seed file example. `hatk seed` and `hatk reset` commands.
124124125125-**Labels** — `defineLabels()` with `evaluate()`. Brief.
125125+**Labels** — `defineLabel()` with `evaluate()`. Brief.
126126127127**OpenGraph** — `defineOG()` with Satori. Brief.
128128
+1-1
packages/hatk/src/cli.ts
···16961696 out += `export { InvalidRequestError, NotFoundError } from '@hatk/hatk/xrpc'\n`
16971697 out += `export { defineSetup } from '@hatk/hatk/setup'\n`
16981698 out += `export { defineHook } from '@hatk/hatk/hooks'\n`
16991699- out += `export { defineLabels } from '@hatk/hatk/labels'\n`
16991699+ out += `export { defineLabel } from '@hatk/hatk/labels'\n`
17001700 out += `export { defineOG } from '@hatk/hatk/opengraph'\n`
17011701 out += `export { defineRenderer } from '@hatk/hatk/renderer'\n`
17021702 out += `export type Ctx<K extends keyof XrpcSchema & keyof Registry> = XrpcContext<\n`
+1-1
packages/hatk/src/labels.ts
···5252 evaluate?: (ctx: LabelRuleContext) => Promise<string[]>
5353}
54545555-export function defineLabels(module: LabelModule) {
5555+export function defineLabel(module: LabelModule) {
5656 return { __type: 'labels' as const, ...module }
5757}
5858