node-app-build 6.5.0

Mini app developer CLI: scaffold, validate, package node-app-* Debian packages
# AGENTS.md — coding agent onboarding for {{name}}

> **You are a coding agent working in `node-app-{{name}}`.**
> This app was scaffolded by `node-app new --profile native-fullstack`.
> It is a **native Rust cdylib loaded in-process by the platform** plus an
> **embedded React + Vite UI bundle** served by the platform reverse-proxy.
> It is NOT eligible for the shared Bun runtime (#810) — that feature is
> for Bun apps. Native apps already share the host process.

## What this means for you

- **No `Bun.serve()`, no own HTTP listener, no own systemd unit.** The
  platform's native loader resolves `_node_app_entry` from your `.so` and
  calls `init() → handle_capability() → shutdown()` directly.
- **In-process**: a panic in your code crashes the host. Use `Result` and
  `?` everywhere; avoid `.unwrap()` outside tests.
- **UI is served by the platform, not by you.** Build with
  `bun --cwd ui build`, ship `ui/dist/` via the .deb, and the platform's
  reverse-proxy mounts it at `/api/v2/node-apps/{{name}}/ui/`. Same-origin
  → no CORS, no token flapping.
- **FirstParty tier requires GPG signing.** Non-econ-v1 community apps
  should prefer the `bun-fullstack` profile.

## First files to open

| File | Why |
|---|---|
| `src/lib.rs` | the `NodeApp` impl + `declare_node_app!(App)` |
| `ui/src/App.tsx` | iframe handshake (postMessage `ready``auth_token`) |
| `manifest.json` | declare your capabilities; `has_ui: true`, `ui_path: "ui/dist"` |
| `Cargo.toml` | add crate deps (keep `node-app-sdk-rust` pinned) |
| `ui/package.json` | UI deps (React 19 + Vite 6 pre-installed) |
| `node-app.toml` | per-app dev config |

## UI ↔ backend handshake

The iframe is same-origin. The handshake is:

1. UI mounts → posts `{ type: 'ready' }` to `window.parent`.
2. Platform replies with `{ type: 'auth_token', token, expires_at }`.
3. UI uses the token as `Authorization: Bearer ${token}` for any backend
   fetches (`/api/v2/node-apps/{{name}}/api/...`).
4. Platform refreshes by posting another `auth_token` before expiry.

The default `ui/src/App.tsx` wires this up — copy the pattern when adding
your own routes.

## HTTP routes from native (if you need them)

The default `src/lib.rs` doesn't expose HTTP routes — most native apps only
need capabilities + a UI bundle (the iframe calls
`/api/v2/node-apps/{{name}}/api/...` which the platform proxies into your
`http_handler` capability if declared).

To add HTTP routes:

1. Add `http_handler` to `manifest.json` `capabilities.provides`.
2. Implement a `handle_capability("http_handler", ...)` branch that takes a
   JSON-encoded request `{ method, path, headers, body }` and returns
   `{ status, headers, body }`.

## Useful commands

```bash
node-app audit            # check this app against the blueprint
node-app dev              # hot-reload dev loop against a local monorepo
node-app build            # build cdylib + ui/dist (phase 3 of #868)
node-app package          # build .deb (phase 3 of #868)
```

## Don'ts

- Don't make HTTP calls to localhost host ports. Use `invoke_capability()`.
- Don't export extra `pub extern "C"` symbols beyond `_node_app_entry`.
- Don't fetch cross-origin from the UI. Backend requests must use the
  same-origin `/api/v2/node-apps/{{name}}/api/...` path.
- Don't expect shared-runtime memory savings — that's a Bun-only feature.