Skip to content

Commit f24c30a

Browse files
fix: validate server fn id during dev
1 parent 19ecfe3 commit f24c30a

1 file changed

Lines changed: 38 additions & 5 deletions

File tree

  • packages/server-functions-plugin/src

packages/server-functions-plugin/src/index.ts

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/// <reference types="vite/client" />
22
import crypto from 'node:crypto'
3+
import assert from 'node:assert'
34
import { TanStackDirectiveFunctionsPluginEnv } from '@tanstack/directive-functions-plugin'
4-
import type { DevEnvironment, Plugin } from 'vite'
5+
import type { Plugin } from 'vite'
56
import type {
67
DirectiveFn,
78
GenerateFunctionIdFn,
@@ -39,16 +40,26 @@ const debug =
3940
process.env.TSR_VITE_DEBUG &&
4041
['true', 'server-functions-plugin'].includes(process.env.TSR_VITE_DEBUG)
4142

43+
const validateServerFnIdVirtualModule = `virtual:tanstack-start-validate-server-fn-id`
44+
45+
function parseIdQuery(id: string): {
46+
filename: string
47+
query: {
48+
[k: string]: string
49+
}
50+
} {
51+
if (!id.includes('?')) return { filename: id, query: {} }
52+
const [filename, rawQuery] = id.split(`?`, 2) as [string, string]
53+
const query = Object.fromEntries(new URLSearchParams(rawQuery))
54+
return { filename, query }
55+
}
56+
4257
export function TanStackServerFnPlugin(
4358
opts: TanStackServerFnPluginOpts,
4459
): Array<Plugin> {
4560
const directiveFnsById: Record<string, DirectiveFn> = {}
46-
let serverDevEnv: DevEnvironment | undefined
4761

4862
const onDirectiveFnsById = (d: Record<string, DirectiveFn>) => {
49-
if (serverDevEnv) {
50-
return
51-
}
5263
if (debug) {
5364
console.info(`onDirectiveFnsById received: `, d)
5465
}
@@ -152,6 +163,26 @@ export function TanStackServerFnPlugin(
152163
provider: opts.provider,
153164
callers: opts.callers,
154165
}),
166+
{
167+
name: 'tanstack-start-server-fn-vite-plugin-validate-serverfn-id',
168+
apply: 'serve',
169+
load: {
170+
filter: {
171+
id: new RegExp(
172+
`^${resolveViteId(validateServerFnIdVirtualModule)}?.+`,
173+
),
174+
},
175+
handler(id) {
176+
const parsed = parseIdQuery(id)
177+
assert(parsed)
178+
assert(parsed.query.id)
179+
if (directiveFnsById[parsed.query.id]) {
180+
return `export {}`
181+
}
182+
this.error(`Invalid server function ID: ${parsed.query.id}`)
183+
},
184+
},
185+
},
155186
{
156187
// On the server, we need to be able to read the server-function manifest from the client build.
157188
// This is likely used in the handler for server functions, so we can find the server function
@@ -191,6 +222,8 @@ export function TanStackServerFnPlugin(
191222
if (this.environment.mode !== 'build') {
192223
const mod = `
193224
export async function getServerFnById(id) {
225+
const validateIdImport = ${JSON.stringify(validateServerFnIdVirtualModule)} + '?id=' + encodeURIComponent(id)
226+
await import(/* @vite-ignore */ '/@id/__x00__' + validateIdImport)
194227
const decoded = Buffer.from(id, 'base64url').toString('utf8')
195228
const devServerFn = JSON.parse(decoded)
196229
const mod = await import(/* @vite-ignore */ devServerFn.file)

0 commit comments

Comments
 (0)