@getvitops/emdash 0.3.10 → 1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,333 @@
1
1
  # @getvitops/emdash
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - c3c1bcb: **New: the design-system editor, mounted inside the EmDash admin.** `vitopsEmdash({
8
+ designSystemEditor: { config } })` (`config` is your `site.json`, e.g. `import config from
9
+ './site.json' with { type: 'json' }`) adds a `/design-system` admin page mounting
10
+ `<wc-theme-editor>` — the same live token editor `@getvitops/vite`'s dev server has always
11
+ offered, now usable by the client directly, no dev server required. An edit is visible
12
+ site-wide immediately (a runtime `:root` override, served via a new plugin API route and
13
+ `page:fragments`) and — once `site.deployment.repo`/`branch` and a `VITOPS_GITHUB_TOKEN`
14
+ secret are set (see the scaffold's `SETUP.html`) — auto-commits to your `dev` branch, so it
15
+ reaches the git-tracked `site.json` through your repo's normal review path rather than
16
+ becoming a second, unreviewed source of truth. Until that's configured, the live half still
17
+ works; only the auto-commit half is skipped (and says so in the admin page). The save route
18
+ runs the exact same accessibility (APCA contrast) gate `generate()` enforces at build time,
19
+ synchronously, before persisting — nothing non-compliant ever goes live even momentarily.
20
+
21
+ Requires `@astrojs/react` + `react` + `react-dom` (already scaffold dependencies, for
22
+ EmDash's own admin) and `@getvitops/core` (added as a new scaffold dependency this release).
23
+ Declares two new plugin capabilities when enabled: `network:request` (for the GitHub
24
+ auto-commit) and `hooks.page-fragments:register` (for the live override) — reviewed once at
25
+ plugin-install time.
26
+
27
+ **Breaking for `@getvitops/emdash`**: `vitopsEmdash()`'s `hooks.page-fragments:register`
28
+ capability is now also granted whenever `designSystemEditor` is set, independent of the
29
+ existing `scripts: 'fragments'` option (which governs something unrelated — web-component
30
+ script delivery). No change if you don't use `designSystemEditor`.
31
+
32
+ Also new, supporting the above:
33
+
34
+ - `@getvitops/generator`: `validateColorContract()` and `buildReverseIndex()` (both
35
+ `/tokens` subpath, Worker-safe) — the monotonicity/contrast gate and the
36
+ `design-manifest.json` reverse-index, each extracted from `generate()`'s `build()` into
37
+ standalone, non-throwing functions. `patchToOverrideCss()` turns a design-system patch
38
+ into the `:root` override `<style>` block. `designSystemPath`/`getAt`/`setAt`/
39
+ `mergePatch`/`formatConfig` moved from `@getvitops/vite` into `@getvitops/generator/config`
40
+ (re-exported from `@getvitops/vite` unchanged) — one "patch a config file's design-system
41
+ subtree" implementation shared by the dev endpoint and the new plugin route. New
42
+ `site.deployment.repo`/`branch` config fields.
43
+ - `@getvitops/utils`: new `/git` subpath — `commitFile()`, a Worker-safe (fetch-only)
44
+ wrapper over GitHub's Contents API.
45
+ - `@getvitops/core`: `<wc-theme-editor>` gains a `save-endpoint` attribute (default
46
+ unchanged — `/__vitops/design-system`) so the same element can target the new plugin
47
+ route instead of the dev-only Vite endpoint.
48
+
49
+ - 0574388: Bump `emdash`/`@emdash-cms/cloudflare` peers to `>=1.0.0 <2` and `vite-plus` to `^1.0.0`, following
50
+ both projects' GA releases.
51
+
52
+ **Breaking for `@getvitops/emdash` consumers on EmDash 0.x**: the peer range no longer admits
53
+ `emdash@0.31.x`/`@emdash-cms/cloudflare@0.31.x`. Upgrade `emdash` and `@emdash-cms/cloudflare` to
54
+ `^1.0.1` first — nothing in `@getvitops/emdash`'s own plugin surface (`admin.portableTextBlocks`,
55
+ the `hooks.page-fragments:register` capability, `definePlugin()`) changed against EmDash 1.0, so no
56
+ code here needed to change, only the declared range.
57
+
58
+ The `emdash` scaffold template (`vp create @getvitops:emdash`) picks up several fixes alongside
59
+ the version bump:
60
+
61
+ - `tailwindcss`/`@tailwindcss/vite` are now real dependencies — the template selected
62
+ `css.format: 'tailwind'` without installing either, which threw on build.
63
+ - `site.json` now sets `site.icons.sprite: true` plus the full `semantic` list the
64
+ `vitops.actionLink` block's icon picker offers — previously its sprite icons pointed at a file
65
+ the build never generated.
66
+ - `astro.config.mjs` sets `migrations: { runtime: 'check', dev: 'auto' }`, and
67
+ `site-deploy-emdash.yml` runs EmDash 1.0's documented `build → status → apply → deploy → check`
68
+ migration sequence explicitly, rather than relying solely on first-request auto-migration. This
69
+ needs a new GitHub Environment variable, `EMDASH_TARGET_FINGERPRINT` (one per environment),
70
+ which only a human can set — run `emdash migrate --status` against the real deployed database,
71
+ review the printed identity, then `gh variable set EMDASH_TARGET_FINGERPRINT --env <env> --body
72
+ <value>`. Deploys fail clearly on the migration-apply step until it's set.
73
+ - `lint.options.typeAware`/`typeCheck` in the template's own `vite.config.ts` are commented out,
74
+ not deleted: vite-plus 1.0 only honours that option in a project's actual root config, and hard
75
+ errors on it in a nested one (which this file is, sitting inside the `design-system` monorepo).
76
+ Uncomment it once scaffolded into its own repo.
77
+
78
+ No config schema changes. `@getvitops/generator` also switches from the `zod/mini` subpath import
79
+ to the standalone `@zod/mini` package (zod 4.5+; same API) and fixes `validateConfig()` silently
80
+ losing the offending key name on an `unrecognized_keys` error (e.g. a typo'd `site.ads` platform
81
+ now names the bad key instead of reporting a bare "Invalid input").
82
+
83
+ Also fixed: `vp check`'s `tsconfig-error` for `packages/create/templates/emdash/tsconfig.json`
84
+ (`extends: "astro/tsconfigs/strict"`, unresolvable from inside this monorepo since the template
85
+ has no `node_modules` of its own — a pre-existing, structural gap, newly surfaced as a hard error
86
+ by oxlint 1.85's deeper config discovery, and blocking on every commit since this repo's pre-commit
87
+ hook runs `vp check --fix`). Fixed with a new `scripts/link-template-deps.mjs`, wired as the root
88
+ `postinstall` script: symlinks `astro`/`emdash`/`@emdash-cms/cloudflare` into the template's own
89
+ `node_modules/` (resolved fresh from sibling packages that already depend on them for real, not a
90
+ hardcoded `.pnpm` hash) and writes a minimal `astro:content` ambient shim at `.astro/types.d.ts`
91
+ (the same path `astro sync` would generate for real). Both are gitignored and only ever exist
92
+ inside this monorepo's copy of the template — a real scaffold installs its own real copies instead.
93
+ Considered and rejected first: inlining astro's strict preset (drift risk against astro's own
94
+ evolving default) and making the template a real pnpm workspace member (would change how its
95
+ `@getvitops/*: "latest"` deps resolve locally, which `templates.test.ts` exists to protect).
96
+
97
+ **Known gap, not fixed here**: `packages/astro/src/components/container.test.ts` (the
98
+ `AstroContainer`-based render tests) fails to even load under vite-plus 1.0's Vite 8 — direct
99
+ `.astro` imports in a Vitest file need the Astro Vite plugin registered, which nothing in this
100
+ repo's test config actually does (Astro's own docs call for `getViteConfig()`, which doesn't
101
+ compose with vite-plus's own `defineConfig`). A type-level shim
102
+ (`packages/astro/src/components/astro-modules.d.ts`) fixes `vp check`'s type-aware pass, but the
103
+ runtime `vp test` failure for this one file is still open.
104
+
105
+ ### Minor Changes
106
+
107
+ - b3d9c07: `vitops docs blocks` prints every EmDash block type and its fields, so an agent can write valid Portable Text without reading the plugin source. It reads `@getvitops/emdash` from the project (and says so if it isn't installed); `@getvitops/emdash` exports `renderBlocksDoc()` for it.
108
+ - 2ef2d41: **Tested against EmDash 1.4.** `emdash` and `@emdash-cms/cloudflare` are now `^1.4.0` in the
109
+ `emdash` template, and `@getvitops/emdash`'s peer ranges for both moved from `>=1.0.0 <2` to
110
+ `>=1.3.0 <2` — **breaking for a site still on EmDash 1.0–1.2**: upgrade `emdash` and
111
+ `@emdash-cms/cloudflare` together (EmDash warns at build when the two differ) before upgrading
112
+ this package. 1.4 fixes a stored XSS in the visual-editing toolbar (an author's published content
113
+ could run script for a signed-in editor), so an existing client site should take it promptly.
114
+
115
+ - **`vitopsHosting()` coalesces D1 reads by default** — new `cloudflare.coalesce` option
116
+ (default `true`, passed to `d1({ coalesce })`). With `session: 'auto'`, EmDash 1.3 stops
117
+ preloading settings/menus/widgets for logged-out visitors unless reads are coalesced, so this
118
+ restores one round trip instead of several. It is experimental upstream: a read and a write
119
+ started together may run write-first, so `await` a read before a write that must not affect it.
120
+ Set `coalesce: false` to opt out. No effect without a session.
121
+ - **Template:** `AGENTS.md` gains an "EmDash 1.x behaviours" section (passkeys are bound to a
122
+ hostname so use _Change domain_ at cutover; admin-authored HTML blocks run JS and conflict with
123
+ Astro CSP; link by `entry.data.slug`, not `entry.id`; submit `/sitemap.xml`; clearing a stuck D1
124
+ lock with `emdash migrate --take-over-lock`).
125
+ - **Upstream behaviour changes to know about (no code change here):** `cacheHint.lastModified` is
126
+ no longer auto-populated and pages lose the implicit `Cache-Control: no-cache`; collection
127
+ sitemaps paginate at 2,000 entries; `entry.id` is always locale-prefixed on multilingual sites.
128
+
129
+ No consumer-facing change in `@getvitops/core`, `@getvitops/generator`, `@getvitops/utils`,
130
+ `@getvitops/cli` or `@getvitops/vite`. `@getvitops/astro` has one — see the scaffold changeset.
131
+
132
+ - 1a8231d: **EmDash blocks are now a tier of the component manifest, and there are four more of them.**
133
+
134
+ `@getvitops/emdash` adds `vitops.gallery`, `vitops.cards`, `vitops.accordion` and `vitops.marquee`
135
+ (each a thin adapter over the matching `@getvitops/astro` component), and `vitops.carousel` now edits
136
+ its slides as a **Slides repeater** instead of two newline-separated fields. Blocks saved before this
137
+ keep rendering: with no `slides`, the carousel still reads `images`/`alts`, and both legacy fields stay
138
+ in the editor, labelled as legacy. The editor's field type now admits `repeater` and `media_picker`.
139
+
140
+ - **New `blocks` plugin option** — `vitopsEmdash({ blocks: { include, exclude, extra } })`. `include` is
141
+ an allowlist, `exclude` drops blocks, `extra` adds the site's own **editor** definitions (the site
142
+ supplies their renderers via `<PortableText components={{ type }}>`, the same route that overrides a
143
+ `vitops.*` renderer). An unknown name or a colliding `type` throws at plugin construction.
144
+ - Link and image URLs in blocks with a scheme other than `http`, `https`, `mailto` or `tel` are
145
+ dropped (see the security entry).
146
+
147
+ `@getvitops/generator`: `TierEntry` gains an optional `emdash: string[]` (block `_type`s) and `Tier`
148
+ gains `'emdash'`, so `tierPatterns('emdash')` projects it. **Breaking only for code that exhaustively
149
+ switches on `Tier` or builds a `Record<Tier, …>`** — add an `emdash` case. The agent doc
150
+ `vitops docs components` gains an "EmDash blocks" table and the docsite a `components/emdash` page. The
151
+ guard that every block and every `emdash` entry agree lives in `@getvitops/emdash`'s `blocks.test.ts`,
152
+ because the generator cannot import the plugin.
153
+
154
+ `@getvitops/create`: the EmDash template's agent guidance explains the blocks, their limits (a block
155
+ cannot contain blocks; `vitops.*` blocks do not render inside EmDash's built-in `columns`) and the
156
+ `blocks` option.
157
+
158
+ Formats reached: none — no CSS change. Other packages in the `fixed` group: No consumer-facing change
159
+ in this package.
160
+
161
+ - 779d22e: Add a `vitops.hero` EmDash block (eyebrow, heading, text, two links, optional image; centered or split layout) built on the `.centered`/`.split` layout primitives. The EmDash template's home page now seeds one of each of hero, cards, accordion and marquee. `@getvitops/generator`: the `split` pattern lists the new block in `TIERS`.
162
+
163
+ ### Patch Changes
164
+
165
+ - 734ab60: EmDash gallery and carousel blocks now derive their element id from the block's `_key`, so two blocks with the same label on one page no longer open each other's dialog. `<wc-entries>` column navigation now honours `prefers-reduced-motion`.
166
+ - 7f4f50e: `@getvitops/utils/url` exports `safeHref()` (a Worker-safe scheme allowlist: http, https, mailto, tel and relative), shared by the EmDash blocks and the Astro components. It now also guards the EmDash image-compare block, the review avatar and the cookie-notice policy link. `nodesToHtml`/`toHtml` throw on invalid tag or attribute names and on `on*` event-handler attributes, and drop `href`/`src`-style values that fail `safeHref`. EmDash cards link text now names the card for screen readers.
167
+ - e5bc937: **Security: JSON-LD can no longer break out of its `<script>` tag.** All 24 `schemas/*.astro`
168
+ components inlined `JSON.stringify(jsonLd)` as-is, so a review, FAQ answer or forum post containing
169
+ `</script><script>…` ran as script on the page. They now go through `jsonLdScript()`, which escapes
170
+ `<`, `>`, `&`, U+2028 and U+2029 (still valid JSON — consumers and search engines parse the same
171
+ document). Sites rendering any user-supplied text through a schema component should upgrade promptly.
172
+
173
+ **`createConversionRoute()` hardening** — behaviour changes:
174
+
175
+ - The body-size cap is now enforced on the stream itself, not only on `Content-Length`; a chunked
176
+ request with no header is refused with 413 once it passes `maxBodyBytes`.
177
+ - **Breaking for non-Cloudflare hosts:** `X-Forwarded-For` is no longer used as the rate-limit key by
178
+ default, since off Cloudflare a client can set it freely and mint a new bucket per request. Pass
179
+ `trustForwardedFor: true` when running behind a proxy that overwrites it. Without
180
+ `CF-Connecting-IP` or that opt-in there is no IP and rate limiting is skipped. No change on
181
+ Cloudflare Workers.
182
+
183
+ `@getvitops/emdash`: the link/button block (`vitops.actionLink`) drops hrefs with a scheme other
184
+ than `http`, `https`, `mailto` or `tel` (e.g. `javascript:`, `data:`) and renders nothing for them.
185
+
186
+ Formats reached: none — no CSS change. Other packages in the `fixed` group: No consumer-facing
187
+ change in this package.
188
+
189
+ - Updated dependencies [65a13cc]
190
+ - Updated dependencies [67e2088]
191
+ - Updated dependencies [89265af]
192
+ - Updated dependencies [0574388]
193
+ - Updated dependencies [c3c1bcb]
194
+ - Updated dependencies [0574388]
195
+ - Updated dependencies [1a8231d]
196
+ - Updated dependencies [779d22e]
197
+ - Updated dependencies [0574388]
198
+ - Updated dependencies [8d8aad7]
199
+ - Updated dependencies [0574388]
200
+ - Updated dependencies [1a3e811]
201
+ - Updated dependencies [0574388]
202
+ - Updated dependencies [dde3df3]
203
+ - Updated dependencies [d9f213b]
204
+ - Updated dependencies [7f4f50e]
205
+ - Updated dependencies [7fd5f8f]
206
+ - Updated dependencies [ceb8310]
207
+ - @getvitops/generator@8.2.0
208
+ - @getvitops/utils@8.2.0
209
+
210
+ ## 1.0.0-alpha.0
211
+
212
+ ### Major Changes
213
+
214
+ - c3c1bcb: **New: the design-system editor, mounted inside the EmDash admin.** `vitopsEmdash({
215
+ designSystemEditor: { config } })` (`config` is your `site.json`, e.g. `import config from
216
+ './site.json' with { type: 'json' }`) adds a `/design-system` admin page mounting
217
+ `<wc-theme-editor>` — the same live token editor `@getvitops/vite`'s dev server has always
218
+ offered, now usable by the client directly, no dev server required. An edit is visible
219
+ site-wide immediately (a runtime `:root` override, served via a new plugin API route and
220
+ `page:fragments`) and — once `site.deployment.repo`/`branch` and a `VITOPS_GITHUB_TOKEN`
221
+ secret are set (see the scaffold's `SETUP.html`) — auto-commits to your `dev` branch, so it
222
+ reaches the git-tracked `site.json` through your repo's normal review path rather than
223
+ becoming a second, unreviewed source of truth. Until that's configured, the live half still
224
+ works; only the auto-commit half is skipped (and says so in the admin page). The save route
225
+ runs the exact same accessibility (APCA contrast) gate `generate()` enforces at build time,
226
+ synchronously, before persisting — nothing non-compliant ever goes live even momentarily.
227
+
228
+ Requires `@astrojs/react` + `react` + `react-dom` (already scaffold dependencies, for
229
+ EmDash's own admin) and `@getvitops/core` (added as a new scaffold dependency this release).
230
+ Declares two new plugin capabilities when enabled: `network:request` (for the GitHub
231
+ auto-commit) and `hooks.page-fragments:register` (for the live override) — reviewed once at
232
+ plugin-install time.
233
+
234
+ **Breaking for `@getvitops/emdash`**: `vitopsEmdash()`'s `hooks.page-fragments:register`
235
+ capability is now also granted whenever `designSystemEditor` is set, independent of the
236
+ existing `scripts: 'fragments'` option (which governs something unrelated — web-component
237
+ script delivery). No change if you don't use `designSystemEditor`.
238
+
239
+ Also new, supporting the above:
240
+ - `@getvitops/generator`: `validateColorContract()` and `buildReverseIndex()` (both
241
+ `/tokens` subpath, Worker-safe) — the monotonicity/contrast gate and the
242
+ `design-manifest.json` reverse-index, each extracted from `generate()`'s `build()` into
243
+ standalone, non-throwing functions. `patchToOverrideCss()` turns a design-system patch
244
+ into the `:root` override `<style>` block. `designSystemPath`/`getAt`/`setAt`/
245
+ `mergePatch`/`formatConfig` moved from `@getvitops/vite` into `@getvitops/generator/config`
246
+ (re-exported from `@getvitops/vite` unchanged) — one "patch a config file's design-system
247
+ subtree" implementation shared by the dev endpoint and the new plugin route. New
248
+ `site.deployment.repo`/`branch` config fields.
249
+ - `@getvitops/utils`: new `/git` subpath — `commitFile()`, a Worker-safe (fetch-only)
250
+ wrapper over GitHub's Contents API.
251
+ - `@getvitops/core`: `<wc-theme-editor>` gains a `save-endpoint` attribute (default
252
+ unchanged — `/__vitops/design-system`) so the same element can target the new plugin
253
+ route instead of the dev-only Vite endpoint.
254
+
255
+ - 0574388: Bump `emdash`/`@emdash-cms/cloudflare` peers to `>=1.0.0 <2` and `vite-plus` to `^1.0.0`, following
256
+ both projects' GA releases.
257
+
258
+ **Breaking for `@getvitops/emdash` consumers on EmDash 0.x**: the peer range no longer admits
259
+ `emdash@0.31.x`/`@emdash-cms/cloudflare@0.31.x`. Upgrade `emdash` and `@emdash-cms/cloudflare` to
260
+ `^1.0.1` first — nothing in `@getvitops/emdash`'s own plugin surface (`admin.portableTextBlocks`,
261
+ the `hooks.page-fragments:register` capability, `definePlugin()`) changed against EmDash 1.0, so no
262
+ code here needed to change, only the declared range.
263
+
264
+ The `emdash` scaffold template (`vp create @getvitops:emdash`) picks up several fixes alongside
265
+ the version bump:
266
+ - `tailwindcss`/`@tailwindcss/vite` are now real dependencies — the template selected
267
+ `css.format: 'tailwind'` without installing either, which threw on build.
268
+ - `site.json` now sets `site.icons.sprite: true` plus the full `semantic` list the
269
+ `vitops.actionLink` block's icon picker offers — previously its sprite icons pointed at a file
270
+ the build never generated.
271
+ - `astro.config.mjs` sets `migrations: { runtime: 'check', dev: 'auto' }`, and
272
+ `site-deploy-emdash.yml` runs EmDash 1.0's documented `build → status → apply → deploy → check`
273
+ migration sequence explicitly, rather than relying solely on first-request auto-migration. This
274
+ needs a new GitHub Environment variable, `EMDASH_TARGET_FINGERPRINT` (one per environment),
275
+ which only a human can set — run `emdash migrate --status` against the real deployed database,
276
+ review the printed identity, then `gh variable set EMDASH_TARGET_FINGERPRINT --env <env> --body
277
+ <value>`. Deploys fail clearly on the migration-apply step until it's set.
278
+ - `lint.options.typeAware`/`typeCheck` in the template's own `vite.config.ts` are commented out,
279
+ not deleted: vite-plus 1.0 only honours that option in a project's actual root config, and hard
280
+ errors on it in a nested one (which this file is, sitting inside the `design-system` monorepo).
281
+ Uncomment it once scaffolded into its own repo.
282
+
283
+ No config schema changes. `@getvitops/generator` also switches from the `zod/mini` subpath import
284
+ to the standalone `@zod/mini` package (zod 4.5+; same API) and fixes `validateConfig()` silently
285
+ losing the offending key name on an `unrecognized_keys` error (e.g. a typo'd `site.ads` platform
286
+ now names the bad key instead of reporting a bare "Invalid input").
287
+
288
+ Also fixed: `vp check`'s `tsconfig-error` for `packages/create/templates/emdash/tsconfig.json`
289
+ (`extends: "astro/tsconfigs/strict"`, unresolvable from inside this monorepo since the template
290
+ has no `node_modules` of its own — a pre-existing, structural gap, newly surfaced as a hard error
291
+ by oxlint 1.85's deeper config discovery, and blocking on every commit since this repo's pre-commit
292
+ hook runs `vp check --fix`). Fixed with a new `scripts/link-template-deps.mjs`, wired as the root
293
+ `postinstall` script: symlinks `astro`/`emdash`/`@emdash-cms/cloudflare` into the template's own
294
+ `node_modules/` (resolved fresh from sibling packages that already depend on them for real, not a
295
+ hardcoded `.pnpm` hash) and writes a minimal `astro:content` ambient shim at `.astro/types.d.ts`
296
+ (the same path `astro sync` would generate for real). Both are gitignored and only ever exist
297
+ inside this monorepo's copy of the template — a real scaffold installs its own real copies instead.
298
+ Considered and rejected first: inlining astro's strict preset (drift risk against astro's own
299
+ evolving default) and making the template a real pnpm workspace member (would change how its
300
+ `@getvitops/*: "latest"` deps resolve locally, which `templates.test.ts` exists to protect).
301
+
302
+ **Known gap, not fixed here**: `packages/astro/src/components/container.test.ts` (the
303
+ `AstroContainer`-based render tests) fails to even load under vite-plus 1.0's Vite 8 — direct
304
+ `.astro` imports in a Vitest file need the Astro Vite plugin registered, which nothing in this
305
+ repo's test config actually does (Astro's own docs call for `getViteConfig()`, which doesn't
306
+ compose with vite-plus's own `defineConfig`). A type-level shim
307
+ (`packages/astro/src/components/astro-modules.d.ts`) fixes `vp check`'s type-aware pass, but the
308
+ runtime `vp test` failure for this one file is still open.
309
+
310
+ ### Patch Changes
311
+
312
+ - Updated dependencies [65a13cc]
313
+ - Updated dependencies [67e2088]
314
+ - Updated dependencies [0574388]
315
+ - Updated dependencies [c3c1bcb]
316
+ - Updated dependencies [0574388]
317
+ - Updated dependencies [0574388]
318
+ - Updated dependencies [0574388]
319
+ - Updated dependencies [1a3e811]
320
+ - Updated dependencies [2a0a559]
321
+ - Updated dependencies [0574388]
322
+ - Updated dependencies [dde3df3]
323
+ - Updated dependencies [d9f213b]
324
+ - Updated dependencies [0f8c018]
325
+ - Updated dependencies [3bbb8c3]
326
+ - @getvitops/generator@8.2.0-alpha.0
327
+ - @getvitops/astro@8.2.0-alpha.0
328
+ - @getvitops/utils@8.2.0-alpha.0
329
+ - @getvitops/core@8.2.0-alpha.0
330
+
3
331
  ## 0.3.10
4
332
 
5
333
  ### Patch Changes
package/README.md CHANGED
@@ -36,7 +36,7 @@ export default defineConfig({
36
36
  });
37
37
  ```
38
38
 
39
- Tested against `emdash@0.31.x`.
39
+ Tested against `emdash@1.4.x`.
40
40
 
41
41
  ## Rendering mode
42
42
 
@@ -125,18 +125,60 @@ export default defineConfig({
125
125
  in the database (D1 export / EmDash seed round-trip), media in the storage
126
126
  backend (bucket/directory copy). Both directions work.
127
127
 
128
- ## Editor blocks (v1)
129
-
130
- | Slash-menu entry | `_type` | Renders |
131
- | ---------------- | --------------------- | ------------------------------------------- |
132
- | Image compare | `vitops.imageCompare` | `<wc-image-compare>` before/after slider |
133
- | Copy snippet | `vitops.copyButton` | `<wc-copy>` with code/inline fallback |
134
- | Banner | `vitops.banner` | `<wc-dismissable>` banner with tone colours |
135
- | Disclosure | `vitops.details` | native `<details>`/`<summary>` |
136
- | Carousel | `vitops.carousel` | `@getvitops/astro`'s `<Carousel />` |
128
+ ## Editor blocks
129
+
130
+ | Slash-menu entry | `_type` | Renders |
131
+ | ---------------- | --------------------- | ---------------------------------------------------------- |
132
+ | Link or button | `vitops.actionLink` | sprite-icon `<a>`, styled `.link`/`.btn`/`.cta` |
133
+ | Image compare | `vitops.imageCompare` | `<wc-image-compare>` before/after slider |
134
+ | Copy snippet | `vitops.copyButton` | `<wc-copy>` with code/inline fallback |
135
+ | Banner | `vitops.banner` | `<wc-dismissable>` banner with tone colours |
136
+ | Disclosure | `vitops.details` | native `<details>`/`<summary>` |
137
+ | Accordion | `vitops.accordion` | a group of `<details>`; optionally one-open-at-a-time |
138
+ | Carousel | `vitops.carousel` | `@getvitops/astro`'s `<Carousel />` over a Slides repeater |
139
+ | Gallery | `vitops.gallery` | `<Gallery />` — thumbnail grid opening a lightbox carousel |
140
+ | Cards | `vitops.cards` | `<Cards />` — a grid of `.card`s, whole-card click with JS |
141
+ | Marquee | `vitops.marquee` | `<Marquee />` — a continuously scrolling row |
137
142
 
138
143
  All blocks render accessible markup that works without JavaScript; the
139
- web components progressively enhance it.
144
+ web components progressively enhance it. Each is a thin adapter over the matching
145
+ `@getvitops/astro` component, so the markup exists once. `@getvitops/generator`'s `TIERS`
146
+ manifest lists which block renders which pattern (its `emdash` key, the `vitops docs components`
147
+ "EmDash blocks" table), and `blocks.test.ts` fails if a block and the manifest disagree.
148
+
149
+ Repeating data (cards, gallery images, accordion items, marquee items, carousel slides) is a
150
+ **repeater** field; images can be a media-library URL or any `http(s)`/relative URL. Link and image
151
+ URLs with any other scheme (`javascript:`, `data:`) are dropped at render time.
152
+
153
+ ### Choosing and extending the blocks
154
+
155
+ ```js
156
+ vitopsEmdash({
157
+ blocks: {
158
+ exclude: ['vitops.marquee'], // or `include: [...]` as an allowlist
159
+ extra: [
160
+ {
161
+ type: 'acme.pricing',
162
+ label: 'Pricing table',
163
+ fields: [/* Block Kit */],
164
+ },
165
+ ],
166
+ },
167
+ });
168
+ ```
169
+
170
+ `extra` adds **editor** definitions only. This plugin cannot render a block it has never heard of,
171
+ so the site maps each of its own types to a component, and can replace a `vitops.*` renderer the same way:
172
+
173
+ ```astro
174
+ <PortableText
175
+ value={page.data.content}
176
+ components={{ type: { 'acme.pricing': PricingTable, 'vitops.cards': MyCards } }}
177
+ />
178
+ ```
179
+
180
+ EmDash merges renderers as built-ins, then plugin `blockComponents`, then this `components` prop, so
181
+ the site's entry wins.
140
182
 
141
183
  ## Script delivery
142
184
 
@@ -153,17 +195,21 @@ loaded on pages that render these blocks. Pick **one**:
153
195
  Enabling both would load the scripts twice (harmless — element registration is
154
196
  guarded — but wasteful).
155
197
 
156
- ## Repeating structured patterns
198
+ ## Patterns that contain other blocks
199
+
200
+ A Portable Text block cannot hold other blocks — a repeater's rows are scalar fields. So a section
201
+ with columns, a hero, or a card holding a button is not a `vitops.*` block. Two routes:
202
+
203
+ - A **`blocks` field** (EmDash's typed page-composition field): define block types such as `hero` or
204
+ `split` in the seed, and map each to an Astro component built from `@getvitops/astro`
205
+ (`Subgrid`, `Cards`, the `.split` classes) with `defineBlockComponents`.
206
+ - **Sections** (`/section`): compose the pattern once as reusable content and let editors insert copies.
157
207
 
158
- EmDash's Portable Text block fields are flat, so patterns with repeating data
159
- (card grids, FAQ lists, spec tables via `wc-entries`, forms) are deliberately
160
- **not** v1 blocks. Use instead:
208
+ EmDash's built-in `columns` block renders its children with marks only, so a `vitops.*` block placed
209
+ inside one does not render. Use a `blocks` field for layout instead.
161
210
 
162
- - **Sections** (`/section`): compose the pattern once as reusable content and
163
- let editors insert copies.
164
- - **Field Kit `list` widgets** on `json` collection fields: model the repeating
165
- rows in the collection schema and render them at the template level with
166
- `Cards.astro` / `NodeRenderer.astro` from `@getvitops/astro`.
211
+ Not yet blocks: tree, entries, reviews (`ReviewCard` reads `.vitops/reviews.json`, which needs a
212
+ build-time import rather than a filesystem read on a Worker), dialog and tabs (no component yet).
167
213
 
168
214
  ## Changelog
169
215
 
package/dist/index.d.mts CHANGED
@@ -1,30 +1,79 @@
1
1
  import { PluginDescriptor, PortableTextBlockConfig } from "emdash";
2
2
  import { AstroIntegration } from "astro";
3
-
4
- //#region src/blocks.d.ts
5
- /** The v1 subset of EmDash Block Kit field elements used by these blocks. */
3
+ /** The subset of EmDash Block Kit field elements these blocks use. */
6
4
  type BlockKitFieldDef = Extract<NonNullable<PortableTextBlockConfig['fields']>[number], {
7
- type: 'text_input' | 'number_input' | 'select' | 'toggle' | 'combobox';
5
+ type: 'text_input' | 'number_input' | 'select' | 'toggle' | 'combobox' | 'repeater' | 'media_picker';
8
6
  }>;
9
7
  type PortableTextBlockDef = Omit<PortableTextBlockConfig, 'fields'> & {
10
8
  fields?: BlockKitFieldDef[];
11
9
  };
12
- declare const BLOCKS: PortableTextBlockDef[];
13
- //#endregion
14
- //#region src/hosting.d.ts
10
+ export declare const BLOCKS: PortableTextBlockDef[];
11
+ /** Which Vitops blocks a site's editor offers, and any it adds of its own. */
12
+ interface BlockSelection {
13
+ /** Offer only these `vitops.*` types. Unknown names throw — a typo must not silently offer nothing. */
14
+ include?: string[];
15
+ /** Drop these `vitops.*` types. Applied after `include`. */
16
+ exclude?: string[];
17
+ /**
18
+ * The site's own blocks. These are EDITOR definitions only: the plugin cannot render a
19
+ * block it has never heard of, so the site maps each `type` to a component with
20
+ * `<PortableText components={{ type: { … } }} />`. A type that collides with an existing
21
+ * one throws, since the later definition would silently replace the earlier one's fields.
22
+ */
23
+ extra?: PortableTextBlockDef[];
24
+ }
25
+ /**
26
+ * Resolve {@link BlockSelection} against {@link BLOCKS}.
27
+ *
28
+ * Pure so a misconfiguration fails at plugin construction, with the offending name in the
29
+ * message, rather than as an editor menu that is quietly missing something.
30
+ */
31
+ export declare function selectBlocks(selection?: BlockSelection): PortableTextBlockDef[];
32
+ interface DesignSystemEditorOptions {
33
+ /**
34
+ * The site's own config, typically `import config from '../../site.json'
35
+ * with { type: 'json' }`. A static, build-time-bundled value — this plugin
36
+ * never reads it from disk at runtime (a deployed Worker has no
37
+ * filesystem), so an edit doesn't take effect here until the *next*
38
+ * deploy; that's exactly the point of the auto-commit half.
39
+ */
40
+ config: unknown;
41
+ /** Which `designSystem.themes` entry this edits. Default: `'default'`. */
42
+ theme?: string;
43
+ }
44
+ /**
45
+ * The block reference an agent reads via `vitops docs blocks`: every Portable Text `_type`,
46
+ * its fields and what each saves. Rendered from the same `BLOCKS` the editor menu uses, so
47
+ * it cannot describe a field the editor doesn't offer.
48
+ */
49
+ export declare function renderBlocksDoc(blocks?: readonly PortableTextBlockDef[]): string;
15
50
  type HostingTarget = 'cloudflare' | 'node';
16
51
  interface VitopsHostingOptions {
17
52
  /** Hosting target. Overridden by the `HOSTING` env var. Default 'cloudflare'. */
18
53
  target?: HostingTarget;
19
54
  cloudflare?: {
20
- /** D1 binding name in wrangler config (default 'DB'). */dbBinding?: string; /** R2 binding name in wrangler config (default 'MEDIA'). */
21
- mediaBinding?: string; /** D1 Sessions API read-replication mode (default 'auto'). */
55
+ /** D1 binding name in wrangler config (default 'DB'). */
56
+ dbBinding?: string;
57
+ /** R2 binding name in wrangler config (default 'MEDIA'). */
58
+ mediaBinding?: string;
59
+ /** D1 Sessions API read-replication mode (default 'auto'). */
22
60
  session?: string;
61
+ /**
62
+ * Batch reads issued together into one D1 round trip (default true).
63
+ * Experimental in emdash: a read and a write started together may run
64
+ * write-first, so await a read before a write that must not affect it.
65
+ * No effect without a session.
66
+ */
67
+ coalesce?: boolean;
23
68
  };
24
69
  node?: {
25
- /** SQLite URL (default `DATABASE_PATH` env or 'file:./data/emdash.db'). */databaseUrl?: string; /** Full database descriptor override (e.g. postgres() from 'emdash/db'). */
26
- database?: unknown; /** Local uploads directory (default './data/uploads'). */
27
- uploadsDir?: string; /** Full storage descriptor override (e.g. s3() from 'emdash/astro'). */
70
+ /** SQLite URL (default `DATABASE_PATH` env or 'file:./data/emdash.db'). */
71
+ databaseUrl?: string;
72
+ /** Full database descriptor override (e.g. postgres() from 'emdash/db'). */
73
+ database?: unknown;
74
+ /** Local uploads directory (default './data/uploads'). */
75
+ uploadsDir?: string;
76
+ /** Full storage descriptor override (e.g. s3() from 'emdash/astro'). */
28
77
  storage?: unknown;
29
78
  };
30
79
  }
@@ -36,10 +85,8 @@ interface VitopsHosting {
36
85
  /** EmDash storage descriptor — pass to emdash({ storage }). */
37
86
  storage: unknown;
38
87
  }
39
- declare function vitopsHosting(options?: VitopsHostingOptions): Promise<VitopsHosting>;
40
- //#endregion
41
- //#region src/index.d.ts
42
- interface VitopsEmdashOptions {
88
+ export declare function vitopsHosting(options?: VitopsHostingOptions): Promise<VitopsHosting>;
89
+ export interface VitopsEmdashOptions {
43
90
  /**
44
91
  * How the web-component runtime scripts reach the page:
45
92
  * - `'integration'` (default) — the site's layout renders `<Head />` from
@@ -53,14 +100,28 @@ interface VitopsEmdashOptions {
53
100
  scripts?: 'integration' | 'fragments';
54
101
  /** Public base path of the web-component bundles (default '/vitops'). */
55
102
  wcBase?: string;
103
+ /**
104
+ * Mounts a `<wc-theme-editor>` admin page at `/design-system`, backed by a
105
+ * plugin API route — see AGENTS.md's "EmDash plugin as the design-system
106
+ * editing surface" section and `design-system-route.ts`'s own docblock.
107
+ * Off by default. Requires the `network:request` capability (declared
108
+ * automatically when this is set) for the GitHub auto-commit half —
109
+ * reviewed once at plugin-install time, same as any other capability.
110
+ */
111
+ designSystemEditor?: DesignSystemEditorOptions | false;
112
+ /**
113
+ * Which blocks the editor offers. All of the `vitops.*` blocks by default. Use `exclude` to
114
+ * drop one a client should not see, `include` for an allowlist, and `extra` to add the
115
+ * site's own — whose renderers the site supplies, see {@link BlockSelection}.
116
+ */
117
+ blocks?: BlockSelection;
56
118
  }
57
119
  /**
58
120
  * Descriptor factory — import in `astro.config.mjs` and pass to the emdash()
59
121
  * integration's `plugins` array.
60
122
  */
61
- declare function vitopsEmdash(options?: VitopsEmdashOptions): PluginDescriptor;
123
+ export declare function vitopsEmdash(options?: VitopsEmdashOptions): PluginDescriptor;
62
124
  /** Runtime side — EmDash imports and calls this from the descriptor's entrypoint. */
63
- declare function createPlugin(options?: VitopsEmdashOptions): import("emdash").ResolvedPlugin<import("emdash").PluginStorageConfig>;
64
- //#endregion
65
- export { BLOCKS, type BlockKitFieldDef, type HostingTarget, type PortableTextBlockDef, VitopsEmdashOptions, type VitopsHosting, type VitopsHostingOptions, createPlugin, createPlugin as default, vitopsEmdash, vitopsHosting };
125
+ export declare function createPlugin(options?: VitopsEmdashOptions): import("emdash").ResolvedPlugin<import("emdash").PluginStorageConfig>;
126
+ export { type BlockKitFieldDef, type BlockSelection, type DesignSystemEditorOptions, type HostingTarget, type PortableTextBlockDef, type VitopsHosting, type VitopsHostingOptions, createPlugin as default };
66
127
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/blocks.ts","../src/hosting.ts","../src/index.ts"],"mappings":";;;;;KAgBY,gBAAA,GAAmB,OAAA,CAC7B,WAAA,CAAY,uBAAA;EACV,IAAA;AAAA;AAAA,KAGQ,oBAAA,GAAuB,IAAA,CAAK,uBAAA;EACtC,MAAA,GAAS,gBAAA;AAAA;AAAA,cAGE,MAAA,EAAQ,oBAAoB;;;KCO7B,aAAA;AAAA,UAIK,oBAAA;EDoKhB;EClKC,MAAA,GAAS,aAAa;EACtB,UAAA;IDduC,yDCgBrC,SAAA;IAEA,YAAA,WAXQ;IAaR,OAAA;EAAA;EAEF,IAAA;IAfuB,2EAiBrB,WAAA,WAbiC;IAejC,QAAA,YAboB;IAepB,UAAA,WAfO;IAiBP,OAAA;EAAA;AAAA;AAAA,UAIa,aAAA;EACf,MAAA,EAAQ,aAAA;EACR,OAAA,EAAS,gBAAgB;EAVvB;EAYF,QAAA;EARE;EAUF,OAAA;AAAA;AAAA,iBAoBoB,aAAA,CAAc,OAAA,GAAS,oBAAA,GAA4B,OAAA,CAAQ,aAAA;;;UCxChE,mBAAA;;;;;;;;;;;EAWf,OAAA;EFtCM;EEwCN,MAAM;AAAA;;;;;iBAOQ,YAAA,CAAa,OAAA,GAAS,mBAAA,GAA2B,gBAAgB;;iBAajE,YAAA,CAAa,OAAA,GAAS,mBAAwB,oBAAA,cAAA,kBAAA,mBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/blocks.ts","../src/design-system-route.ts","../src/blocks-doc.ts","../src/hosting.ts","../src/index.ts"],"mappings":";;;KAsBY,mBAAmB,QAC7B,YAAY;EAEV;;KAWQ,uBAAuB,KAAK;EACtC,SAAS;;qBAGE,QAAQ;;UAsVJ;;EAEf;;EAEA;;;;;;;EAOA,QAAQ;;;;;;;;wBASM,aAAa,YAAW,iBAAsB;UC3V7C;;;;;;;;EAQf;;EAEA;;;;;;;wBC/Bc,gBAAgB,kBAAiB;KCFrC;UAIK;;EAEf,SAAS;EACT;;IAEE;;IAEA;;IAEA;;;;;;;IAOA;;EAEF;;IAEE;;IAEA;;IAEA;;IAEA;;;UAIa;EACf,QAAQ;EACR,SAAS;;EAET;;EAEA;;wBAoBoB,cAAc,UAAS,uBAA4B,QAAQ;iBC7BhE;;;;;;;;;;;EAWf;;EAEA;;;;;;;;;EASA,qBAAqB;;;;;;EAMrB,SAAS;;;;;;wBAOK,aAAa,UAAS,sBAA2B;;wBAmBjD,aAAa,UAAS,uCAAwB,gCAAA"}