@cyberskill/shared 3.6.0 → 3.8.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.
Files changed (48) hide show
  1. package/dist/config/vitest/vitest.e2e.js +1 -1
  2. package/dist/config/vitest/vitest.e2e.js.map +1 -1
  3. package/dist/config/vitest/vitest.unit.js +1 -1
  4. package/dist/config/vitest/vitest.unit.js.map +1 -1
  5. package/dist/constant/common.d.ts +3 -2
  6. package/dist/constant/common.js +1 -1
  7. package/dist/constant/common.js.map +1 -1
  8. package/dist/node/apollo-server/apollo-server.util.js +15 -13
  9. package/dist/node/apollo-server/apollo-server.util.js.map +1 -1
  10. package/dist/node/command/command.util.js +29 -29
  11. package/dist/node/command/command.util.js.map +1 -1
  12. package/dist/node/express/express.util.d.ts +4 -0
  13. package/dist/node/express/express.util.js +7 -6
  14. package/dist/node/express/express.util.js.map +1 -1
  15. package/dist/node/mongo/mongo.controller.mongoose.d.ts +6 -1
  16. package/dist/node/mongo/mongo.controller.mongoose.js +10 -11
  17. package/dist/node/mongo/mongo.controller.mongoose.js.map +1 -1
  18. package/dist/node/mongo/mongo.controller.native.d.ts +1 -1
  19. package/dist/node/mongo/mongo.controller.native.js +5 -4
  20. package/dist/node/mongo/mongo.controller.native.js.map +1 -1
  21. package/dist/node/mongo/mongo.controller.type.d.ts +15 -0
  22. package/dist/node/mongo/mongo.dynamic-populate.js +12 -12
  23. package/dist/node/mongo/mongo.dynamic-populate.js.map +1 -1
  24. package/dist/node/mongo/mongo.util.d.ts +3 -3
  25. package/dist/node/mongo/mongo.util.js.map +1 -1
  26. package/dist/node/path/index.js +2 -2
  27. package/dist/node/path/path.constant.d.ts +21 -7
  28. package/dist/node/path/path.constant.js +48 -29
  29. package/dist/node/path/path.constant.js.map +1 -1
  30. package/dist/node/storage/storage.util.js +2 -6
  31. package/dist/node/storage/storage.util.js.map +1 -1
  32. package/dist/node/ws/ws.util.js +2 -0
  33. package/dist/node/ws/ws.util.js.map +1 -1
  34. package/dist/react/apollo-client/apollo-client.util.js +42 -41
  35. package/dist/react/apollo-client/apollo-client.util.js.map +1 -1
  36. package/dist/react/log/log.util.d.ts +5 -0
  37. package/dist/react/log/log.util.js.map +1 -1
  38. package/dist/typescript/common.type.d.ts +18 -0
  39. package/dist/typescript/common.type.js +9 -2
  40. package/dist/typescript/common.type.js.map +1 -1
  41. package/dist/typescript/index.js +2 -2
  42. package/dist/util/object/object.util.js +43 -37
  43. package/dist/util/object/object.util.js.map +1 -1
  44. package/dist/util/serializer/serializer.util.d.ts +13 -0
  45. package/dist/util/serializer/serializer.util.js.map +1 -1
  46. package/dist/util/string/string.util.js +45 -13
  47. package/dist/util/string/string.util.js.map +1 -1
  48. package/package.json +7 -6
@@ -1,6 +1,6 @@
1
1
  import { deepMerge as e } from "../../util/object/object.util.js";
2
2
  import { defineConfig as t } from "../../node_modules/.pnpm/vitest@4.1.0_@types_node@25.5.0_jsdom@29.0.0_@noble_hashes@1.8.0__vite@8.0.0_@types_nod_53aa4254f295b3c40bb8f17b6ab226b5/node_modules/vitest/dist/config.js";
3
- import n from "@vitejs/plugin-react-swc";
3
+ import n from "@vitejs/plugin-react";
4
4
  //#region src/config/vitest/vitest.e2e.ts
5
5
  function r(r) {
6
6
  return t(e({
@@ -1 +1 @@
1
- {"version":3,"file":"vitest.e2e.js","names":[],"sources":["../../../src/config/vitest/vitest.e2e.ts"],"sourcesContent":["import type { UserConfig } from 'vite';\n\nimport react from '@vitejs/plugin-react-swc';\nimport { defineConfig } from 'vitest/config';\n\nimport { deepMerge } from '../../util/object/index.js';\n\n/**\n * Creates a Vitest configuration for end-to-end testing with browser automation.\n * This function generates a Vitest configuration specifically designed for E2E testing\n * using Playwright with multiple browser instances. It includes React support and\n * browser automation capabilities for comprehensive end-to-end testing.\n *\n * The configuration includes:\n * - React SWC plugin for fast React compilation\n * - Browser automation with Playwright provider\n * - Multiple browser instances (Chromium, Firefox, WebKit)\n * - E2E test file pattern matching\n * - Configurable options merging\n *\n * @param options - Additional Vite configuration options to merge with the E2E config.\n * @returns A Vitest configuration object optimized for end-to-end testing with browser automation.\n */\nexport function vitestE2E(options: UserConfig) {\n const config = {\n plugins: [react()],\n test: {\n include: ['**/*.test.e2e.?(c|m)[jt]s?(x)'],\n },\n };\n\n return defineConfig(deepMerge(config as any, options as any) as UserConfig);\n}\n\nexport default vitestE2E({});\n"],"mappings":";;;;AAuBA,SAAgB,EAAU,GAAqB;AAQ3C,QAAO,EAAa,EAPL;EACX,SAAS,CAAC,GAAO,CAAC;EAClB,MAAM,EACF,SAAS,CAAC,gCAAgC,EAC7C;EACJ,EAE4C,EAAe,CAAe;;AAG/E,IAAA,IAAe,EAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"vitest.e2e.js","names":[],"sources":["../../../src/config/vitest/vitest.e2e.ts"],"sourcesContent":["import type { UserConfig } from 'vite';\n\nimport react from '@vitejs/plugin-react';\nimport { defineConfig } from 'vitest/config';\n\nimport { deepMerge } from '../../util/object/index.js';\n\n/**\n * Creates a Vitest configuration for end-to-end testing with browser automation.\n * This function generates a Vitest configuration specifically designed for E2E testing\n * using Playwright with multiple browser instances. It includes React support and\n * browser automation capabilities for comprehensive end-to-end testing.\n *\n * The configuration includes:\n * - React SWC plugin for fast React compilation\n * - Browser automation with Playwright provider\n * - Multiple browser instances (Chromium, Firefox, WebKit)\n * - E2E test file pattern matching\n * - Configurable options merging\n *\n * @param options - Additional Vite configuration options to merge with the E2E config.\n * @returns A Vitest configuration object optimized for end-to-end testing with browser automation.\n */\nexport function vitestE2E(options: UserConfig) {\n const config = {\n plugins: [react()],\n test: {\n include: ['**/*.test.e2e.?(c|m)[jt]s?(x)'],\n },\n };\n\n return defineConfig(deepMerge(config as any, options as any) as UserConfig);\n}\n\nexport default vitestE2E({});\n"],"mappings":";;;;AAuBA,SAAgB,EAAU,GAAqB;AAQ3C,QAAO,EAAa,EAPL;EACX,SAAS,CAAC,GAAO,CAAC;EAClB,MAAM,EACF,SAAS,CAAC,gCAAgC,EAC7C;EACJ,EAE4C,EAAe,CAAe;;AAG/E,IAAA,IAAe,EAAU,EAAE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { deepMerge as e } from "../../util/object/object.util.js";
2
2
  import { defineConfig as t } from "../../node_modules/.pnpm/vitest@4.1.0_@types_node@25.5.0_jsdom@29.0.0_@noble_hashes@1.8.0__vite@8.0.0_@types_nod_53aa4254f295b3c40bb8f17b6ab226b5/node_modules/vitest/dist/config.js";
3
- import n from "@vitejs/plugin-react-swc";
3
+ import n from "@vitejs/plugin-react";
4
4
  //#region src/config/vitest/vitest.unit.ts
5
5
  function r(r) {
6
6
  return t(e({
@@ -1 +1 @@
1
- {"version":3,"file":"vitest.unit.js","names":[],"sources":["../../../src/config/vitest/vitest.unit.ts"],"sourcesContent":["import type { UserConfig } from 'vite';\n\nimport react from '@vitejs/plugin-react-swc';\nimport { defineConfig } from 'vitest/config';\n\nimport { deepMerge } from '#util/object/index.js';\n\n/**\n * Creates a Vitest configuration for unit testing with React support.\n * This function generates a Vitest configuration specifically designed for unit testing\n * React components and JavaScript/TypeScript modules. It includes JSDOM environment\n * for DOM simulation and comprehensive testing setup.\n *\n * The configuration includes:\n * - React SWC plugin for fast React compilation\n * - JSDOM environment for DOM simulation\n * - Global test functions availability\n * - VM threads pool for parallel test execution\n * - Unit test file pattern matching\n * - Setup files for testing library configuration\n * - Configurable options merging\n *\n * @param options - Additional Vite configuration options to merge with the unit test config.\n * @returns A Vitest configuration object optimized for unit testing with React and DOM support.\n */\nexport function vitestUnit(options: UserConfig) {\n const config = {\n plugins: [react()],\n test: {\n globals: true,\n environment: 'jsdom',\n pool: 'vmThreads',\n include: ['**/*.test.unit.?(c|m)[jt]s?(x)'],\n setupFiles: ['./vitest.unit.setup.ts'],\n coverage: {\n provider: 'istanbul',\n reporter: ['text', 'lcov'],\n reportsDirectory: './coverage',\n thresholds: {\n statements: 80,\n branches: 80,\n functions: 80,\n lines: 80,\n },\n },\n },\n };\n\n return defineConfig(deepMerge(config as any, options as any) as UserConfig);\n}\n\nexport default vitestUnit({});\n"],"mappings":";;;;AAyBA,SAAgB,EAAW,GAAqB;AAuB5C,QAAO,EAAa,EAtBL;EACX,SAAS,CAAC,GAAO,CAAC;EAClB,MAAM;GACF,SAAS;GACT,aAAa;GACb,MAAM;GACN,SAAS,CAAC,iCAAiC;GAC3C,YAAY,CAAC,yBAAyB;GACtC,UAAU;IACN,UAAU;IACV,UAAU,CAAC,QAAQ,OAAO;IAC1B,kBAAkB;IAClB,YAAY;KACR,YAAY;KACZ,UAAU;KACV,WAAW;KACX,OAAO;KACV;IACJ;GACJ;EACJ,EAE4C,EAAe,CAAe;;AAG/E,IAAA,IAAe,EAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"vitest.unit.js","names":[],"sources":["../../../src/config/vitest/vitest.unit.ts"],"sourcesContent":["import type { UserConfig } from 'vite';\n\nimport react from '@vitejs/plugin-react';\nimport { defineConfig } from 'vitest/config';\n\nimport { deepMerge } from '#util/object/index.js';\n\n/**\n * Creates a Vitest configuration for unit testing with React support.\n * This function generates a Vitest configuration specifically designed for unit testing\n * React components and JavaScript/TypeScript modules. It includes JSDOM environment\n * for DOM simulation and comprehensive testing setup.\n *\n * The configuration includes:\n * - React SWC plugin for fast React compilation\n * - JSDOM environment for DOM simulation\n * - Global test functions availability\n * - VM threads pool for parallel test execution\n * - Unit test file pattern matching\n * - Setup files for testing library configuration\n * - Configurable options merging\n *\n * @param options - Additional Vite configuration options to merge with the unit test config.\n * @returns A Vitest configuration object optimized for unit testing with React and DOM support.\n */\nexport function vitestUnit(options: UserConfig) {\n const config = {\n plugins: [react()],\n test: {\n globals: true,\n environment: 'jsdom',\n pool: 'vmThreads',\n include: ['**/*.test.unit.?(c|m)[jt]s?(x)'],\n setupFiles: ['./vitest.unit.setup.ts'],\n coverage: {\n provider: 'istanbul',\n reporter: ['text', 'lcov'],\n reportsDirectory: './coverage',\n thresholds: {\n statements: 80,\n branches: 80,\n functions: 80,\n lines: 80,\n },\n },\n },\n };\n\n return defineConfig(deepMerge(config as any, options as any) as UserConfig);\n}\n\nexport default vitestUnit({});\n"],"mappings":";;;;AAyBA,SAAgB,EAAW,GAAqB;AAuB5C,QAAO,EAAa,EAtBL;EACX,SAAS,CAAC,GAAO,CAAC;EAClB,MAAM;GACF,SAAS;GACT,aAAa;GACb,MAAM;GACN,SAAS,CAAC,iCAAiC;GAC3C,YAAY,CAAC,yBAAyB;GACtC,UAAU;IACN,UAAU;IACV,UAAU,CAAC,QAAQ,OAAO;IAC1B,kBAAkB;IAClB,YAAY;KACR,YAAY;KACZ,UAAU;KACV,WAAW;KACX,OAAO;KACV;IACJ;GACJ;EACJ,EAE4C,EAAe,CAAe;;AAG/E,IAAA,IAAe,EAAW,EAAE,CAAC"}
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Indicates if the current environment is a browser (as opposed to Node.js).
3
- * This constant is true if the global `window` object is defined, false otherwise.
2
+ * Indicates if the current environment is a browser (as opposed to Node.js or SSR).
3
+ * Checks both `window` and `document` to avoid false positives in SSR environments
4
+ * like Next.js where `window` may exist but `document` does not.
4
5
  */
5
6
  export declare const IS_BROWSER: boolean;
@@ -1,5 +1,5 @@
1
1
  //#region src/constant/common.ts
2
- var e = typeof window < "u";
2
+ var e = typeof window < "u" && typeof document < "u";
3
3
  //#endregion
4
4
  export { e as IS_BROWSER };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"common.js","names":[],"sources":["../../src/constant/common.ts"],"sourcesContent":["/**\n * Indicates if the current environment is a browser (as opposed to Node.js).\n * This constant is true if the global `window` object is defined, false otherwise.\n */\nexport const IS_BROWSER = typeof window !== 'undefined';\n"],"mappings":";AAIA,IAAa,IAAa,OAAO,SAAW"}
1
+ {"version":3,"file":"common.js","names":[],"sources":["../../src/constant/common.ts"],"sourcesContent":["/**\n * Indicates if the current environment is a browser (as opposed to Node.js or SSR).\n * Checks both `window` and `document` to avoid false positives in SSR environments\n * like Next.js where `window` may exist but `document` does not.\n */\nexport const IS_BROWSER = typeof window !== 'undefined' && typeof document !== 'undefined';\n"],"mappings":";AAKA,IAAa,IAAa,OAAO,SAAW,OAAe,OAAO,WAAa"}
@@ -1,28 +1,30 @@
1
1
  import { log as e } from "../log/log.util.js";
2
- import { ApolloServer as t } from "@apollo/server";
3
- import { ApolloServerPluginDrainHttpServer as n } from "@apollo/server/plugin/drainHttpServer";
4
- import { ApolloServerPluginLandingPageLocalDefault as r, ApolloServerPluginLandingPageProductionDefault as i } from "@apollo/server/plugin/landingPage/default";
5
- import { expressMiddleware as a } from "@as-integrations/express5";
2
+ import t from "node:process";
3
+ import { ApolloServer as n } from "@apollo/server";
4
+ import { ApolloServerPluginDrainHttpServer as r } from "@apollo/server/plugin/drainHttpServer";
5
+ import { ApolloServerPluginLandingPageLocalDefault as i, ApolloServerPluginLandingPageProductionDefault as a } from "@apollo/server/plugin/landingPage/default";
6
+ import { expressMiddleware as o } from "@as-integrations/express5";
6
7
  //#region src/node/apollo-server/apollo-server.util.ts
7
- function o(a) {
8
- return new t({
9
- schema: a.schema,
8
+ function s(o) {
9
+ let s = o.isDev && t.env.NODE_ENV !== "production";
10
+ return new n({
11
+ schema: o.schema,
10
12
  plugins: [
11
- a.isDev ? r() : i(),
12
- n({ httpServer: a.server }),
13
- ...a.drainServer ? [{ async serverWillStart() {
13
+ s ? i() : a(),
14
+ r({ httpServer: o.server }),
15
+ ...o.drainServer ? [{ async serverWillStart() {
14
16
  return { async drainServer() {
15
- a.drainServer?.(), e.info("Apollo Server drainServer hook called");
17
+ o.drainServer?.(), e.info("Apollo Server drainServer hook called");
16
18
  } };
17
19
  } }] : []
18
20
  ],
19
- ...a.isDev && {
21
+ ...s && {
20
22
  introspection: !0,
21
23
  includeStacktraceInErrorResponses: !0
22
24
  }
23
25
  });
24
26
  }
25
27
  //#endregion
26
- export { o as createApolloServer, a as expressMiddleware };
28
+ export { s as createApolloServer, o as expressMiddleware };
27
29
 
28
30
  //# sourceMappingURL=apollo-server.util.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apollo-server.util.js","names":[],"sources":["../../../src/node/apollo-server/apollo-server.util.ts"],"sourcesContent":["import { ApolloServer } from '@apollo/server';\nimport { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';\nimport {\n ApolloServerPluginLandingPageLocalDefault,\n ApolloServerPluginLandingPageProductionDefault,\n} from '@apollo/server/plugin/landingPage/default';\nimport { expressMiddleware } from '@as-integrations/express5';\n\nimport type { I_ApolloServerOptions } from './apollo-server.type.js';\n\nimport { log } from '../log/index.js';\n\n/**\n * Creates and configures an Apollo Server instance with appropriate plugins and settings.\n * This function sets up an Apollo Server with development or production landing pages,\n * HTTP server draining capabilities, and optional custom drain server hooks.\n *\n * The server is configured with:\n * - Development or production landing page based on the isDev flag\n * - HTTP server draining plugin for graceful shutdowns\n * - Optional custom drain server hook for additional cleanup\n * - Development-specific settings (introspection and stack traces) when isDev is true\n *\n * @param options - Configuration options for the Apollo Server including server instance, schema, and environment settings.\n * @returns A configured Apollo Server instance ready to be started.\n */\nexport function createApolloServer(options: I_ApolloServerOptions): ApolloServer {\n return new ApolloServer({\n schema: options.schema,\n plugins: [\n options.isDev\n ? ApolloServerPluginLandingPageLocalDefault()\n : ApolloServerPluginLandingPageProductionDefault(),\n ApolloServerPluginDrainHttpServer({ httpServer: options.server }),\n ...(options.drainServer\n ? [{\n async serverWillStart() {\n return {\n async drainServer() {\n options.drainServer?.();\n log.info('Apollo Server drainServer hook called');\n },\n };\n },\n }]\n : []),\n ],\n ...(options.isDev && {\n introspection: true,\n includeStacktraceInErrorResponses: true,\n }),\n });\n}\n\nexport { expressMiddleware };\n"],"mappings":";;;;;;AA0BA,SAAgB,EAAmB,GAA8C;AAC7E,QAAO,IAAI,EAAa;EACpB,QAAQ,EAAQ;EAChB,SAAS;GACL,EAAQ,QACF,GAA2C,GAC3C,GAAgD;GACtD,EAAkC,EAAE,YAAY,EAAQ,QAAQ,CAAC;GACjE,GAAI,EAAQ,cACN,CAAC,EACK,MAAM,kBAAkB;AACpB,WAAO,EACH,MAAM,cAAc;AAEhB,KADA,EAAQ,eAAe,EACvB,EAAI,KAAK,wCAAwC;OAExD;MAER,CAAC,GACJ,EAAE;GACX;EACD,GAAI,EAAQ,SAAS;GACjB,eAAe;GACf,mCAAmC;GACtC;EACJ,CAAC"}
1
+ {"version":3,"file":"apollo-server.util.js","names":[],"sources":["../../../src/node/apollo-server/apollo-server.util.ts"],"sourcesContent":["import { ApolloServer } from '@apollo/server';\nimport { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';\nimport {\n ApolloServerPluginLandingPageLocalDefault,\n ApolloServerPluginLandingPageProductionDefault,\n} from '@apollo/server/plugin/landingPage/default';\nimport { expressMiddleware } from '@as-integrations/express5';\nimport process from 'node:process';\n\nimport type { I_ApolloServerOptions } from './apollo-server.type.js';\n\nimport { log } from '../log/index.js';\n\n/**\n * Creates and configures an Apollo Server instance with appropriate plugins and settings.\n * This function sets up an Apollo Server with development or production landing pages,\n * HTTP server draining capabilities, and optional custom drain server hooks.\n *\n * The server is configured with:\n * - Development or production landing page based on the isDev flag\n * - HTTP server draining plugin for graceful shutdowns\n * - Optional custom drain server hook for additional cleanup\n * - Development-specific settings (introspection and stack traces) when isDev is true\n *\n * @param options - Configuration options for the Apollo Server including server instance, schema, and environment settings.\n * @returns A configured Apollo Server instance ready to be started.\n */\nexport function createApolloServer(options: I_ApolloServerOptions): ApolloServer {\n // Defense-in-depth: never enable dev features when NODE_ENV is 'production'\n const safeIsDev = options.isDev && process.env['NODE_ENV'] !== 'production';\n\n return new ApolloServer({\n schema: options.schema,\n plugins: [\n safeIsDev\n ? ApolloServerPluginLandingPageLocalDefault()\n : ApolloServerPluginLandingPageProductionDefault(),\n ApolloServerPluginDrainHttpServer({ httpServer: options.server }),\n ...(options.drainServer\n ? [{\n async serverWillStart() {\n return {\n async drainServer() {\n options.drainServer?.();\n log.info('Apollo Server drainServer hook called');\n },\n };\n },\n }]\n : []),\n ],\n ...(safeIsDev && {\n introspection: true,\n includeStacktraceInErrorResponses: true,\n }),\n });\n}\n\nexport { expressMiddleware };\n"],"mappings":";;;;;;;AA2BA,SAAgB,EAAmB,GAA8C;CAE7E,IAAM,IAAY,EAAQ,SAAS,EAAQ,IAAI,aAAgB;AAE/D,QAAO,IAAI,EAAa;EACpB,QAAQ,EAAQ;EAChB,SAAS;GACL,IACM,GAA2C,GAC3C,GAAgD;GACtD,EAAkC,EAAE,YAAY,EAAQ,QAAQ,CAAC;GACjE,GAAI,EAAQ,cACN,CAAC,EACK,MAAM,kBAAkB;AACpB,WAAO,EACH,MAAM,cAAc;AAEhB,KADA,EAAQ,eAAe,EACvB,EAAI,KAAK,wCAAwC;OAExD;MAER,CAAC,GACJ,EAAE;GACX;EACD,GAAI,KAAa;GACb,eAAe;GACf,mCAAmC;GACtC;EACJ,CAAC"}
@@ -8,41 +8,41 @@ import u from "node:process";
8
8
  import { exec as d, execFile as f } from "node:child_process";
9
9
  import * as p from "node:util";
10
10
  //#region src/node/command/command.util.ts
11
- var m = p.promisify(d), h = p.promisify(f), g = /[|&;<>`$(){}[\]!#~*?]/, _ = /^\s*(\d+):(\d+)\s+(error|warning)\s+(\S+(?:\s+\S+)*)\s+(\S+)$/, v = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS\d+:\s+(\S.+)$/, y = /^✖\s+(\S+(?:\s+\S+)*)\s+\[([^\]]*)\]$/, b = /\s+/;
12
- async function x() {
11
+ var m = p.promisify(d), h = p.promisify(f), g = /[|&;<>`$(){}[\]!#~*?]/, _ = /^\s*(\d+):(\d+)\s+(error|warning)\s+(\S+(?:\s+\S+)*)\s+(\S+)$/, v = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS\d+:\s+(\S.+)$/, y = /^✖\s+(\S+(?:\s+\S+)*)\s+\[([^\]]*)\]$/, b = /\s+/, x = null;
12
+ async function S() {
13
+ if (x) return x;
13
14
  let e = await i();
14
- return e.success ? e.result.name : Date.now().toString();
15
+ return e.success ? (x = e.result.name, x) : Date.now().toString();
15
16
  }
16
- async function S(e) {
17
+ async function C(e) {
17
18
  if (e.length === 0) return;
18
- let t = await x();
19
+ let t = await S();
19
20
  try {
20
- let n = [...await C(), ...e];
21
- await a.set(t, n), setTimeout(async () => {
22
- let e = await a.getLogLink(t);
23
- e && r.info(`📂 Open the error list manually: ${e}`);
24
- }, 0);
21
+ let n = [...await w(), ...e];
22
+ await a.set(t, n);
23
+ let i = await a.getLogLink(t);
24
+ i && r.info(`📂 Open the error list manually: ${i}`);
25
25
  } catch (e) {
26
26
  n(e);
27
27
  }
28
28
  }
29
- async function C() {
29
+ async function w() {
30
30
  try {
31
- let e = await x();
31
+ let e = await S();
32
32
  return await a.get(e) ?? [];
33
33
  } catch (e) {
34
34
  return n(e, { returnValue: [] });
35
35
  }
36
36
  }
37
- async function w() {
37
+ async function T() {
38
38
  try {
39
- let e = await x();
39
+ let e = await S();
40
40
  await a.remove(e);
41
41
  } catch (e) {
42
42
  n(e);
43
43
  }
44
44
  }
45
- async function T(e) {
45
+ async function E(e) {
46
46
  let n = [], i = [], a = "", o = _, s = v, c = y;
47
47
  e.split("\n").forEach((e) => {
48
48
  if (e.startsWith("/")) a = e.trim();
@@ -74,9 +74,9 @@ async function T(e) {
74
74
  }
75
75
  }
76
76
  }
77
- }), n.length && await S(n), i.length && (r.warn("Unmatched lines:"), i.forEach((e) => r.info(` ${e}`)));
77
+ }), n.length && await C(n), i.length && (r.warn("Unmatched lines:"), i.forEach((e) => r.info(` ${e}`)));
78
78
  }
79
- async function E(e) {
79
+ async function D(e) {
80
80
  try {
81
81
  let n = JSON.parse(e), r = [];
82
82
  n.forEach(({ filePath: e, messages: n }) => {
@@ -89,12 +89,12 @@ async function E(e) {
89
89
  message: s
90
90
  });
91
91
  });
92
- }), r.length && await S(r);
92
+ }), r.length && await C(r);
93
93
  } catch {
94
- await T(e);
94
+ await E(e);
95
95
  }
96
96
  }
97
- async function D(e, t = E, n = {}) {
97
+ async function O(e, t = D, n = {}) {
98
98
  let i = new AbortController(), a = () => {
99
99
  r.warn("Process interrupted. Terminating..."), i.abort(), u.exit(130);
100
100
  };
@@ -120,33 +120,33 @@ async function D(e, t = E, n = {}) {
120
120
  u.removeListener("SIGINT", a);
121
121
  }
122
122
  }
123
- function O(e) {
123
+ function k(e) {
124
124
  return {
125
125
  raw: !0,
126
126
  cmd: e
127
127
  };
128
128
  }
129
- function k(e, t) {
129
+ function A(e, t) {
130
130
  return t?.isCurrentProject ? `${l} tsx ${s} ${e}` : `${l} ${o} ${e}`;
131
131
  }
132
- function A(e, t) {
133
- return typeof e == "function" ? k(e(t), t) : typeof e == "object" && e?.raw === !0 ? e.cmd : typeof e == "string" ? k(e, t) : e;
132
+ function j(e, t) {
133
+ return typeof e == "function" ? A(e(t), t) : typeof e == "object" && e?.raw === !0 ? e.cmd : typeof e == "string" ? A(e, t) : e;
134
134
  }
135
- async function j(e) {
135
+ async function M(e) {
136
136
  let t = await i({ name: c });
137
137
  if (t.success) {
138
138
  let n = { isCurrentProject: t.result.isCurrentProject }, r = typeof e == "function" ? e(n) : e;
139
- return Object.fromEntries(Object.entries(r).map(([e, t]) => [e, A(t, n)]));
139
+ return Object.fromEntries(Object.entries(r).map(([e, t]) => [e, j(t, n)]));
140
140
  }
141
141
  }
142
- async function M(t, i, a = {}) {
142
+ async function N(t, i, a = {}) {
143
143
  let o;
144
144
  try {
145
145
  let n = Date.now();
146
146
  r.start(`${t}`), e().DEBUG ? r.info(`→ ${i}`) : o = setInterval(() => {
147
147
  let e = Math.floor((Date.now() - n) / 1e3);
148
148
  e > 0 && u.stdout.write(`\r⏳ ${t}... ${e}s`);
149
- }, 1e3), await D(i, E, a), r.success(`${t} done.`);
149
+ }, 1e3), await O(i, D, a), r.success(`${t} done.`);
150
150
  } catch (e) {
151
151
  if (a.throwOnError) throw e;
152
152
  n(e);
@@ -155,6 +155,6 @@ async function M(t, i, a = {}) {
155
155
  }
156
156
  }
157
157
  //#endregion
158
- export { w as clearAllErrorLists, A as formatCommand, C as getStoredErrorLists, O as rawCommand, j as resolveCommands, M as runCommand };
158
+ export { T as clearAllErrorLists, j as formatCommand, w as getStoredErrorLists, k as rawCommand, M as resolveCommands, N as runCommand };
159
159
 
160
160
  //# sourceMappingURL=command.util.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"command.util.js","names":[],"sources":["../../../src/node/command/command.util.ts"],"sourcesContent":["import { exec, execFile } from 'node:child_process';\nimport process from 'node:process';\nimport * as util from 'node:util';\n\nimport { getEnv } from '#config/env/index.js';\n\nimport type { I_IssueEntry } from '../log/index.js';\nimport type { I_CommandContext, I_EslintError, T_Command, T_CommandMapInput } from './command.type.js';\n\nimport { catchError, E_IssueType, log } from '../log/index.js';\nimport { getPackage } from '../package/index.js';\nimport { CYBERSKILL_CLI, CYBERSKILL_CLI_PATH, CYBERSKILL_PACKAGE_NAME, PNPM_EXEC_CLI, TSX_CLI } from '../path/index.js';\nimport { storage } from '../storage/index.js';\n\nconst execPromise = util.promisify(exec);\nconst execFilePromise = util.promisify(execFile);\nconst SHELL_METACHARACTERS = /[|&;<>`$(){}[\\]!#~*?]/;\nconst RE_ESLINT_ERROR = /^\\s*(\\d+):(\\d+)\\s+(error|warning)\\s+(\\S+(?:\\s+\\S+)*)\\s+(\\S+)$/;\nconst RE_TS_ERROR = /^(.+?)\\((\\d+),(\\d+)\\):\\s+(error|warning)\\s+TS\\d+:\\s+(\\S.+)$/;\nconst RE_COMMITLINT_ERROR = /^✖\\s+(\\S+(?:\\s+\\S+)*)\\s+\\[([^\\]]*)\\]$/;\nconst RE_WHITESPACE = /\\s+/;\n\n/**\n * Retrieves the package name for the current project.\n * This function attempts to get the package name from the current project's package.json.\n * If the package information cannot be retrieved, it returns a timestamp as a fallback.\n *\n * @returns A promise that resolves to the package name or a timestamp string.\n */\nasync function getPackageName() {\n const pkg = await getPackage();\n\n if (!pkg.success) {\n return Date.now().toString();\n }\n\n return pkg.result.name;\n}\n\n/**\n * Saves a list of error entries to persistent storage.\n * This function stores error information with the package name as the key,\n * and provides a log link for manual inspection of the stored errors.\n *\n * @param errorList - An array of error entries to be stored.\n * @returns A promise that resolves when the storage operation is complete.\n */\nasync function saveErrorListToStorage(errorList: I_IssueEntry[]): Promise<void> {\n if (errorList.length === 0) {\n return;\n }\n\n const packageName = await getPackageName();\n\n try {\n const existingErrors = await getStoredErrorLists();\n const mergedErrors = [...existingErrors, ...errorList];\n\n await storage.set(packageName, mergedErrors);\n\n setTimeout(async () => {\n const logPath = await storage.getLogLink(packageName);\n\n if (logPath) {\n log.info(`📂 Open the error list manually: ${logPath}`);\n }\n }, 0);\n }\n catch (error) {\n catchError(error);\n }\n}\n\n/**\n * Retrieves all stored error lists from persistent storage.\n * This function fetches error entries that were previously saved using the package name as the key.\n *\n * @returns A promise that resolves to an array of error entries, or an empty array if none are found.\n */\nexport async function getStoredErrorLists(): Promise<I_IssueEntry[]> {\n try {\n const packageName = await getPackageName();\n const allErrors = await storage.get<I_IssueEntry[]>(packageName);\n\n return allErrors ?? [];\n }\n catch (error) {\n return catchError<I_IssueEntry[]>(error, {\n returnValue: [],\n });\n }\n}\n\n/**\n * Clears all stored error lists from persistent storage.\n * This function removes all error entries associated with the current package name.\n *\n * @returns A promise that resolves when the clearing operation is complete.\n */\nexport async function clearAllErrorLists(): Promise<void> {\n try {\n const packageName = await getPackageName();\n await storage.remove(packageName);\n }\n catch (error) {\n catchError(error);\n }\n}\n\n/**\n * Parses text-based error output and converts it to structured error entries.\n * This function processes command output that contains error information in text format,\n * extracting file paths, line numbers, error types, messages, and rule violations.\n * It handles multiple error formats including ESLint, TypeScript, and commitlint errors.\n *\n * @param output - The raw text output from a command execution containing error information.\n */\nasync function parseTextErrors(output: string): Promise<void> {\n const errorList: I_IssueEntry[] = [];\n const unmatchedLines: string[] = [];\n let lastFilePath = '';\n const eslintErrorDetailsRegex = RE_ESLINT_ERROR;\n const tsRegex = RE_TS_ERROR;\n const commitlintRegex = RE_COMMITLINT_ERROR;\n\n output.split('\\n').forEach((line) => {\n if (line.startsWith('/')) {\n lastFilePath = line.trim();\n }\n else {\n const eslintMatch = eslintErrorDetailsRegex.exec(line);\n\n if (eslintMatch && lastFilePath) {\n errorList.push({\n file: lastFilePath,\n position: `${eslintMatch[1]}:${eslintMatch[2]}`,\n type: eslintMatch[3] === E_IssueType.Error ? E_IssueType.Error : E_IssueType.Warning,\n message: eslintMatch?.[4]?.trim() ?? '',\n rule: eslintMatch?.[5]?.trim() ?? '',\n });\n }\n else {\n const tsMatch = tsRegex.exec(line);\n\n if (tsMatch) {\n errorList.push({\n file: tsMatch?.[1] ?? '',\n position: `${tsMatch[2]}:${tsMatch[3]}`,\n type: tsMatch[4] === E_IssueType.Error ? E_IssueType.Error : E_IssueType.Warning,\n message: tsMatch?.[5]?.trim() ?? '',\n });\n }\n else {\n const commitlintMatch = commitlintRegex.exec(line);\n\n if (commitlintMatch) {\n errorList.push({\n file: 'commitlint',\n type: E_IssueType.Error,\n message: commitlintMatch?.[1]?.trim() ?? '',\n rule: commitlintMatch?.[2]?.trim() ?? '',\n });\n }\n else {\n unmatchedLines.push(line.trim());\n }\n }\n }\n }\n });\n\n if (errorList.length) {\n await saveErrorListToStorage(errorList);\n }\n\n if (unmatchedLines.length) {\n log.warn(`Unmatched lines:`);\n unmatchedLines.forEach(line => log.info(` ${line}`));\n }\n}\n\n/**\n * Parses command output that contains structured error information.\n * This function attempts to parse JSON-formatted error output (typically from ESLint)\n * and converts it to structured error entries. If JSON parsing fails, it falls back\n * to text-based parsing.\n *\n * @param output - The command output to parse, expected to be JSON-formatted error data.\n */\nasync function parseCommandOutput(output: string): Promise<void> {\n try {\n const results: I_EslintError[] = JSON.parse(output);\n const errorList: I_IssueEntry[] = [];\n\n results.forEach(({ filePath, messages }) => {\n messages.forEach(({ severity, line, column, ruleId, message }) => {\n errorList.push({\n type: severity === 2 ? E_IssueType.Error : E_IssueType.Warning,\n file: filePath,\n position: `${line}:${column}`,\n rule: ruleId,\n message,\n });\n });\n });\n\n if (errorList.length) {\n await saveErrorListToStorage(errorList);\n }\n }\n catch {\n await parseTextErrors(output);\n }\n}\n\n/**\n * Executes a command and processes its output for errors.\n * This function runs a command with proper signal handling for graceful termination,\n * processes both stdout and stderr for error information, and handles command failures.\n *\n * @param command - The command string to execute, or undefined if no command should be run.\n * @param parser - The function to use for parsing command output (defaults to parseCommandOutput).\n * @returns A promise that resolves when the command execution is complete.\n */\nasync function executeCommand(command: string | void, parser = parseCommandOutput, options: { timeout?: number } = {}): Promise<void> {\n const controller = new AbortController();\n\n const onSigint = () => {\n log.warn('Process interrupted. Terminating...');\n controller.abort();\n process.exit(130);\n };\n\n process.once('SIGINT', onSigint);\n\n try {\n if (typeof command === 'string') {\n const execOptions = {\n maxBuffer: 10 * 1024 * 1024,\n signal: controller.signal,\n timeout: options.timeout,\n };\n\n let result: { stdout: string; stderr: string };\n\n if (SHELL_METACHARACTERS.test(command)) {\n result = await execPromise(command, execOptions);\n }\n else {\n const parts = command.split(RE_WHITESPACE).filter(Boolean);\n result = await execFilePromise(parts[0]!, parts.slice(1), execOptions);\n }\n\n await Promise.all([result.stdout, result.stderr].map(output => output && parser(output)));\n }\n }\n catch (error) {\n const { stdout, stderr, message } = error as {\n stdout?: string;\n stderr?: string;\n message: string;\n };\n\n await Promise.all([stdout, stderr].map(output => output && parser(output)));\n\n if (!stderr && !stdout) {\n log.error(`Command failed: ${message}`);\n }\n\n throw error;\n }\n finally {\n process.removeListener('SIGINT', onSigint);\n }\n}\n\n/**\n * Creates a raw command object that bypasses CLI formatting.\n * This function wraps a command string in an object that indicates it should be executed\n * as-is without any additional CLI formatting or path resolution.\n *\n * @param cmd - The raw command string to be executed directly.\n * @returns An object containing the raw command with a flag indicating it should not be formatted.\n */\nexport function rawCommand(cmd: string) {\n return { raw: true, cmd };\n}\n\n/**\n * Formats a command for CLI execution based on the current project context.\n * This function determines whether to use the current project's CLI path or the global CLI,\n * and formats the command accordingly with the appropriate executable paths.\n *\n * @param command - The command string to format.\n * @param context - Optional context information about the current project.\n * @returns The formatted command string ready for execution.\n */\nfunction formatCLI(command: string, context?: I_CommandContext) {\n if (context?.isCurrentProject) {\n return `${PNPM_EXEC_CLI} ${TSX_CLI} ${CYBERSKILL_CLI_PATH} ${command}`;\n }\n\n return `${PNPM_EXEC_CLI} ${CYBERSKILL_CLI} ${command}`;\n}\n\n/**\n * Formats a command based on its type and context.\n * This function handles different command types:\n * - Function commands: Executes the function with context and formats the result\n * - Raw commands: Returns the command as-is without formatting\n * - String commands: Formats them as CLI commands\n *\n * @param command - The command to format, which can be a string, function, or raw command object.\n * @param context - Optional context information for command execution.\n * @returns The formatted command string ready for execution.\n */\nexport function formatCommand(command: T_Command, context?: I_CommandContext) {\n if (typeof command === 'function') {\n return formatCLI(command(context), context);\n }\n\n if (typeof command === 'object' && command?.raw === true) {\n return command.cmd;\n }\n\n if (typeof command === 'string') {\n return formatCLI(command, context);\n }\n\n return command;\n}\n\n/**\n * Resolves a map of commands by formatting them based on the current project context.\n * This function takes a command map (either static or dynamic) and formats all commands\n * using the appropriate CLI paths based on whether the current project is the Cyberskill package.\n *\n * @param input - The command map to resolve, which can be static or a function that returns a map.\n * @returns A promise that resolves to an object with formatted command strings, or undefined if package info cannot be retrieved.\n */\nexport async function resolveCommands(input: T_CommandMapInput) {\n const packageData = await getPackage({ name: CYBERSKILL_PACKAGE_NAME });\n\n if (packageData.success) {\n const ctx: I_CommandContext = { isCurrentProject: packageData.result.isCurrentProject };\n const commands = typeof input === 'function' ? input(ctx) : input;\n\n return Object.fromEntries(\n Object.entries(commands).map(([key, cmd]) => [key, formatCommand(cmd, ctx)]),\n );\n }\n}\n\n/**\n * Executes a command with proper logging and error handling.\n * This function provides a standardized way to run commands with:\n * - Progress logging with start and success messages\n * - Debug logging of the actual command when DEBUG mode is enabled\n * - Error handling and reporting\n *\n * @param label - A human-readable label describing what the command does.\n * @param command - The command string to execute, or undefined if no command should be run.\n * @returns A promise that resolves when the command execution is complete.\n */\nexport async function runCommand(label: string, command: string | void, options: { timeout?: number; throwOnError?: boolean } = {}) {\n let timer: NodeJS.Timeout | undefined;\n\n try {\n const startTime = Date.now();\n log.start(`${label}`);\n\n if (getEnv().DEBUG) {\n log.info(`→ ${command}`);\n }\n else {\n timer = setInterval(() => {\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n\n if (elapsed > 0) {\n process.stdout.write(`\\r⏳ ${label}... ${elapsed}s`);\n }\n }, 1000);\n }\n\n await executeCommand(command, parseCommandOutput, options);\n\n log.success(`${label} done.`);\n }\n catch (error) {\n if (options.throwOnError) {\n throw error;\n }\n catchError(error);\n }\n finally {\n if (timer) {\n clearInterval(timer);\n process.stdout.write(`\\r\\x1B[K`);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"command.util.js","names":[],"sources":["../../../src/node/command/command.util.ts"],"sourcesContent":["import { exec, execFile } from 'node:child_process';\nimport process from 'node:process';\nimport * as util from 'node:util';\n\nimport { getEnv } from '#config/env/index.js';\n\nimport type { I_IssueEntry } from '../log/index.js';\nimport type { I_CommandContext, I_EslintError, T_Command, T_CommandMapInput } from './command.type.js';\n\nimport { catchError, E_IssueType, log } from '../log/index.js';\nimport { getPackage } from '../package/index.js';\nimport { CYBERSKILL_CLI, CYBERSKILL_CLI_PATH, CYBERSKILL_PACKAGE_NAME, PNPM_EXEC_CLI, TSX_CLI } from '../path/index.js';\nimport { storage } from '../storage/index.js';\n\nconst execPromise = util.promisify(exec);\nconst execFilePromise = util.promisify(execFile);\nconst SHELL_METACHARACTERS = /[|&;<>`$(){}[\\]!#~*?]/;\nconst RE_ESLINT_ERROR = /^\\s*(\\d+):(\\d+)\\s+(error|warning)\\s+(\\S+(?:\\s+\\S+)*)\\s+(\\S+)$/;\nconst RE_TS_ERROR = /^(.+?)\\((\\d+),(\\d+)\\):\\s+(error|warning)\\s+TS\\d+:\\s+(\\S.+)$/;\nconst RE_COMMITLINT_ERROR = /^✖\\s+(\\S+(?:\\s+\\S+)*)\\s+\\[([^\\]]*)\\]$/;\nconst RE_WHITESPACE = /\\s+/;\n\n/**\n * Retrieves the package name for the current project.\n * This function attempts to get the package name from the current project's package.json.\n * If the package information cannot be retrieved, it returns a timestamp as a fallback.\n * Results are cached after first successful read to avoid redundant I/O.\n *\n * @returns A promise that resolves to the package name or a timestamp string.\n */\nlet _cachedPackageName: string | null = null;\n/** Returns the cached package name, falling back to a timestamp if unavailable. */\nasync function getPackageName() {\n if (_cachedPackageName) {\n return _cachedPackageName;\n }\n\n const pkg = await getPackage();\n\n if (!pkg.success) {\n return Date.now().toString();\n }\n\n _cachedPackageName = pkg.result.name;\n return _cachedPackageName;\n}\n\n/**\n * Saves a list of error entries to persistent storage.\n * This function stores error information with the package name as the key,\n * and provides a log link for manual inspection of the stored errors.\n *\n * @param errorList - An array of error entries to be stored.\n * @returns A promise that resolves when the storage operation is complete.\n */\nasync function saveErrorListToStorage(errorList: I_IssueEntry[]): Promise<void> {\n if (errorList.length === 0) {\n return;\n }\n\n const packageName = await getPackageName();\n\n try {\n const existingErrors = await getStoredErrorLists();\n const mergedErrors = [...existingErrors, ...errorList];\n\n await storage.set(packageName, mergedErrors);\n\n const logPath = await storage.getLogLink(packageName);\n if (logPath) {\n log.info(`📂 Open the error list manually: ${logPath}`);\n }\n }\n catch (error) {\n catchError(error);\n }\n}\n\n/**\n * Retrieves all stored error lists from persistent storage.\n * This function fetches error entries that were previously saved using the package name as the key.\n *\n * @returns A promise that resolves to an array of error entries, or an empty array if none are found.\n */\nexport async function getStoredErrorLists(): Promise<I_IssueEntry[]> {\n try {\n const packageName = await getPackageName();\n const allErrors = await storage.get<I_IssueEntry[]>(packageName);\n\n return allErrors ?? [];\n }\n catch (error) {\n return catchError<I_IssueEntry[]>(error, {\n returnValue: [],\n });\n }\n}\n\n/**\n * Clears all stored error lists from persistent storage.\n * This function removes all error entries associated with the current package name.\n *\n * @returns A promise that resolves when the clearing operation is complete.\n */\nexport async function clearAllErrorLists(): Promise<void> {\n try {\n const packageName = await getPackageName();\n await storage.remove(packageName);\n }\n catch (error) {\n catchError(error);\n }\n}\n\n/**\n * Parses text-based error output and converts it to structured error entries.\n * This function processes command output that contains error information in text format,\n * extracting file paths, line numbers, error types, messages, and rule violations.\n * It handles multiple error formats including ESLint, TypeScript, and commitlint errors.\n *\n * @param output - The raw text output from a command execution containing error information.\n */\nasync function parseTextErrors(output: string): Promise<void> {\n const errorList: I_IssueEntry[] = [];\n const unmatchedLines: string[] = [];\n let lastFilePath = '';\n const eslintErrorDetailsRegex = RE_ESLINT_ERROR;\n const tsRegex = RE_TS_ERROR;\n const commitlintRegex = RE_COMMITLINT_ERROR;\n\n output.split('\\n').forEach((line) => {\n if (line.startsWith('/')) {\n lastFilePath = line.trim();\n }\n else {\n const eslintMatch = eslintErrorDetailsRegex.exec(line);\n\n if (eslintMatch && lastFilePath) {\n errorList.push({\n file: lastFilePath,\n position: `${eslintMatch[1]}:${eslintMatch[2]}`,\n type: eslintMatch[3] === E_IssueType.Error ? E_IssueType.Error : E_IssueType.Warning,\n message: eslintMatch?.[4]?.trim() ?? '',\n rule: eslintMatch?.[5]?.trim() ?? '',\n });\n }\n else {\n const tsMatch = tsRegex.exec(line);\n\n if (tsMatch) {\n errorList.push({\n file: tsMatch?.[1] ?? '',\n position: `${tsMatch[2]}:${tsMatch[3]}`,\n type: tsMatch[4] === E_IssueType.Error ? E_IssueType.Error : E_IssueType.Warning,\n message: tsMatch?.[5]?.trim() ?? '',\n });\n }\n else {\n const commitlintMatch = commitlintRegex.exec(line);\n\n if (commitlintMatch) {\n errorList.push({\n file: 'commitlint',\n type: E_IssueType.Error,\n message: commitlintMatch?.[1]?.trim() ?? '',\n rule: commitlintMatch?.[2]?.trim() ?? '',\n });\n }\n else {\n unmatchedLines.push(line.trim());\n }\n }\n }\n }\n });\n\n if (errorList.length) {\n await saveErrorListToStorage(errorList);\n }\n\n if (unmatchedLines.length) {\n log.warn(`Unmatched lines:`);\n unmatchedLines.forEach(line => log.info(` ${line}`));\n }\n}\n\n/**\n * Parses command output that contains structured error information.\n * This function attempts to parse JSON-formatted error output (typically from ESLint)\n * and converts it to structured error entries. If JSON parsing fails, it falls back\n * to text-based parsing.\n *\n * @param output - The command output to parse, expected to be JSON-formatted error data.\n */\nasync function parseCommandOutput(output: string): Promise<void> {\n try {\n const results: I_EslintError[] = JSON.parse(output);\n const errorList: I_IssueEntry[] = [];\n\n results.forEach(({ filePath, messages }) => {\n messages.forEach(({ severity, line, column, ruleId, message }) => {\n errorList.push({\n type: severity === 2 ? E_IssueType.Error : E_IssueType.Warning,\n file: filePath,\n position: `${line}:${column}`,\n rule: ruleId,\n message,\n });\n });\n });\n\n if (errorList.length) {\n await saveErrorListToStorage(errorList);\n }\n }\n catch {\n await parseTextErrors(output);\n }\n}\n\n/**\n * Executes a command and processes its output for errors.\n * This function runs a command with proper signal handling for graceful termination,\n * processes both stdout and stderr for error information, and handles command failures.\n *\n * @param command - The command string to execute, or undefined if no command should be run.\n * @param parser - The function to use for parsing command output (defaults to parseCommandOutput).\n * @returns A promise that resolves when the command execution is complete.\n */\nasync function executeCommand(command: string | void, parser = parseCommandOutput, options: { timeout?: number } = {}): Promise<void> {\n const controller = new AbortController();\n\n const onSigint = () => {\n log.warn('Process interrupted. Terminating...');\n controller.abort();\n process.exit(130);\n };\n\n process.once('SIGINT', onSigint);\n\n try {\n if (typeof command === 'string') {\n const execOptions = {\n maxBuffer: 10 * 1024 * 1024,\n signal: controller.signal,\n timeout: options.timeout,\n };\n\n let result: { stdout: string; stderr: string };\n\n if (SHELL_METACHARACTERS.test(command)) {\n result = await execPromise(command, execOptions);\n }\n else {\n const parts = command.split(RE_WHITESPACE).filter(Boolean);\n result = await execFilePromise(parts[0]!, parts.slice(1), execOptions);\n }\n\n await Promise.all([result.stdout, result.stderr].map(output => output && parser(output)));\n }\n }\n catch (error) {\n const { stdout, stderr, message } = error as {\n stdout?: string;\n stderr?: string;\n message: string;\n };\n\n await Promise.all([stdout, stderr].map(output => output && parser(output)));\n\n if (!stderr && !stdout) {\n log.error(`Command failed: ${message}`);\n }\n\n throw error;\n }\n finally {\n process.removeListener('SIGINT', onSigint);\n }\n}\n\n/**\n * Creates a raw command object that bypasses CLI formatting.\n * This function wraps a command string in an object that indicates it should be executed\n * as-is without any additional CLI formatting or path resolution.\n *\n * @param cmd - The raw command string to be executed directly.\n * @returns An object containing the raw command with a flag indicating it should not be formatted.\n */\nexport function rawCommand(cmd: string) {\n return { raw: true, cmd };\n}\n\n/**\n * Formats a command for CLI execution based on the current project context.\n * This function determines whether to use the current project's CLI path or the global CLI,\n * and formats the command accordingly with the appropriate executable paths.\n *\n * @param command - The command string to format.\n * @param context - Optional context information about the current project.\n * @returns The formatted command string ready for execution.\n */\nfunction formatCLI(command: string, context?: I_CommandContext) {\n if (context?.isCurrentProject) {\n return `${PNPM_EXEC_CLI} ${TSX_CLI} ${CYBERSKILL_CLI_PATH} ${command}`;\n }\n\n return `${PNPM_EXEC_CLI} ${CYBERSKILL_CLI} ${command}`;\n}\n\n/**\n * Formats a command based on its type and context.\n * This function handles different command types:\n * - Function commands: Executes the function with context and formats the result\n * - Raw commands: Returns the command as-is without formatting\n * - String commands: Formats them as CLI commands\n *\n * @param command - The command to format, which can be a string, function, or raw command object.\n * @param context - Optional context information for command execution.\n * @returns The formatted command string ready for execution.\n */\nexport function formatCommand(command: T_Command, context?: I_CommandContext) {\n if (typeof command === 'function') {\n return formatCLI(command(context), context);\n }\n\n if (typeof command === 'object' && command?.raw === true) {\n return command.cmd;\n }\n\n if (typeof command === 'string') {\n return formatCLI(command, context);\n }\n\n return command;\n}\n\n/**\n * Resolves a map of commands by formatting them based on the current project context.\n * This function takes a command map (either static or dynamic) and formats all commands\n * using the appropriate CLI paths based on whether the current project is the Cyberskill package.\n *\n * @param input - The command map to resolve, which can be static or a function that returns a map.\n * @returns A promise that resolves to an object with formatted command strings, or undefined if package info cannot be retrieved.\n */\nexport async function resolveCommands(input: T_CommandMapInput) {\n const packageData = await getPackage({ name: CYBERSKILL_PACKAGE_NAME });\n\n if (packageData.success) {\n const ctx: I_CommandContext = { isCurrentProject: packageData.result.isCurrentProject };\n const commands = typeof input === 'function' ? input(ctx) : input;\n\n return Object.fromEntries(\n Object.entries(commands).map(([key, cmd]) => [key, formatCommand(cmd, ctx)]),\n );\n }\n}\n\n/**\n * Executes a command with proper logging and error handling.\n * This function provides a standardized way to run commands with:\n * - Progress logging with start and success messages\n * - Debug logging of the actual command when DEBUG mode is enabled\n * - Error handling and reporting\n *\n * @param label - A human-readable label describing what the command does.\n * @param command - The command string to execute, or undefined if no command should be run.\n * @returns A promise that resolves when the command execution is complete.\n */\nexport async function runCommand(label: string, command: string | void, options: { timeout?: number; throwOnError?: boolean } = {}) {\n let timer: NodeJS.Timeout | undefined;\n\n try {\n const startTime = Date.now();\n log.start(`${label}`);\n\n if (getEnv().DEBUG) {\n log.info(`→ ${command}`);\n }\n else {\n timer = setInterval(() => {\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n\n if (elapsed > 0) {\n process.stdout.write(`\\r⏳ ${label}... ${elapsed}s`);\n }\n }, 1000);\n }\n\n await executeCommand(command, parseCommandOutput, options);\n\n log.success(`${label} done.`);\n }\n catch (error) {\n if (options.throwOnError) {\n throw error;\n }\n catchError(error);\n }\n finally {\n if (timer) {\n clearInterval(timer);\n process.stdout.write(`\\r\\x1B[K`);\n }\n }\n}\n"],"mappings":"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"}
@@ -47,6 +47,10 @@ export declare function createSession(options: SessionOptions): RequestHandler;
47
47
  * - Static file serving for specified folders
48
48
  * - GraphQL upload support for file uploads
49
49
  *
50
+ * @remarks
51
+ * **Requires Express 5.x** — This module uses Express 5 APIs and is not compatible with Express 4.
52
+ * The peer dependency requires `express >= 5.0.0`.
53
+ *
50
54
  * @param options - Optional configuration for the Express application including static folder paths.
51
55
  * @returns A configured Express application instance ready for use.
52
56
  */
@@ -11,17 +11,17 @@ import { express as l } from "express-useragent";
11
11
  import u from "graphql-upload/graphqlUploadExpress.mjs";
12
12
  import d from "helmet";
13
13
  //#region src/node/express/express.util.ts
14
- function f({ isDev: e, whiteList: t, ...n }) {
15
- return {
16
- origin: (n, r) => {
17
- if (e && !n) {
14
+ function f({ isDev: t, whiteList: n, ...r }) {
15
+ return t && e.env.NODE_ENV === "production" && console.warn("[CORS] WARNING: isDev is true but NODE_ENV is \"production\". CORS restrictions are relaxed. This is likely a misconfiguration."), {
16
+ origin: (e, r) => {
17
+ if (t && !e) {
18
18
  r(null, !0);
19
19
  return;
20
20
  }
21
- n && t?.includes(n) ? r(null, !0) : r(/* @__PURE__ */ Error("Not allowed by CORS"), !1);
21
+ e && n?.includes(e) ? r(null, !0) : r(/* @__PURE__ */ Error("Not allowed by CORS"), !1);
22
22
  },
23
23
  credentials: !0,
24
- ...n
24
+ ...r
25
25
  };
26
26
  }
27
27
  function p(e) {
@@ -29,6 +29,7 @@ function p(e) {
29
29
  }
30
30
  function m(t) {
31
31
  if (!t.secret) throw Error("Session secret is required. Provide a strong secret string.");
32
+ !t.store && e.env.NODE_ENV === "production" && console.warn("[Session] WARNING: No session store configured in production. The default MemoryStore leaks memory and loses sessions on restart. Use connect-redis, connect-mongo, or another production store.");
32
33
  let n = {
33
34
  resave: !1,
34
35
  saveUninitialized: !1,
@@ -1 +1 @@
1
- {"version":3,"file":"express.util.js","names":[],"sources":["../../../src/node/express/express.util.ts"],"sourcesContent":["import type { INestApplication } from '@nestjs/common';\nimport type { Application, RequestHandler } from 'express';\nimport type { SessionOptions } from 'express-session';\n\nimport { NestFactory } from '@nestjs/core';\nimport bodyParser from 'body-parser';\nimport compression from 'compression';\nimport cookieParser from 'cookie-parser';\nimport cors from 'cors';\nimport express from 'express';\nimport rateLimit from 'express-rate-limit';\nimport session from 'express-session';\nimport { express as useragent } from 'express-useragent';\nimport graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';\nimport helmet from 'helmet';\nimport process from 'node:process';\n\nimport type { I_ExpressOptions, I_NestOptions, T_CorsOptions, T_CorsType } from './express.type.js';\n\n/**\n * Creates CORS options with environment-specific configuration.\n * This function generates CORS options based on the development environment,\n * including whitelist configuration for allowed origins.\n *\n * @param options - CORS configuration options.\n * @param options.isDev - Whether the application is running in development mode.\n * @param options.whiteList - Array of allowed origins for CORS requests.\n * @returns CORS options object configured for the specified environment.\n */\nexport function createCorsOptions<T extends T_CorsType>({ isDev, whiteList, ...rest }: T_CorsOptions<T>) {\n return {\n origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {\n // Allow requests without Origin header only in development mode.\n // In production, undefined origin (e.g., curl, server-to-server) is rejected.\n if (isDev && !origin) {\n callback(null, true);\n return;\n }\n\n if (origin && whiteList?.includes(origin)) {\n callback(null, true);\n }\n else {\n callback(new Error('Not allowed by CORS'), false);\n }\n },\n credentials: true,\n ...rest,\n };\n}\n\n/**\n * Creates a CORS middleware function with the specified configuration.\n * This function creates a CORS middleware that can be used with both Express and NestJS applications,\n * applying the configured CORS options for origin validation and credential handling.\n *\n * @param options - CORS configuration options to apply to the middleware.\n * @returns A CORS middleware function ready to be used in Express or NestJS applications.\n */\nexport function createCors<T extends T_CorsType>(options: T_CorsOptions<T>) {\n return cors<cors.CorsRequest>(createCorsOptions(options));\n}\n\n/**\n * Creates a session middleware function with the specified configuration.\n * This function creates an Express session middleware that can be used to handle user sessions\n * with the provided session options including secret, cookie settings, and storage configuration.\n *\n * @param options - Session configuration options including secret, cookie settings, and storage.\n * @returns A session middleware function ready to be used in Express applications.\n */\nexport function createSession(options: SessionOptions): RequestHandler {\n if (!options.secret) {\n throw new Error('Session secret is required. Provide a strong secret string.');\n }\n\n const secureDefaults: Partial<SessionOptions> = {\n resave: false,\n saveUninitialized: false,\n cookie: {\n httpOnly: true,\n sameSite: 'lax',\n secure: process.env['NODE_ENV'] === 'production',\n maxAge: 24 * 60 * 60 * 1000, // 24 hours\n },\n };\n\n return session({\n ...secureDefaults,\n ...options,\n cookie: { ...secureDefaults.cookie, ...options.cookie },\n });\n}\n\n/**\n * Sets up common middleware for Express applications.\n * This function configures essential middleware including:\n * - Trust proxy settings for proper IP handling\n * - Cookie parsing for request cookies\n * - URL-encoded body parsing for form data\n * - Compression for response optimization\n * - User agent parsing for device/browser detection\n *\n * @param app - The Express application instance to configure with middleware.\n * @param isDev - Whether the application is running in development mode.\n * @param jsonLimit - Maximum request body size for JSON payloads.\n * @param trustProxy - Trust proxy setting; pass a truthy value to enable.\n * @param rateLimitOptions - Rate limit configuration, or `false` to disable.\n */\nfunction setupMiddleware(\n app: Application,\n isDev = false,\n jsonLimit = '1mb',\n trustProxy: boolean | number | string | string[] = false,\n rateLimitOptions: false | import('./express.type.js').I_RateLimitOptions = {},\n) {\n if (trustProxy !== false) {\n app.set('trust proxy', trustProxy);\n }\n app.use(\n helmet({\n crossOriginEmbedderPolicy: isDev ? false : undefined,\n contentSecurityPolicy: isDev ? false : undefined,\n }),\n );\n if (rateLimitOptions !== false) {\n app.use(\n rateLimit({\n windowMs: rateLimitOptions.windowMs ?? 15 * 60 * 1000,\n limit: rateLimitOptions.limit ?? 1000,\n standardHeaders: true,\n legacyHeaders: false,\n ...(rateLimitOptions.store !== undefined && { store: rateLimitOptions.store }),\n ...(rateLimitOptions.skip !== undefined && { skip: rateLimitOptions.skip }),\n }),\n );\n }\n app.use(cookieParser());\n app.use(express.json({ limit: jsonLimit }));\n app.use(express.urlencoded({ extended: true, limit: jsonLimit }));\n app.use(compression());\n app.use(useragent());\n}\n\n/**\n * Sets up static file serving for Express applications.\n * This function configures static file serving for the specified folders,\n * making files in those directories accessible via HTTP requests.\n *\n * @param app - The Express application instance to configure with static file serving.\n * @param staticFolders - A string or array of strings representing the paths to serve statically.\n */\nfunction setupStaticFolders(app: Application, staticFolders?: string | string[]) {\n if (staticFolders) {\n const statics = Array.isArray(staticFolders) ? staticFolders : [staticFolders];\n statics.forEach((folder) => {\n app.use(`/${folder}`, express.static(folder));\n });\n }\n}\n\n/**\n * Creates and configures an Express application with common middleware and settings.\n * This function sets up a complete Express application with:\n * - Essential middleware (cookies, body parsing, compression, user agent)\n * - Static file serving for specified folders\n * - GraphQL upload support for file uploads\n *\n * @param options - Optional configuration for the Express application including static folder paths.\n * @returns A configured Express application instance ready for use.\n */\nexport function createExpress(options?: I_ExpressOptions): Application {\n const app = express();\n\n setupMiddleware(app, options?.isDev, options?.jsonLimit, options?.trustProxy, options?.rateLimit);\n setupStaticFolders(app, options?.static);\n const uploadMiddleware = graphqlUploadExpress({\n maxFileSize: options?.maxFileSize ?? 10_000_000,\n maxFiles: options?.maxFiles ?? 10,\n });\n app.use(options?.uploadPath ?? '/graphql', uploadMiddleware);\n\n return app;\n}\n\n/**\n * Creates and configures a NestJS application with Express integration.\n * This function sets up a NestJS application with:\n * - Express HTTP adapter configuration\n * - Common middleware (cookies, body parsing, compression, user agent)\n * - Static file serving for specified folders\n * - Global filters and pipes if provided\n *\n * @param options - Configuration options for the NestJS application including module, static folders, filters, and pipes.\n * @returns A promise that resolves to a configured NestJS application instance.\n */\nexport async function createNest(options: I_NestOptions): Promise<INestApplication> {\n const app = await NestFactory.create(options.module);\n\n setupMiddleware(app.getHttpAdapter().getInstance(), options.isDev, options.jsonLimit, options.trustProxy, options.rateLimit);\n setupStaticFolders(app.getHttpAdapter().getInstance(), options.static);\n\n if (options.filters) {\n app.useGlobalFilters(...options.filters);\n }\n\n if (options.pipes) {\n app.useGlobalPipes(...options.pipes);\n }\n\n return app;\n}\n\nexport { bodyParser, express };\n"],"mappings":";;;;;;;;;;;;;AA6BA,SAAgB,EAAwC,EAAE,UAAO,cAAW,GAAG,KAA0B;AACrG,QAAO;EACH,SAAS,GAA4B,MAA2D;AAG5F,OAAI,KAAS,CAAC,GAAQ;AAClB,MAAS,MAAM,GAAK;AACpB;;AAGJ,GAAI,KAAU,GAAW,SAAS,EAAO,GACrC,EAAS,MAAM,GAAK,GAGpB,EAAS,gBAAI,MAAM,sBAAsB,EAAE,GAAM;;EAGzD,aAAa;EACb,GAAG;EACN;;AAWL,SAAgB,EAAiC,GAA2B;AACxE,QAAO,EAAuB,EAAkB,EAAQ,CAAC;;AAW7D,SAAgB,EAAc,GAAyC;AACnE,KAAI,CAAC,EAAQ,OACT,OAAU,MAAM,8DAA8D;CAGlF,IAAM,IAA0C;EAC5C,QAAQ;EACR,mBAAmB;EACnB,QAAQ;GACJ,UAAU;GACV,UAAU;GACV,QAAQ,EAAQ,IAAI,aAAgB;GACpC,QAAQ,OAAU,KAAK;GAC1B;EACJ;AAED,QAAO,EAAQ;EACX,GAAG;EACH,GAAG;EACH,QAAQ;GAAE,GAAG,EAAe;GAAQ,GAAG,EAAQ;GAAQ;EAC1D,CAAC;;AAkBN,SAAS,EACL,GACA,IAAQ,IACR,IAAY,OACZ,IAAmD,IACnD,IAA2E,EAAE,EAC/E;AA0BE,CAzBI,MAAe,MACf,EAAI,IAAI,eAAe,EAAW,EAEtC,EAAI,IACA,EAAO;EACH,2BAA2B,IAAQ,KAAQ,KAAA;EAC3C,uBAAuB,IAAQ,KAAQ,KAAA;EAC1C,CAAC,CACL,EACG,MAAqB,MACrB,EAAI,IACA,EAAU;EACN,UAAU,EAAiB,YAAY,MAAU;EACjD,OAAO,EAAiB,SAAS;EACjC,iBAAiB;EACjB,eAAe;EACf,GAAI,EAAiB,UAAU,KAAA,KAAa,EAAE,OAAO,EAAiB,OAAO;EAC7E,GAAI,EAAiB,SAAS,KAAA,KAAa,EAAE,MAAM,EAAiB,MAAM;EAC7E,CAAC,CACL,EAEL,EAAI,IAAI,GAAc,CAAC,EACvB,EAAI,IAAI,EAAQ,KAAK,EAAE,OAAO,GAAW,CAAC,CAAC,EAC3C,EAAI,IAAI,EAAQ,WAAW;EAAE,UAAU;EAAM,OAAO;EAAW,CAAC,CAAC,EACjE,EAAI,IAAI,GAAa,CAAC,EACtB,EAAI,IAAI,GAAW,CAAC;;AAWxB,SAAS,EAAmB,GAAkB,GAAmC;AAC7E,CAAI,MACgB,MAAM,QAAQ,EAAc,GAAG,IAAgB,CAAC,EAAc,EACtE,SAAS,MAAW;AACxB,IAAI,IAAI,IAAI,KAAU,EAAQ,OAAO,EAAO,CAAC;GAC/C;;AAcV,SAAgB,EAAc,GAAyC;CACnE,IAAM,IAAM,GAAS;AAGrB,CADA,EAAgB,GAAK,GAAS,OAAO,GAAS,WAAW,GAAS,YAAY,GAAS,UAAU,EACjG,EAAmB,GAAK,GAAS,OAAO;CACxC,IAAM,IAAmB,EAAqB;EAC1C,aAAa,GAAS,eAAe;EACrC,UAAU,GAAS,YAAY;EAClC,CAAC;AAGF,QAFA,EAAI,IAAI,GAAS,cAAc,YAAY,EAAiB,EAErD;;AAcX,eAAsB,EAAW,GAAmD;CAChF,IAAM,IAAM,MAAM,EAAY,OAAO,EAAQ,OAAO;AAapD,QAXA,EAAgB,EAAI,gBAAgB,CAAC,aAAa,EAAE,EAAQ,OAAO,EAAQ,WAAW,EAAQ,YAAY,EAAQ,UAAU,EAC5H,EAAmB,EAAI,gBAAgB,CAAC,aAAa,EAAE,EAAQ,OAAO,EAElE,EAAQ,WACR,EAAI,iBAAiB,GAAG,EAAQ,QAAQ,EAGxC,EAAQ,SACR,EAAI,eAAe,GAAG,EAAQ,MAAM,EAGjC"}
1
+ {"version":3,"file":"express.util.js","names":[],"sources":["../../../src/node/express/express.util.ts"],"sourcesContent":["import type { INestApplication } from '@nestjs/common';\nimport type { Application, RequestHandler } from 'express';\nimport type { SessionOptions } from 'express-session';\n\nimport { NestFactory } from '@nestjs/core';\nimport bodyParser from 'body-parser';\nimport compression from 'compression';\nimport cookieParser from 'cookie-parser';\nimport cors from 'cors';\nimport express from 'express';\nimport rateLimit from 'express-rate-limit';\nimport session from 'express-session';\nimport { express as useragent } from 'express-useragent';\nimport graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';\nimport helmet from 'helmet';\nimport process from 'node:process';\n\nimport type { I_ExpressOptions, I_NestOptions, T_CorsOptions, T_CorsType } from './express.type.js';\n\n/**\n * Creates CORS options with environment-specific configuration.\n * This function generates CORS options based on the development environment,\n * including whitelist configuration for allowed origins.\n *\n * @param options - CORS configuration options.\n * @param options.isDev - Whether the application is running in development mode.\n * @param options.whiteList - Array of allowed origins for CORS requests.\n * @returns CORS options object configured for the specified environment.\n */\nexport function createCorsOptions<T extends T_CorsType>({ isDev, whiteList, ...rest }: T_CorsOptions<T>) {\n // Safety net: warn loudly if isDev is mistakenly true in production\n if (isDev && process.env['NODE_ENV'] === 'production') {\n console.warn('[CORS] WARNING: isDev is true but NODE_ENV is \"production\". CORS restrictions are relaxed. This is likely a misconfiguration.');\n }\n\n return {\n origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {\n // Allow requests without Origin header only in development mode.\n // In production, undefined origin (e.g., curl, server-to-server) is rejected.\n if (isDev && !origin) {\n callback(null, true);\n return;\n }\n\n if (origin && whiteList?.includes(origin)) {\n callback(null, true);\n }\n else {\n callback(new Error('Not allowed by CORS'), false);\n }\n },\n credentials: true,\n ...rest,\n };\n}\n\n/**\n * Creates a CORS middleware function with the specified configuration.\n * This function creates a CORS middleware that can be used with both Express and NestJS applications,\n * applying the configured CORS options for origin validation and credential handling.\n *\n * @param options - CORS configuration options to apply to the middleware.\n * @returns A CORS middleware function ready to be used in Express or NestJS applications.\n */\nexport function createCors<T extends T_CorsType>(options: T_CorsOptions<T>) {\n return cors<cors.CorsRequest>(createCorsOptions(options));\n}\n\n/**\n * Creates a session middleware function with the specified configuration.\n * This function creates an Express session middleware that can be used to handle user sessions\n * with the provided session options including secret, cookie settings, and storage configuration.\n *\n * @param options - Session configuration options including secret, cookie settings, and storage.\n * @returns A session middleware function ready to be used in Express applications.\n */\nexport function createSession(options: SessionOptions): RequestHandler {\n if (!options.secret) {\n throw new Error('Session secret is required. Provide a strong secret string.');\n }\n\n if (!options.store && process.env['NODE_ENV'] === 'production') {\n console.warn('[Session] WARNING: No session store configured in production. The default MemoryStore leaks memory and loses sessions on restart. Use connect-redis, connect-mongo, or another production store.');\n }\n\n const secureDefaults: Partial<SessionOptions> = {\n resave: false,\n saveUninitialized: false,\n cookie: {\n httpOnly: true,\n sameSite: 'lax',\n secure: process.env['NODE_ENV'] === 'production',\n maxAge: 24 * 60 * 60 * 1000, // 24 hours\n },\n };\n\n return session({\n ...secureDefaults,\n ...options,\n cookie: { ...secureDefaults.cookie, ...options.cookie },\n });\n}\n\n/**\n * Sets up common middleware for Express applications.\n * This function configures essential middleware including:\n * - Trust proxy settings for proper IP handling\n * - Cookie parsing for request cookies\n * - URL-encoded body parsing for form data\n * - Compression for response optimization\n * - User agent parsing for device/browser detection\n *\n * @param app - The Express application instance to configure with middleware.\n * @param isDev - Whether the application is running in development mode.\n * @param jsonLimit - Maximum request body size for JSON payloads.\n * @param trustProxy - Trust proxy setting; pass a truthy value to enable.\n * @param rateLimitOptions - Rate limit configuration, or `false` to disable.\n */\nfunction setupMiddleware(\n app: Application,\n isDev = false,\n jsonLimit = '1mb',\n trustProxy: boolean | number | string | string[] = false,\n rateLimitOptions: false | import('./express.type.js').I_RateLimitOptions = {},\n) {\n if (trustProxy !== false) {\n app.set('trust proxy', trustProxy);\n }\n app.use(\n helmet({\n crossOriginEmbedderPolicy: isDev ? false : undefined,\n contentSecurityPolicy: isDev ? false : undefined,\n }),\n );\n if (rateLimitOptions !== false) {\n app.use(\n rateLimit({\n windowMs: rateLimitOptions.windowMs ?? 15 * 60 * 1000,\n limit: rateLimitOptions.limit ?? 1000,\n standardHeaders: true,\n legacyHeaders: false,\n ...(rateLimitOptions.store !== undefined && { store: rateLimitOptions.store }),\n ...(rateLimitOptions.skip !== undefined && { skip: rateLimitOptions.skip }),\n }),\n );\n }\n app.use(cookieParser());\n app.use(express.json({ limit: jsonLimit }));\n app.use(express.urlencoded({ extended: true, limit: jsonLimit }));\n app.use(compression());\n app.use(useragent());\n}\n\n/**\n * Sets up static file serving for Express applications.\n * This function configures static file serving for the specified folders,\n * making files in those directories accessible via HTTP requests.\n *\n * @param app - The Express application instance to configure with static file serving.\n * @param staticFolders - A string or array of strings representing the paths to serve statically.\n */\nfunction setupStaticFolders(app: Application, staticFolders?: string | string[]) {\n if (staticFolders) {\n const statics = Array.isArray(staticFolders) ? staticFolders : [staticFolders];\n statics.forEach((folder) => {\n app.use(`/${folder}`, express.static(folder));\n });\n }\n}\n\n/**\n * Creates and configures an Express application with common middleware and settings.\n * This function sets up a complete Express application with:\n * - Essential middleware (cookies, body parsing, compression, user agent)\n * - Static file serving for specified folders\n * - GraphQL upload support for file uploads\n *\n * @remarks\n * **Requires Express 5.x** — This module uses Express 5 APIs and is not compatible with Express 4.\n * The peer dependency requires `express >= 5.0.0`.\n *\n * @param options - Optional configuration for the Express application including static folder paths.\n * @returns A configured Express application instance ready for use.\n */\nexport function createExpress(options?: I_ExpressOptions): Application {\n const app = express();\n\n setupMiddleware(app, options?.isDev, options?.jsonLimit, options?.trustProxy, options?.rateLimit);\n setupStaticFolders(app, options?.static);\n const uploadMiddleware = graphqlUploadExpress({\n maxFileSize: options?.maxFileSize ?? 10_000_000,\n maxFiles: options?.maxFiles ?? 10,\n });\n app.use(options?.uploadPath ?? '/graphql', uploadMiddleware);\n\n return app;\n}\n\n/**\n * Creates and configures a NestJS application with Express integration.\n * This function sets up a NestJS application with:\n * - Express HTTP adapter configuration\n * - Common middleware (cookies, body parsing, compression, user agent)\n * - Static file serving for specified folders\n * - Global filters and pipes if provided\n *\n * @param options - Configuration options for the NestJS application including module, static folders, filters, and pipes.\n * @returns A promise that resolves to a configured NestJS application instance.\n */\nexport async function createNest(options: I_NestOptions): Promise<INestApplication> {\n const app = await NestFactory.create(options.module);\n\n setupMiddleware(app.getHttpAdapter().getInstance(), options.isDev, options.jsonLimit, options.trustProxy, options.rateLimit);\n setupStaticFolders(app.getHttpAdapter().getInstance(), options.static);\n\n if (options.filters) {\n app.useGlobalFilters(...options.filters);\n }\n\n if (options.pipes) {\n app.useGlobalPipes(...options.pipes);\n }\n\n return app;\n}\n\nexport { bodyParser, express };\n"],"mappings":"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"}
@@ -13,7 +13,7 @@ export declare class MongooseController<T extends Partial<C_Document>> {
13
13
  *
14
14
  * @param model - The Mongoose model to operate on.
15
15
  * @param options - Optional configuration for the controller.
16
- * @param options.defaultLimit - Maximum documents returned by findAll when no limit is specified (default: 10,000).
16
+ * @param options.defaultLimit - Maximum documents returned by findAll when no limit is specified (default: 1,000).
17
17
  */
18
18
  constructor(model: I_ExtendedModel<T>, options?: {
19
19
  defaultLimit?: number;
@@ -46,6 +46,11 @@ export declare class MongooseController<T extends Partial<C_Document>> {
46
46
  * @returns The documents with dynamic virtuals populated.
47
47
  */
48
48
  private populateDynamicVirtualsForDocuments;
49
+ /**
50
+ * Internal helper that populates dynamic virtuals for an array of documents.
51
+ * Shared implementation used by both single-document and multi-document methods.
52
+ */
53
+ private populateDynamic;
49
54
  /**
50
55
  * Finds a single document with optional population and projection.
51
56
  * Automatically handles dynamic virtual population if configured.
@@ -11,7 +11,7 @@ function u(e) {
11
11
  var d = class {
12
12
  defaultLimit;
13
13
  constructor(e, t) {
14
- this.model = e, this.defaultLimit = t?.defaultLimit ?? 1e4;
14
+ this.model = e, this.defaultLimit = t?.defaultLimit ?? 1e3;
15
15
  }
16
16
  getModelName() {
17
17
  return this.model.modelName;
@@ -25,14 +25,12 @@ var d = class {
25
25
  return this.model.schema.statics._dynamicVirtuals;
26
26
  }
27
27
  async populateDynamicVirtualsForDocument(e, t) {
28
- let n = this.getDynamicVirtuals();
29
- if (n && n.length > 0) {
30
- let r = await l(this.model.base, [e], n, t, void 0, this.model);
31
- return r && r[0] ? r[0] : e;
32
- }
33
- return e;
28
+ return (await this.populateDynamic([e], t))[0] ?? e;
34
29
  }
35
30
  async populateDynamicVirtualsForDocuments(e, t) {
31
+ return this.populateDynamic(e, t);
32
+ }
33
+ async populateDynamic(e, t) {
36
34
  let n = this.getDynamicVirtuals();
37
35
  return n && n.length > 0 && e.length > 0 ? await l(this.model.base, e, n, t, void 0, this.model) : e;
38
36
  }
@@ -59,10 +57,11 @@ var d = class {
59
57
  r.limit || c.limit(this.defaultLimit);
60
58
  let l = s(i, this.getDynamicVirtuals());
61
59
  l && c.populate(l);
62
- let d = await c.exec(), f = await this.populateDynamicVirtualsForDocuments(d, i);
63
- return f.length === this.defaultLimit && !r.limit && o.warn(`[${this.getModelName()}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`), {
60
+ let d = await c.exec(), f = await this.populateDynamicVirtualsForDocuments(d, i), p = f.length === this.defaultLimit && !r.limit;
61
+ return p && o.warn(`[${this.getModelName()}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`), {
64
62
  success: !0,
65
- result: f.map((e) => u(e))
63
+ result: f.map((e) => u(e)),
64
+ truncated: p
66
65
  };
67
66
  } catch (e) {
68
67
  return a(e);
@@ -103,7 +102,7 @@ var d = class {
103
102
  success: !0,
104
103
  result: {
105
104
  ...i,
106
- docs: a.map((e) => e?.toObject?.() ?? e)
105
+ docs: a.map((e) => u(e))
107
106
  }
108
107
  };
109
108
  } catch (e) {