@web-ts-toolkit/express-runtime 0.26.0 → 0.27.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("--")) {
@@ -307,8 +311,6 @@ function isHelp(arg) {
307
311
  function isSubcommand(arg) {
308
312
  return arg === "dev" || arg === "build" || arg === "start" || arg === "build-serverless" || arg === "start-serverless";
309
313
  }
310
- var DEFAULT_WATCH_EXTENSIONS = ["ts", "js", "mjs", "cjs", "json"];
311
- var DEFAULT_WATCH_DELAY = 500;
312
314
  function parseRepeatable(argv, index, arg, list) {
313
315
  const value = readValue(argv, index, arg);
314
316
  for (const part of value.split(",")) {
@@ -681,9 +683,6 @@ function loadEnvFiles(paths) {
681
683
  }
682
684
  }
683
685
  }
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
686
  async function preloadModules(modules) {
688
687
  for (const mod of modules) {
689
688
  moduleRequire(mod);
@@ -763,8 +762,6 @@ function runWithWatch(args) {
763
762
  process.on("SIGTERM", shutdown);
764
763
  spawnChild();
765
764
  }
766
- var TEMP_BUILD_ENTRY_FILENAME = ".express-runtime-build-entry.ts";
767
- var TEMP_SERVERLESS_ENTRY_FILENAME = ".express-runtime-build-serverless-entry.ts";
768
765
  function generateServerlessEntry(appPath, initPath) {
769
766
  const absAppPath = (0, import_node_path.resolve)(process.cwd(), appPath);
770
767
  const absInitPath = initPath ? (0, import_node_path.resolve)(process.cwd(), initPath) : void 0;
@@ -796,11 +793,11 @@ function generateRuntimeEntry(appPath, initPath) {
796
793
  }
797
794
  return lines.join("\n") + "\n";
798
795
  }
799
- async function buildBundle(args, tempEntryFilename, entryContent) {
796
+ async function buildBundleFromEntryContent(args) {
800
797
  const tsupModule = await import("tsup");
801
798
  const { build } = tsupModule;
802
- const tempEntryPath = (0, import_node_path.resolve)(process.cwd(), tempEntryFilename);
803
- (0, import_node_fs.writeFileSync)(tempEntryPath, entryContent, "utf8");
799
+ const tempEntryPath = (0, import_node_path.resolve)(process.cwd(), args.tempEntryFilename);
800
+ (0, import_node_fs.writeFileSync)(tempEntryPath, args.entryContent, "utf8");
804
801
  try {
805
802
  await build({
806
803
  config: false,
@@ -819,10 +816,18 @@ async function buildBundle(args, tempEntryFilename, entryContent) {
819
816
  }
820
817
  }
821
818
  async function buildRuntime(args) {
822
- await buildBundle(args, TEMP_BUILD_ENTRY_FILENAME, generateRuntimeEntry(args.appPath, args.initPath));
819
+ const { runBuildEntryCommand: runBuildEntryCommand2 } = await Promise.resolve().then(() => (init_cli_api(), cli_api_exports));
820
+ await runBuildEntryCommand2(args, {
821
+ generateEntry: generateRuntimeEntry,
822
+ tempEntryFilename: TEMP_BUILD_ENTRY_FILENAME
823
+ });
823
824
  }
824
825
  async function buildServerless(args) {
825
- await buildBundle(args, TEMP_SERVERLESS_ENTRY_FILENAME, generateServerlessEntry(args.appPath, args.initPath));
826
+ const { runBuildEntryCommand: runBuildEntryCommand2 } = await Promise.resolve().then(() => (init_cli_api(), cli_api_exports));
827
+ await runBuildEntryCommand2(args, {
828
+ generateEntry: generateServerlessEntry,
829
+ tempEntryFilename: TEMP_SERVERLESS_ENTRY_FILENAME
830
+ });
826
831
  }
827
832
  function collectBody(req) {
828
833
  return new Promise((resolve, reject) => {
@@ -913,36 +918,120 @@ async function loadHandler(handlerPath) {
913
918
  }
914
919
  return exported;
915
920
  }
921
+ 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;
922
+ var init_cli_utils = __esm({
923
+ "src/cli-utils.ts"() {
924
+ "use strict";
925
+ import_node_url = require("url");
926
+ import_node_path = require("path");
927
+ import_node_fs = require("fs");
928
+ import_node_module = require("module");
929
+ import_node_child_process = require("child_process");
930
+ init_src();
931
+ import_meta = {};
932
+ CLI_VERSION = "0.0.0-PLACEHOLDER";
933
+ DEFAULT_WATCH_EXTENSIONS = ["ts", "js", "mjs", "cjs", "json"];
934
+ DEFAULT_WATCH_DELAY = 500;
935
+ moduleRequire = (0, import_node_module.createRequire)(
936
+ typeof import_meta !== "undefined" && import_meta.url || (0, import_node_path.resolve)(process.cwd(), "x").replace(/x$/, "")
937
+ );
938
+ TEMP_BUILD_ENTRY_FILENAME = ".express-runtime-build-entry.ts";
939
+ TEMP_SERVERLESS_ENTRY_FILENAME = ".express-runtime-build-serverless-entry.ts";
940
+ }
941
+ });
916
942
 
917
- // src/cli.ts
918
- async function main() {
919
- const parsedArgs = parseArgs(process.argv.slice(2));
920
- if (!parsedArgs) {
943
+ // src/cli-api.ts
944
+ var cli_api_exports = {};
945
+ __export(cli_api_exports, {
946
+ CLI_VERSION: () => CLI_VERSION,
947
+ applyServerlessResult: () => applyServerlessResult,
948
+ buildBundleFromEntryContent: () => buildBundleFromEntryContent,
949
+ buildChildArgs: () => buildChildArgs,
950
+ buildRuntime: () => buildRuntime,
951
+ buildServerless: () => buildServerless,
952
+ createServerlessAdapterApp: () => createServerlessAdapterApp,
953
+ extractExport: () => extractExport,
954
+ generateRuntimeEntry: () => generateRuntimeEntry,
955
+ generateServerlessEntry: () => generateServerlessEntry,
956
+ isExpressApp: () => isExpressApp,
957
+ loadApp: () => loadApp,
958
+ loadBuiltApp: () => loadBuiltApp,
959
+ loadEnvFiles: () => loadEnvFiles,
960
+ loadHandler: () => loadHandler,
961
+ parseArgs: () => parseArgs,
962
+ parseEnvFile: () => parseEnvFile,
963
+ preloadModules: () => preloadModules,
964
+ printHelp: () => printHelp,
965
+ readValue: () => readValue,
966
+ resolveExport: () => resolveExport,
967
+ runBuildEntryCommand: () => runBuildEntryCommand,
968
+ runCliCommand: () => runCliCommand,
969
+ runDevCommand: () => runDevCommand,
970
+ runExpressDevCommand: () => runExpressDevCommand,
971
+ runWithWatch: () => runWithWatch,
972
+ toServerlessEvent: () => toServerlessEvent
973
+ });
974
+ async function runDevCommand(args, runner) {
975
+ if (args.watch.length > 0) {
976
+ (runner.watch ?? runWithWatch)(args);
921
977
  return;
922
978
  }
979
+ if (args.env.length > 0) {
980
+ loadEnvFiles(args.env);
981
+ }
982
+ await preloadModules(args.require);
983
+ const loaded = await runner.load(args.appPath);
984
+ runner.start(loaded, { ...args.options, exitAfterShutdown: true });
985
+ }
986
+ async function runExpressDevCommand(args) {
987
+ await runDevCommand(args, {
988
+ load: loadApp,
989
+ start: (app, options) => {
990
+ startLocalServer(app, options);
991
+ }
992
+ });
993
+ }
994
+ async function runBuildEntryCommand(args, options) {
995
+ if (options.allowInit === false && args.initPath) {
996
+ throw new Error(options.initErrorMessage ?? "This build command manages init automatically. Remove --init.");
997
+ }
998
+ await buildBundleFromEntryContent({
999
+ entryContent: options.generateEntry(args.appPath, args.initPath),
1000
+ tempEntryFilename: options.tempEntryFilename,
1001
+ outDir: args.outDir,
1002
+ outName: args.outName,
1003
+ format: args.format,
1004
+ target: args.target,
1005
+ external: args.external,
1006
+ clean: args.clean
1007
+ });
1008
+ }
1009
+ async function runCliCommand(parsedArgs) {
923
1010
  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") {
1011
+ await runExpressDevCommand(parsedArgs.dev);
1012
+ return;
1013
+ }
1014
+ if (parsedArgs.subcommand === "start") {
936
1015
  const { start } = parsedArgs;
937
1016
  if (start.env.length > 0) {
938
1017
  loadEnvFiles(start.env);
939
1018
  }
940
1019
  await preloadModules(start.require);
941
1020
  const { app, init } = await loadBuiltApp(start.appPath);
942
- startLocalServer(app, { ...start.options, init, exitAfterShutdown: true });
943
- } else if (parsedArgs.subcommand === "build") {
1021
+ startLocalServer(app, {
1022
+ ...start.options,
1023
+ init: init ? async () => {
1024
+ await init();
1025
+ } : void 0,
1026
+ exitAfterShutdown: true
1027
+ });
1028
+ return;
1029
+ }
1030
+ if (parsedArgs.subcommand === "build") {
944
1031
  await buildRuntime(parsedArgs.build);
945
- } else if (parsedArgs.subcommand === "start-serverless") {
1032
+ return;
1033
+ }
1034
+ if (parsedArgs.subcommand === "start-serverless") {
946
1035
  const { startServerless } = parsedArgs;
947
1036
  if (startServerless.env.length > 0) {
948
1037
  loadEnvFiles(startServerless.env);
@@ -951,9 +1040,26 @@ async function main() {
951
1040
  const handler = await loadHandler(startServerless.handlerPath);
952
1041
  const app = createServerlessAdapterApp(handler);
953
1042
  startLocalServer(app, { ...startServerless.options, exitAfterShutdown: true });
954
- } else {
955
- await buildServerless(parsedArgs.buildServerless);
1043
+ return;
1044
+ }
1045
+ await buildServerless(parsedArgs.buildServerless);
1046
+ }
1047
+ var init_cli_api = __esm({
1048
+ "src/cli-api.ts"() {
1049
+ "use strict";
1050
+ init_src();
1051
+ init_cli_utils();
1052
+ }
1053
+ });
1054
+
1055
+ // src/cli.ts
1056
+ init_cli_api();
1057
+ async function main() {
1058
+ const parsedArgs = parseArgs(process.argv.slice(2));
1059
+ if (!parsedArgs) {
1060
+ return;
956
1061
  }
1062
+ await runCliCommand(parsedArgs);
957
1063
  }
958
1064
  main().catch((error) => {
959
1065
  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.27.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": {