@decocms/start 2.28.2 → 2.30.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/vtex-commerce.md +5 -1
- package/.agents/skills/deco-to-tanstack-migration/references/worker-cloudflare.md +107 -10
- package/.agents/skills/deco-to-tanstack-migration/templates/package-json.md +5 -1
- package/.cursor/rules/migration-tooling-policy.mdc +22 -2
- package/.github/workflows/deploy.yml +115 -0
- package/.github/workflows/preview.yml +143 -0
- package/.github/workflows/regen-blocks.yml +56 -0
- package/.github/workflows/release.yml +26 -0
- package/.github/workflows/sync-secrets.yml +173 -0
- package/CODEOWNERS +16 -0
- package/MIGRATION_TOOLING_PLAN.md +16 -4
- package/README.md +178 -79
- package/deploy/README.md +85 -0
- package/deploy/sites/als-tanstack.jsonc +7 -0
- package/deploy/sites/americanas-tanstack.jsonc +4 -0
- package/deploy/sites/baggagio-tanstack.jsonc +4 -0
- package/deploy/sites/casaevideo-storefront.jsonc +11 -0
- package/deploy/sites/lebiscuit-tanstack.jsonc +19 -0
- package/deploy/sites/miess-01-tanstack.jsonc +8 -0
- package/deploy/wrangler-template.jsonc +28 -0
- package/package.json +18 -15
- package/scripts/deploy/build-wrangler-config.mjs +49 -0
- package/scripts/deploy/jsonc.mjs +76 -0
- package/scripts/deploy/resolve-site.mjs +58 -0
- package/scripts/deploy/site-registry.mjs +142 -0
- package/scripts/deploy/wrangler-wrapper.mjs +126 -0
- package/scripts/migrate/phase-scaffold.ts +13 -3
- package/scripts/migrate/phase-verify.ts +6 -1
- package/scripts/migrate/templates/github-workflows.ts +98 -0
- package/scripts/migrate/templates/package-json.ts +9 -2
- package/src/cms/resolve.ts +81 -63
- package/src/cms/sectionLoaders.ts +11 -0
- package/src/index.ts +3 -0
- package/src/sdk/cachedLoader.ts +36 -13
- package/src/sdk/composite.test.ts +121 -0
- package/src/sdk/composite.ts +114 -0
- package/src/sdk/instrumentedFetch.ts +56 -0
- package/src/sdk/logger.test.ts +135 -0
- package/src/sdk/logger.ts +166 -0
- package/src/sdk/observability.ts +75 -0
- package/src/sdk/otel.test.ts +59 -0
- package/src/sdk/otel.ts +270 -29
- package/src/sdk/otelAdapters.test.ts +135 -0
- package/src/sdk/otelAdapters.ts +401 -0
- package/src/sdk/sampler.test.ts +127 -0
- package/src/sdk/sampler.ts +183 -0
- package/src/sdk/workerEntry.ts +541 -476
- package/scripts/migrate/templates/wrangler.ts +0 -30
|
@@ -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`
|
|
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 **central** `decocms/deco-start/deploy/wrangler-template.jsonc` (D6); site repos do not commit `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
|
|
@@ -36,7 +36,11 @@ This lets the core component render while gracefully degrading features that dep
|
|
|
36
36
|
|
|
37
37
|
## 7. VTEX API Auth on Cloudflare Workers
|
|
38
38
|
|
|
39
|
-
Env vars
|
|
39
|
+
Env vars are stored as `SECRET_*` GitHub repo secrets (e.g. `SECRET_VTEX_APP_KEY`)
|
|
40
|
+
and pushed to the worker via the centralized `Sync worker secrets` workflow
|
|
41
|
+
(D6). Locally, use `.dev.vars` (gitignored) for development. Do not run
|
|
42
|
+
`npx wrangler secret put` per-site — the central workflow keeps GitHub and
|
|
43
|
+
Cloudflare in sync.
|
|
40
44
|
|
|
41
45
|
|
|
42
46
|
## 8. Cookie Handling
|
|
@@ -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.
|
|
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 **canonical wrangler template** at `decocms/deco-start/deploy/wrangler-template.jsonc` (D6) — sites do not configure this themselves.
|
|
41
41
|
|
|
42
42
|
```typescript
|
|
43
43
|
// src/worker-entry.ts
|
|
@@ -57,13 +57,10 @@ export default createDecoWorkerEntry(serverEntry, {
|
|
|
57
57
|
});
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// NOT: "main": "@tanstack/react-start/server-entry"
|
|
65
|
-
}
|
|
66
|
-
```
|
|
60
|
+
The `main` field is set centrally so a future migration of the entry path
|
|
61
|
+
applies to every site at once (single PR to the template). If you ever need to
|
|
62
|
+
override `main` for a single site, add it under `deploy/sites/<repo>.jsonc` —
|
|
63
|
+
never to a per-site `wrangler.jsonc` (sites don't commit one; see D6).
|
|
67
64
|
|
|
68
65
|
This ensures admin route interception AND edge caching survive the build because they're in the Worker's own fetch handler, outside of TanStack's build pipeline.
|
|
69
66
|
|
|
@@ -136,9 +133,14 @@ Imports like `import Color from "npm:colorjs.io"` use the Deno-specific `npm:` p
|
|
|
136
133
|
After deploying a new build to Cloudflare Workers, the edge cache may still serve old HTML that references previous JS bundle hashes. This causes module import failures.
|
|
137
134
|
|
|
138
135
|
**Fix**: After every deploy, purge the cache:
|
|
139
|
-
1. Set a `PURGE_TOKEN` secret
|
|
136
|
+
1. Set a `PURGE_TOKEN` secret. Add `SECRET_PURGE_TOKEN` to the site repo's
|
|
137
|
+
GitHub Secrets, then trigger the centralized `Sync worker secrets`
|
|
138
|
+
workflow (`workflow_dispatch` → `apply`). This pushes it to the Cloudflare
|
|
139
|
+
worker via `wrangler secret put PURGE_TOKEN`. **Do not** run
|
|
140
|
+
`npx wrangler secret put` manually per-site — the central workflow keeps
|
|
141
|
+
GitHub and Cloudflare in sync.
|
|
140
142
|
2. Call the purge endpoint: `POST /_cache/purge` with `Authorization: Bearer <token>` and body `{"paths":["/"]}`
|
|
141
|
-
3.
|
|
143
|
+
3. The right place to automate this is the **central** `deco-start/.github/workflows/deploy.yml` (D6) so every site picks it up at once. Do not add site-local deploy.yml steps; site repos hold only ~5-line caller workflows.
|
|
142
144
|
|
|
143
145
|
|
|
144
146
|
## 44. Runtime Module Import Kills Lazy-Loaded Sections
|
|
@@ -207,3 +209,98 @@ Or in project `.npmrc` with an env var (for CI):
|
|
|
207
209
|
```
|
|
208
210
|
|
|
209
211
|
**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.
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
## 46. Central Deploy / Wrangler Config (D6)
|
|
215
|
+
|
|
216
|
+
**Severity**: HIGH — site repos must NOT commit `wrangler.jsonc` or per-site deploy logic. Doing so reintroduces drift.
|
|
217
|
+
|
|
218
|
+
Per [D6](../../../../.cursor/rules/migration-tooling-policy.mdc), all
|
|
219
|
+
storefronts deploy via reusable workflows shipped from
|
|
220
|
+
`decocms/deco-start/.github/workflows/{deploy,preview,sync-secrets,regen-blocks}.yml@v2`.
|
|
221
|
+
The canonical `wrangler.jsonc` lives at
|
|
222
|
+
`decocms/deco-start/deploy/wrangler-template.jsonc`; per-site overrides live at
|
|
223
|
+
`decocms/deco-start/deploy/sites/<repo-name>.jsonc`. The two are deep-merged at
|
|
224
|
+
deploy time and written to a generated `wrangler.jsonc` in the runner; site
|
|
225
|
+
repos gitignore the file.
|
|
226
|
+
|
|
227
|
+
### What goes in the site repo
|
|
228
|
+
|
|
229
|
+
Four ~5-line caller workflow stubs and nothing else:
|
|
230
|
+
|
|
231
|
+
```yaml
|
|
232
|
+
# .github/workflows/deploy.yml
|
|
233
|
+
name: Deploy
|
|
234
|
+
on:
|
|
235
|
+
push:
|
|
236
|
+
branches: [main]
|
|
237
|
+
permissions:
|
|
238
|
+
contents: write
|
|
239
|
+
jobs:
|
|
240
|
+
deploy:
|
|
241
|
+
uses: decocms/deco-start/.github/workflows/deploy.yml@v2
|
|
242
|
+
secrets: inherit
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
(Plus equivalent `preview.yml`, `regen-blocks.yml`, `sync-secrets.yml` —
|
|
246
|
+
see `scripts/migrate/templates/github-workflows.ts` for the canonical text.)
|
|
247
|
+
The migration script generates these for new sites; the same stubs are
|
|
248
|
+
hand-applied to existing sites.
|
|
249
|
+
|
|
250
|
+
### What goes in `decocms/deco-start/deploy/sites/<repo>.jsonc`
|
|
251
|
+
|
|
252
|
+
The minimum:
|
|
253
|
+
|
|
254
|
+
```jsonc
|
|
255
|
+
{
|
|
256
|
+
"worker_name": "<repo-name>"
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Plus optional `routes`, `kv_namespaces`, `analytics_engine_datasets`,
|
|
261
|
+
`version_metadata` for the few sites that need them. Adding a new site is a
|
|
262
|
+
PR to deco-start, not a change to the site repo.
|
|
263
|
+
|
|
264
|
+
### Local dev
|
|
265
|
+
|
|
266
|
+
Site repos add three package.json hooks so vite picks up the generated
|
|
267
|
+
`wrangler.jsonc`:
|
|
268
|
+
|
|
269
|
+
```jsonc
|
|
270
|
+
"scripts": {
|
|
271
|
+
"gen:wrangler": "deco-wrangler gen",
|
|
272
|
+
"predev": "deco-wrangler gen",
|
|
273
|
+
"prebuild": "deco-wrangler gen",
|
|
274
|
+
"types": "deco-wrangler types",
|
|
275
|
+
"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"
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
`deco-wrangler` is a `bin` shipped from `@decocms/start` that materializes the
|
|
280
|
+
canonical config from the central registry, then either exits (`gen` mode) or
|
|
281
|
+
execs the real `wrangler` with that config in cwd.
|
|
282
|
+
|
|
283
|
+
### Trust model
|
|
284
|
+
|
|
285
|
+
- The central workflow ignores all caller `inputs:` for site identity.
|
|
286
|
+
- Site name is derived from `${{ github.repository }}` (set by GitHub,
|
|
287
|
+
untamperable by user code) and looked up in `deploy/sites/<repo>.jsonc`.
|
|
288
|
+
- A customer cannot misroute their deploy onto another site's worker
|
|
289
|
+
because they can't write to `decocms/deco-start` (CODEOWNERS-protected).
|
|
290
|
+
|
|
291
|
+
### Common mistakes (do not do these)
|
|
292
|
+
|
|
293
|
+
- **Committing `wrangler.jsonc` to a site repo.** Generated only;
|
|
294
|
+
always gitignored. If you see it tracked, the site missed migration.
|
|
295
|
+
- **Adding a site-local `deploy.yml` step** (e.g. cache purge after deploy).
|
|
296
|
+
Add it to `deco-start/.github/workflows/deploy.yml` instead so every site
|
|
297
|
+
picks it up at once.
|
|
298
|
+
- **Hard-coding `account_id` in a site's wrangler config.** It comes from
|
|
299
|
+
`CLOUDFLARE_ACCOUNT_ID` (org-level GitHub secret in CI; `wrangler login`
|
|
300
|
+
locally). Removing it from JSON is the one-way protection against
|
|
301
|
+
accidentally deploying to the wrong account.
|
|
302
|
+
- **Setting `worker_name` to anything other than the repo name** without
|
|
303
|
+
a strong reason. The 1:1 binding makes audit (and incident response)
|
|
304
|
+
trivial. Exceptions today: `casaevideo-storefront` -> `casaevideo-tanstack`
|
|
305
|
+
and `miess-01-tanstack` -> `miess-tanstack` (both for historical
|
|
306
|
+
Cloudflare worker names that predate the repo).
|
|
@@ -12,7 +12,11 @@
|
|
|
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
|
-
"
|
|
15
|
+
"gen:wrangler": "deco-wrangler gen",
|
|
16
|
+
"predev": "deco-wrangler gen",
|
|
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"
|
|
16
20
|
},
|
|
17
21
|
"dependencies": {
|
|
18
22
|
"@decocms/apps": "^0.20.1",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Constitutional decisions for the deco-start migration-tooling effort (D1–
|
|
2
|
+
description: Constitutional decisions for the deco-start migration-tooling effort (D1–D6, 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–D6), 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,6 +76,25 @@ 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 — Deploy / preview / secrets pipelines: centralize in `deco-start` (signed off 2026-05-07)
|
|
80
|
+
All storefronts deploy via reusable workflows under
|
|
81
|
+
`decocms/deco-start/.github/workflows/{deploy,preview,sync-secrets,regen-blocks}.yml@v2`.
|
|
82
|
+
Per-site overrides live in [`deploy/sites/<repo>.jsonc`](../../deploy/) and
|
|
83
|
+
are deep-merged on top of [`deploy/wrangler-template.jsonc`](../../deploy/wrangler-template.jsonc)
|
|
84
|
+
at deploy time. **Customer repos do not commit `wrangler.jsonc`** — it is
|
|
85
|
+
generated locally by `deco-wrangler gen` (a `bin` shipped from
|
|
86
|
+
`@decocms/start`) and gitignored. The repo→worker binding is the trust
|
|
87
|
+
boundary: the central workflow ignores caller `inputs:` for identity and
|
|
88
|
+
derives the site name from `${{ github.repository }}`. `deploy/**` is
|
|
89
|
+
CODEOWNERS-protected.
|
|
90
|
+
|
|
91
|
+
**Agent behavior**: when adding or migrating a site, do **not** generate a
|
|
92
|
+
per-site `wrangler.jsonc` or per-site `deploy.yml` / `preview.yml` /
|
|
93
|
+
`sync-secrets.yml` / `regen-blocks.yml`. The site repo gets the four
|
|
94
|
+
~5-line caller stubs only. Per-site config goes in a PR to
|
|
95
|
+
`decocms/deco-start` adding `deploy/sites/<repo>.jsonc`. Do not commit
|
|
96
|
+
`wrangler.jsonc` or any wrangler config to a site repo.
|
|
97
|
+
|
|
79
98
|
## Priority order
|
|
80
99
|
|
|
81
100
|
Work proceeds in this order. Higher priorities don't block on lower ones,
|
|
@@ -109,3 +128,4 @@ order — but only if explicitly identified as urgent.
|
|
|
109
128
|
- When reading a section of the plan or a skill, prefer the plan or skill
|
|
110
129
|
over your memory of past conversations.
|
|
111
130
|
- Do not run `deco-deploy` or any deploy command from agent flows.
|
|
131
|
+
- Do not commit `wrangler.jsonc` to a site repo. See **D6** above.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
name: deploy (central)
|
|
2
|
+
|
|
3
|
+
# Reusable workflow that drives `wrangler deploy` for any storefront repo
|
|
4
|
+
# registered under `deploy/sites/<repo-name>.jsonc`.
|
|
5
|
+
#
|
|
6
|
+
# Site identity (worker name, KV bindings, routes, ...) is derived ONLY from
|
|
7
|
+
# `${{ github.repository }}` and the registry checked in to deco-start. The
|
|
8
|
+
# caller cannot pass an `inputs:` block to override the worker name -- this is
|
|
9
|
+
# the trust boundary that prevents one site's commits from deploying on top of
|
|
10
|
+
# another site's worker.
|
|
11
|
+
#
|
|
12
|
+
# Caller usage (in customer repo, `.github/workflows/deploy.yml`):
|
|
13
|
+
#
|
|
14
|
+
# on:
|
|
15
|
+
# push:
|
|
16
|
+
# branches: [main]
|
|
17
|
+
# permissions:
|
|
18
|
+
# contents: write
|
|
19
|
+
# jobs:
|
|
20
|
+
# deploy:
|
|
21
|
+
# uses: decocms/deco-start/.github/workflows/deploy.yml@v2
|
|
22
|
+
# secrets: inherit
|
|
23
|
+
|
|
24
|
+
on:
|
|
25
|
+
workflow_call:
|
|
26
|
+
secrets:
|
|
27
|
+
CLOUDFLARE_API_TOKEN:
|
|
28
|
+
required: true
|
|
29
|
+
CLOUDFLARE_ACCOUNT_ID:
|
|
30
|
+
required: true
|
|
31
|
+
|
|
32
|
+
permissions:
|
|
33
|
+
contents: write
|
|
34
|
+
|
|
35
|
+
concurrency:
|
|
36
|
+
group: deploy-${{ github.repository }}
|
|
37
|
+
cancel-in-progress: false
|
|
38
|
+
|
|
39
|
+
jobs:
|
|
40
|
+
deploy:
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
steps:
|
|
43
|
+
- name: Checkout caller repo
|
|
44
|
+
uses: actions/checkout@v4
|
|
45
|
+
|
|
46
|
+
- name: Resolve deco-start ref + site identity
|
|
47
|
+
id: meta
|
|
48
|
+
run: |
|
|
49
|
+
# github.workflow_ref looks like
|
|
50
|
+
# decocms/deco-start/.github/workflows/deploy.yml@refs/tags/v1
|
|
51
|
+
# or
|
|
52
|
+
# decocms/deco-start/.github/workflows/deploy.yml@refs/heads/main
|
|
53
|
+
WF_REF="${{ github.workflow_ref }}"
|
|
54
|
+
REF="${WF_REF##*@}"
|
|
55
|
+
REF="${REF#refs/tags/}"
|
|
56
|
+
REF="${REF#refs/heads/}"
|
|
57
|
+
echo "deco_start_ref=$REF" >> "$GITHUB_OUTPUT"
|
|
58
|
+
echo "site_name=${GITHUB_REPOSITORY#*/}" >> "$GITHUB_OUTPUT"
|
|
59
|
+
|
|
60
|
+
- name: Checkout deco-start registry at the same ref
|
|
61
|
+
uses: actions/checkout@v4
|
|
62
|
+
with:
|
|
63
|
+
repository: decocms/deco-start
|
|
64
|
+
ref: ${{ steps.meta.outputs.deco_start_ref }}
|
|
65
|
+
path: .deco-start
|
|
66
|
+
|
|
67
|
+
- uses: actions/setup-node@v4
|
|
68
|
+
with:
|
|
69
|
+
node-version: 22
|
|
70
|
+
|
|
71
|
+
- name: Generate lockfile if missing
|
|
72
|
+
if: hashFiles('package-lock.json') == ''
|
|
73
|
+
run: npm install --package-lock-only
|
|
74
|
+
|
|
75
|
+
- name: Restore npm cache
|
|
76
|
+
uses: actions/cache@v4
|
|
77
|
+
with:
|
|
78
|
+
path: ~/.npm
|
|
79
|
+
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
80
|
+
restore-keys: npm-${{ runner.os }}-
|
|
81
|
+
|
|
82
|
+
- name: Sync lockfile and install
|
|
83
|
+
run: |
|
|
84
|
+
npm install --package-lock-only
|
|
85
|
+
if ! git diff --quiet package-lock.json 2>/dev/null; then
|
|
86
|
+
git config user.name "github-actions[bot]"
|
|
87
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
88
|
+
git add package-lock.json
|
|
89
|
+
git commit -m "chore: sync package-lock.json"
|
|
90
|
+
git push || echo "Lockfile push failed (remote ahead); proceeding with deploy"
|
|
91
|
+
fi
|
|
92
|
+
npm ci
|
|
93
|
+
|
|
94
|
+
- name: Build
|
|
95
|
+
run: npm run build
|
|
96
|
+
|
|
97
|
+
- name: Resolve site manifest
|
|
98
|
+
id: site
|
|
99
|
+
run: node .deco-start/scripts/deploy/resolve-site.mjs
|
|
100
|
+
env:
|
|
101
|
+
DECO_START_PATH: .deco-start
|
|
102
|
+
SITE_NAME: ${{ steps.meta.outputs.site_name }}
|
|
103
|
+
|
|
104
|
+
- name: Generate wrangler.jsonc
|
|
105
|
+
run: node .deco-start/scripts/deploy/build-wrangler-config.mjs
|
|
106
|
+
env:
|
|
107
|
+
DECO_START_PATH: .deco-start
|
|
108
|
+
SITE_NAME: ${{ steps.meta.outputs.site_name }}
|
|
109
|
+
OUTPUT_PATH: ./wrangler.jsonc
|
|
110
|
+
|
|
111
|
+
- name: Deploy to Cloudflare Workers
|
|
112
|
+
run: npx wrangler deploy --var BUILD_HASH:$(git rev-parse --short HEAD)
|
|
113
|
+
env:
|
|
114
|
+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
115
|
+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
name: preview (central)
|
|
2
|
+
|
|
3
|
+
# Reusable workflow that uploads a preview version (alias) for any storefront
|
|
4
|
+
# repo registered under `deploy/sites/<repo-name>.jsonc`.
|
|
5
|
+
#
|
|
6
|
+
# Caller usage (in customer repo, `.github/workflows/preview.yml`):
|
|
7
|
+
#
|
|
8
|
+
# on:
|
|
9
|
+
# repository_dispatch:
|
|
10
|
+
# types: [preview-deploy]
|
|
11
|
+
# pull_request:
|
|
12
|
+
# types: [opened, synchronize, reopened]
|
|
13
|
+
# push:
|
|
14
|
+
# branches: ['env/**']
|
|
15
|
+
# permissions:
|
|
16
|
+
# contents: read
|
|
17
|
+
# pull-requests: write
|
|
18
|
+
# statuses: write
|
|
19
|
+
# jobs:
|
|
20
|
+
# preview:
|
|
21
|
+
# uses: decocms/deco-start/.github/workflows/preview.yml@v2
|
|
22
|
+
# secrets: inherit
|
|
23
|
+
|
|
24
|
+
on:
|
|
25
|
+
workflow_call:
|
|
26
|
+
secrets:
|
|
27
|
+
CLOUDFLARE_API_TOKEN:
|
|
28
|
+
required: true
|
|
29
|
+
CLOUDFLARE_ACCOUNT_ID:
|
|
30
|
+
required: true
|
|
31
|
+
|
|
32
|
+
permissions:
|
|
33
|
+
contents: read
|
|
34
|
+
pull-requests: write
|
|
35
|
+
statuses: write
|
|
36
|
+
|
|
37
|
+
concurrency:
|
|
38
|
+
group: preview-${{ github.repository }}-${{ github.event.client_payload.ref || github.head_ref || github.ref_name }}
|
|
39
|
+
cancel-in-progress: true
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
preview:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- name: Resolve ref
|
|
46
|
+
id: resolve
|
|
47
|
+
run: |
|
|
48
|
+
if [ "${{ github.event_name }}" = "repository_dispatch" ]; then
|
|
49
|
+
echo "ref=${{ github.event.client_payload.ref }}" >> "$GITHUB_OUTPUT"
|
|
50
|
+
else
|
|
51
|
+
echo "ref=${{ github.head_ref || github.ref_name }}" >> "$GITHUB_OUTPUT"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
with:
|
|
56
|
+
ref: ${{ steps.resolve.outputs.ref }}
|
|
57
|
+
|
|
58
|
+
- name: Resolve deco-start ref + site identity
|
|
59
|
+
id: meta
|
|
60
|
+
run: |
|
|
61
|
+
WF_REF="${{ github.workflow_ref }}"
|
|
62
|
+
REF="${WF_REF##*@}"
|
|
63
|
+
REF="${REF#refs/tags/}"
|
|
64
|
+
REF="${REF#refs/heads/}"
|
|
65
|
+
echo "deco_start_ref=$REF" >> "$GITHUB_OUTPUT"
|
|
66
|
+
echo "site_name=${GITHUB_REPOSITORY#*/}" >> "$GITHUB_OUTPUT"
|
|
67
|
+
|
|
68
|
+
- name: Checkout deco-start registry at the same ref
|
|
69
|
+
uses: actions/checkout@v4
|
|
70
|
+
with:
|
|
71
|
+
repository: decocms/deco-start
|
|
72
|
+
ref: ${{ steps.meta.outputs.deco_start_ref }}
|
|
73
|
+
path: .deco-start
|
|
74
|
+
|
|
75
|
+
- uses: actions/setup-node@v4
|
|
76
|
+
with:
|
|
77
|
+
node-version: 22
|
|
78
|
+
|
|
79
|
+
- name: Compute preview alias
|
|
80
|
+
id: alias
|
|
81
|
+
run: |
|
|
82
|
+
REF="${{ steps.resolve.outputs.ref }}"
|
|
83
|
+
if echo "$REF" | grep -q '^env/'; then
|
|
84
|
+
ALIAS=$(echo "$REF" | sed 's|^env/||')
|
|
85
|
+
elif [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
86
|
+
ALIAS="pr-${{ github.event.pull_request.number }}"
|
|
87
|
+
else
|
|
88
|
+
ALIAS=$(echo "$REF" | sed 's|[^a-z0-9-]|-|g')
|
|
89
|
+
fi
|
|
90
|
+
echo "alias=$ALIAS" >> "$GITHUB_OUTPUT"
|
|
91
|
+
|
|
92
|
+
- name: Install dependencies
|
|
93
|
+
run: npm install
|
|
94
|
+
|
|
95
|
+
- name: Build
|
|
96
|
+
run: npm run build
|
|
97
|
+
|
|
98
|
+
- name: Resolve site manifest
|
|
99
|
+
id: site
|
|
100
|
+
run: node .deco-start/scripts/deploy/resolve-site.mjs
|
|
101
|
+
env:
|
|
102
|
+
DECO_START_PATH: .deco-start
|
|
103
|
+
SITE_NAME: ${{ steps.meta.outputs.site_name }}
|
|
104
|
+
|
|
105
|
+
- name: Generate wrangler.jsonc
|
|
106
|
+
run: node .deco-start/scripts/deploy/build-wrangler-config.mjs
|
|
107
|
+
env:
|
|
108
|
+
DECO_START_PATH: .deco-start
|
|
109
|
+
SITE_NAME: ${{ steps.meta.outputs.site_name }}
|
|
110
|
+
OUTPUT_PATH: ./wrangler.jsonc
|
|
111
|
+
|
|
112
|
+
- name: Upload preview version
|
|
113
|
+
id: deploy
|
|
114
|
+
run: |
|
|
115
|
+
set +e
|
|
116
|
+
OUTPUT=$(npx wrangler versions upload --preview-alias ${{ steps.alias.outputs.alias }} 2>&1)
|
|
117
|
+
EXIT_CODE=$?
|
|
118
|
+
set -e
|
|
119
|
+
echo "$OUTPUT"
|
|
120
|
+
if [ $EXIT_CODE -ne 0 ]; then
|
|
121
|
+
echo "::error::wrangler versions upload failed with exit code $EXIT_CODE"
|
|
122
|
+
exit $EXIT_CODE
|
|
123
|
+
fi
|
|
124
|
+
PREVIEW_URL=$(echo "$OUTPUT" | grep 'Version Preview URL:' | sed 's/.*Version Preview URL: //')
|
|
125
|
+
ALIAS_URL=$(echo "$OUTPUT" | grep 'Version Preview Alias URL:' | sed 's/.*Version Preview Alias URL: //')
|
|
126
|
+
echo "preview_url=${PREVIEW_URL}" >> "$GITHUB_OUTPUT"
|
|
127
|
+
echo "alias_url=${ALIAS_URL}" >> "$GITHUB_OUTPUT"
|
|
128
|
+
env:
|
|
129
|
+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
130
|
+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
131
|
+
|
|
132
|
+
- name: Comment preview URL on PR
|
|
133
|
+
if: github.event_name == 'pull_request'
|
|
134
|
+
uses: marocchino/sticky-pull-request-comment@v2
|
|
135
|
+
with:
|
|
136
|
+
header: preview-url
|
|
137
|
+
message: |
|
|
138
|
+
### Preview deployed
|
|
139
|
+
|
|
140
|
+
| | URL |
|
|
141
|
+
|---|---|
|
|
142
|
+
| **Version** | ${{ steps.deploy.outputs.preview_url }} |
|
|
143
|
+
| **Alias** | ${{ steps.deploy.outputs.alias_url }} |
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: regen-blocks (central)
|
|
2
|
+
|
|
3
|
+
# Reusable workflow. Regenerates `src/server/cms/blocks.gen.json` and commits
|
|
4
|
+
# the result back to the caller branch. Runs in the caller's runner context;
|
|
5
|
+
# uses bun because that's what the existing `generate:blocks` script expects.
|
|
6
|
+
#
|
|
7
|
+
# Caller usage (in customer repo, `.github/workflows/regen-blocks.yml`):
|
|
8
|
+
#
|
|
9
|
+
# on:
|
|
10
|
+
# push:
|
|
11
|
+
# branches: [main]
|
|
12
|
+
# paths: [".deco/blocks/**"]
|
|
13
|
+
# permissions:
|
|
14
|
+
# contents: write
|
|
15
|
+
# jobs:
|
|
16
|
+
# regen:
|
|
17
|
+
# uses: decocms/deco-start/.github/workflows/regen-blocks.yml@v2
|
|
18
|
+
# secrets: inherit
|
|
19
|
+
|
|
20
|
+
on:
|
|
21
|
+
workflow_call: {}
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: write
|
|
25
|
+
|
|
26
|
+
concurrency:
|
|
27
|
+
group: regen-blocks-${{ github.repository }}
|
|
28
|
+
cancel-in-progress: false
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
regen:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
|
|
36
|
+
- uses: oven-sh/setup-bun@v2
|
|
37
|
+
with:
|
|
38
|
+
bun-version: latest
|
|
39
|
+
|
|
40
|
+
- name: Install deps
|
|
41
|
+
run: bun install --frozen-lockfile
|
|
42
|
+
|
|
43
|
+
- name: Regenerate blocks.gen.json
|
|
44
|
+
run: bun run generate:blocks
|
|
45
|
+
|
|
46
|
+
- name: Commit and push if changed
|
|
47
|
+
run: |
|
|
48
|
+
if git diff --quiet src/server/cms/blocks.gen.json; then
|
|
49
|
+
echo "blocks.gen.json already up to date — nothing to commit."
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
git config user.name "github-actions[bot]"
|
|
53
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
54
|
+
git add src/server/cms/blocks.gen.json
|
|
55
|
+
git commit -m "chore: regenerate blocks.gen.json after .deco sync"
|
|
56
|
+
git push
|
|
@@ -29,3 +29,29 @@ jobs:
|
|
|
29
29
|
run: npx semantic-release
|
|
30
30
|
env:
|
|
31
31
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
32
|
+
|
|
33
|
+
# Caller workflows in storefront repos pin to a moveable major tag (`@v2`),
|
|
34
|
+
# GitHub Actions convention. After every release we fast-forward that major
|
|
35
|
+
# tag to the latest exact tag in the same series. Idempotent: if no new
|
|
36
|
+
# release happened, this just re-points to the existing latest, which is a
|
|
37
|
+
# no-op force-push.
|
|
38
|
+
#
|
|
39
|
+
# Why not a separate workflow on `push: tags`? GitHub suppresses workflow
|
|
40
|
+
# triggers caused by the auto-issued `GITHUB_TOKEN` (anti-recursion guard),
|
|
41
|
+
# and `@semantic-release/git` pushes tags using exactly that token, so a
|
|
42
|
+
# listener would never fire. Inlining keeps the lifecycle visible in one
|
|
43
|
+
# job log.
|
|
44
|
+
- name: Advance moveable major tag
|
|
45
|
+
run: |
|
|
46
|
+
git fetch --tags --force
|
|
47
|
+
LATEST=$(git tag -l 'v*.*.*' --sort=-v:refname | head -n 1)
|
|
48
|
+
if [ -z "$LATEST" ]; then
|
|
49
|
+
echo "::notice::no v*.*.* tags yet; nothing to advance"
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
MAJOR=$(echo "$LATEST" | sed -E 's/^(v[0-9]+).*/\1/')
|
|
53
|
+
git config user.name "github-actions[bot]"
|
|
54
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
55
|
+
git tag -f "$MAJOR" "$LATEST"
|
|
56
|
+
git push origin "$MAJOR" --force
|
|
57
|
+
echo "::notice::Moved $MAJOR -> $LATEST"
|