@getvitops/create 0.7.0 → 0.8.1
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/CHANGELOG.md +443 -6
- package/package.json +2 -3
- package/templates/emdash/.agents/skills/promote/SKILL.md +24 -7
- package/templates/emdash/.astro/types.d.ts +3 -0
- package/templates/emdash/.claude/hooks/session-start.sh +0 -0
- package/templates/emdash/.github/workflows/backmerge.yml +18 -0
- package/templates/emdash/.github/workflows/deploy-prod.yml +1 -1
- package/templates/emdash/.github/workflows/refresh-dev.yml +25 -0
- package/templates/emdash/.node-version +1 -0
- package/templates/emdash/AGENTS.md +51 -9
- package/templates/emdash/README.md +15 -4
- package/templates/emdash/SETUP.html +103 -0
- package/templates/emdash/astro.config.mjs +47 -4
- package/templates/emdash/package.json +15 -11
- package/templates/emdash/pnpm-lock.yaml +183 -0
- package/templates/emdash/pnpm-workspace.yaml +1 -1
- package/templates/emdash/public/_headers +10 -0
- package/templates/emdash/scripts/build-dev-wrangler.mjs +6 -0
- package/templates/emdash/scripts/refresh-dev.mjs +182 -0
- package/templates/emdash/seed/seed.json +104 -5
- package/templates/emdash/site.json +77 -2
- package/templates/emdash/src/layouts/Layout.astro +7 -1
- package/templates/emdash/src/pages/404.astro +5 -0
- package/templates/emdash/src/pages/[...slug].astro +15 -2
- package/templates/emdash/src/pages/index.astro +15 -2
- package/templates/emdash/vite.config.ts +18 -4
- package/templates/emdash/wrangler.jsonc +4 -0
- package/templates/static/.github/workflows/backmerge.yml +18 -0
- package/templates/static/.github/workflows/deploy-prod.yml +1 -1
- package/templates/static/.node-version +1 -0
- package/templates/static/AGENTS.md +9 -9
- package/templates/static/SETUP.html +103 -0
- package/templates/static/package.json +6 -6
- package/templates/static/pnpm-workspace.yaml +21 -0
- package/templates/static/public/_headers +10 -0
- package/templates/static/site.json +2 -2
|
@@ -19,6 +19,16 @@ styled by the Vitops design system.
|
|
|
19
19
|
`getEmDashCollection` / `getEmDashEntry` from `emdash`; render Portable Text
|
|
20
20
|
with `<PortableText />` from `emdash/ui` (the Vitops blocks from
|
|
21
21
|
`@getvitops/emdash` are merged in automatically).
|
|
22
|
+
- **Building pages from patterns:** the editor's insert menu offers the `vitops.*` blocks —
|
|
23
|
+
link/button, image compare, copy snippet, banner, disclosure, accordion, hero, carousel, gallery,
|
|
24
|
+
cards, marquee (`npx vitops docs blocks` lists them with every field). Repeating content (cards, gallery images, accordion items, carousel slides) is
|
|
25
|
+
a repeater field. A block cannot contain other blocks, and a `vitops.*` block inside EmDash's
|
|
26
|
+
built-in `columns` does not render — for layout (a section, a split, a hero) use a `blocks`
|
|
27
|
+
field, or hand-write the page template with `@getvitops/astro` components
|
|
28
|
+
(`Subgrid`, `Cards`, `Carousel`, …). `npx vitops docs components` lists every pattern, which
|
|
29
|
+
tiers provide it, and which block renders it. Override a block's rendering per site with
|
|
30
|
+
`<PortableText components={{ type: { 'vitops.cards': MyCards } }} />`; hide one with
|
|
31
|
+
`vitopsEmdash({ blocks: { exclude: [...] } })` in `astro.config.mjs`.
|
|
22
32
|
- `seed/seed.json` only applies against an empty database: structure
|
|
23
33
|
(collections, menus, settings) on first boot; the `content` entries only
|
|
24
34
|
when the setup wizard's "include sample content" option is chosen. Changing
|
|
@@ -30,15 +40,16 @@ styled by the Vitops design system.
|
|
|
30
40
|
full generated class-vocabulary reference to this file.
|
|
31
41
|
- **Layout foundations — these are the answer, not a starting point.** Six
|
|
32
42
|
substitutions carry the structure of nearly every page:
|
|
33
|
-
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
| `
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
| `repeat(
|
|
41
|
-
| `
|
|
43
|
+
|
|
44
|
+
| About to write… | Write instead |
|
|
45
|
+
| ------------------------------------------------------- | --------------- |
|
|
46
|
+
| a `wrap`/`wrapper`/`container`/`inner` class | **`centered`** |
|
|
47
|
+
| `max-width` + `margin-inline: auto` | **`centered`** |
|
|
48
|
+
| `padding-block` on a section | **`region`** |
|
|
49
|
+
| margins between headings/paragraphs/lists | **`rhythm`** |
|
|
50
|
+
| `display: grid` + `grid-template-columns: repeat(n, …)` | **`subgrid`** |
|
|
51
|
+
| `repeat(auto-fit, minmax(…))` | **`grid-auto`** |
|
|
52
|
+
| `display: flex` + `gap` for a row of controls | **`cluster`** |
|
|
42
53
|
|
|
43
54
|
`centered` is a grid of _named tracks_, not a max-width box — a child widens
|
|
44
55
|
itself with `breakout`/`spotlight`/`fullbleed` without the parent knowing, which
|
|
@@ -105,11 +116,42 @@ styled by the Vitops design system.
|
|
|
105
116
|
the fields its forms collect, where it deploys — rather than from guesses.
|
|
106
117
|
It still needs review before launch.
|
|
107
118
|
|
|
119
|
+
## EmDash 1.x behaviours worth knowing
|
|
120
|
+
|
|
121
|
+
- **Passkeys are bound to the hostname they were created on.** After the
|
|
122
|
+
workers.dev → custom-domain cutover, use **Settings → General → Change
|
|
123
|
+
domain**, then **Continue on** to add a passkey at the new address.
|
|
124
|
+
- **HTML blocks created in the admin run JavaScript** in a sandboxed iframe
|
|
125
|
+
(Contributor and up can add it). Astro's `security.csp` blocks their styles
|
|
126
|
+
and scripts, so don't turn CSP on without allowing for that.
|
|
127
|
+
- **Link entries by `entry.data.slug`, never `entry.id`** — on multilingual
|
|
128
|
+
sites `id` carries a locale prefix.
|
|
129
|
+
- **Submit `/sitemap.xml`** to search engines, not a per-collection sitemap;
|
|
130
|
+
collection sitemaps now split into pages of 2,000 entries.
|
|
131
|
+
- **A stuck D1 migration lock** is cleared with
|
|
132
|
+
`pnpm exec emdash migrate --take-over-lock <id>` (confirms the target, or
|
|
133
|
+
needs `--expected-target-fingerprint` non-interactively).
|
|
134
|
+
|
|
108
135
|
## Docs MCP servers
|
|
109
136
|
|
|
110
137
|
`.mcp.json` preconfigures the Astro docs and EmDash docs MCP servers — prefer
|
|
111
138
|
searching them over pre-trained knowledge for Astro/EmDash questions.
|
|
112
139
|
|
|
140
|
+
## EmDash agent skills
|
|
141
|
+
|
|
142
|
+
The EmDash skills (`building-emdash-site`, `creating-plugins`, `emdash-cli`,
|
|
143
|
+
`upgrading-emdash` and the two WordPress porting skills) are installed per
|
|
144
|
+
project, not globally, so they match the `emdash` version this repo pins. If
|
|
145
|
+
`.agents/skills/building-emdash-site/` is missing, install them (the setup guide
|
|
146
|
+
and `SETUP.html` have the full step):
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npx skills add emdash-cms/skills --skill '*' -a claude-code -y
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Refresh them with `npx skills update` after bumping `emdash` — the
|
|
153
|
+
`upgrading-emdash` skill covers the rest of the upgrade.
|
|
154
|
+
|
|
113
155
|
## Commands
|
|
114
156
|
|
|
115
157
|
- `pnpm dev` — local dev with local D1/R2 emulation (no Cloudflare account)
|
|
@@ -14,7 +14,8 @@ Scaffolded from `vp create @getvitops:emdash`.
|
|
|
14
14
|
(Tailwind v4 format), generates favicons/PWA assets from
|
|
15
15
|
`src/assets/logo.svg`, and serves the web-component runtime
|
|
16
16
|
- **`@getvitops/emdash`** — design-system Portable Text blocks in the editor
|
|
17
|
-
slash menu
|
|
17
|
+
slash menu (hero, cards, accordion, carousel, gallery, marquee, banner, …);
|
|
18
|
+
`npx vitops docs blocks` lists every block and field
|
|
18
19
|
|
|
19
20
|
`src/assets/placeholder/` ships neutral wireframe images for layout work
|
|
20
21
|
before real imagery exists — delete once real assets land (separate from
|
|
@@ -27,6 +28,11 @@ pnpm install
|
|
|
27
28
|
pnpm dev
|
|
28
29
|
```
|
|
29
30
|
|
|
31
|
+
Once this is its own repo (not sitting inside the `getvitops/design-system`
|
|
32
|
+
monorepo), uncomment `lint.options` in `vite.config.ts` for type-aware
|
|
33
|
+
`vp check`/`vp lint` — it ships commented out because vite-plus 1.0 only
|
|
34
|
+
honours that option at a project's actual root, and errors on it otherwise.
|
|
35
|
+
|
|
30
36
|
No Cloudflare account needed: `astro dev` runs the Worker locally with local
|
|
31
37
|
D1/R2 emulation (state in `.wrangler/`). On first boot EmDash runs its
|
|
32
38
|
migrations and applies the structure from `seed/seed.json` — a `pages`
|
|
@@ -82,7 +88,8 @@ The repo ships a two-environment flow modeled on branch = environment:
|
|
|
82
88
|
into `main` with auto-merge enabled. With required reviews on `main`, a
|
|
83
89
|
human approves the PR; merging deploys prod.
|
|
84
90
|
|
|
85
|
-
One-time setup —
|
|
91
|
+
One-time setup — see [Start a new EmDash site](https://docs.vitops.ca/guides/new-emdash-site) for the whole
|
|
92
|
+
procedure, then work through the checklist:
|
|
86
93
|
|
|
87
94
|
```bash
|
|
88
95
|
pnpm run sop && open SETUP.html # or: xdg-open SETUP.html
|
|
@@ -113,12 +120,12 @@ is a configurable dimension of the project, not a rewrite:
|
|
|
113
120
|
- **`node`** — `@astrojs/node` (standalone) + SQLite file + local uploads,
|
|
114
121
|
for a VPS / docker-compose / k8s host. Not installed by default; to switch:
|
|
115
122
|
`pnpm add @astrojs/node better-sqlite3`, then `vitopsHosting({ target:
|
|
116
|
-
'node' })` (or set `HOSTING=node` — the env var wins). Run the built site
|
|
123
|
+
'node' })` (or set `HOSTING=node` — the env var wins). Run the built site
|
|
117
124
|
with `node ./dist/server/entry.mjs`; data lives in `./data/` (gitignored) —
|
|
118
125
|
persist it as a volume. Scheduled publishing runs in-process on Node, so
|
|
119
126
|
the worker/cron pieces aren't needed. For production, move storage to
|
|
120
127
|
S3-compatible and/or the database to Postgres via `vitopsHosting({ node:
|
|
121
|
-
{ database, storage } })`. CI deploy for Node hosts is TBD — the shipped
|
|
128
|
+
{ database, storage } })`. CI deploy for Node hosts is TBD — the shipped
|
|
122
129
|
workflows are Cloudflare-specific.
|
|
123
130
|
|
|
124
131
|
Moving an existing site between targets (either direction) is a data
|
|
@@ -134,6 +141,10 @@ and media in the storage backend (bucket/directory copy).
|
|
|
134
141
|
- **Skills** (`.agents/skills/`): `promote` dispatches the dev → main
|
|
135
142
|
promotion workflow. Run `npx vitops agents` to also write the design-system
|
|
136
143
|
class reference into `AGENTS.md`.
|
|
144
|
+
- **EmDash skills** are installed per project so they match the pinned `emdash`
|
|
145
|
+
version: `npx skills add emdash-cms/skills --skill '*' -a claude-code -y`,
|
|
146
|
+
then commit `.agents/skills/` and `skills-lock.json`. Update with
|
|
147
|
+
`npx skills update` after an `emdash` bump.
|
|
137
148
|
- **Claude Code on the web**: the SessionStart hook
|
|
138
149
|
(`.claude/hooks/session-start.sh`) installs Node 24 (matching
|
|
139
150
|
`devEngines`), activates the pinned pnpm, and installs dependencies in the
|
|
@@ -159,6 +159,94 @@
|
|
|
159
159
|
this exists.
|
|
160
160
|
</span>
|
|
161
161
|
</label>
|
|
162
|
+
<label class="custom-check">
|
|
163
|
+
<input type="checkbox" data-sop="hosting.emdash-fingerprint" />
|
|
164
|
+
<span class="custom-check__box"
|
|
165
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
166
|
+
></span>
|
|
167
|
+
<span>
|
|
168
|
+
<strong>(EmDash template)</strong> After the first deploy to each environment, run
|
|
169
|
+
<code>npx emdash migrate --status</code> locally against that environment's real
|
|
170
|
+
database, review the printed account/database identity, and set the reviewed
|
|
171
|
+
fingerprint:
|
|
172
|
+
<code
|
|
173
|
+
>gh variable set EMDASH_TARGET_FINGERPRINT --env dev --body <value></code
|
|
174
|
+
>
|
|
175
|
+
and again with <code>--env production</code>. No command can do this for you — it's
|
|
176
|
+
the human review the fingerprint guard exists for. Deploys fail clearly on the
|
|
177
|
+
migration-apply step until it's set for that environment.
|
|
178
|
+
</span>
|
|
179
|
+
</label>
|
|
180
|
+
<label class="custom-check">
|
|
181
|
+
<input type="checkbox" data-sop="hosting.design-system-editor-token" />
|
|
182
|
+
<span class="custom-check__box"
|
|
183
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
184
|
+
></span>
|
|
185
|
+
<span>
|
|
186
|
+
<strong>(EmDash template, only if <code>designSystemEditor</code> is on)</strong>
|
|
187
|
+
Create a fine-grained GitHub PAT scoped to this one repository,
|
|
188
|
+
<code>Contents: Read and write</code> only — no <code>admin</code> scope, no access
|
|
189
|
+
to any other repo — then <code>gh secret set VITOPS_GITHUB_TOKEN</code>. Also set
|
|
190
|
+
<code>site.deployment.repo</code> (<code>"owner/name"</code>) and
|
|
191
|
+
<code>site.deployment.branch</code> (default <code>"dev"</code>) in
|
|
192
|
+
<code>site.json</code>. Without these the live design-system editor still works —
|
|
193
|
+
only the auto-commit-to-source half is skipped, and the admin page's response says
|
|
194
|
+
so.
|
|
195
|
+
</span>
|
|
196
|
+
</label>
|
|
197
|
+
<label class="custom-check">
|
|
198
|
+
<input type="checkbox" data-sop="hosting.content-in-prod" />
|
|
199
|
+
<span class="custom-check__box"
|
|
200
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
201
|
+
></span>
|
|
202
|
+
<span>
|
|
203
|
+
<strong>Know where content is edited (EmDash template).</strong> Editors work on the
|
|
204
|
+
<em>production</em> site — drafts, "Publish changes" and preview links are the
|
|
205
|
+
staging step. The dev site holds a disposable copy of production's database; it is
|
|
206
|
+
refreshed from prod and never promoted back. Code, pages and
|
|
207
|
+
<code>site.json</code> still go dev → main.
|
|
208
|
+
</span>
|
|
209
|
+
</label>
|
|
210
|
+
<label class="custom-check">
|
|
211
|
+
<input type="checkbox" data-sop="hosting.refresh-dev" />
|
|
212
|
+
<span class="custom-check__box"
|
|
213
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
214
|
+
></span>
|
|
215
|
+
<span>
|
|
216
|
+
EmDash template: run <strong>Refresh dev from prod</strong> (Actions tab) once the
|
|
217
|
+
prod site has content, and again before rehearsing a schema change. It runs weekly
|
|
218
|
+
on its own. To copy media as well, set <code>R2_ACCESS_KEY_ID</code> and
|
|
219
|
+
<code>R2_SECRET_ACCESS_KEY</code> (an R2 API token's S3 credentials) as repo
|
|
220
|
+
secrets; without them only the database is refreshed.
|
|
221
|
+
</span>
|
|
222
|
+
</label>
|
|
223
|
+
<label class="custom-check">
|
|
224
|
+
<input type="checkbox" data-sop="hosting.magic-link" />
|
|
225
|
+
<span class="custom-check__box"
|
|
226
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
227
|
+
></span>
|
|
228
|
+
<span>
|
|
229
|
+
EmDash template: onboard the sender domain for sign-in email —
|
|
230
|
+
<code>npx vitops email setup send.<your-domain></code>, then put that address
|
|
231
|
+
in <code>cloudflareEmail({ from })</code> in <code>astro.config.mjs</code> (it ships
|
|
232
|
+
a placeholder). Editors sign in with a magic link ("Sign in with email" on the login
|
|
233
|
+
page) because a passkey only works at the origin it was registered on, so a
|
|
234
|
+
refreshed dev site has no other way in. Check <strong>Settings → Email</strong> and
|
|
235
|
+
send the test email on both prod and dev.
|
|
236
|
+
</span>
|
|
237
|
+
</label>
|
|
238
|
+
<label class="custom-check">
|
|
239
|
+
<input type="checkbox" data-sop="hosting.preview-secret" />
|
|
240
|
+
<span class="custom-check__box"
|
|
241
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
242
|
+
></span>
|
|
243
|
+
<span>
|
|
244
|
+
EmDash template: set a different <code>EMDASH_PREVIEW_SECRET</code> on the dev
|
|
245
|
+
worker (<code>wrangler secret put EMDASH_PREVIEW_SECRET</code>). The secret lives in
|
|
246
|
+
the database, so a refresh copies prod's — and prod preview links would then open
|
|
247
|
+
drafts on dev.
|
|
248
|
+
</span>
|
|
249
|
+
</label>
|
|
162
250
|
</div>
|
|
163
251
|
</details>
|
|
164
252
|
|
|
@@ -326,6 +414,21 @@
|
|
|
326
414
|
<code>npx vitops setup ads</code>.
|
|
327
415
|
</span>
|
|
328
416
|
</label>
|
|
417
|
+
<label class="custom-check">
|
|
418
|
+
<input type="checkbox" data-sop="connections.email" />
|
|
419
|
+
<span class="custom-check__box"
|
|
420
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
421
|
+
></span>
|
|
422
|
+
<span>
|
|
423
|
+
If <code>site.notifications.email</code> sends mail, onboard its sender domain:
|
|
424
|
+
<code>npx vitops email setup --dry</code>, then <code>npx vitops email setup</code>.
|
|
425
|
+
Cloudflare onboards an exact name — usually a subdomain like
|
|
426
|
+
<code>send.<domain></code>, not the apex — so a mismatch here is silent at
|
|
427
|
+
build time and only fails when a form is actually submitted in production. Both
|
|
428
|
+
templates' <code>deploy</code> script already runs
|
|
429
|
+
<code>vitops email check</code> first as a non-blocking warning.
|
|
430
|
+
</span>
|
|
431
|
+
</label>
|
|
329
432
|
<label class="custom-check">
|
|
330
433
|
<input type="checkbox" data-sop="connections.manual" />
|
|
331
434
|
<span class="custom-check__box"
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import react from '@astrojs/react';
|
|
2
|
+
import { cloudflareEmail } from '@emdash-cms/cloudflare/plugins';
|
|
2
3
|
import vitops from '@getvitops/astro';
|
|
4
|
+
import { resolveOrganizationName } from '@getvitops/astro/routes';
|
|
3
5
|
import { vitopsEmdash, vitopsHosting } from '@getvitops/emdash';
|
|
4
6
|
import { defineConfig } from 'astro/config';
|
|
5
7
|
import emdash from 'emdash/astro';
|
|
8
|
+
import config from './site.json' with { type: 'json' };
|
|
9
|
+
|
|
10
|
+
// site.json's organization.name is the one build-time-readable source for a
|
|
11
|
+
// display name — EmDash's own getSiteSettings() only resolves inside a live
|
|
12
|
+
// Worker request (AsyncLocalStorage + a DB binding), so it can't be read here
|
|
13
|
+
// even though it's what Layout.astro shows on rendered pages. See AGENTS.md's
|
|
14
|
+
// "EmDash plugin as the design-system editing surface".
|
|
15
|
+
const organizationName = resolveOrganizationName(config) ?? 'My EmDash Site';
|
|
6
16
|
|
|
7
17
|
// Hosting seam: adapter + EmDash database/storage for the configured target.
|
|
8
18
|
// Default 'cloudflare' (Workers + D1 + R2 — see wrangler.jsonc / src/worker.ts).
|
|
@@ -26,16 +36,49 @@ export default defineConfig({
|
|
|
26
36
|
emdash({
|
|
27
37
|
database,
|
|
28
38
|
storage,
|
|
29
|
-
// Vitops design-system blocks (image compare, copy snippet,
|
|
30
|
-
// disclosure,
|
|
39
|
+
// Vitops design-system blocks (link/button, image compare, copy snippet,
|
|
40
|
+
// banner, disclosure, accordion, hero, carousel, gallery, cards, marquee) in the
|
|
41
|
+
// editor slash menu. Narrow them with `vitopsEmdash({ blocks: { exclude } })`. Default 'integration'
|
|
31
42
|
// script delivery: Layout.astro renders <Head /> from @getvitops/astro,
|
|
32
43
|
// which emits the web-component runtime tags.
|
|
33
|
-
|
|
44
|
+
//
|
|
45
|
+
// designSystemEditor mounts a live <wc-theme-editor> admin page at
|
|
46
|
+
// /design-system — edits are visible site-wide immediately (no
|
|
47
|
+
// rebuild) and auto-sync back to source once site.deployment.repo and
|
|
48
|
+
// a VITOPS_GITHUB_TOKEN secret are set (see SETUP.html) — see
|
|
49
|
+
// AGENTS.md's "EmDash plugin as the design-system editing surface".
|
|
50
|
+
// Until then the live half still works; only the sync half is skipped.
|
|
51
|
+
//
|
|
52
|
+
// cloudflareEmail sends magic-link sign-in, invites and account recovery
|
|
53
|
+
// through Cloudflare Email Sending (the EMAIL binding in wrangler.jsonc).
|
|
54
|
+
// Magic link is how an editor gets into a site whose database was copied
|
|
55
|
+
// from another origin: a passkey only works at the origin it was
|
|
56
|
+
// registered on, so a dev database refreshed from prod
|
|
57
|
+
// (scripts/refresh-dev.mjs) would otherwise lock everyone out of dev. The
|
|
58
|
+
// cloned users already exist, so the same email signs in on both origins.
|
|
59
|
+
// `from` must be on a domain onboarded with Cloudflare Email Sending —
|
|
60
|
+
// `npx vitops email setup send.<your-domain>` — and is usually the
|
|
61
|
+
// subdomain, not the apex (see AGENTS.md's "Sender-domain onboarding").
|
|
62
|
+
// Without it, magic link answers "Email is not configured".
|
|
63
|
+
plugins: [
|
|
64
|
+
vitopsEmdash({ designSystemEditor: { config } }),
|
|
65
|
+
cloudflareEmail({
|
|
66
|
+
from: { email: 'cms@send.my-emdash-site.example.com', name: organizationName },
|
|
67
|
+
}),
|
|
68
|
+
],
|
|
69
|
+
// 1.0's runtime migration mode defaults to 'auto' (apply pending core
|
|
70
|
+
// migrations on first request) — fine for local dev, but a deploy
|
|
71
|
+
// should have already migrated before traffic arrives. 'check' 503s a
|
|
72
|
+
// request instead of migrating behind it if the explicit `emdash
|
|
73
|
+
// migrate` step in site-deploy-emdash.yml (see AGENTS.md's CI/CD
|
|
74
|
+
// section) was skipped or failed. `dev: 'auto'` keeps the convenient
|
|
75
|
+
// first-run behaviour for `pnpm dev`.
|
|
76
|
+
migrations: { runtime: 'check', dev: 'auto' },
|
|
34
77
|
}),
|
|
35
78
|
vitops({
|
|
36
79
|
favicon: {
|
|
37
80
|
source: 'src/assets/logo.svg',
|
|
38
|
-
name:
|
|
81
|
+
name: organizationName,
|
|
39
82
|
themeColor: '#2e9b73',
|
|
40
83
|
backgroundColor: '#ffffff',
|
|
41
84
|
},
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
"dev": "astro dev",
|
|
8
8
|
"build": "astro build",
|
|
9
9
|
"preview": "astro preview",
|
|
10
|
-
"deploy": "astro build && wrangler deploy",
|
|
11
|
-
"deploy:dev": "astro build && node scripts/build-dev-wrangler.mjs && wrangler deploy --config dist/server/wrangler.dev.json",
|
|
10
|
+
"deploy": "vitops email check && astro build && emdash migrate --wrangler-config wrangler.jsonc && wrangler deploy",
|
|
11
|
+
"deploy:dev": "vitops email check && astro build && node scripts/build-dev-wrangler.mjs && emdash migrate --wrangler-config dist/server/wrangler.dev.json && wrangler deploy --config dist/server/wrangler.dev.json",
|
|
12
12
|
"init:github": "vitops setup repo",
|
|
13
13
|
"init:hosting": "vitops setup hosting",
|
|
14
14
|
"setup": "vitops setup all",
|
|
@@ -20,19 +20,23 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@astrojs/cloudflare": "^14.0.0",
|
|
23
|
-
"@astrojs/react": "^
|
|
24
|
-
"@emdash-cms/cloudflare": "^
|
|
23
|
+
"@astrojs/react": "^7.1.2",
|
|
24
|
+
"@emdash-cms/cloudflare": "^1.4.0",
|
|
25
25
|
"@getvitops/astro": "latest",
|
|
26
|
+
"@getvitops/core": "latest",
|
|
26
27
|
"@getvitops/emdash": "latest",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"react
|
|
28
|
+
"@tailwindcss/vite": "^4.3.3",
|
|
29
|
+
"astro": "^7.4.4",
|
|
30
|
+
"emdash": "^1.4.0",
|
|
31
|
+
"react": "^19.3.1",
|
|
32
|
+
"react-dom": "^19.3.1",
|
|
33
|
+
"tailwindcss": "^4.3.3"
|
|
31
34
|
},
|
|
32
35
|
"devDependencies": {
|
|
33
|
-
"@astrojs/check": "^0.9.
|
|
36
|
+
"@astrojs/check": "^0.9.12",
|
|
34
37
|
"@cloudflare/workers-types": "^4.20260305.1",
|
|
35
38
|
"@getvitops/cli": "latest",
|
|
39
|
+
"@iconify-json/fa7-solid": "^1.2.5",
|
|
36
40
|
"typescript": "^6.0.3",
|
|
37
41
|
"vite": "latest",
|
|
38
42
|
"vite-plus": "latest",
|
|
@@ -41,11 +45,11 @@
|
|
|
41
45
|
"devEngines": {
|
|
42
46
|
"runtime": {
|
|
43
47
|
"name": "node",
|
|
44
|
-
"version": "24
|
|
48
|
+
"version": "24",
|
|
45
49
|
"onFail": "download"
|
|
46
50
|
}
|
|
47
51
|
},
|
|
48
|
-
"packageManager": "pnpm@
|
|
52
|
+
"packageManager": "pnpm@12.16.1",
|
|
49
53
|
"emdash": {
|
|
50
54
|
"seed": "seed/seed.json"
|
|
51
55
|
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
lockfileVersion: '9.0'
|
|
3
|
+
|
|
4
|
+
importers:
|
|
5
|
+
|
|
6
|
+
.:
|
|
7
|
+
configDependencies: {}
|
|
8
|
+
packageManagerDependencies:
|
|
9
|
+
'@pnpm/exe':
|
|
10
|
+
specifier: 12.16.1
|
|
11
|
+
version: 12.16.1
|
|
12
|
+
pnpm:
|
|
13
|
+
specifier: 12.16.1
|
|
14
|
+
version: 12.16.1
|
|
15
|
+
|
|
16
|
+
packages:
|
|
17
|
+
|
|
18
|
+
'@pnpm/exe.android-arm64@12.16.1':
|
|
19
|
+
resolution: {integrity: sha512-PKf78Ew+i0CBYf0Xc+eMcqQiqyBT+u8XCVg1F5roc98/6wWfdYlWhrUMmEBiKWaJ3JqHxrtt8l1NwZ7qfJt2/Q==}
|
|
20
|
+
cpu: [arm64]
|
|
21
|
+
os: [android]
|
|
22
|
+
|
|
23
|
+
'@pnpm/exe.android-x64@12.16.1':
|
|
24
|
+
resolution: {integrity: sha512-xdu7gMbB98pdvhwMeA6612Of515FDlRUtfA/1f7nWPZfPLnEdSRBO2u+1N0XBtQ/ennhPH/lrxB1gC6gnR/cdg==}
|
|
25
|
+
cpu: [x64]
|
|
26
|
+
os: [android]
|
|
27
|
+
|
|
28
|
+
'@pnpm/exe.darwin-arm64@12.16.1':
|
|
29
|
+
resolution: {integrity: sha512-pVbmIIbhixiLvADLu1WA3TaW8FZy/D72R1De27WbbFx8/2mxvnsTyFVm4fO9kjpjMY7RzJd48CiQ96p8fO3ebQ==}
|
|
30
|
+
cpu: [arm64]
|
|
31
|
+
os: [darwin]
|
|
32
|
+
|
|
33
|
+
'@pnpm/exe.darwin-x64@12.16.1':
|
|
34
|
+
resolution: {integrity: sha512-xZvQBFqcZjO7vFKTK3XsJpqY6lnBL9EWSLCzVUPq3kZ94+D96gwJCa76xxGNK8Cj32f4eeM91Qg+yNRR4sRpDw==}
|
|
35
|
+
cpu: [x64]
|
|
36
|
+
os: [darwin]
|
|
37
|
+
|
|
38
|
+
'@pnpm/exe.freebsd-x64@12.16.1':
|
|
39
|
+
resolution: {integrity: sha512-zTtunfi9mBhRXiXEJYfwiJj0tk7MgTSfqDSRh+Az9FZ9THazVIiQiVNS8jpcsftDOqu7LKNffQdjmgwHDThfUg==}
|
|
40
|
+
cpu: [x64]
|
|
41
|
+
os: [freebsd]
|
|
42
|
+
|
|
43
|
+
'@pnpm/exe.linux-arm64-musl@12.16.1':
|
|
44
|
+
resolution: {integrity: sha512-BJ3mOmcmQgcUo92Ee/WfEOt1pRiv3y2MMAkhEiYHd85UiPpHTfFhv+SpCbALmfExzXk3UlaRtMYwHlkQymc4VA==}
|
|
45
|
+
cpu: [arm64]
|
|
46
|
+
os: [linux]
|
|
47
|
+
libc: [musl]
|
|
48
|
+
|
|
49
|
+
'@pnpm/exe.linux-arm64@12.16.1':
|
|
50
|
+
resolution: {integrity: sha512-JaRd5gNxwdNGBBkrZFt8bknrK4YmHVJBW0JMhUQ0fJ0dEYp6C2GT9ExaCqOO8EwYEyqM+jpKgJIK+8WFaJy3ew==}
|
|
51
|
+
cpu: [arm64]
|
|
52
|
+
os: [linux]
|
|
53
|
+
libc: [glibc]
|
|
54
|
+
|
|
55
|
+
'@pnpm/exe.linux-ppc64@12.16.1':
|
|
56
|
+
resolution: {integrity: sha512-FnSV0Jv40S1cMv7vFNWwvu0X567Lec4L4HCRead3CFcD6zQDNbGw81s8N5bcKPahtPD9ApVuhsbmFCx4rw6RMw==}
|
|
57
|
+
cpu: [ppc64]
|
|
58
|
+
os: [linux]
|
|
59
|
+
libc: [glibc]
|
|
60
|
+
|
|
61
|
+
'@pnpm/exe.linux-riscv64@12.16.1':
|
|
62
|
+
resolution: {integrity: sha512-C1Sww4FN5IttD4atRRhAKmQtSGWVp04ZAKNxO8pfu2bkRPwOW+7v+2DH1Xs1W+kZYYpO86BYDvUcadefF+AgaQ==}
|
|
63
|
+
cpu: [riscv64]
|
|
64
|
+
os: [linux]
|
|
65
|
+
libc: [glibc]
|
|
66
|
+
|
|
67
|
+
'@pnpm/exe.linux-s390x@12.16.1':
|
|
68
|
+
resolution: {integrity: sha512-kn2fautsTcxIMODoovQVqZyfpDRdNgGkoeVqNdrKqbeBBvrEl+fXLkmZiq5xDht1LMr4sYiCNcsMfNMT6JPFmg==}
|
|
69
|
+
cpu: [s390x]
|
|
70
|
+
os: [linux]
|
|
71
|
+
libc: [glibc]
|
|
72
|
+
|
|
73
|
+
'@pnpm/exe.linux-x64-musl@12.16.1':
|
|
74
|
+
resolution: {integrity: sha512-PM6ccHCOe/O9SsTflTJTYWfwogJZa6EmUvpnwZgiPguJBddh20wDQKgxUPXf48rDsPm9vMsIij0uHswwwbXL8g==}
|
|
75
|
+
cpu: [x64]
|
|
76
|
+
os: [linux]
|
|
77
|
+
libc: [musl]
|
|
78
|
+
|
|
79
|
+
'@pnpm/exe.linux-x64@12.16.1':
|
|
80
|
+
resolution: {integrity: sha512-RK//8ZLcXGW8A2k8bQOXZDBN1Qu92zN4dYnG1bzj1zoQ1fkZ6jNzZ1AvXtsfGVma795CJtvoaF5bLXf4l/FIUw==}
|
|
81
|
+
cpu: [x64]
|
|
82
|
+
os: [linux]
|
|
83
|
+
libc: [glibc]
|
|
84
|
+
|
|
85
|
+
'@pnpm/exe.win32-arm64@12.16.1':
|
|
86
|
+
resolution: {integrity: sha512-Ox3kNNVxtGw6pK7SVejmeOUgHhUTZgAM7NQQ6cU7frPw3ix9+j7d2MGbRg3fyEFAaKWq8ZAZLTQGcDyLnAu+qA==}
|
|
87
|
+
cpu: [arm64]
|
|
88
|
+
os: [win32]
|
|
89
|
+
|
|
90
|
+
'@pnpm/exe.win32-x64@12.16.1':
|
|
91
|
+
resolution: {integrity: sha512-k+FhRJ0ttphFoFIVB1Sk4v76YJAulafmA/Ly57cysesUhhIzVlApeOShUz0jXubKx317TThlEfpQrukldnqORA==}
|
|
92
|
+
cpu: [x64]
|
|
93
|
+
os: [win32]
|
|
94
|
+
|
|
95
|
+
'@pnpm/exe@12.16.1':
|
|
96
|
+
resolution: {integrity: sha512-Opsh2R7IuFY3ekd0C282Tmzgr5hiSlKMOv05/3dJXUrrp5NbmjC1Cm5PCFsa8xsiXY7z4oSkI4Qof1LjTkgAJg==}
|
|
97
|
+
engines: {node: '>=18'}
|
|
98
|
+
hasBin: true
|
|
99
|
+
|
|
100
|
+
pnpm@12.16.1:
|
|
101
|
+
resolution: {integrity: sha512-CR0d7nknV1Zhsl2rPCrjHK/BxU1rce1qZgDPDByxBDSkR+rhQBXxsj4ua+3u1535SpMuIWTSgyKA3OP7MvZW0Q==}
|
|
102
|
+
engines: {node: '>=18'}
|
|
103
|
+
hasBin: true
|
|
104
|
+
|
|
105
|
+
snapshots:
|
|
106
|
+
|
|
107
|
+
'@pnpm/exe.android-arm64@12.16.1':
|
|
108
|
+
optional: true
|
|
109
|
+
|
|
110
|
+
'@pnpm/exe.android-x64@12.16.1':
|
|
111
|
+
optional: true
|
|
112
|
+
|
|
113
|
+
'@pnpm/exe.darwin-arm64@12.16.1':
|
|
114
|
+
optional: true
|
|
115
|
+
|
|
116
|
+
'@pnpm/exe.darwin-x64@12.16.1':
|
|
117
|
+
optional: true
|
|
118
|
+
|
|
119
|
+
'@pnpm/exe.freebsd-x64@12.16.1':
|
|
120
|
+
optional: true
|
|
121
|
+
|
|
122
|
+
'@pnpm/exe.linux-arm64-musl@12.16.1':
|
|
123
|
+
optional: true
|
|
124
|
+
|
|
125
|
+
'@pnpm/exe.linux-arm64@12.16.1':
|
|
126
|
+
optional: true
|
|
127
|
+
|
|
128
|
+
'@pnpm/exe.linux-ppc64@12.16.1':
|
|
129
|
+
optional: true
|
|
130
|
+
|
|
131
|
+
'@pnpm/exe.linux-riscv64@12.16.1':
|
|
132
|
+
optional: true
|
|
133
|
+
|
|
134
|
+
'@pnpm/exe.linux-s390x@12.16.1':
|
|
135
|
+
optional: true
|
|
136
|
+
|
|
137
|
+
'@pnpm/exe.linux-x64-musl@12.16.1':
|
|
138
|
+
optional: true
|
|
139
|
+
|
|
140
|
+
'@pnpm/exe.linux-x64@12.16.1':
|
|
141
|
+
optional: true
|
|
142
|
+
|
|
143
|
+
'@pnpm/exe.win32-arm64@12.16.1':
|
|
144
|
+
optional: true
|
|
145
|
+
|
|
146
|
+
'@pnpm/exe.win32-x64@12.16.1':
|
|
147
|
+
optional: true
|
|
148
|
+
|
|
149
|
+
'@pnpm/exe@12.16.1':
|
|
150
|
+
optionalDependencies:
|
|
151
|
+
'@pnpm/exe.android-arm64': 12.16.1
|
|
152
|
+
'@pnpm/exe.android-x64': 12.16.1
|
|
153
|
+
'@pnpm/exe.darwin-arm64': 12.16.1
|
|
154
|
+
'@pnpm/exe.darwin-x64': 12.16.1
|
|
155
|
+
'@pnpm/exe.freebsd-x64': 12.16.1
|
|
156
|
+
'@pnpm/exe.linux-arm64': 12.16.1
|
|
157
|
+
'@pnpm/exe.linux-arm64-musl': 12.16.1
|
|
158
|
+
'@pnpm/exe.linux-ppc64': 12.16.1
|
|
159
|
+
'@pnpm/exe.linux-riscv64': 12.16.1
|
|
160
|
+
'@pnpm/exe.linux-s390x': 12.16.1
|
|
161
|
+
'@pnpm/exe.linux-x64': 12.16.1
|
|
162
|
+
'@pnpm/exe.linux-x64-musl': 12.16.1
|
|
163
|
+
'@pnpm/exe.win32-arm64': 12.16.1
|
|
164
|
+
'@pnpm/exe.win32-x64': 12.16.1
|
|
165
|
+
|
|
166
|
+
pnpm@12.16.1:
|
|
167
|
+
optionalDependencies:
|
|
168
|
+
'@pnpm/exe.android-arm64': 12.16.1
|
|
169
|
+
'@pnpm/exe.android-x64': 12.16.1
|
|
170
|
+
'@pnpm/exe.darwin-arm64': 12.16.1
|
|
171
|
+
'@pnpm/exe.darwin-x64': 12.16.1
|
|
172
|
+
'@pnpm/exe.freebsd-x64': 12.16.1
|
|
173
|
+
'@pnpm/exe.linux-arm64': 12.16.1
|
|
174
|
+
'@pnpm/exe.linux-arm64-musl': 12.16.1
|
|
175
|
+
'@pnpm/exe.linux-ppc64': 12.16.1
|
|
176
|
+
'@pnpm/exe.linux-riscv64': 12.16.1
|
|
177
|
+
'@pnpm/exe.linux-s390x': 12.16.1
|
|
178
|
+
'@pnpm/exe.linux-x64': 12.16.1
|
|
179
|
+
'@pnpm/exe.linux-x64-musl': 12.16.1
|
|
180
|
+
'@pnpm/exe.win32-arm64': 12.16.1
|
|
181
|
+
'@pnpm/exe.win32-x64': 12.16.1
|
|
182
|
+
|
|
183
|
+
---
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Cloudflare Workers static assets apply this file to every asset response.
|
|
2
|
+
#
|
|
3
|
+
# A baseline that cannot break a page. No Content-Security-Policy on purpose: <Head /> emits
|
|
4
|
+
# inline scripts (the consent stub, the colour-scheme bootstrap), so a strict policy needs
|
|
5
|
+
# per-site nonces or hashes — add one deliberately once you know which third-party tags you load.
|
|
6
|
+
/*
|
|
7
|
+
X-Content-Type-Options: nosniff
|
|
8
|
+
Referrer-Policy: strict-origin-when-cross-origin
|
|
9
|
+
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
|
|
10
|
+
X-Frame-Options: SAMEORIGIN
|
|
@@ -66,6 +66,12 @@ cfg.r2_buckets = (cfg.r2_buckets ?? []).map((r) =>
|
|
|
66
66
|
r.binding === 'MEDIA' ? { ...r, bucket_name: `${r.bucket_name}-dev` } : r,
|
|
67
67
|
);
|
|
68
68
|
|
|
69
|
+
// No cron on dev. Dev's database is a copy of prod (scripts/refresh-dev.mjs),
|
|
70
|
+
// so it carries prod's scheduled publishes and plugin jobs; leaving the trigger
|
|
71
|
+
// on would run them a second time against the copy. The cost: scheduled
|
|
72
|
+
// publishing can't be exercised on dev.
|
|
73
|
+
delete cfg.triggers;
|
|
74
|
+
|
|
69
75
|
// Flat config — no nested environments.
|
|
70
76
|
delete cfg.env;
|
|
71
77
|
|