Commit Graph

1363 Commits

Author SHA1 Message Date
emdashbot[bot] 4c3edadeec ci: release (#2419)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@emdash-cms/admin@0.34.0 @emdash-cms/auth-atproto@0.2.34 @emdash-cms/auth@0.34.0 @emdash-cms/blocks@0.34.0 @emdash-cms/cloudflare@0.34.0 @emdash-cms/gutenberg-to-portable-text@0.34.0 @emdash-cms/plugin-embeds@0.1.42 @emdash-cms/plugin-forms@0.2.5 @emdash-cms/sandbox-workerd@0.5.0 @emdash-cms/x402@0.34.0 create-emdash@0.34.0 emdash@0.34.0 @emdash-cms/plugin-cli@0.8.1
2026-08-18 13:26:49 +01:00
Matt Kane 470a62cd0c ci: adopt Worker Previews for playground (#2533) 2026-08-18 12:38:31 +01:00
Matt Kane f1ab3f93aa fix(bot): make verification efficient and recoverable (#2537)
* fix(bot): focus implementation verification

* fix(bot): keep verification commands stable

* fix(bot): prevent verification history wedges
2026-08-18 12:22:47 +01:00
Armand Philippot eba44f7c63 i18n(fr): translate in French the 89 missing keys (#2464)
* i18n(fr): translate in French the 89 missing keys

* example.com

Co-authored-by: emdashbot[bot] <273199577+emdashbot[bot]@users.noreply.github.com>

---------

Co-authored-by: emdashbot[bot] <273199577+emdashbot[bot]@users.noreply.github.com>
Co-authored-by: Matt Kane <mkane@cloudflare.com>
2026-08-18 10:00:02 +01:00
helio-cf ef32567fd5 fix(core): generate row types for repeater fields (#2469)
* fix(core): generate row types for repeater fields

`fieldTypeToTypeScript` had no `repeater` case, so every repeater field
fell through to `default: return "unknown"` -- while the zod side derives
a precise row schema from the same `validation.subFields` metadata.

This was an oversight rather than a decision. The emitter's switch,
including its deliberate `case "json": return "unknown"`, dates from
43fcb9a1 and predates the field type: #111 added `repeater` without
touching this file at all, so neither the zod case nor the TS case
arrived with the feature. #2458 then added the zod case and left the TS
side as it was. Type generation is now the only consumer of `subFields`
that discards it -- media-usage extraction and the admin field editor
both read it.

Consumers cannot index or iterate `unknown`, so they declare row shapes
by hand and cast to them. Those casts silence the compiler: when a
sub-field is renamed or retyped, the generated type stays `unknown`, the
cast keeps asserting the old shape, and the drift surfaces as a silently
blank render rather than a type error.

- Build an inline row type from `subFields`, reusing the existing
  per-type mapping so a `select` sub-field enumerates its options and an
  `image` sub-field emits the same media literal as a top-level image.
- Type a sub-field that is not required as `T | null`, since
  `generateRepeaterRowSchema` applies `.nullish()` to it. A bare `T`
  would trade an honest `unknown` for an unsound type.
- Keep emitting `unknown` when `subFields` is absent or empty. A repeater
  with no declared rows is schema-valid, and `{}[]` would be falsely
  permissive.

`fieldTypeToTypeScript` now takes a structural subset of `Field` so a
sub-field can reuse the mapping without a type assertion.

Sub-field slugs match `/^[a-z][a-z0-9_]*$/`, so they are valid bare
identifiers and need no quoting in the emitted literal.

* fix(core): emit valid repeater row types from unvalidated sub-fields

Quote member names, keep the last declaration of a duplicated slug, and
fall back to `unknown` when `subFields` is not an array.

---------

Co-authored-by: Matt Kane <mkane@cloudflare.com>
2026-08-18 08:49:14 +00:00
Matt Kane a07b4a5379 fix(bot): summarize and resume timed-out runs (#2536)
* fix(bot): preserve timed-out runs for resume

* fix(bot): recover rejected resume dispatches

* fix(bot): dedupe resumed deliveries atomically

* fix(bot): confirm resumed agent callbacks
2026-08-18 08:57:28 +01:00
emdashbot[bot] d328bdd6a6 chore: extract locale catalogs [skip ci] 2026-08-18 07:20:38 +00:00
Frank Bartolitsch f8a4fcefd2 fix(taxonomies): respect active locale in admin surfaces (#2342)
* fix(taxonomies): respect active locale in admin surfaces

Group translated definitions by logical identity before rendering admin navigation and editor choices. Scope visible term counts and cache entries to the resolved content locale.

* fix(taxonomies): preserve locale in admin term views

* ci: update query-count snapshots

* fix(admin): preserve locale sidebar active state

* fix(taxonomies): preserve exact locale updates

* test(perf): update locale query snapshots

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
2026-08-18 07:18:22 +00:00
Matt Kane a8b9483fd2 fix(bot): preserve context for long write runs (#2532) 2026-08-17 17:39:05 +00:00
Matt Kane a927afe2af docs: add EmDash documentation writing skill (#2529)
* docs: add EmDash documentation writing skill

* style: format

* ci: review documentation with writing skill

* docs(agents): load documentation writing skill

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
2026-08-17 14:47:25 +01:00
Matt Kane 68a8593b5a fix(bot): preserve workspaces through sandbox restarts (#2530) 2026-08-17 13:01:06 +00:00
Matt Kane 87d201ffa5 fix(bot): classify comments with one AI call (#2528) 2026-08-17 12:12:15 +00:00
emdashbot[bot] 75860bf32e chore: extract locale catalogs [skip ci] 2026-08-17 09:46:58 +00:00
Matt Kane 5c216c2f92 fix: preserve taxonomy assignments across locale fallbacks (#2508)
* fix(taxonomies): preserve assignments across locale fallback

* fix(admin): clarify taxonomy locale resolution

* perf(taxonomies): join locale fallbacks once

* fix(admin): gate taxonomy creation by permission

* chore: retry external preview build

* fix(admin): show flat taxonomy creation errors
2026-08-17 09:45:55 +00:00
emdashbot[bot] f15d433a4f chore: extract locale catalogs [skip ci] 2026-08-17 09:19:44 +00:00
Matt Kane 5289385499 fix: generate inline taxonomy slugs server-side (#2506)
* fix: keep inline taxonomy terms Unicode-safe

* fix: retry concurrent taxonomy slug collisions
2026-08-17 10:17:39 +01:00
emdashbot[bot] a5d31d547f chore: extract locale catalogs [skip ci] 2026-08-17 09:14:42 +00:00
Matt Kane 515c08d17c fix(scheduler): warn when scheduled maintenance stops (#2512)
* fix(scheduler): surface missed scheduled work

Persist maintenance heartbeats so authenticated editors are warned when overdue content indicates the scheduler has stopped.

* fix(scheduler): keep heartbeat writes non-fatal

A transient operator-health write must not reject maintenance that already completed successfully.

* test(scheduler): cover heartbeat upsert failures

Keep the non-fatal heartbeat contract exercised for both initial inserts and existing-row updates.
2026-08-17 10:12:12 +01:00
Matt Kane 40953d0859 feat(cli): diagnose broken Cloudflare scheduler wiring (#2511)
* feat(cli): detect broken scheduler wiring

Catch Cloudflare deployments that would silently miss scheduled work before they are deployed.

* fix(cli): keep doctor type-aware lint clean

* fix(cli): preserve additive doctor checks

Keep explicit database diagnosis intact, recognize Wrangler TOML, and avoid flagging Workers that do not opt into EmDash scheduled maintenance.

* fix(cli): make scheduler fixes config-aware

Keep doctor guidance copy-pasteable for Wrangler TOML users as well as JSON and JSONC sites.

* fix(cli): finish TOML doctor guidance

Keep every copy-pasteable scheduler fix and the command help accurate for all supported Wrangler formats.
2026-08-17 10:12:11 +01:00
emdashbot[bot] b87da7d12a chore: extract locale catalogs [skip ci] 2026-08-16 22:24:40 +00:00
Matt Kane 582823328e fix: preserve Unicode in routable content slugs (#2505)
* fix: keep routable content addressable across languages

* fix: keep invalid legacy slugs out of sitemaps

* fix: close routable publish bypasses

* fix: support slugless non-routable seeds

* fix: protect published routable slugs on update

* fix: normalize unusable slugs in seed exports

* fix: reject slugless routable schedules

* chore: clarify slug generation contract

* chore: remove editor implementation narrative

* test: keep revisionless fixture routable
2026-08-16 23:23:34 +01:00
emdashbot[bot] 140179959d chore: extract locale catalogs [skip ci] 2026-08-16 19:57:18 +00:00
Noah (Nguyen Pham) 318b821927 fix(admin): restore image and HTML toolbar actions (#2510)
* fix(admin): keep script formatting contextual

* fix(admin): restore image and HTML toolbar actions
2026-08-16 20:55:21 +01:00
Matt Kane ae87ce8772 Fix plugin updates being reverted on publish (#2494)
* fix plugin updates being reverted on publish

* test plugin drafts with valid portable text

* clarify draft-aware plugin update comment
2026-08-16 20:47:56 +01:00
Matt Kane ed1e79c0ab perf(core): batch public menu reference resolution (#2501)
* perf(core): avoid per-item menu reference queries

* refactor(core): keep menu lookup values minimal
2026-08-16 19:35:15 +01:00
Matt Kane 5394ecd098 fix(loader): expose folded bylines on live entries (#2500)
* fix(loader): make folded bylines available to live entries

* fix(loader): keep folded byline hydration in sync

* test(loader): assert the public byline credit type

* test(loader): pin folded custom field behavior

* test(loader): isolate byline field cache by dialect
2026-08-16 18:05:39 +00:00
Matt Kane 9b998224a5 fix(editor): protect inline edits from file navigation (#2502)
* fix(editor): protect inline edits from file navigation

* test(editor): rely on cancellable transfer behavior

* fix(editor): own unsupported file drag lifecycle

* fix(editor): reannounce repeated file guidance
2026-08-16 18:43:06 +01:00
Matt Kane cd4268d1d1 fix(security): prevent image parser denial of service (#2504)
* fix(security): prevent image parser denial of service

* test(security): cover all patched parser paths

* chore(build): preserve patched dependency rationale
2026-08-16 17:35:49 +00:00
Matt Kane 48806e224b fix(plugins): honor locale when creating content (#2498)
* fix(plugins): honor configured locale on content creation

* fix(plugins): align sandbox content locale types

* fix(workerd): apply default locale to batch creates

* docs(plugins): clarify explicit locale validation

* fix(plugins): initialize sandbox translation groups
2026-08-16 17:25:28 +00:00
emdashbot[bot] 1318b0cb32 chore: extract locale catalogs [skip ci] 2026-08-16 16:59:31 +00:00
Matt Kane 1c4d4f04b2 feat(core): expose outer user middleware hook (#2499)
* feat(core): wrap EmDash with user middleware

* fix(core): validate outer middleware config
2026-08-16 17:39:47 +01:00
Matt Kane 13db62c82f fix(core): match FileValue to persisted media snapshots (#2489)
* fix(core): match file values to persisted media snapshots

* fix(core): preserve sparse file snapshots safely
2026-08-16 17:02:11 +01:00
Matt Kane 2398b8d1bd fix: prevent unsupported Portable Text mark loss (#2493)
* fix: prevent unsupported Portable Text marks from being lost

* fix: keep editor open after rejected section insert
2026-08-16 16:59:22 +01:00
Matt Kane 964f51e5da Fix tag autocomplete navigation and overflow (#2491)
* fix(admin): make tag matches reachable

* test(admin): cover tag ranking and focus
2026-08-16 16:57:19 +01:00
Matt Kane 144e378161 fix(taxonomies): resolve omitted locales at write time (#2488)
* fix(taxonomies): avoid stale locale defaults

* ci: update query-count snapshots

* fix(perf): keep locale diagnostic off public cold path

* Revert "ci: update query-count snapshots"

This reverts commit 3dd19c561e889b60a88584a8c7863856118c1bc9.

* refactor(taxonomies): remove unreachable locale branches

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
2026-08-16 16:49:50 +01:00
emdashbot[bot] 38797a95c5 chore: extract locale catalogs [skip ci] 2026-08-16 12:14:49 +00:00
logelog 4c565ea7f9 feat(admin): allow trusted plugins to add content list columns (#2195)
* feat(admin): allow trusted plugins to add content list columns

* fix(admin): use ESM extensions for plugin columns

* test(admin): cover combined content list columns

* fix(admin): pass visible page to plugin columns

* fix(admin): use ASCII plugin column fallback

* fix(admin): enforce plugin column contracts

* docs(admin): use neutral column examples

* fix(admin): preserve plugin column state

* fix(admin): accept wrapped plugin column components

---------

Co-authored-by: logelog <194732487+logelog@users.noreply.github.com>
Co-authored-by: Matt Kane <mkane@cloudflare.com>
2026-08-16 12:13:37 +00:00
logelog e5cda04660 feat(content): filter indexed custom fields (#2213)
* feat(content): filter indexed custom fields

* fix(content): normalize field filters before validation

* test(content): cover indexed field filter contracts

* fix(content): cap indexed filter bind budget

* fix(content): preserve indexed filter query plans

* fix(content): keep the missing-collection error contract with field filters

* fix(content): settle both list queries before rethrowing

`findMany` races the page query against the count query. A collection whose
table is missing rejects both, and `Promise.all` returns on the first while
the other stays in flight holding a pooled connection. A Postgres pool
destroyed inside that window never finishes closing.

This predates the branch. The missing-collection regression test added here
is the first to reach the path on Postgres, so the suite cannot pass without
it.

* fix(content): resolve a missing collection before filter identifiers

Identifier validation ran first, so a request naming both a collection that
does not exist and an invalid filter field answered VALIDATION_ERROR while
the same request without filters answered COLLECTION_NOT_FOUND. The field
names reach the lookup as bound parameters, so deferring validation past the
collection check keeps the query parameterized.

Drop four comments that justify decisions rather than record an invariant.

* fix(content): resolve a missing collection before the filter cap

The cap on filter count threw before the collection lookup, so a request
naming a collection that does not exist alongside more than the allowed
number of filters answered VALIDATION_ERROR while the same request without
filters answered COLLECTION_NOT_FOUND. The cap stays where it is, since it
also bounds how many field slugs reach the lookup as bound parameters.

Drop the comment above the settled list queries. The missing-collection test
fails without them, which is where that contract belongs.

* refactor(content): drop the note above the filter cap

The tests around the cap already say what it protects.

---------

Co-authored-by: logelog <194732487+logelog@users.noreply.github.com>
Co-authored-by: Matt Kane <mkane@cloudflare.com>
2026-08-16 12:07:54 +00:00
Kevin Kyburz 8313255a60 feat(plugins): expose authenticated caller to route handlers as ctx.user (#1947)
* feat(plugins): expose authenticated caller to route handlers as ctx.user

The plugin API catch-all resolves and authorizes the caller, then drops
it before dispatch, leaving plugins no safe way to know who is calling
a private route. Thread the validated user through handlePluginApiRoute
into RouteContext (native format) and routeCtx.user (standard format,
in-process and worker sandboxes alike) as the read-only UserInfo shape.

Public routes and machine tokens with no bound user receive undefined;
the catch-all only forwards the caller after private-route auth, so an
ambient admin session is never bound to a public route.

Fixes #812

* docs(core): use canonical users capability name

* fix(core): forward callers to MCP plugin routes

---------

Co-authored-by: Matt Kane <mkane@cloudflare.com>
2026-08-16 12:36:43 +01:00
Mason James a9ace36a0d feat(mcp): add safe schema update tools (#2354)
* feat(mcp): add safe schema update tools

* fix(mcp): harden schema update safety

* fix(schema): preserve partial update invariants

* fix(schema): skip unchanged field indexes

* fix(mcp): expose indexed field updates

* fix(schema): preserve collection update behavior

* fix(mcp): align schema update validation

* fix(core): share URL pattern cache state

* fix(mcp): reuse collection support schema

---------

Co-authored-by: Matt Kane <mkane@cloudflare.com>
2026-08-16 10:21:41 +01:00
emdashbot[bot] 19978ffcfc chore: extract locale catalogs [skip ci] 2026-08-16 08:19:52 +00:00
Eyüp Can Akman 77080152db fix(admin): parse API token created date as UTC (#2467)
Co-authored-by: Matt Kane <mkane@cloudflare.com>
2026-08-16 09:18:45 +01:00
emdashbot[bot] 0991de0e09 chore: extract locale catalogs [skip ci] 2026-08-16 06:42:11 +00:00
CacheMeOwside 5224b5711a feat(core): configurable titleField and dateField per collection (#1973)
* feat(core): configurable displayField and dateField per collection

* style: format

* ci: update query-count snapshots

* add fixes as per PR comments

* ci: update query-count snapshots

* reject field type changes that break displayField/dateField

* rename displayField to titleField

* match content-list search and suggestions against configured titleField

* ci: update query-count snapshots

* update integration tests

* style: format

* removed reference to PR from comments

* Remove PR reference

Co-authored-by: emdashbot[bot] <273199577+emdashbot[bot]@users.noreply.github.com>

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
Co-authored-by: emdashbot[bot] <273199577+emdashbot[bot]@users.noreply.github.com>
2026-08-16 07:41:13 +01:00
Daniel 4e76317978 fix(core): remove stale restampEntryPivot call that crashes content publish (#2466)
* fix(core): remove stale restampEntryPivot call that crashes content publish

The merge of #2460 and #2461 left main with a publish path that calls
restampEntryPivot, a method #2461 deleted together with the pivot
denormalization it maintained. Every content publish now throws
"this.restampEntryPivot is not a function".

No replacement call is needed: since migration 068 the pivot columns the
call re-stamped are legacy, and reads join the authoritative ec_* row.

* chore: add changeset for the publish crash fix

The fix changes the published emdash package, and release notes are
built from changeset files, so the crash fix needs an entry even though
the crash itself never shipped in a release.
2026-08-14 16:04:43 +01:00
Matt Kane 6602ae05bc Fix taxonomy filter detection across collections (#2459)
* fix(loader): scope taxonomy filters to collections

* ci: update query-count snapshots

* fix(loader): harden taxonomy name cache

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
2026-08-13 17:23:31 +00:00
Matt Kane 598e6fb95f Fix taxonomy assignments across content translations (#2461)
* fix: share taxonomy assignments across translations

* fix: count shared taxonomy assignments once

* ci: update query-count snapshots

---------

Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
2026-08-13 18:20:40 +01:00
Matt Kane d236776195 fix: prevent revisionless publish data loss (#2460) 2026-08-13 16:43:41 +00:00
Matt Kane d7fe781ed9 fix: prevent queued pruning from deleting concurrent revisions (#2457) 2026-08-13 16:02:18 +00:00
Matt Kane 7385d434ca fix: enforce repeater constraints on content saves (#2458) 2026-08-13 16:00:29 +00:00