UNPKG

@lunora/cli

Version:

The Lunora CLI: init, dev, deploy, codegen, migrate, seed, doctor, insights, logs, registry, and the rest of the project commands

143 lines (119 loc) • 6.84 kB
--- name: lunora-create-package description: Builds a reusable Lunora capability, either as a registry item that `lunora add` / `lunora registry add` copies into an app's `lunora/`, or as a publishable `@lunora/*` workspace package in the Lunora monorepo. Use when the user wants to package schema + functions + wrangler bindings + env vars for other apps, add or edit an item under `registry/<name>/` (`registry.json`), run `vis generate lunora-package`, or wire a new `ctx.*` capability into codegen. --- # Lunora Create Package Pick the shape by whether the code is copied into the user's `lunora/` or imported as a dependency: | Shape | Distribution | Use for | | ------------- | -------------------------------- | ------------------------------------------------ | | Registry item | `lunora registry add <name>` | App-owned code (schema/functions) the user edits | | Workspace pkg | `import … from "@lunora/<name>"` | Library code consumed as a versioned dependency | Many capabilities use both: a `@lunora/<name>` package holds the runtime and a registry item scaffolds the glue (files under `lunora/<name>/`, bindings, env vars). `auth`, `mail`, `ratelimit` and `storage` follow this pattern. Skip this skill for a one-off feature in a single app (write it in `lunora/`), or when the capability already exists (`lunora registry list`). ## Path A: registry item An item is a directory `registry/<name>/` holding `registry.json`, the source files it copies, and a `README.md`. Validate against `registry/schema/registry-item.schema.json`. ```jsonc // registry/<name>/registry.json { "$schema": "../schema/registry-item.schema.json", "name": "<name>", "title": "Human Title", "description": "One-paragraph summary shown in `lunora registry list`.", "docs": "Post-install steps printed after `lunora registry add`.", "requires": [], // other items, installed first (e.g. auth-clerk requires auth) "deps": { "@lunora/server": "workspace:*" }, "devDependencies": {}, "bindings": [ // structural edits applied to wrangler.jsonc { "path": ["d1_databases"], "value": [{ "binding": "DB", "database_name": "REPLACE_ME-db", "database_id": "<replace-with-d1-create-id>" }] }, ], "envVars": [{ "name": "MY_SECRET", "description": "What it is and how to generate it.", "secret": true }], "files": [ { "from": "schema.ts", "to": "lunora/<name>/schema.ts", "merge": "schema-extension" }, { "from": "<name>.ts", "to": "lunora/<name>/index.ts", "merge": "create-or-skip" }, ], } ``` - `files[].merge`: `create-or-skip` writes whole files and never clobbers a file the user edited; `schema-extension` AST-merges into `lunora/schema.ts`. - `envVars` land in `.dev.vars`. Non-secret vars get their `value`; secrets get an empty placeholder plus a `wrangler secret put <NAME>` reminder. - `entrypointReexports` (`[{ "module": "_generated/workflows" }]`) injects `export * from './lunora/<module>'` into the worker entry of framework (class B/C) projects, for items whose generated classes the worker must export. No shipped item uses it yet. - Function files import builders from `#lunora/_generated/server.js`, the module codegen emits in a consumer project. `registry/tsconfig.json` stubs that module so the item typechecks here. - `deps` ranges are copied verbatim into the user's `package.json`. Use `workspace:*` for `@lunora/*` (resolved at publish); any other range must admit the version the workspace resolves, or `pnpm install` fails (`scripts/check-registry-catalog-ranges.js`). Verify: ```bash lunora registry build --from ./registry # regenerate registry/index.json from the item dirs lunora registry build --from ./registry --check # CI: index is current pnpm run lint:types:registry # tsc over every item (builds packages first) pnpm run lint:registry:items # manifest + generated-deps tests lunora registry view <name> --from <repo>/registry # preview lunora registry add <name> --from <repo>/registry --dry-run # in a scratch app ``` `registry/index.json` is generated; do not hand-edit it. ## Path B: workspace package (Lunora monorepo) ```bash vis generate lunora-package --name=search --description='Typed full-text search over Lunora tables' --category=add-on ``` Pass every option as `--name=value`; vis reads `--name search` as `--name=true` plus a stray positional. This writes `packages/search/` with `package.json` (ESM-only, `"sideEffects": false`, catalog versions), `src/index.ts`, `tsconfig.json`, `vitest.config.ts`, `packem.config.ts`, `eslint.config.js`, `prettier.config.js`, `project.json` (tags `type:package` + `category:<category>`), `.releaserc.json` and `README.md`. It does not create `__tests__/` or `LICENSE.md`. Then: 1. `cp packages/config/LICENSE.md packages/search/LICENSE.md` (packem and `files` expect it). 2. Add a row to `.agents/docs/packages.md`, and list the directory in one tier of `scripts/api-snapshot.js` and the matching tier in `ROADMAP.md`. The `pnpm install` postinstall checks (`check-agents-md-packages`, `check-roadmap-tiers`) fail until both are done. 3. `pnpm install`, then add tests under `__tests__/`. Repo conventions: relative imports without `.js`, named exports only (a `default` only as a file's sole export), dependency versions via `catalog:*` from `pnpm-workspace.yaml`. Verify: ```bash pnpm --filter "@lunora/search..." run build pnpm --filter "@lunora/search" run lint:types pnpm --filter "@lunora/search" run test pnpm run lint:package-json pnpm run api:update # writes api-snapshots/search.api.md from the fresh build; commit it ``` ## Wiring a `ctx.*` capability into codegen Codegen decides which `ctx.*` fields exist by detecting usage, so a new binding-backed helper is a literal row in `CAPABILITY_ROWS` (`packages/codegen/src/capabilities.ts`; `CAPABILITIES` is a read-only view of it): its package, `ctx` property, tier (`"every"` or `"action"`-only), ctx type fragment, ShardDO binding, and `defineApp` method. Rate the feature for every target in the `PlatformCapabilities` matrices in `@lunora/platform` (`packages/platform/src/capabilities/`) as `native`, `emulated` or `unsupported` in the same change. A feature a target leaves unrated is dropped from that target's generated surface with a diagnostic. Declaration-gated surfaces (flags, notify, containers, workflows, queues, agents) also have their own emitters; some of them (flags, notify, containers, workflows) keep a row too, for usage probing, so a row and a dedicated emitter can coexist. Document in the README any `lunora/*.ts` declaration the user must add for codegen to emit the typed surface.