Spaces:
Running
Running
| ; | |
| Object.defineProperty(exports, "__esModule", { | |
| value: true | |
| }); | |
| Object.defineProperty(exports, "apiResolver", { | |
| enumerable: true, | |
| get: function() { | |
| return apiResolver; | |
| } | |
| }); | |
| const _bytes = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/bytes")); | |
| const _etag = require("../../lib/etag"); | |
| const _sendpayload = require("../../send-payload"); | |
| const _stream = require("stream"); | |
| const _iserror = /*#__PURE__*/ _interop_require_default(require("../../../lib/is-error")); | |
| const _utils = require("../../../shared/lib/utils"); | |
| const _interopdefault = require("../../../lib/interop-default"); | |
| const _index = require("./../index"); | |
| const _getcookieparser = require("./../get-cookie-parser"); | |
| const _constants = require("../../../lib/constants"); | |
| const _trygetpreviewdata = require("./try-get-preview-data"); | |
| const _parsebody = require("./parse-body"); | |
| function _interop_require_default(obj) { | |
| return obj && obj.__esModule ? obj : { | |
| default: obj | |
| }; | |
| } | |
| function getMaxContentLength(responseLimit) { | |
| if (responseLimit && typeof responseLimit !== 'boolean') { | |
| return _bytes.default.parse(responseLimit); | |
| } | |
| return _index.RESPONSE_LIMIT_DEFAULT; | |
| } | |
| /** | |
| * Send `any` body to response | |
| * @param req request object | |
| * @param res response object | |
| * @param body of response | |
| */ function sendData(req, res, body) { | |
| if (body === null || body === undefined) { | |
| res.end(); | |
| return; | |
| } | |
| // strip irrelevant headers/body | |
| if (res.statusCode === 204 || res.statusCode === 304) { | |
| res.removeHeader('Content-Type'); | |
| res.removeHeader('Content-Length'); | |
| res.removeHeader('Transfer-Encoding'); | |
| if (process.env.NODE_ENV === 'development' && body) { | |
| console.warn(`A body was attempted to be set with a 204 statusCode for ${req.url}, this is invalid and the body was ignored.\n` + `See more info here https://nextjs.org/docs/messages/invalid-api-status-body`); | |
| } | |
| res.end(); | |
| return; | |
| } | |
| const contentType = res.getHeader('Content-Type'); | |
| if (body instanceof _stream.Stream) { | |
| if (!contentType) { | |
| res.setHeader('Content-Type', 'application/octet-stream'); | |
| } | |
| body.pipe(res); | |
| return; | |
| } | |
| const isJSONLike = [ | |
| 'object', | |
| 'number', | |
| 'boolean' | |
| ].includes(typeof body); | |
| const stringifiedBody = isJSONLike ? JSON.stringify(body) : body; | |
| const etag = (0, _etag.generateETag)(stringifiedBody); | |
| if ((0, _sendpayload.sendEtagResponse)(req, res, etag)) { | |
| return; | |
| } | |
| if (Buffer.isBuffer(body)) { | |
| if (!contentType) { | |
| res.setHeader('Content-Type', 'application/octet-stream'); | |
| } | |
| res.setHeader('Content-Length', body.length); | |
| res.end(body); | |
| return; | |
| } | |
| if (isJSONLike) { | |
| res.setHeader('Content-Type', _constants.JSON_CONTENT_TYPE_HEADER); | |
| } | |
| res.setHeader('Content-Length', Buffer.byteLength(stringifiedBody)); | |
| res.end(stringifiedBody); | |
| } | |
| /** | |
| * Send `JSON` object | |
| * @param res response object | |
| * @param jsonBody of data | |
| */ function sendJson(res, jsonBody) { | |
| // Set header to application/json | |
| res.setHeader('Content-Type', _constants.JSON_CONTENT_TYPE_HEADER); | |
| // Use send to handle request | |
| res.send(JSON.stringify(jsonBody)); | |
| } | |
| function isValidData(str) { | |
| return typeof str === 'string' && str.length >= 16; | |
| } | |
| function setDraftMode(res, options) { | |
| if (!isValidData(options.previewModeId)) { | |
| throw Object.defineProperty(new Error('invariant: invalid previewModeId'), "__NEXT_ERROR_CODE", { | |
| value: "E169", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| const expires = options.enable ? undefined : new Date(0); | |
| // To delete a cookie, set `expires` to a date in the past: | |
| // https://tools.ietf.org/html/rfc6265#section-4.1.1 | |
| // `Max-Age: 0` is not valid, thus ignored, and the cookie is persisted. | |
| const { serialize } = require('next/dist/compiled/cookie'); | |
| const previous = res.getHeader('Set-Cookie'); | |
| res.setHeader(`Set-Cookie`, [ | |
| ...typeof previous === 'string' ? [ | |
| previous | |
| ] : Array.isArray(previous) ? previous : [], | |
| serialize(_index.COOKIE_NAME_PRERENDER_BYPASS, options.previewModeId, { | |
| httpOnly: true, | |
| sameSite: process.env.NODE_ENV !== 'development' ? 'none' : 'lax', | |
| secure: process.env.NODE_ENV !== 'development', | |
| path: '/', | |
| expires | |
| }) | |
| ]); | |
| return res; | |
| } | |
| function setPreviewData(res, data, options) { | |
| if (!isValidData(options.previewModeId)) { | |
| throw Object.defineProperty(new Error('invariant: invalid previewModeId'), "__NEXT_ERROR_CODE", { | |
| value: "E169", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| if (!isValidData(options.previewModeEncryptionKey)) { | |
| throw Object.defineProperty(new Error('invariant: invalid previewModeEncryptionKey'), "__NEXT_ERROR_CODE", { | |
| value: "E334", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| if (!isValidData(options.previewModeSigningKey)) { | |
| throw Object.defineProperty(new Error('invariant: invalid previewModeSigningKey'), "__NEXT_ERROR_CODE", { | |
| value: "E436", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| const jsonwebtoken = require('next/dist/compiled/jsonwebtoken'); | |
| const { encryptWithSecret } = require('../../crypto-utils'); | |
| 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 Object.defineProperty(new Error(`Preview data is limited to 2KB currently, reduce how much data you are storing as preview data to continue`), "__NEXT_ERROR_CODE", { | |
| value: "E465", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| const { serialize } = require('next/dist/compiled/cookie'); | |
| const previous = res.getHeader('Set-Cookie'); | |
| res.setHeader(`Set-Cookie`, [ | |
| ...typeof previous === 'string' ? [ | |
| previous | |
| ] : Array.isArray(previous) ? previous : [], | |
| serialize(_index.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 | |
| } : undefined, | |
| ...options.path !== undefined ? { | |
| path: options.path | |
| } : undefined | |
| }), | |
| serialize(_index.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 | |
| } : undefined, | |
| ...options.path !== undefined ? { | |
| path: options.path | |
| } : undefined | |
| }) | |
| ]); | |
| return res; | |
| } | |
| async function revalidate(urlPath, opts, req, context) { | |
| if (typeof urlPath !== 'string' || !urlPath.startsWith('/')) { | |
| throw Object.defineProperty(new Error(`Invalid urlPath provided to revalidate(), must be a path e.g. /blog/post-1, received ${urlPath}`), "__NEXT_ERROR_CODE", { | |
| value: "E153", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| const revalidateHeaders = { | |
| [_constants.PRERENDER_REVALIDATE_HEADER]: context.previewModeId, | |
| ...opts.unstable_onlyGenerated ? { | |
| [_constants.PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER]: '1' | |
| } : {} | |
| }; | |
| const allowedRevalidateHeaderKeys = [ | |
| ...context.allowedRevalidateHeaderKeys || [] | |
| ]; | |
| if (context.trustHostHeader || context.dev) { | |
| allowedRevalidateHeaderKeys.push('cookie'); | |
| } | |
| if (context.trustHostHeader) { | |
| allowedRevalidateHeaderKeys.push('x-vercel-protection-bypass'); | |
| } | |
| for (const key of Object.keys(req.headers)){ | |
| if (allowedRevalidateHeaderKeys.includes(key)) { | |
| revalidateHeaders[key] = req.headers[key]; | |
| } | |
| } | |
| const internalRevalidate = context.internalRevalidate; | |
| try { | |
| // We use the revalidate in router-server if available. | |
| // If we are operating without router-server (serverless) | |
| // we must go through network layer with fetch request | |
| if (internalRevalidate) { | |
| return await internalRevalidate({ | |
| urlPath, | |
| revalidateHeaders, | |
| opts | |
| }); | |
| } | |
| if (context.trustHostHeader) { | |
| const res = await fetch(`https://${req.headers.host}${urlPath}`, { | |
| method: 'HEAD', | |
| headers: revalidateHeaders | |
| }); | |
| // we use the cache header to determine successful revalidate as | |
| // a non-200 status code can be returned from a successful revalidate | |
| // e.g. notFound: true returns 404 status code but is successful | |
| const cacheHeader = res.headers.get('x-vercel-cache') || res.headers.get('x-nextjs-cache'); | |
| if ((cacheHeader == null ? void 0 : cacheHeader.toUpperCase()) !== 'REVALIDATED' && res.status !== 200 && !(res.status === 404 && opts.unstable_onlyGenerated)) { | |
| throw Object.defineProperty(new Error(`Invalid response ${res.status}`), "__NEXT_ERROR_CODE", { | |
| value: "E175", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| } else { | |
| throw Object.defineProperty(new Error(`Invariant: missing internal router-server-methods this is an internal bug`), "__NEXT_ERROR_CODE", { | |
| value: "E676", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| } catch (err) { | |
| throw Object.defineProperty(new Error(`Failed to revalidate ${urlPath}: ${(0, _iserror.default)(err) ? err.message : err}`), "__NEXT_ERROR_CODE", { | |
| value: "E240", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| } | |
| async function apiResolver(req, res, query, resolverModule, apiContext, propagateError, dev, page, onError) { | |
| const apiReq = req; | |
| const apiRes = res; | |
| try { | |
| var _config_api, _config_api1, _config_api2; | |
| if (!resolverModule) { | |
| res.statusCode = 404; | |
| res.end('Not Found'); | |
| return; | |
| } | |
| const config = resolverModule.config || {}; | |
| const bodyParser = ((_config_api = config.api) == null ? void 0 : _config_api.bodyParser) !== false; | |
| const responseLimit = ((_config_api1 = config.api) == null ? void 0 : _config_api1.responseLimit) ?? true; | |
| const externalResolver = ((_config_api2 = config.api) == null ? void 0 : _config_api2.externalResolver) || false; | |
| // Parsing of cookies | |
| (0, _index.setLazyProp)({ | |
| req: apiReq | |
| }, 'cookies', (0, _getcookieparser.getCookieParser)(req.headers)); | |
| // Ensure req.query is a writable, enumerable property by using Object.defineProperty. | |
| // This addresses Express 5.x, which defines query as a getter only (read-only). | |
| Object.defineProperty(apiReq, 'query', { | |
| value: { | |
| ...query | |
| }, | |
| writable: true, | |
| enumerable: true, | |
| configurable: true | |
| }); | |
| // Parsing preview data | |
| (0, _index.setLazyProp)({ | |
| req: apiReq | |
| }, 'previewData', ()=>(0, _trygetpreviewdata.tryGetPreviewData)(req, res, apiContext, !!apiContext.multiZoneDraftMode)); | |
| // Checking if preview mode is enabled | |
| (0, _index.setLazyProp)({ | |
| req: apiReq | |
| }, 'preview', ()=>apiReq.previewData !== false ? true : undefined); | |
| // Set draftMode to the same value as preview | |
| (0, _index.setLazyProp)({ | |
| req: apiReq | |
| }, 'draftMode', ()=>apiReq.preview); | |
| // Parsing of body | |
| if (bodyParser && !apiReq.body) { | |
| apiReq.body = await (0, _parsebody.parseBody)(apiReq, config.api && config.api.bodyParser && config.api.bodyParser.sizeLimit ? config.api.bodyParser.sizeLimit : '1mb'); | |
| } | |
| let contentLength = 0; | |
| const maxContentLength = getMaxContentLength(responseLimit); | |
| const writeData = apiRes.write; | |
| const endResponse = apiRes.end; | |
| apiRes.write = (...args)=>{ | |
| contentLength += Buffer.byteLength(args[0] || ''); | |
| return writeData.apply(apiRes, args); | |
| }; | |
| apiRes.end = (...args)=>{ | |
| if (args.length && typeof args[0] !== 'function') { | |
| contentLength += Buffer.byteLength(args[0] || ''); | |
| } | |
| if (responseLimit && contentLength >= maxContentLength) { | |
| console.warn(`API response for ${req.url} exceeds ${_bytes.default.format(maxContentLength)}. API Routes are meant to respond quickly. https://nextjs.org/docs/messages/api-routes-response-size-limit`); | |
| } | |
| return endResponse.apply(apiRes, args); | |
| }; | |
| apiRes.status = (statusCode)=>(0, _index.sendStatusCode)(apiRes, statusCode); | |
| apiRes.send = (data)=>sendData(apiReq, apiRes, data); | |
| apiRes.json = (data)=>sendJson(apiRes, data); | |
| apiRes.redirect = (statusOrUrl, url)=>(0, _index.redirect)(apiRes, statusOrUrl, url); | |
| apiRes.setDraftMode = (options = { | |
| enable: true | |
| })=>setDraftMode(apiRes, Object.assign({}, apiContext, options)); | |
| apiRes.setPreviewData = (data, options = {})=>setPreviewData(apiRes, data, Object.assign({}, apiContext, options)); | |
| apiRes.clearPreviewData = (options = {})=>(0, _index.clearPreviewData)(apiRes, options); | |
| apiRes.revalidate = (urlPath, opts)=>revalidate(urlPath, opts || {}, req, apiContext); | |
| const resolver = (0, _interopdefault.interopDefault)(resolverModule); | |
| let wasPiped = false; | |
| if (process.env.NODE_ENV !== 'production') { | |
| // listen for pipe event and don't show resolve warning | |
| res.once('pipe', ()=>wasPiped = true); | |
| } | |
| const apiRouteResult = await resolver(req, res); | |
| if (process.env.NODE_ENV !== 'production') { | |
| if (typeof apiRouteResult !== 'undefined') { | |
| if (apiRouteResult instanceof Response) { | |
| throw Object.defineProperty(new Error('API route returned a Response object in the Node.js runtime, this is not supported. Please use `runtime: "edge"` instead: https://nextjs.org/docs/api-routes/edge-api-routes'), "__NEXT_ERROR_CODE", { | |
| value: "E36", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| console.warn(`API handler should not return a value, received ${typeof apiRouteResult}.`); | |
| } | |
| if (!externalResolver && !(0, _utils.isResSent)(res) && !wasPiped) { | |
| console.warn(`API resolved without sending a response for ${req.url}, this may result in stalled requests.`); | |
| } | |
| } | |
| } catch (err) { | |
| await (onError == null ? void 0 : onError(err, { | |
| method: req.method || 'GET', | |
| headers: req.headers, | |
| path: req.url || '/' | |
| }, { | |
| routerKind: 'Pages Router', | |
| routePath: page || '', | |
| routeType: 'route', | |
| revalidateReason: undefined | |
| })); | |
| if (err instanceof _index.ApiError) { | |
| (0, _index.sendError)(apiRes, err.statusCode, err.message); | |
| } else { | |
| if (dev) { | |
| if ((0, _iserror.default)(err)) { | |
| err.page = page; | |
| } | |
| throw err; | |
| } | |
| console.error(err); | |
| if (propagateError) { | |
| throw err; | |
| } | |
| (0, _index.sendError)(apiRes, 500, 'Internal Server Error'); | |
| } | |
| } | |
| } | |
| //# sourceMappingURL=api-resolver.js.map |