Skip to content

v1.6.0

Choose a tag to compare

@cpojer cpojer released this 04 Nov 09:10
· 40 commits to main since this release
Immutable release. Only release title and notes can be modified.
  • Added routing.typedRoutes to check URL strings in links, navigation, and rewrites. Enabled by default in new Pages apps.
  • Added automatic aria-current and data-void-active indicators to Link, with activeMatch="prefix" for nested pages.
  • Added data-void-pending to Link while its destination is loading.
  • Added prefetch.defaultStrategy to configure a default prefetch strategy for every Link.
  • Improved Link prefetching to skip external URLs, respect data saver and 2G connections, and wait 300 ms before prefetching visible links.
  • Added { resolveOn: 'data' } to React router.visit() and router.refresh() to avoid deadlocks when awaiting navigation inside Actions or transitions.
  • Added a threading option to sendEmail() so replies sent later can stay in the same conversation.
  • Added rotating refresh tokens for connected apps, allowing access to be renewed without hourly sign-in prompts.
  • Added --runtime-logs minimal for self-hosted platforms to omit request URLs and log and exception messages from runtime telemetry.
  • Improved native Cloudflare deploys to serve static files and prerendered pages without Worker invocations when no server processing is needed.
  • Fixed page middleware breaking loader and action responses and dropping validator types.
  • Fixed query-only and relative navigation URLs resolving against the site root instead of the current page.
  • Fixed Vue Link types rejecting standard attributes and listeners such as target, download, and @click.
  • Fixed Svelte useForm() clearing errors written directly in an input handler.
  • Fixed action errors showing a generic status instead of the message from a plain-text 4xx response.
  • Fixed forms and actions scrolling to the top after updating the current page in place.
  • Fixed custom response headers in local development and native deploys without overriding private authentication cache policy.
  • Fixed missing Sandbox and Container Durable Object bindings in the dev server.
  • Fixed Markdown client scripts missing from production builds when no .island. file was present.
  • Fixed invalid Markdown frontmatter stopping the dev server. Errors now identify the affected file, and other pages keep working.
  • Fixed platform setup requiring DNS Edit permission when using an existing compatible DNS record.
  • Fixed resumed platform installations ignoring replacement runtime tokens and leaving already deployed Workers with old credentials.

Thanks to @0froq, @Dazzanova, @dvkam, @iPLAYCAFE-dev, @karthickeyan-dev, @morinokami, @serkodev, @sglyon, @ubugeeei, and @yangshun for their contributions!

New Features

Typed Routes

New Pages apps enable typed route URLs automatically. To enable them in an existing app:

// void.config.ts
import { defineConfig } from 'void/config';

export default defineConfig({
  routing: { typedRoutes: true },
});

TypeScript then checks URL strings passed to Link, router methods, and c.rewrite() against your app's routes.

Checked URL strings

Active and Pending Links

Style the current page and a navigation in progress with CSS:

a[data-void-active] {
  font-weight: 600;
}

a[data-void-pending] {
  opacity: 0.6;
  transition: opacity 0.15s 0.1s;
}

Use activeMatch="prefix" to keep a section's link active on nested pages:

<Link href="/users" activeMatch="prefix">Users</Link>

Active links · Pending links

Prefetch Defaults

Configure prefetching once in your framework adapter:

voidReact({ prefetch: { defaultStrategy: 'hover' } });

The same option works with voidVue, voidSvelte, and voidSolid. Individual links can override it:

<Link href="/reports" prefetch="visible">Reports</Link>
<Link href="/exports" prefetch={false}>Exports</Link>

Visible links wait 300 ms before prefetching. Automatic prefetching skips when the browser reports data saver or a 2G connection.

Prefetching

Awaiting Navigation in React Actions

Pass resolveOn: 'data' when awaiting navigation inside a React Action or transition:

startTransition(async () => {
  await saveUser();
  await router.refresh({ resolveOn: 'data' });
});

This lets the Action finish once page data is ready, allowing React to commit the update.

React navigation completion

Email Threading

Save an incoming message's ID and use it when sending a reply later, such as from a queue job:

await sendEmail({
  to: ticket.from,
  subject: `Re: ${ticket.subject}`,
  text: 'We fixed it.',
  threading: { inReplyTo: ticket.messageId },
});

Reply later

Connected-App Refresh Tokens

Connected apps can renew access by posting grant_type=refresh_token and their refresh token to /oauth/token, using HTTP Basic client authentication.

Connected apps

Minimal Runtime Logs

Choose minimal logging when installing or upgrading a self-hosted platform:

void platform install --runtime-logs minimal
void platform upgrade --runtime-logs minimal

Runtime logs

Upgrade Guide

Form types are stricter in this release:

  • Form status fields are read-only, and form.data and form.errors cannot be replaced. In React and Solid, update fields through the form methods. Vue and Svelte continue to support editing data and errors in place.
  • Island form errors are now typed as string | undefined. Check that an error exists before using it.
  • Svelte useIslandForm() now infers field types from its defaults. Annotate defaults that need a wider type, such as null as File | null.