ci: release#1123
Conversation
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-perf-coordinator | aea18ae | May 23 2026, 06:20 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-i18n | aea18ae | May 23 2026, 06:20 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | 7c5e36c | May 26 2026, 04:43 PM |
Scope checkThis PR touches 29 files. PRs with a broad scope are harder to review. Please confirm the scope hasn't drifted beyond the intended change. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 7c5e36c | May 26 2026, 04:44 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-playground | 7c5e36c | May 26 2026, 04:43 PM |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
d244620 to
0bd6ba4
Compare
67d6a96 to
8aacac7
Compare
d4919bc to
4fae997
Compare
4fae997 to
aea18ae
Compare
5e1c6b5 to
678ae04
Compare
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
678ae04 to
004fa48
Compare
004fa48 to
7c5e36c
Compare
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@emdash-cms/admin@0.15.0
Minor Changes
#1146
11b3001Thanks @MohamedH1998! - Adds first-class i18n support for bylines, mirroring the row-per-locale model already used by menus and taxonomies (PR feat: i18n menus and taxonomies #916, migrations 036).Schema (migration 040)
_emdash_bylinesgains two columns:locale—TEXT NOT NULL DEFAULT 'en'. Every row now belongs to exactly one locale.translation_group—TEXT NOT NULL. Shared across every locale variant of a single byline identity. The anchor row'stranslation_groupequals itsid; siblings inherit it.A partial unique index
idx_bylines_group_locale_uniqueenforces one row per(translation_group, locale). The pre-existing(slug)unique index becomes(slug, locale)to allow the same slug across locales.Existing rows are backfilled to the configured
defaultLocale(or'en'if i18n isn't configured) withtranslation_group = id. Monolingual sites see no functional change; multilingual sites continue rendering the same byline data at the default locale until editors create translations.Credit hydration: strict per-locale
_emdash_content_bylines.byline_idnow stores the byline'stranslation_group, not its row id. When an entry is rendered, credits are filtered by joining the junction against the byline sibling whoselocalematches the entry'slocale. If no sibling exists at the entry's locale, the credit hydrates as empty — there is no fallback to other locales' bios.Author-inferred bylines (where an entry has no explicit credits but its author is linked to a byline) still fall back per-locale and respect the strictness gate: an entry with explicit credits at any locale will not infer from the author even if the explicit credits don't resolve at the rendering locale.
This is a deliberate behavior change for multilingual sites. The motivation is correctness: chain-walking credits across locales renders the wrong-language bio on translated entries.
The "explicit credit suppresses author fallback" check reads
primary_byline_iddirectly from the content row — set bysetContentBylinesiff junction rows exist, backfilled by migration 040 for pre-existing rows. No separate probe against_emdash_content_bylinesis needed at hydration time; the column is folded into the single per-entry context fetch (author_id+primary_byline_idin one query). Both monolingual and multilingual sites get the same query count.Identity lookups: chain-walk
getBylineBySlug(slug, { locale })walks the configured fallback chain (resolveLocaleChain), likegetMenuandgetTerm. Author pages for un-translated bylines still render an identity rather than 404'ing. This is conceptually distinct from credit hydration and runs throughrequestCachedfor per-render dedupe.Admin
POST /_emdash/api/admin/bylines/:id/translationsendpoint./bylinesfilters the list strictly to one locale. Cross-locale navigation via TranslationsPanel routes through/bylines?locale=…./bylines?locale=…for inline creation.POST /content/:collectionwithtranslationOf) callscopyContentBylinesto inherit the source's credits — these resolve at the new entry's locale via the strict-hydration model, so credits "follow" the content across translations once sibling bylines exist.API additions
GET /_emdash/api/admin/bylines/:id/translations— list every sibling row sharing a translation_group.POST /_emdash/api/admin/bylines/:id/translations— create a sibling at a target locale. Body defaults (slug, displayName, websiteUrl, avatar) inherit from the source.POST /_emdash/api/admin/bylinesacceptstranslationOf+localeto create a sibling in one call.GET /_emdash/api/admin/bylines?locale=…filters strictly.BylineSummarygainslocale: stringandtranslationGroup: string | null(additive — existing consumers ignore the new fields).Permissions
Two new entries on
@emdash-cms/auth:bylines:read— minimumSUBSCRIBER.bylines:manage— minimumEDITOR.All byline routes (list, get, update, delete, translations) now check these instead of
content:read/Role.EDITOR. Role thresholds are unchanged, so existing users see no permission differences. Custom RBAC configurations that bind to the old strings should add the new permission names.Repository
BylineRepositoryis strict per-locale:findMany,findBySlug,findByIdaccept an optionallocaleand return rows matching that locale (or all locales when omitted, for the manager view).listTranslations(id),findByTranslationGroup(group),copyContentBylines(collection, fromId, toId).setContentBylinesdeduplicates bytranslation_groupafter resolving wire row ids, so passing two sibling row ids of the same identity collapses to one credit row.deleteis sibling-aware: removing one locale variant leaves siblings standing.Notable trade-offs
byline_translationsside-table. Matches the existing content / menu / taxonomy convention so query patterns and indexes are consistent across the codebase.#1176
fae97eeThanks @ascorbic! - Code blocks in the rich text editor now have an inline language picker. Hover over any code block to reveal a chip in the corner; click it to enter a language (free-form input with curated suggestions for ~30 common languages including TypeScript, Python, Bash, Rust, Astro, SQL, and more). Aliases resolve automatically -- typingtsstorestypescript,c++storescpp, etc. The existing markdown shortcut (typing```htmlfollowed by a space or Enter) continues to pre-populate the language. The chosen language persists on the Portable Textlanguagefield and is emitted as alanguage-{id}class on the rendered<pre>so frontend syntax highlighters can pick it up. The visual (in-place) editor gets the same picker UI.#1114
9a30607Thanks @ascorbic! - Plugins installed from the experimental registry can now be uninstalled and updated from the admin, the same way marketplace plugins always could. The "uninstall is not yet available for registry plugins" placeholder is gone — registry plugin rows now show the same Uninstall and Update buttons.The Plugins page's "updates available" indicator now covers registry plugins too. If the registry aggregator is unreachable, marketplace updates still load (and vice versa).
Updates that need newly-declared permissions, or that newly expose a public (unauthenticated) route, prompt for re-consent before installing the new version — matching the gate that marketplace updates already have.
#1125
d0ff94bThanks @ascorbic! - Adds a version picker to the registry plugin detail page. Older releases of a registry-hosted plugin are now selectable from a dropdown next to the Install button, and the displayed version, indexed date, permissions, and source link swap to match the selected release. Pre-release versions (e.g.1.0.0-alpha.1) are flagged with a "Pre-release" badge so admins can spot them before installing. Versions still inside the configured minimum-release-age holdback remain visible in the dropdown but stay non-installable until they age into the window.Patch Changes
#1177
b9cc08eThanks @ascorbic! - Bumps@cloudflare/kumofrom 1.16 to 2.3. Two internal call sites picked up breaking API changes from Kumo 2.0:Collapsibleis now a compound component (Collapsible.Root/.DefaultTrigger/.DefaultPanelinstead of<Collapsible label=...>), used by the accordion block; andChartPalette.color()was renamed toChartPalette.categorical()in the chart block. No public API changes -- consumers see identical behaviour. Tests in@emdash-cms/adminthat asserted onButton's nativetitleattribute now readaria-labelinstead, because Kumo 2 wraps<Button title>in a Tooltip popup rather than setting the DOM attribute.#1119
393dd26Thanks @adentdk! - Fixes auto-save not detecting plugin block field changes. When editing an existing block's attributes via the Block Kit modal, the change now correctly triggers TipTap'sonUpdatecallback, propagating through to the auto-save dirty detection.Updated dependencies [
cf3c706,b9cc08e]:@emdash-cms/auth@0.15.0
Minor Changes
#1146
11b3001Thanks @MohamedH1998! - Adds first-class i18n support for bylines, mirroring the row-per-locale model already used by menus and taxonomies (PR feat: i18n menus and taxonomies #916, migrations 036).Schema (migration 040)
_emdash_bylinesgains two columns:locale—TEXT NOT NULL DEFAULT 'en'. Every row now belongs to exactly one locale.translation_group—TEXT NOT NULL. Shared across every locale variant of a single byline identity. The anchor row'stranslation_groupequals itsid; siblings inherit it.A partial unique index
idx_bylines_group_locale_uniqueenforces one row per(translation_group, locale). The pre-existing(slug)unique index becomes(slug, locale)to allow the same slug across locales.Existing rows are backfilled to the configured
defaultLocale(or'en'if i18n isn't configured) withtranslation_group = id. Monolingual sites see no functional change; multilingual sites continue rendering the same byline data at the default locale until editors create translations.Credit hydration: strict per-locale
_emdash_content_bylines.byline_idnow stores the byline'stranslation_group, not its row id. When an entry is rendered, credits are filtered by joining the junction against the byline sibling whoselocalematches the entry'slocale. If no sibling exists at the entry's locale, the credit hydrates as empty — there is no fallback to other locales' bios.Author-inferred bylines (where an entry has no explicit credits but its author is linked to a byline) still fall back per-locale and respect the strictness gate: an entry with explicit credits at any locale will not infer from the author even if the explicit credits don't resolve at the rendering locale.
This is a deliberate behavior change for multilingual sites. The motivation is correctness: chain-walking credits across locales renders the wrong-language bio on translated entries.
The "explicit credit suppresses author fallback" check reads
primary_byline_iddirectly from the content row — set bysetContentBylinesiff junction rows exist, backfilled by migration 040 for pre-existing rows. No separate probe against_emdash_content_bylinesis needed at hydration time; the column is folded into the single per-entry context fetch (author_id+primary_byline_idin one query). Both monolingual and multilingual sites get the same query count.Identity lookups: chain-walk
getBylineBySlug(slug, { locale })walks the configured fallback chain (resolveLocaleChain), likegetMenuandgetTerm. Author pages for un-translated bylines still render an identity rather than 404'ing. This is conceptually distinct from credit hydration and runs throughrequestCachedfor per-render dedupe.Admin
POST /_emdash/api/admin/bylines/:id/translationsendpoint./bylinesfilters the list strictly to one locale. Cross-locale navigation via TranslationsPanel routes through/bylines?locale=…./bylines?locale=…for inline creation.POST /content/:collectionwithtranslationOf) callscopyContentBylinesto inherit the source's credits — these resolve at the new entry's locale via the strict-hydration model, so credits "follow" the content across translations once sibling bylines exist.API additions
GET /_emdash/api/admin/bylines/:id/translations— list every sibling row sharing a translation_group.POST /_emdash/api/admin/bylines/:id/translations— create a sibling at a target locale. Body defaults (slug, displayName, websiteUrl, avatar) inherit from the source.POST /_emdash/api/admin/bylinesacceptstranslationOf+localeto create a sibling in one call.GET /_emdash/api/admin/bylines?locale=…filters strictly.BylineSummarygainslocale: stringandtranslationGroup: string | null(additive — existing consumers ignore the new fields).Permissions
Two new entries on
@emdash-cms/auth:bylines:read— minimumSUBSCRIBER.bylines:manage— minimumEDITOR.All byline routes (list, get, update, delete, translations) now check these instead of
content:read/Role.EDITOR. Role thresholds are unchanged, so existing users see no permission differences. Custom RBAC configurations that bind to the old strings should add the new permission names.Repository
BylineRepositoryis strict per-locale:findMany,findBySlug,findByIdaccept an optionallocaleand return rows matching that locale (or all locales when omitted, for the manager view).listTranslations(id),findByTranslationGroup(group),copyContentBylines(collection, fromId, toId).setContentBylinesdeduplicates bytranslation_groupafter resolving wire row ids, so passing two sibling row ids of the same identity collapses to one credit row.deleteis sibling-aware: removing one locale variant leaves siblings standing.Notable trade-offs
byline_translationsside-table. Matches the existing content / menu / taxonomy convention so query patterns and indexes are consistent across the codebase.Patch Changes
#1139
88f544dThanks @ask-bonk! - Upgradeskyselyto^0.29.0(was^0.27.0) to resolve three high-severity advisories fixed in>=0.28.17:JSONPathBuilder.key()/.at()sql.lit(string)Also updates import paths for
MigratorandMigrationtypes tokysely/migrationto comply with kysely 0.29 export changes.emdash@0.15.0
Minor Changes
#426
02ed8baThanks @BenjaminPrice! - Adds workerd-based plugin sandboxing for Node.js deployments.isHealthy()toSandboxRunnerinterface,SandboxUnavailableErrorclass,sandbox: falseconfig option,mediaStoragefield onSandboxOptions, and exportscreateHttpAccess/createUnrestrictedHttpAccess/PluginStorageRepository/UserRepository/OptionsRepositoryfor platform adapters.isHealthy()onCloudflareSandboxRunner. FixesstorageQuery()andstorageCount()to honorwhere,orderBy, andcursoroptions (previously ignored, causing infinite pagination loops and incorrect filtered counts). AddsstorageConfigtoPluginBridgePropssoPluginStorageRepositorycan use declared indexes.WorkerdSandboxRunnerfor production (workerd child process + capnp config + authenticated HTTP backing service) andMiniflareDevRunnerfor development.#1146
11b3001Thanks @MohamedH1998! - Adds first-class i18n support for bylines, mirroring the row-per-locale model already used by menus and taxonomies (PR feat: i18n menus and taxonomies #916, migrations 036).Schema (migration 040)
_emdash_bylinesgains two columns:locale—TEXT NOT NULL DEFAULT 'en'. Every row now belongs to exactly one locale.translation_group—TEXT NOT NULL. Shared across every locale variant of a single byline identity. The anchor row'stranslation_groupequals itsid; siblings inherit it.A partial unique index
idx_bylines_group_locale_uniqueenforces one row per(translation_group, locale). The pre-existing(slug)unique index becomes(slug, locale)to allow the same slug across locales.Existing rows are backfilled to the configured
defaultLocale(or'en'if i18n isn't configured) withtranslation_group = id. Monolingual sites see no functional change; multilingual sites continue rendering the same byline data at the default locale until editors create translations.Credit hydration: strict per-locale
_emdash_content_bylines.byline_idnow stores the byline'stranslation_group, not its row id. When an entry is rendered, credits are filtered by joining the junction against the byline sibling whoselocalematches the entry'slocale. If no sibling exists at the entry's locale, the credit hydrates as empty — there is no fallback to other locales' bios.Author-inferred bylines (where an entry has no explicit credits but its author is linked to a byline) still fall back per-locale and respect the strictness gate: an entry with explicit credits at any locale will not infer from the author even if the explicit credits don't resolve at the rendering locale.
This is a deliberate behavior change for multilingual sites. The motivation is correctness: chain-walking credits across locales renders the wrong-language bio on translated entries.
The "explicit credit suppresses author fallback" check reads
primary_byline_iddirectly from the content row — set bysetContentBylinesiff junction rows exist, backfilled by migration 040 for pre-existing rows. No separate probe against_emdash_content_bylinesis needed at hydration time; the column is folded into the single per-entry context fetch (author_id+primary_byline_idin one query). Both monolingual and multilingual sites get the same query count.Identity lookups: chain-walk
getBylineBySlug(slug, { locale })walks the configured fallback chain (resolveLocaleChain), likegetMenuandgetTerm. Author pages for un-translated bylines still render an identity rather than 404'ing. This is conceptually distinct from credit hydration and runs throughrequestCachedfor per-render dedupe.Admin
POST /_emdash/api/admin/bylines/:id/translationsendpoint./bylinesfilters the list strictly to one locale. Cross-locale navigation via TranslationsPanel routes through/bylines?locale=…./bylines?locale=…for inline creation.POST /content/:collectionwithtranslationOf) callscopyContentBylinesto inherit the source's credits — these resolve at the new entry's locale via the strict-hydration model, so credits "follow" the content across translations once sibling bylines exist.API additions
GET /_emdash/api/admin/bylines/:id/translations— list every sibling row sharing a translation_group.POST /_emdash/api/admin/bylines/:id/translations— create a sibling at a target locale. Body defaults (slug, displayName, websiteUrl, avatar) inherit from the source.POST /_emdash/api/admin/bylinesacceptstranslationOf+localeto create a sibling in one call.GET /_emdash/api/admin/bylines?locale=…filters strictly.BylineSummarygainslocale: stringandtranslationGroup: string | null(additive — existing consumers ignore the new fields).Permissions
Two new entries on
@emdash-cms/auth:bylines:read— minimumSUBSCRIBER.bylines:manage— minimumEDITOR.All byline routes (list, get, update, delete, translations) now check these instead of
content:read/Role.EDITOR. Role thresholds are unchanged, so existing users see no permission differences. Custom RBAC configurations that bind to the old strings should add the new permission names.Repository
BylineRepositoryis strict per-locale:findMany,findBySlug,findByIdaccept an optionallocaleand return rows matching that locale (or all locales when omitted, for the manager view).listTranslations(id),findByTranslationGroup(group),copyContentBylines(collection, fromId, toId).setContentBylinesdeduplicates bytranslation_groupafter resolving wire row ids, so passing two sibling row ids of the same identity collapses to one credit row.deleteis sibling-aware: removing one locale variant leaves siblings standing.Notable trade-offs
byline_translationsside-table. Matches the existing content / menu / taxonomy convention so query patterns and indexes are consistent across the codebase.#1176
fae97eeThanks @ascorbic! - Code blocks in the rich text editor now have an inline language picker. Hover over any code block to reveal a chip in the corner; click it to enter a language (free-form input with curated suggestions for ~30 common languages including TypeScript, Python, Bash, Rust, Astro, SQL, and more). Aliases resolve automatically -- typingtsstorestypescript,c++storescpp, etc. The existing markdown shortcut (typing```htmlfollowed by a space or Enter) continues to pre-populate the language. The chosen language persists on the Portable Textlanguagefield and is emitted as alanguage-{id}class on the rendered<pre>so frontend syntax highlighters can pick it up. The visual (in-place) editor gets the same picker UI.#1114
9a30607Thanks @ascorbic! - Plugins installed from the experimental registry can now be uninstalled and updated from the admin, the same way marketplace plugins always could. The "uninstall is not yet available for registry plugins" placeholder is gone — registry plugin rows now show the same Uninstall and Update buttons.The Plugins page's "updates available" indicator now covers registry plugins too. If the registry aggregator is unreachable, marketplace updates still load (and vice versa).
Updates that need newly-declared permissions, or that newly expose a public (unauthenticated) route, prompt for re-consent before installing the new version — matching the gate that marketplace updates already have.
#1125
d0ff94bThanks @ascorbic! - Adds a version picker to the registry plugin detail page. Older releases of a registry-hosted plugin are now selectable from a dropdown next to the Install button, and the displayed version, indexed date, permissions, and source link swap to match the selected release. Pre-release versions (e.g.1.0.0-alpha.1) are flagged with a "Pre-release" badge so admins can spot them before installing. Versions still inside the configured minimum-release-age holdback remain visible in the dropdown but stay non-installable until they age into the window.Patch Changes
#1139
88f544dThanks @ask-bonk! - Upgradeskyselyto^0.29.0(was^0.27.0) to resolve three high-severity advisories fixed in>=0.28.17:JSONPathBuilder.key()/.at()sql.lit(string)Also updates import paths for
MigratorandMigrationtypes tokysely/migrationto comply with kysely 0.29 export changes.Updated dependencies [
cf3c706,b9cc08e,11b3001,fae97ee,88f544d,393dd26,9a30607,d0ff94b]:@emdash-cms/plugin-cli@0.4.0
Minor Changes
#1126
cf3c706Thanks @ascorbic! - Addsemdash-plugin update-package, a CLI command for editing an already-published plugin's registry record (license, authors, security contacts, name, description, keywords) without cutting a new release. Without--yesit prints a diff and exits without writing; with--yesit writes the updated record to the publisher's PDS using atproto'sswapRecordprecondition (concurrent writes surface asSTALE_RECORDinstead of silently overwriting each other) and bumpslastUpdated. Optional fields use a "manifest absent = no change" policy: removing a key from the manifest doesn't wipe the published value, matchingpublishsemantics. Renaming a plugin via the manifest now surfaces a "looks like a rename" message listing the publisher's existing packages instead of a generic not-found, so publishers don't accidentally orphan releases under the old slug.The publishing client (
@emdash-cms/registry-client) gains aswapRecordparameter onputRecordandunsafePutRecordfor callers needing optimistic-concurrency writes.Patch Changes
463c7a2Thanks @ascorbic! - Refactors the build pipeline's runtime validation of the probed plugin'sdefault export to use a Zod schema. Error messages keep the same format
(
hook "X" must be a function or { handler, ... },hook "X" has invalid FIELD VALUE (...)). Exotic-object entries (Date, RegExp,Promise, class instances) now produce the wrong-shape error instead of
falling through to a misleading "missing handler" error. BigInt /
cyclic-object / function / symbol field values are rendered safely in
error messages instead of crashing with a TypeError.
cf3c706]:@emdash-cms/registry-client@0.2.0
Minor Changes
#1126
cf3c706Thanks @ascorbic! - Addsemdash-plugin update-package, a CLI command for editing an already-published plugin's registry record (license, authors, security contacts, name, description, keywords) without cutting a new release. Without--yesit prints a diff and exits without writing; with--yesit writes the updated record to the publisher's PDS using atproto'sswapRecordprecondition (concurrent writes surface asSTALE_RECORDinstead of silently overwriting each other) and bumpslastUpdated. Optional fields use a "manifest absent = no change" policy: removing a key from the manifest doesn't wipe the published value, matchingpublishsemantics. Renaming a plugin via the manifest now surfaces a "looks like a rename" message listing the publisher's existing packages instead of a generic not-found, so publishers don't accidentally orphan releases under the old slug.The publishing client (
@emdash-cms/registry-client) gains aswapRecordparameter onputRecordandunsafePutRecordfor callers needing optimistic-concurrency writes.@emdash-cms/sandbox-workerd@0.1.0
Minor Changes
02ed8baThanks @BenjaminPrice! - Adds workerd-based plugin sandboxing for Node.js deployments.isHealthy()toSandboxRunnerinterface,SandboxUnavailableErrorclass,sandbox: falseconfig option,mediaStoragefield onSandboxOptions, and exportscreateHttpAccess/createUnrestrictedHttpAccess/PluginStorageRepository/UserRepository/OptionsRepositoryfor platform adapters.isHealthy()onCloudflareSandboxRunner. FixesstorageQuery()andstorageCount()to honorwhere,orderBy, andcursoroptions (previously ignored, causing infinite pagination loops and incorrect filtered counts). AddsstorageConfigtoPluginBridgePropssoPluginStorageRepositorycan use declared indexes.WorkerdSandboxRunnerfor production (workerd child process + capnp config + authenticated HTTP backing service) andMiniflareDevRunnerfor development.Patch Changes
#1144
c50c3b2Thanks @ascorbic! - Aligns thekyselypeer dependency with the rest of the monorepo (>=0.29.0) and switches the dev/peer references to the workspace catalog so all packages bump in lockstep going forward.#1147
20c87feThanks @ascorbic! - Tightens the workerd sandbox internals so the package now lints and type-checks cleanly.require*/optional*helpers instead of uncheckedascasts. A misbehaving plugin that sends a malformed JSON-RPC body now gets a clear "Parameter X must be Y" error rather than triggering a downstream type confusion.ec_*collections) is centralised behind a typedasContentDb()helper. Known tables (users,media,_plugin_storage) drop theiras keyof Databasecasts entirely.initmarshalling validates each field at the bridge boundary, including form-data parts.HttpErrorclass for status-bearing errors and validates incoming chunks/body shape defensively.getPluginStorageConfig()returns the realPluginStorageConfigshape from the manifest instead ofRecord<string, unknown>.WorkerdSandboxedPluginnow implements the correctSandboxedPluginInstanceinterface (the oldSandboxedPluginsymbol did not exist).typecheckscript (tsgo --noEmit) so the package participates inpnpm typecheckgoing forward.No runtime behaviour changes.
Updated dependencies [
02ed8ba,11b3001,fae97ee,88f544d,9a30607,d0ff94b]:@emdash-cms/auth-atproto@0.2.8
Patch Changes
#1177
b9cc08eThanks @ascorbic! - Bumps@cloudflare/kumofrom 1.16 to 2.3. Two internal call sites picked up breaking API changes from Kumo 2.0:Collapsibleis now a compound component (Collapsible.Root/.DefaultTrigger/.DefaultPanelinstead of<Collapsible label=...>), used by the accordion block; andChartPalette.color()was renamed toChartPalette.categorical()in the chart block. No public API changes -- consumers see identical behaviour. Tests in@emdash-cms/adminthat asserted onButton's nativetitleattribute now readaria-labelinstead, because Kumo 2 wraps<Button title>in a Tooltip popup rather than setting the DOM attribute.#1139
88f544dThanks @ask-bonk! - Upgradeskyselyto^0.29.0(was^0.27.0) to resolve three high-severity advisories fixed in>=0.28.17:JSONPathBuilder.key()/.at()sql.lit(string)Also updates import paths for
MigratorandMigrationtypes tokysely/migrationto comply with kysely 0.29 export changes.Updated dependencies [
02ed8ba,11b3001,fae97ee,88f544d,9a30607,d0ff94b]:@emdash-cms/blocks@0.15.0
Patch Changes
b9cc08eThanks @ascorbic! - Bumps@cloudflare/kumofrom 1.16 to 2.3. Two internal call sites picked up breaking API changes from Kumo 2.0:Collapsibleis now a compound component (Collapsible.Root/.DefaultTrigger/.DefaultPanelinstead of<Collapsible label=...>), used by the accordion block; andChartPalette.color()was renamed toChartPalette.categorical()in the chart block. No public API changes -- consumers see identical behaviour. Tests in@emdash-cms/adminthat asserted onButton's nativetitleattribute now readaria-labelinstead, because Kumo 2 wraps<Button title>in a Tooltip popup rather than setting the DOM attribute.@emdash-cms/cloudflare@0.15.0
Patch Changes
#426
02ed8baThanks @BenjaminPrice! - Adds workerd-based plugin sandboxing for Node.js deployments.isHealthy()toSandboxRunnerinterface,SandboxUnavailableErrorclass,sandbox: falseconfig option,mediaStoragefield onSandboxOptions, and exportscreateHttpAccess/createUnrestrictedHttpAccess/PluginStorageRepository/UserRepository/OptionsRepositoryfor platform adapters.isHealthy()onCloudflareSandboxRunner. FixesstorageQuery()andstorageCount()to honorwhere,orderBy, andcursoroptions (previously ignored, causing infinite pagination loops and incorrect filtered counts). AddsstorageConfigtoPluginBridgePropssoPluginStorageRepositorycan use declared indexes.WorkerdSandboxRunnerfor production (workerd child process + capnp config + authenticated HTTP backing service) andMiniflareDevRunnerfor development.#1139
88f544dThanks @ask-bonk! - Upgradeskyselyto^0.29.0(was^0.27.0) to resolve three high-severity advisories fixed in>=0.28.17:JSONPathBuilder.key()/.at()sql.lit(string)Also updates import paths for
MigratorandMigrationtypes tokysely/migrationto comply with kysely 0.29 export changes.Updated dependencies [
02ed8ba,11b3001,fae97ee,88f544d,9a30607,d0ff94b]:@emdash-cms/plugin-embeds@0.1.16
Patch Changes
b9cc08e,02ed8ba,11b3001,fae97ee,88f544d,9a30607,d0ff94b]:create-emdash@0.15.0
@emdash-cms/gutenberg-to-portable-text@0.15.0
@emdash-cms/x402@0.15.0
@emdash-cms/fixture-perf-site@0.0.11
Patch Changes
02ed8ba,11b3001,fae97ee,88f544d,9a30607,d0ff94b]:@emdash-cms/perf-demo-site@0.0.11
Patch Changes
cf3c706,02ed8ba,11b3001,fae97ee,88f544d,9a30607,d0ff94b,463c7a2]:@emdash-cms/cache-demo-site@0.0.11
Patch Changes
cf3c706,02ed8ba,11b3001,fae97ee,88f544d,9a30607,d0ff94b,463c7a2]:Try this PR
Open a fresh playground →
A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.
Tracks
changeset-release/main. Updated automatically when the playground redeploys.