@jsnw/srv-utils 1.3.2 → 2.0.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 +348 -0
  3. package/dist/index.d.cts +167 -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,348 @@
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
+ * @returns {Promise<void>} A promise that resolves when the function execution is complete.
297
+ * @throws - Will throw an error if the `@nestjs/core` and/or `@nestjs/common` library is not found.
298
+ * @throws - Will propagate any error thrown by the executed function `fn`.
299
+ */
300
+ async function withNest(moduleCls, fn) {
301
+ let nestFactory = null;
302
+ try {
303
+ nestFactory = (await import("@nestjs/core"))?.NestFactory;
304
+ if (!nestFactory) throw new Error("NestFactory not found");
305
+ } catch (e) {
306
+ throw new Error("@nestjs/core and @nestjs/common are required for this function to work");
307
+ }
308
+ const app = await nestFactory.createApplicationContext(moduleCls);
309
+ let closeApplication = true;
310
+ let _e = void 0;
311
+ try {
312
+ await fn(app, () => {
313
+ closeApplication = false;
314
+ });
315
+ } catch (e) {
316
+ console.error("Error caught while executing the WithNestFn. Error:", e);
317
+ _e = e;
318
+ }
319
+ try {
320
+ if (closeApplication) await app.close();
321
+ } catch (e) {
322
+ console.error("Failed to close application. Error:", e);
323
+ }
324
+ if (_e) throw _e;
325
+ }
326
+ //#endregion
327
+ //#region src/create-random-string.ts
328
+ /**
329
+ * @param {number} length The length of the string
330
+ * @return {Promise<string>}
331
+ */
332
+ function createRandomString(length) {
333
+ if (length <= 0) return Promise.resolve("");
334
+ return new Promise((resolve, reject) => {
335
+ (0, node_crypto.randomBytes)(Math.ceil(length / 2), (err, buff) => {
336
+ if (err) return reject(err);
337
+ return resolve(buff.toString("hex").slice(0, length));
338
+ });
339
+ });
340
+ }
341
+ //#endregion
342
+ exports.ConfigLoader = ConfigLoader;
343
+ exports.configSchemas = configSchemas;
344
+ exports.createRandomString = createRandomString;
345
+ exports.fileExists = fileExists;
346
+ exports.fileExistsSync = fileExistsSync;
347
+ exports.getRootPackageDirnameSync = getRootPackageDirnameSync;
348
+ exports.withNest = withNest;
@@ -0,0 +1,167 @@
1
+ import { z } from "zod";
2
+ import { ErrorResult } from "@jsnw/common-utils";
3
+ import { INestApplicationContext } from "@nestjs/common";
4
+
5
+ //#region src/file-exists.d.ts
6
+ /**
7
+ * @param {string} path
8
+ * @param {number} [mode]
9
+ * @returns {boolean}
10
+ */
11
+ declare function fileExists(path: string, mode?: number): Promise<boolean>;
12
+ /**
13
+ * @param {string} path
14
+ * @param {number} [mode]
15
+ * @returns {boolean}
16
+ */
17
+ declare function fileExistsSync(path: string, mode?: number): boolean;
18
+ //#endregion
19
+ //#region src/getRootPackageDirname.d.ts
20
+ /**
21
+ * @returns {string}
22
+ */
23
+ declare function getRootPackageDirnameSync(): string;
24
+ //#endregion
25
+ //#region src/config/config-loader.types.d.ts
26
+ type ResolvedConfig<T extends z.ZodObject, P extends object | undefined = undefined> = z.output<T> & {
27
+ isDev: boolean;
28
+ } & (P extends undefined ? {} : P);
29
+ //#endregion
30
+ //#region src/config/config-loader.d.ts
31
+ declare class ConfigLoader {
32
+ private static _instance;
33
+ /**
34
+ * @returns {ConfigLoader}
35
+ */
36
+ static instance(): ConfigLoader;
37
+ /**
38
+ * @template {z.ZodObject} S
39
+ * @template {object} P
40
+ * @param {string} path You can use %pkgroot prefix for automatic project root resolution by AppConfigLoader.
41
+ * Also, you can use %env:ENV_VARIABLE to resolve config path based on environment variable
42
+ * Example 1: %pkgroot/config.yml
43
+ * Example 2: %env:CONFIG_PATH/config.yml
44
+ * @param {S} schema
45
+ * @param {P} [addProps]
46
+ * @returns {ResolvedConfig<S, P>}
47
+ */
48
+ static loadConfig<S extends z.ZodObject, P extends object | undefined = undefined>(path: string, schema: S, addProps?: P): ResolvedConfig<S, P>;
49
+ private constructor();
50
+ /**
51
+ * @param {string} path
52
+ * @returns {ErrorResult<any, Error>}
53
+ * @protected
54
+ */
55
+ protected loadYamlFile(path: string): ErrorResult<any, Error>;
56
+ /**
57
+ * @template {z.ZodTypeAny} T
58
+ * @param data
59
+ * @param {T} schema
60
+ * @returns {ErrorResult<output<T>, Error>}
61
+ * @protected
62
+ */
63
+ protected validateYaml<T extends z.ZodTypeAny>(data: any, schema: T): ErrorResult<z.infer<T>, Error>;
64
+ /**
65
+ * @param {string} mainYamlDirname
66
+ * @param yaml
67
+ * @returns {ErrorResult<any, Error[]>}
68
+ * @protected
69
+ */
70
+ protected processDirectives(mainYamlDirname: string, yaml: any): ErrorResult<any, Error[]>;
71
+ private resolveFilePath;
72
+ /**
73
+ * @param {string} fromDirname
74
+ * @param {string} toPath
75
+ * @returns {string}
76
+ * @private
77
+ */
78
+ private resolveIncludePath;
79
+ }
80
+ //#endregion
81
+ //#region src/config/predefined-schemas/index.d.ts
82
+ declare const configSchemas: {
83
+ timeString: import("zod").ZodPipe<import("zod").ZodString, import("zod").ZodTransform<number, string>>;
84
+ connection: import("zod").ZodObject<{
85
+ host: import("zod").ZodString;
86
+ port: import("zod").ZodCoercedNumber<unknown>;
87
+ user: import("zod").ZodString;
88
+ pass: import("zod").ZodString;
89
+ }, import("zod/v4/core").$strip>;
90
+ mongodbConnection: import("zod").ZodPipe<import("zod").ZodObject<{
91
+ host: import("zod").ZodString;
92
+ port: import("zod").ZodCoercedNumber<unknown>;
93
+ user: import("zod").ZodString;
94
+ pass: import("zod").ZodString;
95
+ db: import("zod").ZodString;
96
+ authDb: import("zod").ZodOptional<import("zod").ZodString>;
97
+ connectTimeout: import("zod").ZodDefault<import("zod").ZodPipe<import("zod").ZodString, import("zod").ZodTransform<number, string>>>;
98
+ }, import("zod/v4/core").$strip>, import("zod").ZodTransform<{
99
+ authDb: string;
100
+ dsn: string;
101
+ host: string;
102
+ port: number;
103
+ user: string;
104
+ pass: string;
105
+ db: string;
106
+ connectTimeout: number;
107
+ }, {
108
+ host: string;
109
+ port: number;
110
+ user: string;
111
+ pass: string;
112
+ db: string;
113
+ connectTimeout: number;
114
+ authDb?: string;
115
+ }>>;
116
+ mysqlConnection: import("zod").ZodObject<{
117
+ host: import("zod").ZodString;
118
+ port: import("zod").ZodCoercedNumber<unknown>;
119
+ user: import("zod").ZodString;
120
+ pass: import("zod").ZodString;
121
+ dbname: import("zod").ZodString;
122
+ }, import("zod/v4/core").$strip>;
123
+ redisConnection: import("zod").ZodObject<{
124
+ host: import("zod").ZodString;
125
+ port: import("zod").ZodCoercedNumber<unknown>;
126
+ user: import("zod").ZodString;
127
+ pass: import("zod").ZodString;
128
+ db: import("zod").ZodDefault<import("zod").ZodNumber>;
129
+ keyPrefix: import("zod").ZodDefault<import("zod").ZodString>;
130
+ }, import("zod/v4/core").$strip>;
131
+ rabbitConnection: import("zod").ZodObject<{
132
+ host: import("zod").ZodString;
133
+ port: import("zod").ZodCoercedNumber<unknown>;
134
+ user: import("zod").ZodString;
135
+ pass: import("zod").ZodString;
136
+ vhost: import("zod").ZodDefault<import("zod").ZodString>;
137
+ }, import("zod/v4/core").$strip>;
138
+ };
139
+ //#endregion
140
+ //#region src/withNest.d.ts
141
+ type WithNestFn = (app: INestApplicationContext, preventClosing: () => void) => Promise<void>;
142
+ /**
143
+ * Executes a given function within the context of a NestJS application.
144
+ *
145
+ * This asynchronous function initializes a NestJS application context using the specified
146
+ * module class and then executes the provided function `fn` with the application instance.
147
+ * The application context is automatically closed upon completion of the function execution,
148
+ * unless the function execution requests otherwise by invoking a callback.
149
+ *
150
+ * @param {any} moduleCls - The module class to be used for creating the NestJS application context.
151
+ * @param {WithNestFn} fn - The function to be executed with the NestJS application context.
152
+ * It receives the application instance and a callback to prevent
153
+ * automatic application context closure.
154
+ * @returns {Promise<void>} A promise that resolves when the function execution is complete.
155
+ * @throws - Will throw an error if the `@nestjs/core` and/or `@nestjs/common` library is not found.
156
+ * @throws - Will propagate any error thrown by the executed function `fn`.
157
+ */
158
+ declare function withNest(moduleCls: any, fn: WithNestFn): Promise<void>;
159
+ //#endregion
160
+ //#region src/create-random-string.d.ts
161
+ /**
162
+ * @param {number} length The length of the string
163
+ * @return {Promise<string>}
164
+ */
165
+ declare function createRandomString(length: number): Promise<string>;
166
+ //#endregion
167
+ 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.0.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
+ }