Repository navigation
emdash@1.2.0
Minor Changes
-
#3056
b92f2d6Thanks @emdashbot! - Adds anadmin.localesoption that limits the admin interface to the languages a site uses, which makes the admin bundle smaller.emdash({ admin: { locales: ["en", "de"] }, });
Only the listed languages are built into the admin and offered in its language switcher. Users whose preferred languages aren't listed see English.
enis always included as the fallback, even when the list leaves it out, soadmin: { locales: ["en-GB"] }still ships English alongside British English. A code the admin doesn't ship fails the build, and the error lists the available codes. Sites that don't set the option keep every language. -
#3877
5f69896Thanks @swissky! - Updates the admin user editor to show the name as read-only, with a hint to change it at the identity provider, when an external auth provider such as Cloudflare Access syncs names (the default). Previously the field looked editable, but the change was replaced on that user's next request. SetsyncName: falsein the provider config to make names editable again. -
#3744
1e275aeThanks @swissky! - Adds a Change domain dialog to Settings > General for moving a site to a new domain. Before it changes the Site URL, EmDash checks that the new domain serves the site. Links in emails and plugins, sitemaps,robots.txt, hreflang links, social image URLs, and canonical links set in the SEO panel then use the new domain. If the check can't reach the site, for example onlocalhostor behind a login, the dialog offers to store the address without the check.The Site URL field becomes read-only, and saving Settings > General no longer writes it. When
siteUrl,EMDASH_SITE_URL, orSITE_URLis set, the page names that address, which links in emails and plugins keep using.Passkeys only work at the address where they were created. After a move, keep signing in at the old address, or sign in at the new one with an email link and add a passkey there.
-
#3697
0742f27Thanks @swissky! - Adds alabelsprop to theCommentsandCommentFormcomponents fromemdash/ui/comments, so sites can translate the comment heading, member badge, Like button, form fields, submit button, and status messages. Keys you leave out keep their English defaults.Commentsnow formats comment dates in the page locale (Astro.currentLocale) instead of always usingen-US, and accepts alocaleprop to override it. Sites without Astro i18n routing still showen-USdates; passlocale="en-US"to keep the previous format on a localized site.After a successful submission,
CommentFormnow says "Comment published" when the comment is approved immediately and "Comment submitted for review" when it waits for moderation, instead of always showing "Comment submitted!". -
#3744
1e275aeThanks @swissky! - Adds an Email users action to Settings > General that tells every other active user where the site now lives. Each user gets an email with a button to the sign-in page at the configuredsiteUrl, or the Site URL when none is set, and a note that passkeys from the old address don't work there. The email does not sign anyone in. The action needs an email provider, passkey sign-in, and theusers:managepermission, and shows how many emails were sent and how many the provider rejected.The emails come from the new
POST /_emdash/api/settings/domain/notifyendpoint. It accepts signed-in sessions only and can be used 3 times per hour per site. -
#3827
373446fThanks @khoinguyenpham04! - Adds a video block to the rich text editor. Type/videoto choose a Media Library video or upload one. Closing the picker leaves an empty video block in place, which you can fill later by clicking it or dropping a video file on it. Video files dropped or pasted anywhere in the text also upload to the Media Library and appear where you dropped them. The video plays in the editor at the width of the text, with a caption field under it and Replace video and Delete video in its corner. A video's Used in tab in the Media Library lists the entries that use it in a video block.On the site,
Videofromemdash/uirenders thevideoblock as the browser's own player with its caption. Media Library videos play from your storage's public URL when one is configured, and need the block'sasset.url: a block without one renders nothing on the site, and the editor shows it as unplayable. A block whoseasset.providernames a media provider renders from that provider's embed. An empty video block is saved withoutassetand renders nothing.Uploads follow
maxUploadSize, 50 MiB by default. The admin's content security policy now allows media fromblob:andhttps:URLs (media-src 'self' blob: https:), as it already did for images. This lets the admin read a video's size before uploading it, and preview a video block whoseasset.urlis on another site. Before, videos uploaded from the admin in production were saved without a width and height.What should I do?
- If a plugin already defines a
videoblock, the editor keeps using the plugin's block: it doesn't offer the built-in Video block, and dropped video files aren't uploaded. On the site, the plugin's renderer still wins; a plugin without one getsVideofor blocks that have only the built-in fields. In TypeScript, narrowingPortableTextBlockon_type === "video"now givesPortableTextVideoBlock | PortableTextUnknownBlock, so reading the plugin's own fields needs a check. - If you edit Portable Text with
portableTextToProsemirrorandprosemirrorToPortableTextfromemdashin your own TipTap editor, add avideoBlocknode with the attributessrc,mediaId,provider,caption,widthandheightto its schema.portableTextToProsemirrorturns every built-in video block into that node, and a schema without it can't load the document. - The media usage API and
emdash/clientcan now return the reference type"portable_text_video"for a video used in a video block. Code that checks every reference type, or validates the list, needs to accept it. - With Astro's content security policy turned on and media on another host, allow that host in
media-src.
- If a plugin already defines a
-
#3875
0a17191Thanks @swissky! - Adds asyncNameoption to external auth providers such as Cloudflare Access. By default, EmDash still replaces a user's name with the provider's name on every authenticated request, so a name edited in the admin is restored on that user's next request. SetsyncName: falseto keep names edited in the admin; the provider's name is then used only when the user is first provisioned.auth: access({ teamDomain: "myteam.cloudflareaccess.com", syncName: false, }),
-
#3773
e6fe5d4Thanks @khoinguyenpham04! - Adds numbered pages to every collection list in the admin. The All and Trash tabs load one page of entries at a time, so a collection opens with 20 entries instead of fetching 100, and both tabs use the Media Library's pagination footer pinned to the bottom of the screen: the entry range, 20, 50, or 100 entries per page, and controls to jump to any page. The Trash badge counts every trashed entry instead of stopping at 50, and every trashed entry is reachable.Selections persist across pages. Changing the search, a filter, the locale, or the collection clears them.
GET /_emdash/api/content/{collection}andGET /_emdash/api/content/{collection}/trashaccept a 1-basedpageparameter instead ofcursor. A numbered page returnstotaland nonextCursor, and sending bothpageandcursorreturns a400validation error. Cursor pagination is unchanged.ContentListaccepts optionalpaginationandtrashPaginationprops for numbered pages; without them it behaves as before. -
#3744
1e275aeThanks @swissky! - Adds a Continue on button to Settings > General after a site moves to a new domain. Passkeys only work at the address where they were created, so a user signed in at the old address can select the button to sign in at the new one without email. The single-use link expires after 5 minutes and opens Settings > Security, ready to add a passkey for the new address. The button appears when you are signed in at an address other than the Site URL, or the configuredsiteUrlwhen one is set. It is not shown when an external provider such as Cloudflare Access handles sign-in.The link comes from the new
POST /_emdash/api/auth/handoverendpoint, which accepts signed-in sessions only and allows 5 links per user every 5 minutes.GET /_emdash/api/settings/domainnow also returnssiteOrigin, the address the link points to.@emdash-cms/authexportscreateMagicLinkUrl(), which creates a single-use sign-in link without sending an email.
Patch Changes
-
#3781
d22f62fThanks @emdashbot! - Fixes locally stored images being served as unoptimized originals on sites that set their public origin withEMDASH_SITE_URLorSITE_URLinstead ofsiteUrl, such as Node.js deployments behind an HTTPS reverse proxy. The variable must be set whenastro buildruns; a value set only in the runtime environment does not enable image optimization. -
#3767
04a3d8dThanks @danielmlr! - Fixes API token "Last used" dates and the cleanup of expired authentication and rate-limit records on Cloudflare Workers, where the Worker could stop before these writes finished. These writes now finish after the response is sent, and a failure is logged instead of ignored. -
#3753
36b46d9Thanks @emdashbot! - Fixes scheduled 404-log cleanup to run only when the table has grown past its cap. The check uses a bounded sample, so most cron ticks no longer scan the entire_emdash_404_logtable when there is nothing to evict. This prevents the per-minute cleanup from consuming a large D1 row-read budget for tables that are below the limit. -
#3762
f09797cThanks @danielmlr! - Fixes WordPress imports turning tables in Classic editor posts into a single paragraph. Tables whose cells hold only text now import as tables, keeping their rows, header row, formatting and links. Tables with images, headings, lists or merged cells, with a caption or footer rows, or inside a<div>or<figure>keep their previous output.gutenbergToPortableText()also setshasHeaderRow: trueon tables whose first row holds only<th>cells. -
#3802
cd21162Thanks @DiogoDuart3! - FixesgetEmDashCollection()returning published content in edit mode and preview, whilegetEmDashEntry()returned the draft. Lists now show each entry's draft revision to editors in edit mode, and the draft of the previewed entry to a preview link, so inline edits made on a list page no longer appear to revert after saving and previews of list pages show the changes. Other entries in a preview, and all public requests, still get published content. -
#3631
e3a9de3Thanks @DavidPivert! - Fixescomment:afterCreatehooks being cut short on Cloudflare Workers. The hooks for a new comment ran as fire-and-forget work that the host did not keep alive, so they could be cancelled as soon as the response was sent. Sandboxed plugins, which call back into the host for settings and email, were stopped at their first call and never ran: a plugin that emails admins about new comments sent nothing. These hooks now run through the host'swaitUntil, after the response, until they finish. -
#3381
5b01664Thanks @swissky! - Fixes comment listings so a fractionallimitno longer fails with a 500. The page size is rounded down to a whole number on the public comments endpoint, the moderation inbox, and plugin comment reads, and a non-numericlimituses the default of 50. -
#3785
4b2b6e4Thanks @emdashbot! - Fixesplugin:installandplugin:activatenever running for plugins registered in thepluginsarray ofastro.config.mjs, so setup such asctx.cron.schedule()inplugin:activatenow takes effect.Each plugin's hooks run once, when the site first starts with that plugin. On existing sites, this happens on the first start after upgrading for every plugin in
pluginsthat you have never enabled, disabled, or changed MCP access for in the admin. Aplugin:installhook that is not safe to run on a site where the plugin is already in use will run then, so check your plugins before upgrading.If either hook throws, EmDash logs the error and disables the plugin instead of retrying on every start. Re-enable it from the Plugins page after fixing the problem; this runs
plugin:activateagain. -
#3930
47cb798Thanks @ryofukutani! - FixesPUT /_emdash/api/content/{collection}/{id}so a save that carries_revcan no longer overwrite a change another writer saved while the request was being processed. The token was checked once against the first read of the entry, and a save that landed before the entry was read again for the write went unnoticed. The version used by the write is now checked against_revas well, and a mismatch returns409 CONFLICT. Saves without_revare unchanged. -
#3911
c4e6737Thanks @emdashbot! - LoadEMDASH_ENCRYPTION_KEYfrom the project.envintoprocess.envduringastro dev. This lets freshly scaffolded Node.js sites save plugin settings declared withtype: "secret"without first exporting the.envfile into the shell. Existing environment variables are honored and never overwritten; other EmDash variables are not copied so that.envvalues intended for production do not override generated dev values. -
#3744
1e275aeThanks @swissky! - Fixes email links pointing to the address a site was set up on after it moved to a new domain. Sign-in, invitation, self-signup, recovery, and comment notification emails now use the Site URL from Settings > General whensiteUrl,EMDASH_SITE_URL, orSITE_URLis not configured, and fall back to the setup address when the field is empty. Only the origin of the Site URL is used, and it must usehttps://unless the host is a loopback address. A configuredsiteUrlstill takes precedence.emdash export-seedno longer copies the Site URL into the seed.If you don't configure
siteUrland the Site URL field holds an address that doesn't serve this site's admin, for example an old domain, links in these emails point there after upgrading. Check the field before upgrading; clearing it restores the previous behavior. Seeds that setsettings.url, including seeds exported by earlier versions, still fill in the Site URL, so removeurlfrom a seed copied from another site before using it. -
#3920
709dbf4Thanks @emdashbot! - Fixesemdash typesso the generated.emdash/types.tsimportsBylineSummary,ContentBylineCredit, andTaxonomyTermalongsidePortableTextBlock.Previously the CLI downloaded TypeScript definitions whose collection interfaces referenced these three names but only imported
PortableTextBlock, causingtscto reportTS2304errors for every collection. -
#3591
038e322Thanks @emdashbot! - Fixes the visual editor stripping superscript and subscript formatting from Portable Text fields on save, and adds superscript and subscript buttons to its formatting menu. A field that contains formatting the visual editor can't represent now shows a message instead of opening for editing, so editing on the page no longer silently removes that formatting. -
#3736
b9613bdThanks @emdashbot! - Fixes thecore:recent-postswidget so it shows each post's publication date and thumbnail. Dates use the page's locale and the site's configured timezone, falling back to UTC when the timezone setting isn't recognized. The widget doesn't apply thedateFormatsetting; dates always use the locale's long format, such as "October 1, 2026" in English. Thumbnails render at up to 96 pixels wide instead of at full size. -
#3731
6cf612cThanks @emdashbot! - FixesdecodeSlug()so malformed percent-escaped slugs returnundefinedinstead of throwing, letting[slug]pages fall through to their 404 handling. -
#3941
8450114Thanks @swissky! - Fixes installing and updating registry plugins whose releases were attested withactions/attest-build-provenancev3, including releases from the workflow thatemdash-plugin release setupgenerates. These installs previously failed with "release provenance could not be verified". Provenance in both GitHub formats is now accepted, and releases built on self-hosted runners are still rejected. -
#3851
3bcd2cbThanks @Zahid09987! - Adds Indonesian translations for the site domain-change flow, general settings screen, marketplace capability labels, and visual-editing toolbar strings. -
#3746
9ee7415Thanks @keybits! - Fixes in-page visual editing removing the link and alignment from Portable Text images. Saving any edit to a Portable Text field from the page no longer turns linked images into plain images or resets left, right, center, wide, and full alignment. -
#3795
36aee2dThanks @DiogoDuart3! - Fixes the content editor failing to open any entry with a date field when the site timezone setting is not a valid IANA timezone (for exampleLisboainstead ofEurope/Lisbon). The editor now falls back to UTC for such a value instead of crashing, and the settings API and MCP settings tool reject an unrecognized timezone with a validation error. A site that already stores one can still save its other settings, and can fix the timezone in Settings > General. -
#3922
da088aaThanks @swissky! - Fixesentry.idsometimes missing the locale prefix on multilingual sites. With several locales configured, entries in a locale whose URLs are prefixed get anentry.idsuch asen/my-post. With a Cloudflare database (D1, Durable Object SQL or Hyperdrive), in production and inastro dev, the prefix could be missing, depending on what else had already run in the same isolate, so the same entry returnedmy-poston some requests anden/my-poston others. Collection queries,getEmDashEntry()and referenced entries now always include the prefix.If your templates add the locale to links themselves, for example
/en/posts/${entry.id}, or passentry.idtogetEmDashEntry(), useentry.data.sluginstead, which never includes the locale. -
#3828
609c912Thanks @khoinguyenpham04! - Fixes videos served from/_emdash/api/media/file/not playing in Safari and on iOS, and not seeking past the buffered part in other browsers. With the local, S3, and R2 storage adapters, the media route answersRangerequests with206 Partial Content, or416 Range Not Satisfiablefor a range past the end of the file, and sendsAccept-Ranges: bytes.Custom storage adapters can serve ranges by accepting the optional
options.rangeargument todownload()and settingrangeon the result, as described in the storage interface docs. Adapters that ignore the argument still work: range requests to them receive the whole file, or416for a range past the end of the file. -
#3914
a834e75Thanks @emdashbot! - Fixes admin media uploads skippingmedia:beforeUploadandmedia:afterUploadplugin hooks. Plugins can validate, rename, change the file type, or cancel uploads before they are accepted, and receive a notification after a new media item becomes ready. Filename and type changes are validated; the upload size stays tied to the original client bytes. -
#3755
e2a07aeThanks @danielmlr! - Fixesemdash media upload --altand--caption, which reported a successful upload but saved neither value on the new media item. Direct uploads toPOST /_emdash/api/mediastore thealtandcaptionform fields. -
#3855
e8b61b3Thanks @emdashbot! - AddsETagandLast-Modifiedvalidators to media file responses and/imagetransforms, and returns304 Not Modifiedwhen a browser'sIf-None-MatchorIf-Modified-Sinceprecondition matches. This lets cached mutable media (images that can be replaced under the same storage key) be revalidated with a single header exchange instead of re-downloaded on every visit. Storage backends now reportlastModifiedwith downloads where available (local filesystem, S3-compatible, and R2). The shortpublic, max-age=0, must-revalidatecache lifetime for images is unchanged, so replacements still appear immediately. -
#3758
d0c7384Thanks @danielmlr! - Fixes the admin's new-entry form ignoring field default values: a boolean field withdefaultValue: truestarted switched off, and saving the entry untouched could store no value. New entries in the admin now start with each field's default value.Manifest field descriptors now include stored field defaults as
defaultValue, except for relation-bound reference fields. -
#3573
c3cc974Thanks @swissky! - Speeds up the first anonymous page views on each new server instance, such as a fresh Cloudflare Worker isolate, when migrations run automatically: the database setup check now runs at the same time as runtime startup instead of before it.When all migrations are already applied, a temporary database error during the startup migration check (for example a lost D1 connection) no longer blocks runtime startup on that instance for 30 seconds; the next request tries again. An error while pending migrations are being applied, or a migration lock left behind by a stopped instance, still pauses retries.
-
#3806
07f6f44Thanks @swissky! - Fixes collection sitemaps silently dropping entries beyond the first 50,000. Each/sitemap-{collection}.xmlnow holds up to 2,000 entries, ordered by entry ID instead of last update, and continues at/sitemap-{collection}-2.xml,-3.xml, and so on./sitemap.xmllists every page with its own last-modified date, and translations that land on different pages still list each other as hreflang alternates.What should I do?
Nothing, if search engines read
/sitemap.xmland you have not replaced the sitemap routes. For collections with more than 2,000 listed entries:- If you submitted a collection sitemap such as
/sitemap-post.xmldirectly to a search console, submit/sitemap.xmlinstead so search engines find every page. - If you replaced
src/pages/sitemap.xml.ts, add/sitemap-{collection}-{n}.xmlfor each further page of 2,000 entries. - If you replaced
src/pages/sitemap-[collection].xml.ts, handle the-{n}suffix in thecollectionparameter (for examplepost-2) and serve that page of entries.
- If you submitted a collection sitemap such as
-
#3546
2c8c12aThanks @swissky! - Addsgroupto plugin admin pages, in native plugin descriptors and inadmin.pagesofemdash-plugin.jsonc, to place them in collapsible admin sidebar folders. A page whose group matches the group of a collection shown in the sidebar appears inside that folder, after its collections and taxonomies. Pages that share any other group, from one plugin or several, fold into one folder in the Plugins section. Pages without a group stay where they are. -
#3602
82cea2cThanks @itaides! - Fixes trusted (in-process) plugin API routes dropping errordetails: a route that throwsPluginRouteError.badRequest(message, details), or whoseinputschema rejects the request, now returns those details in the JSON error body (error.details), so a form can show which fields failed. Unexpected errors still return only a generic message. -
#3741
4bc129cThanks @KirbyBT! - Fixes native plugin routes returning a genericINTERNAL_ERRORunderastro devwhen the handler throwsPluginRouteError, so the client receives the error's code, status, and message. -
#3744
1e275aeThanks @swissky! - Fixes plugins seeing an outdated site address inctx.site.urlandctx.url(). They now use the same origin as links in emails: the configuredsiteUrl,EMDASH_SITE_URL, orSITE_URL, then the Site URL from Settings > General, then the address the site was set up on. Previously plugins only saw the setup address, even whensiteUrlwas configured or the site had moved to a new domain. A changed Site URL reaches plugins after the server restarts or, on Cloudflare Workers, as new isolates start. -
#3776
9f389fbThanks @emdashbot! - Fixes pluginctx.storage.<collection>.getMany()anddeleteMany()failing on D1 withtoo many SQL variableswhen passed more than 98 ids. Both now accept any number of ids, in trusted and sandboxed plugins alike. -
#3931
9538600Thanks @danielmlr! - FixesparseApiResponsefromemdash/plugin-utilsrejecting with an error message that ends in a bare colon when a plugin route responds with an error page instead of an error message. The message is now the fallback message alone, without the HTTP status text, which browsers leave empty over HTTP/2 and HTTP/3. -
#3574
d8c6d64Thanks @swissky! - Speeds up the first request on a fresh Cloudflare Worker isolate for sites on D1 or Durable Object SQLite: runtime startup now loads the stored plugin provider selections (such as the active comment moderator) with its other startup reads, saving one database round trip. -
#3553
aa7cc95Thanks @swissky! - Stops the datetime normalization migration from printing an error-level[datetime migration] 0 noncanonical values …line on new sites and on upgrades with nothing to convert. When stored datetimes are rewritten, the migration still prints its report, now as an informational message. -
#1899
e9cf2c3Thanks @swissky! - Adds an optionalurlTemplateprop to thecore:recent-postswidget (e.g."/blog/:slug"or"/:slug"for catch-all routes), using the same:collection,:id,:slug, and:pathtokens as LiveSearch'srouteMap, with a localized label in the admin widget form. Without a template the widget links exactly as before. -
#3287
766aa29Thanks @danielmlr! - Fixes missing redirect hit counts and 404 log entries on Cloudflare Workers. The Worker could stop before these writes finished. It now stays alive until they complete, and a failed write is logged with a[emdash:redirects]prefix. -
#3943
f223ecdThanks @ascorbic! - Fixes publishing and installing registry plugins attested by a GitHub Actions reusable workflow in the same repository and ref as its calling workflow. These releases previously failed withPROVENANCE_UNVERIFIABLEbecause the caller and signer were treated as the same workflow. -
#3898
34f480eThanks @swissky! - Fixes Astro route rules caching responses that belong to one visitor. With a cache provider such ascacheCloudflare(), a page rendered for a signed-in user (for example a comment form showing their name and email) could be stored and served to anonymous visitors, and a catch-all rule such as/[...slug]could store EmDash admin API responses or anonymous401responses and serve them to other users.Responses rendered for a signed-in user, and responses sent with
Cache-Control: privateorno-store, are no longer stored in the route cache. This includes EmDash API responses such as/_emdash/api/search, so route rules no longer cache them. A page requested by a signed-in user is filled into the cache by the next anonymous visitor instead. -
#3559
f6ee57eThanks @khoinguyenpham04! - Fixes Select All inside code blocks in the admin and inline visual editors so it selects only the code instead of the entire document. -
#3861
9451267Thanks @emdashbot! - Fixes every-minute cron ticks exceeding the Workers Free CPU limit on cold isolates by running system cleanup once per hour instead of on every tick. The scheduled-publish sweep, cron tasks, and heartbeat still run each minute; bookkeeping cleanups now run only on the top of the hour. -
#3525
3d5a102Thanks @danielmlr! - Fixesemdash seed --no-contentapplying the seed's content entries, bylines, and taxonomy terms anyway. The flag now skips them as documented, so combining it with--on-conflict updateno longer overwrites existing entries.What should I do?
If a script uses the undocumented
--noContentspelling, switch it to--no-contentor--content=false.--noContentwas the only spelling that skipped content before this release. It is now ignored without an error, so the command applies the seed's content. -
#3857
0157a63Thanks @swissky! - Warns when a seed file'srepeaterfield has novalidation.subFields, or declares its sub-fields underfieldsinstead. Such a repeater previously seeded without any warning, and the admin then showed rows labelled "Item 1", "Item 2" with no inputs to edit.emdash seedprints the warning naming the field, andvalidateSeed()returns it inwarnings; the seed still applies as before. The setup wizard does not display seed warnings. -
#3672
064f46cThanks @masonjames! - Fixes seed validation accepting reserved collection and field slugs, such as a field namedversion.emdash seed --validateand the check that runs before a seed is applied now report the reserved slug, instead of the seed passing validation and then failing while it is applied. -
#3578
bafa475Thanks @swissky! - Warns whenemdash seed(including--validate) finds a widget that sets its options undersettings. Seeding ignores that key; widget options belong inprops. -
#3754
7f3093eThanks @danielmlr! - Fixes the setup wizard staying on "Loading EmDash..." on sites whose Astrosecurity.cspsetsscriptDirective.strictDynamic. The setup page now gets the same Content-Security-Policy as the rest of the admin. -
#3749
3bfd6fcThanks @danielmlr! - Fixes new sites created from a template keeping the template's site title and tagline instead of the ones entered in the setup wizard. Sites set up on 0.39.0 or later keep their stored values after upgrading; change them under Settings → General. -
#3595
1bad6d8Thanks @edrpls! - Fixes/sitemap-{collection}.xmlreturning 500<!-- EmDash not configured -->for names that are not valid collection slugs, such as the/sitemap-0.xmlthat crawlers request. These now return 404. -
#3750
4f967aeThanks @swissky! - Fixes blurry small images, such as avatars and icons, on high-density screens, and stops requesting high-density sizes larger than the original image.Media-provider images in
Imagefromemdash/ui, Portable Text images, and galleries now get asrcsetwith the rendered width and, up to 1920 pixels, a high-density candidate: twice the rendered width, or the original width when that is smaller. Before, provider images narrower than 320 pixels had nosrcsetat all, and other provider images could list widths larger than the original. Provider images shown at their original size, as gallery images always are, now also offer that original width, even above 1920 pixels.Imageapplies the same high-density candidate to media URLs from another origin, such as a public R2 bucket. -
#3889
d5b8b38Thanks @swissky! - Fixes assigning more than about 30 categories or tags to an entry on Cloudflare D1, and removing more than about 100 at once. These failed withtoo many SQL variables, whether from the admin, the content terms API, a plugin, or the WordPress import, which left such imported posts without any terms. -
#3681
cfc7e7dThanks @khoinguyenpham04! - Fixes stored cross-site scripting through the editor toolbar. EmDash inserted the toolbar before the first</body>in a response, but Astro leaves<and>unescaped in attribute values, so content such as an image's alt text could contain</body>and move the toolbar inside that attribute, turning the rest of the text into live markup. The editor toolbar, and the Cloudflare preview and playground toolbars, now go only before the closing body tag of a whole HTML document, never into server island or partial page responses.Before this fix:
- Unless a site set
toolbar: false, an Author's published content could run script for any signed-in Author, Editor, or Admin who viewed it, and a Contributor's draft could do the same to a signed-in Author, Editor, or Admin who previewed it. - With
toolbar: "client", published content could also run script for every visitor. - In preview Workers built with
createPreviewMiddleware, published content could run script for anyone who opened a preview link, whatever thetoolbarsetting.
- Unless a site set
-
#3823
f4dc955Thanks @emdashbot! - Fixes parameterized redirect patterns so URLs with a trailing slash match the same rule as URLs without one, consistent with exact and catch-all redirects. -
#3771
550e59bThanks @danielmlr! - Fixes the visual editing toolbar's Publish button switching to English after a save when the toolbar is shown in another language. The button now keeps its translated label, and the toolbar's status badges and image popover can be translated as well. -
#3756
ea88e8eThanks @danielmlr! - Fixes Publish in the visual editing toolbar publishing an older version when it is clicked while an inline Portable Text edit is still saving, which left that edit as unpublished changes. Publish now waits until every save on the page has finished. -
#3894
740de2bThanks @oddharsh! - Fixes theWebMcpSearchcomponent'ssearch_sitetool so agents can tell a failed search from an empty one. An empty query, an HTTP error or a network failure now fails the tool call, where it previously reached the agent as a successful result. Results now arrive as a JSON array of{ title, url, collection, excerpt }objects, without a JSON-encoded string nested inside. -
#3575
161ff98Thanks @swissky! - UpdatesgetWidgetAreas()to return areas in creation order (previously unspecified), and removes a database round trip from logged-out page loads on Cloudflare D1. -
#3896
f715431Thanks @swissky! - Fixes WordPress imports leaving links to the old site's uploads in place outside image blocks. After the media import, these URLs now also point to the imported media: cover backgrounds, file blocks, self-hosted audio and video, links in text and tables (for example to a PDF), buttons, and images and links in raw HTML blocks. Content imported before this fix is not changed. -
#3895
622a324Thanks @swissky! - Fixes scheduled WordPress posts being imported as plain drafts. The WordPress export file (WXR) import and the WordPress plugin import in the admin now schedule them for their original publish date. Posts whose scheduled date has already passed are still imported as drafts. Posts imported before this fix are skipped on a re-import, so schedule them from the editor or delete and import them again.The WordPress plugin import also reads post dates as UTC now. On Node servers running in a time zone other than UTC, imported created and modified dates were shifted by the server's offset.
-
Updated dependencies [
5c1ebc3,b92f2d6,5f69896,90f39e0,a17408f,f5406f8,1e275ae,f09797c,3787eb9,e63cc44,c77c6cf,395087d,bfd05b0,1e275ae,06a9146,373446f,1e275ae,24a4327,9f09f60,8885267,c07437f,b3e17f6,8450114,d1065a1,595fd15,392ade3,3bcd2cb,36aee2d,9538600,6d2a3bb,841a5b3,2210c2c,142da40,d72b615,2f59cc3,e6fe5d4,06a9146,d0c7384,e6fe5d4,b854616,2c8c12a,8867aba,2210c2c,e9cf2c3,f223ecd,f6ee57e,1e275ae,788a371,2881234,550e59b,8037f5a,dea8f58,c5cef43]:- @emdash-cms/admin@1.2.0
- @emdash-cms/gutenberg-to-portable-text@1.2.0
- @emdash-cms/registry-verification@0.3.4
- @emdash-cms/plugin-types@0.6.0
- @emdash-cms/auth@1.2.0
- @emdash-cms/blocks@1.2.0