# nifra site (Vue)

A nifra + **Vue** SSR site - file-based routes, typed loaders/actions, hydration - that deploys to
**Bun, Node (Docker), Deno Deploy, Cloudflare Pages, and Vercel Edge from one source**. `app.fetch`
is Web-standard, so only the server entry + build target differ per platform.

```sh
bun install
bun run dev        # nifra dev → true-HMR dev server (Bun + nifra SSR) at http://localhost:3000
bun run preview    # wrangler pages dev dist → preview the built Cloudflare bundle (run `bun run build` first)
```

The backend starter includes response security headers, explicit-origin CORS, a 30-second request
deadline, bounded concurrency, and a development rate limit. Its in-memory rate-limit store refuses
production unless `NIFRA_ALLOW_MEMORY_RATE_LIMIT=true`; use a shared store for multi-instance deploys.
For cookie sessions, add signed CSRF middleware and require both runtime authentication and CSRF
evidence in `nifra.assurance.ts`.

Routes are **Vue SFCs** (`.vue`) under `routes/` - `index.vue` (landing + a live loader/action
counter), `_layout.vue` (chrome via the default slot), `_404.vue`. A route SFC's plain `<script>`
carries nifra's `loader`/`action`/`meta`; `<script setup>` + `<template>` are the component. The
build compiles them with `vueBunPlugin` (`@nifrajs/web-vue/plugin`). The frontend adapter is one line in
`framework.ts`; data lives behind `backend.ts`.

## Deploy - pick a target

| target | build | deploy |
| --- | --- | --- |
| **Bun** (flagship) | `bun run build:bun` | `bun run start` - any host |
| **Node** | `bun run build:node` | `docker build -t app . && docker run -p 3000:3000 app` (or `bun run start:node`) |
| **Deno Deploy** | `bun run build:deno` | `deployctl deploy --prod --entrypoint=dist-deno/server-deno.js` |
| **Cloudflare Pages** | `bun run build` | `bun run deploy:cf` |
| **Vercel Edge** | `bun run build:vercel` | `bun run deploy:vercel` |

The routes, `backend.ts`, and the client bundle are shared; each `build*` script swaps `buildServer`'s
target/conditions and the server entry. nifra never enters your cloud credentials - it scaffolds the
configs (`Dockerfile`, `deno.json`, `wrangler.toml`, Vercel Build Output API); you run the vendor CLI.

## Structure

```
routes/        index.vue (landing), _layout.vue (chrome), _404.vue  (Vue SFCs)
framework.ts   the adapter (vueAdapter) - imported by the server entries (edge-bundlable)
nifra.config.ts the nifra CLI's dev/build config (adapter + clientModule + Vue plugins) - read by `nifra dev`
backend.ts     your contract (loaders/actions call it in-process)
server-bun.ts  Bun entry (Bun.serve)         build-bun.ts    → dist-bun/
_worker.ts     Cloudflare Pages entry        build.ts        → dist/
server-node.ts Node entry (@nifrajs/node)       build-node.ts   → dist-node/   (Dockerfile)
server-deno.ts Deno entry (@nifrajs/deno)       build-deno.ts   → dist-deno/    (deno.json)
server-vercel.ts Vercel Edge function        build-vercel.ts → .vercel/output/
```
