@decocms/start 3.0.0 → 4.0.0
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/.agents/skills/deco-to-tanstack-migration/SKILL.md +1 -1
- package/.agents/skills/deco-to-tanstack-migration/references/worker-cloudflare.md +32 -135
- package/.agents/skills/deco-to-tanstack-migration/templates/package-json.md +2 -5
- package/.cursor/rules/migration-tooling-policy.mdc +32 -48
- package/CODEOWNERS +4 -12
- package/MIGRATION_TOOLING_PLAN.md +9 -13
- package/package.json +2 -3
- package/scripts/migrate/phase-scaffold.ts +9 -12
- package/scripts/migrate/phase-verify.ts +3 -5
- package/scripts/migrate/templates/package-json.ts +6 -9
- package/.github/workflows/deploy.yml +0 -141
- package/.github/workflows/preview.yml +0 -200
- package/.github/workflows/sync-secrets.yml +0 -171
- package/deploy/README.md +0 -121
- package/deploy/wrangler-template.jsonc +0 -46
- package/scripts/deploy/build-wrangler-config.mjs +0 -47
- package/scripts/deploy/jsonc.mjs +0 -76
- package/scripts/deploy/site-registry.mjs +0 -95
- package/scripts/deploy/wrangler-wrapper.mjs +0 -118
- package/scripts/migrate/templates/github-workflows.ts +0 -159
|
@@ -315,7 +315,7 @@ See: `references/search.md`
|
|
|
315
315
|
5. **`tsconfig.json` mirrors `vite.config.ts`** -- only `"~/*": ["./src/*"]` in paths
|
|
316
316
|
6. **Signals don't auto-subscribe in React** -- reading `signal.value` in render creates NO subscription; use `useStore(signal.store)` from `@tanstack/react-store`
|
|
317
317
|
7. **Commerce loaders need request context** -- `resolve.ts` must pass URL/path to PLP/PDP loaders
|
|
318
|
-
8. **`wrangler.jsonc` main must be a custom worker-entry** -- TanStack Start ignores `export default` in `server.ts`. The `main` field lives in the
|
|
318
|
+
8. **`wrangler.jsonc` main must be a custom worker-entry** -- TanStack Start ignores `export default` in `server.ts`. The `main` field lives in the site's per-site `wrangler.jsonc`.
|
|
319
319
|
9. **Copy components faithfully, never rewrite** -- `cp` the original, then only change mechanical things (class→className, imports). NEVER regenerate or "improve" — AI-rewritten components are the #1 source of visual regressions
|
|
320
320
|
10. **Tailwind v4 logical property hazard** -- mixed `px-*` + `pl-*/pr-*` on the same element breaks the cascade
|
|
321
321
|
11. **oklch CSS variables need triplets, not hex** -- `oklch(var(--x))` must store variables as oklch triplets
|
|
@@ -37,7 +37,7 @@ TanStack Start's Cloudflare adapter **completely ignores** the `export default`
|
|
|
37
37
|
|
|
38
38
|
**Diagnosis**: Search the built `dist/server/worker-entry-*.js` bundle for your custom code (e.g., `X-Cache`, `caches.open`, `_cache/purge`). If absent, TanStack stripped it.
|
|
39
39
|
|
|
40
|
-
**Fix**: Create a **separate** `src/worker-entry.ts` file that wraps TanStack Start's built handler. Wrangler is told to use this file via `main: "./src/worker-entry.ts"` in the
|
|
40
|
+
**Fix**: Create a **separate** `src/worker-entry.ts` file that wraps TanStack Start's built handler. Wrangler is told to use this file via `main: "./src/worker-entry.ts"` in the site's `wrangler.jsonc`.
|
|
41
41
|
|
|
42
42
|
```typescript
|
|
43
43
|
// src/worker-entry.ts
|
|
@@ -59,7 +59,7 @@ export default createDecoWorkerEntry(serverEntry, {
|
|
|
59
59
|
|
|
60
60
|
The `main` field is set centrally so a future migration of the entry path
|
|
61
61
|
applies to every site at once (single PR to the template). There is no
|
|
62
|
-
per-site override file
|
|
62
|
+
per-site override file; if a single site truly needs a different
|
|
63
63
|
entry path, change the template (and accept that all sites get it) or add a
|
|
64
64
|
substitution token like `$WORKER_ENTRY_PATH` and feed it from a per-site env.
|
|
65
65
|
|
|
@@ -141,7 +141,7 @@ After deploying a new build to Cloudflare Workers, the edge cache may still serv
|
|
|
141
141
|
`npx wrangler secret put` manually per-site — the central workflow keeps
|
|
142
142
|
GitHub and Cloudflare in sync.
|
|
143
143
|
2. Call the purge endpoint: `POST /_cache/purge` with `Authorization: Bearer <token>` and body `{"paths":["/"]}`
|
|
144
|
-
3.
|
|
144
|
+
3. Currently this lives in each storefront's per-site `deploy.yml` (D6 centralization was reverted; D6.3 Workers Builds replacement is in flight).
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
## 44. Runtime Module Import Kills Lazy-Loaded Sections
|
|
@@ -212,137 +212,34 @@ Or in project `.npmrc` with an env var (for CI):
|
|
|
212
212
|
**Tradeoff with `github:` syntax**: No semver resolution — `npm update` is meaningless. Pin to a tag for stability: `github:decocms/deco-start#v0.14.2`. Without a tag, you get HEAD of the default branch.
|
|
213
213
|
|
|
214
214
|
|
|
215
|
-
## 46.
|
|
216
|
-
|
|
217
|
-
**Severity**: HIGH — site repos must NOT commit `wrangler.jsonc`, must NOT hold
|
|
218
|
-
Cloudflare credentials, and must NOT have per-site deploy logic. Doing so
|
|
219
|
-
reintroduces drift and breaks the trust model.
|
|
220
|
-
|
|
221
|
-
Per [D6.2](../../../../.cursor/rules/migration-tooling-policy.mdc), all
|
|
222
|
-
storefronts deploy via reusable workflows shipped from
|
|
223
|
-
`decocms/deco-start/.github/workflows/{deploy,preview,sync-secrets,regen-blocks}.yml@v3`.
|
|
224
|
-
There is no per-site registry: worker name == storefront repo basename by
|
|
225
|
-
convention. The canonical `wrangler.jsonc` lives at
|
|
226
|
-
`decocms/deco-start/deploy/wrangler-template.jsonc`; the build script
|
|
227
|
-
substitutes `$WORKER_NAME` / `$WORKER_UNDERSCORE` tokens at deploy time and
|
|
228
|
-
writes a generated `wrangler.jsonc` in the runner. Site repos gitignore the
|
|
229
|
-
file.
|
|
230
|
-
|
|
231
|
-
### What goes in the site repo
|
|
232
|
-
|
|
233
|
-
Four caller workflow stubs that mint a `decocms-deployer` GitHub App
|
|
234
|
-
installation token and call `gh workflow run` on `decocms/deco-start@v3`:
|
|
235
|
-
|
|
236
|
-
```yaml
|
|
237
|
-
# .github/workflows/deploy.yml
|
|
238
|
-
name: Deploy
|
|
239
|
-
on:
|
|
240
|
-
push:
|
|
241
|
-
branches: [main]
|
|
242
|
-
permissions:
|
|
243
|
-
contents: read
|
|
244
|
-
jobs:
|
|
245
|
-
trigger:
|
|
246
|
-
runs-on: ubuntu-latest
|
|
247
|
-
steps:
|
|
248
|
-
- uses: actions/create-github-app-token@v1
|
|
249
|
-
id: app-token
|
|
250
|
-
with:
|
|
251
|
-
app-id: ${{ secrets.DECOCMS_DEPLOYER_APP_ID }}
|
|
252
|
-
private-key: ${{ secrets.DECOCMS_DEPLOYER_APP_PRIVATE_KEY }}
|
|
253
|
-
owner: decocms
|
|
254
|
-
repositories: deco-start
|
|
255
|
-
- env:
|
|
256
|
-
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
|
257
|
-
run: |
|
|
258
|
-
gh workflow run deploy.yml \
|
|
259
|
-
--repo decocms/deco-start \
|
|
260
|
-
--ref v3 \
|
|
261
|
-
-f site_owner=${GITHUB_REPOSITORY%%/*} \
|
|
262
|
-
-f site_name=${GITHUB_REPOSITORY##*/}
|
|
263
|
-
```
|
|
215
|
+
## 46. Deploy / Wrangler Config (interim, D6.3 in flight)
|
|
264
216
|
|
|
265
|
-
(
|
|
266
|
-
|
|
267
|
-
The
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
```jsonc
|
|
292
|
-
"scripts": {
|
|
293
|
-
"gen:wrangler": "deco-wrangler gen",
|
|
294
|
-
"predev": "deco-wrangler gen",
|
|
295
|
-
"prebuild": "deco-wrangler gen",
|
|
296
|
-
"types": "deco-wrangler types",
|
|
297
|
-
"deploy": "echo 'Production deploys are managed by .github/workflows/deploy.yml on push to main. For an emergency manual deploy run: npx deco-wrangler deploy'; exit 1"
|
|
298
|
-
}
|
|
299
|
-
```
|
|
217
|
+
**Status (2026-05-07)**: D6.2's centralized App-mediated dispatch was
|
|
218
|
+
**reverted** in favour of Cloudflare Workers Builds owning the deploy
|
|
219
|
+
pipeline per-worker. The Workers Builds onboarding plan is being
|
|
220
|
+
designed in a follow-up PR. Until it lands, this section describes the
|
|
221
|
+
**interim state**: each storefront retains its own per-site inline
|
|
222
|
+
`deploy.yml` workflow (the original pre-D6 setup), with its own
|
|
223
|
+
`CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` repo secrets.
|
|
224
|
+
|
|
225
|
+
Site repos **do** commit a per-site `wrangler.jsonc` during the interim
|
|
226
|
+
period. The `deco-wrangler` CLI no longer ships from `@decocms/start`.
|
|
227
|
+
|
|
228
|
+
### What changes when Workers Builds onboarding ships
|
|
229
|
+
|
|
230
|
+
When the D6.3 replacement lands, expect:
|
|
231
|
+
|
|
232
|
+
- Per-storefront CF Builds connection (one dashboard click per worker).
|
|
233
|
+
- Per-site `.github/workflows/deploy.yml` removed; CF Builds takes over
|
|
234
|
+
on push.
|
|
235
|
+
- `wrangler.jsonc` continues to live in the site repo, but a `deco-build`
|
|
236
|
+
CLI in `@decocms/start` regenerates the bindings (KV, R2, etc.) from a
|
|
237
|
+
central template at build time so customers can't add bindings to
|
|
238
|
+
other tenants' resources.
|
|
239
|
+
- `name` field in `wrangler.jsonc` is enforced by CF (verified against
|
|
240
|
+
`baggagio-tanstack` 2026-05-07 — a malicious `name` value is ignored
|
|
241
|
+
and CF auto-opens a PR to fix it).
|
|
300
242
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
`wrangler` with that config in cwd.
|
|
305
|
-
|
|
306
|
-
### Trust model
|
|
307
|
-
|
|
308
|
-
- **Authorization gate**: the deploy can only start if the
|
|
309
|
-
`decocms-deployer` App is installed on the target storefront repo. The
|
|
310
|
-
central workflow's App-token mint step fails with a clear error otherwise.
|
|
311
|
-
- **Worker naming is convention-based and not customer-controlled.** A
|
|
312
|
-
customer with push access to their own storefront cannot rename the worker
|
|
313
|
-
their deploy lands on (the central workflow uses `inputs.site_name` as the
|
|
314
|
-
worker name; modifying their stub to pass a different `site_name` would
|
|
315
|
-
also require the App to be installed on that other repo).
|
|
316
|
-
- **Cloudflare credentials never leave `decocms/deco-start`.** The central
|
|
317
|
-
workflow runs in deco-start's context, so the env-var resolves natively
|
|
318
|
-
from repo secrets.
|
|
319
|
-
- **Force-rollback is impossible for production.** The central deploy
|
|
320
|
-
workflow ignores any caller-supplied sha and always resolves the
|
|
321
|
-
storefront's current default-branch HEAD itself.
|
|
322
|
-
- **Per-site runtime secrets** (`SECRET_*`) live in deco-start environments,
|
|
323
|
-
not storefront repos. The storefront caller stub for `sync-secrets.yml`
|
|
324
|
-
triggers a workflow that binds to the matching env and runs
|
|
325
|
-
`wrangler secret put`. The storefront repo holds zero secrets beyond the
|
|
326
|
-
`decocms-deployer` App credentials.
|
|
327
|
-
|
|
328
|
-
### Common mistakes (do not do these)
|
|
329
|
-
|
|
330
|
-
- **Committing `wrangler.jsonc` to a site repo.** Generated only;
|
|
331
|
-
always gitignored. If you see it tracked, the site missed migration.
|
|
332
|
-
- **Adding a site-local `deploy.yml` step** (e.g. cache purge after deploy).
|
|
333
|
-
Add it to `deco-start/.github/workflows/deploy.yml` instead so every site
|
|
334
|
-
picks it up at once.
|
|
335
|
-
- **Adding `CLOUDFLARE_*` to a storefront repo's secrets.** They never
|
|
336
|
-
belong there. The central workflow runs in deco-start's context.
|
|
337
|
-
- **Adding `SECRET_*` to a storefront repo's secrets.** They live in the
|
|
338
|
-
matching `<site_name>-secrets` environment in deco-start.
|
|
339
|
-
- **Hard-coding `account_id` in a site's wrangler config.** It comes from
|
|
340
|
-
`CLOUDFLARE_ACCOUNT_ID` (in CI; `wrangler login` locally) — keeping
|
|
341
|
-
it out of JSON is the one-way protection against accidentally deploying
|
|
342
|
-
to the wrong account.
|
|
343
|
-
- **Trying to override the worker name** for one site. There is no
|
|
344
|
-
per-site override mechanism in D6.2. If the worker MUST be named
|
|
345
|
-
differently from the repo, the right answer is either to rename the
|
|
346
|
-
repo to match (cleanest) or to do a CF-side migration (deploy a new
|
|
347
|
-
worker with the repo-name and re-attach routes). This trade-off was
|
|
348
|
-
taken intentionally in exchange for the registry-free architecture.
|
|
243
|
+
Until then, do NOT scaffold caller stubs that reference
|
|
244
|
+
`decocms/deco-start/.github/workflows/*.yml@vN` — those workflows are
|
|
245
|
+
gone.
|
|
@@ -12,11 +12,8 @@
|
|
|
12
12
|
"generate:blocks": "tsx node_modules/@decocms/start/scripts/generate-blocks.ts",
|
|
13
13
|
"generate:invoke": "tsx node_modules/@decocms/start/scripts/generate-invoke.ts",
|
|
14
14
|
"generate:schema": "tsx node_modules/@decocms/start/scripts/generate-schema.ts --site storefront",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"prebuild": "deco-wrangler gen",
|
|
18
|
-
"types": "deco-wrangler types",
|
|
19
|
-
"deploy": "echo 'Production deploys are managed by .github/workflows/deploy.yml on push to main. See D6.'; exit 1"
|
|
15
|
+
"deploy": "wrangler deploy",
|
|
16
|
+
"types": "wrangler types"
|
|
20
17
|
},
|
|
21
18
|
"dependencies": {
|
|
22
19
|
"@decocms/apps": "^0.20.1",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Constitutional decisions for the deco-start migration-tooling effort (D1–D6, priorities, process). Always loaded.
|
|
2
|
+
description: Constitutional decisions for the deco-start migration-tooling effort (D1–D5 + D6.3 revert, priorities, process). Always loaded.
|
|
3
3
|
alwaysApply: true
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -14,7 +14,7 @@ summary; always defer to the plan when they conflict.
|
|
|
14
14
|
1. **Design for 100 sites, not 3.** When the surface of an abstraction is
|
|
15
15
|
well-understood, ship it. Don't defer waiting for "more signal" — design
|
|
16
16
|
for the projection. When the surface is *not* understood, *decide*
|
|
17
|
-
explicitly (write a D-record like D1–
|
|
17
|
+
explicitly (write a D-record like D1–D5), don't ship fast.
|
|
18
18
|
2. **Strict over flexible.** No support layers, no soft drift, no
|
|
19
19
|
fork-runtime adapters. Every fork divergence becomes either a PR back to
|
|
20
20
|
canonical or visible local debt.
|
|
@@ -76,51 +76,36 @@ Failure modes get documented in skills, not encoded as escape hatches.
|
|
|
76
76
|
**Agent behavior**: when a migration goes sideways, propose deletion +
|
|
77
77
|
re-run, not in-place repair. Add the failure mode to the skill.
|
|
78
78
|
|
|
79
|
-
### D6.
|
|
80
|
-
|
|
81
|
-
`decocms/deco-start/.github/workflows/{deploy,preview,sync-secrets
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
`
|
|
106
|
-
per-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
protection rules. **The storefront repo holds zero secrets** beyond the
|
|
110
|
-
App credentials (which only grant the ability to trigger workflows on
|
|
111
|
-
`decocms/deco-start`).
|
|
112
|
-
|
|
113
|
-
`deploy/`, `scripts/deploy/`, and the central workflow files are
|
|
114
|
-
CODEOWNERS-protected.
|
|
115
|
-
|
|
116
|
-
**Agent behavior**: when adding or migrating a site, do **not** generate a
|
|
117
|
-
per-site `wrangler.jsonc`, do **not** generate a `deploy/sites/<repo>.jsonc`
|
|
118
|
-
file (that whole directory was removed in D6.2), and do **not** add
|
|
119
|
-
`CLOUDFLARE_*` or `SECRET_*` to a storefront repo's secrets. The site repo
|
|
120
|
-
gets four ~15-line caller stubs that mint a `decocms-deployer` App token and
|
|
121
|
-
fire `workflow_dispatch` at `decocms/deco-start@v3`; the App ID + private key
|
|
122
|
-
live as `deco-sites` org-level secrets `DECOCMS_DEPLOYER_APP_ID` and
|
|
123
|
-
`DECOCMS_DEPLOYER_APP_PRIVATE_KEY`.
|
|
79
|
+
### D6.3 — Revert D6/D6.1/D6.2; Cloudflare Workers Builds owns deploy (signed off 2026-05-07)
|
|
80
|
+
The whole D6 family — centralized GitHub Actions reusable workflows under
|
|
81
|
+
`decocms/deco-start/.github/workflows/{deploy,preview,sync-secrets}.yml`,
|
|
82
|
+
the `decocms-deployer` GitHub App, the per-storefront `<site_name>-secrets`
|
|
83
|
+
GitHub Environments, the central `deploy/wrangler-template.jsonc`, the
|
|
84
|
+
`deco-wrangler` CLI, the `deploy/sites/<repo>.jsonc` registry, and the
|
|
85
|
+
per-site caller stubs — has been **reverted**.
|
|
86
|
+
|
|
87
|
+
Why: GitHub Free orgs do not propagate org-level secrets to private repos,
|
|
88
|
+
which forced the App private key to be distributed to every storefront repo
|
|
89
|
+
individually. That key gives the holder the ability to mint installation
|
|
90
|
+
tokens for any installed repo, concentrating blast radius on a credential
|
|
91
|
+
that had to be rotated across N storefronts. The trust model couldn't pay
|
|
92
|
+
for itself at our scale.
|
|
93
|
+
|
|
94
|
+
**Replacement direction (to be elaborated in a follow-up D-record once
|
|
95
|
+
shipped):** Cloudflare Workers Builds owns deploy/preview pipelines per-worker.
|
|
96
|
+
The dashboard repo<->worker connection is the source of truth — verified
|
|
97
|
+
empirically against `baggagio-tanstack` 2026-05-07 that a malicious
|
|
98
|
+
`wrangler.jsonc` `name` field is ignored, the deploy lands on the connected
|
|
99
|
+
worker, and CF auto-opens a PR to fix the config. Per-storefront wiring is
|
|
100
|
+
one CF dashboard click per worker.
|
|
101
|
+
|
|
102
|
+
**Agent behavior — current interim period**: while D6.3's replacement is
|
|
103
|
+
being designed, do **not** scaffold `decocms/deco-start@vN`-calling caller
|
|
104
|
+
stubs in storefronts and do **not** depend on a `deco-wrangler` CLI from
|
|
105
|
+
`@decocms/start` (it no longer exists). Storefronts retain their existing
|
|
106
|
+
per-site inline `deploy.yml` (with their own `CLOUDFLARE_*` secrets) until
|
|
107
|
+
Workers Builds onboarding lands. Site repos do still commit `wrangler.jsonc`
|
|
108
|
+
during this interim — `deco-wrangler gen` is gone.
|
|
124
109
|
|
|
125
110
|
## Priority order
|
|
126
111
|
|
|
@@ -155,4 +140,3 @@ order — but only if explicitly identified as urgent.
|
|
|
155
140
|
- When reading a section of the plan or a skill, prefer the plan or skill
|
|
156
141
|
over your memory of past conversations.
|
|
157
142
|
- Do not run `deco-deploy` or any deploy command from agent flows.
|
|
158
|
-
- Do not commit `wrangler.jsonc` to a site repo. See **D6** above.
|
package/CODEOWNERS
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
# CODEOWNERS for decocms/deco-start
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
# The central reusable workflows under `.github/workflows/` are in the same
|
|
8
|
-
# trust boundary: they decide how every site is built and deployed.
|
|
9
|
-
deploy/ @vibe-dex
|
|
10
|
-
.github/workflows/deploy.yml @vibe-dex
|
|
11
|
-
.github/workflows/preview.yml @vibe-dex
|
|
12
|
-
.github/workflows/sync-secrets.yml @vibe-dex
|
|
13
|
-
.github/workflows/regen-blocks.yml @vibe-dex
|
|
14
|
-
scripts/deploy/ @vibe-dex
|
|
3
|
+
# Workflows under `.github/workflows/` decide how this package is built,
|
|
4
|
+
# released, and what blocks regeneration sites can trigger. Only the
|
|
5
|
+
# platform team approves changes.
|
|
6
|
+
.github/workflows/ @vibe-dex
|
|
@@ -120,6 +120,7 @@ this plan.
|
|
|
120
120
|
| 2026-05-07 | **D6 — Deploy / preview / secrets pipelines: centralize in `deco-start`** | At 6 sites the "1-minute copy" of `deploy.yml` / `preview.yml` / `wrangler.jsonc` had already produced unintended drift (lebiscuit missing 2 workflows, miess missing `account_id`, casaevideo's `loadtest:tail` worker name out of sync with its wrangler config). All sites now consume reusable workflows from `decocms/deco-start@v2` and a per-site registry under [`deploy/sites/<repo>.jsonc`](./deploy/) deep-merged on top of [`deploy/wrangler-template.jsonc`](./deploy/wrangler-template.jsonc) at deploy time. Customer repos hold only ~5-line caller workflows; `wrangler.jsonc` is generated and gitignored. The repo→worker binding is the trust boundary that prevents one site's commits from misrouting onto another site's worker (the central workflow ignores caller `inputs:` for identity and derives the site name from `${{ github.repository }}`). See [`deploy/README.md`](./deploy/README.md) for the contract. |
|
|
121
121
|
| 2026-05-07 | **D6.1 — Cloudflare credentials never leave `deco-start`** | Same-day refinement of D6 after the first central deploy on `baggagio-tanstack` failed with `Secret CLOUDFLARE_API_TOKEN is required, but not provided while calling`. The original D6 design used `secrets: inherit` from the storefront stub and required `CLOUDFLARE_*` to live in the `deco-sites` org, which broke the principle that *the only secrets a storefront repo holds are the secrets that go into wrangler secrets, not the ones used to deploy*. First-pass refinement: the central `deploy.yml` / `preview.yml` / `sync-secrets.yml` jobs declared `environment: production` to try to make `${{ secrets.CLOUDFLARE_* }}` resolve from `decocms/deco-start`'s `production` Environment. **Found broken empirically on 2026-05-07** — the deployment registers in the *caller* repo, not the called workflow's repo, so the environment lookup uses the caller's `production` env (auto-created with no secrets). Superseded by D6.2 the same evening. |
|
|
122
122
|
| 2026-05-07 | **D6.2 — App-mediated dispatch + no per-site registry (supersedes D6 + D6.1)** | After D6.1's `environment:` mechanism was empirically shown not to work cross-repo, the architecture pivoted: a `decocms-deployer` GitHub App is installed on `decocms/deco-start` (`actions:write`) and on each storefront repo (`contents:read`, optionally `pull-requests:write`). The storefront caller stub mints a short-lived App-installation token and calls `gh workflow run deploy.yml --repo decocms/deco-start --ref v3 -f site_owner=… -f site_name=…`. The central workflow runs in `decocms/deco-start`'s context, so `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_ACCOUNT_ID` are ordinary repo secrets. For runtime `SECRET_*` values, each storefront has a `<site_name>-secrets` GitHub Environment in `decocms/deco-start` (S1 design); `sync-secrets.yml` binds to that environment and pushes to `wrangler secret put`. The per-site registry under `deploy/sites/<repo>.jsonc` was dropped entirely (Pure C): worker name = repo basename by convention; the App being installed on the storefront repo is the deploy authorization gate; rare per-worker derived fields (like AE dataset name) use `$WORKER_*` substitution tokens in the template. Force-rollback is impossible for production deploys because the central workflow ignores caller-supplied `site_sha` and resolves the storefront's current default-branch HEAD itself. See [`deploy/README.md`](./deploy/README.md) for the full trust model. **Operational migrations required by Pure C:** `miess-01-tanstack` repo's worker shifts from `miess-tanstack` to `miess-01-tanstack` (CF-side cutover); `lebiscuit-tanstack` AE dataset shifts from `deco_metrics_lebiscuit` to `deco_metrics_lebiscuit_tanstack` (orphans old data). |
|
|
123
|
+
| 2026-05-07 | **D6.3 — Revert D6/D6.1/D6.2; deploys move to Cloudflare Workers Builds** | The whole D6 family (centralized GitHub Actions reusable workflows + `decocms-deployer` GitHub App + per-storefront GitHub Environments + central `deploy/wrangler-template.jsonc` + `deco-wrangler` CLI + per-site caller stubs) is being **reverted**. Trigger: GitHub Free orgs do not propagate org-level secrets to private repos, which forced the App private key to live as a per-storefront repo secret in every storefront — that key gives the holder the ability to mint installation tokens that can trigger workflows on `decocms/deco-start`, which in turn have the only Cloudflare credentials in the system. Per-repo distribution + rotation of that key across N customer storefronts didn't scale and concentrated blast radius on one credential. **Replacement (chosen, to be detailed in a follow-up D-record once shipped):** [Cloudflare Workers Builds](https://developers.cloudflare.com/workers/ci-cd/builds/) owns the deploy/preview pipelines per-worker. Verified empirically on `baggagio-tanstack` 2026-05-07: a malicious `wrangler.jsonc` `name` field pointing at a different worker (`americanas-tanstack`) is **ignored** by CF Builds — the deploy lands on the connected worker (`baggagio-tanstack`), CF surfaces a warning banner in the dashboard, and CF auto-opens a PR to fix the config (deco-sites/baggagio-tanstack#34). The dashboard repo<->worker connection is the source of truth; the in-repo config is treated as a secondary input. Per-storefront wiring (one CF dashboard click per worker) is acceptable at our scale; revisit when CF's [git-integration enable API](https://github.com/cloudflare/workers-sdk/issues/12058) lands. The `deco-build` CLI (regenerates `wrangler.jsonc` bindings from a central template) and runtime-secrets management remain to be designed in a separate PR. |
|
|
123
124
|
|
|
124
125
|
The full text of the constitutional rule (loaded into every agent
|
|
125
126
|
session for this repo) lives at
|
|
@@ -1678,19 +1679,14 @@ props. One broken section never takes the page down.
|
|
|
1678
1679
|
`regen-blocks.yml` and its `wrangler.jsonc` lacked `account_id`,
|
|
1679
1680
|
lebiscuit's preview workflow swallowed `wrangler` exit codes, and
|
|
1680
1681
|
casaevideo's `loadtest:tail` referenced a worker name that didn't
|
|
1681
|
-
match its `wrangler.jsonc`. **
|
|
1682
|
-
D6.
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
No `deploy/sites/<repo>.jsonc` PR is needed — worker name is the
|
|
1690
|
-
repo basename by convention. No `wrangler.jsonc` is committed to the
|
|
1691
|
-
site repo — `deco-wrangler gen` (a `bin` shipped from `@decocms/start`)
|
|
1692
|
-
materializes it from the central template on demand for local dev
|
|
1693
|
-
and CI alike.
|
|
1682
|
+
match its `wrangler.jsonc`. **Status 2026-05-07: D6 → D6.1 → D6.2
|
|
1683
|
+
reverted via D6.3** in favour of Cloudflare Workers Builds owning
|
|
1684
|
+
the deploy/preview pipelines per-worker. The replacement is being
|
|
1685
|
+
designed in a follow-up; until it ships, the existing per-site
|
|
1686
|
+
inline `deploy.yml` workflows in each storefront remain the
|
|
1687
|
+
operational deploy path (i.e. the original drift problem comes back
|
|
1688
|
+
on the surface for now, but with full single-credential trust
|
|
1689
|
+
isolation per storefront — no shared credentials).
|
|
1694
1690
|
|
|
1695
1691
|
#### Counter-evidence the user-rule asks for
|
|
1696
1692
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/start",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deco framework for TanStack Start - CMS bridge, admin protocol, hooks, schema generation",
|
|
6
6
|
"main": "./src/index.ts",
|
|
7
7
|
"bin": {
|
|
8
8
|
"deco-migrate": "./scripts/migrate.ts",
|
|
9
9
|
"deco-post-cleanup": "./scripts/migrate-post-cleanup.ts",
|
|
10
|
-
"deco-htmx-analyze": "./scripts/htmx-analyze.ts"
|
|
11
|
-
"deco-wrangler": "./scripts/deploy/wrangler-wrapper.mjs"
|
|
10
|
+
"deco-htmx-analyze": "./scripts/htmx-analyze.ts"
|
|
12
11
|
},
|
|
13
12
|
"exports": {
|
|
14
13
|
".": "./src/index.ts",
|
|
@@ -5,7 +5,6 @@ import { log, logPhase } from "./types";
|
|
|
5
5
|
import { generatePackageJson } from "./templates/package-json";
|
|
6
6
|
import { generateTsconfig } from "./templates/tsconfig";
|
|
7
7
|
import { generateViteConfig } from "./templates/vite-config";
|
|
8
|
-
import { generateGithubWorkflows } from "./templates/github-workflows";
|
|
9
8
|
import { generateKnipConfig } from "./templates/knip-config";
|
|
10
9
|
import { generateRoutes } from "./templates/routes";
|
|
11
10
|
import { generateSetup } from "./templates/setup";
|
|
@@ -50,20 +49,21 @@ function writeMultiFile(ctx: MigrationContext, files: Record<string, string>) {
|
|
|
50
49
|
export function scaffold(ctx: MigrationContext): void {
|
|
51
50
|
logPhase("Scaffold");
|
|
52
51
|
|
|
53
|
-
// Root config files. wrangler.jsonc is
|
|
54
|
-
//
|
|
55
|
-
// deploy
|
|
56
|
-
//
|
|
57
|
-
// by convention; there is no per-site registry.
|
|
52
|
+
// Root config files. wrangler.jsonc is intentionally NOT generated by
|
|
53
|
+
// the migration script -- it's per-site, lives in the site repo, and
|
|
54
|
+
// is wired by hand on first deploy (D6.3 interim state until the
|
|
55
|
+
// Cloudflare Workers Builds onboarding lands).
|
|
58
56
|
writeFile(ctx, "package.json", generatePackageJson(ctx));
|
|
59
57
|
writeFile(ctx, "tsconfig.json", generateTsconfig());
|
|
60
58
|
writeFile(ctx, "vite.config.ts", generateViteConfig(ctx));
|
|
61
59
|
writeFile(ctx, "knip.config.ts", generateKnipConfig());
|
|
62
60
|
writeFile(ctx, ".gitignore", generateGitignore());
|
|
63
61
|
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
|
|
62
|
+
// Deploy / preview pipelines are owned by Cloudflare Workers Builds
|
|
63
|
+
// configured per-worker in the CF dashboard (D6.3). The migration
|
|
64
|
+
// does NOT scaffold deploy/preview/sync-secrets workflows in the site
|
|
65
|
+
// repo; the operator wires the repo<->worker connection in the CF
|
|
66
|
+
// dashboard once after the first push.
|
|
67
67
|
writeFile(ctx, ".prettierrc", JSON.stringify({
|
|
68
68
|
semi: true,
|
|
69
69
|
singleQuote: false,
|
|
@@ -216,9 +216,6 @@ dist/
|
|
|
216
216
|
# Cloudflare Workers
|
|
217
217
|
.wrangler/
|
|
218
218
|
.dev.vars
|
|
219
|
-
# Generated by \`deco-wrangler\` from @decocms/start's wrangler template.
|
|
220
|
-
# Worker name is derived from the git remote / package.json by convention.
|
|
221
|
-
wrangler.jsonc
|
|
222
219
|
|
|
223
220
|
# TanStack Router (auto-generated)
|
|
224
221
|
src/routeTree.gen.ts
|
|
@@ -13,12 +13,10 @@ const REQUIRED_FILES = [
|
|
|
13
13
|
"package.json",
|
|
14
14
|
"tsconfig.json",
|
|
15
15
|
"vite.config.ts",
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
".github/workflows/preview.yml",
|
|
16
|
+
// Deploy / preview / sync-secrets pipelines are owned by Cloudflare
|
|
17
|
+
// Workers Builds (D6.3) -- configured in the CF dashboard, not via
|
|
18
|
+
// GitHub workflow files in the site repo.
|
|
20
19
|
".github/workflows/regen-blocks.yml",
|
|
21
|
-
".github/workflows/sync-secrets.yml",
|
|
22
20
|
"knip.config.ts",
|
|
23
21
|
".prettierrc",
|
|
24
22
|
"src/server.ts",
|
|
@@ -109,15 +109,12 @@ export function generatePackageJson(ctx: MigrationContext): string {
|
|
|
109
109
|
build:
|
|
110
110
|
"npm run generate:blocks && npm run generate:sections && npm run generate:loaders && npm run generate:schema && npm run generate:invoke && tsr generate && vite build",
|
|
111
111
|
preview: "vite preview",
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
deploy:
|
|
119
|
-
"echo 'Production deploys are managed by .github/workflows/deploy.yml on push to main. For an emergency manual deploy run: npx deco-wrangler deploy'; exit 1",
|
|
120
|
-
types: "deco-wrangler types",
|
|
112
|
+
// Deploy is owned by Cloudflare Workers Builds (D6.3); the
|
|
113
|
+
// repo<->worker connection is configured per-worker in the CF
|
|
114
|
+
// dashboard. Local devs use plain `wrangler` against the
|
|
115
|
+
// committed wrangler.jsonc.
|
|
116
|
+
deploy: "wrangler deploy",
|
|
117
|
+
types: "wrangler types",
|
|
121
118
|
typecheck: "tsc --noEmit",
|
|
122
119
|
format: 'prettier --write "src/**/*.{ts,tsx}"',
|
|
123
120
|
"format:check": 'prettier --check "src/**/*.{ts,tsx}"',
|