npm package: @ossy/app
Description: Server-side rendering runtime and build tooling for Ossy apps. Use with `@ossy/cli` for the convention-based setup (`npx @ossy/cli dev`).
Author: Ossy
Latest version: 1.9.0

# `@ossy/app`

Server-side rendering runtime and build tooling for Ossy apps. Use with `@ossy/cli` for the convention-based setup (`npx @ossy/cli dev`).

For custom setups (Next.js, Vite, etc.), use `@ossy/connected-components` directly — see the [root README](../README.md#when-to-use-what).

## Setup

Create `*.page.jsx` files in `src/`:

```jsx
// src/home.page.jsx
import React from 'react'
export default () => <h1>Welcome</h1>
```

Each file becomes a route: `home.page.jsx` → `/`, `about.page.jsx` → `/about`. Optionally export `metadata` for custom id/path or multi-language:

```js
export const metadata = { path: { en: '/about', sv: '/om' } }
export default () => <h1>About</h1>
```

For a single-file setup, use `src/pages.jsx` (legacy).

Split pages are merged into **`build/.ossy/pages.generated.jsx`** (next to other build output) during `dev` / `build`.

**Client JS (per-page):** For each `*.page.jsx`, the build emits **`build/.ossy/hydrate-<pageId>.jsx`** → **`public/static/hydrate-<pageId>.js`**. The HTML for a request only loads the hydrate script for the **current** route (full document navigation), so other pages’ components are not part of that entry. React and shared dependencies still go into hashed shared chunks. The inline config (`window.__INITIAL_APP_CONFIG__`) no longer includes the full `pages` list—only request-time fields (theme, `apiUrl`, etc.).

Add `src/config.js` for workspace and theme:

```js
import { CloudLight } from '@ossy/themes'

export default {
  workspaceId: 'your-workspace-id',
  theme: CloudLight, // or 'light' | 'dark' | CloudDark
  apiUrl: 'https://api.ossy.se/api/v0', // optional
}
```

Config is loaded at build time and merged with request-time settings (e.g. user theme preference from cookies). The server passes `workspaceId`, `apiUrl`, and `theme` to the App component.

Run `npx @ossy/cli dev` or `npx @ossy/cli build`.

If the package has **`src/resource-templates/`**, the build also writes **`.ossy-system-templates.generated.js`** there (merging `*.resource.js` into `SystemTemplates`, ordered by filename).

## API routes

Define HTTP handlers as an array of `{ id, path, handle(req, res) }` objects (same shape the server passes to `@ossy/router`).

Add any number of `*.api.js` (or `.api.mjs` / `.api.cjs`) files under `src/` (nested dirs allowed). Each file’s **default export** is either one route object or an array of routes. Files are merged in lexicographic path order.

Build/dev always writes **`build/.ossy/api.generated.js`** (typically gitignored with `build/`). With no API files it exports an empty array.

Example `src/health.api.js`:

```js
export default {
  id: 'health',
  path: '/api/health',
  handle(req, res) {
    res.json({ status: 'ok' })
  },
}
```

API routes are matched before the app is rendered. The router supports dynamic segments (e.g. `path: '/api/users/:id'`); extract params from `req.originalUrl` if needed. Use paths that don't conflict with `/@ossy/*` (reserved for the internal proxy).

## Background worker tasks (`*.task.js`)

For long-running job processors (separate from the SSR server), use **`npx @ossy/cli build --worker`** in a package that only needs the worker. It uses the same Rollup + Babel pipeline as `ossy build`, discovers **`*.task.js`** (and `.task.mjs` / `.task.cjs`) under `src/` (or `--pages <dir>`), and writes **`build/.ossy/tasks.generated.js`** when needed—same idea as `*.api.js` and the generated API bundle.

Optional legacy aggregate: **`src/tasks.js`** default export is merged **first**, then each `*.task.js` in path order.

Each task file’s **default export** is `{ type, handler }` where `type` matches the platform job type string, and `handler` is `async ({ sdk, job }) => { ... }` (see `@ossy/worker` for examples).

**Override:** `--task-source ./path/to/tasks.js` skips discovery and uses a single file.

Output: **`build/worker.js`**. Run with `node build/worker.js` (after `import 'dotenv/config'` via the entry). Set `OSSY_WORKSPACE_ID`, `OSSY_API_URL`, and `OSSY_API_TOKEN` as before.

## Port configuration

By default, the server listens on port **3000**.

- **Environment variable**: set `PORT`
- **CLI argument**: pass `--port <number>` (or `-p <number>`) when running the built server file

Examples:

```bash
# env var
PORT=4000 node build/server.js

# CLI arg
node build/server.js --port 4000
node build/server.js -p 4000
```