|
function setPreviewData<T>( |
|
res: NextApiResponse<T>, |
|
data: object | string, // TODO: strict runtime type checking |
|
options: { |
|
maxAge?: number |
|
} & __ApiPreviewProps |
|
): NextApiResponse<T> { |
|
if ( |
|
typeof options.previewModeId !== 'string' || |
|
options.previewModeId.length < 16 |
|
) { |
|
throw new Error('invariant: invalid previewModeId') |
|
} |
|
if ( |
|
typeof options.previewModeEncryptionKey !== 'string' || |
|
options.previewModeEncryptionKey.length < 16 |
|
) { |
|
throw new Error('invariant: invalid previewModeEncryptionKey') |
|
} |
|
if ( |
|
typeof options.previewModeSigningKey !== 'string' || |
|
options.previewModeSigningKey.length < 16 |
|
) { |
|
throw new Error('invariant: invalid previewModeSigningKey') |
|
} |
|
|
|
const jsonwebtoken = require('next/dist/compiled/jsonwebtoken') as typeof import('jsonwebtoken') |
|
|
|
const payload = jsonwebtoken.sign( |
|
{ |
|
data: encryptWithSecret( |
|
Buffer.from(options.previewModeEncryptionKey), |
|
JSON.stringify(data) |
|
), |
|
}, |
|
options.previewModeSigningKey, |
|
{ |
|
algorithm: 'HS256', |
|
...(options.maxAge !== undefined |
|
? { expiresIn: options.maxAge } |
|
: undefined), |
|
} |
|
) |
|
|
|
// limit preview mode cookie to 2KB since we shouldn't store too much |
|
// data here and browsers drop cookies over 4KB |
|
if (payload.length > 2048) { |
|
throw new Error( |
|
`Preview data is limited to 2KB currently, reduce how much data you are storing as preview data to continue` |
|
) |
|
} |
|
|
|
const { |
|
serialize, |
|
} = require('next/dist/compiled/cookie') as typeof import('cookie') |
|
const previous = res.getHeader('Set-Cookie') |
|
res.setHeader(`Set-Cookie`, [ |
|
...(typeof previous === 'string' |
|
? [previous] |
|
: Array.isArray(previous) |
|
? previous |
|
: []), |
|
serialize(COOKIE_NAME_PRERENDER_BYPASS, options.previewModeId, { |
|
httpOnly: true, |
|
sameSite: process.env.NODE_ENV !== 'development' ? 'none' : 'lax', |
|
secure: process.env.NODE_ENV !== 'development', |
|
path: '/', |
|
...(options.maxAge !== undefined |
|
? ({ maxAge: options.maxAge } as CookieSerializeOptions) |
|
: undefined), |
|
}), |
|
serialize(COOKIE_NAME_PRERENDER_DATA, payload, { |
|
httpOnly: true, |
|
sameSite: process.env.NODE_ENV !== 'development' ? 'none' : 'lax', |
|
secure: process.env.NODE_ENV !== 'development', |
|
path: '/', |
|
...(options.maxAge !== undefined |
|
? ({ maxAge: options.maxAge } as CookieSerializeOptions) |
|
: undefined), |
|
}), |
|
]) |
|
return res |
|
} |