> ## Documentation Index
> Fetch the complete documentation index at: https://greenteagentic.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Server Functions

> Typed RPC between the browser and the Worker.

All server logic lives in `*.functions.ts` files using `createServerFn` from `@tanstack/react-start`.

## `createAndRunBrew`

**File:** `src/lib/brews.functions.ts`
Creates a brew row, seeds five stage rows, runs the full pipeline sequentially, and returns the new `brewId`.

```ts theme={null}
const run = useServerFn(createAndRunBrew);
const { brewId } = await run({
  data: {
    title: "Edge AI in 2026",
    brew_type: "research",
    goal: "Briefing for product team",
    context: "...notes...",
    tone: "calm, precise",
    output_format: "report",
  },
});
```

## `refineBrew`

Takes the current `final_output` plus user feedback and produces a refined output. Appends a row to `brew_outputs` and updates `brews.final_output`.

```ts theme={null}
await refine({ data: { brewId, feedback: "Tighter intro, more examples." } });
```

## `rerunBrew`

Deletes existing `brew_steps`, reseeds them, and runs the pipeline from scratch using the brew's original inputs.

## `archiveAsRecipe`

Snapshots the brew's inputs into a new `recipes` row.

```ts theme={null}
await archive({
  data: { brewId, name: "Weekly competitive scan", description: "..." },
});
```

## Cellar functions

**File:** `src/lib/cellar.functions.ts`

* `listCellar()` — return the user's entries grouped by `kind`.
* `addCellarEntry({ kind, content, weight? })` — manual add.
* `updateCellarEntry({ id, content?, kind?, weight? })` — edit in place.
* `deleteCellarEntry({ id })` — forget an entry.
* `getCellarSettings()` / `updateCellarSettings({ enabled?, max_entries?, manual_pack? })`.

The Cellar is read automatically by `brews.functions.ts` on every stage — you don't need to wire it manually.

## Ingest functions

**File:** `src/lib/ingest.functions.ts`

### `scrapeUrl({ url })`

Scrapes any public URL via Firecrawl, returns `{ title, sourceUrl, markdown }`. Large pages are truncated to 20k characters.

```ts theme={null}
const scraped = await scrape({ data: { url: "https://example.com/post" } });
```

### `searchKeyword({ query, sources, limit, afterReddit?, pageHN? })`

Searches Reddit and/or Hacker News for conversations around a keyword.

| Param         | Type                   | Default            | Description                 |
| ------------- | ---------------------- | ------------------ | --------------------------- |
| `query`       | string                 | required           | Keyword or phrase           |
| `sources`     | `("reddit" \| "hn")[]` | `["reddit", "hn"]` | Which sources to query      |
| `limit`       | number                 | `8`                | Results per source (max 25) |
| `afterReddit` | string?                | —                  | Reddit pagination cursor    |
| `pageHN`      | number                 | `0`                | HN page number via Algolia  |

Returns `{ query, count, markdown, afterReddit, hasMoreHN, nextPageHN }`. Reddit uses cursor-based pagination; HN uses numbered pages. The markdown block includes titles, scores, comment counts, and post snippets grouped by source.

```ts theme={null}
const res = await search({
  data: { query: "agentic workflow", sources: ["reddit", "hn"], limit: 10 },
});
// res.afterReddit → cursor for next Reddit batch
// res.hasMoreHN → true if more HN pages exist
```

## Share functions

**File:** `src/lib/shares.functions.ts`

* `getMyShare({ brewId })` — returns the existing slug, if any.
* `createShare({ brewId })` — mints a new nanoid slug (idempotent if not revoked).
* `revokeShare({ brewId })` — sets `revoked_at`; the public route returns 404 afterwards.

Anonymous reads go through the server route below.

## Wallet auth functions

**File:** `src/lib/wallet-auth.functions.ts`

* `getWalletChallenge({ publicKey })` — issues a one-time nonce to sign.
* `verifyWalletSignature({ publicKey, signature, nonce })` — verifies the Ed25519 signature and returns a Supabase session keyed to the wallet's `auth.users` row.

## Public API route

**File:** `src/routes/api/public/brew.$slug.ts`

`GET /api/public/brew/:slug` returns a safe DTO for the shared brew (no `user_id`, no `context`, no internal step payloads beyond stage names + statuses). Backed by `supabaseAdmin`; protected by slug entropy and `revoked_at`.

## Authoring rules

* Use `.middleware([requireSupabaseAuth])` for any function that touches user data.
* Validate input with Zod via `.inputValidator()`.
* Read secrets like `TEAGENTIC_AI_KEY` inside `.handler()`, never at module scope.
* Don't import server-only modules from client code (the `*.server.ts` suffix blocks this).
