Skip to content

Commit c50ce77

Browse files
committed
fix: Add /__void/ready handler to framework-mode wrapper.
1 parent 6152253 commit c50ce77

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

‎packages/void/src/cli/wrapper.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,15 @@ function generateWrapperSource(
250250
lines.push('async function wrappedFetch(request, env, ctx) {');
251251
lines.push(' const url = new URL(request.url);');
252252

253+
// Readiness probe — platform polls this to confirm the worker is live
254+
// after WfP upload. Handled here (before original.fetch) so the user's
255+
// framework handler doesn't route it to env.ASSETS, which returns CF's
256+
// "Assets have not yet been deployed" stub during asset propagation
257+
// and would trip the platform's probe.
258+
lines.push(' if (request.method === "GET" && url.pathname === "/__void/ready") {');
259+
lines.push(' return Response.json({ ready: true });');
260+
lines.push(' }');
261+
253262
// Migration handler
254263
if (migrations && migrations.length > 0) {
255264
lines.push(' if (request.method === "POST" && url.pathname === "/__void/migrate") {');

‎packages/void/test/unit/wrapper.test.ts‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,42 @@ describe('generateWrapper with migrations', () => {
153153
expect(existsSync(join(workerDir, '__void_migration_handler.mjs'))).toBe(true);
154154
});
155155

156+
it('intercepts GET /__void/ready with {ready:true} when wrapper is generated', async () => {
157+
// Platform's deploy-time readiness probe (packages/api/src/routes/deploy.ts)
158+
// expects a JSON 200 from GET /__void/ready before dispatching migrations.
159+
// Without this, the request falls through to the user's framework handler
160+
// (e.g. SvelteKit -> env.ASSETS), which returns CF's "Assets have not yet
161+
// been deployed to this script." stub during WfP propagation, causing the
162+
// probe to retry until exhaustion.
163+
mkdirSync(workerDir, { recursive: true });
164+
writeFileSync(
165+
join(workerDir, 'index.mjs'),
166+
'export default { fetch() { return new Response("ok"); } };',
167+
);
168+
169+
mkdirSync(join(projectRoot, 'db', 'migrations'), { recursive: true });
170+
writeFileSync(
171+
join(projectRoot, 'db', 'migrations', '001_test.sql'),
172+
'CREATE TABLE test (id INTEGER PRIMARY KEY);',
173+
);
174+
175+
await generateWrapper(workerDir, 'index.mjs', projectRoot, {
176+
...base,
177+
hasMigrations: true,
178+
migrationDialect: 'sqlite',
179+
});
180+
181+
const wrapper = readFileSync(join(workerDir, 'index.mjs'), 'utf-8');
182+
expect(wrapper).toContain('/__void/ready');
183+
expect(wrapper).toMatch(/Response\.json\(\s*\{\s*ready:\s*true\s*\}\s*\)/);
184+
// Must be checked before delegating to original.fetch, otherwise the
185+
// user's framework handler will see the request.
186+
const readyIdx = wrapper.indexOf('/__void/ready');
187+
const originalIdx = wrapper.indexOf('original.fetch');
188+
expect(readyIdx).toBeGreaterThanOrEqual(0);
189+
expect(originalIdx).toBeGreaterThan(readyIdx);
190+
});
191+
156192
it('does not generate migration handler when hasMigrations is false', async () => {
157193
mkdirSync(workerDir, { recursive: true });
158194
writeFileSync(

0 commit comments

Comments
 (0)