npm package: @ossy/cli
Description: Command line tool that makes it easier to interact with our APIs
Author: Ossy
Latest version: 1.9.0

# @ossy/cli

Unified CLI for the Ossy platform: app dev/build and CMS workflows.

## Commands

| Command | Description |
|---------|-------------|
| `init [dir]` | Scaffold a new Ossy app (default: current directory) |
| `dev` | Start dev server with watch (uses `src/*.page.jsx` or `src/pages.jsx`, `src/config.js`) |
| `build` | Production build |
| `publish` | Queue a container deployment via `@ossy/deployment-tools` (**temporary**; see below), then upload `resourceTemplates` and **site build artifacts** (S3 presign + CMS resource) when `workspaceId` is set |
| `cms upload` | Upload resource templates only (same API as publish’s upload step) |
| `cms validate` | Validate ossy config and resource templates |

## App: dev & build

```bash
npx @ossy/cli dev
npx @ossy/cli build
```

Options: e.g. `--config` for `src/config.js`. See `packages/app/README.md` for app build behavior.

## Publish (container / website)

Publishes a site by sending a deployment request to your platform queue (same as `npx @ossy/deployment-tools deployment deploy`). Run from the **website package** directory (where `src/config.js` lives) so domain/platform can be read automatically.

### Temporary: no execution of `src/config.js` for CMS steps

After deploy succeeds, **`publish`** still needs **`workspaceId`**, **`apiUrl`** (optional, for absolute URLs), and **`resourceTemplates`** from `src/config.js`. Those values are **not** loaded with `import()` anymore: running the real config in plain Node would execute imports such as `@ossy/themes`, which are only meant to be resolved during **`ossy build`** (Rollup).

Instead, the CLI uses a **temporary** pipeline:

- **`workspaceId`** and **`apiUrl`** — read with **string-literal regexes** (same idea as deploy hints).
- **`resourceTemplates`** — parsed with **`@babel/parser`** from `export default { … }` when that array is **JSON-like literals only** (no function calls, variables, spreads, or template literals in that subtree).

If `resourceTemplates` cannot be extracted, template upload is skipped. This is a **stopgap** until publish is driven by build output or platform events (see **Future direction**).

### Future direction (planned)

The explicit **`deployment deploy`** step (SQS / deployment queue from **`@ossy/deployment-tools`**) is **intended to go away**: the platform should **react to a website upload / artifact event** (e.g. after the container image or site bundle is published) and roll out without the CLI calling deploy. When that exists, **`publish`** can shrink to CMS-only steps (resource templates + site artifacts), or those can move to separate workflows entirely. Treat the current **deploy + follow-ups** combo as **temporary** coupling.

---

### Authentication

**`publish`** requires **`--authentication` / `-a`** or **`OSSY_API_KEY`**: the **Ossy API JWT** (workspace API token). That same value is used for post-deploy CMS calls (resource templates, site artifacts).

Container deploys assume **Amazon ECR** in **`deployments.json`** (`registry` like `123456789012.dkr.ecr.eu-north-1.amazonaws.com`, **`image`** unchanged). The **worker** always pulls with **IAM** (`aws ecr get-login-password`); nothing in the queue carries a registry password. For **`docker push` from CI**, call **`POST /api/v0/registry/ecr/push-credentials`** with the same JWT and **`workspaceId`**, then **`docker login`** / **`docker push`**.

```bash
cd packages/my-website
export OSSY_API_KEY=<ossy-api-jwt>   # or pass --authentication <ossy-api-jwt>

npx @ossy/cli publish \
  --platforms-path ../infrastructure/platforms.json \
  --deployments-path "../infrastructure/deployments/**/*.json"
```

**Non-ECR container registries** are not supported; container rows in **`deployments.json`** must use **ECR** and a **`registry`** endpoint as described above.

API and worker packages can use the same pattern: a minimal **`src/config.js`** with string-literal **`domain`** (and optional **`platform`**) matching **`deployments.json`**, then run **`publish`** from **`packages/api`** or **`packages/worker`** with **`--skip-resource-templates`** and **`--skip-site-artifacts`** (no website `workspaceId` / `build/` flow).

- **`--domain` / `--platform`** — Optional if `src/config.js` contains string literals `domain: '…'` and `platform: '…'` (or `targetDeploymentPlatform`).
- **`--config`** — Path to another `config.js` if not `./src/config.js`.
- If `platform` is omitted but `domain` is set (from flags or config), it is inferred from `deployments.json` when that domain appears under exactly one `targetDeploymentPlatform`.
- **`--all`** — Runs `deployment deploy-all` for the platform; requires `--platform` or `platform` in config.
- **Resource templates** — After a successful deploy, the CLI reads **`workspaceId`** / **`resourceTemplates`** from `./src/config.js` (or `--config`) using the **static extraction** described above (not `import()`). If **`workspaceId`** is set and **`resourceTemplates`** is a non-empty array, they are **POST**ed to **`{api}/resource-templates`** with the **`workspaceId`** header (same as the CMS). Skipped when **`--skip-resource-templates`** is set, or when `workspaceId` / `resourceTemplates` are missing or not extractable.
- **Site artifacts** — Uses the same **static `workspaceId` / `apiUrl` extraction** as resource templates. If **`workspaceId`** is set and **`build/`** exists next to `src/` (i.e. run **`npm run build`** first), the CLI calls **`/site-artifacts/presign-batch`**, **PUT**s each file to S3, then **`/site-artifacts/commit-batch`** so a **`@ossy/platform/site-artifact-batch`** resource is created in the CMS. Skipped with **`--skip-site-artifacts`**, when there is no **`build/`**, or when **`workspaceId`** is missing. Override the build output directory with **`--site-artifacts-build-dir`** (absolute or cwd-relative).
- **`--api-url`** — Optional API base for CMS calls (e.g. `https://api.ossy.se/api/v0`). Otherwise **`OSSY_API_URL`**, else an **absolute** `apiUrl` from config, else `https://api.ossy.se/api/v0`. Relative app `apiUrl` values (e.g. `/@ossy`) are ignored unless you pass **`--api-url`** or set **`OSSY_API_URL`**.

Requires network access so `npx` can run `@ossy/deployment-tools`.

## CMS: upload

Upload resource templates to your workspace so they can be used in the UI.

Prefer **`--authentication` / `-a`** for the **Ossy API JWT** (same as **`publish`**); it matches **`OSSY_API_KEY`** in CI.

```bash
npx @ossy/cli cms upload --authentication <ossy-api-jwt> --config src/config.js
# optional: --api-url https://api.ossy.se/api/v0  (or set OSSY_API_URL)
# In CI you may omit --authentication when OSSY_API_KEY is set
```

When **`--config`** is omitted, **`./src/config.js`** is used if it exists (same as **`publish`**).

### Config consistency

- **App** (`dev`, `build`), **CMS** (`cms upload` / `cms validate`), and **publish** all use **`--config`** (`-c`) for the app / workspace config file (`src/config.js` by default when present).

### Workflow example

Prefer **`publish`** so deploy and template upload run together (see **Publish** above). For template-only updates, `cms upload` still works.

```yaml
name: "[CMS] Upload resource templates"

on:
  workflow_dispatch:

jobs:
  upload-resource-templates:
    name: Upload resource templates
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: "16"
      - name: Upload
        run: |
          npx --yes @ossy/cli cms upload \
            --authentication ${{ secrets.OSSY_API_KEY }} \
            --config src/config.js
```

### cms validate

Validate an ossy config file before uploading:

```bash
npx @ossy/cli cms validate --config src/config.js
```

When **`--config`** is omitted, **`./src/config.js`** is used if it exists.

### Arguments

| Argument | Description | Required |
|----------|-------------|----------|
| --authentication, -a | **Ossy API JWT** (primary; same role as **`OSSY_API_KEY`**) | Yes (upload only) |
| --config, -c | App config (`workspaceId`, `resourceTemplates`, …) | Optional if `./src/config.js` exists |
| --api-url | API base URL for upload (`…/api/v0`) | No |

## init

Scaffold a new Ossy app:

```bash
npx @ossy/cli init
npx @ossy/cli init my-app
```

Creates `src/pages.jsx`, `src/config.js`, and `package.json` (if missing).