@ix-xs/node-comfort 1.1.3 → 1.2.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.
@@ -0,0 +1,303 @@
1
+ /**
2
+ * Reads an environment variable from process.env.
3
+ * @param {string} value - The environment variable name.
4
+ * @param {string} [envFilePath] - Reserved for future use.
5
+ * @returns {string|undefined} The environment value, or undefined if not set.
6
+ */
7
+ export function getEnv(value: string, envFilePath?: string): string | undefined;
8
+ /**
9
+ * Resolves a path even when it does not already exist.
10
+ * @param {string} [path=process.cwd()] - The path to resolve.
11
+ * @returns {string} The resolved path.
12
+ */
13
+ export function createPath(path?: string): string;
14
+ /**
15
+ * Returns folders found inside a path.
16
+ * @param {string} [path=process.cwd()] - The base path to inspect.
17
+ * @param {boolean} [recursive=true] - Whether to scan recursively.
18
+ * @returns {string[]|undefined} Matching folders, or undefined if the path cannot be resolved.
19
+ */
20
+ export function getFoldersIn(path?: string, recursive?: boolean): string[] | undefined;
21
+ /**
22
+ * Returns the resolved folder path.
23
+ * @param {string} [path=process.cwd()] - The folder path to resolve.
24
+ * @returns {string|undefined} The resolved folder path, or undefined if not found.
25
+ */
26
+ export function getFolder(path?: string): string | undefined;
27
+ /**
28
+ * Returns files found inside a path.
29
+ * @param {string} [path=process.cwd()] - The base path to inspect.
30
+ * @param {boolean} [recursive=true] - Whether to scan recursively.
31
+ * @returns {string[]|undefined} Matching files, or undefined if the path cannot be resolved.
32
+ */
33
+ export function getFilesIn(path?: string, recursive?: boolean): string[] | undefined;
34
+ /**
35
+ * Returns the resolved file path.
36
+ * @param {string} path - The file path to resolve.
37
+ * @returns {string|undefined} The resolved file path, or undefined if not found.
38
+ */
39
+ export function getFile(path: string): string | undefined;
40
+ /**
41
+ * Creates a folder.
42
+ * @param {string} path - The folder path to create.
43
+ * @param {boolean} [force=false] - Whether to recreate the folder if it already exists.
44
+ * @returns {boolean|undefined} True on success, false on failure, undefined if no path was provided.
45
+ */
46
+ export function createFolder(path: string, force?: boolean): boolean | undefined;
47
+ /**
48
+ * Creates a file.
49
+ * @param {string} path - The file path to create.
50
+ * @param {boolean} [force=false] - Whether to recreate the file if it already exists.
51
+ * @param {string|object|null|undefined} [data] - File content to write.
52
+ * @returns {boolean|undefined} True on success, false on failure, undefined if no path was provided.
53
+ */
54
+ export function createFile(path: string, force?: boolean, data?: string | object | null | undefined): boolean | undefined;
55
+ /**
56
+ * Deletes folders found inside a path.
57
+ * @param {string} [path=process.cwd()] - The base path to inspect.
58
+ * @param {(folder: string) => boolean} [filter=() => true] - Filter applied to each folder path.
59
+ * @returns {number|undefined} Number of deleted folders, or undefined if the path cannot be resolved.
60
+ */
61
+ export function deleteFoldersIn(path?: string, filter?: (folder: string) => boolean): number | undefined;
62
+ /**
63
+ * Deletes a folder.
64
+ * @param {string} path - The folder path to delete.
65
+ * @returns {boolean|undefined} True on success, false on failure, undefined if the path is invalid.
66
+ */
67
+ export function deleteFolder(path: string): boolean | undefined;
68
+ /**
69
+ * Deletes files found inside a path.
70
+ * @param {string} [path=process.cwd()] - The base path to inspect.
71
+ * @param {boolean} [recursive=false] - Whether to scan recursively.
72
+ * @param {(file: string) => boolean} [filter=() => true] - Filter applied to each file path.
73
+ * @returns {number|undefined} Number of deleted files, or undefined if the path cannot be resolved.
74
+ */
75
+ export function deleteFilesIn(path?: string, recursive?: boolean, filter?: (file: string) => boolean): number | undefined;
76
+ /**
77
+ * Deletes a file.
78
+ * @param {string} path - The file path to delete.
79
+ * @returns {boolean|undefined} True on success, false on failure, undefined if the path is invalid.
80
+ */
81
+ export function deleteFile(path: string): boolean | undefined;
82
+ /**
83
+ * Copies folders from a source path into a destination folder.
84
+ * @param {Object} options - Copy options.
85
+ * @param {string} options.dest - Destination path.
86
+ * @param {string} [options.path] - Source path.
87
+ * @param {boolean} [options.recursive=true] - Whether to recurse into subfolders.
88
+ * @param {boolean} [options.withFiles=false] - Whether to copy files as well.
89
+ * @param {boolean} [options.force=false] - Whether to overwrite existing folders.
90
+ * @param {(folder: string) => boolean} [options.filter=() => true] - Filter applied to each folder.
91
+ * @returns {number|undefined} Number of copied folders, or undefined if invalid input.
92
+ */
93
+ export function copyFoldersIn(options: {
94
+ dest: string;
95
+ path?: string | undefined;
96
+ recursive?: boolean | undefined;
97
+ withFiles?: boolean | undefined;
98
+ force?: boolean | undefined;
99
+ filter?: ((folder: string) => boolean) | undefined;
100
+ }): number | undefined;
101
+ /**
102
+ * Copies a folder to a destination path.
103
+ * @param {Object} options - Copy options.
104
+ * @param {string} options.dest - Destination path.
105
+ * @param {string} [options.path] - Source path.
106
+ * @param {boolean} [options.recursive=false] - Whether to copy subfolders.
107
+ * @param {boolean} [options.withFiles=false] - Whether to copy files.
108
+ * @param {boolean} [options.force=false] - Whether to overwrite the destination.
109
+ * @returns {boolean|undefined} True on success, false on failure, undefined if invalid input.
110
+ */
111
+ export function copyFolder(options: {
112
+ dest: string;
113
+ path?: string | undefined;
114
+ recursive?: boolean | undefined;
115
+ withFiles?: boolean | undefined;
116
+ force?: boolean | undefined;
117
+ }): boolean | undefined;
118
+ /**
119
+ * Copies files from a source path into a destination folder.
120
+ * @param {Object} options - Copy options.
121
+ * @param {string} options.dest - Destination path.
122
+ * @param {string} [options.path] - Source path.
123
+ * @param {boolean} [options.recursive=true] - Whether to recurse into subfolders.
124
+ * @param {boolean} [options.force=false] - Whether to overwrite existing files.
125
+ * @param {(file: string) => boolean} [options.filter=() => true] - Filter applied to each file.
126
+ * @returns {number|undefined} Number of copied files, or undefined if invalid input.
127
+ */
128
+ export function copyFilesIn(options: {
129
+ dest: string;
130
+ path?: string | undefined;
131
+ recursive?: boolean | undefined;
132
+ force?: boolean | undefined;
133
+ filter?: ((file: string) => boolean) | undefined;
134
+ }): number | undefined;
135
+ /**
136
+ * Copies a file to a destination path.
137
+ * @param {Object} options - Copy options.
138
+ * @param {string} options.path - Source file path.
139
+ * @param {string} options.dest - Destination path.
140
+ * @param {boolean} [options.force=false] - Whether to overwrite the destination file.
141
+ * @returns {boolean|undefined} True on success, false on failure, undefined if invalid input.
142
+ */
143
+ export function copyFile(options: {
144
+ path: string;
145
+ dest: string;
146
+ force?: boolean | undefined;
147
+ }): boolean | undefined;
148
+ /**
149
+ * Moves folders from a source path into a destination folder.
150
+ * @param {Object} options - Move options.
151
+ * @param {string} options.dest - Destination path.
152
+ * @param {string} [options.path] - Source path.
153
+ * @param {boolean} [options.recursive=true] - Whether to recurse into subfolders.
154
+ * @param {boolean} [options.withFiles=false] - Whether to move files as well.
155
+ * @param {boolean} [options.force=false] - Whether to overwrite existing folders.
156
+ * @param {(folder: string) => boolean} [options.filter=() => true] - Filter applied to each folder.
157
+ * @returns {number|undefined} Number of copied folders, or undefined if invalid input.
158
+ */
159
+ export function moveFoldersIn(options: {
160
+ dest: string;
161
+ path?: string | undefined;
162
+ recursive?: boolean | undefined;
163
+ withFiles?: boolean | undefined;
164
+ force?: boolean | undefined;
165
+ filter?: ((folder: string) => boolean) | undefined;
166
+ }): number | undefined;
167
+ /**
168
+ * Moves a folder to a destination path.
169
+ * @param {Object} options - Move options.
170
+ * @param {string} options.path - Source folder path.
171
+ * @param {string} options.dest - Destination path.
172
+ * @param {boolean} [options.recursive=false] - Whether to move subfolders.
173
+ * @param {boolean} [options.withFiles=false] - Whether to move files.
174
+ * @param {boolean} [options.force=false] - Whether to overwrite the destination.
175
+ * @returns {boolean|undefined} True on success, false on failure, undefined if invalid input.
176
+ */
177
+ export function moveFolder(options: {
178
+ path: string;
179
+ dest: string;
180
+ recursive?: boolean | undefined;
181
+ withFiles?: boolean | undefined;
182
+ force?: boolean | undefined;
183
+ }): boolean | undefined;
184
+ /**
185
+ * Moves files from a source path into a destination folder.
186
+ * @param {Object} options - Move options.
187
+ * @param {string} options.dest - Destination path.
188
+ * @param {string} [options.path] - Source path.
189
+ * @param {boolean} [options.recursive=true] - Whether to recurse into subfolders.
190
+ * @param {boolean} [options.force=false] - Whether to overwrite existing files.
191
+ * @param {(file: string) => boolean} [options.filter=() => true] - Filter applied to each file.
192
+ * @returns {number|undefined} Number of copied files, or undefined if invalid input.
193
+ */
194
+ export function moveFilesIn(options: {
195
+ dest: string;
196
+ path?: string | undefined;
197
+ recursive?: boolean | undefined;
198
+ force?: boolean | undefined;
199
+ filter?: ((file: string) => boolean) | undefined;
200
+ }): number | undefined;
201
+ /**
202
+ * Moves a file to a destination path.
203
+ * @param {Object} options - Move options.
204
+ * @param {string} options.path - Source file path.
205
+ * @param {string} options.dest - Destination path.
206
+ * @param {boolean} [options.force=false] - Whether to overwrite the destination file.
207
+ * @returns {boolean|undefined} True on success, false on failure, undefined if invalid input.
208
+ */
209
+ export function moveFile(options: {
210
+ path: string;
211
+ dest: string;
212
+ force?: boolean | undefined;
213
+ }): boolean | undefined;
214
+ /**
215
+ * Reads a file as UTF-8 text.
216
+ * @param {string} path - The file path to read.
217
+ * @returns {string|undefined} File content, or undefined if the file cannot be read.
218
+ */
219
+ export function readFile(path: string): string | undefined;
220
+ /**
221
+ * Reads and parses a JSON file.
222
+ * @template T
223
+ * @param {string} path - The JSON file path.
224
+ * @param {T} [fallback] - Value returned when the file is missing or invalid.
225
+ * @returns {T|any|undefined} The parsed value, or the fallback.
226
+ */
227
+ export function readJSON<T>(path: string, fallback?: T): T | any | undefined;
228
+ /**
229
+ * Serializes a value to JSON and writes it to a file (creating folders as needed).
230
+ * @param {string} path - The destination file path.
231
+ * @param {*} data - The value to serialize.
232
+ * @param {{ spaces?: number, force?: boolean }} [options] - Formatting options (`spaces` default 2).
233
+ * @returns {boolean} True on success, false on failure.
234
+ */
235
+ export function writeJSON(path: string, data: any, options?: {
236
+ spaces?: number;
237
+ force?: boolean;
238
+ }): boolean;
239
+ /**
240
+ * Appends text to a file, creating it (and its folders) if necessary.
241
+ * @param {string} path - The file path.
242
+ * @param {string} data - The text to append.
243
+ * @returns {boolean} True on success, false on failure.
244
+ */
245
+ export function appendFile(path: string, data: string): boolean;
246
+ /**
247
+ * Checks whether a path (file or folder) exists.
248
+ * @param {string} path - The path to check.
249
+ * @returns {boolean} True if the path exists.
250
+ */
251
+ export function exists(path: string): boolean;
252
+ /**
253
+ * Returns filesystem stats for a path, or undefined if it does not exist.
254
+ * @param {string} path - The path to stat.
255
+ * @returns {import("node:fs").Stats|undefined} The stats object, or undefined.
256
+ */
257
+ export function stat(path: string): any | undefined;
258
+ /**
259
+ * Returns the size of a file in bytes.
260
+ * @param {string} path - The file path.
261
+ * @returns {number|undefined} Size in bytes, or undefined if not found.
262
+ */
263
+ export function fileSize(path: string): number | undefined;
264
+ /**
265
+ * Computes a hash digest of a file's contents.
266
+ * @param {string} path - The file path.
267
+ * @param {{ algorithm?: string, encoding?: "hex"|"base64"|"base64url" }} [options] - Hash options.
268
+ * @returns {string|undefined} The digest, or undefined if the file cannot be read.
269
+ */
270
+ export function hashFile(path: string, options?: {
271
+ algorithm?: string;
272
+ encoding?: "hex" | "base64" | "base64url";
273
+ }): string | undefined;
274
+ /**
275
+ * Empties a folder's contents while keeping the folder itself.
276
+ * @param {string} path - The folder to empty.
277
+ * @returns {boolean|undefined} True on success, false on failure, undefined if not found.
278
+ */
279
+ export function emptyFolder(path: string): boolean | undefined;
280
+ /**
281
+ * Watches a path and exposes event listeners.
282
+ * @param {Object} [options] - Watch options.
283
+ * @param {string} [options.path=process.cwd()] - Path to watch.
284
+ * @param {boolean} [options.recursive=false] - Whether to watch recursively.
285
+ * @param {(event: "rename"|"change", file: string) => boolean} [options.filter] - Filter applied before dispatch.
286
+ * @returns {{
287
+ * on: <E extends "change"|"rename"|"all">(event: E, callback: E extends "all" ? (event: "change"|"rename", file: string) => void|Promise<void> : (file: string) => void|Promise<void>) => any,
288
+ * stop: () => void,
289
+ * pause: () => any,
290
+ * resume: () => any,
291
+ * }|undefined} Watch controller, or undefined if the path cannot be resolved.
292
+ */
293
+ export function watch(options?: {
294
+ path?: string | undefined;
295
+ recursive?: boolean | undefined;
296
+ filter?: ((event: "rename" | "change", file: string) => boolean) | undefined;
297
+ }): {
298
+ on: <E extends "change" | "rename" | "all">(event: E, callback: E extends "all" ? (event: "change" | "rename", file: string) => void | Promise<void> : (file: string) => void | Promise<void>) => any;
299
+ stop: () => void;
300
+ pause: () => any;
301
+ resume: () => any;
302
+ } | undefined;
303
+ //# sourceMappingURL=FS.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FS.d.ts","sourceRoot":"","sources":["../../src/FS.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Creates a debounced version of a function that delays invocation until
3
+ * `wait` ms have elapsed since the last call.
4
+ *
5
+ * The returned function exposes `.cancel()` and `.flush()`.
6
+ *
7
+ * @example
8
+ * const onResize = nodeComfort.func.debounce(() => render(), 200);
9
+ * window.on("resize", onResize);
10
+ * onResize.cancel(); // drop any pending call
11
+ *
12
+ * @template {(...args: any[]) => any} F
13
+ * @param {F} fn - Function to debounce.
14
+ * @param {number} wait - Delay in milliseconds.
15
+ * @param {{ leading?: boolean }} [options] - Set `leading` to fire on the first call.
16
+ * @returns {F & { cancel: () => void, flush: () => void }} The debounced function.
17
+ */
18
+ export function debounce<F extends (...args: any[]) => any>(fn: F, wait: number, options?: {
19
+ leading?: boolean;
20
+ }): F & {
21
+ cancel: () => void;
22
+ flush: () => void;
23
+ };
24
+ /**
25
+ * Creates a throttled version of a function that runs at most once per
26
+ * `wait` ms.
27
+ *
28
+ * @example
29
+ * const onScroll = nodeComfort.func.throttle(() => update(), 100);
30
+ *
31
+ * @template {(...args: any[]) => any} F
32
+ * @param {F} fn - Function to throttle.
33
+ * @param {number} wait - Minimum interval in milliseconds.
34
+ * @param {{ trailing?: boolean }} [options] - Set `trailing` (default true) to run a final call.
35
+ * @returns {F & { cancel: () => void }} The throttled function.
36
+ */
37
+ export function throttle<F extends (...args: any[]) => any>(fn: F, wait: number, options?: {
38
+ trailing?: boolean;
39
+ }): F & {
40
+ cancel: () => void;
41
+ };
42
+ /**
43
+ * Wraps a function so it can only ever run once; subsequent calls return
44
+ * the first result.
45
+ *
46
+ * @example
47
+ * const init = nodeComfort.func.once(() => expensiveSetup());
48
+ *
49
+ * @template {(...args: any[]) => any} F
50
+ * @param {F} fn - Function to wrap.
51
+ * @returns {F} The single-call function.
52
+ */
53
+ export function once<F extends (...args: any[]) => any>(fn: F): F;
54
+ /**
55
+ * Memoizes a function, caching results by argument key.
56
+ *
57
+ * By default the cache key is a JSON serialization of the arguments; pass a
58
+ * `resolver` for custom keys.
59
+ *
60
+ * @example
61
+ * const fib = nodeComfort.func.memoize((n) => (n < 2 ? n : fib(n - 1) + fib(n - 2)));
62
+ *
63
+ * @template {(...args: any[]) => any} F
64
+ * @param {F} fn - Function to memoize.
65
+ * @param {(...args: any[]) => any} [resolver] - Cache-key resolver.
66
+ * @returns {F & { cache: Map<any, any> }} The memoized function.
67
+ */
68
+ export function memoize<F extends (...args: any[]) => any>(fn: F, resolver?: (...args: any[]) => any): F & {
69
+ cache: Map<any, any>;
70
+ };
71
+ /**
72
+ * Retries an async function until it succeeds or the attempt budget runs out.
73
+ *
74
+ * Supports fixed or exponential backoff and a `shouldRetry` guard.
75
+ *
76
+ * @example
77
+ * const data = await nodeComfort.func.retry(() => fetch(url), {
78
+ * attempts: 5,
79
+ * delay: 200,
80
+ * backoff: 2, // 200, 400, 800, ...
81
+ * });
82
+ *
83
+ * @template T
84
+ * @param {() => T|Promise<T>} fn - Function to run.
85
+ * @param {{
86
+ * attempts?: number,
87
+ * delay?: number,
88
+ * backoff?: number,
89
+ * maxDelay?: number,
90
+ * shouldRetry?: (error: unknown, attempt: number) => boolean,
91
+ * onRetry?: (error: unknown, attempt: number) => void
92
+ * }} [options] - Retry options.
93
+ * @returns {Promise<T>} The resolved value.
94
+ * @throws Re-throws the last error if all attempts fail.
95
+ */
96
+ export function retry<T>(fn: () => T | Promise<T>, options?: {
97
+ attempts?: number;
98
+ delay?: number;
99
+ backoff?: number;
100
+ maxDelay?: number;
101
+ shouldRetry?: (error: unknown, attempt: number) => boolean;
102
+ onRetry?: (error: unknown, attempt: number) => void;
103
+ }): Promise<T>;
104
+ /**
105
+ * Runs a promise (or async function) with a timeout, rejecting if it takes
106
+ * too long.
107
+ *
108
+ * @example
109
+ * await nodeComfort.func.timeout(fetch(url), 5000, "fetch too slow");
110
+ *
111
+ * @template T
112
+ * @param {Promise<T>|(() => Promise<T>)} promise - Promise or async function.
113
+ * @param {number} ms - Timeout in milliseconds.
114
+ * @param {string} [message="Operation timed out"] - Error message on timeout.
115
+ * @returns {Promise<T>} The resolved value.
116
+ * @throws {Error} If the timeout elapses first.
117
+ */
118
+ export function timeout<T>(promise: Promise<T> | (() => Promise<T>), ms: number, message?: string): Promise<T>;
119
+ /**
120
+ * Composes functions left-to-right: `pipe(f, g)(x)` is `g(f(x))`.
121
+ *
122
+ * The first function may take multiple arguments; the rest take one.
123
+ *
124
+ * @example
125
+ * const process = nodeComfort.func.pipe(
126
+ * (s) => s.trim(),
127
+ * (s) => s.toUpperCase(),
128
+ * );
129
+ * process(" hi "); // "HI"
130
+ *
131
+ * @param {...((arg: any) => any)} fns - Functions to compose.
132
+ * @returns {(...args: any[]) => any} The composed function.
133
+ */
134
+ export function pipe(...fns: ((arg: any) => any)[]): (...args: any[]) => any;
135
+ /**
136
+ * Composes functions right-to-left: `compose(f, g)(x)` is `f(g(x))`.
137
+ *
138
+ * @example
139
+ * const process = nodeComfort.func.compose(
140
+ * (s) => s.toUpperCase(),
141
+ * (s) => s.trim(),
142
+ * );
143
+ * process(" hi "); // "HI"
144
+ *
145
+ * @param {...((arg: any) => any)} fns - Functions to compose.
146
+ * @returns {(...args: any[]) => any} The composed function.
147
+ */
148
+ export function compose(...fns: ((arg: any) => any)[]): (...args: any[]) => any;
149
+ /**
150
+ * Curries a function so it can be called with arguments one (or a few) at a time.
151
+ *
152
+ * @example
153
+ * const add = nodeComfort.func.curry((a, b, c) => a + b + c);
154
+ * add(1)(2)(3); // 6
155
+ * add(1, 2)(3); // 6
156
+ *
157
+ * @param {(...args: any[]) => any} fn - Function to curry.
158
+ * @param {number} [arity=fn.length] - Number of arguments to wait for.
159
+ * @returns {(...args: any[]) => any} The curried function.
160
+ */
161
+ export function curry(fn: (...args: any[]) => any, arity?: number): (...args: any[]) => any;
162
+ /**
163
+ * Returns a function that negates the result of `predicate`.
164
+ *
165
+ * @example
166
+ * const isOdd = nodeComfort.func.negate((n) => n % 2 === 0);
167
+ *
168
+ * @param {(...args: any[]) => boolean} predicate - Predicate to negate.
169
+ * @returns {(...args: any[]) => boolean} The negated predicate.
170
+ */
171
+ export function negate(predicate: (...args: any[]) => boolean): (...args: any[]) => boolean;
172
+ /**
173
+ * Wraps a function so that it is only actually invoked from the `n`-th call on.
174
+ *
175
+ * @example
176
+ * const save = nodeComfort.func.after(2, () => persist());
177
+ * save(); save(); // persists on the 2nd call
178
+ *
179
+ * @template {(...args: any[]) => any} F
180
+ * @param {number} n - Number of calls before `fn` fires.
181
+ * @param {F} fn - Function to wrap.
182
+ * @returns {F} The wrapped function.
183
+ */
184
+ export function after<F extends (...args: any[]) => any>(n: number, fn: F): F;
185
+ /**
186
+ * Turns a Node-style callback function (`(err, result) => ...`) into one that
187
+ * returns a Promise.
188
+ *
189
+ * @example
190
+ * const readFile = nodeComfort.func.promisify(fs.readFile);
191
+ * const data = await readFile("a.txt", "utf8");
192
+ *
193
+ * @param {(...args: any[]) => void} fn - Callback-style function.
194
+ * @returns {(...args: any[]) => Promise<any>} A promise-returning function.
195
+ */
196
+ export function promisify(fn: (...args: any[]) => void): (...args: any[]) => Promise<any>;
197
+ /**
198
+ * Wraps an async function so it resolves to a `[error, result]` tuple instead
199
+ * of throwing • Go-style error handling.
200
+ *
201
+ * @example
202
+ * const [err, user] = await nodeComfort.func.attempt(() => getUser(id))();
203
+ * if (err) return handle(err);
204
+ *
205
+ * @template T
206
+ * @param {(...args: any[]) => Promise<T>|T} fn - Function to wrap.
207
+ * @returns {(...args: any[]) => Promise<[unknown, T|undefined]>} The safe function.
208
+ */
209
+ export function attempt<T>(fn: (...args: any[]) => Promise<T> | T): (...args: any[]) => Promise<[unknown, T | undefined]>;
210
+ //# sourceMappingURL=Func.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Func.d.ts","sourceRoot":"","sources":["../../src/Func.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Generates a random UUID v4.
3
+ *
4
+ * @example
5
+ * nodeComfort.id.uuid(); // "3f2504e0-4f89-41d3-9a0c-0305e82c3301"
6
+ *
7
+ * @returns {string} A UUID v4 string.
8
+ */
9
+ export function uuid(): string;
10
+ /**
11
+ * Generates a URL-safe, collision-resistant ID (nanoid-compatible alphabet).
12
+ *
13
+ * Uses secure randomness with unbiased rejection sampling.
14
+ *
15
+ * @example
16
+ * nodeComfort.id.nano(); // "V1StGXR8_Z5jdHi6B-myT"
17
+ * nodeComfort.id.nano(10); // "IRFa-VaY2b"
18
+ *
19
+ * @param {number} [size=21] - Desired length.
20
+ * @param {string} [alphabet] - Custom alphabet.
21
+ * @returns {string} The generated ID.
22
+ */
23
+ export function nano(size?: number, alphabet?: string): string;
24
+ /**
25
+ * Generates a ULID • a lexicographically-sortable, timestamp-prefixed ID.
26
+ *
27
+ * ULIDs sort by creation time and are a great primary-key alternative to UUIDs.
28
+ *
29
+ * @example
30
+ * nodeComfort.id.ulid(); // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
31
+ *
32
+ * @param {number} [time=Date.now()] - Timestamp in ms to encode.
33
+ * @returns {string} A 26-character ULID.
34
+ */
35
+ export function ulid(time?: number): string;
36
+ /**
37
+ * Generates a cryptographically-secure random token.
38
+ *
39
+ * @example
40
+ * nodeComfort.id.token(); // 32-byte hex string
41
+ * nodeComfort.id.token(16, "base64url"); // 16 bytes, URL-safe base64
42
+ *
43
+ * @param {number} [bytes=32] - Number of random bytes.
44
+ * @param {"hex"|"base64"|"base64url"|"base58"} [encoding="hex"] - Output encoding.
45
+ * @returns {string} The token.
46
+ */
47
+ export function token(bytes?: number, encoding?: "hex" | "base64" | "base64url" | "base58"): string;
48
+ /**
49
+ * Generates a short, human-friendly random code (uppercase + digits by default).
50
+ *
51
+ * Ambiguous characters (`0/O`, `1/I`) are excluded, making it suitable for
52
+ * coupons, OTP-like codes and invite links.
53
+ *
54
+ * @example
55
+ * nodeComfort.id.code(); // "K7QF9X"
56
+ * nodeComfort.id.code(4, "1234"); // "3142"
57
+ *
58
+ * @param {number} [length=6] - Number of characters.
59
+ * @param {string} [alphabet="ABCDEFGHJKLMNPQRSTUVWXYZ23456789"] - Characters to pick from.
60
+ * @returns {string} The random code.
61
+ */
62
+ export function code(length?: number, alphabet?: string): string;
63
+ /**
64
+ * Hashes a value with a chosen algorithm.
65
+ *
66
+ * @example
67
+ * nodeComfort.id.hash("hello"); // sha256 hex
68
+ * nodeComfort.id.hash("hello", { algorithm: "md5" });
69
+ *
70
+ * @param {string|Buffer} value - Data to hash.
71
+ * @param {{ algorithm?: string, encoding?: "hex"|"base64"|"base64url" }} [options] - Hash options.
72
+ * @returns {string} The digest.
73
+ */
74
+ export function hash(value: string | Buffer, options?: {
75
+ algorithm?: string;
76
+ encoding?: "hex" | "base64" | "base64url";
77
+ }): string;
78
+ /**
79
+ * Computes an HMAC signature for a value using a secret key.
80
+ *
81
+ * @example
82
+ * nodeComfort.id.hmac("payload", "secret"); // sha256 HMAC hex
83
+ *
84
+ * @param {string|Buffer} value - Data to sign.
85
+ * @param {string|Buffer} secret - Secret key.
86
+ * @param {{ algorithm?: string, encoding?: "hex"|"base64"|"base64url" }} [options] - HMAC options.
87
+ * @returns {string} The signature.
88
+ */
89
+ export function hmac(value: string | Buffer, secret: string | Buffer, options?: {
90
+ algorithm?: string;
91
+ encoding?: "hex" | "base64" | "base64url";
92
+ }): string;
93
+ /**
94
+ * Compares two strings/buffers in constant time to prevent timing attacks.
95
+ *
96
+ * Use this when comparing secrets, tokens, or signatures.
97
+ *
98
+ * @example
99
+ * if (nodeComfort.id.safeEqual(provided, expected)) { ... }
100
+ *
101
+ * @param {string|Buffer} a - First value.
102
+ * @param {string|Buffer} b - Second value.
103
+ * @returns {boolean} True if equal.
104
+ */
105
+ export function safeEqual(a: string | Buffer, b: string | Buffer): boolean;
106
+ /**
107
+ * Returns a monotonically-increasing counter ID prefixed with an optional label.
108
+ *
109
+ * Useful for readable, unique keys within a single process run.
110
+ *
111
+ * @example
112
+ * nodeComfort.id.seq("user"); // "user-1"
113
+ * nodeComfort.id.seq("user"); // "user-2"
114
+ *
115
+ * @param {string} [prefix=""] - Optional prefix.
116
+ * @returns {string} The sequential ID.
117
+ */
118
+ export function seq(prefix?: string): string;
119
+ //# sourceMappingURL=Id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Id.d.ts","sourceRoot":"","sources":["../../src/Id.js"],"names":[],"mappings":"AAyDE;;;;;;;GAOG;AACH,wBAFa,MAAM,CAIlB;AAED;;;;;;;;;;;;GAYG;AACH,4BAJW,MAAM,aACN,MAAM,GACJ,MAAM,CAgBlB;AAED;;;;;;;;;;GAUG;AACH,4BAHW,MAAM,GACJ,MAAM,CAgBlB;AAED;;;;;;;;;;GAUG;AACH,8BAJW,MAAM,aACN,KAAK,GAAC,QAAQ,GAAC,WAAW,GAAC,QAAQ,GACjC,MAAM,CAMlB;AAED;;;;;;;;;;;;;GAaG;AACH,8BAJW,MAAM,aACN,MAAM,GACJ,MAAM,CASlB;AAED;;;;;;;;;;GAUG;AACH,4BAJW,MAAM,GAAC,MAAM,YACb;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,GAAC,QAAQ,GAAC,WAAW,CAAA;CAAE,GAC3D,MAAM,CAMlB;AAED;;;;;;;;;;GAUG;AACH,4BALW,MAAM,GAAC,MAAM,UACb,MAAM,GAAC,MAAM,YACb;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,GAAC,QAAQ,GAAC,WAAW,CAAA;CAAE,GAC3D,MAAM,CAMlB;AAED;;;;;;;;;;;GAWG;AACH,6BAJW,MAAM,GAAC,MAAM,KACb,MAAM,GAAC,MAAM,GACX,OAAO,CAOnB;AAED;;;;;;;;;;;GAWG;AACH,6BAHW,MAAM,GACJ,MAAM,CAKlB"}