Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f94f678

Browse files
committed
disallow next/rootparams in route handlers and server actions
1 parent 8275a51 commit f94f678

File tree

4 files changed

+74
-12
lines changed

4 files changed

+74
-12
lines changed

packages/next/errors.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,5 +716,7 @@
716716
"715": "%s must not be used within a client component. Next.js should be preventing it from being included in client components statically, but did not in this case.",
717717
"716": "Route %s used %s in Pages Router. This API is only available within App Router.",
718718
"717": "\\`unstable_rootParams\\` must not be used within a client component. Next.js should be preventing it from being included in client components statically, but did not in this case.",
719-
"718": "Missing workStore in %s"
719+
"718": "Missing workStore in %s",
720+
"719": "Route %s used %s inside a Route Handler. Support for this API in Route Handlers is planned for a future version of Next.js.",
721+
"720": "%s was used inside a Server Action. This is not supported. Functions from 'next/root-params' can only be called in the context of a route."
720722
}

packages/next/src/server/request/root-params.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
describeStringPropertyAccess,
2121
wellKnownProperties,
2222
} from '../../shared/lib/utils/reflect-utils'
23+
import { actionAsyncStorage } from '../app-render/action-async-storage.external'
2324

2425
interface CacheLifetime {}
2526
const CachedParams = new WeakMap<CacheLifetime, Promise<Params>>()
@@ -208,6 +209,23 @@ export async function getRootParam(paramName: string): Promise<ParamValue> {
208209
throw new InvariantError(`Missing workStore in ${apiName}`)
209210
}
210211

212+
const actionStore = actionAsyncStorage.getStore()
213+
if (actionStore) {
214+
if (actionStore.isAppRoute) {
215+
// TODO(root-params): add support for route handlers
216+
throw new Error(
217+
`Route ${workStore.route} used ${apiName} inside a Route Handler. Support for this API in Route Handlers is planned for a future version of Next.js.`
218+
)
219+
}
220+
if (actionStore.isAction) {
221+
// Actions are not fundamentally tied to a route (even if they're always submitted from some page),
222+
// so root params would be inconsistent if an action is called from multiple roots.
223+
throw new Error(
224+
`${apiName} was used inside a Server Action. This is not supported. Functions from 'next/root-params' can only be called in the context of a route.`
225+
)
226+
}
227+
}
228+
211229
const workUnitStore = workUnitAsyncStorage.getStore()
212230

213231
if (!workUnitStore) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { lang } from 'next/root-params'
2+
3+
export default function Page() {
4+
return (
5+
<form
6+
action={async () => {
7+
'use server'
8+
// not allowed, should error
9+
await lang()
10+
}}
11+
>
12+
<button type="submit">Submit form</button>
13+
</form>
14+
)
15+
}

test/e2e/app-dir/app-root-params-getters/simple.test.ts

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import { assertNoRedbox, retry } from 'next-test-utils'
33
import { join } from 'path'
44
import { createSandbox } from 'development-sandbox'
55
import { outdent } from 'outdent'
6+
import { createRequestTracker } from '../../../lib/e2e-utils/request-tracker'
67

78
describe('app-root-param-getters - simple', () => {
8-
const { next, isNextDev, isTurbopack } = nextTestSetup({
9+
const { next, isNextDev, isTurbopack, isNextDeploy } = nextTestSetup({
910
files: join(__dirname, 'fixtures', 'simple'),
1011
})
1112

@@ -89,18 +90,44 @@ describe('app-root-param-getters - simple', () => {
8990
})
9091
}
9192

92-
// root params currently don't work in route handlers.
93-
it.failing(
94-
'should allow reading root params in a route handler',
95-
async () => {
96-
const params = { lang: 'en', locale: 'us' }
97-
const response = await next.fetch(
98-
`/${params.lang}/${params.locale}/route-handler`
93+
it('should error when used in a server action', async () => {
94+
const params = { lang: 'en', locale: 'us' }
95+
const browser = await next.browser(
96+
`/${params.lang}/${params.locale}/server-action`
97+
)
98+
const tracker = createRequestTracker(browser)
99+
const [, response] = await tracker.captureResponse(
100+
async () => {
101+
await browser.elementByCss('button[type="submit"]').click()
102+
},
103+
{
104+
request: {
105+
method: 'POST',
106+
pathname: `/${params.lang}/${params.locale}/server-action`,
107+
},
108+
}
109+
)
110+
expect(response.status()).toBe(500)
111+
if (!isNextDeploy) {
112+
expect(next.cliOutput).toInclude(
113+
"`import('next/root-params').lang()` was used inside a Server Action. This is not supported. Functions from 'next/root-params' can only be called in the context of a route."
114+
)
115+
}
116+
})
117+
118+
// TODO(root-params): add support for route handlers
119+
it('should error when used in a route handler (until we implement it)', async () => {
120+
const params = { lang: 'en', locale: 'us' }
121+
const response = await next.fetch(
122+
`/${params.lang}/${params.locale}/route-handler`
123+
)
124+
expect(response.status).toBe(500)
125+
if (!isNextDeploy) {
126+
expect(next.cliOutput).toInclude(
127+
"Route /[lang]/[locale]/route-handler used `import('next/root-params').lang()` inside a Route Handler. Support for this API in Route Handlers is planned for a future version of Next.js."
99128
)
100-
expect(response.status).toBe(200)
101-
expect(await response.json()).toEqual(params)
102129
}
103-
)
130+
})
104131
})
105132

106133
/** Run cleanup after the current test. */

0 commit comments

Comments
 (0)