@web-ts-toolkit/express-runtime 0.40.1 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +246 -66
- package/chunk-UPFG3S34.mjs +1494 -0
- package/chunk-VPFBKM2K.mjs +487 -0
- package/cli-api.d.mts +133 -29
- package/cli-api.d.ts +133 -29
- package/cli-api.js +1150 -196
- package/cli-api.mjs +51 -771
- package/cli-utils-4POUMJN7.mjs +69 -0
- package/cli.js +1143 -195
- package/index.d.mts +74 -33
- package/index.d.ts +74 -33
- package/index.js +314 -47
- package/index.mjs +7 -3
- package/package.json +12 -3
- package/chunk-SOW7OLVN.mjs +0 -221
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import http from "http";
|
|
3
|
+
import express from "express";
|
|
4
|
+
import serverless from "serverless-http";
|
|
5
|
+
|
|
6
|
+
// src/numeric-validation.ts
|
|
7
|
+
var MAX_INTEGER_OPTION_VALUE = Number.MAX_SAFE_INTEGER;
|
|
8
|
+
function validateFiniteInteger(value, options) {
|
|
9
|
+
const min = options.min ?? Number.MIN_SAFE_INTEGER;
|
|
10
|
+
const max = options.max ?? MAX_INTEGER_OPTION_VALUE;
|
|
11
|
+
if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value < min || value > max) {
|
|
12
|
+
throw new Error(`Invalid ${options.name}: ${String(value)}. Must be a finite integer in ${min}..${max}.`);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function parsePortValue(value, name) {
|
|
17
|
+
if (typeof value === "number") {
|
|
18
|
+
return validateFiniteInteger(value, { name, min: 0, max: 65535 });
|
|
19
|
+
}
|
|
20
|
+
if (value.trim() === "") {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Invalid ${name}: ${JSON.stringify(value)}. Must be a port number in 0..65535 or a named pipe path.`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
if (value.trim() !== value) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Invalid ${name}: ${JSON.stringify(value)}. Numeric ports must not contain surrounding whitespace.`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
if (/^(0|[1-9]\d*)$/.test(value)) {
|
|
31
|
+
return validateFiniteInteger(Number(value), { name, min: 0, max: 65535 });
|
|
32
|
+
}
|
|
33
|
+
if (/^[+-]?(?:\d+|\d*\.\d+)(?:e[+-]?\d+)?$/i.test(value) || /^[+-]?(?:infinity|nan)$/i.test(value)) {
|
|
34
|
+
throw new Error(`Invalid ${name}: ${value}. Numeric ports must be canonical decimal integers in 0..65535.`);
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/index.ts
|
|
40
|
+
var defaultLogger = {
|
|
41
|
+
log: (...args) => console.log(...args),
|
|
42
|
+
error: (...args) => console.error(...args),
|
|
43
|
+
debug: (...args) => console.debug(...args)
|
|
44
|
+
};
|
|
45
|
+
function applySettings(app, options) {
|
|
46
|
+
if (options.disablePoweredBy !== false) {
|
|
47
|
+
app.disable("x-powered-by");
|
|
48
|
+
}
|
|
49
|
+
app.set("etag", options.etag ?? false);
|
|
50
|
+
app.set("trust proxy", options.trustProxy ?? false);
|
|
51
|
+
}
|
|
52
|
+
function applyMiddlewareList(app, list) {
|
|
53
|
+
if (list) {
|
|
54
|
+
for (const mw of list) {
|
|
55
|
+
app.use(mw);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function applyRouters(app, options) {
|
|
60
|
+
const mounts = [];
|
|
61
|
+
if (options.router) mounts.push(options.router);
|
|
62
|
+
if (options.routers) mounts.push(...options.routers);
|
|
63
|
+
for (const mount of mounts) {
|
|
64
|
+
const path = typeof mount.path === "function" ? mount.path() : mount.path;
|
|
65
|
+
app.use(path, mount.handler);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function createDefaultErrorHandler(logger) {
|
|
69
|
+
return (error, _req, _res, next) => {
|
|
70
|
+
logger.error("Unhandled Express error:", error);
|
|
71
|
+
next(error);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function createExpressApp(options = {}) {
|
|
75
|
+
const app = express();
|
|
76
|
+
const logger = options.logger ?? defaultLogger;
|
|
77
|
+
applySettings(app, options);
|
|
78
|
+
applyMiddlewareList(app, options.preMiddleware);
|
|
79
|
+
if (options.json !== false) {
|
|
80
|
+
app.use(express.json(options.json ?? { limit: "1mb" }));
|
|
81
|
+
}
|
|
82
|
+
if (options.urlencoded !== false) {
|
|
83
|
+
app.use(express.urlencoded(options.urlencoded ?? { extended: false, limit: "1mb" }));
|
|
84
|
+
}
|
|
85
|
+
applyMiddlewareList(app, options.middleware);
|
|
86
|
+
applyRouters(app, options);
|
|
87
|
+
applyMiddlewareList(app, options.postMiddleware);
|
|
88
|
+
if (options.finalize) {
|
|
89
|
+
options.finalize(app);
|
|
90
|
+
}
|
|
91
|
+
if (options.errorHandler) {
|
|
92
|
+
app.use(options.errorHandler);
|
|
93
|
+
} else {
|
|
94
|
+
app.use(createDefaultErrorHandler(logger));
|
|
95
|
+
}
|
|
96
|
+
return app;
|
|
97
|
+
}
|
|
98
|
+
function defaultRequestHook(req, maxBodyBytes = 1024 * 1024, logger = defaultLogger) {
|
|
99
|
+
if (!req.body || !Buffer.isBuffer(req.body)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (req.body.length > maxBodyBytes) {
|
|
103
|
+
logger.debug?.(" Skipping oversized serverless body for content-type parsing");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const bodyStr = req.body.toString("utf8");
|
|
107
|
+
const contentType = getHeaderValue(req.headers, "content-type");
|
|
108
|
+
if (isJsonMediaType(contentType)) {
|
|
109
|
+
if (isReadableRequest(req)) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
req.body = JSON.parse(bodyStr);
|
|
114
|
+
} catch (_error) {
|
|
115
|
+
void _error;
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
req.body = bodyStr;
|
|
120
|
+
}
|
|
121
|
+
function getHeaderValue(headers, name) {
|
|
122
|
+
if (!headers) return "";
|
|
123
|
+
const direct = headers[name];
|
|
124
|
+
if (direct !== void 0) return Array.isArray(direct) ? direct.join(", ") : direct;
|
|
125
|
+
const found = Object.entries(headers).find(([key]) => key.toLowerCase() === name);
|
|
126
|
+
const value = found?.[1];
|
|
127
|
+
if (value === void 0) return "";
|
|
128
|
+
return Array.isArray(value) ? value.join(", ") : value;
|
|
129
|
+
}
|
|
130
|
+
function getMediaType(contentType) {
|
|
131
|
+
return contentType.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
132
|
+
}
|
|
133
|
+
function isJsonMediaType(contentType) {
|
|
134
|
+
const mediaType = getMediaType(contentType);
|
|
135
|
+
if (mediaType === "application/json") return true;
|
|
136
|
+
if (!mediaType.startsWith("application/")) return false;
|
|
137
|
+
const subtype = mediaType.slice("application/".length);
|
|
138
|
+
return subtype.endsWith("+json") && subtype.length > "+json".length;
|
|
139
|
+
}
|
|
140
|
+
function isReadableRequest(req) {
|
|
141
|
+
const candidate = req;
|
|
142
|
+
return req instanceof http.IncomingMessage || typeof candidate.pipe === "function" && typeof candidate.on === "function" && typeof candidate.read === "function";
|
|
143
|
+
}
|
|
144
|
+
function createServerlessHandler(app, options = {}) {
|
|
145
|
+
const logger = options.logger ?? defaultLogger;
|
|
146
|
+
const maxBodyBytes = options.maxBodyBytes ?? 1024 * 1024;
|
|
147
|
+
const requestHook = options.request ?? ((req) => defaultRequestHook(req, maxBodyBytes, logger));
|
|
148
|
+
const baseOptions = {
|
|
149
|
+
...options.serverlessOptions ?? {},
|
|
150
|
+
request: requestHook
|
|
151
|
+
};
|
|
152
|
+
if (options.response) {
|
|
153
|
+
baseOptions.response = options.response;
|
|
154
|
+
}
|
|
155
|
+
const apiHandler = serverless(app, baseOptions);
|
|
156
|
+
let initialized = null;
|
|
157
|
+
let initSettled = false;
|
|
158
|
+
const ensureInit = () => {
|
|
159
|
+
if (!initialized) {
|
|
160
|
+
logger.debug?.("Serverless cold start: running init");
|
|
161
|
+
initSettled = false;
|
|
162
|
+
initialized = Promise.resolve().then(() => options.init?.()).then(
|
|
163
|
+
() => {
|
|
164
|
+
initSettled = true;
|
|
165
|
+
},
|
|
166
|
+
(error) => {
|
|
167
|
+
initSettled = true;
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
return initialized;
|
|
173
|
+
};
|
|
174
|
+
const handler = async (event, context) => {
|
|
175
|
+
await ensureInit();
|
|
176
|
+
return apiHandler(event, context);
|
|
177
|
+
};
|
|
178
|
+
handler.reset = () => {
|
|
179
|
+
if (initialized && !initSettled) {
|
|
180
|
+
logger.debug?.("Serverless init reset ignored while initialization is pending");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
initialized = null;
|
|
184
|
+
initSettled = false;
|
|
185
|
+
};
|
|
186
|
+
return handler;
|
|
187
|
+
}
|
|
188
|
+
var DEFAULT_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
189
|
+
var DEFAULT_SHUTDOWN_TIMEOUT = 5e3;
|
|
190
|
+
function normalizePort(val, name = "port") {
|
|
191
|
+
if (val === void 0 || val === "") {
|
|
192
|
+
const envPort = process.env.PORT;
|
|
193
|
+
if (envPort === void 0 || envPort === "") {
|
|
194
|
+
return 8080;
|
|
195
|
+
}
|
|
196
|
+
val = envPort;
|
|
197
|
+
}
|
|
198
|
+
return parsePortValue(val, name);
|
|
199
|
+
}
|
|
200
|
+
function defaultOnError(error, port, logger) {
|
|
201
|
+
if (error.syscall !== "listen") {
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
const bind = typeof port === "string" ? `Pipe ${port}` : `Port ${port}`;
|
|
205
|
+
if (error.code === "EACCES") {
|
|
206
|
+
logger.error(`${bind} requires elevated privileges`);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
} else if (error.code === "EADDRINUSE") {
|
|
209
|
+
logger.error(`${bind} is already in use`);
|
|
210
|
+
process.exit(1);
|
|
211
|
+
} else {
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function startLocalServer(app, options = {}) {
|
|
216
|
+
const logger = options.logger ?? defaultLogger;
|
|
217
|
+
const port = normalizePort(options.port);
|
|
218
|
+
const host = options.host ?? process.env.HOST ?? "0.0.0.0";
|
|
219
|
+
const shutdownTimeout = validateFiniteInteger(options.shutdownTimeout ?? DEFAULT_SHUTDOWN_TIMEOUT, {
|
|
220
|
+
name: "shutdownTimeout",
|
|
221
|
+
min: 0,
|
|
222
|
+
max: MAX_INTEGER_OPTION_VALUE
|
|
223
|
+
});
|
|
224
|
+
const server = http.createServer(app);
|
|
225
|
+
app.set("port", port);
|
|
226
|
+
let state = "initializing";
|
|
227
|
+
let shutdownPromise = null;
|
|
228
|
+
let readySettled = false;
|
|
229
|
+
let readyResolve;
|
|
230
|
+
let readyReject;
|
|
231
|
+
const ready = new Promise((resolve, reject) => {
|
|
232
|
+
readyResolve = () => {
|
|
233
|
+
if (!readySettled) {
|
|
234
|
+
readySettled = true;
|
|
235
|
+
resolve();
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
readyReject = (err) => {
|
|
239
|
+
if (!readySettled) {
|
|
240
|
+
readySettled = true;
|
|
241
|
+
reject(err);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
ready.catch(() => {
|
|
246
|
+
});
|
|
247
|
+
const ownedSignalHandlers = /* @__PURE__ */ new Map();
|
|
248
|
+
const cleanupSignalHandlers = () => {
|
|
249
|
+
for (const [sig, handler] of ownedSignalHandlers.entries()) {
|
|
250
|
+
process.removeListener(sig, handler);
|
|
251
|
+
}
|
|
252
|
+
ownedSignalHandlers.clear();
|
|
253
|
+
};
|
|
254
|
+
const handleListenError = (error) => {
|
|
255
|
+
if (state === "stopping" || state === "stopped" || state === "failed") {
|
|
256
|
+
logger.error("Server error after terminal state:", error);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (state === "initializing") {
|
|
260
|
+
state = "failed";
|
|
261
|
+
cleanupSignalHandlers();
|
|
262
|
+
readyReject(error);
|
|
263
|
+
if (options.onError) {
|
|
264
|
+
try {
|
|
265
|
+
options.onError(error);
|
|
266
|
+
} catch (e) {
|
|
267
|
+
logger.error(e);
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
try {
|
|
271
|
+
defaultOnError(error, port, logger);
|
|
272
|
+
} catch (e) {
|
|
273
|
+
logger.error(e);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
server.close();
|
|
278
|
+
} catch (_err) {
|
|
279
|
+
void _err;
|
|
280
|
+
}
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (options.onError) {
|
|
284
|
+
try {
|
|
285
|
+
options.onError(error);
|
|
286
|
+
} catch (e) {
|
|
287
|
+
logger.error(e);
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
try {
|
|
291
|
+
defaultOnError(error, port, logger);
|
|
292
|
+
} catch (e) {
|
|
293
|
+
logger.error(e);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
const onListening = () => {
|
|
298
|
+
if (state === "stopping" || state === "stopped" || state === "failed") {
|
|
299
|
+
try {
|
|
300
|
+
server.close();
|
|
301
|
+
} catch (_err) {
|
|
302
|
+
void _err;
|
|
303
|
+
}
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
state = "listening";
|
|
307
|
+
const addr = server.address();
|
|
308
|
+
const bind = typeof addr === "string" ? `pipe ${addr}` : `port ${addr?.port}`;
|
|
309
|
+
const actualPort = typeof addr === "object" && addr !== null ? addr.port : port;
|
|
310
|
+
if (typeof addr === "object" && addr !== null) {
|
|
311
|
+
logger.log(`Server running at http://${host}:${actualPort}/ (${bind})`);
|
|
312
|
+
} else if (typeof addr === "string") {
|
|
313
|
+
logger.log(`Server running at pipe ${addr} (${bind})`);
|
|
314
|
+
} else {
|
|
315
|
+
logger.log(`Server running at http://${host}:${port}/ (${bind})`);
|
|
316
|
+
}
|
|
317
|
+
try {
|
|
318
|
+
options.onListening?.();
|
|
319
|
+
} catch (e) {
|
|
320
|
+
logger.error("onListening hook failed:", e);
|
|
321
|
+
}
|
|
322
|
+
readyResolve();
|
|
323
|
+
};
|
|
324
|
+
const handleClose = () => {
|
|
325
|
+
if (state === "stopping") {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (state === "listening") {
|
|
329
|
+
state = "stopped";
|
|
330
|
+
cleanupSignalHandlers();
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (state === "initializing" && !readySettled) {
|
|
334
|
+
state = "stopped";
|
|
335
|
+
cleanupSignalHandlers();
|
|
336
|
+
readyReject(new Error("Server closed before listening"));
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (state === "initializing") {
|
|
340
|
+
state = "stopped";
|
|
341
|
+
cleanupSignalHandlers();
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
server.on("error", handleListenError);
|
|
345
|
+
server.on("listening", onListening);
|
|
346
|
+
server.on("close", handleClose);
|
|
347
|
+
const doShutdown = async () => {
|
|
348
|
+
if (state === "stopping" || state === "stopped") {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (state === "failed") {
|
|
352
|
+
state = "stopped";
|
|
353
|
+
cleanupSignalHandlers();
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
state = "stopping";
|
|
357
|
+
if (!readySettled) {
|
|
358
|
+
readyReject(new Error("Server shutdown before listening"));
|
|
359
|
+
}
|
|
360
|
+
cleanupSignalHandlers();
|
|
361
|
+
logger.log("Shutting down...");
|
|
362
|
+
await new Promise((resolve) => {
|
|
363
|
+
if (!server.listening) {
|
|
364
|
+
resolve();
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
let settled = false;
|
|
368
|
+
const done = () => {
|
|
369
|
+
if (settled) return;
|
|
370
|
+
settled = true;
|
|
371
|
+
clearTimeout(timer);
|
|
372
|
+
resolve();
|
|
373
|
+
};
|
|
374
|
+
const timer = setTimeout(() => {
|
|
375
|
+
try {
|
|
376
|
+
server.closeAllConnections?.();
|
|
377
|
+
} catch (_err) {
|
|
378
|
+
void _err;
|
|
379
|
+
}
|
|
380
|
+
done();
|
|
381
|
+
}, shutdownTimeout);
|
|
382
|
+
timer.unref?.();
|
|
383
|
+
try {
|
|
384
|
+
server.close((err) => {
|
|
385
|
+
if (err) {
|
|
386
|
+
logger.error("Server close error:", err);
|
|
387
|
+
}
|
|
388
|
+
done();
|
|
389
|
+
});
|
|
390
|
+
} catch (err) {
|
|
391
|
+
logger.error("Server close error:", err);
|
|
392
|
+
done();
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
let shutdownError;
|
|
396
|
+
try {
|
|
397
|
+
if (options.onShutdown) {
|
|
398
|
+
await options.onShutdown();
|
|
399
|
+
}
|
|
400
|
+
} catch (err) {
|
|
401
|
+
logger.error("onShutdown hook failed:", err);
|
|
402
|
+
shutdownError = err;
|
|
403
|
+
}
|
|
404
|
+
if (shutdownError) {
|
|
405
|
+
state = "failed";
|
|
406
|
+
if (options.exitAfterShutdown) {
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
throw shutdownError;
|
|
410
|
+
}
|
|
411
|
+
state = "stopped";
|
|
412
|
+
if (options.exitAfterShutdown) {
|
|
413
|
+
process.exit(0);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
const shutdown = () => {
|
|
417
|
+
if (shutdownPromise) return shutdownPromise;
|
|
418
|
+
shutdownPromise = doShutdown();
|
|
419
|
+
return shutdownPromise;
|
|
420
|
+
};
|
|
421
|
+
if (options.signals !== false) {
|
|
422
|
+
const list = options.signals === void 0 || options.signals === true ? DEFAULT_SIGNALS : options.signals;
|
|
423
|
+
for (const sig of list) {
|
|
424
|
+
const handler = () => {
|
|
425
|
+
void shutdown().catch(() => {
|
|
426
|
+
});
|
|
427
|
+
};
|
|
428
|
+
ownedSignalHandlers.set(sig, handler);
|
|
429
|
+
process.once(sig, handler);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const start = async () => {
|
|
433
|
+
try {
|
|
434
|
+
if (options.init) {
|
|
435
|
+
await options.init();
|
|
436
|
+
}
|
|
437
|
+
if (state === "stopping" || state === "stopped" || state === "failed") {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
if (typeof port === "number") {
|
|
441
|
+
server.listen(port, host);
|
|
442
|
+
} else {
|
|
443
|
+
server.listen(port);
|
|
444
|
+
}
|
|
445
|
+
} catch (err) {
|
|
446
|
+
if (state === "stopping" || state === "stopped") {
|
|
447
|
+
logger.error("Init failed after shutdown started:", err);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
state = "failed";
|
|
451
|
+
cleanupSignalHandlers();
|
|
452
|
+
const error = err;
|
|
453
|
+
readyReject(error);
|
|
454
|
+
if (options.onError) {
|
|
455
|
+
try {
|
|
456
|
+
options.onError(error);
|
|
457
|
+
} catch (e) {
|
|
458
|
+
logger.error(e);
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
logger.error("Init failed:", error);
|
|
462
|
+
}
|
|
463
|
+
try {
|
|
464
|
+
server.close();
|
|
465
|
+
} catch (_err) {
|
|
466
|
+
void _err;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
void start();
|
|
471
|
+
return {
|
|
472
|
+
server,
|
|
473
|
+
shutdown,
|
|
474
|
+
ready
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export {
|
|
479
|
+
MAX_INTEGER_OPTION_VALUE,
|
|
480
|
+
validateFiniteInteger,
|
|
481
|
+
parsePortValue,
|
|
482
|
+
createExpressApp,
|
|
483
|
+
defaultRequestHook,
|
|
484
|
+
createServerlessHandler,
|
|
485
|
+
normalizePort,
|
|
486
|
+
startLocalServer
|
|
487
|
+
};
|