@web-ts-toolkit/express-runtime 0.26.0 → 0.28.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/cli.js CHANGED
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
9
16
  var __copyProps = (to, from, except, desc) => {
10
17
  if (from && typeof from === "object" || typeof from === "function") {
11
18
  for (let key of __getOwnPropNames(from))
@@ -23,22 +30,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
30
  mod
24
31
  ));
25
32
 
26
- // src/cli-utils.ts
27
- var import_node_url = require("url");
28
- var import_node_path = require("path");
29
- var import_node_fs = require("fs");
30
- var import_node_module = require("module");
31
- var import_node_child_process = require("child_process");
32
-
33
33
  // src/index.ts
34
- var import_node_http = __toESM(require("http"));
35
- var import_express = __toESM(require("express"));
36
- var import_serverless_http = __toESM(require("serverless-http"));
37
- var defaultLogger = {
38
- log: (...args) => console.log(...args),
39
- error: (...args) => console.error(...args),
40
- debug: (...args) => console.debug(...args)
41
- };
42
34
  function applySettings(app, options) {
43
35
  if (options.disablePoweredBy !== false) {
44
36
  app.disable("x-powered-by");
@@ -83,8 +75,6 @@ function createExpressApp(options = {}) {
83
75
  }
84
76
  return app;
85
77
  }
86
- var DEFAULT_SIGNALS = ["SIGINT", "SIGTERM"];
87
- var DEFAULT_SHUTDOWN_TIMEOUT = 5e3;
88
78
  function normalizePort(val) {
89
79
  if (val === void 0 || val === "") {
90
80
  const envPort = process.env.PORT;
@@ -194,10 +184,24 @@ function startLocalServer(app, options = {}) {
194
184
  shutdown
195
185
  };
196
186
  }
187
+ var import_node_http, import_express, import_serverless_http, defaultLogger, DEFAULT_SIGNALS, DEFAULT_SHUTDOWN_TIMEOUT;
188
+ var init_src = __esm({
189
+ "src/index.ts"() {
190
+ "use strict";
191
+ import_node_http = __toESM(require("http"));
192
+ import_express = __toESM(require("express"));
193
+ import_serverless_http = __toESM(require("serverless-http"));
194
+ defaultLogger = {
195
+ log: (...args) => console.log(...args),
196
+ error: (...args) => console.error(...args),
197
+ debug: (...args) => console.debug(...args)
198
+ };
199
+ DEFAULT_SIGNALS = ["SIGINT", "SIGTERM"];
200
+ DEFAULT_SHUTDOWN_TIMEOUT = 5e3;
201
+ }
202
+ });
197
203
 
198
204
  // src/cli-utils.ts
199
- var import_meta = {};
200
- var CLI_VERSION = "0.0.0-PLACEHOLDER";
201
205
  function readValue(argv, index, name) {
202
206
  const value = argv[index + 1];
203
207
  if (value === void 0 || value.startsWith("--")) {
@@ -228,12 +232,14 @@ Dev options:
228
232
  --shutdown-timeout <ms> Max ms to wait for in-flight requests (default: 5000)
229
233
  --require <module> Module(s) to preload before app load (repeatable)
230
234
  --env <path> Env file(s) to load (repeatable; existing env vars are not overridden)
235
+ --tsconfig <path> Tsconfig used by config-aware consumers for TS path resolution
231
236
  --watch <paths> Comma-separated paths to watch for restart (repeatable; dev only)
232
237
  --ext <extensions> Comma-separated extensions to watch (default: ts,js,mjs,cjs,json)
233
238
  --delay <ms> Debounce ms before restarting on change (default: 500)
234
239
 
235
240
  Build options:
236
241
  --init <path> Init hook module (default export, async function)
242
+ --tsconfig <path> Use a custom tsconfig for bundling
237
243
  --out-dir <path> Output directory (default: dist)
238
244
  --out-name <name> Output filename without extension (default: app)
239
245
  --format <cjs|esm> Output format (default: cjs)
@@ -251,6 +257,7 @@ Start options:
251
257
 
252
258
  Build-serverless options:
253
259
  --init <path> Init hook module (default export, async function)
260
+ --tsconfig <path> Use a custom tsconfig for bundling
254
261
  --out-dir <path> Output directory (default: dist)
255
262
  --out-name <name> Output filename without extension (default: handler)
256
263
  --format <cjs|esm> Output format (default: cjs)
@@ -307,8 +314,6 @@ function isHelp(arg) {
307
314
  function isSubcommand(arg) {
308
315
  return arg === "dev" || arg === "build" || arg === "start" || arg === "build-serverless" || arg === "start-serverless";
309
316
  }
310
- var DEFAULT_WATCH_EXTENSIONS = ["ts", "js", "mjs", "cjs", "json"];
311
- var DEFAULT_WATCH_DELAY = 500;
312
317
  function parseRepeatable(argv, index, arg, list) {
313
318
  const value = readValue(argv, index, arg);
314
319
  for (const part of value.split(",")) {
@@ -324,6 +329,7 @@ function parseDevArgs(argv) {
324
329
  const watchPaths = [];
325
330
  let watchExt;
326
331
  let watchDelay;
332
+ let tsconfigPath;
327
333
  let appPath;
328
334
  for (let index = 0; index < argv.length; index += 1) {
329
335
  const arg = argv[index];
@@ -390,6 +396,15 @@ function parseDevArgs(argv) {
390
396
  }
391
397
  continue;
392
398
  }
399
+ if (arg === "--tsconfig") {
400
+ tsconfigPath = readValue(argv, index, arg);
401
+ index += 1;
402
+ continue;
403
+ }
404
+ if (arg.startsWith("--tsconfig=")) {
405
+ tsconfigPath = arg.slice("--tsconfig=".length);
406
+ continue;
407
+ }
393
408
  if (arg === "--watch") {
394
409
  index = parseRepeatable(argv, index, arg, watchPaths);
395
410
  continue;
@@ -439,6 +454,7 @@ function parseDevArgs(argv) {
439
454
  return {
440
455
  appPath,
441
456
  options,
457
+ tsconfigPath,
442
458
  require: requireModules,
443
459
  env: envFiles,
444
460
  watch: watchPaths,
@@ -448,8 +464,8 @@ function parseDevArgs(argv) {
448
464
  }
449
465
  function parseStartLikeArgs(argv, subcommandName) {
450
466
  for (const arg of argv) {
451
- if (arg === "--watch" || arg.startsWith("--watch=") || arg === "--ext" || arg.startsWith("--ext=") || arg === "--delay" || arg.startsWith("--delay=")) {
452
- throw new Error(`--watch/--ext/--delay are not supported with the ${subcommandName} subcommand`);
467
+ if (arg === "--watch" || arg.startsWith("--watch=") || arg === "--tsconfig" || arg.startsWith("--tsconfig=") || arg === "--ext" || arg.startsWith("--ext=") || arg === "--delay" || arg.startsWith("--delay=")) {
468
+ throw new Error(`--watch/--tsconfig/--ext/--delay are not supported with the ${subcommandName} subcommand`);
453
469
  }
454
470
  }
455
471
  return parseDevArgs(argv);
@@ -477,6 +493,7 @@ function parseBuildArgs(argv, outNameDefault) {
477
493
  const external = [];
478
494
  const result = {
479
495
  initPath: void 0,
496
+ tsconfigPath: void 0,
480
497
  outDir: "dist",
481
498
  outName: outNameDefault,
482
499
  format: "cjs",
@@ -501,6 +518,15 @@ function parseBuildArgs(argv, outNameDefault) {
501
518
  result.initPath = arg.slice("--init=".length);
502
519
  continue;
503
520
  }
521
+ if (arg === "--tsconfig") {
522
+ result.tsconfigPath = readValue(argv, index, arg);
523
+ index += 1;
524
+ continue;
525
+ }
526
+ if (arg.startsWith("--tsconfig=")) {
527
+ result.tsconfigPath = arg.slice("--tsconfig=".length);
528
+ continue;
529
+ }
504
530
  if (arg === "--out-dir") {
505
531
  result.outDir = readValue(argv, index, arg);
506
532
  index += 1;
@@ -681,9 +707,6 @@ function loadEnvFiles(paths) {
681
707
  }
682
708
  }
683
709
  }
684
- var moduleRequire = (0, import_node_module.createRequire)(
685
- typeof import_meta !== "undefined" && import_meta.url || (0, import_node_path.resolve)(process.cwd(), "x").replace(/x$/, "")
686
- );
687
710
  async function preloadModules(modules) {
688
711
  for (const mod of modules) {
689
712
  moduleRequire(mod);
@@ -696,6 +719,7 @@ function buildChildArgs(args) {
696
719
  if (args.options.signals === false) result.push("--no-signals");
697
720
  if (args.options.shutdownTimeout !== void 0)
698
721
  result.push("--shutdown-timeout", String(args.options.shutdownTimeout));
722
+ if (args.tsconfigPath !== void 0) result.push("--tsconfig", args.tsconfigPath);
699
723
  for (const r of args.require) result.push("--require", r);
700
724
  for (const e of args.env) result.push("--env", e);
701
725
  return result;
@@ -763,8 +787,6 @@ function runWithWatch(args) {
763
787
  process.on("SIGTERM", shutdown);
764
788
  spawnChild();
765
789
  }
766
- var TEMP_BUILD_ENTRY_FILENAME = ".express-runtime-build-entry.ts";
767
- var TEMP_SERVERLESS_ENTRY_FILENAME = ".express-runtime-build-serverless-entry.ts";
768
790
  function generateServerlessEntry(appPath, initPath) {
769
791
  const absAppPath = (0, import_node_path.resolve)(process.cwd(), appPath);
770
792
  const absInitPath = initPath ? (0, import_node_path.resolve)(process.cwd(), initPath) : void 0;
@@ -796,15 +818,16 @@ function generateRuntimeEntry(appPath, initPath) {
796
818
  }
797
819
  return lines.join("\n") + "\n";
798
820
  }
799
- async function buildBundle(args, tempEntryFilename, entryContent) {
821
+ async function buildBundleFromEntryContent(args) {
800
822
  const tsupModule = await import("tsup");
801
823
  const { build } = tsupModule;
802
- const tempEntryPath = (0, import_node_path.resolve)(process.cwd(), tempEntryFilename);
803
- (0, import_node_fs.writeFileSync)(tempEntryPath, entryContent, "utf8");
824
+ const tempEntryPath = (0, import_node_path.resolve)(process.cwd(), args.tempEntryFilename);
825
+ (0, import_node_fs.writeFileSync)(tempEntryPath, args.entryContent, "utf8");
804
826
  try {
805
827
  await build({
806
828
  config: false,
807
829
  entry: { [args.outName]: tempEntryPath },
830
+ tsconfig: args.tsconfigPath,
808
831
  format: [args.format],
809
832
  target: args.target,
810
833
  outDir: args.outDir,
@@ -819,10 +842,18 @@ async function buildBundle(args, tempEntryFilename, entryContent) {
819
842
  }
820
843
  }
821
844
  async function buildRuntime(args) {
822
- await buildBundle(args, TEMP_BUILD_ENTRY_FILENAME, generateRuntimeEntry(args.appPath, args.initPath));
845
+ const { runBuildEntryCommand: runBuildEntryCommand2 } = await Promise.resolve().then(() => (init_cli_api(), cli_api_exports));
846
+ await runBuildEntryCommand2(args, {
847
+ generateEntry: generateRuntimeEntry,
848
+ tempEntryFilename: TEMP_BUILD_ENTRY_FILENAME
849
+ });
823
850
  }
824
851
  async function buildServerless(args) {
825
- await buildBundle(args, TEMP_SERVERLESS_ENTRY_FILENAME, generateServerlessEntry(args.appPath, args.initPath));
852
+ const { runBuildEntryCommand: runBuildEntryCommand2 } = await Promise.resolve().then(() => (init_cli_api(), cli_api_exports));
853
+ await runBuildEntryCommand2(args, {
854
+ generateEntry: generateServerlessEntry,
855
+ tempEntryFilename: TEMP_SERVERLESS_ENTRY_FILENAME
856
+ });
826
857
  }
827
858
  function collectBody(req) {
828
859
  return new Promise((resolve, reject) => {
@@ -913,36 +944,121 @@ async function loadHandler(handlerPath) {
913
944
  }
914
945
  return exported;
915
946
  }
947
+ var import_node_url, import_node_path, import_node_fs, import_node_module, import_node_child_process, import_meta, CLI_VERSION, DEFAULT_WATCH_EXTENSIONS, DEFAULT_WATCH_DELAY, moduleRequire, TEMP_BUILD_ENTRY_FILENAME, TEMP_SERVERLESS_ENTRY_FILENAME;
948
+ var init_cli_utils = __esm({
949
+ "src/cli-utils.ts"() {
950
+ "use strict";
951
+ import_node_url = require("url");
952
+ import_node_path = require("path");
953
+ import_node_fs = require("fs");
954
+ import_node_module = require("module");
955
+ import_node_child_process = require("child_process");
956
+ init_src();
957
+ import_meta = {};
958
+ CLI_VERSION = "0.0.0-PLACEHOLDER";
959
+ DEFAULT_WATCH_EXTENSIONS = ["ts", "js", "mjs", "cjs", "json"];
960
+ DEFAULT_WATCH_DELAY = 500;
961
+ moduleRequire = (0, import_node_module.createRequire)(
962
+ typeof import_meta !== "undefined" && import_meta.url || (0, import_node_path.resolve)(process.cwd(), "x").replace(/x$/, "")
963
+ );
964
+ TEMP_BUILD_ENTRY_FILENAME = ".express-runtime-build-entry.ts";
965
+ TEMP_SERVERLESS_ENTRY_FILENAME = ".express-runtime-build-serverless-entry.ts";
966
+ }
967
+ });
916
968
 
917
- // src/cli.ts
918
- async function main() {
919
- const parsedArgs = parseArgs(process.argv.slice(2));
920
- if (!parsedArgs) {
969
+ // src/cli-api.ts
970
+ var cli_api_exports = {};
971
+ __export(cli_api_exports, {
972
+ CLI_VERSION: () => CLI_VERSION,
973
+ applyServerlessResult: () => applyServerlessResult,
974
+ buildBundleFromEntryContent: () => buildBundleFromEntryContent,
975
+ buildChildArgs: () => buildChildArgs,
976
+ buildRuntime: () => buildRuntime,
977
+ buildServerless: () => buildServerless,
978
+ createServerlessAdapterApp: () => createServerlessAdapterApp,
979
+ extractExport: () => extractExport,
980
+ generateRuntimeEntry: () => generateRuntimeEntry,
981
+ generateServerlessEntry: () => generateServerlessEntry,
982
+ isExpressApp: () => isExpressApp,
983
+ loadApp: () => loadApp,
984
+ loadBuiltApp: () => loadBuiltApp,
985
+ loadEnvFiles: () => loadEnvFiles,
986
+ loadHandler: () => loadHandler,
987
+ parseArgs: () => parseArgs,
988
+ parseEnvFile: () => parseEnvFile,
989
+ preloadModules: () => preloadModules,
990
+ printHelp: () => printHelp,
991
+ readValue: () => readValue,
992
+ resolveExport: () => resolveExport,
993
+ runBuildEntryCommand: () => runBuildEntryCommand,
994
+ runCliCommand: () => runCliCommand,
995
+ runDevCommand: () => runDevCommand,
996
+ runExpressDevCommand: () => runExpressDevCommand,
997
+ runWithWatch: () => runWithWatch,
998
+ toServerlessEvent: () => toServerlessEvent
999
+ });
1000
+ async function runDevCommand(args, runner) {
1001
+ if (args.watch.length > 0) {
1002
+ (runner.watch ?? runWithWatch)(args);
921
1003
  return;
922
1004
  }
1005
+ if (args.env.length > 0) {
1006
+ loadEnvFiles(args.env);
1007
+ }
1008
+ await preloadModules(args.require);
1009
+ const loaded = await runner.load(args.appPath);
1010
+ runner.start(loaded, { ...args.options, exitAfterShutdown: true });
1011
+ }
1012
+ async function runExpressDevCommand(args) {
1013
+ await runDevCommand(args, {
1014
+ load: loadApp,
1015
+ start: (app, options) => {
1016
+ startLocalServer(app, options);
1017
+ }
1018
+ });
1019
+ }
1020
+ async function runBuildEntryCommand(args, options) {
1021
+ if (options.allowInit === false && args.initPath) {
1022
+ throw new Error(options.initErrorMessage ?? "This build command manages init automatically. Remove --init.");
1023
+ }
1024
+ await buildBundleFromEntryContent({
1025
+ entryContent: options.generateEntry(args.appPath, args.initPath),
1026
+ tempEntryFilename: options.tempEntryFilename,
1027
+ tsconfigPath: args.tsconfigPath,
1028
+ outDir: args.outDir,
1029
+ outName: args.outName,
1030
+ format: args.format,
1031
+ target: args.target,
1032
+ external: args.external,
1033
+ clean: args.clean
1034
+ });
1035
+ }
1036
+ async function runCliCommand(parsedArgs) {
923
1037
  if (parsedArgs.subcommand === "dev") {
924
- const { dev } = parsedArgs;
925
- if (dev.watch.length > 0) {
926
- runWithWatch(dev);
927
- return;
928
- }
929
- if (dev.env.length > 0) {
930
- loadEnvFiles(dev.env);
931
- }
932
- await preloadModules(dev.require);
933
- const app = await loadApp(dev.appPath);
934
- startLocalServer(app, { ...dev.options, exitAfterShutdown: true });
935
- } else if (parsedArgs.subcommand === "start") {
1038
+ await runExpressDevCommand(parsedArgs.dev);
1039
+ return;
1040
+ }
1041
+ if (parsedArgs.subcommand === "start") {
936
1042
  const { start } = parsedArgs;
937
1043
  if (start.env.length > 0) {
938
1044
  loadEnvFiles(start.env);
939
1045
  }
940
1046
  await preloadModules(start.require);
941
1047
  const { app, init } = await loadBuiltApp(start.appPath);
942
- startLocalServer(app, { ...start.options, init, exitAfterShutdown: true });
943
- } else if (parsedArgs.subcommand === "build") {
1048
+ startLocalServer(app, {
1049
+ ...start.options,
1050
+ init: init ? async () => {
1051
+ await init();
1052
+ } : void 0,
1053
+ exitAfterShutdown: true
1054
+ });
1055
+ return;
1056
+ }
1057
+ if (parsedArgs.subcommand === "build") {
944
1058
  await buildRuntime(parsedArgs.build);
945
- } else if (parsedArgs.subcommand === "start-serverless") {
1059
+ return;
1060
+ }
1061
+ if (parsedArgs.subcommand === "start-serverless") {
946
1062
  const { startServerless } = parsedArgs;
947
1063
  if (startServerless.env.length > 0) {
948
1064
  loadEnvFiles(startServerless.env);
@@ -951,9 +1067,26 @@ async function main() {
951
1067
  const handler = await loadHandler(startServerless.handlerPath);
952
1068
  const app = createServerlessAdapterApp(handler);
953
1069
  startLocalServer(app, { ...startServerless.options, exitAfterShutdown: true });
954
- } else {
955
- await buildServerless(parsedArgs.buildServerless);
1070
+ return;
1071
+ }
1072
+ await buildServerless(parsedArgs.buildServerless);
1073
+ }
1074
+ var init_cli_api = __esm({
1075
+ "src/cli-api.ts"() {
1076
+ "use strict";
1077
+ init_src();
1078
+ init_cli_utils();
1079
+ }
1080
+ });
1081
+
1082
+ // src/cli.ts
1083
+ init_cli_api();
1084
+ async function main() {
1085
+ const parsedArgs = parseArgs(process.argv.slice(2));
1086
+ if (!parsedArgs) {
1087
+ return;
956
1088
  }
1089
+ await runCliCommand(parsedArgs);
957
1090
  }
958
1091
  main().catch((error) => {
959
1092
  const message = error instanceof Error ? error.message : String(error);
package/index.mjs CHANGED
@@ -1,216 +1,10 @@
1
- // src/index.ts
2
- import http from "http";
3
- import express from "express";
4
- import serverless from "serverless-http";
5
- var defaultLogger = {
6
- log: (...args) => console.log(...args),
7
- error: (...args) => console.error(...args),
8
- debug: (...args) => console.debug(...args)
9
- };
10
- function applySettings(app, options) {
11
- if (options.disablePoweredBy !== false) {
12
- app.disable("x-powered-by");
13
- }
14
- app.set("etag", options.etag ?? false);
15
- app.set("trust proxy", options.trustProxy ?? false);
16
- }
17
- function applyMiddlewareList(app, list) {
18
- if (list) {
19
- for (const mw of list) {
20
- app.use(mw);
21
- }
22
- }
23
- }
24
- function applyRouters(app, options) {
25
- const mounts = [];
26
- if (options.router) mounts.push(options.router);
27
- if (options.routers) mounts.push(...options.routers);
28
- for (const mount of mounts) {
29
- const path = typeof mount.path === "function" ? mount.path() : mount.path;
30
- app.use(path, mount.handler);
31
- }
32
- }
33
- function createExpressApp(options = {}) {
34
- const app = express();
35
- applySettings(app, options);
36
- applyMiddlewareList(app, options.preMiddleware);
37
- if (options.json !== false) {
38
- app.use(express.json(options.json ?? { limit: "1mb" }));
39
- }
40
- if (options.urlencoded !== false) {
41
- app.use(express.urlencoded(options.urlencoded ?? { extended: false, limit: "1mb" }));
42
- }
43
- applyMiddlewareList(app, options.middleware);
44
- applyRouters(app, options);
45
- applyMiddlewareList(app, options.postMiddleware);
46
- if (options.finalize) {
47
- options.finalize(app);
48
- }
49
- if (options.errorHandler) {
50
- app.use(options.errorHandler);
51
- }
52
- return app;
53
- }
54
- function defaultRequestHook(req, maxBodyBytes = 1024 * 1024, logger = defaultLogger) {
55
- if (!req.body || !Buffer.isBuffer(req.body)) {
56
- return;
57
- }
58
- if (req.body.length > maxBodyBytes) {
59
- logger.debug?.(" Skipping oversized serverless body for content-type parsing");
60
- return;
61
- }
62
- try {
63
- const bodyStr = req.body.toString("utf8");
64
- const contentType = (req.headers?.["content-type"] ?? "").toLowerCase();
65
- if (contentType.startsWith("application/json")) {
66
- req.body = JSON.parse(bodyStr);
67
- } else {
68
- req.body = bodyStr;
69
- }
70
- } catch (error) {
71
- logger.error("Failed to parse serverless request body:", error);
72
- }
73
- }
74
- function createServerlessHandler(app, options = {}) {
75
- const logger = options.logger ?? defaultLogger;
76
- const maxBodyBytes = options.maxBodyBytes ?? 1024 * 1024;
77
- const requestHook = options.request ?? ((req) => defaultRequestHook(req, maxBodyBytes, logger));
78
- const baseOptions = {
79
- ...options.serverlessOptions ?? {},
80
- request: requestHook
81
- };
82
- if (options.response) {
83
- baseOptions.response = options.response;
84
- }
85
- const apiHandler = serverless(app, baseOptions);
86
- let initialized = null;
87
- const ensureInit = () => {
88
- if (!initialized) {
89
- logger.debug?.("Serverless cold start: running init");
90
- initialized = options.init ? options.init() : Promise.resolve();
91
- }
92
- return initialized;
93
- };
94
- const handler = async (event, context) => {
95
- await ensureInit();
96
- return apiHandler(event, context);
97
- };
98
- handler.reset = () => {
99
- initialized = null;
100
- };
101
- return handler;
102
- }
103
- var DEFAULT_SIGNALS = ["SIGINT", "SIGTERM"];
104
- var DEFAULT_SHUTDOWN_TIMEOUT = 5e3;
105
- function normalizePort(val) {
106
- if (val === void 0 || val === "") {
107
- const envPort = process.env.PORT;
108
- if (envPort === void 0 || envPort === "") {
109
- return 8080;
110
- }
111
- val = envPort;
112
- }
113
- if (typeof val === "string") {
114
- const parsed = Number(val);
115
- if (Number.isNaN(parsed)) {
116
- return val;
117
- }
118
- val = parsed;
119
- }
120
- if (!Number.isFinite(val) || val < 0 || val > 65535) {
121
- throw new Error(`Invalid port: ${String(val)}`);
122
- }
123
- return val;
124
- }
125
- function defaultOnError(error, port, logger) {
126
- if (error.syscall !== "listen") {
127
- throw error;
128
- }
129
- const bind = typeof port === "string" ? `Pipe ${port}` : `Port ${port}`;
130
- if (error.code === "EACCES") {
131
- logger.error(`${bind} requires elevated privileges`);
132
- process.exit(1);
133
- } else if (error.code === "EADDRINUSE") {
134
- logger.error(`${bind} is already in use`);
135
- process.exit(1);
136
- } else {
137
- throw error;
138
- }
139
- }
140
- function startLocalServer(app, options = {}) {
141
- const logger = options.logger ?? defaultLogger;
142
- const port = normalizePort(options.port);
143
- const host = options.host ?? process.env.HOST ?? "0.0.0.0";
144
- const shutdownTimeout = options.shutdownTimeout ?? DEFAULT_SHUTDOWN_TIMEOUT;
145
- const server = http.createServer(app);
146
- app.set("port", port);
147
- const onError = (error) => {
148
- if (options.onError) {
149
- options.onError(error);
150
- } else {
151
- defaultOnError(error, port, logger);
152
- }
153
- };
154
- const onListening = () => {
155
- const addr = server.address();
156
- const bind = typeof addr === "string" ? `pipe ${addr}` : `port ${addr?.port}`;
157
- logger.log(`Server running at http://${host}:${port}/ (${bind})`);
158
- options.onListening?.();
159
- };
160
- server.on("error", onError);
161
- server.on("listening", onListening);
162
- const shutdown = async () => {
163
- logger.log("Shutting down...");
164
- try {
165
- if (options.onShutdown) {
166
- await options.onShutdown();
167
- }
168
- } catch (err) {
169
- logger.error("onShutdown hook failed:", err);
170
- }
171
- await new Promise((resolve) => {
172
- const timer = setTimeout(() => {
173
- server.closeAllConnections?.();
174
- resolve();
175
- }, shutdownTimeout);
176
- server.close((err) => {
177
- clearTimeout(timer);
178
- if (err) {
179
- logger.error("Server close error:", err);
180
- }
181
- resolve();
182
- });
183
- });
184
- if (options.exitAfterShutdown) {
185
- process.exit(0);
186
- }
187
- };
188
- if (options.signals !== false) {
189
- const list = options.signals === void 0 || options.signals === true ? DEFAULT_SIGNALS : options.signals;
190
- for (const sig of list) {
191
- process.once(sig, () => void shutdown());
192
- }
193
- }
194
- const start = async () => {
195
- try {
196
- if (options.init) {
197
- await options.init();
198
- }
199
- if (typeof port === "number") {
200
- server.listen(port, host);
201
- } else {
202
- server.listen(port);
203
- }
204
- } catch (err) {
205
- server.emit("error", err);
206
- }
207
- };
208
- void start();
209
- return {
210
- server,
211
- shutdown
212
- };
213
- }
1
+ import {
2
+ createExpressApp,
3
+ createServerlessHandler,
4
+ defaultRequestHook,
5
+ normalizePort,
6
+ startLocalServer
7
+ } from "./chunk-SOW7OLVN.mjs";
214
8
  export {
215
9
  createExpressApp,
216
10
  createServerlessHandler,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@web-ts-toolkit/express-runtime",
3
3
  "description": "Express app factory plus serverless handler and local dev server helpers",
4
4
  "homepage": "https://web-ts-toolkit.pages.dev/docs/packages/express-runtime",
5
- "version": "0.26.0",
5
+ "version": "0.28.0",
6
6
  "sideEffects": false,
7
7
  "keywords": [
8
8
  "express",
@@ -24,6 +24,12 @@
24
24
  "import": "./index.mjs",
25
25
  "require": "./index.js",
26
26
  "default": "./index.js"
27
+ },
28
+ "./cli": {
29
+ "types": "./cli-api.d.ts",
30
+ "import": "./cli-api.mjs",
31
+ "require": "./cli-api.js",
32
+ "default": "./cli-api.js"
27
33
  }
28
34
  },
29
35
  "engines": {