Skip to content

fix(void): answer Astro dev triggers in apps that have their own middleware - #434

Merged
Brooooooklyn merged 1 commit into
mainfrom
fix/astro-dev-triggers
Oct 15, 2026
Merged

Brooooooklyn merged 1 commit into
mainfrom
fix/astro-dev-triggers

Conversation

@Brooooooklyn

Copy link
Copy Markdown
Member

Problem

The jobs guide says /__void/scheduled and /__void/queue work in astro dev. Void adds them through a generated src/middleware.ts. When the app already has its own middleware, Void cannot write that file:

astro dev, app has src/middleware.ts
  POST /__void/scheduled ──▶ Astro ──▶ 404
  warning ──▶ "see the setup docs" (no Astro steps there) + a paste-in snippet that never prints

A safe paste-in snippet is not possible: it would import .void/dev-triggers.ts, which exists only in dev and holds the dev trigger token.

What this PR changes

astro dev
  ├─ app has no middleware      ──▶ generated src/middleware.ts (unchanged)
  ├─ app has its own middleware ──▶ dev-only wrapper around @astrojs/cloudflare/entrypoints/server
  │                                 answers /__void/scheduled and /__void/queue before Astro
  └─ own middleware + custom Worker entry that calls handle() from @astrojs/cloudflare/handler
                                ──▶ warning: call fetch() on the default export of
                                    @astrojs/cloudflare/entrypoints/server to use the endpoints
astro build ──▶ never imports the dev dispatch file (no token in the build)

The wrapper is the one Void already uses for the PostgreSQL and MySQL request scope. D1 apps get it only in dev and only when they have their own middleware.

Decisions

Topic Decision
Keep the middleware writer Yes, for apps without middleware. A custom Worker entry that calls handle() never loads the server entry, so the writer is the only path that works for it.
Leftover src/middleware.ts from a killed dev process Treated as app middleware; the wrapper still answers the triggers. No new cleanup.

Known limits

  • An app with its own middleware and a custom Worker entry still has no dev trigger endpoints. The warning says what to change.
  • Only .ts middleware files are detected, the same as main.

Testing

Check Result
astro.test.ts D1 dev block New /__void/scheduled check through the generated middleware; fails with the writer turned off
astro.test.ts PostgreSQL dev Trigger through the wrapper, with app middleware
Wrapper unit tests dev vs build output, request scope per dialect
vp run build:all, vp run check, vp lint, vp fmt --check pass
vp run test 485 files pass

🤖 Generated with Claude Code

https://claude.ai/code/session_0123r5HnanmW2VUrZ7VWDufH

…leware

Void adds the dev trigger endpoints to Astro through a generated
src/middleware.ts. When the app already has its own middleware, Void cannot
write that file, so /__void/scheduled and /__void/queue returned 404 and
the warning linked to setup steps that do not exist.

For those apps, Void now answers the endpoints in a dev-only wrapper around
Astro's Cloudflare server entry. Apps without middleware keep the generated
file. An app with its own middleware and a custom Worker entry gets a
warning that says what to change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123r5HnanmW2VUrZ7VWDufH
@cloudflare-workers-and-pages

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://fix-astro-dev-triggers-void-cloud.voidzero-docs.workers.dev (commit f3f302f)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://945930dd-void-cloud.voidzero-docs.workers.dev f3f302f 2026-10-15T05:21:58.500Z Visit the dashboard ↗

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T05:24:10.064976Z f3f302f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Brooooooklyn
Brooooooklyn merged commit e21421f into main Oct 15, 2026
34 checks passed
@Brooooooklyn
Brooooooklyn deleted the fix/astro-dev-triggers branch October 15, 2026 05:49
Brooooooklyn added a commit that referenced this pull request Oct 15, 2026
…hed (#433)

## Problem

The pre-release review found 46 places where Void promised something
that the code did not do. The promise was in the docs, `--help`, a
public type, or an error message.

```
promise                                   what happened
───────────────────────────────────────   ──────────────────────────────────────────────
copy button on Markdown code blocks   ──▶ button is drawn, nothing copies
auth.providers: ['cognito']           ──▶ every request fails (domain/region missing)
void db execute --remote --file       ──▶ "not yet supported ... pipe through stdin" (no stdin path)
                                          and the SQL goes to the first D1 row, not the configured binding
void gen model "… and DB types"       ──▶ no .void/db.d.ts until the next dev/prepare (tsc TS6053)
remote R2 get/put/list options        ──▶ silently ignored, metadata faked
void deploy --provision               ──▶ works, recommended in the D1 guide, missing from help and reference
platform uninstall --keep-zone        ──▶ does nothing; hidden --delete-zone only throws
useIslandForm "infers the action URL" ──▶ every adapter needs post(url)
connectEventStream({ events })        ──▶ option never read
… and ~30 more doc, help and type promises
```

## What this PR changes

Each item gets one of three treatments:

```
build it        ── copy button · cognito settings · hosted D1 --file on the configured binding
                   · gen model writes db.d.ts · remote R2 metadata and list options
make it true    ── help · CLI reference · API reference · guides · error messages · interactive hints
deprecate       ── public options and exports that never worked; kept for 1.x, marked @deprecated
```

Remote R2 in dev now refuses what it cannot do, instead of returning
wrong data:

```
get(key, { range: {offset, length} })         ──▶ throws: not supported in remote mode
get(key, { range: request.headers, ... })     ──▶ whole object, as before (browser reloads, media)
put(key, body, { customMetadata })            ──▶ stored with metadata on a current deployment
                                                  throws "stored without …" on an older one or the REST fallback
list({ delimiter, startAfter, include })      ──▶ real answer, or a clear error with retry/deploy advice
```

The Astro dev trigger fix is in its own PR, #434, because it changes the
dev middleware writer.

## Decisions

| Topic | Decision |
| --- | --- |
| Semver (Void 1.x) | No public export, option, type, or documented flag
is removed. Two hidden CLI flags that could only fail are removed:
`platform uninstall --delete-zone` and `email domain add --subdomain`. |
| Layout paths (`layout: './Shell.vue'`) | Build warning; default
layouts are used, as before. A hard error would break existing builds. |
| `sendInDev` | Deprecated. Behavior unchanged. |
| `DeployTargetAdapter.capabilities` | Deprecated, still required, so
code that reads it still compiles. |
| Copy button script | One small inline script on pages with code
blocks. A CSP without `'unsafe-inline'` blocks it, and the button stays
inert as before. |
| Hosted D1 `--file` | Sent as one request, the same as inline SQL. Real
D1 splits the statements on the server for both the binding and REST
paths; a failing statement rolls back the whole request. |
| `void.json` compatibility pin | Unchanged. The "Found both
void.config.ts and void.json" error now says how to fix it. |

## Behavior changes to note in the release

- Markdown code blocks: the copy button copies the code (removed diff
lines are left out). Pages with code blocks have a small inline script.
- `cognito`: set `AUTH_COGNITO_DOMAIN`, `AUTH_COGNITO_REGION`,
`AUTH_COGNITO_USER_POOL_ID`, or the same settings in `auth.ts`.
- Remote R2: `put()` with metadata throws when the project deployment is
older than this Void version (the object is stored without the
metadata). `get()` with an object-form `range` or `onlyIf` throws.
- `ai.provider().fetch()` on the platform proxy sends JSON bodies as
written, the same as the direct path. Before, file-shaped values were
rewritten into an internal marker.
- `void email domain add --subdomain` fails at once as an unknown
option.
- A page layout path logs a build warning.
- Deprecated: `shiki.langs`, `FrontmatterContext`, `setFrontmatter()`,
`sendInDev`, `StaticEdgeConfig.assetConfig`, the `@void/isr` legacy key
helpers, `DeployTargetCapabilities`,
`DatabaseProvisionResult.projectId`, `ConnectEventStreamOptions.events`,
`void/remote`, `ImageFileInput`, `platform uninstall --keep-zone`.

## Known limits

- `void db status` and `void db migrate --remote` on the Void platform
still use the first D1 resource. This is unchanged from main.
- A multi-line `CREATE TRIGGER … BEGIN … END` in a multi-statement SQL
string can fail on real D1 (workers-sdk#15690). Inline `--command`
already had this limit.
- A Markdown page under a strict CSP keeps an inert copy button.

## Testing

| Check | Result |
| --- | --- |
| New and changed tests | Each fails with its fix reverted |
| Markdown copy button | Browser test in dev and production: clipboard
text, diff lines skipped |
| Remote R2 | Unit tests through the binding handler; Miniflare runs for
a new client against the old handler and an old client against the new
handler |
| Hosted D1 `--file` | Live on real D1, through REST `/query` and
through a deployed Worker binding (`prepare(sql).bind().all()` /
`.run()`): every statement runs; a failing statement rolls back the
whole request |
| `vp run build:all`, `vp run check`, `vp lint`, `vp fmt --check` | pass
|
| `vp run test` | 583 files pass |

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_0123r5HnanmW2VUrZ7VWDufH

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant