Update app and tooling
This commit is contained in:
parent
3046531bdd
commit
e620ec7349
4950 changed files with 2975120 additions and 10 deletions
35
node_modules/edge-runtime/dist/server/body-streams.d.ts
generated
vendored
Normal file
35
node_modules/edge-runtime/dist/server/body-streams.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
import type { IncomingMessage } from 'http';
|
||||
import type { Writable } from 'stream';
|
||||
type BodyStream = ReadableStream<Uint8Array>;
|
||||
/**
|
||||
* An interface that encapsulates body stream cloning
|
||||
* of an incoming request.
|
||||
*/
|
||||
export declare function getClonableBodyStream<T extends IncomingMessage>(incomingMessage: T, KUint8Array: typeof Uint8Array, KTransformStream: typeof TransformStream): {
|
||||
/**
|
||||
* Replaces the original request body if necessary.
|
||||
* This is done because once we read the body from the original request,
|
||||
* we can't read it again.
|
||||
*/
|
||||
finalize(): void;
|
||||
/**
|
||||
* Clones the body stream
|
||||
* to pass into a middleware
|
||||
*/
|
||||
cloneBodyStream(): BodyStream;
|
||||
};
|
||||
/**
|
||||
* Creates an async iterator from a ReadableStream that ensures that every
|
||||
* emitted chunk is a `Uint8Array`. If there is some invalid chunk it will
|
||||
* throw.
|
||||
*/
|
||||
export declare function consumeUint8ArrayReadableStream(body?: ReadableStream): AsyncGenerator<Uint8Array, void, unknown>;
|
||||
/**
|
||||
* Pipes the chunks of a BodyStream into a Response. This optimizes for
|
||||
* laziness, pauses reading if we experience back-pressure, and handles early
|
||||
* disconnects by the client on the other end of the server response.
|
||||
*/
|
||||
export declare function pipeBodyStreamToResponse(body: BodyStream | null, res: Writable): Promise<void>;
|
||||
export {};
|
||||
161
node_modules/edge-runtime/dist/server/body-streams.js
generated
vendored
Normal file
161
node_modules/edge-runtime/dist/server/body-streams.js
generated
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.pipeBodyStreamToResponse = exports.consumeUint8ArrayReadableStream = exports.getClonableBodyStream = void 0;
|
||||
const stream_1 = require("stream");
|
||||
/**
|
||||
* An interface that encapsulates body stream cloning
|
||||
* of an incoming request.
|
||||
*/
|
||||
function getClonableBodyStream(incomingMessage, KUint8Array, KTransformStream) {
|
||||
let bufferedBodyStream = null;
|
||||
return {
|
||||
/**
|
||||
* Replaces the original request body if necessary.
|
||||
* This is done because once we read the body from the original request,
|
||||
* we can't read it again.
|
||||
*/
|
||||
finalize() {
|
||||
if (bufferedBodyStream) {
|
||||
replaceRequestBody(incomingMessage, bodyStreamToNodeStream(bufferedBodyStream));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Clones the body stream
|
||||
* to pass into a middleware
|
||||
*/
|
||||
cloneBodyStream() {
|
||||
const originalStream = bufferedBodyStream !== null && bufferedBodyStream !== void 0 ? bufferedBodyStream : requestToBodyStream(incomingMessage, KUint8Array, KTransformStream);
|
||||
const [stream1, stream2] = originalStream.tee();
|
||||
bufferedBodyStream = stream1;
|
||||
return stream2;
|
||||
},
|
||||
};
|
||||
}
|
||||
exports.getClonableBodyStream = getClonableBodyStream;
|
||||
/**
|
||||
* Creates a ReadableStream from a Node.js HTTP request
|
||||
*/
|
||||
function requestToBodyStream(request, KUint8Array, KTransformStream) {
|
||||
const transform = new KTransformStream({
|
||||
start(controller) {
|
||||
request.on('data', (chunk) => controller.enqueue(new KUint8Array([...new Uint8Array(chunk)])));
|
||||
request.on('end', () => controller.terminate());
|
||||
request.on('error', (err) => controller.error(err));
|
||||
},
|
||||
});
|
||||
return transform.readable;
|
||||
}
|
||||
function bodyStreamToNodeStream(bodyStream) {
|
||||
const reader = bodyStream.getReader();
|
||||
return stream_1.Readable.from((async function* () {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
yield value;
|
||||
}
|
||||
})());
|
||||
}
|
||||
function replaceRequestBody(base, stream) {
|
||||
for (const key in stream) {
|
||||
let v = stream[key];
|
||||
if (typeof v === 'function') {
|
||||
v = v.bind(stream);
|
||||
}
|
||||
base[key] = v;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
function isUint8ArrayChunk(value) {
|
||||
var _a;
|
||||
return ((_a = value === null || value === void 0 ? void 0 : value.constructor) === null || _a === void 0 ? void 0 : _a.name) == 'Uint8Array';
|
||||
}
|
||||
/**
|
||||
* Creates an async iterator from a ReadableStream that ensures that every
|
||||
* emitted chunk is a `Uint8Array`. If there is some invalid chunk it will
|
||||
* throw.
|
||||
*/
|
||||
async function* consumeUint8ArrayReadableStream(body) {
|
||||
const reader = body === null || body === void 0 ? void 0 : body.getReader();
|
||||
if (reader) {
|
||||
let error;
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
if (!isUint8ArrayChunk(value)) {
|
||||
error = new TypeError('This ReadableStream did not return bytes.');
|
||||
break;
|
||||
}
|
||||
yield value;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (error) {
|
||||
reader.cancel(error);
|
||||
throw error;
|
||||
}
|
||||
else {
|
||||
reader.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.consumeUint8ArrayReadableStream = consumeUint8ArrayReadableStream;
|
||||
/**
|
||||
* Pipes the chunks of a BodyStream into a Response. This optimizes for
|
||||
* laziness, pauses reading if we experience back-pressure, and handles early
|
||||
* disconnects by the client on the other end of the server response.
|
||||
*/
|
||||
async function pipeBodyStreamToResponse(body, res) {
|
||||
if (!body)
|
||||
return;
|
||||
// If the client has already disconnected, then we don't need to pipe anything.
|
||||
if (res.destroyed)
|
||||
return body.cancel();
|
||||
// When the server pushes more data than the client reads, then we need to
|
||||
// wait for the client to catch up before writing more data. We register this
|
||||
// generic handler once so that we don't incur constant register/unregister
|
||||
// calls.
|
||||
let drainResolve;
|
||||
res.on('drain', () => drainResolve === null || drainResolve === void 0 ? void 0 : drainResolve());
|
||||
// If the user aborts, then we'll receive a close event before the
|
||||
// body closes. In that case, we want to end the streaming.
|
||||
let open = true;
|
||||
res.on('close', () => {
|
||||
open = false;
|
||||
drainResolve === null || drainResolve === void 0 ? void 0 : drainResolve();
|
||||
});
|
||||
const reader = body.getReader();
|
||||
while (open) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done)
|
||||
break;
|
||||
if (!isUint8ArrayChunk(value)) {
|
||||
const error = new TypeError('This ReadableStream did not return bytes.');
|
||||
reader.cancel(error);
|
||||
throw error;
|
||||
}
|
||||
if (open) {
|
||||
const bufferSpaceAvailable = res.write(value);
|
||||
// If there's no more space in the buffer, then we need to wait on the
|
||||
// client to read data before pushing again.
|
||||
if (!bufferSpaceAvailable) {
|
||||
await new Promise((res) => {
|
||||
drainResolve = res;
|
||||
});
|
||||
}
|
||||
}
|
||||
// If the client disconnected early, then we need to cleanup the stream.
|
||||
// This cannot be joined with the above if-statement, because the client may
|
||||
// have disconnected while waiting for a drain signal.
|
||||
if (!open) {
|
||||
return reader.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.pipeBodyStreamToResponse = pipeBodyStreamToResponse;
|
||||
//# sourceMappingURL=body-streams.js.map
|
||||
1
node_modules/edge-runtime/dist/server/body-streams.js.map
generated
vendored
Normal file
1
node_modules/edge-runtime/dist/server/body-streams.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
26
node_modules/edge-runtime/dist/server/create-handler.d.ts
generated
vendored
Normal file
26
node_modules/edge-runtime/dist/server/create-handler.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/// <reference types="node" />
|
||||
import type { EdgeRuntime } from '../edge-runtime';
|
||||
import type { IncomingMessage, ServerResponse } from 'http';
|
||||
import type { Logger } from '../types';
|
||||
import type { EdgeContext } from '@edge-runtime/vm';
|
||||
export interface Options<T extends EdgeContext> {
|
||||
/**
|
||||
* A logger interface. If none is provided there will be no logs.
|
||||
*/
|
||||
logger?: Logger;
|
||||
/**
|
||||
* The runtime where the FetchEvent will be triggered whenever the server
|
||||
* receives a request.
|
||||
*/
|
||||
runtime: EdgeRuntime<T>;
|
||||
}
|
||||
/**
|
||||
* Creates an HHTP handler that can be used to create a Node.js HTTP server.
|
||||
* Whenever a request is handled it will transform it into a `dispatchFetch`
|
||||
* call for the given `EdgeRuntime`. Then it will transform the response
|
||||
* into an HTTP response.
|
||||
*/
|
||||
export declare function createHandler<T extends EdgeContext>(options: Options<T>): {
|
||||
handler: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
||||
waitUntil: () => Promise<unknown[]>;
|
||||
};
|
||||
94
node_modules/edge-runtime/dist/server/create-handler.js
generated
vendored
Normal file
94
node_modules/edge-runtime/dist/server/create-handler.js
generated
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createHandler = void 0;
|
||||
const body_streams_1 = require("./body-streams");
|
||||
const pretty_ms_1 = __importDefault(require("pretty-ms"));
|
||||
const time_span_1 = __importDefault(require("time-span"));
|
||||
const http_1 = require("http");
|
||||
/**
|
||||
* Creates an HHTP handler that can be used to create a Node.js HTTP server.
|
||||
* Whenever a request is handled it will transform it into a `dispatchFetch`
|
||||
* call for the given `EdgeRuntime`. Then it will transform the response
|
||||
* into an HTTP response.
|
||||
*/
|
||||
function createHandler(options) {
|
||||
const awaiting = new Set();
|
||||
return {
|
||||
handler: async (req, res) => {
|
||||
var _a, _b;
|
||||
try {
|
||||
const start = (0, time_span_1.default)();
|
||||
const body = req.method !== 'GET' && req.method !== 'HEAD'
|
||||
? (0, body_streams_1.getClonableBodyStream)(req, options.runtime.evaluate('Uint8Array'), options.runtime.context.TransformStream)
|
||||
: undefined;
|
||||
const response = await options.runtime.dispatchFetch(String(getURL(req)), {
|
||||
headers: toRequestInitHeaders(req),
|
||||
method: req.method,
|
||||
body: body === null || body === void 0 ? void 0 : body.cloneBodyStream(),
|
||||
});
|
||||
const waitUntil = response.waitUntil();
|
||||
awaiting.add(waitUntil);
|
||||
waitUntil.finally(() => awaiting.delete(waitUntil));
|
||||
res.statusCode = response.status;
|
||||
res.statusMessage = response.statusText;
|
||||
for (const [key, value] of Object.entries(toNodeHeaders(response.headers))) {
|
||||
if (value !== undefined) {
|
||||
res.setHeader(key, value);
|
||||
}
|
||||
}
|
||||
await (0, body_streams_1.pipeBodyStreamToResponse)(response.body, res);
|
||||
const subject = `${req.socket.remoteAddress} ${req.method} ${req.url}`;
|
||||
const time = `${(_a = (0, pretty_ms_1.default)(start())
|
||||
.match(/[a-zA-Z]+|[0-9]+/g)) === null || _a === void 0 ? void 0 : _a.join(' ')}`;
|
||||
const code = `${res.statusCode} ${http_1.STATUS_CODES[res.statusCode]}`;
|
||||
(_b = options.logger) === null || _b === void 0 ? void 0 : _b.debug(`${subject} → ${code} in ${time}`);
|
||||
res.end();
|
||||
}
|
||||
finally {
|
||||
if (!res.writableEnded) {
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
},
|
||||
waitUntil: () => Promise.all(awaiting),
|
||||
};
|
||||
}
|
||||
exports.createHandler = createHandler;
|
||||
/**
|
||||
* Builds a full URL from the provided incoming message. Note this function
|
||||
* is not safe as one can set has a host anything based on headers. It is
|
||||
* useful to build the fetch request full URL.
|
||||
*/
|
||||
function getURL(req) {
|
||||
var _a;
|
||||
const proto = ((_a = req.socket) === null || _a === void 0 ? void 0 : _a.encrypted) ? 'https' : 'http';
|
||||
return new URL(String(req.url), `${proto}://${String(req.headers.host)}`);
|
||||
}
|
||||
/**
|
||||
* Takes headers from IncomingMessage and transforms them into the signature
|
||||
* accepted by fetch. It simply folds headers into a single value when they
|
||||
* hold an array. For others it just copies the value.
|
||||
*/
|
||||
function toRequestInitHeaders(req) {
|
||||
return Object.keys(req.headers).map((key) => {
|
||||
const value = req.headers[key];
|
||||
return [key, Array.isArray(value) ? value.join(', ') : value !== null && value !== void 0 ? value : ''];
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Transforms WHATWG Headers into a Node Headers shape. Copies all items but
|
||||
* does a special case for Set-Cookie using the [`getSetCookie`](https://developer.mozilla.org/en-US/docs/Web/API/Headers/getSetCookie) method.
|
||||
*/
|
||||
function toNodeHeaders(headers) {
|
||||
const result = {};
|
||||
if (headers) {
|
||||
for (const [key, value] of headers.entries()) {
|
||||
result[key] = key === 'set-cookie' ? headers.getSetCookie() : value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//# sourceMappingURL=create-handler.js.map
|
||||
1
node_modules/edge-runtime/dist/server/create-handler.js.map
generated
vendored
Normal file
1
node_modules/edge-runtime/dist/server/create-handler.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3
node_modules/edge-runtime/dist/server/index.d.ts
generated
vendored
Normal file
3
node_modules/edge-runtime/dist/server/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export { consumeUint8ArrayReadableStream, pipeBodyStreamToResponse, } from './body-streams';
|
||||
export { createHandler } from './create-handler';
|
||||
export { runServer, EdgeRuntimeServer } from './run-server';
|
||||
11
node_modules/edge-runtime/dist/server/index.js
generated
vendored
Normal file
11
node_modules/edge-runtime/dist/server/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.runServer = exports.createHandler = exports.pipeBodyStreamToResponse = exports.consumeUint8ArrayReadableStream = void 0;
|
||||
var body_streams_1 = require("./body-streams");
|
||||
Object.defineProperty(exports, "consumeUint8ArrayReadableStream", { enumerable: true, get: function () { return body_streams_1.consumeUint8ArrayReadableStream; } });
|
||||
Object.defineProperty(exports, "pipeBodyStreamToResponse", { enumerable: true, get: function () { return body_streams_1.pipeBodyStreamToResponse; } });
|
||||
var create_handler_1 = require("./create-handler");
|
||||
Object.defineProperty(exports, "createHandler", { enumerable: true, get: function () { return create_handler_1.createHandler; } });
|
||||
var run_server_1 = require("./run-server");
|
||||
Object.defineProperty(exports, "runServer", { enumerable: true, get: function () { return run_server_1.runServer; } });
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/edge-runtime/dist/server/index.js.map
generated
vendored
Normal file
1
node_modules/edge-runtime/dist/server/index.js.map
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";;;AAAA,+CAGuB;AAFrB,+HAAA,+BAA+B,OAAA;AAC/B,wHAAA,wBAAwB,OAAA;AAE1B,mDAAgD;AAAvC,+GAAA,aAAa,OAAA;AACtB,2CAA2D;AAAlD,uGAAA,SAAS,OAAA","sourcesContent":["export {\n consumeUint8ArrayReadableStream,\n pipeBodyStreamToResponse,\n} from './body-streams'\nexport { createHandler } from './create-handler'\nexport { runServer, EdgeRuntimeServer } from './run-server'\n"]}
|
||||
27
node_modules/edge-runtime/dist/server/run-server.d.ts
generated
vendored
Normal file
27
node_modules/edge-runtime/dist/server/run-server.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/// <reference types="node" />
|
||||
import { Options } from './create-handler';
|
||||
import type { EdgeContext } from '@edge-runtime/vm';
|
||||
import type { ListenOptions } from 'net';
|
||||
interface ServerOptions<T extends EdgeContext> extends Options<T> {
|
||||
}
|
||||
export interface EdgeRuntimeServer {
|
||||
/**
|
||||
* The server URL.
|
||||
*/
|
||||
url: string;
|
||||
/**
|
||||
* Waits for all the current effects and closes the server.
|
||||
*/
|
||||
close: () => Promise<void>;
|
||||
/**
|
||||
* Waits for all current effects returning their result.
|
||||
*/
|
||||
waitUntil: () => Promise<any[]>;
|
||||
}
|
||||
/**
|
||||
* This helper will create a handler based on the given options and then
|
||||
* immediately run a server on the provided port. If there is no port, the
|
||||
* server will use a random one.
|
||||
*/
|
||||
export declare function runServer<T extends EdgeContext>(options: ListenOptions & ServerOptions<T>): Promise<EdgeRuntimeServer>;
|
||||
export {};
|
||||
37
node_modules/edge-runtime/dist/server/run-server.js
generated
vendored
Normal file
37
node_modules/edge-runtime/dist/server/run-server.js
generated
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.runServer = void 0;
|
||||
const create_handler_1 = require("./create-handler");
|
||||
const async_listen_1 = __importDefault(require("async-listen"));
|
||||
const http_1 = __importDefault(require("http"));
|
||||
/**
|
||||
* This helper will create a handler based on the given options and then
|
||||
* immediately run a server on the provided port. If there is no port, the
|
||||
* server will use a random one.
|
||||
*/
|
||||
async function runServer(options) {
|
||||
if (options.port === undefined)
|
||||
options.port = 0;
|
||||
const { handler, waitUntil } = (0, create_handler_1.createHandler)(options);
|
||||
const server = http_1.default.createServer(handler);
|
||||
const url = await (0, async_listen_1.default)(server, options);
|
||||
return {
|
||||
url: String(url),
|
||||
close: async () => {
|
||||
await waitUntil();
|
||||
await new Promise((resolve, reject) => {
|
||||
return server.close((err) => {
|
||||
if (err)
|
||||
reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
waitUntil,
|
||||
};
|
||||
}
|
||||
exports.runServer = runServer;
|
||||
//# sourceMappingURL=run-server.js.map
|
||||
1
node_modules/edge-runtime/dist/server/run-server.js.map
generated
vendored
Normal file
1
node_modules/edge-runtime/dist/server/run-server.js.map
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"run-server.js","sourceRoot":"","sources":["../../src/server/run-server.ts"],"names":[],"mappings":";;;;;;AAAA,qDAAyD;AAEzD,gEAAiC;AACjC,gDAAuB;AAoBvB;;;;GAIG;AACI,KAAK,UAAU,SAAS,CAC7B,OAAyC;IAEzC,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,GAAG,CAAC,CAAA;IAChD,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAA,8BAAa,EAAC,OAAO,CAAC,CAAA;IACrD,MAAM,MAAM,GAAG,cAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAA;IACzC,MAAM,GAAG,GAAG,MAAM,IAAA,sBAAM,EAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAEzC,OAAO;QACL,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC;QAChB,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,SAAS,EAAE,CAAA;YACjB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC1C,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC1B,IAAI,GAAG;wBAAE,MAAM,CAAC,GAAG,CAAC,CAAA;oBACpB,OAAO,EAAE,CAAA;gBACX,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC;QACD,SAAS;KACV,CAAA;AACH,CAAC;AArBD,8BAqBC","sourcesContent":["import { createHandler, Options } from './create-handler'\nimport type { EdgeContext } from '@edge-runtime/vm'\nimport listen from 'async-listen'\nimport http from 'http'\nimport type { ListenOptions } from 'net'\n\ninterface ServerOptions<T extends EdgeContext> extends Options<T> {}\n\nexport interface EdgeRuntimeServer {\n /**\n * The server URL.\n */\n url: string\n /**\n * Waits for all the current effects and closes the server.\n */\n close: () => Promise<void>\n /**\n * Waits for all current effects returning their result.\n */\n waitUntil: () => Promise<any[]>\n}\n\n/**\n * This helper will create a handler based on the given options and then\n * immediately run a server on the provided port. If there is no port, the\n * server will use a random one.\n */\nexport async function runServer<T extends EdgeContext>(\n options: ListenOptions & ServerOptions<T>,\n): Promise<EdgeRuntimeServer> {\n if (options.port === undefined) options.port = 0\n const { handler, waitUntil } = createHandler(options)\n const server = http.createServer(handler)\n const url = await listen(server, options)\n\n return {\n url: String(url),\n close: async () => {\n await waitUntil()\n await new Promise<void>((resolve, reject) => {\n return server.close((err) => {\n if (err) reject(err)\n resolve()\n })\n })\n },\n waitUntil,\n }\n}\n"]}
|
||||
Loading…
Add table
Add a link
Reference in a new issue