---
changelog:
  category: Release
  version: blume@2.1.1
date: '2026-10-03T03:37:15Z'
seo:
  description: >-
    The Algolia sync no longer fails on long pages. Algolia caps a record at 10
    KB on its Build and Grow plans and rejects the whole upload when one page's
    record…
title: blume@2.1.1
type: changelog
---
## Patch Changes

- 579ae91: The Algolia sync no longer fails on long pages. Algolia caps a record at 10 KB on its Build and Grow plans and rejects the whole upload when one page's record is larger, so the sync now splits a longer page into several records, each carrying the page's title, description, and URL with a stretch of its text. It sets the index's `attributeForDistinct` to `url` (unless you set your own), so a split page appears once in results, at its best-matching record.
- dc89029: On hand-written API pages, an optional body field with no `default` or `placeholder` now starts empty in the Try it panel and stays out of the request samples, instead of being sent as `"string"`, `0`, or `true`.
- 29abb61: The assistant route now exposes `Retry-After` to the origins listed in `ai.assistant.cors`, so a page on another site can read how long to wait after a `429` from the rate limit. Browsers hid the header from cross-origin callers before.
- 05b0acf: The assistant keeps a question asked outside the docs, such as from the homepage or another site, to one language. It searched every translation before, so on a translated site the translations of each page crowded out the answer. Retrieval and the assistant's own searches now keep to the locale the page's URL names (`/ja`), or the default locale.
- 3ea55bb: Long conversations with the assistant keep working. The panel sent the whole conversation with every question, and once it passed the route's 24,000 characters or 40 messages, every answer failed. It now sends the latest turns that fit, dropping the oldest first; the reader still sees the whole conversation. `useAssistant` does the same.
- 075d362: Update `@astrojs/react` to 7. Its `babel` option is gone, so the React Compiler now runs on Oxc (`oxc-transform-react`) instead of Babel (`babel-plugin-react-compiler`). It still ships with Blume and stays on by default; `react: { compiler: false }` still turns it off.
- 9772956: AsyncAPI `kcat` samples now follow the Kafka bindings and the server's security. A channel binding's `topic` replaces the channel address, a message binding's `key` keys the message (`key|payload` with `-K '|'`), and a server that declares a SASL scheme adds the `-X` settings librdkafka needs, reading the credentials from `$KAFKA_USERNAME` and `$KAFKA_PASSWORD`, with TLS for `kafka-secure`. When a channel's servers declare different security, the Authorization section names the servers each scheme applies to and those that need none, instead of marking every scheme required everywhere.
- cf1f04a: `blume audit --url` now requests each configured redirect's old URL on the live site and reports `BLUME_AUDIT_REDIRECT_NOT_SERVED` when it isn't redirected to the configured destination: an error when the old URL fails, and a warning when the host serves the build's meta-refresh page instead of an HTTP redirect.
- 4561f51: `blume audit` no longer says a page always wins over a redirect configured from the same path. Which one readers get depends on the host, so the finding and its fix now say so.
- 6c7a96e: `blume audit` now reads every `User-agent` group in robots.txt, not only `*`, and warns with `BLUME_AUDIT_ROBOTS_BLOCKS_CRAWLER` when a rule aimed at one crawler blocks it from pages the sitemap advertises.
- a0041e5: `blume audit` no longer reports a full URL on the site's own host but outside `deployment.base` as a broken link: it names another app on that host, which is how the navigation docs say to link one.
- ed324f3: `blume audit` no longer says a page nothing links to (a `sidebar.hidden` page, say) is "reachable only from the sidebar", and the fix for an indexable page missing from the sitemap now mentions a `public/sitemap.xml` that replaces the generated one.
- 08b514f: The generated `/changelog` index's "No changelog entries yet." line is now a UI string (`changelog.empty`), translated in every built-in language pack and overridable under `i18n.ui`, instead of always showing in English.
- 605e65f: A new top-level `changelog` config sets the generated `/changelog` index's `title` and `description`, each a string or a per-locale map, so a site can rename its changelog without overriding UI strings under `i18n.ui`. They also title the index's OG card and its Markdown mirror.
- 2495c48: `--budget-js`, `--budget-css`, `--analyze`, and `blume audit` now read a `cloudflare()` server build with `base` set from `dist/client/<base>/`, where the adapter writes it. They read `dist/client` before, so a budget measured nothing and passed, and the audit reported every page's links and assets as broken.
- 351f29c: `contentful()` renders an embedded file that isn't an image, like a PDF, as a link to it instead of a broken image, and warns with `BLUME_SOURCE_UNRESOLVED_LINK` when a page embeds or links an asset or entry the Delivery API didn't return (an unpublished one, say) instead of dropping it silently. An embed of another entry of the same content type now resolves. New `host` and `previewHost` options reach a space with EU data residency, and `fields.order` on `contentful()`, `payload()`, and `strapi()` reads a page's sidebar order from a number field.
- 0d7a9dc: A `contentful()` rich text link to another entry of the source's content type now links to that entry's page, at the route it's built at (prefix, nested slug, and locale included). A link to an entry of any other content type still keeps only its text, and a link to an entry the Delivery API didn't return (an unpublished one, say) warns with `BLUME_SOURCE_UNRESOLVED_LINK`.
- 3e3e65f: `blume dev` now answers an exact redirect with its configured `status`, as the production outputs do, instead of a `301` for every redirect to a docs page.
- 2d13649: `blume dev` now watches the local spec and overlay files your API references read, so saving a spec updates its reference without restarting the server.
- e69a55e: `blume doctor` now reports a tab, selector item, featured link, header action, or call to action whose path matches no page (`BLUME_NAV_MISSING_PAGE`), the same warning `blume dev` and `blume build` print. It checks against every route the site serves, custom `.astro` pages, the generated changelog, and references included.
- c82742b: `codeSamples: []` on `openapi()` or `graphql()` now shows no generated code samples, like `codeSamples: false`, instead of falling back to the default cURL, JavaScript, and Python.
- 2dda5fe: EPUB export now names the site as the book's author and publisher and uses the page's language, instead of "anonymous" and English. Links to other pages point at the live site, and an image the browser can't fetch is left out with a console warning instead of failing the whole export.
- 7ab09df: `blume eval --agent claude` no longer loads your Claude Code settings files or `CLAUDE.md` into the reader and judge, the way Codex runs already skip your Codex config. Hooks, plugins, and memory could hand the reader context your docs never gave it. Your Claude Code login still works; set any other variables it needs, such as `ANTHROPIC_API_KEY`, in your shell rather than in `settings.json`.
- bec8930: `blume eval --agent claude` now runs the reader and judge with every Claude Code built-in tool turned off, so the reader has only the docs tools. Its list of blocked tools had fallen behind Claude Code, which left newer tools such as `Monitor` (which runs shell commands) and `Skill` (which loads your installed skills) available to it.
- 8dc7ed3: `blume eval --fix` now tells the agent to verify its edits with the same `--agent`, `--file`, `--threshold`, and `--timeout` the run used. It used to say a bare `blume eval`, which graded `evals.yaml` with Codex even when the run being fixed used Claude Code or another evals file.
- 35af3c6: A missed `severity: warning` question in `blume eval` now reads as the warning it is. Its line shows `⚠ warn` instead of `✖ fail`, the summary counts it as warned rather than failed, and its finding prints as a `⚠` line instead of a `fix:` line, matching the exit code, which already ignored it. Each question in the `--json` results now carries its `severity`.
- d5ef2f0: An exact redirect from a page's own URL now warns with `BLUME_REDIRECT_MATCHES_PAGE` in `blume validate`, `doctor`, `dev`, and `build`: the redirect takes the URL over, so the page never publishes. Before, only a pattern redirect was flagged.
- e09dcd4: `blume validate --external` and `blume audit --external` now fail a link only when it's dead: a 404 or 410, or a host name that doesn't resolve. A refused or dropped connection is a warning, like a timeout or any other error status, since it's more often the other site or the runner's network than the link. The finding also names the reason a request failed (`getaddrinfo ENOTFOUND …`) instead of Node's bare "fetch failed".
- b28119d: Frontmatter that isn't valid YAML, such as an unquoted value holding `: `, is now reported as `BLUME_FRONTMATTER_INVALID` at its file and line instead of failing `blume validate`, `doctor`, `audit`, `build`, and `dev` with `BLUME_INTERNAL`.
- c505dbe: `githubReleases()` takes a `baseUrl` for a repository on GitHub Enterprise Server, and tags a draft release it includes (with `drafts: true`) `Draft` instead of `Release`. An RSS item now falls back to the page's `seo.description`, so the releases feed describes each release with the summary of its notes.
- 4cda96b: GraphQL example variables start at each argument's declared default, so `first: Int = 20` is `20` rather than `0`, and input objects fill their fields' defaults the same way. Generated example queries and responses leave deprecated fields out.
  
  `graphql()` takes an `auth` option, in the shape of `api.auth` for hand-written endpoint pages: `{ method: "bearer" }`, `"basic"`, or `"key"` with the header `name` (`x-api-key` by default). With it, every operation page shows an Authorization section, the Try it panel gets a credential field, and the code samples send a placeholder credential. A per-source `auth` overrides the adapter's.
- 922d680: The `BLUME_INCLUDE_MALFORMED` suggestion no longer says only `lang` and `meta` attributes are read; it says attributes need lowercase names and quoted values, and that any other attribute is a prop.
- aa7539b: `blume init` now adds `.env.local`, where Blume says to put local secrets, to `.gitignore`.
- 86da6d4: `blume init`'s pnpm workspace note now says pnpm 11 and later stop the install over an unapproved esbuild build script; pnpm 10 only warns.
- 0a38c27: The MCP `search_docs` and `list_pages` tools now match a number or boolean in `filters` against the facet's string form, the way facet values are stored, so `{"priority": 1}` finds pages with `priority: 1`. Such a value used to be dropped, and the tool answered as if no filter had been sent.
- 12c2213: `mdxRemote()` fixes: `blume validate` resolves a link between remote files (`./02-errors.mdx`) to the page it publishes at instead of reporting it broken, a `!` pattern in `include` now excludes what it matches as it does for `filesystem()` instead of including every file, a `github.path` with nothing under it at the ref warns with `BLUME_SOURCE_PATH_MISSING`, and the `BLUME_SOURCE_TRUNCATED` warning no longer suggests narrowing `path`, which can't help.
- c8820c2: A Mermaid diagram that fails to parse now logs Mermaid's parser error to the browser console, and `blume dev` shows it under the "Could not render this diagram." message, so you can find the line to fix. Mermaid's "Syntax error in text" graphic no longer appears at the bottom of the page.
- f442afe: The `blume-migrate` skill's Docusaurus reference now replaces `<DocCardList />` and generated-index categories with a folder's `directory: "card"` listing, and turns an `id` that differs from its filename into a `slug`, so the page keeps the URL Docusaurus built from its ID.
- 2f798ce: The `blume-migrate` skill's Fumadocs reference now redirects URLs that lose a numeric filename prefix, hides the pages a `meta.json` `pages` list without `"..."` left out of the sidebar, maps `full: true` to `mode: wide`, and reads newer scaffolds: collections in `lib/source.ts`, a `baseUrl` constant, `components/mdx.tsx`, and the header title, GitHub link, and links in `lib/layout.shared.tsx`.
- 22c4f41: The `blume-migrate` skill now keeps a source's inline math inline, rewriting `$x$` as `$$x$$` inside its sentence. It used to treat inline math as unsupported and move each formula onto its own line or drop it, though Blume renders `$$…$$` inline.
- 449d11b: The `blume-migrate` skill's Nextra reference now moves a Nextra 4 default-locale folder (`content/en/`) up to the content root, keeps each page's heading as its `title` with the `_meta` label as `sidebar.label`, maps `layout: "full"` to `mode: wide`, and keeps `_meta` ordering in nested folders with `display: "group"`.
- b02e9a4: The `blume-migrate` skill's Starlight reference now carries `head` meta tags (site verification, `theme-color`, and the like) over to `seo.metatags` instead of dropping them.
- 74546a6: The `blume-migrate` skill's Starlight reference now reads the sidebar's `items: [{ autogenerate }]` shape from Starlight 0.39 on, carries Discord, X, and other social links over to `footer.socials`, maps a `Footer` override to Blume's `PageFooter` slot rather than the site footer, keeps per-fence `wrap`, and approximates splash pages with `mode: center`.
- 258a9aa: A `<Component path>` that names no example now gets a `BLUME_EXAMPLE_NOT_FOUND` warning at its line from `blume dev`, `blume build`, and `blume doctor`, instead of only a "No example found" box on the page. A `components.ts` override or island named `Component` replaces the built-in, so its `path` isn't checked.
- 1dd0e1e: Mixedbread search results now link to their pages. The endpoint read each result's link from metadata nothing sets, so every result pointed back at the current page; it now finds the page whose file `mxbai store sync` uploaded, shows that page's title, and lists each page once. When the search endpoint fails, the dialog shows its error message instead of "No results".
- ea6591b: With Mixedbread search, the search dialog now waits for the reader to pause typing before it sends a query, and cancels a query the reader has typed past. A search costs a request or a few instead of one per letter, which keeps readers under the search endpoint's rate limit, and a slow earlier response can no longer replace newer results. `useSearch()` and the WebMCP search tool still send each query at once.
- 3d96865: The Mixedbread search endpoint now checks `rateLimit` in `blume dev` and `blume build`, answering `429 Too Many Requests` past the limit. Only `blume eject` used to limit it.
- 458b6e6: `node()` takes `allowedDomains`, set as Astro's `security.allowedDomains`, for a server behind a reverse proxy. Astro only reads the reader's address from `X-Forwarded-For` for a host listed there, so every reader behind a proxy shared one rate limit count; with the proxy's host listed, each reader gets their own.
- 62c4ec8: OpenAPI 3.2 specs now render as written, and a `query` operation, for the HTTP `QUERY` method, gets a page, Try it, and code samples like any other method. The 3.2 additions Blume doesn't render yet, `additionalOperations` and `in: querystring` parameters, log a `BLUME_OPENAPI_UNSUPPORTED` warning instead of dropping out without a sign.
- 66abad4: An operation's Callbacks section now lists each callback's parameters, such as a signature header, beside its request body and responses. A 3.1 or later spec that still keeps its webhooks under `x-webhooks`, which renders none of them, now logs a `BLUME_OPENAPI_X_WEBHOOKS` warning that says to rename the field to `webhooks`.
- 8ac7650: An operation's own `x-codeSamples` now reach its Markdown copy, so `llms-full.txt`, the MCP server, and the assistant see your SDK calls, and site search indexes them like any code block. A sample whose `source` is a `$ref` to a file is read relative to the spec, and one that can't be read logs a `BLUME_OPENAPI_CODE_SAMPLE_REF` warning instead of disappearing.
- ac5b593: OpenAPI references now warn about spec mistakes that used to render wrong without a sign: a `{name}` in a path with no path parameter of that name (`BLUME_OPENAPI_PATH_PARAMETER_MISSING`), a path parameter the path never uses (`BLUME_OPENAPI_PATH_PARAMETER_UNUSED`), and a `security` requirement naming a scheme that `components.securitySchemes` doesn't define (`BLUME_OPENAPI_UNKNOWN_SECURITY_SCHEME`). The pages still build.
- cea759c: Page actions now show in windows narrower than 1,280px and on phones. Edit on GitHub, Copy as Markdown, Export, Open in chat, and Connect to MCP sit at the bottom of the "On this page" dropdown above the content, their menus opening in place, and that dropdown now shows on a page with no headings too. The actions render once per page and move between the right rail and that dropdown as the window crosses 1,280px. A `TableOfContents` layout override receives the place they move into as children of its `mobile` variant, so render a `<slot />` there to keep them.
- e6713a4: `blume build` with `pagefind()` now reports how many pages the search index holds. The "Indexed N page(s) for search" line used to count every HTML file in the build, including search-excluded pages, hidden pages, and the 404 page, which the index leaves out.
- b86f051: With `pagefind()`, search now follows a switch to another language. Pagefind read the page's language once, on the first search, so after picking another language in the switcher, which swaps the page without a reload, search kept returning results in the first language until a full page load.
- 904eb98: Pagefind search results now link to each page's own URL. They ended in a slash (`/quickstart/`), which Blume doesn't serve, so a host redirected every result and `blume preview` answered Not Found. With `deployment.base` set, they also carried the base twice (`/docs/docs/quickstart/`).
- 1b89b4e: API reference parameter tables and the Try it panel now show a parameter's description when the spec puts it on the parameter's schema, as Elysia and oRPC do. A description on the parameter itself still wins.
- 8bfb639: `payload()` now warns with `BLUME_SOURCE_UNSUPPORTED_NODE` when a page's Lexical body holds a node it leaves out as a comment, like a block with no serializer or a relationship, naming the page and the node, instead of dropping it without a word.
- 00ce3b9: The API playground's built-in proxy now checks `rateLimit` in `blume dev` and `blume build`, answering `429 Too Many Requests` past the limit. Only `blume eject` used to limit it.
- e12b668: Printing a page, or exporting it to PDF, now leaves out everything after the article (last updated, feedback, previous and next links, the site footer) and the buttons on code blocks, prints collapsed `expandable` code blocks in full, and prints a page read in the dark theme in the light one.
- f5151c7: A redirect from one page to another now moves the page's raw Markdown too: `/old.md` and `/old.mdx` redirect to `/new.md` and `/new.mdx` with the same status, in `blume dev`, the redirect files a static build writes, and every server build. They used to 404.
- c5f25f5: A reference source's `label` now names its sidebar group as written (`GitHub OAuth (v2)`, not "Github OAuth V2" from its route), and a reference's tag groups follow the spec's declared tag order in the sidebar, the same order as its overview page, instead of sorting alphabetically.
- 0dc7156: API reference schema tables now match the examples beside them: request body tables leave out `readOnly` properties, and response tables leave out `writeOnly` ones. A webhook's or callback's body, which your API sends, keeps its `readOnly` properties.
- 0ff3d0e: A `sanity()` body held in a Markdown string field now renders as Markdown instead of an empty page. A query that finds no documents while `SANITY_TOKEN` is unset now warns with `BLUME_MISSING_SECRET`, since a private dataset answers a query without a token with nothing rather than an error.
- 4562581: The site stylesheet now scans your project's `.jsx` files for Tailwind classes, as the theming docs say, so a class used only in a `.jsx` island is generated. Ejected apps scan them too.
- 2c6022a: The search dialog's "All languages" toggle now works with `pagefind()`: it merges every language's index into the search, where it used to return the page's language alone. With `mixedbread()`, which can't limit a search to one language, the dialog no longer shows the toggle, since every search already spans every language.
- fa68c94: Search analytics can keep query text away from your analytics providers. With `search: { analytics: { queries: false } }`, the `search` and `search_select` events carry the query's length as `queryChars` instead of its text, and the text travels only on the `blume:track` DOM event, the way the assistant handles questions. By default queries are still sent as typed.
- 7beba3e: Search now finds translations in a non-Latin script on a site whose default language is written in Latin script, such as the Japanese and Hindi pages of an English site. Each of those locales' pages is indexed with its own word-segmenting tokenizer, so the search dialog, the MCP server's `search_docs`, and the assistant match them, whether the search is scoped to one language or runs across all of them. Latin-script pages keep the tokenizer they had.
- 05a06e3: A failed search sync now fails the build when its admin key is set. Algolia, Orama Cloud, and Typesense syncs used to only warn when the upload failed, so a site could deploy against an index the build never updated; they now stop `blume build` with `BLUME_SEARCH_SYNC_FAILED`. Without the key (or, for Orama Cloud, without `indexId`), the build still warns and skips the sync, so a build without secrets keeps working.
- 55b417c: API references now read a field whose schema is an `allOf` with one member, the way drf-spectacular writes enums and nested serializers, as that member: it's labeled with the member's name or type instead of `object`, lists its allowed values, and the Try it panel gives it the member's type and choices. A model that points back at itself through such a wrapper no longer crashes the build.
- e47a621: The sitemap now leaves out a page whose `seo.canonical` names another URL, so following the duplicate-content fix no longer trips `BLUME_AUDIT_NON_CANONICAL_IN_SITEMAP`. An archived-version page whose own `seo.canonical` names itself stays listed.
- 2b14092: A content source's missing token or SDK is now reported as itself on a fresh build, instead of as `BLUME_SOURCE_FETCH_FAILED` with the API's error. `blume dev`, `blume build`, and `blume doctor` warn about unset variables before any source fetches, `notion()` and `contentful()` stop before their first request with `BLUME_MISSING_SECRET` when their token is unset, and a missing SDK fails as `BLUME_SOURCE_SDK_MISSING`.
- 3114c92: `BLUME_MDX_CURLY_ANCHOR` now also catches the spaced `{ #id }` and kramdown `{: #id }` heading anchors in `.mdx` pages, which fail the compile the same way `{#id}` does, and quotes the marker as written. Only the unspaced `{#id}` pins an anchor in `.md`.
- 00c4707: With fallbacks off (`fallbackLocale: null`), the language switcher no longer links to a translation that doesn't exist. A language the page isn't translated into is left out of the switcher, where it used to link to a 404.
- 492fdf2: `blume translate` no longer copies a page's `seo.canonical` into its translations. The canonical names the source-language page, so every translation used to canonicalize to it and drop out of search in its own language; a translation now gets the default canonical, its own URL.
- 68ed70d: The Try it panel's CORS message now names the right setting for the page it's on: `playground: { proxy: true }` on the `openapi()` or `graphql()` reference, or `api: { playground: { proxy: true } }` for hand-written API pages. It also says the proxy needs server output.
- 0ea988e: Typesense syncs no longer take search down while they run. Each `blume build` imports your pages into a new collection, then points an alias with your `collection` name at it and drops the collection it replaced, so searches keep reading the previous collection until the new one is complete, and a failed sync leaves it serving instead of leaving no collection at all. On the first sync, a collection that already has that name is replaced by the alias, and search keys scoped to the name keep working. The admin key needs to manage aliases as well as collections.
- 7d904d4: `typesense()` takes a `locale`, a two-letter language code such as `"ja"`, `"zh"`, or `"th"`. The sync then tokenizes the collection's searched text fields for that language, so a query in a script written without spaces matches words inside a run of text, not only at its start.
- ef2ebd4: Typesense results rank by relevance again. The dialog sorted by relevance in ten buckets and then by `search.boost`, which ranked pages inside each bucket by boost alone, so with equal boosts the best match could land behind weaker ones. It now sorts by relevance first and uses the boost to order results that match equally well.
- d4087e8: A `layout` override in `components.ts` whose key isn't a layout slot (a typo, or `footer` for `Footer`) now logs a warning that lists the slots, instead of being ignored silently.
- b780c28: Update dependencies: `@astrojs/vercel` 11.0.11, `@pierre/diffs` 1.5.1, `@scalar/astro` 0.4.26, `dompurify` 3.4.16, and `js-yaml` 5.4.2.
- d1668f0: `upstash()` rate limiting now counts a request and sets its window in one step. A window that ended mid-request could leave the reader's count with no expiry, which locked them out of that route for good; a count left that way now gets a window again on the reader's next request.
- 7790b31: `upstash()` takes `urlEnv` and `tokenEnv`, the names of the env vars its REST endpoint and token are read from, so a database added from Vercel's Marketplace works with the `KV_REST_API_URL` and `KV_REST_API_TOKEN` it sets: `upstash({ urlEnv: "KV_REST_API_URL", tokenEnv: "KV_REST_API_TOKEN" })`. `blume build` warns about the variables you name.
- 95ff53e: Add `--ignore <glob>` to `blume validate` and `blume audit`. With `--external`, an external link whose URL matches the glob is never requested or reported, so a placeholder domain, a local server, or a site that turns bots away no longer fails the check: `--ignore "https://api.acme.example/**"`. Repeat the flag for more patterns. Internal links are always checked.
- d0db71f: `blume validate` now checks every link form Markdown and MDX render, not only one-line inline links: reference-style links (at their `[label]: /target` definition), autolinks like `<https://example.com>`, links whose label wraps onto the next line, and lowercase HTML `<a href>` tags. An `<a href>` ships as written, so its relative path resolves against the page's URL, as a browser reads it, and no `basePath` is added to it.
- 6b7366b: `Accept: text/markdown` negotiation on a Vercel server build now reads media types in any case and honors q-values the way `blume dev` and Cloudflare do: `text/markdown;q=0` gets HTML, and so does a header that weighs `text/html` above Markdown. The prerendered 404's JSON twin negotiates the same way. When Markdown and HTML both carry a q-value below 1, Vercel's routing rules can't compare them and serve HTML. `blume dev` now sends `Vary: Accept` on the HTML answer at a negotiated URL too, not only on the Markdown one.
- 916861d: A `vercel()` server build with `base` set now serves the site under it. `@astrojs/vercel` ignores the base: it left the static files and routes at the root, so every page asset and server route 404'd, and its redirects came out as `^/docsold$` → `/docs/docs/new`. The build now moves the static files to `.vercel/output/static/<base>/` and the routes and redirects under the base.
