Allow custom path for preview mode cookies (#38313)
* Allow custom path for preview mode cookies * update params order and tests * update tests * fix tests and update docs Co-authored-by: JJ Kasper <jj@jjsweb.site>
This commit is contained in:
parent
963585a4fc
commit
a5029e9fd4
6 changed files with 67 additions and 8 deletions
|
@ -194,10 +194,12 @@ Then, send a request to `/api/clear-preview-mode-cookies` to invoke the API Rout
|
|||
`setPreviewData` takes an optional second parameter which should be an options object. It accepts the following keys:
|
||||
|
||||
- `maxAge`: Specifies the number (in seconds) for the preview session to last for.
|
||||
- `path`: Specifies the path the cookie should be applied under. Defaults to `/` enabling preview mode for all paths.
|
||||
|
||||
```js
|
||||
setPreviewData(data, {
|
||||
maxAge: 60 * 60, // The preview mode cookies expire in 1 hour
|
||||
path: '/about', // The preview mode cookies apply to paths with /about
|
||||
})
|
||||
```
|
||||
|
||||
|
|
|
@ -469,6 +469,7 @@ function setPreviewData<T>(
|
|||
data: object | string, // TODO: strict runtime type checking
|
||||
options: {
|
||||
maxAge?: number
|
||||
path?: string
|
||||
} & __ApiPreviewProps
|
||||
): NextApiResponse<T> {
|
||||
if (isNotValidData(options.previewModeId)) {
|
||||
|
@ -522,6 +523,9 @@ function setPreviewData<T>(
|
|||
...(options.maxAge !== undefined
|
||||
? ({ maxAge: options.maxAge } as CookieSerializeOptions)
|
||||
: undefined),
|
||||
...(options.path !== undefined
|
||||
? ({ path: options.path } as CookieSerializeOptions)
|
||||
: undefined),
|
||||
}),
|
||||
serialize(COOKIE_NAME_PRERENDER_DATA, payload, {
|
||||
httpOnly: true,
|
||||
|
@ -531,6 +535,9 @@ function setPreviewData<T>(
|
|||
...(options.maxAge !== undefined
|
||||
? ({ maxAge: options.maxAge } as CookieSerializeOptions)
|
||||
: undefined),
|
||||
...(options.path !== undefined
|
||||
? ({ path: options.path } as CookieSerializeOptions)
|
||||
: undefined),
|
||||
}),
|
||||
])
|
||||
return res
|
||||
|
|
|
@ -252,6 +252,11 @@ export type NextApiResponse<T = any> = ServerResponse & {
|
|||
* when the client shuts down (browser is closed).
|
||||
*/
|
||||
maxAge?: number
|
||||
/**
|
||||
* Specifies the path for the preview session to work under. By default,
|
||||
* the path is considered the "default path", i.e., any pages under "/".
|
||||
*/
|
||||
path?: string
|
||||
}
|
||||
) => NextApiResponse<T>
|
||||
clearPreviewData: () => NextApiResponse<T>
|
||||
|
|
|
@ -6,14 +6,12 @@ export default (req, res) => {
|
|||
return res.status(500).end('too big')
|
||||
}
|
||||
} else {
|
||||
res.setPreviewData(
|
||||
req.query,
|
||||
req.query.cookieMaxAge
|
||||
? {
|
||||
maxAge: req.query.cookieMaxAge,
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
res.setPreviewData(req.query, {
|
||||
...(req.query.cookieMaxAge
|
||||
? { maxAge: req.query.cookieMaxAge }
|
||||
: undefined),
|
||||
...(req.query.cookiePath ? { path: req.query.cookiePath } : undefined),
|
||||
})
|
||||
}
|
||||
|
||||
res.status(200).end()
|
||||
|
|
|
@ -121,6 +121,26 @@ function runTests(startServer = nextStart) {
|
|||
expect(cookies[1]).toHaveProperty('__next_preview_data')
|
||||
expect(cookies[1]['Max-Age']).toBe(expiry)
|
||||
})
|
||||
it('should set custom path cookies', async () => {
|
||||
const path = '/path'
|
||||
const res = await fetchViaHTTP(appPort, '/api/preview', {
|
||||
cookiePath: path,
|
||||
})
|
||||
expect(res.status).toBe(200)
|
||||
|
||||
const originalCookies = res.headers.get('set-cookie').split(',')
|
||||
const cookies = originalCookies.map(cookie.parse)
|
||||
|
||||
expect(originalCookies.every((c) => c.includes('; Secure;'))).toBe(true)
|
||||
|
||||
expect(cookies.length).toBe(2)
|
||||
expect(cookies[0]).toMatchObject({ Path: path, SameSite: 'None' })
|
||||
expect(cookies[0]).toHaveProperty('__prerender_bypass')
|
||||
expect(cookies[0]['Path']).toBe(path)
|
||||
expect(cookies[0]).toMatchObject({ Path: path, SameSite: 'None' })
|
||||
expect(cookies[1]).toHaveProperty('__next_preview_data')
|
||||
expect(cookies[1]['Path']).toBe(path)
|
||||
})
|
||||
it('should not return fallback page on preview request', async () => {
|
||||
const res = await fetchViaHTTP(
|
||||
appPort,
|
||||
|
|
|
@ -44,6 +44,16 @@ describe('splitCookiesString', () => {
|
|||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
it('should parse path', () => {
|
||||
const { joined, expected } = generateCookies({
|
||||
name: 'foo',
|
||||
value: 'bar',
|
||||
path: '/path',
|
||||
})
|
||||
const result = splitCookiesString(joined)
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
it('should parse with all the options', () => {
|
||||
const { joined, expected } = generateCookies({
|
||||
name: 'foo',
|
||||
|
@ -111,6 +121,23 @@ describe('splitCookiesString', () => {
|
|||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
it('should parse path', () => {
|
||||
const { joined, expected } = generateCookies(
|
||||
{
|
||||
name: 'foo',
|
||||
value: 'bar',
|
||||
path: '/path',
|
||||
},
|
||||
{
|
||||
name: 'x',
|
||||
value: 'y',
|
||||
path: '/path',
|
||||
}
|
||||
)
|
||||
const result = splitCookiesString(joined)
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
it('should parse with all the options', () => {
|
||||
const { joined, expected } = generateCookies(
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue