Skip to content

Commit 60b5b3a

Browse files
Merge branch 'canary' into bump-turbopack
2 parents 7859963 + 4b4925f commit 60b5b3a

File tree

17 files changed

+242
-98
lines changed

17 files changed

+242
-98
lines changed

packages/next/src/build/index.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -301,23 +301,6 @@ export default async function build(
301301
NextBuildContext.appDir = appDir
302302
hasAppDir = Boolean(appDir)
303303

304-
if (isAppDirEnabled && hasAppDir) {
305-
if (
306-
(!process.env.__NEXT_TEST_MODE ||
307-
process.env.__NEXT_TEST_MODE === 'e2e') &&
308-
ciEnvironment.hasNextSupport
309-
) {
310-
const requireHook = require.resolve('../server/require-hook')
311-
const contents = await promises.readFile(requireHook, 'utf8')
312-
await promises.writeFile(
313-
requireHook,
314-
`process.env.__NEXT_PRIVATE_PREBUNDLED_REACT = '${
315-
config.experimental.serverActions ? 'experimental' : 'next'
316-
}'\n${contents}`
317-
)
318-
}
319-
}
320-
321304
const isSrcDir = path
322305
.relative(dir, pagesDir || appDir || '')
323306
.startsWith('src')

packages/next/src/client/components/layout-router.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ class InnerScrollAndFocusHandler extends React.Component<ScrollAndFocusHandlerPr
211211

212212
// State is mutated to ensure that the focus and scroll is applied only once.
213213
focusAndScrollRef.apply = false
214+
focusAndScrollRef.hashFragment = null
215+
focusAndScrollRef.segmentPaths = []
214216

215217
handleSmoothScroll(
216218
() => {

packages/next/src/client/components/redirect.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { requestAsyncStorage } from './request-async-storage'
2+
import type { ResponseCookies } from '../../server/web/spec-extension/cookies'
3+
14
const REDIRECT_ERROR_CODE = 'NEXT_REDIRECT'
25

36
export enum RedirectType {
@@ -7,18 +10,20 @@ export enum RedirectType {
710

811
type RedirectError<U extends string> = Error & {
912
digest: `${typeof REDIRECT_ERROR_CODE};${RedirectType};${U}`
13+
mutableCookies: ResponseCookies
1014
}
1115

1216
export function getRedirectError(
1317
url: string,
1418
type: RedirectType
1519
): RedirectError<typeof url> {
16-
// eslint-disable-next-line no-throw-literal
17-
const error = new Error(REDIRECT_ERROR_CODE)
18-
;(
19-
error as RedirectError<typeof url>
20-
).digest = `${REDIRECT_ERROR_CODE};${type};${url}`
21-
return error as RedirectError<typeof url>
20+
const error = new Error(REDIRECT_ERROR_CODE) as RedirectError<typeof url>
21+
error.digest = `${REDIRECT_ERROR_CODE};${type};${url}`
22+
const requestStore = requestAsyncStorage.getStore()
23+
if (requestStore) {
24+
error.mutableCookies = requestStore.mutableCookies
25+
}
26+
return error
2227
}
2328

2429
/**

packages/next/src/server/app-render/action-handler.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { FlightRenderResult } from './flight-render-result'
2222
import { ActionResult } from './types'
2323
import { ActionAsyncStorage } from '../../client/components/action-async-storage'
2424
import { filterReqHeaders, forbiddenHeaders } from '../lib/server-ipc/utils'
25+
import { appendMutableCookies } from '../web/spec-extension/adapters/request-cookies'
2526

2627
function nodeToWebReadableStream(nodeReadable: import('stream').Readable) {
2728
if (process.env.NEXT_RUNTIME !== 'edge') {
@@ -377,6 +378,16 @@ export async function handleAction({
377378
)
378379
}
379380

381+
if (err.mutableCookies) {
382+
const headers = new Headers()
383+
384+
// If there were mutable cookies set, we need to set them on the
385+
// response.
386+
if (appendMutableCookies(headers, err.mutableCookies)) {
387+
res.setHeader('set-cookie', Array.from(headers.values()))
388+
}
389+
}
390+
380391
res.setHeader('Location', redirectUrl)
381392
res.statusCode = 303
382393
return new RenderResult('')

packages/next/src/server/app-render/app-render.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import {
7272
import { handleAction } from './action-handler'
7373
import { NEXT_DYNAMIC_NO_SSR_CODE } from '../../shared/lib/lazy-dynamic/no-ssr-error'
7474
import { warn } from '../../build/output/log'
75+
import { appendMutableCookies } from '../web/spec-extension/adapters/request-cookies'
7576

7677
export const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'
7778

@@ -1505,6 +1506,15 @@ export async function renderToHTMLOrFlight(
15051506
}
15061507
if (isRedirectError(err)) {
15071508
res.statusCode = 307
1509+
if (err.mutableCookies) {
1510+
const headers = new Headers()
1511+
1512+
// If there were mutable cookies set, we need to set them on the
1513+
// response.
1514+
if (appendMutableCookies(headers, err.mutableCookies)) {
1515+
res.setHeader('set-cookie', Array.from(headers.values()))
1516+
}
1517+
}
15081518
res.setHeader('Location', getURLFromRedirectError(err))
15091519
}
15101520

packages/next/src/server/async-storage/request-async-storage-wrapper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function getMutableCookies(
4141
res: ServerResponse | BaseNextResponse | undefined
4242
): ResponseCookies {
4343
const cookies = new RequestCookies(HeadersAdapter.from(headers))
44-
return MutableRequestCookiesAdapter.seal(cookies, res)
44+
return MutableRequestCookiesAdapter.wrap(cookies, res)
4545
}
4646

4747
export type RequestContext = {

packages/next/src/server/future/route-modules/app-route/helpers/resolve-handler-error.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function resolveHandlerError(err: any): Response | false {
1616
}
1717

1818
// This is a redirect error! Send the redirect response.
19-
return handleTemporaryRedirectResponse(redirect)
19+
return handleTemporaryRedirectResponse(redirect, err.mutableCookies)
2020
}
2121

2222
if (isNotFoundError(err)) {

packages/next/src/server/future/route-modules/app-route/module.ts

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,8 @@ import { RouteKind } from '../../route-kind'
3131
import * as Log from '../../../../build/output/log'
3232
import { autoImplementMethods } from './helpers/auto-implement-methods'
3333
import { getNonStaticMethods } from './helpers/get-non-static-methods'
34-
import { SYMBOL_MODIFY_COOKIE_VALUES } from '../../../web/spec-extension/adapters/request-cookies'
35-
import { ResponseCookies } from '../../../web/spec-extension/cookies'
36-
import { HeadersAdapter } from '../../../web/spec-extension/adapters/headers'
3734
import { PrerenderManifest } from '../../../../build'
35+
import { appendMutableCookies } from '../../../web/spec-extension/adapters/request-cookies'
3836

3937
/**
4038
* AppRouteRouteHandlerContext is the context that is passed to the route
@@ -358,54 +356,19 @@ export class AppRouteRouteModule extends RouteModule<
358356
// It's possible cookies were set in the handler, so we need
359357
// to merge the modified cookies and the returned response
360358
// here.
361-
// TODO: Move this into a helper function.
362359
const requestStore = this.requestAsyncStorage.getStore()
363360
if (requestStore && requestStore.mutableCookies) {
364-
const modifiedCookieValues = (
365-
requestStore.mutableCookies as any
366-
)[SYMBOL_MODIFY_COOKIE_VALUES] as NonNullable<
367-
ReturnType<InstanceType<typeof ResponseCookies>['get']>
368-
>[]
369-
if (modifiedCookieValues.length) {
370-
// Return a new response that extends the response with
371-
// the modified cookies as fallbacks. `res`' cookies
372-
// will still take precedence.
373-
const resCookies = new ResponseCookies(
374-
HeadersAdapter.from(res.headers)
361+
const headers = new Headers(res.headers)
362+
if (
363+
appendMutableCookies(
364+
headers,
365+
requestStore.mutableCookies
375366
)
376-
const returnedCookies = resCookies.getAll()
377-
378-
// Set the modified cookies as fallbacks.
379-
for (const cookie of modifiedCookieValues) {
380-
resCookies.set(cookie)
381-
}
382-
// Set the original cookies as the final values.
383-
for (const cookie of returnedCookies) {
384-
resCookies.set(cookie)
385-
}
386-
387-
const responseHeaders = new Headers({})
388-
// Set all the headers except for the cookies.
389-
res.headers.forEach((value, key) => {
390-
if (key.toLowerCase() !== 'set-cookie') {
391-
responseHeaders.append(key, value)
392-
}
393-
})
394-
// Set the final cookies, need to append cookies one
395-
// at a time otherwise it might not work in some browsers.
396-
resCookies.getAll().forEach((cookie) => {
397-
const tempCookies = new ResponseCookies(new Headers())
398-
tempCookies.set(cookie)
399-
responseHeaders.append(
400-
'Set-Cookie',
401-
tempCookies.toString()
402-
)
403-
})
404-
367+
) {
405368
return new Response(res.body, {
406369
status: res.status,
407370
statusText: res.statusText,
408-
headers: responseHeaders,
371+
headers,
409372
})
410373
}
411374
}
Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,29 @@
1-
export function handleTemporaryRedirectResponse(url: string): Response {
2-
return new Response(null, {
3-
status: 302,
4-
statusText: 'Found',
5-
headers: {
6-
location: url,
7-
},
8-
})
1+
import { appendMutableCookies } from '../../../web/spec-extension/adapters/request-cookies'
2+
import { ResponseCookies } from '../../../web/spec-extension/cookies'
3+
4+
export function handleTemporaryRedirectResponse(
5+
url: string,
6+
mutableCookies: ResponseCookies
7+
): Response {
8+
const headers = new Headers({ location: url })
9+
10+
appendMutableCookies(headers, mutableCookies)
11+
12+
return new Response(null, { status: 307, headers })
913
}
1014

1115
export function handleBadRequestResponse(): Response {
12-
return new Response(null, {
13-
status: 400,
14-
statusText: 'Bad Request',
15-
})
16+
return new Response(null, { status: 400 })
1617
}
1718

1819
export function handleNotFoundResponse(): Response {
19-
return new Response(null, {
20-
status: 404,
21-
statusText: 'Not Found',
22-
})
20+
return new Response(null, { status: 404 })
2321
}
2422

2523
export function handleMethodNotAllowedResponse(): Response {
26-
return new Response(null, {
27-
status: 405,
28-
statusText: 'Method Not Allowed',
29-
})
24+
return new Response(null, { status: 405 })
3025
}
3126

3227
export function handleInternalServerErrorResponse(): Response {
33-
return new Response(null, {
34-
status: 500,
35-
statusText: 'Internal Server Error',
36-
})
28+
return new Response(null, { status: 500 })
3729
}

packages/next/src/server/web/spec-extension/adapters/request-cookies.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,53 @@ export class RequestCookiesAdapter {
4040
}
4141
}
4242

43-
export const SYMBOL_MODIFY_COOKIE_VALUES = Symbol.for('next.mutated.cookies')
43+
const SYMBOL_MODIFY_COOKIE_VALUES = Symbol.for('next.mutated.cookies')
44+
45+
function getModifiedCookieValues(cookies: ResponseCookies): ResponseCookie[] {
46+
const modified: ResponseCookie[] | undefined = (cookies as unknown as any)[
47+
SYMBOL_MODIFY_COOKIE_VALUES
48+
]
49+
if (!modified || !Array.isArray(modified) || modified.length === 0) {
50+
return []
51+
}
52+
53+
return modified
54+
}
55+
56+
export function appendMutableCookies(
57+
headers: Headers,
58+
mutableCookies: ResponseCookies
59+
): boolean {
60+
const modifiedCookieValues = getModifiedCookieValues(mutableCookies)
61+
if (modifiedCookieValues.length === 0) {
62+
return false
63+
}
64+
65+
// Return a new response that extends the response with
66+
// the modified cookies as fallbacks. `res`' cookies
67+
// will still take precedence.
68+
const resCookies = new ResponseCookies(headers)
69+
const returnedCookies = resCookies.getAll()
70+
71+
// Set the modified cookies as fallbacks.
72+
for (const cookie of modifiedCookieValues) {
73+
resCookies.set(cookie)
74+
}
75+
76+
// Set the original cookies as the final values.
77+
for (const cookie of returnedCookies) {
78+
resCookies.set(cookie)
79+
}
80+
81+
return true
82+
}
4483

4584
type ResponseCookie = NonNullable<
4685
ReturnType<InstanceType<typeof ResponseCookies>['get']>
4786
>
4887

4988
export class MutableRequestCookiesAdapter {
50-
public static seal(
89+
public static wrap(
5190
cookies: RequestCookies,
5291
res: ServerResponse | BaseNextResponse | undefined
5392
): ResponseCookies {

0 commit comments

Comments
 (0)