@lunora/cli 1.0.0-alpha.47 → 1.0.0-alpha.471
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +33 -0
- package/README.md +3 -1
- package/dist/bin.mjs +3 -10
- package/dist/cli.d.mts +31 -0
- package/dist/cli.d.ts +31 -0
- package/dist/cli.mjs +1 -0
- package/dist/index.d.mts +1167 -416
- package/dist/index.d.ts +1167 -416
- package/dist/index.mjs +1 -19
- package/dist/packem_chunks/cli.mjs +2 -0
- package/dist/packem_chunks/dispatch.mjs +1 -0
- package/dist/packem_chunks/handler.mjs +55 -158
- package/dist/packem_chunks/handler10.mjs +2 -16
- package/dist/packem_chunks/handler11.mjs +1 -22
- package/dist/packem_chunks/handler12.mjs +1 -192
- package/dist/packem_chunks/handler13.mjs +1 -131
- package/dist/packem_chunks/handler14.mjs +3 -65
- package/dist/packem_chunks/handler15.mjs +1 -58
- package/dist/packem_chunks/handler16.mjs +1 -80
- package/dist/packem_chunks/handler17.mjs +1 -43
- package/dist/packem_chunks/handler18.mjs +1 -105
- package/dist/packem_chunks/handler19.mjs +1 -170
- package/dist/packem_chunks/handler2.mjs +1 -114
- package/dist/packem_chunks/handler20.mjs +1 -94
- package/dist/packem_chunks/handler21.mjs +7 -94
- package/dist/packem_chunks/handler22.mjs +1 -0
- package/dist/packem_chunks/handler23.mjs +3 -0
- package/dist/packem_chunks/handler24.mjs +3 -0
- package/dist/packem_chunks/handler25.mjs +2 -0
- package/dist/packem_chunks/handler26.mjs +1 -0
- package/dist/packem_chunks/handler27.mjs +2 -0
- package/dist/packem_chunks/handler28.mjs +99 -0
- package/dist/packem_chunks/handler29.mjs +3 -0
- package/dist/packem_chunks/handler3.mjs +1 -204
- package/dist/packem_chunks/handler30.mjs +15 -0
- package/dist/packem_chunks/handler31.mjs +1 -0
- package/dist/packem_chunks/handler32.mjs +1 -0
- package/dist/packem_chunks/handler4.mjs +1 -33
- package/dist/packem_chunks/handler5.mjs +1 -49
- package/dist/packem_chunks/handler6.mjs +3 -91
- package/dist/packem_chunks/handler7.mjs +1 -42
- package/dist/packem_chunks/handler8.mjs +1 -174
- package/dist/packem_chunks/handler9.mjs +1 -315
- package/dist/packem_chunks/runCodegenCommand.mjs +4 -52
- package/dist/packem_chunks/runDevCommand.mjs +6 -0
- package/dist/packem_chunks/runInitCommand.mjs +423 -1447
- package/dist/packem_chunks/runResetCommand.mjs +1 -41
- package/dist/packem_chunks/runRpcCommand.mjs +1 -68
- package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck9tABfr.mjs +1 -0
- package/dist/packem_shared/EXIT_CODE-DQVhSE-1.mjs +1 -0
- package/dist/packem_shared/admin-token-VdUnvnKW.mjs +1 -0
- package/dist/packem_shared/admin-url-DJB8P6Jh.mjs +1 -0
- package/dist/packem_shared/api-spec-lYyq4vL6.mjs +1 -0
- package/dist/packem_shared/binding-manifest-file-CQ1eQYy1.mjs +2 -0
- package/dist/packem_shared/buildRegistryIndex-Dc8D8AR6.mjs +1 -0
- package/dist/packem_shared/cap-error-body-YBKO32BF.mjs +1 -0
- package/dist/packem_shared/catalog-CahzmDLV.mjs +1 -0
- package/dist/packem_shared/cli-manifest-DoQ_3bzs.mjs +1 -0
- package/dist/packem_shared/cloudflare-credentials-BVmZnDZk.mjs +1 -0
- package/dist/packem_shared/codegen-error-AmH54ofi.mjs +3 -0
- package/dist/packem_shared/command-BpMv2n0o.mjs +1 -0
- package/dist/packem_shared/commands-CkuCMUP_.mjs +13 -0
- package/dist/packem_shared/createLogger-4TujevyB.mjs +2 -0
- package/dist/packem_shared/createRecordingSpawner-DchLi0gR.mjs +1 -0
- package/dist/packem_shared/deploy-target-resolve-BTCW1Iv4.mjs +1 -0
- package/dist/packem_shared/diffSnapshots-Y1G8am6C.mjs +7 -0
- package/dist/packem_shared/docker-DpVxvYpL.mjs +1 -0
- package/dist/packem_shared/export-rows-EzdNDYpa.mjs +3 -0
- package/dist/packem_shared/free-port-DjbFhaaT.mjs +1 -0
- package/dist/packem_shared/health-probe-BLnoq_oC.mjs +13 -0
- package/dist/packem_shared/import-3Y59Ry9F.mjs +13 -0
- package/dist/packem_shared/index-oHZBGBwB.mjs +1 -0
- package/dist/packem_shared/insertSchemaExtension-CbTH3lCQ.mjs +10 -0
- package/dist/packem_shared/js-literal-FWLi94Lh.mjs +1 -0
- package/dist/packem_shared/lint-ignore-report-DKZagpqk.mjs +2 -0
- package/dist/packem_shared/mcp-config-file-GR1Y_CVw.mjs +2 -0
- package/dist/packem_shared/open-url-EnKy--w-.mjs +1 -0
- package/dist/packem_shared/output-format-DWe_tkTR.mjs +2 -0
- package/dist/packem_shared/parseManifest-CwPTKdtS.mjs +1 -0
- package/dist/packem_shared/path-containment-CgxYZggb.mjs +1 -0
- package/dist/packem_shared/plan-pog5AvMk.mjs +5 -0
- package/dist/packem_shared/planDevCommand-Bl6OrwXm.mjs +1 -0
- package/dist/packem_shared/platform-diagnostics-Cn2g6Jh-.mjs +4 -0
- package/dist/packem_shared/prompt-cancelled-BvsNxg_Q.mjs +1 -0
- package/dist/packem_shared/render-lunora-error-JsLelWwR.mjs +2 -0
- package/dist/packem_shared/resolve-Bdc9KEUv.mjs +5 -0
- package/dist/packem_shared/resolve-target-BRvw8Pf7.mjs +1 -0
- package/dist/packem_shared/runAddCommand-gThKW-ZB.mjs +1 -0
- package/dist/packem_shared/runDeployCommand-CNgOUx91.mjs +1 -0
- package/dist/packem_shared/runExportCommand-_PtkJJDT.mjs +5 -0
- package/dist/packem_shared/runMigrateGenerateCommand-CguLEIZp.mjs +11 -0
- package/dist/packem_shared/schemaIrToSnapshot-Ck7DSPdf.mjs +1 -0
- package/dist/packem_shared/shared-CV7ESvuj.mjs +2 -0
- package/dist/packem_shared/storage-3GOIFVZm.mjs +1 -0
- package/dist/packem_shared/tui-prompts-B3YwUhGw.mjs +4 -0
- package/dist/packem_shared/variables-CPYyJtsL.mjs +1 -0
- package/dist/packem_shared/vectorize-metadata-DK61NmVx.mjs +2 -0
- package/dist/packem_shared/wrangler-name-Dsk5K1f-.mjs +1 -0
- package/dist/packem_shared/wrangler-secrets-C9siMBwN.mjs +1 -0
- package/package.json +45 -19
- package/skills/README.md +36 -17
- package/skills/lunora/SKILL.md +158 -65
- package/skills/lunora-cloudflare-audit/SKILL.md +164 -0
- package/skills/lunora-create-package/SKILL.md +97 -84
- package/skills/lunora-deploy/SKILL.md +212 -102
- package/skills/lunora-functions/SKILL.md +367 -60
- package/skills/lunora-migration-helper/SKILL.md +194 -149
- package/skills/lunora-performance-audit/SKILL.md +137 -95
- package/skills/lunora-quickstart/SKILL.md +136 -136
- package/skills/lunora-realtime/SKILL.md +217 -97
- package/skills/lunora-setup-auth/SKILL.md +203 -101
- package/skills/lunora-setup-hyperdrive/SKILL.md +153 -110
- package/skills/lunora-setup-hyperdrive-global/SKILL.md +152 -94
- package/skills/lunora-setup-mail/SKILL.md +87 -113
- package/skills/lunora-setup-scheduler/SKILL.md +133 -97
- package/skills/lunora-setup-storage/SKILL.md +189 -95
- package/dist/packem_chunks/planDevCommand.mjs +0 -541
- package/dist/packem_chunks/runDeployCommand.mjs +0 -594
- package/dist/packem_chunks/runMigrateGenerateCommand.mjs +0 -397
- package/dist/packem_shared/COMMANDS-B0ftFD_3.mjs +0 -948
- package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs +0 -244
- package/dist/packem_shared/admin-url-4UzT-CI4.mjs +0 -19
- package/dist/packem_shared/api-spec-CtA6ilu4.mjs +0 -13
- package/dist/packem_shared/buildRegistryIndex-BcYe607_.mjs +0 -38
- package/dist/packem_shared/codegen-error-DJG-ghs_.mjs +0 -31
- package/dist/packem_shared/command-D3lB_4Az.mjs +0 -19
- package/dist/packem_shared/commands-B-gR09Z_.mjs +0 -845
- package/dist/packem_shared/createLogger-B40gPzQo.mjs +0 -78
- package/dist/packem_shared/createRecordingSpawner-DxI3mebw.mjs +0 -43
- package/dist/packem_shared/detect-package-manager-DYp7n3mJ.mjs +0 -61
- package/dist/packem_shared/diffSnapshots-BeDvvNiF.mjs +0 -161
- package/dist/packem_shared/docker-hMQ97KSQ.mjs +0 -21
- package/dist/packem_shared/insertSchemaExtension-DAqbfr9Z.mjs +0 -64
- package/dist/packem_shared/open-url-Dfq6fAyT.mjs +0 -41
- package/dist/packem_shared/output-format-wUvAN6AL.mjs +0 -17
- package/dist/packem_shared/parseArgs-YXFuKdEk.mjs +0 -56
- package/dist/packem_shared/parseManifest--vZf2FY1.mjs +0 -94
- package/dist/packem_shared/prompt-cancelled-APzX1Im-.mjs +0 -9
- package/dist/packem_shared/resolve-target-qbsJ_5sF.mjs +0 -16
- package/dist/packem_shared/runAddCommand-bnY6-HKb.mjs +0 -4
- package/dist/packem_shared/schema-drift-gate-BtBt0as0.mjs +0 -79
- package/dist/packem_shared/schemaIrToSnapshot-DdsljJT-.mjs +0 -43
- package/dist/packem_shared/storage-BIsph-Vk.mjs +0 -84
- package/dist/packem_shared/tui-prompts-BjEN8XgP.mjs +0 -658
- package/dist/packem_shared/wrangler-name-cy4yhm9j.mjs +0 -12
- package/dist/packem_shared/wrangler-secrets-P2_ZUR-k.mjs +0 -47
|
@@ -1,47 +1,36 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lunora-create-package
|
|
3
|
-
description: Builds a reusable Lunora capability
|
|
4
|
-
`lunora registry add
|
|
5
|
-
|
|
3
|
+
description: Builds a reusable Lunora capability, either as a registry item that
|
|
4
|
+
`lunora add` / `lunora registry add` copies into an app's `lunora/`, or as a
|
|
5
|
+
publishable `@lunora/*` workspace package in the Lunora monorepo. Use when the
|
|
6
|
+
user wants to package schema + functions + wrangler bindings + env vars for
|
|
7
|
+
other apps, add or edit an item under `registry/<name>/` (`registry.json`),
|
|
8
|
+
run `vis generate lunora-package`, or wire a new `ctx.*` capability into
|
|
9
|
+
codegen.
|
|
6
10
|
---
|
|
7
11
|
|
|
8
12
|
# Lunora Create Package
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
**imported as a dependency**.
|
|
14
|
+
Pick the shape by whether the code is copied into the user's `lunora/` or
|
|
15
|
+
imported as a dependency:
|
|
13
16
|
|
|
14
|
-
| Shape
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
17
|
+
| Shape | Distribution | Use for |
|
|
18
|
+
| ------------- | -------------------------------- | ------------------------------------------------ |
|
|
19
|
+
| Registry item | `lunora registry add <name>` | App-owned code (schema/functions) the user edits |
|
|
20
|
+
| Workspace pkg | `import … from "@lunora/<name>"` | Library code consumed as a versioned dependency |
|
|
18
21
|
|
|
19
|
-
Many capabilities use
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
and `storage` all follow this pattern.
|
|
22
|
+
Many capabilities use both: a `@lunora/<name>` package holds the runtime and a
|
|
23
|
+
registry item scaffolds the glue (files under `lunora/<name>/`, bindings, env
|
|
24
|
+
vars). `auth`, `mail`, `ratelimit` and `storage` follow this pattern.
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
Skip this skill for a one-off feature in a single app (write it in `lunora/`),
|
|
27
|
+
or when the capability already exists (`lunora registry list`).
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
- Authoring a new capability (presence, search, payments, …) for other apps.
|
|
28
|
-
- Adding a new item to this repo's `registry/`.
|
|
29
|
+
## Path A: registry item
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
- The capability already exists as a registry item or `@lunora/*` package — use
|
|
34
|
-
it (`lunora registry list` to browse).
|
|
35
|
-
|
|
36
|
-
## Path A: Registry Item
|
|
37
|
-
|
|
38
|
-
A registry item is a directory under `registry/<name>/` with three files:
|
|
39
|
-
|
|
40
|
-
- `registry.json` — the manifest (deps, bindings, env vars, files, requires).
|
|
41
|
-
- `index.ts` (and any siblings) — the code copied into the user's project.
|
|
42
|
-
- `README.md` — install + configuration docs.
|
|
43
|
-
|
|
44
|
-
### Manifest shape
|
|
31
|
+
An item is a directory `registry/<name>/` holding `registry.json`, the source
|
|
32
|
+
files it copies, and a `README.md`. Validate against
|
|
33
|
+
`registry/schema/registry-item.schema.json`.
|
|
45
34
|
|
|
46
35
|
```jsonc
|
|
47
36
|
// registry/<name>/registry.json
|
|
@@ -50,80 +39,104 @@ A registry item is a directory under `registry/<name>/` with three files:
|
|
|
50
39
|
"name": "<name>",
|
|
51
40
|
"title": "Human Title",
|
|
52
41
|
"description": "One-paragraph summary shown in `lunora registry list`.",
|
|
53
|
-
"docs": "Post-install steps
|
|
54
|
-
"requires": [], // other
|
|
42
|
+
"docs": "Post-install steps printed after `lunora registry add`.",
|
|
43
|
+
"requires": [], // other items, installed first (e.g. auth-clerk requires auth)
|
|
55
44
|
"deps": { "@lunora/server": "workspace:*" },
|
|
45
|
+
"devDependencies": {},
|
|
56
46
|
"bindings": [
|
|
57
|
-
//
|
|
47
|
+
// structural edits applied to wrangler.jsonc
|
|
58
48
|
{ "path": ["d1_databases"], "value": [{ "binding": "DB", "database_name": "REPLACE_ME-db", "database_id": "<replace-with-d1-create-id>" }] },
|
|
59
49
|
],
|
|
60
50
|
"envVars": [{ "name": "MY_SECRET", "description": "What it is and how to generate it.", "secret": true }],
|
|
61
|
-
"files": [
|
|
51
|
+
"files": [
|
|
52
|
+
{ "from": "schema.ts", "to": "lunora/<name>/schema.ts", "merge": "schema-extension" },
|
|
53
|
+
{ "from": "<name>.ts", "to": "lunora/<name>/index.ts", "merge": "create-or-skip" },
|
|
54
|
+
],
|
|
62
55
|
}
|
|
63
56
|
```
|
|
64
57
|
|
|
65
|
-
- `files[].merge
|
|
66
|
-
`
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
58
|
+
- `files[].merge`: `create-or-skip` writes whole files and never clobbers a file
|
|
59
|
+
the user edited; `schema-extension` AST-merges into `lunora/schema.ts`.
|
|
60
|
+
- `envVars` land in `.dev.vars`. Non-secret vars get their `value`; secrets get
|
|
61
|
+
an empty placeholder plus a `wrangler secret put <NAME>` reminder.
|
|
62
|
+
- `entrypointReexports` (`[{ "module": "_generated/workflows" }]`) injects
|
|
63
|
+
`export * from './lunora/<module>'` into the worker entry of framework
|
|
64
|
+
(class B/C) projects, for items whose generated classes the worker must
|
|
65
|
+
export. No shipped item uses it yet.
|
|
66
|
+
- Function files import builders from `#lunora/_generated/server.js`, the
|
|
67
|
+
module codegen emits in a consumer project. `registry/tsconfig.json` stubs
|
|
68
|
+
that module so the item typechecks here.
|
|
69
|
+
- `deps` ranges are copied verbatim into the user's `package.json`. Use
|
|
70
|
+
`workspace:*` for `@lunora/*` (resolved at publish); any other range must
|
|
71
|
+
admit the version the workspace resolves, or `pnpm install` fails
|
|
72
|
+
(`scripts/check-registry-catalog-ranges.js`).
|
|
73
|
+
|
|
74
|
+
Verify:
|
|
74
75
|
|
|
75
76
|
```bash
|
|
76
|
-
lunora registry build
|
|
77
|
-
lunora registry build --check
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
lunora registry build --from ./registry # regenerate registry/index.json from the item dirs
|
|
78
|
+
lunora registry build --from ./registry --check # CI: index is current
|
|
79
|
+
pnpm run lint:types:registry # tsc over every item (builds packages first)
|
|
80
|
+
pnpm run lint:registry:items # manifest + generated-deps tests
|
|
81
|
+
lunora registry view <name> --from <repo>/registry # preview
|
|
82
|
+
lunora registry add <name> --from <repo>/registry --dry-run # in a scratch app
|
|
80
83
|
```
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
`registry/index.json` is generated; do not hand-edit it.
|
|
83
86
|
|
|
84
|
-
|
|
85
|
-
`--name=value` form):
|
|
87
|
+
## Path B: workspace package (Lunora monorepo)
|
|
86
88
|
|
|
87
89
|
```bash
|
|
88
|
-
vis generate lunora-package --name=search --description='Typed full-text search over Lunora tables'
|
|
90
|
+
vis generate lunora-package --name=search --description='Typed full-text search over Lunora tables' --category=add-on
|
|
89
91
|
```
|
|
90
92
|
|
|
91
|
-
|
|
92
|
-
`
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
Pass every option as `--name=value`; vis reads `--name search` as
|
|
94
|
+
`--name=true` plus a stray positional.
|
|
95
|
+
|
|
96
|
+
This writes `packages/search/` with `package.json` (ESM-only,
|
|
97
|
+
`"sideEffects": false`, catalog versions), `src/index.ts`, `tsconfig.json`,
|
|
98
|
+
`vitest.config.ts`, `packem.config.ts`, `eslint.config.js`,
|
|
99
|
+
`prettier.config.js`, `project.json` (tags `type:package` +
|
|
100
|
+
`category:<category>`), `.releaserc.json` and `README.md`. It does not create
|
|
101
|
+
`__tests__/` or `LICENSE.md`. Then:
|
|
95
102
|
|
|
96
|
-
|
|
103
|
+
1. `cp packages/config/LICENSE.md packages/search/LICENSE.md` (packem and
|
|
104
|
+
`files` expect it).
|
|
105
|
+
2. Add a row to `.agents/docs/packages.md`, and list the directory in one tier
|
|
106
|
+
of `scripts/api-snapshot.js` and the matching tier in `ROADMAP.md`. The
|
|
107
|
+
`pnpm install` postinstall checks (`check-agents-md-packages`,
|
|
108
|
+
`check-roadmap-tiers`) fail until both are done.
|
|
109
|
+
3. `pnpm install`, then add tests under `__tests__/`.
|
|
97
110
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
more than one export.
|
|
102
|
-
- **Use the dependency catalogs** in `pnpm-workspace.yaml` (`catalog:test`,
|
|
103
|
-
`catalog:lint`, …) — never hard-code a version that lives in a catalog.
|
|
104
|
-
- Tag `project.json` with `type:package` and a `category:<slug>`.
|
|
111
|
+
Repo conventions: relative imports without `.js`, named exports only (a
|
|
112
|
+
`default` only as a file's sole export), dependency versions via `catalog:*`
|
|
113
|
+
from `pnpm-workspace.yaml`.
|
|
105
114
|
|
|
106
|
-
|
|
115
|
+
Verify:
|
|
107
116
|
|
|
108
117
|
```bash
|
|
118
|
+
pnpm --filter "@lunora/search..." run build
|
|
109
119
|
pnpm --filter "@lunora/search" run lint:types
|
|
110
120
|
pnpm --filter "@lunora/search" run test
|
|
121
|
+
pnpm run lint:package-json
|
|
122
|
+
pnpm run api:update # writes api-snapshots/search.api.md from the fresh build; commit it
|
|
111
123
|
```
|
|
112
124
|
|
|
113
|
-
##
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
## Wiring a `ctx.*` capability into codegen
|
|
126
|
+
|
|
127
|
+
Codegen decides which `ctx.*` fields exist by detecting usage, so a new
|
|
128
|
+
binding-backed helper is a literal row in `CAPABILITY_ROWS`
|
|
129
|
+
(`packages/codegen/src/capabilities.ts`; `CAPABILITIES` is a read-only view of
|
|
130
|
+
it): its package, `ctx` property, tier
|
|
131
|
+
(`"every"` or `"action"`-only), ctx type fragment, ShardDO binding, and
|
|
132
|
+
`defineApp` method. Rate the feature for every target in the
|
|
133
|
+
`PlatformCapabilities` matrices in `@lunora/platform`
|
|
134
|
+
(`packages/platform/src/capabilities/`) as `native`, `emulated` or
|
|
135
|
+
`unsupported` in the same change. A feature a target leaves unrated is dropped
|
|
136
|
+
from that target's generated surface with a diagnostic. Declaration-gated
|
|
137
|
+
surfaces (flags, notify, containers, workflows, queues, agents) also have their
|
|
138
|
+
own emitters; some of them (flags, notify, containers, workflows) keep a row too,
|
|
139
|
+
for usage probing, so a row and a dedicated emitter can coexist.
|
|
140
|
+
|
|
141
|
+
Document in the README any `lunora/*.ts` declaration the user must add for
|
|
142
|
+
codegen to emit the typed surface.
|
|
@@ -1,150 +1,260 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lunora-deploy
|
|
3
|
-
description: Deploys a Lunora app to Cloudflare.
|
|
4
|
-
bindings (SHARD/SESSION DOs, D1, R2), provisioning databases/buckets, secrets
|
|
5
|
-
(`wrangler secret` vs `.dev.vars`), the `lunora doctor` preflight, the
|
|
6
|
-
schema-drift gate, and dev-vs-prod separation.
|
|
3
|
+
description: Deploys a Lunora app to Cloudflare Workers + Durable Objects and gets wrangler.jsonc, remote resources and secrets to line up. Covers `lunora deploy` (and `--env`, `--dry-run`, `--migrate`), isolated per-PR previews (`lunora preview deploy | list | delete`), the `lunora doctor` / `lunora verify` / `lunora prepare` preflights, Durable Object bindings (SHARD, SHARD_REGISTRY, SCHEDULER), the `DB` D1 binding and its placeholder id, R2 buckets, production secrets (`lunora env push`, `wrangler secret put`) versus `.dev.vars`, the schema-drift gate, the architecture diff, and rollback with `lunora cloudflare deployments`. Use when the user asks to "deploy", "ship to production", "set up a staging environment", wire CI deploys, or when a deploy fails on a binding, a placeholder `database_id`, an unexported Durable Object class, a missing secret, or "schema drift gate blocked deploy".
|
|
7
4
|
---
|
|
8
5
|
|
|
9
6
|
# Lunora Deploy
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
Deploying a Lunora app means making `wrangler.jsonc`, the remote Cloudflare
|
|
9
|
+
resources (D1, R2, secrets) and the worker's exports agree. `lunora deploy`
|
|
10
|
+
automates most of that and refuses to ship when they don't.
|
|
11
|
+
|
|
12
|
+
Local development is `lunora dev` (see `lunora-quickstart`). If the deploy is
|
|
13
|
+
blocked by a breaking schema change, stage it with `lunora-migration-helper`
|
|
14
|
+
first.
|
|
15
|
+
|
|
16
|
+
## What `lunora deploy` does
|
|
17
|
+
|
|
18
|
+
In order, stopping at the first failure:
|
|
19
|
+
|
|
20
|
+
1. **Codegen** — regenerates `lunora/_generated/`. ERROR-level codegen
|
|
21
|
+
advisories fail the deploy in CI (`--strict-advisories` forces this locally,
|
|
22
|
+
`--no-strict-advisories` turns it off). Nothing here runs `tsc` and wrangler
|
|
23
|
+
strips types, so a project with a type error deploys — gate CI on
|
|
24
|
+
`lunora verify`, which does type-check.
|
|
25
|
+
2. **Schema-drift gate** — compares the schema with the committed baseline
|
|
26
|
+
`lunora/.lunora-schema.json` (details below).
|
|
27
|
+
3. **Architecture diff** — prints modules and edges (calls, table reads/writes,
|
|
28
|
+
enqueues) added or removed since the last successful deploy. Informational
|
|
29
|
+
only; the manifest is recorded in `.lunora/architecture[.<env>].json` after
|
|
30
|
+
wrangler succeeds.
|
|
31
|
+
4. **Binding reconcile** — writes the bindings the code implies into
|
|
32
|
+
`wrangler.jsonc`: Durable Object bindings plus their `new_sqlite_classes`
|
|
33
|
+
migration, the `DB` D1 binding for `.global()` tables, crons, and the
|
|
34
|
+
compatibility date. R2 buckets are not auto-written (the bucket name is
|
|
35
|
+
yours to choose); you get a warning instead.
|
|
36
|
+
5. **Read-only checks** — blocks on a D1 `database_id` still set to
|
|
37
|
+
`<replace-with-d1-create-id>`, on a loopback URL (`localhost`, `127.x`,
|
|
38
|
+
`::1`) in `vars`, on a missing container Dockerfile, or on no Docker engine
|
|
39
|
+
when a container builds locally.
|
|
40
|
+
6. **Validate `wrangler.jsonc`** — the `SHARD` binding to `ShardDO` (or
|
|
41
|
+
`LunoraDO` for apps that merge their DOs), a minimum `compatibility_date`,
|
|
42
|
+
DO classes registered in `migrations`, and the shape of every binding.
|
|
43
|
+
`compatibility_flags` are not checked; templates ship `nodejs_compat` for
|
|
44
|
+
dependencies that import `node:` builtins.
|
|
45
|
+
7. **Secrets gate** — lists the secrets the app's packages need and checks
|
|
46
|
+
which are set on the worker. Interactive runs offer to mint and push the
|
|
47
|
+
generatable ones (`BETTER_AUTH_SECRET`, `LUNORA_ADMIN_TOKEN`, …). In CI a
|
|
48
|
+
missing required secret aborts the deploy. Skipped for `--dry-run`, for
|
|
49
|
+
`lunora preview` (it uploads its own secrets), and when the worker doesn't
|
|
50
|
+
exist yet.
|
|
51
|
+
8. **Services, then `wrangler deploy`** — services declared in
|
|
52
|
+
`lunora.config` deploy first (`--skip-services` to skip), then the app.
|
|
53
|
+
9. **After a successful deploy** — records the URL as the project link
|
|
54
|
+
(`lunora link`), optionally runs `--migrate` and `--health-check`, and only
|
|
55
|
+
then re-blesses the schema baseline.
|
|
56
|
+
|
|
57
|
+
`lunora prepare` runs steps 1–6 without deploying (useful in CI), but it takes
|
|
58
|
+
no `--env`, so it validates the top-level config only. `lunora verify` runs
|
|
59
|
+
validation, a codegen dry run and `tsc --noEmit` without writing files, and does
|
|
60
|
+
take `--env`.
|
|
61
|
+
|
|
62
|
+
Flags worth knowing:
|
|
63
|
+
|
|
64
|
+
| Flag | Effect |
|
|
65
|
+
| ---------------------- | ------------------------------------------------------------------------------- |
|
|
66
|
+
| `--env <name>` | Deploy a wrangler environment; checks read that env's (non-inherited) bindings. |
|
|
67
|
+
| `--dry-run` | Run every gate and bundle without publishing; `wrangler.jsonc` edits roll back. |
|
|
68
|
+
| `--health-check` | Probe `/_lunora/health/ready` on the new version; fail if it never answers. |
|
|
69
|
+
| `--prebuilt` | Skip codegen and the drift gate when `lunora prepare` already ran in this job. |
|
|
70
|
+
| `--migrate` | Run every declared data migration (`up` is idempotent) against the live worker. |
|
|
71
|
+
| `--allow-schema-drift` | Deploy despite blocked drift; checks nothing, the baseline is not advanced. |
|
|
72
|
+
|
|
73
|
+
`--migrate` is checked before wrangler runs, so a missing requirement aborts the
|
|
74
|
+
whole deploy:
|
|
75
|
+
|
|
76
|
+
- `--migrate-yes` — confirms running production data migrations.
|
|
77
|
+
- `--migrate-url <https://…>` — required unless this checkout is linked for the
|
|
78
|
+
same `--env` (a previous successful deploy links it automatically).
|
|
79
|
+
- An admin token — `--migrate-token` or `LUNORA_ADMIN_TOKEN`.
|
|
15
80
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- A deploy fails on a binding, a placeholder id, or the schema-drift gate.
|
|
20
|
-
- Provisioning D1 / R2 / secrets for a Lunora app.
|
|
21
|
-
|
|
22
|
-
## When Not to Use
|
|
23
|
-
|
|
24
|
-
- Local development — that is `lunora dev` (see `lunora-quickstart`).
|
|
25
|
-
- A schema/data change that needs migrating — do that first with
|
|
26
|
-
`lunora-migration-helper`, then deploy.
|
|
27
|
-
|
|
28
|
-
## What `lunora deploy` Does
|
|
29
|
-
|
|
30
|
-
`lunora deploy` runs a fixed pipeline:
|
|
31
|
-
|
|
32
|
-
1. **Codegen** — regenerates `lunora/_generated/` and typechecks.
|
|
33
|
-
2. **Validate `wrangler.jsonc`** — required `compatibility_date`, the
|
|
34
|
-
`nodejs_compat` flag, and the `SHARD` Durable Object binding.
|
|
35
|
-
3. **Schema-drift gate** — blocks if the committed baseline
|
|
36
|
-
(`lunora/.lunora-schema.json`) drifted with a breaking change and no
|
|
37
|
-
accompanying migration. The baseline is re-blessed only after the deploy
|
|
38
|
-
succeeds.
|
|
39
|
-
4. **`wrangler deploy`** — builds and pushes the worker (and any container
|
|
40
|
-
images).
|
|
81
|
+
```bash
|
|
82
|
+
lunora deploy --migrate --migrate-yes --migrate-url https://app.example.com
|
|
83
|
+
```
|
|
41
84
|
|
|
42
|
-
|
|
43
|
-
data migrations against the live worker after deploy, with `--migrate-token` /
|
|
44
|
-
`--migrate-url`), `--allow-schema-drift` (override the gate — use sparingly), and
|
|
45
|
-
`--update-schema-baseline` (re-bless the baseline with the current shape).
|
|
85
|
+
## Per-PR previews
|
|
46
86
|
|
|
47
|
-
|
|
87
|
+
`lunora deploy --preview` is refused: a Worker version shares production's
|
|
88
|
+
Durable Objects, D1 and R2, and gets no preview URL. Use `lunora preview`:
|
|
48
89
|
|
|
49
|
-
|
|
90
|
+
```bash
|
|
91
|
+
lunora preview deploy 123 --seed # own Worker + DO namespace + D1/KV/R2, migrated, seeded
|
|
92
|
+
lunora preview deploy 123 --dry-run # the plan and env block, no API call
|
|
93
|
+
lunora preview list
|
|
94
|
+
lunora preview delete 123 # Worker + every resource on its record
|
|
95
|
+
```
|
|
50
96
|
|
|
51
|
-
- `
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
|
|
97
|
+
- Records are keyed by `lunora.appId` in `package.json` (the first local
|
|
98
|
+
`lunora preview deploy` writes it; commit it, CI cannot mint one), so a Worker rename does not
|
|
99
|
+
lose a preview. Old Worker-name keys are re-keyed on the next deploy/delete.
|
|
100
|
+
- `--env <name>` plans from that Wrangler environment (top level plus `env.<name>`)
|
|
101
|
+
for an app whose bindings live only there; recorded, so `delete` needs no flag for the
|
|
102
|
+
resources. If that environment names a different `account_id`, pass the same `--env` to
|
|
103
|
+
`list`/`delete` (or set `CLOUDFLARE_ACCOUNT_ID`); they refuse rather than guess.
|
|
104
|
+
Without it, env-only bindings are refused. CI leaves it unset.
|
|
105
|
+
- Resources are named `<worker>-preview-<name>-<binding>` and recorded in the
|
|
106
|
+
account's `lunora-preview-registry` KV namespace; `delete` only removes what a
|
|
107
|
+
record lists, and refuses anything production's config names.
|
|
108
|
+
- Mintable secrets are minted per deploy, or derived from
|
|
109
|
+
`LUNORA_PREVIEW_SECRET_SEED` when set (stable across deploys); a provider key
|
|
110
|
+
reaches the preview only via `--secret KEY` (value from the environment).
|
|
111
|
+
- Production `vars` are copied; override one with `--var KEY=VALUE` (e.g. an
|
|
112
|
+
auth base URL pointing at the preview's workers.dev URL).
|
|
113
|
+
- Refused (with the list) when the app binds Hyperdrive, services, queues,
|
|
114
|
+
workflows, Vectorize or another binding a preview cannot isolate yet.
|
|
115
|
+
- Token needs Workers Scripts, D1, Workers KV Storage and Workers R2 Storage:
|
|
116
|
+
Edit. Cloudflare only; celld and Node refuse.
|
|
117
|
+
- `lunora init --ci github|gitlab` scaffolds the deploy-on-PR and
|
|
118
|
+
delete-on-close jobs.
|
|
119
|
+
|
|
120
|
+
## Preflight
|
|
56
121
|
|
|
57
122
|
```bash
|
|
58
|
-
lunora doctor
|
|
123
|
+
lunora doctor # read-only; exits 1 on any FAIL, WARN/INFO don't block
|
|
124
|
+
lunora doctor --format json # each finding carries a stable `code` for CI/agents
|
|
125
|
+
lunora verify --env production
|
|
59
126
|
```
|
|
60
127
|
|
|
61
|
-
`lunora
|
|
62
|
-
|
|
128
|
+
`lunora doctor` fails on a missing or invalid `wrangler.jsonc`, a missing
|
|
129
|
+
`SHARD` binding, a placeholder D1 id (`d1-placeholder-id`), and a binding whose
|
|
130
|
+
class the worker doesn't export (`wrangler-class-unexported`), and an Artifacts
|
|
131
|
+
namespace in the wrong jurisdiction. It warns on unfilled `.dev.vars` secrets,
|
|
132
|
+
placeholder `send_email` destinations, an account near its Durable Object class
|
|
133
|
+
cap, and a `cloudflare.config.ts` (`cf-config-present`).
|
|
63
134
|
|
|
64
|
-
## `wrangler.jsonc`
|
|
135
|
+
## `wrangler.jsonc`
|
|
65
136
|
|
|
66
|
-
|
|
67
|
-
|
|
137
|
+
Templates ship this shape. The `d1_databases` and `r2_buckets` entries are
|
|
138
|
+
only needed when the app uses `.global()` tables or auth (D1) and storage (R2):
|
|
68
139
|
|
|
69
140
|
```jsonc
|
|
70
141
|
{
|
|
71
142
|
"name": "my-app",
|
|
72
|
-
"main": "src/
|
|
73
|
-
"compatibility_date": "2026-
|
|
143
|
+
"main": "src/server.ts",
|
|
144
|
+
"compatibility_date": "2026-10-01",
|
|
74
145
|
"compatibility_flags": ["nodejs_compat"],
|
|
75
146
|
"durable_objects": {
|
|
76
147
|
"bindings": [
|
|
77
148
|
{ "name": "SHARD", "class_name": "ShardDO" },
|
|
78
|
-
{ "name": "
|
|
149
|
+
{ "name": "SHARD_REGISTRY", "class_name": "ShardRegistryDO" },
|
|
79
150
|
],
|
|
80
151
|
},
|
|
81
|
-
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["ShardDO", "
|
|
82
|
-
"
|
|
83
|
-
"
|
|
152
|
+
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["ShardDO", "ShardRegistryDO"] }],
|
|
153
|
+
"limits": { "cpu_ms": 30000 },
|
|
154
|
+
"d1_databases": [{ "binding": "DB", "database_name": "my-app", "database_id": "<replace-with-d1-create-id>" }],
|
|
155
|
+
"r2_buckets": [{ "binding": "UPLOADS", "bucket_name": "my-app-uploads" }],
|
|
84
156
|
}
|
|
85
157
|
```
|
|
86
158
|
|
|
87
|
-
|
|
88
|
-
bindings
|
|
89
|
-
|
|
159
|
+
Reconcile adds `SCHEDULER` → `SchedulerDO` when the app schedules work, and
|
|
160
|
+
bindings for generated containers, workflows and agents. Every `class_name`
|
|
161
|
+
must be exported by the worker entry or wrangler rejects the deploy.
|
|
162
|
+
|
|
163
|
+
Lunora writes the bindings but cannot create the remote resources:
|
|
90
164
|
|
|
91
165
|
```bash
|
|
92
|
-
wrangler d1 create my-app
|
|
93
|
-
wrangler r2 bucket create my-app-
|
|
166
|
+
wrangler d1 create my-app # paste the returned database_id into wrangler.jsonc
|
|
167
|
+
wrangler r2 bucket create my-app-uploads
|
|
94
168
|
```
|
|
95
169
|
|
|
96
|
-
|
|
97
|
-
`
|
|
98
|
-
|
|
99
|
-
container export proactively.
|
|
170
|
+
When using `--env`, remember that `vars`, `d1_databases`, `durable_objects` and
|
|
171
|
+
`containers` do not inherit in wrangler. Each environment needs its own entries,
|
|
172
|
+
including its own D1 database.
|
|
100
173
|
|
|
101
|
-
## Secrets
|
|
174
|
+
## Secrets
|
|
102
175
|
|
|
103
|
-
`.dev.vars` is
|
|
104
|
-
|
|
105
|
-
into Cloudflare:
|
|
176
|
+
`.dev.vars` is for development only: it is git-ignored and `wrangler deploy`
|
|
177
|
+
never uploads it. Production secrets live in Cloudflare:
|
|
106
178
|
|
|
107
179
|
```bash
|
|
108
|
-
|
|
109
|
-
|
|
180
|
+
lunora env diff --env production # keys local-only vs set remotely
|
|
181
|
+
lunora env push --env production --yes # uploads .dev.vars values; refuses placeholders
|
|
182
|
+
wrangler secret put RESEND_API_KEY --env production # set a prod-only value by hand
|
|
110
183
|
```
|
|
111
184
|
|
|
112
|
-
|
|
113
|
-
|
|
185
|
+
`lunora env push` uploads the values from `.dev.vars`. If production needs
|
|
186
|
+
different values than dev (it usually does for provider keys), set those with
|
|
187
|
+
`wrangler secret put` instead.
|
|
188
|
+
|
|
189
|
+
## Schema-drift gate
|
|
190
|
+
|
|
191
|
+
The gate blocks when the schema changed in a breaking way since
|
|
192
|
+
`lunora/.lunora-schema.json` and no new `defineMigration` on the affected table
|
|
193
|
+
covers it. The block message lists each change and a paste-ready
|
|
194
|
+
`lunora migrate create … --table …` command. Commit the baseline file so CI
|
|
195
|
+
and every machine gate against the same shape. It is advanced only after a
|
|
196
|
+
successful deploy, so a failed deploy never moves it past a change that didn't
|
|
197
|
+
ship.
|
|
198
|
+
|
|
199
|
+
When the stored rows already fit a tightening, `lunora deploy` notices on its own:
|
|
200
|
+
it reads the affected tables from the deployed worker (`--migrate-url` or the
|
|
201
|
+
project link, plus `LUNORA_ADMIN_TOKEN`) and lets the change through, naming any
|
|
202
|
+
row that does not fit otherwise. A new unique index is checked the same way, for repeated values.
|
|
203
|
+
`--allow-schema-drift` skips the gate for one run without checking. Otherwise
|
|
204
|
+
stage the change with `lunora-migration-helper`.
|
|
205
|
+
|
|
206
|
+
## `.global()` table DDL
|
|
114
207
|
|
|
115
|
-
|
|
208
|
+
The runtime provisions `.global()` tables itself on first use
|
|
209
|
+
(`CREATE TABLE IF NOT EXISTS` plus additive `ADD COLUMN` / indexes), so additive
|
|
210
|
+
changes need no step. `lunora migrate generate` writes a reviewable SQL file for
|
|
211
|
+
D1-backed global tables, but no command applies it, `lunora deploy` included.
|
|
212
|
+
Destructive or hand-written statements in it (drops, a backfilling `UPDATE`, a
|
|
213
|
+
rename) must be applied by hand:
|
|
116
214
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
215
|
+
```bash
|
|
216
|
+
wrangler d1 execute DB --remote --file=lunora/migrations/<file>.sql
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
See `lunora-migration-helper` for the full flow.
|
|
121
220
|
|
|
122
|
-
|
|
123
|
-
migrate generate` before deploying; `@lunora/d1`'s runner applies them. For data
|
|
124
|
-
backfills, deploy first, then `lunora deploy --migrate` (or `lunora migrate up
|
|
125
|
-
--prod`). See `lunora-migration-helper`.
|
|
221
|
+
## Rollback
|
|
126
222
|
|
|
127
|
-
|
|
223
|
+
```bash
|
|
224
|
+
lunora cloudflare deployments list
|
|
225
|
+
lunora cloudflare deployments status # which versions carry traffic, and how much
|
|
226
|
+
lunora cloudflare deployments rollback --yes # previous version
|
|
227
|
+
lunora cloudflare deployments promote <version-id> --yes # send 100% of traffic to a version
|
|
228
|
+
```
|
|
128
229
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
230
|
+
A partial rollout (`--percent N --from <live-version-id> --confirm-shared-state`) runs two versions against one Durable Object database. Nothing in `promote` compares the two versions' schemas, so confirm them yourself before using it. Two facts bound the risk: `lunora deploy --preview` is refused, so a version that never carried traffic was uploaded outside Lunora with `wrangler versions upload`, which never ran the schema-drift gate, while a superseded version that `lunora deploy` once shipped passed it against the schema of its own time, unless that deploy used `--prebuilt` or `--allow-schema-drift`, which skip or override the gate; and `wrangler versions upload` refuses a version with a pending Durable Object migration, so that migration reaches traffic only through `deploy`, at 100%. A split whose live version predates a migration the target relies on is not detected by either check.
|
|
231
|
+
|
|
232
|
+
Rolling back code does not roll back data migrations or D1 DDL.
|
|
233
|
+
|
|
234
|
+
## Common pitfalls
|
|
235
|
+
|
|
236
|
+
1. **Placeholder `database_id`.** Reconcile writes
|
|
237
|
+
`<replace-with-d1-create-id>`; deploy refuses it. Run `wrangler d1 create`
|
|
238
|
+
and paste the id.
|
|
239
|
+
2. **DO class not exported.** Export `ShardDO` (and any generated container /
|
|
240
|
+
workflow class) from the worker entry; `lunora doctor` names the gap.
|
|
241
|
+
3. **Secrets only in `.dev.vars`.** They never reach production. Push or
|
|
242
|
+
`wrangler secret put` them before the first request.
|
|
243
|
+
4. **Dev and prod sharing resources.** Give each environment its own D1
|
|
244
|
+
database, R2 buckets and secrets; never point a dev worker at prod data.
|
|
245
|
+
5. **Uncommitted schema baseline.** Commit `lunora/.lunora-schema.json` (and
|
|
246
|
+
`lunora/migrations/.snapshot.json` if you use `migrate generate`).
|
|
247
|
+
`lunora/_generated/` is regenerated by deploy; templates git-ignore it.
|
|
248
|
+
6. **Using `cf dev` / `cf build` / `cf deploy`.** They read
|
|
249
|
+
`cloudflare.config.ts`, which Lunora never updates
|
|
250
|
+
([#964](https://github.com/anolilab/lunora/issues/964)). Use `lunora dev` /
|
|
251
|
+
`lunora deploy`; `cf` resource commands (zones, DNS, KV) are fine.
|
|
140
252
|
|
|
141
253
|
## Checklist
|
|
142
254
|
|
|
143
|
-
- [ ] `lunora doctor`
|
|
144
|
-
- [ ]
|
|
145
|
-
|
|
146
|
-
- [ ]
|
|
147
|
-
- [ ]
|
|
148
|
-
- [ ]
|
|
149
|
-
- [ ] Schema changes migrated; the drift gate is green (no `--allow-schema-drift`).
|
|
150
|
-
- [ ] `lunora deploy` succeeded; `--migrate` run if data backfills were pending.
|
|
255
|
+
- [ ] `lunora doctor` has no FAIL; `lunora verify --env <name>` passes in CI.
|
|
256
|
+
- [ ] D1 / R2 resources created per environment; real ids in `wrangler.jsonc`.
|
|
257
|
+
- [ ] Every DO / container / workflow `class_name` is exported by the worker entry.
|
|
258
|
+
- [ ] Production secrets set (`lunora env diff --env <name>` shows nothing local-only that prod needs).
|
|
259
|
+
- [ ] Breaking schema changes staged with a migration; drift gate green.
|
|
260
|
+
- [ ] `lunora deploy --env <name> --health-check` succeeded; `--migrate --migrate-yes` run if backfills were pending.
|