exisjs 0.1.2 → 0.1.4

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.
Files changed (79) hide show
  1. package/README.md +8 -2
  2. package/dist/cli/commands/build.d.ts.map +1 -1
  3. package/dist/cli/commands/build.js +1 -0
  4. package/dist/cli/commands/build.js.map +1 -1
  5. package/dist/cli/commands/dev.d.ts.map +1 -1
  6. package/dist/cli/commands/dev.js +9 -13
  7. package/dist/cli/commands/dev.js.map +1 -1
  8. package/dist/cli/commands/start.d.ts.map +1 -1
  9. package/dist/cli/commands/start.js +1 -6
  10. package/dist/cli/commands/start.js.map +1 -1
  11. package/dist/cli/commands/test.d.ts +1 -0
  12. package/dist/cli/commands/test.d.ts.map +1 -1
  13. package/dist/cli/commands/test.js +7 -12
  14. package/dist/cli/commands/test.js.map +1 -1
  15. package/dist/cli/index.js +1 -0
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/decorators/index.d.ts +59 -0
  18. package/dist/decorators/index.d.ts.map +1 -1
  19. package/dist/decorators/index.js +80 -11
  20. package/dist/decorators/index.js.map +1 -1
  21. package/dist/di/inject.d.ts +17 -0
  22. package/dist/di/inject.d.ts.map +1 -1
  23. package/dist/di/inject.js +17 -0
  24. package/dist/di/inject.js.map +1 -1
  25. package/dist/integrations/mongoose.d.ts.map +1 -1
  26. package/dist/integrations/mongoose.js +3 -2
  27. package/dist/integrations/mongoose.js.map +1 -1
  28. package/dist/module/module.d.ts +16 -0
  29. package/dist/module/module.d.ts.map +1 -1
  30. package/dist/module/module.js +16 -0
  31. package/dist/module/module.js.map +1 -1
  32. package/dist/router/router.d.ts.map +1 -1
  33. package/dist/router/router.js +44 -22
  34. package/dist/router/router.js.map +1 -1
  35. package/dist/server/app.d.ts.map +1 -1
  36. package/dist/server/app.js +156 -95
  37. package/dist/server/app.js.map +1 -1
  38. package/dist/server/cluster.d.ts.map +1 -1
  39. package/dist/server/cluster.js +4 -9
  40. package/dist/server/cluster.js.map +1 -1
  41. package/dist/server/define.d.ts +14 -0
  42. package/dist/server/define.d.ts.map +1 -1
  43. package/dist/server/define.js +14 -0
  44. package/dist/server/define.js.map +1 -1
  45. package/dist/server/request.d.ts +136 -0
  46. package/dist/server/request.d.ts.map +1 -1
  47. package/dist/server/request.js +136 -0
  48. package/dist/server/request.js.map +1 -1
  49. package/dist/server/response.d.ts +186 -0
  50. package/dist/server/response.d.ts.map +1 -1
  51. package/dist/server/response.js +188 -1
  52. package/dist/server/response.js.map +1 -1
  53. package/dist/server/route.d.ts +28 -2
  54. package/dist/server/route.d.ts.map +1 -1
  55. package/dist/server/route.js +28 -2
  56. package/dist/server/route.js.map +1 -1
  57. package/dist/server/uws-adapter.d.ts +4 -1
  58. package/dist/server/uws-adapter.d.ts.map +1 -1
  59. package/dist/server/uws-adapter.js +55 -6
  60. package/dist/server/uws-adapter.js.map +1 -1
  61. package/dist/testing/expect.d.ts +56 -0
  62. package/dist/testing/expect.d.ts.map +1 -0
  63. package/dist/testing/expect.js +435 -0
  64. package/dist/testing/expect.js.map +1 -0
  65. package/dist/testing/index.d.ts +52 -2
  66. package/dist/testing/index.d.ts.map +1 -1
  67. package/dist/testing/index.js +147 -18
  68. package/dist/testing/index.js.map +1 -1
  69. package/dist/testing/reporter.d.ts +5 -10
  70. package/dist/testing/reporter.d.ts.map +1 -1
  71. package/dist/testing/reporter.js +144 -59
  72. package/dist/testing/reporter.js.map +1 -1
  73. package/dist/websocket/server.d.ts.map +1 -1
  74. package/dist/websocket/server.js +5 -3
  75. package/dist/websocket/server.js.map +1 -1
  76. package/dist/websocket/socket.d.ts.map +1 -1
  77. package/dist/websocket/socket.js +8 -6
  78. package/dist/websocket/socket.js.map +1 -1
  79. package/package.json +2 -2
@@ -752,10 +752,8 @@ class App {
752
752
  return this._compiledPipeline;
753
753
  }
754
754
  // ─── Web Standard Fetch (Edge Runtime) & Inject ──────────────────────────────
755
- fetch(request, env, ctx) {
756
- // Dynamic require to avoid circular dependencies and top-level execution
757
- // eslint-disable-next-line @typescript-eslint/no-require-imports
758
- const { handleFetch } = require('../adapters/fetch');
755
+ async fetch(request, env, ctx) {
756
+ const { handleFetch } = await Promise.resolve().then(() => __importStar(require('../adapters/fetch')));
759
757
  return handleFetch(this, request, env, ctx);
760
758
  }
761
759
  async inject(options) {
@@ -1033,42 +1031,42 @@ class App {
1033
1031
  });
1034
1032
  },
1035
1033
  ];
1036
- await (0, router_1.runHandlers)(pipeline, req, res, async (err) => {
1037
- if (isAborted)
1038
- return;
1039
- if (err) {
1040
- this.log.error({ err }, 'Error during uWS WebSocket upgrade middleware');
1034
+ this._executeWithContext(req, res, () => {
1035
+ (0, router_1.runHandlers)(pipeline, req, res, async (err) => {
1036
+ if (isAborted)
1037
+ return;
1038
+ if (err) {
1039
+ this.log.error({ err }, 'Error during uWS WebSocket upgrade middleware');
1040
+ uwsRes.cork(() => {
1041
+ uwsRes.writeStatus('500 Internal Server Error');
1042
+ uwsRes.end();
1043
+ });
1044
+ return;
1045
+ }
1046
+ if (res.headersSent) {
1047
+ return; // Middleware sent an HTTP response
1048
+ }
1049
+ // We need to fetch headers directly from the shimReq.headers
1050
+ const secWebSocketKey = shimReq.headers['sec-websocket-key'] || '';
1051
+ const secWebSocketProtocol = shimReq.headers['sec-websocket-protocol'] || '';
1052
+ const secWebSocketExtensions = shimReq.headers['sec-websocket-extensions'] || '';
1053
+ // Prepare user data for the upgraded websocket
1054
+ const userData = {
1055
+ req,
1056
+ res,
1057
+ exisWs: new socket_1.ExisWebSocket(null, req, this.wsServer), // the raw will be set to shim in open()
1058
+ finalHandler: matched.route.handlers[matched.route.handlers.length - 1],
1059
+ };
1060
+ this.wsServer.track(userData.exisWs);
1061
+ req.ws = userData.exisWs;
1041
1062
  uwsRes.cork(() => {
1042
- uwsRes.writeStatus('500 Internal Server Error');
1043
- uwsRes.end();
1063
+ uwsRes.upgrade(userData, secWebSocketKey, secWebSocketProtocol, secWebSocketExtensions, context);
1064
+ });
1065
+ Promise.resolve(userData.finalHandler(req, res, () => {
1066
+ /* noop */
1067
+ })).catch((e) => {
1068
+ this.log.error({ err: e }, 'Error in uWS WebSocket handler');
1044
1069
  });
1045
- return;
1046
- }
1047
- if (res.headersSent) {
1048
- return; // Middleware sent an HTTP response
1049
- }
1050
- // We need to fetch headers directly from the shimReq.headers
1051
- const secWebSocketKey = shimReq.headers['sec-websocket-key'] || '';
1052
- const secWebSocketProtocol = shimReq.headers['sec-websocket-protocol'] || '';
1053
- const secWebSocketExtensions = shimReq.headers['sec-websocket-extensions'] || '';
1054
- // Prepare user data for the upgraded websocket
1055
- const userData = {
1056
- req,
1057
- res,
1058
- exisWs: new socket_1.ExisWebSocket(null, req, this.wsServer), // the raw will be set to shim in open()
1059
- finalHandler: matched.route.handlers[matched.route.handlers.length - 1],
1060
- };
1061
- this.wsServer.track(userData.exisWs);
1062
- req.ws = userData.exisWs;
1063
- uwsRes.cork(() => {
1064
- uwsRes.upgrade(userData, secWebSocketKey, secWebSocketProtocol, secWebSocketExtensions, context);
1065
- });
1066
- // The open handler in createUwsApp will call finalHandler?
1067
- // Actually we should just execute the finalHandler here since upgrade succeeds immediately if we don't block
1068
- Promise.resolve(userData.finalHandler(req, res, () => {
1069
- /* noop */
1070
- })).catch((e) => {
1071
- this.log.error({ err: e }, 'Error in uWS WebSocket handler');
1072
1070
  });
1073
1071
  });
1074
1072
  }
@@ -1121,8 +1119,10 @@ class App {
1121
1119
  onListen(address);
1122
1120
  }
1123
1121
  else {
1124
- const url = `http://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;
1125
- this.log.info({ url, env: this.options.env, backend: 'uws' }, `Server running at ${url} (uWebSockets.js)`);
1122
+ if (!process.env.__EXIS_DEV_SERVER && !process.env.__EXIS_CLI) {
1123
+ const url = `http://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;
1124
+ this.log.info({ url, env: this.options.env, backend: 'uws' }, `Server running at ${url} (uWebSockets.js)`);
1125
+ }
1126
1126
  }
1127
1127
  if (this.options.env === 'production') {
1128
1128
  const handleShutdown = async () => {
@@ -1274,10 +1274,19 @@ class App {
1274
1274
  : 'use --host 0.0.0.0 to expose';
1275
1275
  const readyMs = 125;
1276
1276
  const displayEnv = this.options.env || process.env.NODE_ENV || 'development';
1277
+ const workerCount = process.env.__EXIS_CLUSTER_WORKERS;
1278
+ const cluster = await Promise.resolve().then(() => __importStar(require('node:cluster')));
1279
+ // In cluster mode, ONLY let Worker #1 print the banner so we don't spam the console 12 times
1280
+ if (cluster.default.isWorker && cluster.default.worker?.id !== 1) {
1281
+ return;
1282
+ }
1277
1283
  console.log(`\n ${c.primary}${c.bold}EXIS v${fwVersion}${c.reset} ready in ${c.bold}${readyMs} ms${c.reset}\n`);
1278
1284
  console.log(` ${c.white}➜${c.reset} ${c.bold}Local:${c.reset} ${c.blue}http://${displayHost}:${port}/${c.reset}`);
1279
1285
  console.log(` ${c.white}➜${c.reset} ${c.dim}Network:${c.reset} ${c.blue}${networkHost}/${c.reset}`);
1280
1286
  console.log(` ${c.white}➜${c.reset} ${c.dim}Environ:${c.reset} ${c.green}${displayEnv}${c.reset}`);
1287
+ if (workerCount && Number(workerCount) > 1) {
1288
+ console.log(` ${c.white}➜${c.reset} ${c.dim}Workers:${c.reset} ${c.magenta}${workerCount}${c.reset}`);
1289
+ }
1281
1290
  console.log(` ${c.white}➜${c.reset} press ${c.bold}h + enter${c.reset} ${c.dim}to show help${c.reset}\n`);
1282
1291
  }
1283
1292
  // ─── Graceful Shutdown ────────────────────────────────────────────────────────
@@ -1477,8 +1486,14 @@ class App {
1477
1486
  let url = (0, node_url_1.pathToFileURL)(manifestPath).href;
1478
1487
  if (!isProd)
1479
1488
  url += '?t=' + Date.now(); // cache bust for dev
1480
- const dynamicImport = new Function('specifier', 'return import(specifier)');
1481
- const mod = await dynamicImport(url);
1489
+ let mod;
1490
+ if (process.env.VITEST || process.env.NODE_ENV === 'test') {
1491
+ mod = await Promise.resolve(`${url}`).then(s => __importStar(require(s)));
1492
+ }
1493
+ else {
1494
+ const dynamicImport = new Function('specifier', 'return import(specifier)');
1495
+ mod = await dynamicImport(url);
1496
+ }
1482
1497
  const manifest = mod.manifest;
1483
1498
  if (Array.isArray(manifest)) {
1484
1499
  for (const entry of manifest) {
@@ -1647,10 +1662,17 @@ class App {
1647
1662
  }
1648
1663
  async mountRouteFile(filePath, routePath) {
1649
1664
  let mod;
1650
- const dynamicImport = new Function('specifier', 'return import(specifier)');
1651
1665
  try {
1652
- const url = (0, node_url_1.pathToFileURL)(filePath).href + '?t=' + Date.now();
1653
- mod = await dynamicImport(url);
1666
+ const url = process.env.VITEST || process.env.NODE_ENV === 'test'
1667
+ ? (0, node_url_1.pathToFileURL)(filePath).href
1668
+ : (0, node_url_1.pathToFileURL)(filePath).href + '?t=' + Date.now();
1669
+ if (process.env.VITEST || process.env.NODE_ENV === 'test') {
1670
+ mod = await Promise.resolve(`${url}`).then(s => __importStar(require(s)));
1671
+ }
1672
+ else {
1673
+ const dynamicImport = new Function('specifier', 'return import(specifier)');
1674
+ mod = await dynamicImport(url);
1675
+ }
1654
1676
  }
1655
1677
  catch {
1656
1678
  // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -1688,10 +1710,28 @@ class App {
1688
1710
  else if (await fs.stat(gwPathJs).catch(() => null))
1689
1711
  targetGw = gwPathJs;
1690
1712
  if (targetGw) {
1691
- const url = (0, node_url_1.pathToFileURL)(targetGw).href + '?t=' + Date.now();
1692
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1693
- const gwMod = await dynamicImport(url).catch(() => require(targetGw));
1694
- const gwConfig = gwMod.default || gwMod;
1713
+ const gwUrl = process.env.VITEST || process.env.NODE_ENV === 'test'
1714
+ ? (0, node_url_1.pathToFileURL)(targetGw).href
1715
+ : (0, node_url_1.pathToFileURL)(targetGw).href + '?t=' + Date.now();
1716
+ let gwMod;
1717
+ try {
1718
+ if (process.env.VITEST || process.env.NODE_ENV === 'test') {
1719
+ gwMod = await Promise.resolve(`${gwUrl}`).then(s => __importStar(require(s)));
1720
+ }
1721
+ else {
1722
+ const dynamicImportGw = new Function('specifier', 'return import(specifier)');
1723
+ gwMod = await dynamicImportGw(gwUrl);
1724
+ }
1725
+ }
1726
+ catch {
1727
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
1728
+ gwMod = require(targetGw);
1729
+ }
1730
+ const gwConfig = gwMod && gwMod.default && gwMod.default.default
1731
+ ? gwMod.default.default
1732
+ : gwMod && gwMod.default
1733
+ ? gwMod.default
1734
+ : gwMod;
1695
1735
  if (gwConfig) {
1696
1736
  const isExcluded = (reqPath, reqMethod) => {
1697
1737
  if (!gwConfig.exclude)
@@ -1769,9 +1809,7 @@ class App {
1769
1809
  if (ms) {
1770
1810
  req.timeoutTimer = setTimeout(() => {
1771
1811
  if (!res.headersSent) {
1772
- res
1773
- .status(408)
1774
- .json({
1812
+ res.status(408).json({
1775
1813
  success: false,
1776
1814
  error: {
1777
1815
  code: 'REQUEST_TIMEOUT',
@@ -1818,45 +1856,66 @@ class App {
1818
1856
  /* ignore */
1819
1857
  }
1820
1858
  }
1821
- if (!mod.config)
1822
- mod.config = {};
1823
- if (mod.config.middleware)
1824
- allMiddlewares.push(...mod.config.middleware);
1825
- if (mod.config.cors !== undefined)
1826
- allCors = mod.config.cors;
1827
- if (mod.config.headers)
1828
- allHeaders = { ...allHeaders, ...mod.config.headers };
1829
- if (mod.config.plugins) {
1830
- for (const plugin of mod.config.plugins) {
1859
+ const routeConfig = mod.config || {};
1860
+ if (routeConfig.middleware)
1861
+ allMiddlewares.push(...routeConfig.middleware);
1862
+ if (routeConfig.cors !== undefined)
1863
+ allCors = routeConfig.cors;
1864
+ if (routeConfig.headers)
1865
+ allHeaders = { ...allHeaders, ...routeConfig.headers };
1866
+ if (routeConfig.plugins) {
1867
+ for (const plugin of routeConfig.plugins) {
1831
1868
  await this.register(plugin);
1832
1869
  }
1833
1870
  }
1834
- // Inject Gateway features into module config for compileFunctionalController and OOP
1835
- mod.config.filters = [
1871
+ // Pass gateway features to controllers via metadata if necessary
1872
+ const combinedFilters = [
1836
1873
  ...allFilters,
1837
- ...(mod.config.filters
1838
- ? Array.isArray(mod.config.filters)
1839
- ? mod.config.filters
1840
- : [mod.config.filters]
1874
+ ...(routeConfig.filters
1875
+ ? Array.isArray(routeConfig.filters)
1876
+ ? routeConfig.filters
1877
+ : [routeConfig.filters]
1841
1878
  : []),
1842
1879
  ];
1843
- mod.config.guards = [
1880
+ const combinedGuards = [
1844
1881
  ...allGuards,
1845
- ...(mod.config.guards
1846
- ? Array.isArray(mod.config.guards)
1847
- ? mod.config.guards
1848
- : [mod.config.guards]
1882
+ ...(routeConfig.guards
1883
+ ? Array.isArray(routeConfig.guards)
1884
+ ? routeConfig.guards
1885
+ : [routeConfig.guards]
1849
1886
  : []),
1850
1887
  ];
1851
- mod.config.interceptors = [
1888
+ const combinedInterceptors = [
1852
1889
  ...allInterceptors,
1853
- ...(mod.config.interceptors
1854
- ? Array.isArray(mod.config.interceptors)
1855
- ? mod.config.interceptors
1856
- : [mod.config.interceptors]
1890
+ ...(routeConfig.interceptors
1891
+ ? Array.isArray(routeConfig.interceptors)
1892
+ ? routeConfig.interceptors
1893
+ : [routeConfig.interceptors]
1857
1894
  : []),
1858
1895
  ];
1859
- mod.config.metadata = { ...allMetadata, ...(mod.config.metadata || {}) };
1896
+ // Inject into the default export if it's a functional controller
1897
+ if (mod.default && typeof mod.default === 'object') {
1898
+ try {
1899
+ if (!mod.default.filters)
1900
+ mod.default.filters = [];
1901
+ mod.default.filters.push(...combinedFilters);
1902
+ if (!mod.default.guards)
1903
+ mod.default.guards = [];
1904
+ mod.default.guards.push(...combinedGuards);
1905
+ if (!mod.default.interceptors)
1906
+ mod.default.interceptors = [];
1907
+ mod.default.interceptors.push(...combinedInterceptors);
1908
+ if (!mod.default.metadata)
1909
+ mod.default.metadata = {};
1910
+ Object.assign(mod.default.metadata, {
1911
+ ...allMetadata,
1912
+ ...(routeConfig.metadata || {}),
1913
+ });
1914
+ }
1915
+ catch {
1916
+ // If mod.default is frozen, ignore
1917
+ }
1918
+ }
1860
1919
  const prefixMiddlewares = [];
1861
1920
  if (allCors !== undefined) {
1862
1921
  if (allCors === true)
@@ -1875,19 +1934,25 @@ class App {
1875
1934
  const isRouter = (obj) => obj && 'handle' in obj && 'get' in obj;
1876
1935
  const CONTROLLER_PREFIX = Symbol.for('exisjs:controller_prefix');
1877
1936
  const isController = (obj) => obj && obj.prototype && obj.prototype[CONTROLLER_PREFIX] !== undefined;
1878
- if (mod.default && mod.default.__isController) {
1937
+ const unwrappedMod = mod && mod.default && mod.default.default
1938
+ ? mod.default.default
1939
+ : mod && mod.default
1940
+ ? mod.default
1941
+ : mod;
1942
+ const functionalControllerObj = unwrappedMod && unwrappedMod.__isController ? unwrappedMod : null;
1943
+ if (functionalControllerObj) {
1879
1944
  // ─── THE NEW PERFECT FUNCTIONAL CONTROLLER ───
1880
- const compiledRouter = this.compileFunctionalController(mod.default);
1945
+ const compiledRouter = this.compileFunctionalController(functionalControllerObj);
1881
1946
  this.mountRouteWithSource(routePath, compiledRouter, filePath, prefixMiddlewares);
1882
1947
  }
1883
1948
  else if (mod.router && isRouter(mod.router)) {
1884
1949
  this.mountRouteWithSource(routePath, mod.router, filePath, prefixMiddlewares);
1885
1950
  }
1886
- else if (mod.default && isController(mod.default)) {
1887
- this.registerControllers([mod.default], routePath, prefixMiddlewares);
1951
+ else if (unwrappedMod && isController(unwrappedMod)) {
1952
+ this.registerControllers([unwrappedMod], routePath, prefixMiddlewares);
1888
1953
  }
1889
- else if (mod.default && isRouter(mod.default)) {
1890
- this.mountRouteWithSource(routePath, mod.default, filePath, prefixMiddlewares);
1954
+ else if (unwrappedMod && isRouter(unwrappedMod)) {
1955
+ this.mountRouteWithSource(routePath, unwrappedMod, filePath, prefixMiddlewares);
1891
1956
  }
1892
1957
  else if (isRouter(mod)) {
1893
1958
  this.mountRouteWithSource(routePath, mod, filePath, prefixMiddlewares);
@@ -1897,14 +1962,10 @@ class App {
1897
1962
  }
1898
1963
  }
1899
1964
  compileFunctionalController(config) {
1900
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1901
- const { Router } = require('../router/router');
1902
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1903
- const { cors } = require('../middleware/middleware');
1904
- const router = new Router();
1965
+ const router = new router_1.Router();
1905
1966
  const fileMiddleware = [];
1906
1967
  if (config.cors) {
1907
- fileMiddleware.push(config.cors === true ? cors({}) : cors(config.cors));
1968
+ fileMiddleware.push(config.cors === true ? (0, middleware_1.cors)({}) : (0, middleware_1.cors)(config.cors));
1908
1969
  }
1909
1970
  if (config.middleware) {
1910
1971
  fileMiddleware.push(...(Array.isArray(config.middleware)
@@ -1926,7 +1987,7 @@ class App {
1926
1987
  continue;
1927
1988
  const routeMiddlewares = [...fileMiddleware];
1928
1989
  if (rc.cors) {
1929
- routeMiddlewares.push(rc.cors === true ? cors({}) : cors(rc.cors));
1990
+ routeMiddlewares.push(rc.cors === true ? (0, middleware_1.cors)({}) : (0, middleware_1.cors)(rc.cors));
1930
1991
  }
1931
1992
  if (rc.middleware) {
1932
1993
  routeMiddlewares.push(...(Array.isArray(rc.middleware) ? rc.middleware : [rc.middleware]));
@@ -1947,9 +2008,7 @@ class App {
1947
2008
  : guard.canActivate(req));
1948
2009
  if (!allowed) {
1949
2010
  if (res && !res.headersSent) {
1950
- res
1951
- .status(403)
1952
- .json({
2011
+ res.status(403).json({
1953
2012
  success: false,
1954
2013
  error: { code: 'FORBIDDEN', message: 'Forbidden by Guard' },
1955
2014
  });
@@ -2078,9 +2137,11 @@ class App {
2078
2137
  }
2079
2138
  else {
2080
2139
  if (Object.keys(schema).length > 0) {
2140
+ ;
2081
2141
  router[method](rc.path, ...routeMiddlewares, schema, superHandler);
2082
2142
  }
2083
2143
  else {
2144
+ ;
2084
2145
  router[method](rc.path, ...routeMiddlewares, superHandler);
2085
2146
  }
2086
2147
  }