diff --git a/.changeset/path-addressed-server-functions.md b/.changeset/path-addressed-server-functions.md new file mode 100644 index 0000000..d92dd4f --- /dev/null +++ b/.changeset/path-addressed-server-functions.md @@ -0,0 +1,5 @@ +--- +"@solidjs/vite-plugin": minor +--- + +Route path-addressed server function calls (solidjs/solid#3076). A call's address is now `/` with arguments in the query, so the dev middleware and the generated request-dispatch gate match the endpoint by mount prefix instead of exact pathname, and the dev middleware's module-preload id comes from the path segment. The retired `X-Server-Function-Id` header and `?id=` forms remain as transitional fallbacks for the RC window only — they will be dropped before the stable release. diff --git a/examples/start-ssr/test/host-dispatch.mjs b/examples/start-ssr/test/host-dispatch.mjs index 9478d33..a79f7a6 100644 --- a/examples/start-ssr/test/host-dispatch.mjs +++ b/examples/start-ssr/test/host-dispatch.mjs @@ -33,7 +33,7 @@ try { // same-origin protection rejects dispatches without it. const response = await handler.handleServerFunctionRequest( new Request( - `http://localhost${handler.endpoint}?id=${encodeURIComponent(match[1])}&args=${encodeURIComponent('["host"]')}`, + `http://localhost${handler.endpoint}/${encodeURIComponent(match[1])}?args=${encodeURIComponent('["host"]')}`, { method: 'POST', headers: { 'Sec-Fetch-Site': 'same-origin' } }, ), ); @@ -46,7 +46,7 @@ try { if (!nativeMatch) throw new Error('could not extract nativeAddress function id'); const nativeResponse = await handler.handleServerFunctionRequest( new Request( - `http://localhost${handler.endpoint}?id=${encodeURIComponent(nativeMatch[1])}&args=${encodeURIComponent('[]')}`, + `http://localhost${handler.endpoint}/${encodeURIComponent(nativeMatch[1])}?args=${encodeURIComponent('[]')}`, { method: 'POST', headers: { 'Sec-Fetch-Site': 'same-origin' } }, ), { event: { nativeEvent: { socket: { remoteAddress: '198.51.100.7' } } } }, diff --git a/examples/start-ssr/test/run.mjs b/examples/start-ssr/test/run.mjs index f46fe21..7ac299f 100644 --- a/examples/start-ssr/test/run.mjs +++ b/examples/start-ssr/test/run.mjs @@ -307,7 +307,7 @@ function extractFunctionId(transformedCode, name) { } async function runCsrfChecks(mode, origin) { - const crossSite = await fetch(origin + '/_server?id=csrf-probe', { + const crossSite = await fetch(origin + '/_server/csrf-probe', { method: 'POST', headers: { 'Sec-Fetch-Site': 'cross-site' }, }); @@ -318,7 +318,7 @@ async function runCsrfChecks(mode, origin) { crossSite.status === 403, ); - const sameOrigin = await fetch(origin + '/_server?id=csrf-probe', { method: 'POST' }); + const sameOrigin = await fetch(origin + '/_server/csrf-probe', { method: 'POST' }); record(mode, 'csrf', 'same-origin request reaches dispatch', sameOrigin.status === 404); } @@ -910,7 +910,7 @@ async function runDevMode() { // from the query string when no instance header is present. const cold = functionId ? await fetch( - `${origin}/_server?id=${encodeURIComponent(functionId)}&args=${encodeURIComponent('["start-ssr"]')}`, + `${origin}/_server/${encodeURIComponent(functionId)}?args=${encodeURIComponent('["start-ssr"]')}`, { method: 'POST' }, ) : null; @@ -922,7 +922,7 @@ async function runDevMode() { coldText === 'hello start-ssr from the server', functionId ? `got ${JSON.stringify(coldText)}` : 'could not extract function id', ); - const bogus = await fetch(origin + '/_server?id=bogus-0'); + const bogus = await fetch(origin + '/_server/bogus-0'); record(mode, 'sf', 'dev middleware rejects unknown id', bogus.status === 404); await runCsrfChecks(mode, origin); @@ -1190,7 +1190,7 @@ async function runProdMode() { try { await waitForHttp(origin + '/', 30000, { headers: { accept: 'text/html' } }); - const bogus = await fetch(origin + '/_server?id=bogus-0'); + const bogus = await fetch(origin + '/_server/bogus-0'); record(mode, 'sf', 'prod handler rejects unknown id', bogus.status === 404); await runCsrfChecks(mode, origin); @@ -1621,7 +1621,7 @@ async function runEndpointMode() { const functionId = extractFunctionId(clientModule, 'getServerMessage'); const custom = functionId ? await fetch( - `${origin}${endpoint}?id=${encodeURIComponent(functionId)}&args=${encodeURIComponent('["endpoint"]')}`, + `${origin}${endpoint}/${encodeURIComponent(functionId)}?args=${encodeURIComponent('["endpoint"]')}`, { method: 'POST' }, ) : null; @@ -1634,7 +1634,7 @@ async function runEndpointMode() { functionId ? `got ${JSON.stringify(customText)}` : 'could not extract function id', ); - const fallback = await fetch(`${origin}/_server?id=${encodeURIComponent(functionId || '')}`); + const fallback = await fetch(`${origin}/_server/${encodeURIComponent(functionId || '')}`); record( mode, 'rpc', @@ -1687,7 +1687,7 @@ async function runConfigureMode() { }; const dispatch = async (id) => { const res = await fetch( - `${origin}/_server?id=${encodeURIComponent(id)}&args=${encodeURIComponent('[]')}`, + `${origin}/_server/${encodeURIComponent(id)}?args=${encodeURIComponent('[]')}`, { method: 'POST' }, ); return { @@ -1849,7 +1849,7 @@ async function runNoMiddlewareMode() { const functionId = extractFunctionId(clientModule, 'getServerMessage'); const res = functionId ? await fetch( - `${origin}/_server?id=${encodeURIComponent(functionId)}&args=${encodeURIComponent('["nobody"]')}`, + `${origin}/_server/${encodeURIComponent(functionId)}?args=${encodeURIComponent('["nobody"]')}`, { method: 'POST' }, ) : null; @@ -2614,7 +2614,7 @@ async function runMiddlewareChecksOverHttp(mode, origin, functionId) { if (functionId) { const fn = await fetch( - `${origin}/_server?id=${encodeURIComponent(functionId)}&args=${encodeURIComponent('[]')}`, + `${origin}/_server/${encodeURIComponent(functionId)}?args=${encodeURIComponent('[]')}`, { method: 'POST' }, ); const fnBody = await fn.text(); @@ -2920,7 +2920,7 @@ async function runPreviewMode() { } // The endpoint dispatches through the same handler. - const bogus = await fetch(origin + '/_server?id=bogus-0', { method: 'POST' }); + const bogus = await fetch(origin + '/_server/bogus-0', { method: 'POST' }); record(mode, 'sf', 'preview dispatches /_server (unknown id rejected)', bogus.status === 404); // Middleware fronts preview exactly like dev and prod. @@ -3035,7 +3035,7 @@ async function runBaseMode() { const functionId = extractFunctionId(clientModule, 'getServerMessage'); const call = functionId ? await fetch( - `${devOrigin}${basePrefix}/_server?id=${encodeURIComponent(functionId)}&args=${encodeURIComponent('["base"]')}`, + `${devOrigin}${basePrefix}/_server/${encodeURIComponent(functionId)}?args=${encodeURIComponent('["base"]')}`, { method: 'POST' }, ) : null; @@ -3098,7 +3098,7 @@ async function runBaseMode() { // #300: the server-function endpoint must dispatch through the built // handler even though preview stripped the base from req.url. Under the // bug this request fell through to page rendering (200 text/html). - const bogus = await fetch(previewOrigin + basePrefix + '/_server?id=bogus-0', { + const bogus = await fetch(previewOrigin + basePrefix + '/_server/bogus-0', { method: 'POST', }); record( @@ -3119,7 +3119,7 @@ async function runBaseMode() { )?.[1]; const call = prodId ? await fetch( - `${previewOrigin}${basePrefix}/_server?id=${encodeURIComponent(prodId)}&args=${encodeURIComponent('["preview"]')}`, + `${previewOrigin}${basePrefix}/_server/${encodeURIComponent(prodId)}?args=${encodeURIComponent('["preview"]')}`, { method: 'POST' }, ) : null; @@ -3241,7 +3241,7 @@ async function runExternalMode() { const functionResponse = functionId ? await handler.handleRequest( new Request( - `http://localhost/_server?id=${encodeURIComponent(functionId)}&args=${encodeURIComponent('["external"]')}`, + `http://localhost/_server/${encodeURIComponent(functionId)}?args=${encodeURIComponent('["external"]')}`, // The composing host forwards the browser's fetch metadata; the // runtime's same-origin protection rejects dispatches without it. { method: 'POST', headers: { 'Sec-Fetch-Site': 'same-origin' } }, @@ -3310,7 +3310,7 @@ async function runDetectMode() { await new Promise((resolve) => httpServer.listen(0, '127.0.0.1', resolve)); const origin = `http://127.0.0.1:${httpServer.address().port}`; - const endpointResponse = await fetch(`${origin}/_server?id=x&args=%5B%5D`, { method: 'POST' }); + const endpointResponse = await fetch(`${origin}/_server/x?args=%5B%5D`, { method: 'POST' }); record( mode, 'sf', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index df58981..ed24790 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,11 +7,11 @@ settings: catalogs: default: '@solidjs/web': - specifier: ^2.0.0-rc.3 - version: 2.0.0-rc.3 + specifier: ^2.0.0-rc.4 + version: 2.0.0-rc.4 solid-js: - specifier: ^2.0.0-rc.3 - version: 2.0.0-rc.3 + specifier: ^2.0.0-rc.4 + version: 2.0.0-rc.4 importers: @@ -25,13 +25,13 @@ importers: version: 7.29.7 '@solidjs/babel-plugin': specifier: ^2.0.0-rc.3 - version: 2.0.0-rc.3(@babel/core@7.29.7) + version: 2.0.0-rc.4(@babel/core@7.29.7) '@solidjs/compiler': specifier: ^2.0.0-rc.3 - version: 2.0.0-rc.3 + version: 2.0.0-rc.4 '@solidjs/web': specifier: ^2.0.0-rc.0 - version: 2.0.0-rc.2(solid-js@2.0.0-rc.2) + version: 2.0.0-rc.4(solid-js@2.0.0-rc.4) '@testing-library/jest-dom': specifier: ^5.16.6 || ^5.17.0 || ^6.* version: 6.10.0(@testing-library/dom@10.4.1) @@ -68,10 +68,10 @@ importers: version: 0.2.2 '@solidjs/diagnostics': specifier: ^2.0.0-rc.3 - version: 2.0.0-rc.3(vitest@4.1.11) + version: 2.0.0-rc.4(vitest@4.1.11) '@solidjs/start-devtools': specifier: ^1.0.0-next.3 - version: 1.0.0-next.4(@solidjs/web@2.0.0-rc.2(solid-js@2.0.0-rc.2))(solid-js@2.0.0-rc.2) + version: 1.0.0-next.4(@solidjs/web@2.0.0-rc.4(solid-js@2.0.0-rc.4))(solid-js@2.0.0-rc.4) '@types/node': specifier: ^24.0.0 version: 24.13.3 @@ -98,7 +98,7 @@ importers: version: 1.0.0(rollup@4.62.2) solid-js: specifier: ^2.0.0-rc.0 - version: 2.0.0-rc.2 + version: 2.0.0-rc.4 typescript: specifier: ^5.2.2 version: 5.9.3 @@ -110,10 +110,10 @@ importers: dependencies: '@solidjs/web': specifier: 'catalog:' - version: 2.0.0-rc.3(solid-js@2.0.0-rc.3) + version: 2.0.0-rc.4(solid-js@2.0.0-rc.4) solid-js: specifier: 'catalog:' - version: 2.0.0-rc.3 + version: 2.0.0-rc.4 devDependencies: '@solidjs/vite-plugin': specifier: workspace:* @@ -126,10 +126,10 @@ importers: dependencies: '@solidjs/web': specifier: 'catalog:' - version: 2.0.0-rc.3(solid-js@2.0.0-rc.3) + version: 2.0.0-rc.4(solid-js@2.0.0-rc.4) solid-js: specifier: 'catalog:' - version: 2.0.0-rc.3 + version: 2.0.0-rc.4 devDependencies: '@solidjs/vite-plugin': specifier: workspace:* @@ -142,10 +142,10 @@ importers: dependencies: '@solidjs/web': specifier: 'catalog:' - version: 2.0.0-rc.3(solid-js@2.0.0-rc.3) + version: 2.0.0-rc.4(solid-js@2.0.0-rc.4) solid-js: specifier: 'catalog:' - version: 2.0.0-rc.3 + version: 2.0.0-rc.4 devDependencies: '@solidjs/vite-plugin': specifier: workspace:* @@ -158,10 +158,10 @@ importers: dependencies: '@solidjs/web': specifier: 'catalog:' - version: 2.0.0-rc.3(solid-js@2.0.0-rc.3) + version: 2.0.0-rc.4(solid-js@2.0.0-rc.4) solid-js: specifier: 'catalog:' - version: 2.0.0-rc.3 + version: 2.0.0-rc.4 valibot: specifier: ^1.1.0 version: 1.4.2(typescript@5.9.3) @@ -183,10 +183,10 @@ importers: dependencies: '@solidjs/web': specifier: 'catalog:' - version: 2.0.0-rc.3(solid-js@2.0.0-rc.3) + version: 2.0.0-rc.4(solid-js@2.0.0-rc.4) solid-js: specifier: 'catalog:' - version: 2.0.0-rc.3 + version: 2.0.0-rc.4 devDependencies: '@solidjs/vite-plugin': specifier: workspace:* @@ -205,14 +205,14 @@ importers: dependencies: '@solidjs/web': specifier: 'catalog:' - version: 2.0.0-rc.3(solid-js@2.0.0-rc.3) + version: 2.0.0-rc.4(solid-js@2.0.0-rc.4) solid-js: specifier: 'catalog:' - version: 2.0.0-rc.3 + version: 2.0.0-rc.4 devDependencies: '@solidjs/testing-library': specifier: ^1.0.0-beta.2 - version: 1.0.0-beta.2(@solidjs/web@2.0.0-rc.3(solid-js@2.0.0-rc.3))(solid-js@2.0.0-rc.3) + version: 1.0.0-beta.2(@solidjs/web@2.0.0-rc.4(solid-js@2.0.0-rc.4))(solid-js@2.0.0-rc.4) '@solidjs/vite-plugin': specifier: workspace:* version: link:../.. @@ -1068,11 +1068,12 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - '@napi-rs/wasm-runtime@1.1.6': - resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + '@napi-rs/wasm-runtime@1.2.3': + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -1354,56 +1355,53 @@ packages: resolution: {integrity: sha512-T4Wyi9lUuz0a1C2OHuzqZ0aFOCI0AmaGTb2LP9sHgWdoHXlB3JU02gfBpa0Y081G/gFsJYpQ/R0iCJRzF/nknw==} hasBin: true - '@solidjs/babel-plugin@2.0.0-rc.3': - resolution: {integrity: sha512-VLqCvvMukrACeMuF3uPTyx9l+qCQ9H1G25vOl7FXAdu9rMrLEKZ2IEoiUMczn0mhXAVeplJVEvr7+gSy5m4omA==} + '@solidjs/babel-plugin@2.0.0-rc.4': + resolution: {integrity: sha512-4RYR4PWAlQIz1dmIyPheaUvVb9EnSIw5KIGsEISmHod5qfT1IPVKgtb9bctyQ5FeDAuc7JcpbkFYN2heLrk6rQ==} peerDependencies: '@babel/core': ^7.20.12 - '@solidjs/compiler-darwin-arm64@2.0.0-rc.3': - resolution: {integrity: sha512-P9Ngf6KUwM+KGAAUZ40776+1utbk/n3+F+WhyyYm+rUpjO0um9EqBJLvafqEp6kGgSHQ2j5UhioqcuqhesMLbQ==} + '@solidjs/compiler-darwin-arm64@2.0.0-rc.4': + resolution: {integrity: sha512-YR4T15ucsV1Vb4J6yaHxss2hakdcbZ353ye53AhX+FWNayuEhO/Cyjdtb9uS38Dfzysok/rIEQdaeZcaXt+rPA==} cpu: [arm64] os: [darwin] - '@solidjs/compiler-darwin-x64@2.0.0-rc.3': - resolution: {integrity: sha512-PozalaeiMJxPF7H5ePpqOGM8F9H07sFsSGxyHHZiUn8c4HIBlsacNpc06gUcoJ1xzm7AvayNCV9BJOw2hQYaYg==} + '@solidjs/compiler-darwin-x64@2.0.0-rc.4': + resolution: {integrity: sha512-95SkVSyXP2eh7PvPWi+fTeH5aTcTwOUvRV7ubeUrutE4akW3ndq1N8cvg2WZ+LhKrf2pvDO0eSDEZ72I769CLg==} cpu: [x64] os: [darwin] - '@solidjs/compiler-linux-arm64-gnu@2.0.0-rc.3': - resolution: {integrity: sha512-riY4uwHCqq5vfrlYY7AK8xy/r/Wd98NCnbGqFsDb7bL7TNw398VuA5+hoK4cnsQJe4dqvI2zXFEdmP5xSNAFSQ==} + '@solidjs/compiler-linux-arm64-gnu@2.0.0-rc.4': + resolution: {integrity: sha512-36Ht+EUAVUt8fAxq8zlfPS0+vZ61hfJRJDiX1HDNXvlAwZE1B7FH/ym1wfXrhG1TvrNA63Sjjj5CeccYO2H4Tg==} cpu: [arm64] os: [linux] - '@solidjs/compiler-linux-x64-gnu@2.0.0-rc.3': - resolution: {integrity: sha512-y2GlcmfIqtWBrxOnvgLsGZvdH2tVK/9JzcFTUzWo5kjoiEy+VCV3NSNcBZrMbLJ7ozIDTiuWePZd/G5LphYdmA==} + '@solidjs/compiler-linux-x64-gnu@2.0.0-rc.4': + resolution: {integrity: sha512-DSFOQEjfYmmRQ70pNLamRXPNQ+aP+5vyh1rMjSKwAzONt0xB2rcy9Alt02GU38gztW9YN6ZyxM4rwkYe+7MfaQ==} cpu: [x64] os: [linux] - '@solidjs/compiler-wasm32-wasi@2.0.0-rc.3': - resolution: {integrity: sha512-mx7LnrAwKaXd9ZiaAwZeBlMjdWNdmR73F+3I1iOxSpH9Lh2Kyx9IIVff0a1AnwUy17tdDxXMbWxoI/ctYfZsdw==} + '@solidjs/compiler-wasm32-wasi@2.0.0-rc.4': + resolution: {integrity: sha512-zVxXS+01rbv+0yOp2vaGjIu0om5I1UhhPpzNYeE+AmfpVc2eCWxqDsPai3dIxFDGPTjaJ+npwjKJRmOTaoknRw==} engines: {node: '>=14.0.0'} - '@solidjs/compiler-win32-x64-msvc@2.0.0-rc.3': - resolution: {integrity: sha512-7MQDvdSI42/+lSac6L6WVgCYkUezzliLRoCjo7ultpN2hHy3XgohxvrWfE005OQEMg2pamzzFmfeIl8FUi2JRA==} + '@solidjs/compiler-win32-x64-msvc@2.0.0-rc.4': + resolution: {integrity: sha512-DkzTHMZXzaiL/KhL76UJWN24pKkkXeLpPYtDxUqX6VaKuOCPDmp/m7GLWSDrqCdF7leuYsig2MuMJTXZRLOkbQ==} cpu: [x64] os: [win32] - '@solidjs/compiler@2.0.0-rc.3': - resolution: {integrity: sha512-gu2AnJwkrJfk3SBKGRxEUGuP/SZpwUGzHQS5zt56eNG4GFlEMyurahVRSLMWWBhtC1On7wH5SmLxybH2yDCqAg==} + '@solidjs/compiler@2.0.0-rc.4': + resolution: {integrity: sha512-lKx6Jp1KbHxqO+v+g7cRbm8I1DHx/10Lj8bKG4vmdGnCfSlFbyhCd8cPTLdLV0YVG7GGSzzF5m8NkC9NlfGN5w==} - '@solidjs/diagnostics@2.0.0-rc.3': - resolution: {integrity: sha512-fPb20MXqN7LpT02+kxfMBhY3reCKeh7vB++g9Su1EJZ6Ie0PeydyU/CnkUNa9gwLCMKoZG1x0pfAMb9yLGowtw==} + '@solidjs/diagnostics@2.0.0-rc.4': + resolution: {integrity: sha512-BF2kb5VKcJIwAAnFvto8MHvshnV/Tn4AyvaGLEm1Jp/RQrsmsR+on2w8EOawA+imZjhIh3azuBmed71tW1HV6w==} peerDependencies: vitest: '>=2.0.0' peerDependenciesMeta: vitest: optional: true - '@solidjs/signals@2.0.0-rc.2': - resolution: {integrity: sha512-nJyXdBZJaYGqtDuQt8csE9LY9oNZV2fZfPRmJHQT9QjQEuHKQ1OaZScZ8YFaeATrnavzys4Ws95LnUdv8pCidQ==} - - '@solidjs/signals@2.0.0-rc.3': - resolution: {integrity: sha512-/yPhTf3xS1FRR4MX8kTYCd4MjsFxzwkO+KyOTfbu35lTEiaJ4Fxy+JL91XonDzt31GV1mYaZ9CGD2TQIzvXuNA==} + '@solidjs/signals@2.0.0-rc.4': + resolution: {integrity: sha512-l7P0g8+2pnNscaIPOGDMhv0boaidGAsvR8QN66JySIWNMvVnuq2ayv7ZnvP+IR00DJC+RqCNnnTG/UCdxf+h8g==} '@solidjs/start-devtools@1.0.0-next.4': resolution: {integrity: sha512-RNjndz1PfUicxJi3XHwjoIsu9AHeOhpP8Y/bgRmumR5Z9ymdMsiRCL89Fq1YqxhBnHf+GL4kX/VvC+F8lgmTVA==} @@ -1418,15 +1416,10 @@ packages: '@solidjs/web': '>=2.0.0' solid-js: '>=2.0.0' - '@solidjs/web@2.0.0-rc.2': - resolution: {integrity: sha512-JazuW9NCI+kcpZXRq9J/DAGPmMd0pEWr3kuXFmPZV9tOviiTOHDXOf56pjbUFVDZd+120AKoe/ULmYdSDpJmsA==} - peerDependencies: - solid-js: ^2.0.0-rc.2 - - '@solidjs/web@2.0.0-rc.3': - resolution: {integrity: sha512-5ckKgOjem1pN5ADycOk6TjHmTtjbbN2fukqxo6RW3Oe3H7z0gaXWAdt8dLISto5/O4Nn8VxprFXFWpfy31+DUg==} + '@solidjs/web@2.0.0-rc.4': + resolution: {integrity: sha512-acM9W0FByf0aJDMG5kMbHr0BLTjvFIg8lxwLwHzsu3ybWSmsP1FiOOs2RHNItve/AiX+MGR9CQBCazmnfPykEA==} peerDependencies: - solid-js: ^2.0.0-rc.3 + solid-js: ^2.0.0-rc.4 '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -2805,11 +2798,8 @@ packages: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} - solid-js@2.0.0-rc.2: - resolution: {integrity: sha512-1C++20cho5f+omXbX6MIl+VrBZ+by6QkWpCtpbVmmUR80EGgH4irqV0UdP88GAYHx1U+FzpCcHxIGoA9raCyQA==} - - solid-js@2.0.0-rc.3: - resolution: {integrity: sha512-pmW6bRoTvfp/rN4jN7JmLvSaoIpFt7wm0Hi3j508S/smuJqUbRg3dQEjOPTkAwHW+McYnXrMG7cJ4AMNpLevtQ==} + solid-js@2.0.0-rc.4: + resolution: {integrity: sha512-hSkDmtduesjFtvzjNyqLphrqiSvhSD5+njkPQUR+9YEoR60MMWtuv36SbLL4OucI0Ronof3Jc+AsUp0oWffwMg==} source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} @@ -4219,7 +4209,7 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': dependencies: '@emnapi/core': 1.11.3 '@emnapi/runtime': 1.11.3 @@ -4409,7 +4399,7 @@ snapshots: kleur: 4.1.5 yargs-parser: 20.2.9 - '@solidjs/babel-plugin@2.0.0-rc.3(@babel/core@7.29.7)': + '@solidjs/babel-plugin@2.0.0-rc.4(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 '@babel/helper-module-imports': 7.18.6 @@ -4419,69 +4409,61 @@ snapshots: parse5: 7.3.0 validate-html-nesting: 1.2.4 - '@solidjs/compiler-darwin-arm64@2.0.0-rc.3': + '@solidjs/compiler-darwin-arm64@2.0.0-rc.4': optional: true - '@solidjs/compiler-darwin-x64@2.0.0-rc.3': + '@solidjs/compiler-darwin-x64@2.0.0-rc.4': optional: true - '@solidjs/compiler-linux-arm64-gnu@2.0.0-rc.3': + '@solidjs/compiler-linux-arm64-gnu@2.0.0-rc.4': optional: true - '@solidjs/compiler-linux-x64-gnu@2.0.0-rc.3': + '@solidjs/compiler-linux-x64-gnu@2.0.0-rc.4': optional: true - '@solidjs/compiler-wasm32-wasi@2.0.0-rc.3': + '@solidjs/compiler-wasm32-wasi@2.0.0-rc.4': dependencies: '@emnapi/core': 1.11.3 '@emnapi/runtime': 1.11.3 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) optional: true - '@solidjs/compiler-win32-x64-msvc@2.0.0-rc.3': + '@solidjs/compiler-win32-x64-msvc@2.0.0-rc.4': optional: true - '@solidjs/compiler@2.0.0-rc.3': + '@solidjs/compiler@2.0.0-rc.4': optionalDependencies: - '@solidjs/compiler-darwin-arm64': 2.0.0-rc.3 - '@solidjs/compiler-darwin-x64': 2.0.0-rc.3 - '@solidjs/compiler-linux-arm64-gnu': 2.0.0-rc.3 - '@solidjs/compiler-linux-x64-gnu': 2.0.0-rc.3 - '@solidjs/compiler-wasm32-wasi': 2.0.0-rc.3 - '@solidjs/compiler-win32-x64-msvc': 2.0.0-rc.3 + '@solidjs/compiler-darwin-arm64': 2.0.0-rc.4 + '@solidjs/compiler-darwin-x64': 2.0.0-rc.4 + '@solidjs/compiler-linux-arm64-gnu': 2.0.0-rc.4 + '@solidjs/compiler-linux-x64-gnu': 2.0.0-rc.4 + '@solidjs/compiler-wasm32-wasi': 2.0.0-rc.4 + '@solidjs/compiler-win32-x64-msvc': 2.0.0-rc.4 - '@solidjs/diagnostics@2.0.0-rc.3(vitest@4.1.11)': + '@solidjs/diagnostics@2.0.0-rc.4(vitest@4.1.11)': dependencies: - '@solidjs/signals': 2.0.0-rc.3 + '@solidjs/signals': 2.0.0-rc.4 optionalDependencies: vitest: 4.1.11(@types/node@24.13.3)(@vitest/browser-playwright@4.1.11)(jsdom@26.1.0)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.28.2)) - '@solidjs/signals@2.0.0-rc.2': {} + '@solidjs/signals@2.0.0-rc.4': {} - '@solidjs/signals@2.0.0-rc.3': {} - - '@solidjs/start-devtools@1.0.0-next.4(@solidjs/web@2.0.0-rc.2(solid-js@2.0.0-rc.2))(solid-js@2.0.0-rc.2)': + '@solidjs/start-devtools@1.0.0-next.4(@solidjs/web@2.0.0-rc.4(solid-js@2.0.0-rc.4))(solid-js@2.0.0-rc.4)': dependencies: - '@solidjs/web': 2.0.0-rc.2(solid-js@2.0.0-rc.2) - solid-js: 2.0.0-rc.2 + '@solidjs/web': 2.0.0-rc.4(solid-js@2.0.0-rc.4) + solid-js: 2.0.0-rc.4 - '@solidjs/testing-library@1.0.0-beta.2(@solidjs/web@2.0.0-rc.3(solid-js@2.0.0-rc.3))(solid-js@2.0.0-rc.3)': + '@solidjs/testing-library@1.0.0-beta.2(@solidjs/web@2.0.0-rc.4(solid-js@2.0.0-rc.4))(solid-js@2.0.0-rc.4)': dependencies: - '@solidjs/web': 2.0.0-rc.3(solid-js@2.0.0-rc.3) + '@solidjs/web': 2.0.0-rc.4(solid-js@2.0.0-rc.4) '@testing-library/dom': 10.4.1 - solid-js: 2.0.0-rc.3 - - '@solidjs/web@2.0.0-rc.2(solid-js@2.0.0-rc.2)': - dependencies: - seroval: 1.5.6 - seroval-plugins: 1.5.6(seroval@1.5.6) - solid-js: 2.0.0-rc.2 + solid-js: 2.0.0-rc.4 - '@solidjs/web@2.0.0-rc.3(solid-js@2.0.0-rc.3)': + '@solidjs/web@2.0.0-rc.4(solid-js@2.0.0-rc.4)': dependencies: seroval: 1.5.6 seroval-plugins: 1.5.6(seroval@1.5.6) - solid-js: 2.0.0-rc.3 + solid-js: 2.0.0-rc.4 '@standard-schema/spec@1.1.0': {} @@ -5898,16 +5880,9 @@ snapshots: astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 - solid-js@2.0.0-rc.2: - dependencies: - '@solidjs/signals': 2.0.0-rc.2 - csstype: 3.2.3 - seroval: 1.5.6 - seroval-plugins: 1.5.6(seroval@1.5.6) - - solid-js@2.0.0-rc.3: + solid-js@2.0.0-rc.4: dependencies: - '@solidjs/signals': 2.0.0-rc.3 + '@solidjs/signals': 2.0.0-rc.4 csstype: 3.2.3 seroval: 1.5.6 seroval-plugins: 1.5.6(seroval@1.5.6) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index dc1a7d7..4ee798d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -8,26 +8,26 @@ allowBuilds: msw: true catalog: - solid-js: "^2.0.0-rc.3" - "@solidjs/web": "^2.0.0-rc.3" + solid-js: "^2.0.0-rc.4" + "@solidjs/web": "^2.0.0-rc.4" ignoredBuiltDependencies: - cypress minimumReleaseAgeExclude: - - '@solidjs/signals@2.0.0-beta.30 || 2.0.0-beta.31 || 2.0.0-beta.32 || 2.0.0-rc.0 || 2.0.0-rc.1 || 2.0.0-rc.2 || 2.0.0-rc.3' + - '@solidjs/signals@2.0.0-beta.30 || 2.0.0-beta.31 || 2.0.0-beta.32 || 2.0.0-rc.0 || 2.0.0-rc.1 || 2.0.0-rc.2 || 2.0.0-rc.3 || 2.0.0-rc.4' - '@solidjs/start-devtools@1.0.0-next.1 || 1.0.0-next.2 || 1.0.0-next.3' - - '@solidjs/web@2.0.0-beta.30 || 2.0.0-beta.31 || 2.0.0-beta.32 || 2.0.0-rc.0 || 2.0.0-rc.1 || 2.0.0-rc.2 || 2.0.0-rc.3' - - '@solidjs/babel-plugin@2.0.0-rc.3' - - '@solidjs/compiler@2.0.0-rc.3' - - '@solidjs/compiler-darwin-arm64@2.0.0-rc.3' - - '@solidjs/compiler-darwin-x64@2.0.0-rc.3' - - '@solidjs/compiler-linux-arm64-gnu@2.0.0-rc.3' - - '@solidjs/compiler-linux-x64-gnu@2.0.0-rc.3' - - '@solidjs/compiler-win32-x64-msvc@2.0.0-rc.3' - - '@solidjs/compiler-wasm32-wasi@2.0.0-rc.3' - - '@solidjs/diagnostics@2.0.0-rc.3' - - solid-js@2.0.0-beta.30 || 2.0.0-beta.31 || 2.0.0-beta.32 || 2.0.0-rc.0 || 2.0.0-rc.1 || 2.0.0-rc.2 || 2.0.0-rc.3 + - '@solidjs/web@2.0.0-beta.30 || 2.0.0-beta.31 || 2.0.0-beta.32 || 2.0.0-rc.0 || 2.0.0-rc.1 || 2.0.0-rc.2 || 2.0.0-rc.3 || 2.0.0-rc.4' + - '@solidjs/babel-plugin@2.0.0-rc.3 || 2.0.0-rc.4' + - '@solidjs/compiler@2.0.0-rc.3 || 2.0.0-rc.4' + - '@solidjs/compiler-darwin-arm64@2.0.0-rc.3 || 2.0.0-rc.4' + - '@solidjs/compiler-darwin-x64@2.0.0-rc.3 || 2.0.0-rc.4' + - '@solidjs/compiler-linux-arm64-gnu@2.0.0-rc.3 || 2.0.0-rc.4' + - '@solidjs/compiler-linux-x64-gnu@2.0.0-rc.3 || 2.0.0-rc.4' + - '@solidjs/compiler-win32-x64-msvc@2.0.0-rc.3 || 2.0.0-rc.4' + - '@solidjs/compiler-wasm32-wasi@2.0.0-rc.3 || 2.0.0-rc.4' + - '@solidjs/diagnostics@2.0.0-rc.3 || 2.0.0-rc.4' + - solid-js@2.0.0-beta.30 || 2.0.0-beta.31 || 2.0.0-beta.32 || 2.0.0-rc.0 || 2.0.0-rc.1 || 2.0.0-rc.2 || 2.0.0-rc.3 || 2.0.0-rc.4 - '@dom-expressions/babel-plugin-jsx@0.50.0-next.35 || 0.50.0-next.37 || 0.50.0-next.40 || 0.50.0-next.43' - '@dom-expressions/compiler-darwin-arm64@0.50.0-next.35 || 0.50.0-next.37 || 0.50.0-next.40 || 0.50.0-next.43' - '@dom-expressions/compiler-darwin-x64@0.50.0-next.35 || 0.50.0-next.37 || 0.50.0-next.40 || 0.50.0-next.43' diff --git a/src/server-functions/index.ts b/src/server-functions/index.ts index faeac2f..49c1cf3 100644 --- a/src/server-functions/index.ts +++ b/src/server-functions/index.ts @@ -515,27 +515,50 @@ export function serverFunctions( if (internal.externalDevServer || !isRunnableEnvironment(ssrEnvironment)) { return; } + // A call's address is `/` (solidjs/solid#3076) — the + // mount plus exactly one path segment. Bare-mount requests still + // reach the runtime handler (it answers 404), so misdirected posts + // fail through the endpoint rather than falling through to SSR. + const underMount = (pathname: string, mount: string) => + pathname === mount || pathname.startsWith(mount + '/'); server.middlewares.use((req, res, next) => { const url = new URL(req.url || '/', 'http://localhost'); // Match with and without `base` — middleware-mode hosts may mount // vite.middlewares below the base themselves. - if (url.pathname !== resolvedEndpoint && url.pathname !== endpoint) { + if (!underMount(url.pathname, resolvedEndpoint) && !underMount(url.pathname, endpoint)) { return next(); } + const basePrefixed = underMount(url.pathname, resolvedEndpoint); // When the stripped form matched, restore the base for dispatch: // the generated handler compares the request pathname against the // base-prefixed endpoint, and production handlers only ever see // base-prefixed URLs. - const dispatchUrl = - url.pathname === resolvedEndpoint ? undefined : joinBase(base, req.url || '/'); + const dispatchUrl = basePrefixed ? undefined : joinBase(base, req.url || '/'); (async () => { // Make sure the referenced module has been evaluated in the SSR // environment so its registration exists — functions only client // code references are never loaded by the SSR render itself. - const headerId = req.headers['x-server-function-id']; - const functionId = - (typeof headerId === 'string' ? headerId.split('#')[0] : undefined) || - url.searchParams.get('id'); + // The id lives in the path segment after the mount. + const mount = basePrefixed ? resolvedEndpoint : endpoint; + const segment = url.pathname.slice(mount.length + 1); + let functionId: string | null = null; + if (segment && !segment.includes('/')) { + try { + functionId = decodeURIComponent(segment); + } catch { + // not an address; the runtime handler answers the 404 + } + } + if (!functionId) { + // TRANSITIONAL (remove before 3.0 stable): the retired header + // and `?id=` addressing, kept only for the RC window where this + // plugin meets a @solidjs/web older than the path-addressing + // change (solidjs/solid#3076). + const headerId = req.headers['x-server-function-id']; + functionId = + (typeof headerId === 'string' ? headerId.split('#')[0] : undefined) || + url.searchParams.get('id'); + } if (functionId) { const entry = moduleForFunctionId(functionId); if (entry) await ssrEnvironment.runner.import(moduleDevUrl(entry)); diff --git a/src/ssr/index.ts b/src/ssr/index.ts index 14d700d..d2609d5 100644 --- a/src/ssr/index.ts +++ b/src/ssr/index.ts @@ -1002,7 +1002,11 @@ export function startServe( lines.push(``, `async function dispatchRequest(request, event, options) {`); if (composeServerFunctions) { lines.push( - ` if (new URL(request.url).pathname === endpoint) {`, + // A call's address is `/` (solidjs/solid#3076); the + // bare mount still routes so a misaddressed request 404s through the + // runtime handler instead of rendering a page at it. + ` const requestPath = new URL(request.url).pathname;`, + ` if (requestPath === endpoint || requestPath.startsWith(endpoint + '/')) {`, // The call shares the middleware chain's event (locals decoration, // the response stub); an explicit host-provided createEvent wins. // No fold here: the runtime's server-function handler runs the