@catbee/utils 2.0.0-next.0 → 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.
- package/LICENSE +1 -1
- package/README.md +102 -52
- package/array/index.cjs +215 -74
- package/array/index.d.ts +345 -2
- package/array/index.mjs +201 -74
- package/async/index.cjs +116 -39
- package/async/index.d.ts +292 -2
- package/async/index.mjs +116 -40
- package/cache/index.cjs +2 -2
- package/cache/index.d.ts +156 -2
- package/cache/index.mjs +3 -3
- package/config/index.cjs +80 -66
- package/config/index.d.ts +65 -3
- package/config/index.mjs +77 -65
- package/context-store/index.cjs +2 -3
- package/context-store/index.d.ts +193 -2
- package/context-store/index.mjs +2 -3
- package/crypto/index.cjs +55 -5
- package/crypto/index.d.ts +225 -2
- package/crypto/index.mjs +52 -7
- package/date/index.cjs +676 -2
- package/date/index.d.ts +676 -2
- package/date/index.mjs +665 -3
- package/decorator/index.cjs +2172 -0
- package/{decorators/decorators.utils.d.ts → decorator/index.d.ts} +58 -54
- package/decorator/index.mjs +2131 -0
- package/{dir → directory}/index.cjs +5 -4
- package/{dir/dir.utils.d.ts → directory/index.d.ts} +24 -21
- package/{dir → directory}/index.mjs +5 -4
- package/env/index.cjs +100 -68
- package/env/index.d.ts +391 -2
- package/env/index.mjs +100 -68
- package/exception/index.cjs +1 -1
- package/exception/index.d.ts +233 -2
- package/exception/index.mjs +1 -1
- package/fs/index.cjs +71 -37
- package/fs/index.d.ts +206 -2
- package/fs/index.mjs +65 -35
- package/http-status-codes/index.cjs +1 -1
- package/http-status-codes/index.d.ts +268 -2
- package/http-status-codes/index.mjs +1 -1
- package/id/index.cjs +1 -1
- package/id/index.d.ts +38 -2
- package/id/index.mjs +1 -1
- package/index.cjs +13 -13
- package/index.d.ts +5 -5
- package/index.mjs +5 -5
- package/logger/index.cjs +13 -15
- package/logger/index.d.ts +190 -2
- package/logger/index.mjs +14 -16
- package/middleware/index.cjs +1 -1
- package/middleware/index.d.ts +104 -2
- package/middleware/index.mjs +1 -1
- package/object/index.cjs +379 -0
- package/{obj/obj.utils.d.ts → object/index.d.ts} +73 -33
- package/object/index.mjs +360 -0
- package/package.json +41 -23
- package/performance/index.cjs +4 -4
- package/performance/index.d.ts +139 -2
- package/performance/index.mjs +4 -4
- package/request/index.cjs +37 -25
- package/request/index.d.ts +242 -3
- package/request/index.mjs +37 -25
- package/response/index.cjs +1 -1
- package/response/index.d.ts +319 -3
- package/response/index.mjs +1 -1
- package/server/index.cjs +249 -146
- package/server/index.d.ts +866 -5
- package/server/index.mjs +248 -144
- package/stream/index.cjs +1 -1
- package/stream/index.d.ts +91 -2
- package/stream/index.mjs +1 -1
- package/string/index.cjs +34 -1
- package/string/index.d.ts +146 -2
- package/string/index.mjs +31 -2
- package/type/index.cjs +19 -2
- package/type/index.d.ts +144 -2
- package/type/index.mjs +17 -3
- package/types/index.cjs +1 -1
- package/types/index.d.ts +775 -5
- package/types/index.mjs +1 -1
- package/url/index.cjs +63 -5
- package/url/index.d.ts +200 -2
- package/url/index.mjs +59 -6
- package/{validate → validation}/index.cjs +91 -44
- package/{validate/validate.utils.d.ts → validation/index.d.ts} +33 -24
- package/{validate → validation}/index.mjs +87 -44
- package/array/array.utils.d.ts +0 -191
- package/async/async.utils.d.ts +0 -296
- package/cache/cache.utils.d.ts +0 -176
- package/config/config.d.ts +0 -57
- package/context-store/context-store.utils.d.ts +0 -212
- package/crypto/crypto.utils.d.ts +0 -183
- package/date/date.utils.d.ts +0 -190
- package/decorators/index.cjs +0 -913
- package/decorators/index.d.ts +0 -25
- package/decorators/index.mjs +0 -872
- package/dir/index.d.ts +0 -25
- package/env/env.utils.d.ts +0 -400
- package/exception/exception.utils.d.ts +0 -253
- package/fs/fs.utils.d.ts +0 -196
- package/http-status-codes/http-status-codes.d.ts +0 -289
- package/id/id.utils.d.ts +0 -59
- package/logger/logger.utils.d.ts +0 -210
- package/middleware/middleware.utils.d.ts +0 -123
- package/obj/index.cjs +0 -317
- package/obj/index.d.ts +0 -25
- package/obj/index.mjs +0 -301
- package/performance/performance.utils.d.ts +0 -159
- package/request/request.utils.d.ts +0 -109
- package/response/response.utils.d.ts +0 -186
- package/server/server.builder.d.ts +0 -531
- package/server/server.d.ts +0 -303
- package/stream/stream.utils.d.ts +0 -111
- package/string/string.utils.d.ts +0 -124
- package/type/type.utils.d.ts +0 -129
- package/types/api-response.d.ts +0 -175
- package/types/common.d.ts +0 -148
- package/types/config.d.ts +0 -88
- package/types/server.d.ts +0 -291
- package/url/url.utils.d.ts +0 -164
- package/validate/index.d.ts +0 -25
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* The MIT License
|
|
3
3
|
*
|
|
4
|
-
* Copyright (c)
|
|
4
|
+
* Copyright (c) 2026 Catbee Technologies. https://catbee.in/license
|
|
5
5
|
*
|
|
6
6
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
* of this software and associated documentation files (the "Software"), to deal
|
|
@@ -142,7 +142,7 @@ function watchDir(dirPath, callback) {
|
|
|
142
142
|
__name(watchDir, "watchDir");
|
|
143
143
|
async function findFilesByPattern(pattern, options = {}) {
|
|
144
144
|
const matchPattern = /* @__PURE__ */ __name((name, pattern2) => {
|
|
145
|
-
let escaped = pattern2.replaceAll(/[.+^${}()|[\]\\]/g,
|
|
145
|
+
let escaped = pattern2.replaceAll(/[.+^${}()|[\]\\]/g, String.raw`\$&`);
|
|
146
146
|
escaped = escaped.replaceAll("*", ".*").replaceAll("?", ".");
|
|
147
147
|
const regex = new RegExp(`^${escaped}$`);
|
|
148
148
|
return regex.test(name);
|
|
@@ -152,7 +152,7 @@ async function findFilesByPattern(pattern, options = {}) {
|
|
|
152
152
|
async function walk(dir, segIndex) {
|
|
153
153
|
if (segIndex >= segments.length) return [];
|
|
154
154
|
const segment = segments[segIndex];
|
|
155
|
-
const entries = await
|
|
155
|
+
const entries = await fsp__default.default.readdir(dir, {
|
|
156
156
|
withFileTypes: true
|
|
157
157
|
});
|
|
158
158
|
let matchedFiles = [];
|
|
@@ -254,7 +254,8 @@ async function findNewestFile(dirPath, recursive = false) {
|
|
|
254
254
|
path: file,
|
|
255
255
|
mtime: (await fsp__default.default.stat(file)).mtime
|
|
256
256
|
})));
|
|
257
|
-
|
|
257
|
+
const sorted = stats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
258
|
+
return sorted[0].path;
|
|
258
259
|
}
|
|
259
260
|
__name(findNewestFile, "findNewestFile");
|
|
260
261
|
async function findOldestFile(dirPath, recursive = false) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* The MIT License
|
|
3
3
|
*
|
|
4
|
-
* Copyright (c)
|
|
4
|
+
* Copyright (c) 2026 Catbee Technologies. https://catbee.in/license
|
|
5
5
|
*
|
|
6
6
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
* of this software and associated documentation files (the "Software"), to deal
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import fs from 'fs';
|
|
25
|
+
import fs from 'node:fs';
|
|
26
|
+
|
|
26
27
|
/**
|
|
27
28
|
* Ensures that a directory exists, creating parent directories if needed (like `mkdir -p`).
|
|
28
29
|
*
|
|
@@ -30,7 +31,7 @@ import fs from 'fs';
|
|
|
30
31
|
* @returns {Promise<void>} Resolves when the directory exists.
|
|
31
32
|
* @throws {Error} If directory cannot be created.
|
|
32
33
|
*/
|
|
33
|
-
|
|
34
|
+
declare function ensureDir(dirPath: string): Promise<void>;
|
|
34
35
|
/**
|
|
35
36
|
* Recursively lists all files in a directory.
|
|
36
37
|
*
|
|
@@ -39,7 +40,7 @@ export declare function ensureDir(dirPath: string): Promise<void>;
|
|
|
39
40
|
* @returns {Promise<string[]>} Array of absolute file paths.
|
|
40
41
|
* @throws {Error} If the directory cannot be read.
|
|
41
42
|
*/
|
|
42
|
-
|
|
43
|
+
declare function listFiles(dirPath: string, recursive?: boolean): Promise<string[]>;
|
|
43
44
|
/**
|
|
44
45
|
* Deletes a directory and all its contents recursively (like `rm -rf`).
|
|
45
46
|
*
|
|
@@ -47,14 +48,14 @@ export declare function listFiles(dirPath: string, recursive?: boolean): Promise
|
|
|
47
48
|
* @returns {Promise<void>} Resolves when deletion is complete.
|
|
48
49
|
* @throws {Error} If deletion fails.
|
|
49
50
|
*/
|
|
50
|
-
|
|
51
|
+
declare function deleteDirRecursive(dirPath: string): Promise<void>;
|
|
51
52
|
/**
|
|
52
53
|
* Checks whether a given path is a directory.
|
|
53
54
|
*
|
|
54
55
|
* @param {string} pathStr - Path to check.
|
|
55
56
|
* @returns {Promise<boolean>} True if the path is a directory, else false.
|
|
56
57
|
*/
|
|
57
|
-
|
|
58
|
+
declare function isDirectory(pathStr: string): Promise<boolean>;
|
|
58
59
|
/**
|
|
59
60
|
* Recursively copies a directory and all its contents to a destination.
|
|
60
61
|
*
|
|
@@ -63,7 +64,7 @@ export declare function isDirectory(pathStr: string): Promise<boolean>;
|
|
|
63
64
|
* @returns {Promise<void>} Resolves when copy is complete.
|
|
64
65
|
* @throws {Error} If source does not exist or copy fails.
|
|
65
66
|
*/
|
|
66
|
-
|
|
67
|
+
declare function copyDir(src: string, dest: string): Promise<void>;
|
|
67
68
|
/**
|
|
68
69
|
* Moves a directory to a new location by copying and deleting the original.
|
|
69
70
|
*
|
|
@@ -72,7 +73,7 @@ export declare function copyDir(src: string, dest: string): Promise<void>;
|
|
|
72
73
|
* @returns {Promise<void>} Resolves when move is complete.
|
|
73
74
|
* @throws {Error} If copy or deletion fails.
|
|
74
75
|
*/
|
|
75
|
-
|
|
76
|
+
declare function moveDir(src: string, dest: string): Promise<void>;
|
|
76
77
|
/**
|
|
77
78
|
* Empties a directory by deleting all files and subdirectories inside it.
|
|
78
79
|
*
|
|
@@ -80,7 +81,7 @@ export declare function moveDir(src: string, dest: string): Promise<void>;
|
|
|
80
81
|
* @returns {Promise<void>} Resolves when the directory has been emptied.
|
|
81
82
|
* @throws {Error} If files or subdirectories cannot be removed.
|
|
82
83
|
*/
|
|
83
|
-
|
|
84
|
+
declare function emptyDir(dirPath: string): Promise<void>;
|
|
84
85
|
/**
|
|
85
86
|
* Calculates the total size (in bytes) of all files in a directory (recursive).
|
|
86
87
|
*
|
|
@@ -88,7 +89,7 @@ export declare function emptyDir(dirPath: string): Promise<void>;
|
|
|
88
89
|
* @returns {Promise<number>} Total size in bytes.
|
|
89
90
|
* @throws {Error} If any file stats cannot be read.
|
|
90
91
|
*/
|
|
91
|
-
|
|
92
|
+
declare function getDirSize(dirPath: string): Promise<number>;
|
|
92
93
|
/**
|
|
93
94
|
* Watches a directory for file changes and calls a callback on each event.
|
|
94
95
|
*
|
|
@@ -96,7 +97,7 @@ export declare function getDirSize(dirPath: string): Promise<number>;
|
|
|
96
97
|
* @param {(eventType: "rename" | "change", filename: string | null) => void} callback - Callback for each change event.
|
|
97
98
|
* @returns {() => void} A function to stop watching the directory.
|
|
98
99
|
*/
|
|
99
|
-
|
|
100
|
+
declare function watchDir(dirPath: string, callback: (eventType: 'rename' | 'change', filename: string | null) => void): () => void;
|
|
100
101
|
/**
|
|
101
102
|
* Recursively finds files matching a simple pattern (supports '*' and '?').
|
|
102
103
|
*
|
|
@@ -106,7 +107,7 @@ export declare function watchDir(dirPath: string, callback: (eventType: 'rename'
|
|
|
106
107
|
* @param {boolean} [options.dot=false] - Include dotfiles in matches.
|
|
107
108
|
* @returns {Promise<string[]>} Array of matched file paths.
|
|
108
109
|
*/
|
|
109
|
-
|
|
110
|
+
declare function findFilesByPattern(pattern: string, options?: {
|
|
110
111
|
cwd?: string;
|
|
111
112
|
dot?: boolean;
|
|
112
113
|
}): Promise<string[]>;
|
|
@@ -118,7 +119,7 @@ export declare function findFilesByPattern(pattern: string, options?: {
|
|
|
118
119
|
* @returns {Promise<string[]>} Array of absolute subdirectory paths.
|
|
119
120
|
* @throws {Error} If directory cannot be read.
|
|
120
121
|
*/
|
|
121
|
-
|
|
122
|
+
declare function getSubdirectories(dirPath: string, recursive?: boolean): Promise<string[]>;
|
|
122
123
|
/**
|
|
123
124
|
* Ensures a directory exists and is empty.
|
|
124
125
|
*
|
|
@@ -126,7 +127,7 @@ export declare function getSubdirectories(dirPath: string, recursive?: boolean):
|
|
|
126
127
|
* @returns {Promise<void>} Resolves when the directory exists and is empty.
|
|
127
128
|
* @throws {Error} If directory cannot be created or emptied.
|
|
128
129
|
*/
|
|
129
|
-
|
|
130
|
+
declare function ensureEmptyDir(dirPath: string): Promise<void>;
|
|
130
131
|
/**
|
|
131
132
|
* Creates a temporary directory with optional auto-cleanup.
|
|
132
133
|
*
|
|
@@ -137,7 +138,7 @@ export declare function ensureEmptyDir(dirPath: string): Promise<void>;
|
|
|
137
138
|
* @returns {Promise<{ path: string, cleanup: () => Promise<void> }>} Object with directory path and cleanup function.
|
|
138
139
|
* @throws {Error} If directory cannot be created.
|
|
139
140
|
*/
|
|
140
|
-
|
|
141
|
+
declare function createTempDir(options?: {
|
|
141
142
|
prefix?: string;
|
|
142
143
|
parentDir?: string;
|
|
143
144
|
cleanup?: boolean;
|
|
@@ -153,7 +154,7 @@ export declare function createTempDir(options?: {
|
|
|
153
154
|
* @returns {Promise<string | null>} Path to the newest file or null if no files.
|
|
154
155
|
* @throws {Error} If directory cannot be read.
|
|
155
156
|
*/
|
|
156
|
-
|
|
157
|
+
declare function findNewestFile(dirPath: string, recursive?: boolean): Promise<string | null>;
|
|
157
158
|
/**
|
|
158
159
|
* Finds the oldest file in a directory.
|
|
159
160
|
*
|
|
@@ -162,7 +163,7 @@ export declare function findNewestFile(dirPath: string, recursive?: boolean): Pr
|
|
|
162
163
|
* @returns {Promise<string | null>} Path to the oldest file or null if no files.
|
|
163
164
|
* @throws {Error} If directory cannot be read.
|
|
164
165
|
*/
|
|
165
|
-
|
|
166
|
+
declare function findOldestFile(dirPath: string, recursive?: boolean): Promise<string | null>;
|
|
166
167
|
/**
|
|
167
168
|
* Finds files or directories in a directory matching a predicate function.
|
|
168
169
|
*
|
|
@@ -172,7 +173,7 @@ export declare function findOldestFile(dirPath: string, recursive?: boolean): Pr
|
|
|
172
173
|
* @returns {Promise<string[]>} Array of matching paths.
|
|
173
174
|
* @throws {Error} If directory cannot be read.
|
|
174
175
|
*/
|
|
175
|
-
|
|
176
|
+
declare function findInDir(dirPath: string, predicate: (path: string, stat: fs.Stats) => boolean | Promise<boolean>, recursive?: boolean): Promise<string[]>;
|
|
176
177
|
/**
|
|
177
178
|
* Watches a directory recursively for file changes.
|
|
178
179
|
*
|
|
@@ -182,7 +183,7 @@ export declare function findInDir(dirPath: string, predicate: (path: string, sta
|
|
|
182
183
|
* @returns {Promise<() => void>} A function to stop watching the directory.
|
|
183
184
|
* @throws {Error} If directory cannot be watched.
|
|
184
185
|
*/
|
|
185
|
-
|
|
186
|
+
declare function watchDirRecursive(dirPath: string, callback: (eventType: 'rename' | 'change', filename: string) => void, includeSubdirs?: boolean): Promise<() => void>;
|
|
186
187
|
/**
|
|
187
188
|
* Gets detailed directory statistics including file count, directory count, and size.
|
|
188
189
|
*
|
|
@@ -190,7 +191,7 @@ export declare function watchDirRecursive(dirPath: string, callback: (eventType:
|
|
|
190
191
|
* @returns {Promise<{ fileCount: number, dirCount: number, totalSize: number }>} Directory statistics.
|
|
191
192
|
* @throws {Error} If directory cannot be read.
|
|
192
193
|
*/
|
|
193
|
-
|
|
194
|
+
declare function getDirStats(dirPath: string): Promise<{
|
|
194
195
|
fileCount: number;
|
|
195
196
|
dirCount: number;
|
|
196
197
|
totalSize: number;
|
|
@@ -205,7 +206,7 @@ export declare function getDirStats(dirPath: string): Promise<{
|
|
|
205
206
|
* @param {'pre' | 'post'} [options.traversalOrder='pre'] - Whether to visit directories before or after their contents.
|
|
206
207
|
* @throws {Error} If directory cannot be read.
|
|
207
208
|
*/
|
|
208
|
-
|
|
209
|
+
declare function walkDir(dirPath: string, options: {
|
|
209
210
|
visitorFn: (entry: {
|
|
210
211
|
path: string;
|
|
211
212
|
name: string;
|
|
@@ -214,3 +215,5 @@ export declare function walkDir(dirPath: string, options: {
|
|
|
214
215
|
}) => boolean | void | Promise<boolean | void>;
|
|
215
216
|
traversalOrder?: 'pre' | 'post';
|
|
216
217
|
}): Promise<void>;
|
|
218
|
+
|
|
219
|
+
export { copyDir, createTempDir, deleteDirRecursive, emptyDir, ensureDir, ensureEmptyDir, findFilesByPattern, findInDir, findNewestFile, findOldestFile, getDirSize, getDirStats, getSubdirectories, isDirectory, listFiles, moveDir, walkDir, watchDir, watchDirRecursive };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* The MIT License
|
|
3
3
|
*
|
|
4
|
-
* Copyright (c)
|
|
4
|
+
* Copyright (c) 2026 Catbee Technologies. https://catbee.in/license
|
|
5
5
|
*
|
|
6
6
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
* of this software and associated documentation files (the "Software"), to deal
|
|
@@ -133,7 +133,7 @@ function watchDir(dirPath, callback) {
|
|
|
133
133
|
__name(watchDir, "watchDir");
|
|
134
134
|
async function findFilesByPattern(pattern, options = {}) {
|
|
135
135
|
const matchPattern = /* @__PURE__ */ __name((name, pattern2) => {
|
|
136
|
-
let escaped = pattern2.replaceAll(/[.+^${}()|[\]\\]/g,
|
|
136
|
+
let escaped = pattern2.replaceAll(/[.+^${}()|[\]\\]/g, String.raw`\$&`);
|
|
137
137
|
escaped = escaped.replaceAll("*", ".*").replaceAll("?", ".");
|
|
138
138
|
const regex = new RegExp(`^${escaped}$`);
|
|
139
139
|
return regex.test(name);
|
|
@@ -143,7 +143,7 @@ async function findFilesByPattern(pattern, options = {}) {
|
|
|
143
143
|
async function walk(dir, segIndex) {
|
|
144
144
|
if (segIndex >= segments.length) return [];
|
|
145
145
|
const segment = segments[segIndex];
|
|
146
|
-
const entries = await
|
|
146
|
+
const entries = await fsp.readdir(dir, {
|
|
147
147
|
withFileTypes: true
|
|
148
148
|
});
|
|
149
149
|
let matchedFiles = [];
|
|
@@ -245,7 +245,8 @@ async function findNewestFile(dirPath, recursive = false) {
|
|
|
245
245
|
path: file,
|
|
246
246
|
mtime: (await fsp.stat(file)).mtime
|
|
247
247
|
})));
|
|
248
|
-
|
|
248
|
+
const sorted = stats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
249
|
+
return sorted[0].path;
|
|
249
250
|
}
|
|
250
251
|
__name(findNewestFile, "findNewestFile");
|
|
251
252
|
async function findOldestFile(dirPath, recursive = false) {
|
package/env/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* The MIT License
|
|
3
3
|
*
|
|
4
|
-
* Copyright (c)
|
|
4
|
+
* Copyright (c) 2026 Catbee Technologies. https://catbee.in/license
|
|
5
5
|
*
|
|
6
6
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
* of this software and associated documentation files (the "Software"), to deal
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
|
|
27
27
|
var fs = require('fs');
|
|
28
28
|
var path = require('path');
|
|
29
|
+
var date = require('@catbee/utils/date');
|
|
30
|
+
var validation = require('@catbee/utils/validation');
|
|
29
31
|
|
|
30
32
|
var __defProp = Object.defineProperty;
|
|
31
33
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
@@ -83,9 +85,7 @@ var Env = class _Env {
|
|
|
83
85
|
static set(key, value) {
|
|
84
86
|
process.env[key] = value;
|
|
85
87
|
this.cache.delete(key);
|
|
86
|
-
for (const cacheKey of
|
|
87
|
-
...this.cache.keys()
|
|
88
|
-
]) {
|
|
88
|
+
for (const cacheKey of this.cache.keys()) {
|
|
89
89
|
if (cacheKey.includes(`:${key}`)) {
|
|
90
90
|
this.cache.delete(cacheKey);
|
|
91
91
|
}
|
|
@@ -114,7 +114,7 @@ var Env = class _Env {
|
|
|
114
114
|
*/
|
|
115
115
|
static get(key, defaultValue) {
|
|
116
116
|
let value = process.env[key] ?? defaultValue;
|
|
117
|
-
if (value
|
|
117
|
+
if (value?.includes("${")) {
|
|
118
118
|
value = value.replace(/\${([A-Za-z0-9_]+)}/g, (_, varName) => {
|
|
119
119
|
return process.env[varName] ?? "";
|
|
120
120
|
});
|
|
@@ -172,7 +172,7 @@ var Env = class _Env {
|
|
|
172
172
|
return defaultValue;
|
|
173
173
|
}
|
|
174
174
|
const numberValue = Number(value);
|
|
175
|
-
if (isNaN(numberValue)) {
|
|
175
|
+
if (Number.isNaN(numberValue)) {
|
|
176
176
|
throw new Error(`Environment variable '${key}' is not a valid number, got: "${value}"`);
|
|
177
177
|
}
|
|
178
178
|
this.cache.set(`number:${key}`, numberValue);
|
|
@@ -363,7 +363,7 @@ var Env = class _Env {
|
|
|
363
363
|
static getNumberArray(key, defaultValue = [], splitter = ",") {
|
|
364
364
|
return _Env.getArray(key, defaultValue, splitter, (item) => {
|
|
365
365
|
const num = Number(item);
|
|
366
|
-
if (isNaN(num)) {
|
|
366
|
+
if (Number.isNaN(num)) {
|
|
367
367
|
throw new Error(`Value "${item}" in array '${key}' is not a valid number`);
|
|
368
368
|
}
|
|
369
369
|
return num;
|
|
@@ -439,20 +439,33 @@ var Env = class _Env {
|
|
|
439
439
|
if (!value) {
|
|
440
440
|
throw new Error(`URL environment variable '${key}' is missing or empty`);
|
|
441
441
|
}
|
|
442
|
-
|
|
442
|
+
const url = this.parseUrl(value, key);
|
|
443
|
+
this.validateProtocol(url, key, options);
|
|
444
|
+
this.validateHostname(url, key, options);
|
|
445
|
+
this.cache.set(cacheKey, value);
|
|
446
|
+
return value;
|
|
447
|
+
}
|
|
448
|
+
static parseUrl(value, key) {
|
|
443
449
|
try {
|
|
444
|
-
|
|
450
|
+
return new URL(value);
|
|
445
451
|
} catch {
|
|
446
452
|
throw new Error(`Environment variable '${key}' is not a valid URL: "${value}"`);
|
|
447
453
|
}
|
|
454
|
+
}
|
|
455
|
+
static validateProtocol(url, key, options) {
|
|
448
456
|
if (options.protocols && options.protocols.length > 0) {
|
|
449
457
|
const protocol = url.protocol.replace(":", "");
|
|
450
458
|
if (!options.protocols.includes(protocol)) {
|
|
451
459
|
throw new Error(`Environment variable '${key}' must use one of the protocols: ${options.protocols.join(", ")}. Got: ${protocol}`);
|
|
452
460
|
}
|
|
453
461
|
}
|
|
462
|
+
}
|
|
463
|
+
static isIp(hostname) {
|
|
464
|
+
return /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(hostname);
|
|
465
|
+
}
|
|
466
|
+
static validateHostname(url, key, options) {
|
|
454
467
|
const { hostname } = url;
|
|
455
|
-
const isIp =
|
|
468
|
+
const isIp = _Env.isIp(hostname);
|
|
456
469
|
const isLocalhost = hostname === "localhost";
|
|
457
470
|
if (isIp && options.allowIp === false) {
|
|
458
471
|
throw new Error(`Environment variable '${key}' cannot be an IP address: "${hostname}"`);
|
|
@@ -465,8 +478,6 @@ var Env = class _Env {
|
|
|
465
478
|
throw new Error(`Environment variable '${key}' must have a valid host with TLD: "${hostname}"`);
|
|
466
479
|
}
|
|
467
480
|
}
|
|
468
|
-
this.cache.set(cacheKey, value);
|
|
469
|
-
return value;
|
|
470
481
|
}
|
|
471
482
|
/**
|
|
472
483
|
* Retrieves an email environment variable and validates it.
|
|
@@ -490,8 +501,7 @@ var Env = class _Env {
|
|
|
490
501
|
}
|
|
491
502
|
return defaultValue;
|
|
492
503
|
}
|
|
493
|
-
|
|
494
|
-
if (!emailRegex.test(value)) {
|
|
504
|
+
if (!validation.isEmail(value)) {
|
|
495
505
|
throw new Error(`Environment variable '${key}' is not a valid email address: "${value}"`);
|
|
496
506
|
}
|
|
497
507
|
this.cache.set(`email:${key}`, value);
|
|
@@ -579,7 +589,7 @@ var Env = class _Env {
|
|
|
579
589
|
return defaultValue instanceof Date ? defaultValue : /* @__PURE__ */ new Date();
|
|
580
590
|
}
|
|
581
591
|
const date = new Date(value);
|
|
582
|
-
if (isNaN(date.getTime())) {
|
|
592
|
+
if (Number.isNaN(date.getTime())) {
|
|
583
593
|
throw new Error(`Environment variable '${key}' is not a valid date: "${value}"`);
|
|
584
594
|
}
|
|
585
595
|
return date;
|
|
@@ -603,26 +613,9 @@ var Env = class _Env {
|
|
|
603
613
|
if (this.cache.has(cacheKey)) {
|
|
604
614
|
return this.cache.get(cacheKey);
|
|
605
615
|
}
|
|
606
|
-
const
|
|
607
|
-
if (!
|
|
608
|
-
|
|
609
|
-
const ms2 = parseInt(value, 10);
|
|
610
|
-
this.cache.set(cacheKey, ms2);
|
|
611
|
-
return ms2;
|
|
612
|
-
}
|
|
613
|
-
const durationRegex = /^(?:(\d+)y)?(?:(\d+)w)?(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?(?:(\d+)ms)?$/;
|
|
614
|
-
const matches = value.match(durationRegex);
|
|
615
|
-
if (!matches || matches[0] === "") {
|
|
616
|
-
throw new Error(`Environment variable '${key}' has invalid duration format: "${value}". Use formats like 1y, 2w, 3d, 4h, 5m, 6s, or 7ms.`);
|
|
617
|
-
}
|
|
618
|
-
let ms = 0;
|
|
619
|
-
if (matches[1]) ms += parseInt(matches[1], 10) * 31536e6;
|
|
620
|
-
if (matches[2]) ms += parseInt(matches[2], 10) * 6048e5;
|
|
621
|
-
if (matches[3]) ms += parseInt(matches[3], 10) * 864e5;
|
|
622
|
-
if (matches[4]) ms += parseInt(matches[4], 10) * 36e5;
|
|
623
|
-
if (matches[5]) ms += parseInt(matches[5], 10) * 6e4;
|
|
624
|
-
if (matches[6]) ms += parseInt(matches[6], 10) * 1e3;
|
|
625
|
-
if (matches[7]) ms += parseInt(matches[7], 10);
|
|
616
|
+
const raw = _Env.get(key, String(defaultValue));
|
|
617
|
+
if (!raw) return 0;
|
|
618
|
+
const ms = date.parseDuration(raw);
|
|
626
619
|
this.cache.set(cacheKey, ms);
|
|
627
620
|
return ms;
|
|
628
621
|
}
|
|
@@ -667,63 +660,102 @@ var Env = class _Env {
|
|
|
667
660
|
throw new Error(`Environment file not found: "${path}"`);
|
|
668
661
|
}
|
|
669
662
|
const content = fs.readFileSync(path, "utf8");
|
|
663
|
+
const variables = this.parseEnvContent(content);
|
|
664
|
+
for (const [k, v] of Object.entries(variables)) {
|
|
665
|
+
if (!process.env[k]) {
|
|
666
|
+
process.env[k] = v;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return variables;
|
|
670
|
+
}
|
|
671
|
+
static parseEnvContent(content) {
|
|
670
672
|
const variables = {};
|
|
671
673
|
const lines = content.split(/\r?\n/);
|
|
672
674
|
let i = 0;
|
|
673
675
|
while (i < lines.length) {
|
|
674
676
|
let line = lines[i].trim();
|
|
675
|
-
if (
|
|
677
|
+
if (this.isCommentOrEmpty(line)) {
|
|
676
678
|
i++;
|
|
677
679
|
continue;
|
|
678
680
|
}
|
|
679
|
-
const match =
|
|
681
|
+
const match = this.extractKeyValue(line);
|
|
680
682
|
if (!match) {
|
|
681
683
|
i++;
|
|
682
684
|
continue;
|
|
683
685
|
}
|
|
684
686
|
const key = match[1].trim();
|
|
685
687
|
let value = match[2].trim();
|
|
686
|
-
if (
|
|
687
|
-
|
|
688
|
-
if (hashIndex !== -1) {
|
|
689
|
-
value = value.slice(0, hashIndex).trim();
|
|
690
|
-
}
|
|
688
|
+
if (!this.isQuoted(value)) {
|
|
689
|
+
value = this.stripInlineComment(value);
|
|
691
690
|
}
|
|
692
|
-
if (
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
i++;
|
|
697
|
-
while (i < lines.length) {
|
|
698
|
-
const nextLine = lines[i];
|
|
699
|
-
if (nextLine.endsWith(quote)) {
|
|
700
|
-
multilineValue += "\n" + nextLine.slice(0, -1);
|
|
701
|
-
break;
|
|
702
|
-
} else {
|
|
703
|
-
multilineValue += "\n" + nextLine;
|
|
704
|
-
}
|
|
705
|
-
i++;
|
|
706
|
-
}
|
|
707
|
-
value = multilineValue;
|
|
708
|
-
} else {
|
|
709
|
-
value = value.slice(1, -1);
|
|
710
|
-
}
|
|
691
|
+
if (this.isQuoted(value) && value.length > 1) {
|
|
692
|
+
const result = this.parseQuotedValue(lines, i, value);
|
|
693
|
+
value = result.value;
|
|
694
|
+
i = result.nextIndex;
|
|
711
695
|
} else {
|
|
712
|
-
i
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
i++;
|
|
716
|
-
}
|
|
717
|
-
i--;
|
|
696
|
+
const result = this.parseUnquotedMultiline(lines, i, value);
|
|
697
|
+
value = result.value;
|
|
698
|
+
i = result.nextIndex;
|
|
718
699
|
}
|
|
719
700
|
if (!process.env[key]) {
|
|
720
|
-
process.env[key] = value;
|
|
721
701
|
variables[key] = value;
|
|
722
702
|
}
|
|
723
703
|
i++;
|
|
724
704
|
}
|
|
725
705
|
return variables;
|
|
726
706
|
}
|
|
707
|
+
static isCommentOrEmpty(line) {
|
|
708
|
+
return !line || line.startsWith("#");
|
|
709
|
+
}
|
|
710
|
+
static extractKeyValue(line) {
|
|
711
|
+
return line.match(/^([^=]+)=(.*)$/);
|
|
712
|
+
}
|
|
713
|
+
static isQuoted(value) {
|
|
714
|
+
return /^['"]/.test(value);
|
|
715
|
+
}
|
|
716
|
+
static stripInlineComment(value) {
|
|
717
|
+
const hashIndex = value.indexOf(" #");
|
|
718
|
+
if (hashIndex !== -1) {
|
|
719
|
+
return value.slice(0, hashIndex).trim();
|
|
720
|
+
}
|
|
721
|
+
return value;
|
|
722
|
+
}
|
|
723
|
+
static parseQuotedValue(lines, currentIndex, value) {
|
|
724
|
+
const quote = value[0];
|
|
725
|
+
if (!value.endsWith(quote) || value.length === 1) {
|
|
726
|
+
let multilineValue = value.slice(1);
|
|
727
|
+
let i = currentIndex + 1;
|
|
728
|
+
while (i < lines.length) {
|
|
729
|
+
const nextLine = lines[i];
|
|
730
|
+
if (nextLine.endsWith(quote)) {
|
|
731
|
+
multilineValue += "\n" + nextLine.slice(0, -1);
|
|
732
|
+
break;
|
|
733
|
+
} else {
|
|
734
|
+
multilineValue += "\n" + nextLine;
|
|
735
|
+
}
|
|
736
|
+
i++;
|
|
737
|
+
}
|
|
738
|
+
return {
|
|
739
|
+
value: multilineValue,
|
|
740
|
+
nextIndex: i
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
return {
|
|
744
|
+
value: value.slice(1, -1),
|
|
745
|
+
nextIndex: currentIndex
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
static parseUnquotedMultiline(lines, currentIndex, value) {
|
|
749
|
+
let i = currentIndex + 1;
|
|
750
|
+
while (i < lines.length && !lines[i].includes("=") && lines[i].trim() !== "") {
|
|
751
|
+
value += "\n" + lines[i];
|
|
752
|
+
i++;
|
|
753
|
+
}
|
|
754
|
+
return {
|
|
755
|
+
value,
|
|
756
|
+
nextIndex: i - 1
|
|
757
|
+
};
|
|
758
|
+
}
|
|
727
759
|
/**
|
|
728
760
|
* Checks whether the specified environment variable exists.
|
|
729
761
|
*
|