emdash@0.23.0
Minor Changes
- #1349
bd6cc3aThanks @MA2153! - Breaking: generated TypeScript interface names inemdash-env.d.tsnow derive from the collection slug (singularized) instead oflabelSingular. This fixes invalid identifiers (labels with spaces/punctuation) and duplicate identifiers (two collections sharing a label), while keeping names singular so each interface reads as a single entry (slugposts→Post,blog_posts→BlogPost). Interfaces are renamed wherever the old label-derived name differed from the slug. Users should regenerateemdash-env.d.ts(emdash typesor dev-server start) and update any direct interface references in their code.
Patch Changes
-
#1593
b4d7228Thanks @ascorbic! - Fixes the admin stylesheet leaking onto public routes inastro dev. The compiled Kumo/Tailwind theme was injected into every page's<head>, overriding host:roottokens (--text-base,--text-lg, ...) and styling otherwise-unstyled pages. The admin shell now loads its stylesheet as a route-scoped<link>, so public routes are unaffected — matching production behaviour. -
#1625
d74269dThanks @ascorbic! - Resolves the database connection at use-time for the cron sweep, plugin hook contexts, and media providers instead of capturing it once at startup. This makes scheduled publishing, plugin cron, and database-querying plugin hooks work on connection-backed adapters like Postgres over Cloudflare Hyperdrive, where a connection is bound to the event that opened it. Stateless adapters (D1, Node SQLite) are unaffected. -
#1617
e39984fThanks @ascorbic! - Cuts cold-start latency by batching runtime initialization reads into a single round trip. On a fresh isolate (or Worker), the auto-seed check, plugin-state load, and site-info load now run as one batched query on backends that support it (Cloudflare D1, Durable Objects) instead of several serialized round trips. On D1 this roughly halves runtime init time on cold start. Other backends (Node/SQLite) are unaffected. -
#1559
280b877Thanks @marcusbellamyshaw-cell! - Fixes the editor toolbar leaking into a shared cache (#1398). When a logged-in editor browsed the public site behind a shared cache (such as Cloudflare), responses carrying the injected toolbar could be cached and then served to anonymous visitors, exposing the toolbar markup and the fact that a session was active. Toolbar-bearing responses are now markedCache-Control: private, no-storeso they are never shared-cacheable; responses without an injected toolbar keep their original caching. -
#1553
7fca12fThanks @marcusbellamyshaw-cell! - Byline avatar hydration now includes the media LQIP placeholder fields (#1457). Content byline credits already folded in the avatar'savatarStorageKeyandavatarAltvia the media join, but dropped theblurhash/dominant_colorplaceholder columns, so author avatars couldn't render a low-quality image placeholder while loading even though the media stored one.BylineSummarynow also carriesavatarBlurhashandavatarDominantColor, populated bygetContentBylines,getContentBylinesMany, andfindByUserIds(and surfaced in the byline API response), so themes can paint a blurhash/dominant-colour placeholder for byline avatars exactly as they can for other media. -
#1613
fd077e0Thanks @scottbuscemi! - Fixes a build failure in theEmDashMediacomponent. The component-embed branch contained HTML comments (<!-- ... -->) inside a JSX expression, which the Astro compiler rejects with "Unexpected token", breaking every productionastro buildand returning 500s in dev on any page that renders media. The note is now a JSX comment. -
#1389
9ebb47eThanks @nanangdev! - Fixesemdash export-seed --with-content=allso it exports content from every collection, matching the documented behaviour. Previously the literal string"all"was treated as a collection name and matched none, producing an emptycontentblock. The bare flag and--with-content=truewere the only sentinels honoured. -
#1616
8c7bc81Thanks @MA2153! - Fixes plugins declaring themedia:writecapability receiving a read-onlyctx.mediawith noupload(). The plugin context only granted a writable media surface when an internal upload-URL provider was wired, which the runtime never supplied — soctx.media.upload()was alwaysundefined. Write access is now granted whenever storage is configured (allupload()needs), andgetUploadUrl()is derived from storage when no provider is set. Amedia:writeplugin on a site without storage now logs a warning instead of silently degrading to read-only. -
#1555
55613e1Thanks @marcusbellamyshaw-cell! - Plugin route handlers that callctx.request.json()(or.text(),.formData(),.arrayBuffer(),.blob()) now get a clear error pointing them toctx.inputinstead of the runtime's cryptic "Body has already been read" failure (#1293). EmDash parses the request body once before the handler runs and exposes it asctx.input, leavingctx.request's stream consumed; the request handed to handlers now guards those body-reading methods with an actionable message. All other request members (url,method,headers,signal, …) are unaffected. -
#1396
c5f58b9Thanks @nanangdev! - fix: render text alignment from rich-text editor end-to-end (#1201)The previous fix in
text-align-round-trippatched only thepackages/core/src/content/converters/pair but the rich-text editor saves through two other ProseMirror ↔ Portable Text converters that each carried their own copy of the same logic — so reporter and maintainer kept seeing alignment dropped on save:packages/admin/src/components/PortableTextEditor.tsx(admin save path)packages/core/src/components/InlinePortableTextEditor.tsx(in-page inline editing)
Both now forward
node.attrs?.textAlignfor paragraphs and headings (onlycenter,right,justify—leftis the editor default and is omitted so existing content stays byte-identical) and restore it on the reverse path. Each editor's localPortableTextTextBlockinterface gained thetextAlign?: "left" | "center" | "right" | "justify"field, mirroring the type inpackages/core/src/content/converters/types.ts.The Portable Text frontend renderer now emits a WordPress-style
has-text-align-{value}class on the rendered<p>/<h1..h6>/<blockquote>whenever the block carriestextAlign. A newBlockcomponent is added underemdash/uifor callers composing custom Portable Text components who want to keep the EmDash behaviour. The class allowlist is enforced viaObject.hasOwn, so a hostile or hand-edited Portable Text block cannot inject arbitrary class names.Consolidating the three duplicated converter pairs into a single shared module is a follow-up refactor and intentionally out of scope here.
-
#1619
c056060Thanks @ascorbic! - Speeds up content reads by fetching each entry or collection together with its author bylines and taxonomy terms in one database query instead of three. This cuts time-to-first-byte on hosted databases like D1 where every query is a network round trip. -
#1406
c43c412Thanks @SailingGreg! - Honor image alignment from WordPress imports at render and in the editor, and surface display-size controls for migrated images.The Gutenberg to Portable Text importer already captured image
alignment, but it was dropped by the renderer and not editable.Image.astronow emitsemdash-image--align-*classes (left/right float, center, wide/full), the admin editor threadsalignmentthrough the PortableText/TipTap serializer and image node and adds an alignment control that reflects in the node view, and the Display Size panel now shows for migrated images that carry only display dimensions. -
#1614
b5ea8e7Thanks @scottbuscemi! - Fixes request-scoped database adapters that hold a real connection (e.g. Postgres over Cloudflare Hyperdrive) so they work on Workers.locals.emdash.dbis now resolved lazily, so routes get the per-request connection instead of a snapshot of the shared singleton, and a request-scoped connection is now closed only after the response body finishes streaming rather than before — Astro streams HTML while components still query, so closing earlier broke server-rendered pages. No effect on D1 or other stateless bindings. -
#1396
c5f58b9Thanks @nanangdev! - fix(core/converters): persist text alignment from rich-text editor through ProseMirror ↔ Portable Text round-trip (#1201)prosemirrorToPortableTextnow readsnode.attrs.textAlignfor paragraphs and headings and forwards it into the Portable Text block.portableTextToProsemirrorrestores it back into ProseMirror node attrs. ThePortableTextTextBlocktype gained an optionaltextAlign?: "left" | "center" | "right" | "justify"field. Left alignment is not persisted (it is TipTap's default and would bloat existing content). -
Updated dependencies []:
- @emdash-cms/admin@0.23.0
- @emdash-cms/auth@0.23.0
- @emdash-cms/gutenberg-to-portable-text@0.23.0