feat(blog): add file-based blog with dynamic slugs, MDX content and layout shell

- Introduced blog routing using Next.js App Router
- Implemented dynamic [slug] pages for blog posts
- Added MDX-based content loading via lib/posts
- Integrated shared TopBar layout with navigation
- Established clear content, lib and component separation
This commit is contained in:
PascalSchattenburg
2026-01-22 14:14:15 +01:00
parent b717952234
commit d147843c76
10412 changed files with 2475583 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
import type { BaseNextRequest, BaseNextResponse } from './';
import type { NodeNextRequest, NodeNextResponse } from './node';
import type { WebNextRequest, WebNextResponse } from './web';
/**
* This file provides some helpers that should be used in conjunction with
* explicit environment checks. When combined with the environment checks, it
* will ensure that the correct typings are used as well as enable code
* elimination.
*/
/**
* Type guard to determine if a request is a WebNextRequest. This does not
* actually check the type of the request, but rather the runtime environment.
* It's expected that when the runtime environment is the edge runtime, that any
* base request is a WebNextRequest.
*/
export declare const isWebNextRequest: (req: BaseNextRequest) => req is WebNextRequest;
/**
* Type guard to determine if a response is a WebNextResponse. This does not
* actually check the type of the response, but rather the runtime environment.
* It's expected that when the runtime environment is the edge runtime, that any
* base response is a WebNextResponse.
*/
export declare const isWebNextResponse: (res: BaseNextResponse) => res is WebNextResponse;
/**
* Type guard to determine if a request is a NodeNextRequest. This does not
* actually check the type of the request, but rather the runtime environment.
* It's expected that when the runtime environment is the node runtime, that any
* base request is a NodeNextRequest.
*/
export declare const isNodeNextRequest: (req: BaseNextRequest) => req is NodeNextRequest;
/**
* Type guard to determine if a response is a NodeNextResponse. This does not
* actually check the type of the response, but rather the runtime environment.
* It's expected that when the runtime environment is the node runtime, that any
* base response is a NodeNextResponse.
*/
export declare const isNodeNextResponse: (res: BaseNextResponse) => res is NodeNextResponse;

View File

@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
isNodeNextRequest: null,
isNodeNextResponse: null,
isWebNextRequest: null,
isWebNextResponse: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
isNodeNextRequest: function() {
return isNodeNextRequest;
},
isNodeNextResponse: function() {
return isNodeNextResponse;
},
isWebNextRequest: function() {
return isWebNextRequest;
},
isWebNextResponse: function() {
return isWebNextResponse;
}
});
const isWebNextRequest = (req)=>process.env.NEXT_RUNTIME === 'edge';
const isWebNextResponse = (res)=>process.env.NEXT_RUNTIME === 'edge';
const isNodeNextRequest = (req)=>process.env.NEXT_RUNTIME !== 'edge';
const isNodeNextResponse = (res)=>process.env.NEXT_RUNTIME !== 'edge';
//# sourceMappingURL=helpers.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/base-http/helpers.ts"],"sourcesContent":["import type { BaseNextRequest, BaseNextResponse } from './'\nimport type { NodeNextRequest, NodeNextResponse } from './node'\nimport type { WebNextRequest, WebNextResponse } from './web'\n\n/**\n * This file provides some helpers that should be used in conjunction with\n * explicit environment checks. When combined with the environment checks, it\n * will ensure that the correct typings are used as well as enable code\n * elimination.\n */\n\n/**\n * Type guard to determine if a request is a WebNextRequest. This does not\n * actually check the type of the request, but rather the runtime environment.\n * It's expected that when the runtime environment is the edge runtime, that any\n * base request is a WebNextRequest.\n */\nexport const isWebNextRequest = (req: BaseNextRequest): req is WebNextRequest =>\n process.env.NEXT_RUNTIME === 'edge'\n\n/**\n * Type guard to determine if a response is a WebNextResponse. This does not\n * actually check the type of the response, but rather the runtime environment.\n * It's expected that when the runtime environment is the edge runtime, that any\n * base response is a WebNextResponse.\n */\nexport const isWebNextResponse = (\n res: BaseNextResponse\n): res is WebNextResponse => process.env.NEXT_RUNTIME === 'edge'\n\n/**\n * Type guard to determine if a request is a NodeNextRequest. This does not\n * actually check the type of the request, but rather the runtime environment.\n * It's expected that when the runtime environment is the node runtime, that any\n * base request is a NodeNextRequest.\n */\nexport const isNodeNextRequest = (\n req: BaseNextRequest\n): req is NodeNextRequest => process.env.NEXT_RUNTIME !== 'edge'\n\n/**\n * Type guard to determine if a response is a NodeNextResponse. This does not\n * actually check the type of the response, but rather the runtime environment.\n * It's expected that when the runtime environment is the node runtime, that any\n * base response is a NodeNextResponse.\n */\nexport const isNodeNextResponse = (\n res: BaseNextResponse\n): res is NodeNextResponse => process.env.NEXT_RUNTIME !== 'edge'\n"],"names":["isNodeNextRequest","isNodeNextResponse","isWebNextRequest","isWebNextResponse","req","process","env","NEXT_RUNTIME","res"],"mappings":";;;;;;;;;;;;;;;;;IAoCaA,iBAAiB;eAAjBA;;IAUAC,kBAAkB;eAAlBA;;IA7BAC,gBAAgB;eAAhBA;;IASAC,iBAAiB;eAAjBA;;;AATN,MAAMD,mBAAmB,CAACE,MAC/BC,QAAQC,GAAG,CAACC,YAAY,KAAK;AAQxB,MAAMJ,oBAAoB,CAC/BK,MAC2BH,QAAQC,GAAG,CAACC,YAAY,KAAK;AAQnD,MAAMP,oBAAoB,CAC/BI,MAC2BC,QAAQC,GAAG,CAACC,YAAY,KAAK;AAQnD,MAAMN,qBAAqB,CAChCO,MAC4BH,QAAQC,GAAG,CAACC,YAAY,KAAK","ignoreList":[0]}

View File

@@ -0,0 +1,65 @@
import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http';
import type { I18NConfig } from '../config-shared';
import type { NextApiRequestCookies } from '../api-utils';
export interface BaseNextRequestConfig {
basePath: string | undefined;
i18n?: I18NConfig;
trailingSlash?: boolean | undefined;
}
export type FetchMetric = {
url: string;
idx: number;
end: number;
start: number;
method: string;
status: number;
cacheReason: string;
cacheStatus: 'hit' | 'miss' | 'skip' | 'hmr';
cacheWarning?: string;
};
export type FetchMetrics = Array<FetchMetric>;
export declare abstract class BaseNextRequest<Body = any> {
method: string;
url: string;
body: Body;
protected _cookies: NextApiRequestCookies | undefined;
abstract headers: IncomingHttpHeaders;
abstract fetchMetrics: FetchMetric[] | undefined;
constructor(method: string, url: string, body: Body);
get cookies(): Partial<{
[key: string]: string;
}>;
}
export declare abstract class BaseNextResponse<Destination = any> {
destination: Destination;
abstract statusCode: number | undefined;
abstract statusMessage: string | undefined;
abstract get sent(): boolean;
constructor(destination: Destination);
/**
* Sets a value for the header overwriting existing values
*/
abstract setHeader(name: string, value: string | string[]): this;
/**
* Removes a header
*/
abstract removeHeader(name: string): this;
/**
* Appends value for the given header name
*/
abstract appendHeader(name: string, value: string): this;
/**
* Get all values for a header as an array or undefined if no value is present
*/
abstract getHeaderValues(name: string): string[] | undefined;
abstract hasHeader(name: string): boolean;
/**
* Get values for a header concatenated using `,` or undefined if no value is present
*/
abstract getHeader(name: string): string | undefined;
abstract getHeaders(): OutgoingHttpHeaders;
abstract body(value: string): this;
abstract send(): void;
abstract onClose(callback: () => void): void;
redirect(destination: string, statusCode: number): this;
}

View File

@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
BaseNextRequest: null,
BaseNextResponse: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
BaseNextRequest: function() {
return BaseNextRequest;
},
BaseNextResponse: function() {
return BaseNextResponse;
}
});
const _redirectstatuscode = require("../../client/components/redirect-status-code");
const _getcookieparser = require("../api-utils/get-cookie-parser");
class BaseNextRequest {
constructor(method, url, body){
this.method = method;
this.url = url;
this.body = body;
}
// Utils implemented using the abstract methods above
get cookies() {
if (this._cookies) return this._cookies;
return this._cookies = (0, _getcookieparser.getCookieParser)(this.headers)();
}
}
class BaseNextResponse {
constructor(destination){
this.destination = destination;
}
// Utils implemented using the abstract methods above
redirect(destination, statusCode) {
this.setHeader('Location', destination);
this.statusCode = statusCode;
// Since IE11 doesn't support the 308 header add backwards
// compatibility using refresh header
if (statusCode === _redirectstatuscode.RedirectStatusCode.PermanentRedirect) {
this.setHeader('Refresh', `0;url=${destination}`);
}
return this;
}
}
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/base-http/index.ts"],"sourcesContent":["import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http'\nimport type { I18NConfig } from '../config-shared'\n\nimport { RedirectStatusCode } from '../../client/components/redirect-status-code'\nimport type { NextApiRequestCookies } from '../api-utils'\nimport { getCookieParser } from '../api-utils/get-cookie-parser'\n\nexport interface BaseNextRequestConfig {\n basePath: string | undefined\n i18n?: I18NConfig\n trailingSlash?: boolean | undefined\n}\n\nexport type FetchMetric = {\n url: string\n idx: number\n end: number\n start: number\n method: string\n status: number\n cacheReason: string\n cacheStatus: 'hit' | 'miss' | 'skip' | 'hmr'\n cacheWarning?: string\n}\n\nexport type FetchMetrics = Array<FetchMetric>\n\nexport abstract class BaseNextRequest<Body = any> {\n protected _cookies: NextApiRequestCookies | undefined\n public abstract headers: IncomingHttpHeaders\n public abstract fetchMetrics: FetchMetric[] | undefined\n\n constructor(\n public method: string,\n public url: string,\n public body: Body\n ) {}\n\n // Utils implemented using the abstract methods above\n\n public get cookies() {\n if (this._cookies) return this._cookies\n return (this._cookies = getCookieParser(this.headers)())\n }\n}\n\nexport abstract class BaseNextResponse<Destination = any> {\n abstract statusCode: number | undefined\n abstract statusMessage: string | undefined\n abstract get sent(): boolean\n\n constructor(public destination: Destination) {}\n\n /**\n * Sets a value for the header overwriting existing values\n */\n abstract setHeader(name: string, value: string | string[]): this\n\n /**\n * Removes a header\n */\n abstract removeHeader(name: string): this\n\n /**\n * Appends value for the given header name\n */\n abstract appendHeader(name: string, value: string): this\n\n /**\n * Get all values for a header as an array or undefined if no value is present\n */\n abstract getHeaderValues(name: string): string[] | undefined\n\n abstract hasHeader(name: string): boolean\n\n /**\n * Get values for a header concatenated using `,` or undefined if no value is present\n */\n abstract getHeader(name: string): string | undefined\n\n abstract getHeaders(): OutgoingHttpHeaders\n\n abstract body(value: string): this\n\n abstract send(): void\n\n abstract onClose(callback: () => void): void\n\n // Utils implemented using the abstract methods above\n\n public redirect(destination: string, statusCode: number) {\n this.setHeader('Location', destination)\n this.statusCode = statusCode\n\n // Since IE11 doesn't support the 308 header add backwards\n // compatibility using refresh header\n if (statusCode === RedirectStatusCode.PermanentRedirect) {\n this.setHeader('Refresh', `0;url=${destination}`)\n }\n\n return this\n }\n}\n"],"names":["BaseNextRequest","BaseNextResponse","constructor","method","url","body","cookies","_cookies","getCookieParser","headers","destination","redirect","statusCode","setHeader","RedirectStatusCode","PermanentRedirect"],"mappings":";;;;;;;;;;;;;;;IA2BsBA,eAAe;eAAfA;;IAmBAC,gBAAgB;eAAhBA;;;oCA3Ca;iCAEH;AAsBzB,MAAeD;IAKpBE,YACE,AAAOC,MAAc,EACrB,AAAOC,GAAW,EAClB,AAAOC,IAAU,CACjB;aAHOF,SAAAA;aACAC,MAAAA;aACAC,OAAAA;IACN;IAEH,qDAAqD;IAErD,IAAWC,UAAU;QACnB,IAAI,IAAI,CAACC,QAAQ,EAAE,OAAO,IAAI,CAACA,QAAQ;QACvC,OAAQ,IAAI,CAACA,QAAQ,GAAGC,IAAAA,gCAAe,EAAC,IAAI,CAACC,OAAO;IACtD;AACF;AAEO,MAAeR;IAKpBC,YAAY,AAAOQ,WAAwB,CAAE;aAA1BA,cAAAA;IAA2B;IAqC9C,qDAAqD;IAE9CC,SAASD,WAAmB,EAAEE,UAAkB,EAAE;QACvD,IAAI,CAACC,SAAS,CAAC,YAAYH;QAC3B,IAAI,CAACE,UAAU,GAAGA;QAElB,0DAA0D;QAC1D,qCAAqC;QACrC,IAAIA,eAAeE,sCAAkB,CAACC,iBAAiB,EAAE;YACvD,IAAI,CAACF,SAAS,CAAC,WAAW,CAAC,MAAM,EAAEH,aAAa;QAClD;QAEA,OAAO,IAAI;IACb;AACF","ignoreList":[0]}

View File

@@ -0,0 +1,50 @@
import type { ServerResponse, IncomingMessage } from 'http';
import type { Writable, Readable } from 'stream';
import { SYMBOL_CLEARED_COOKIES } from '../api-utils';
import type { NextApiRequestCookies } from '../api-utils';
import { NEXT_REQUEST_META } from '../request-meta';
import type { RequestMeta } from '../request-meta';
import { BaseNextRequest, BaseNextResponse, type FetchMetric } from './index';
import type { OutgoingHttpHeaders } from 'node:http';
type Req = IncomingMessage & {
[NEXT_REQUEST_META]?: RequestMeta;
cookies?: NextApiRequestCookies;
fetchMetrics?: FetchMetric[];
};
export declare class NodeNextRequest extends BaseNextRequest<Readable> {
private _req;
headers: import("http").IncomingHttpHeaders;
fetchMetrics: FetchMetric[] | undefined;
[NEXT_REQUEST_META]: RequestMeta;
constructor(_req: Req);
get originalRequest(): Req;
set originalRequest(value: Req);
private streaming;
}
export declare class NodeNextResponse extends BaseNextResponse<Writable> {
private _res;
private textBody;
[SYMBOL_CLEARED_COOKIES]?: boolean;
get originalResponse(): ServerResponse<IncomingMessage> & {
[SYMBOL_CLEARED_COOKIES]?: boolean;
};
constructor(_res: ServerResponse & {
[SYMBOL_CLEARED_COOKIES]?: boolean;
});
get sent(): boolean;
get statusCode(): number;
set statusCode(value: number);
get statusMessage(): string;
set statusMessage(value: string);
setHeader(name: string, value: string | string[]): this;
removeHeader(name: string): this;
getHeaderValues(name: string): string[] | undefined;
hasHeader(name: string): boolean;
getHeader(name: string): string | undefined;
getHeaders(): OutgoingHttpHeaders;
appendHeader(name: string, value: string): this;
body(value: string): this;
send(): void;
onClose(callback: () => void): void;
}
export {};

View File

@@ -0,0 +1,147 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
NodeNextRequest: null,
NodeNextResponse: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
NodeNextRequest: function() {
return NodeNextRequest;
},
NodeNextResponse: function() {
return NodeNextResponse;
}
});
const _apiutils = require("../api-utils");
const _requestmeta = require("../request-meta");
const _index = require("./index");
let prop;
class NodeNextRequest extends _index.BaseNextRequest {
static #_ = prop = _NEXT_REQUEST_META = _requestmeta.NEXT_REQUEST_META;
constructor(_req){
var _this__req;
super(_req.method.toUpperCase(), _req.url, _req), this._req = _req, this.headers = this._req.headers, this.fetchMetrics = (_this__req = this._req) == null ? void 0 : _this__req.fetchMetrics, this[_NEXT_REQUEST_META] = this._req[_requestmeta.NEXT_REQUEST_META] || {}, this.streaming = false;
}
get originalRequest() {
// Need to mimic these changes to the original req object for places where we use it:
// render.tsx, api/ssg requests
this._req[_requestmeta.NEXT_REQUEST_META] = this[_requestmeta.NEXT_REQUEST_META];
this._req.url = this.url;
this._req.cookies = this.cookies;
return this._req;
}
set originalRequest(value) {
this._req = value;
}
/**
* Returns the request body as a Web Readable Stream. The body here can only
* be read once as the body will start flowing as soon as the data handler
* is attached.
*
* @internal
*/ stream() {
if (this.streaming) {
throw Object.defineProperty(new Error('Invariant: NodeNextRequest.stream() can only be called once'), "__NEXT_ERROR_CODE", {
value: "E467",
enumerable: false,
configurable: true
});
}
this.streaming = true;
return new ReadableStream({
start: (controller)=>{
this._req.on('data', (chunk)=>{
controller.enqueue(new Uint8Array(chunk));
});
this._req.on('end', ()=>{
controller.close();
});
this._req.on('error', (err)=>{
controller.error(err);
});
}
});
}
}
class NodeNextResponse extends _index.BaseNextResponse {
get originalResponse() {
if (_apiutils.SYMBOL_CLEARED_COOKIES in this) {
this._res[_apiutils.SYMBOL_CLEARED_COOKIES] = this[_apiutils.SYMBOL_CLEARED_COOKIES];
}
return this._res;
}
constructor(_res){
super(_res), this._res = _res, this.textBody = undefined;
}
get sent() {
return this._res.finished || this._res.headersSent;
}
get statusCode() {
return this._res.statusCode;
}
set statusCode(value) {
this._res.statusCode = value;
}
get statusMessage() {
return this._res.statusMessage;
}
set statusMessage(value) {
this._res.statusMessage = value;
}
setHeader(name, value) {
this._res.setHeader(name, value);
return this;
}
removeHeader(name) {
this._res.removeHeader(name);
return this;
}
getHeaderValues(name) {
const values = this._res.getHeader(name);
if (values === undefined) return undefined;
return (Array.isArray(values) ? values : [
values
]).map((value)=>value.toString());
}
hasHeader(name) {
return this._res.hasHeader(name);
}
getHeader(name) {
const values = this.getHeaderValues(name);
return Array.isArray(values) ? values.join(',') : undefined;
}
getHeaders() {
return this._res.getHeaders();
}
appendHeader(name, value) {
const currentValues = this.getHeaderValues(name) ?? [];
if (!currentValues.includes(value)) {
this._res.setHeader(name, [
...currentValues,
value
]);
}
return this;
}
body(value) {
this.textBody = value;
return this;
}
send() {
this._res.end(this.textBody);
}
onClose(callback) {
this.originalResponse.on('close', callback);
}
}
var _NEXT_REQUEST_META;
//# sourceMappingURL=node.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,34 @@
import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http';
import type { FetchMetrics } from './index';
import { BaseNextRequest, BaseNextResponse } from './index';
import type { NextRequestHint } from '../web/adapter';
export declare class WebNextRequest extends BaseNextRequest<ReadableStream | null> {
request: Request;
headers: IncomingHttpHeaders;
fetchMetrics: FetchMetrics | undefined;
constructor(request: NextRequestHint);
parseBody(_limit: string | number): Promise<any>;
}
export declare class WebNextResponse extends BaseNextResponse<WritableStream> {
transformStream: TransformStream<any, any>;
private headers;
private textBody;
private closeController;
statusCode: number | undefined;
statusMessage: string | undefined;
constructor(transformStream?: TransformStream<any, any>);
setHeader(name: string, value: string | string[]): this;
removeHeader(name: string): this;
getHeaderValues(name: string): string[] | undefined;
getHeader(name: string): string | undefined;
getHeaders(): OutgoingHttpHeaders;
hasHeader(name: string): boolean;
appendHeader(name: string, value: string): this;
body(value: string): this;
private readonly sendPromise;
private _sent;
send(): void;
get sent(): boolean;
toResponse(): Promise<Response>;
onClose(callback: () => void): void;
}

View File

@@ -0,0 +1,124 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
WebNextRequest: null,
WebNextResponse: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
WebNextRequest: function() {
return WebNextRequest;
},
WebNextResponse: function() {
return WebNextResponse;
}
});
const _utils = require("../web/utils");
const _index = require("./index");
const _detachedpromise = require("../../lib/detached-promise");
const _webonclose = require("../web/web-on-close");
const _invarianterror = require("../../shared/lib/invariant-error");
class WebNextRequest extends _index.BaseNextRequest {
constructor(request){
const url = new URL(request.url);
super(request.method, url.href.slice(url.origin.length), request.clone().body);
this.request = request;
this.fetchMetrics = request.fetchMetrics;
this.headers = {};
for (const [name, value] of request.headers.entries()){
this.headers[name] = value;
}
}
async parseBody(_limit) {
throw Object.defineProperty(new Error('parseBody is not implemented in the web runtime'), "__NEXT_ERROR_CODE", {
value: "E213",
enumerable: false,
configurable: true
});
}
}
class WebNextResponse extends _index.BaseNextResponse {
constructor(transformStream = new TransformStream()){
super(transformStream.writable), this.transformStream = transformStream, this.headers = new Headers(), this.textBody = undefined, this.closeController = new _webonclose.CloseController(), this.sendPromise = new _detachedpromise.DetachedPromise(), this._sent = false;
}
setHeader(name, value) {
this.headers.delete(name);
for (const val of Array.isArray(value) ? value : [
value
]){
this.headers.append(name, val);
}
return this;
}
removeHeader(name) {
this.headers.delete(name);
return this;
}
getHeaderValues(name) {
var _this_getHeader;
// https://developer.mozilla.org/docs/Web/API/Headers/get#example
return (_this_getHeader = this.getHeader(name)) == null ? void 0 : _this_getHeader.split(',').map((v)=>v.trimStart());
}
getHeader(name) {
return this.headers.get(name) ?? undefined;
}
getHeaders() {
return (0, _utils.toNodeOutgoingHttpHeaders)(this.headers);
}
hasHeader(name) {
return this.headers.has(name);
}
appendHeader(name, value) {
this.headers.append(name, value);
return this;
}
body(value) {
this.textBody = value;
return this;
}
send() {
this.sendPromise.resolve();
this._sent = true;
}
get sent() {
return this._sent;
}
async toResponse() {
// If we haven't called `send` yet, wait for it to be called.
if (!this.sent) await this.sendPromise.promise;
const body = this.textBody ?? this.transformStream.readable;
let bodyInit = body;
// if the response is streaming, onClose() can still be called after this point.
const canAddListenersLater = typeof bodyInit !== 'string';
const shouldTrackBody = canAddListenersLater ? true : this.closeController.listeners > 0;
if (shouldTrackBody) {
bodyInit = (0, _webonclose.trackBodyConsumed)(body, ()=>{
this.closeController.dispatchClose();
});
}
return new Response(bodyInit, {
headers: this.headers,
status: this.statusCode,
statusText: this.statusMessage
});
}
onClose(callback) {
if (this.closeController.isClosed) {
throw Object.defineProperty(new _invarianterror.InvariantError('Cannot call onClose on a WebNextResponse that is already closed'), "__NEXT_ERROR_CODE", {
value: "E599",
enumerable: false,
configurable: true
});
}
return this.closeController.onClose(callback);
}
}
//# sourceMappingURL=web.js.map

File diff suppressed because one or more lines are too long