@jsnw/srv-utils 1.3.2 → 2.1.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 (36) hide show
  1. package/README.md +0 -10
  2. package/dist/index.cjs +349 -0
  3. package/dist/index.d.cts +169 -0
  4. package/package.json +22 -28
  5. package/dist/config/config-loader.js +0 -179
  6. package/dist/config/config-loader.types.js +0 -2
  7. package/dist/config/index.js +0 -7
  8. package/dist/config/predefined-schemas/connection.schema.js +0 -10
  9. package/dist/config/predefined-schemas/index.js +0 -17
  10. package/dist/config/predefined-schemas/mongodb-connection.schema.js +0 -15
  11. package/dist/config/predefined-schemas/mysql-connection.schema.js +0 -8
  12. package/dist/config/predefined-schemas/rabbit-connection.schema.js +0 -8
  13. package/dist/config/predefined-schemas/redis-connection.schema.js +0 -9
  14. package/dist/config/predefined-schemas/timestring.schema.js +0 -14
  15. package/dist/create-random-string.js +0 -21
  16. package/dist/file-exists.js +0 -34
  17. package/dist/getRootPackageDirname.js +0 -32
  18. package/dist/index.js +0 -17
  19. package/dist/types/config/config-loader.d.ts +0 -52
  20. package/dist/types/config/config-loader.types.d.ts +0 -4
  21. package/dist/types/config/index.d.ts +0 -3
  22. package/dist/types/config/predefined-schemas/connection.schema.d.ts +0 -7
  23. package/dist/types/config/predefined-schemas/index.d.ts +0 -57
  24. package/dist/types/config/predefined-schemas/mongodb-connection.schema.d.ts +0 -27
  25. package/dist/types/config/predefined-schemas/mysql-connection.schema.d.ts +0 -8
  26. package/dist/types/config/predefined-schemas/rabbit-connection.schema.d.ts +0 -8
  27. package/dist/types/config/predefined-schemas/redis-connection.schema.d.ts +0 -9
  28. package/dist/types/config/predefined-schemas/timestring.schema.d.ts +0 -2
  29. package/dist/types/create-random-string.d.ts +0 -5
  30. package/dist/types/file-exists.d.ts +0 -12
  31. package/dist/types/getRootPackageDirname.d.ts +0 -4
  32. package/dist/types/index.d.ts +0 -6
  33. package/dist/types/useTsconfigPaths.d.ts +0 -9
  34. package/dist/types/withNest.d.ts +0 -20
  35. package/dist/useTsconfigPaths.js +0 -34
  36. package/dist/withNest.js +0 -84
package/README.md CHANGED
@@ -9,20 +9,10 @@ npm install @jsnw/srv-utils
9
9
  ```
10
10
 
11
11
  Optional dependencies:
12
- - `module-alias` for `useTsconfigPaths`
13
12
  - `@nestjs/core` and `@nestjs/common` for `withNest`
14
13
 
15
14
  ## Exports
16
15
 
17
- ### useTsconfigPaths(fromPath, tsconfigPath)
18
- Loads `compilerOptions.paths` from a tsconfig file and registers them via `module-alias`.
19
-
20
- ```ts
21
- import {useTsconfigPaths} from '@jsnw/srv-utils';
22
-
23
- useTsconfigPaths(__dirname, './tsconfig.json');
24
- ```
25
-
26
16
  ### getRootPackageDirnameSync()
27
17
  Finds the highest directory (from the current module) that still has a readable `package.json`.
28
18
 
package/dist/index.cjs ADDED
@@ -0,0 +1,349 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let node_fs_promises = require("node:fs/promises");
25
+ let node_fs = require("node:fs");
26
+ let node_path = require("node:path");
27
+ let zod = require("zod");
28
+ let yaml = require("yaml");
29
+ let ms = require("ms");
30
+ ms = __toESM(ms);
31
+ let node_crypto = require("node:crypto");
32
+ //#region src/file-exists.ts
33
+ /**
34
+ * @param {string} path
35
+ * @param {number} [mode]
36
+ * @returns {boolean}
37
+ */
38
+ async function fileExists(path, mode = node_fs.constants.F_OK | node_fs.constants.R_OK) {
39
+ try {
40
+ await (0, node_fs_promises.access)(path, mode);
41
+ return true;
42
+ } catch (e) {
43
+ return false;
44
+ }
45
+ }
46
+ /**
47
+ * @param {string} path
48
+ * @param {number} [mode]
49
+ * @returns {boolean}
50
+ */
51
+ function fileExistsSync(path, mode = node_fs.constants.F_OK | node_fs.constants.R_OK) {
52
+ try {
53
+ (0, node_fs.accessSync)(path, mode);
54
+ return true;
55
+ } catch (e) {
56
+ return false;
57
+ }
58
+ }
59
+ //#endregion
60
+ //#region src/getRootPackageDirname.ts
61
+ let cachedRootPackageDirname = null;
62
+ /**
63
+ * @returns {string}
64
+ */
65
+ function getRootPackageDirnameSync() {
66
+ if (cachedRootPackageDirname !== null) return cachedRootPackageDirname;
67
+ let path = (0, node_path.resolve)(__dirname, ".."), lastValidPath = path;
68
+ if (/[\\\/]node_modules[\\\/]/i.test(path)) {
69
+ const pieces = path.split(/[\\\/]node_modules[\\\/]/i);
70
+ if (pieces.length > 0) path = pieces[0];
71
+ }
72
+ while (true) {
73
+ const packageJsonPath = (0, node_path.resolve)(path, "package.json");
74
+ try {
75
+ (0, node_fs.accessSync)(packageJsonPath, node_fs.constants.F_OK | node_fs.constants.R_OK);
76
+ } catch (e) {
77
+ break;
78
+ }
79
+ lastValidPath = path;
80
+ path = (0, node_path.resolve)(path, "..");
81
+ }
82
+ cachedRootPackageDirname = lastValidPath;
83
+ return lastValidPath;
84
+ }
85
+ //#endregion
86
+ //#region src/config/config-loader.ts
87
+ const PKG_ROOT_REGEX = /^%pkgroot(?:[\/\\]|$)/i;
88
+ const ENV_VAR_REGEX = /^%env:(?<var_name>[A-Za-z0-9_]+)(?:[\/\\]|$)/i;
89
+ var ConfigLoader = class ConfigLoader {
90
+ static _instance;
91
+ /**
92
+ * @returns {ConfigLoader}
93
+ */
94
+ static instance() {
95
+ if (!ConfigLoader._instance) ConfigLoader._instance = new ConfigLoader();
96
+ return ConfigLoader._instance;
97
+ }
98
+ /**
99
+ * @template {z.ZodObject} S
100
+ * @template {object} P
101
+ * @param {string} path You can use %pkgroot prefix for automatic project root resolution by AppConfigLoader.
102
+ * Also, you can use %env:ENV_VARIABLE to resolve config path based on environment variable
103
+ * Example 1: %pkgroot/config.yml
104
+ * Example 2: %env:CONFIG_PATH/config.yml
105
+ * @param {S} schema
106
+ * @param {P} [addProps]
107
+ * @returns {ResolvedConfig<S, P>}
108
+ */
109
+ static loadConfig(path, schema, addProps) {
110
+ const loader = ConfigLoader.instance();
111
+ const [yaml$1, loadError] = loader.loadYamlFile(path);
112
+ if (loadError) {
113
+ console.error(loadError.message);
114
+ process.exit(1);
115
+ }
116
+ const [processedYaml, directiveErrors] = loader.processDirectives((0, node_path.dirname)(loader.resolveFilePath(path)), yaml$1);
117
+ if (directiveErrors && directiveErrors.length > 0) {
118
+ for (const err of directiveErrors) console.error(`directive error: ${err.message}`);
119
+ process.exit(1);
120
+ }
121
+ const [validatedYaml, validateError] = loader.validateYaml(processedYaml, schema);
122
+ if (validateError) {
123
+ console.error(validateError.message);
124
+ process.exit(1);
125
+ }
126
+ validatedYaml["isDev"] = (process?.env?.APP_CONTEXT ?? process?.env?.APPLICATION_CONTEXT ?? process?.env?.NODE_ENV ?? "").toLowerCase() !== "production";
127
+ return {
128
+ ...validatedYaml,
129
+ ...addProps ?? {}
130
+ };
131
+ }
132
+ constructor() {}
133
+ /**
134
+ * @param {string} path
135
+ * @returns {ErrorResult<any, Error>}
136
+ * @protected
137
+ */
138
+ loadYamlFile(path) {
139
+ path = this.resolveFilePath(path);
140
+ if (!fileExistsSync(path)) return [null, /* @__PURE__ */ new Error(`YAML file does not exists at path: ${path}`)];
141
+ let data = void 0, parsedYml = void 0;
142
+ try {
143
+ data = (0, node_fs.readFileSync)(path, "utf-8");
144
+ } catch (e) {
145
+ return [null, /* @__PURE__ */ new Error(`Failed to read config file at path: ${path}`)];
146
+ }
147
+ try {
148
+ parsedYml = (0, yaml.parse)(data, { prettyErrors: true });
149
+ } catch (e) {
150
+ return [null, /* @__PURE__ */ new Error(`Failed to parse YAML file at path: ${path}`)];
151
+ }
152
+ return [parsedYml, null];
153
+ }
154
+ /**
155
+ * @template {z.ZodTypeAny} T
156
+ * @param data
157
+ * @param {T} schema
158
+ * @returns {ErrorResult<output<T>, Error>}
159
+ * @protected
160
+ */
161
+ validateYaml(data, schema) {
162
+ const { data: parsed, error, success } = schema.safeParse(data);
163
+ if (!success) {
164
+ if (error && error instanceof zod.ZodError) return [null, /* @__PURE__ */ new Error(`Failed to validate yaml (#1). Error message: ${zod.z.prettifyError(error)}`)];
165
+ return [null, /* @__PURE__ */ new Error(`Failed to validate yaml (#2)`)];
166
+ }
167
+ return [parsed, null];
168
+ }
169
+ /**
170
+ * @param {string} mainYamlDirname
171
+ * @param yaml
172
+ * @returns {ErrorResult<any, Error[]>}
173
+ * @protected
174
+ */
175
+ processDirectives(mainYamlDirname, yaml$2) {
176
+ if (typeof yaml$2 !== "object") return yaml$2;
177
+ const nodesToVisit = [yaml$2], errors = [];
178
+ for (let i = 0; i < nodesToVisit.length; i++) {
179
+ const node = nodesToVisit[i];
180
+ if (typeof node !== "object" || Array.isArray(node)) continue;
181
+ const nodeFields = Object.keys(node);
182
+ for (const field of nodeFields) if (field === "$include") {
183
+ const $includePaths = [];
184
+ if (typeof node["$include"] === "string") $includePaths.push(node["$include"]);
185
+ else if (Array.isArray(node["$include"])) $includePaths.push(...node["$include"].filter((v) => v && typeof v === "string" && v.trim() !== ""));
186
+ delete node["$include"];
187
+ for (const path of $includePaths) {
188
+ const [loadedYaml, loadError] = this.loadYamlFile(this.resolveIncludePath(mainYamlDirname, path));
189
+ if (loadError) errors.push(loadError);
190
+ else for (const [k, v] of Object.entries(loadedYaml)) node[k] = v;
191
+ }
192
+ } else if (typeof node[field] === "string" && /^\s*\$[A-Z0-9_]+$/.test(node[field])) node[field] = process.env?.[node[field].trim().slice(1)] ?? "";
193
+ for (const k of Object.keys(node)) if (Object.hasOwn(node, k) && typeof node[k] === "object" && !Array.isArray(node[k])) nodesToVisit.push(node[k]);
194
+ }
195
+ return [yaml$2, errors];
196
+ }
197
+ resolveFilePath(path) {
198
+ const initialPath = path;
199
+ while (ENV_VAR_REGEX.test(path)) {
200
+ const m = path.match(ENV_VAR_REGEX);
201
+ if (m.groups?.["var_name"]) if (process.env?.[m.groups["var_name"]]) path = path.replace(ENV_VAR_REGEX, process.env[m.groups["var_name"]].replace(/[\/\\]+$/, "") + node_path.sep);
202
+ else throw new Error(`Failed to resolve path: "${initialPath}"`);
203
+ }
204
+ if (PKG_ROOT_REGEX.test(path)) path = path.replace(PKG_ROOT_REGEX, getRootPackageDirnameSync() + node_path.sep);
205
+ return (0, node_path.resolve)(path);
206
+ }
207
+ /**
208
+ * @param {string} fromDirname
209
+ * @param {string} toPath
210
+ * @returns {string}
211
+ * @private
212
+ */
213
+ resolveIncludePath(fromDirname, toPath) {
214
+ return (0, node_path.resolve)(this.resolveFilePath(fromDirname), toPath);
215
+ }
216
+ };
217
+ //#endregion
218
+ //#region src/config/predefined-schemas/timestring.schema.ts
219
+ const TIMESTRING_REGEX = new RegExp(`\\d+\\s*(?:${[
220
+ "Years",
221
+ "Year",
222
+ "Yrs",
223
+ "Yr",
224
+ "Y",
225
+ "Weeks",
226
+ "Week",
227
+ "W",
228
+ "Days",
229
+ "Day",
230
+ "D",
231
+ "Hours",
232
+ "Hour",
233
+ "Hrs",
234
+ "Hr",
235
+ "H",
236
+ "Minutes",
237
+ "Minute",
238
+ "Mins",
239
+ "Min",
240
+ "M",
241
+ "Seconds",
242
+ "Second",
243
+ "Secs",
244
+ "Sec",
245
+ "s",
246
+ "Milliseconds",
247
+ "Millisecond",
248
+ "Msecs",
249
+ "Msec",
250
+ "Ms"
251
+ ].map((unit) => unit.toLowerCase()).join("|")})`, "i");
252
+ const timeStringSchema = zod.z.string().nonempty().regex(TIMESTRING_REGEX).transform((v) => (0, ms.default)(v));
253
+ //#endregion
254
+ //#region src/config/predefined-schemas/connection.schema.ts
255
+ const connectionSchema = zod.z.object({
256
+ host: zod.z.string().nonempty(),
257
+ port: zod.z.coerce.number().min(1).max(65535),
258
+ user: zod.z.string(),
259
+ pass: zod.z.string()
260
+ });
261
+ //#endregion
262
+ //#region src/config/predefined-schemas/index.ts
263
+ const configSchemas = {
264
+ timeString: timeStringSchema,
265
+ connection: connectionSchema,
266
+ mongodbConnection: connectionSchema.extend({
267
+ db: zod.z.string().nonempty(),
268
+ authDb: zod.z.string().optional(),
269
+ connectTimeout: timeStringSchema.default(5e3)
270
+ }).transform((v) => ({
271
+ ...v,
272
+ authDb: v.authDb || v.db,
273
+ dsn: `mongodb://${v.host}:${v.port}/${v.db}`
274
+ })),
275
+ mysqlConnection: connectionSchema.extend({ dbname: zod.z.string().nonempty() }),
276
+ redisConnection: connectionSchema.extend({
277
+ db: zod.z.number().min(0).default(0),
278
+ keyPrefix: zod.z.string().default("")
279
+ }),
280
+ rabbitConnection: connectionSchema.extend({ vhost: zod.z.string().default("/") })
281
+ };
282
+ //#endregion
283
+ //#region src/withNest.ts
284
+ /**
285
+ * Executes a given function within the context of a NestJS application.
286
+ *
287
+ * This asynchronous function initializes a NestJS application context using the specified
288
+ * module class and then executes the provided function `fn` with the application instance.
289
+ * The application context is automatically closed upon completion of the function execution,
290
+ * unless the function execution requests otherwise by invoking a callback.
291
+ *
292
+ * @param {any} moduleCls - The module class to be used for creating the NestJS application context.
293
+ * @param {WithNestFn} fn - The function to be executed with the NestJS application context.
294
+ * It receives the application instance and a callback to prevent
295
+ * automatic application context closure.
296
+ * @param {NestApplicationContextOptions} [options]
297
+ * @returns {Promise<void>} A promise that resolves when the function execution is complete.
298
+ * @throws - Will throw an error if the `@nestjs/core` and/or `@nestjs/common` library is not found.
299
+ * @throws - Will propagate any error thrown by the executed function `fn`.
300
+ */
301
+ async function withNest(moduleCls, fn, options) {
302
+ let nestFactory = null;
303
+ try {
304
+ nestFactory = (await import("@nestjs/core"))?.NestFactory;
305
+ if (!nestFactory) throw new Error("NestFactory not found");
306
+ } catch (e) {
307
+ throw new Error("@nestjs/core and @nestjs/common are required for this function to work");
308
+ }
309
+ const app = await nestFactory.createApplicationContext(moduleCls, options);
310
+ let closeApplication = true;
311
+ let _e = void 0;
312
+ try {
313
+ await fn(app, () => {
314
+ closeApplication = false;
315
+ });
316
+ } catch (e) {
317
+ console.error("Error caught while executing the WithNestFn. Error:", e);
318
+ _e = e;
319
+ }
320
+ try {
321
+ if (closeApplication) await app.close();
322
+ } catch (e) {
323
+ console.error("Failed to close application. Error:", e);
324
+ }
325
+ if (_e) throw _e;
326
+ }
327
+ //#endregion
328
+ //#region src/create-random-string.ts
329
+ /**
330
+ * @param {number} length The length of the string
331
+ * @return {Promise<string>}
332
+ */
333
+ function createRandomString(length) {
334
+ if (length <= 0) return Promise.resolve("");
335
+ return new Promise((resolve, reject) => {
336
+ (0, node_crypto.randomBytes)(Math.ceil(length / 2), (err, buff) => {
337
+ if (err) return reject(err);
338
+ return resolve(buff.toString("hex").slice(0, length));
339
+ });
340
+ });
341
+ }
342
+ //#endregion
343
+ exports.ConfigLoader = ConfigLoader;
344
+ exports.configSchemas = configSchemas;
345
+ exports.createRandomString = createRandomString;
346
+ exports.fileExists = fileExists;
347
+ exports.fileExistsSync = fileExistsSync;
348
+ exports.getRootPackageDirnameSync = getRootPackageDirnameSync;
349
+ exports.withNest = withNest;
@@ -0,0 +1,169 @@
1
+ import { z } from "zod";
2
+ import { ErrorResult } from "@jsnw/common-utils";
3
+ import { INestApplicationContext } from "@nestjs/common";
4
+ import { NestApplicationContextOptions } from "@nestjs/common/interfaces/nest-application-context-options.interface";
5
+
6
+ //#region src/file-exists.d.ts
7
+ /**
8
+ * @param {string} path
9
+ * @param {number} [mode]
10
+ * @returns {boolean}
11
+ */
12
+ declare function fileExists(path: string, mode?: number): Promise<boolean>;
13
+ /**
14
+ * @param {string} path
15
+ * @param {number} [mode]
16
+ * @returns {boolean}
17
+ */
18
+ declare function fileExistsSync(path: string, mode?: number): boolean;
19
+ //#endregion
20
+ //#region src/getRootPackageDirname.d.ts
21
+ /**
22
+ * @returns {string}
23
+ */
24
+ declare function getRootPackageDirnameSync(): string;
25
+ //#endregion
26
+ //#region src/config/config-loader.types.d.ts
27
+ type ResolvedConfig<T extends z.ZodObject, P extends object | undefined = undefined> = z.output<T> & {
28
+ isDev: boolean;
29
+ } & (P extends undefined ? {} : P);
30
+ //#endregion
31
+ //#region src/config/config-loader.d.ts
32
+ declare class ConfigLoader {
33
+ private static _instance;
34
+ /**
35
+ * @returns {ConfigLoader}
36
+ */
37
+ static instance(): ConfigLoader;
38
+ /**
39
+ * @template {z.ZodObject} S
40
+ * @template {object} P
41
+ * @param {string} path You can use %pkgroot prefix for automatic project root resolution by AppConfigLoader.
42
+ * Also, you can use %env:ENV_VARIABLE to resolve config path based on environment variable
43
+ * Example 1: %pkgroot/config.yml
44
+ * Example 2: %env:CONFIG_PATH/config.yml
45
+ * @param {S} schema
46
+ * @param {P} [addProps]
47
+ * @returns {ResolvedConfig<S, P>}
48
+ */
49
+ static loadConfig<S extends z.ZodObject, P extends object | undefined = undefined>(path: string, schema: S, addProps?: P): ResolvedConfig<S, P>;
50
+ private constructor();
51
+ /**
52
+ * @param {string} path
53
+ * @returns {ErrorResult<any, Error>}
54
+ * @protected
55
+ */
56
+ protected loadYamlFile(path: string): ErrorResult<any, Error>;
57
+ /**
58
+ * @template {z.ZodTypeAny} T
59
+ * @param data
60
+ * @param {T} schema
61
+ * @returns {ErrorResult<output<T>, Error>}
62
+ * @protected
63
+ */
64
+ protected validateYaml<T extends z.ZodTypeAny>(data: any, schema: T): ErrorResult<z.infer<T>, Error>;
65
+ /**
66
+ * @param {string} mainYamlDirname
67
+ * @param yaml
68
+ * @returns {ErrorResult<any, Error[]>}
69
+ * @protected
70
+ */
71
+ protected processDirectives(mainYamlDirname: string, yaml: any): ErrorResult<any, Error[]>;
72
+ private resolveFilePath;
73
+ /**
74
+ * @param {string} fromDirname
75
+ * @param {string} toPath
76
+ * @returns {string}
77
+ * @private
78
+ */
79
+ private resolveIncludePath;
80
+ }
81
+ //#endregion
82
+ //#region src/config/predefined-schemas/index.d.ts
83
+ declare const configSchemas: {
84
+ timeString: import("zod").ZodPipe<import("zod").ZodString, import("zod").ZodTransform<number, string>>;
85
+ connection: import("zod").ZodObject<{
86
+ host: import("zod").ZodString;
87
+ port: import("zod").ZodCoercedNumber<unknown>;
88
+ user: import("zod").ZodString;
89
+ pass: import("zod").ZodString;
90
+ }, import("zod/v4/core").$strip>;
91
+ mongodbConnection: import("zod").ZodPipe<import("zod").ZodObject<{
92
+ host: import("zod").ZodString;
93
+ port: import("zod").ZodCoercedNumber<unknown>;
94
+ user: import("zod").ZodString;
95
+ pass: import("zod").ZodString;
96
+ db: import("zod").ZodString;
97
+ authDb: import("zod").ZodOptional<import("zod").ZodString>;
98
+ connectTimeout: import("zod").ZodDefault<import("zod").ZodPipe<import("zod").ZodString, import("zod").ZodTransform<number, string>>>;
99
+ }, import("zod/v4/core").$strip>, import("zod").ZodTransform<{
100
+ authDb: string;
101
+ dsn: string;
102
+ host: string;
103
+ port: number;
104
+ user: string;
105
+ pass: string;
106
+ db: string;
107
+ connectTimeout: number;
108
+ }, {
109
+ host: string;
110
+ port: number;
111
+ user: string;
112
+ pass: string;
113
+ db: string;
114
+ connectTimeout: number;
115
+ authDb?: string;
116
+ }>>;
117
+ mysqlConnection: import("zod").ZodObject<{
118
+ host: import("zod").ZodString;
119
+ port: import("zod").ZodCoercedNumber<unknown>;
120
+ user: import("zod").ZodString;
121
+ pass: import("zod").ZodString;
122
+ dbname: import("zod").ZodString;
123
+ }, import("zod/v4/core").$strip>;
124
+ redisConnection: import("zod").ZodObject<{
125
+ host: import("zod").ZodString;
126
+ port: import("zod").ZodCoercedNumber<unknown>;
127
+ user: import("zod").ZodString;
128
+ pass: import("zod").ZodString;
129
+ db: import("zod").ZodDefault<import("zod").ZodNumber>;
130
+ keyPrefix: import("zod").ZodDefault<import("zod").ZodString>;
131
+ }, import("zod/v4/core").$strip>;
132
+ rabbitConnection: import("zod").ZodObject<{
133
+ host: import("zod").ZodString;
134
+ port: import("zod").ZodCoercedNumber<unknown>;
135
+ user: import("zod").ZodString;
136
+ pass: import("zod").ZodString;
137
+ vhost: import("zod").ZodDefault<import("zod").ZodString>;
138
+ }, import("zod/v4/core").$strip>;
139
+ };
140
+ //#endregion
141
+ //#region src/withNest.d.ts
142
+ type WithNestFn = (app: INestApplicationContext, preventClosing: () => void) => Promise<void>;
143
+ /**
144
+ * Executes a given function within the context of a NestJS application.
145
+ *
146
+ * This asynchronous function initializes a NestJS application context using the specified
147
+ * module class and then executes the provided function `fn` with the application instance.
148
+ * The application context is automatically closed upon completion of the function execution,
149
+ * unless the function execution requests otherwise by invoking a callback.
150
+ *
151
+ * @param {any} moduleCls - The module class to be used for creating the NestJS application context.
152
+ * @param {WithNestFn} fn - The function to be executed with the NestJS application context.
153
+ * It receives the application instance and a callback to prevent
154
+ * automatic application context closure.
155
+ * @param {NestApplicationContextOptions} [options]
156
+ * @returns {Promise<void>} A promise that resolves when the function execution is complete.
157
+ * @throws - Will throw an error if the `@nestjs/core` and/or `@nestjs/common` library is not found.
158
+ * @throws - Will propagate any error thrown by the executed function `fn`.
159
+ */
160
+ declare function withNest(moduleCls: any, fn: WithNestFn, options?: NestApplicationContextOptions): Promise<void>;
161
+ //#endregion
162
+ //#region src/create-random-string.d.ts
163
+ /**
164
+ * @param {number} length The length of the string
165
+ * @return {Promise<string>}
166
+ */
167
+ declare function createRandomString(length: number): Promise<string>;
168
+ //#endregion
169
+ export { ConfigLoader, type ResolvedConfig, configSchemas, createRandomString, fileExists, fileExistsSync, getRootPackageDirnameSync, withNest };
package/package.json CHANGED
@@ -1,23 +1,16 @@
1
1
  {
2
2
  "name": "@jsnw/srv-utils",
3
- "version": "1.3.2",
3
+ "version": "2.1.0",
4
4
  "description": "Server-side utilities for Node.js/TypeScript: tsconfig paths, Nest helpers, and config loading.",
5
- "main": "./dist/index.js",
6
- "types": "./dist/types/index.d.ts",
5
+ "engines": {
6
+ "node": ">=20"
7
+ },
7
8
  "exports": {
8
- ".": {
9
- "require": "./dist/index.js",
10
- "types": "./dist/types/index.d.ts"
9
+ "node": {
10
+ "default": "./dist/index.cjs",
11
+ "types": "./dist/index.d.cts"
11
12
  }
12
13
  },
13
- "scripts": {
14
- "clean": "rimraf ./dist",
15
- "build": "npm run clean && tsc -p tsconfig.json",
16
- "test": "jest --passWithNoTests",
17
- "test:watch": "jest --watch",
18
- "test:coverage": "jest --coverage",
19
- "prepublishOnly": "npm run build"
20
- },
21
14
  "files": [
22
15
  "./dist",
23
16
  "README.md"
@@ -42,25 +35,26 @@
42
35
  "dependencies": {
43
36
  "@jsnw/common-utils": "^1.0.0",
44
37
  "ms": "^2.1.3",
45
- "yaml": "^2.8.2",
46
- "zod": "^4.3.6"
38
+ "yaml": "^2.9.0",
39
+ "zod": "^4.4.3"
47
40
  },
48
41
  "optionalDependencies": {
49
- "@nestjs/common": "^11.1.12",
50
- "@nestjs/core": "^11.1.12",
51
- "module-alias": "^2.3.3"
42
+ "@nestjs/common": "^11.1.27",
43
+ "@nestjs/core": "^11.1.27"
52
44
  },
53
45
  "devDependencies": {
54
- "@nestjs/common": "^11.1.12",
55
- "@nestjs/core": "^11.1.12",
56
46
  "@types/jest": "^30.0.0",
57
- "@types/module-alias": "^2.0.4",
58
47
  "@types/ms": "^2.1.0",
59
- "jest": "^30.2.0",
60
- "module-alias": "^2.3.3",
61
- "rimraf": "^6.1.2",
62
- "ts-jest": "^29.4.6",
63
- "tslib": "^2.8.1",
48
+ "@types/node": "^24.13.2",
49
+ "jest": "^30.4.2",
50
+ "ts-jest": "^29.4.11",
51
+ "tsdown": "^0.22.3",
64
52
  "typescript": "^5.9.3"
53
+ },
54
+ "scripts": {
55
+ "build": "tsdown",
56
+ "test": "jest --passWithNoTests",
57
+ "test:watch": "jest --watch",
58
+ "test:coverage": "jest --coverage"
65
59
  }
66
- }
60
+ }