melperjs 16.0.0 → 17.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/README.md CHANGED
@@ -13,10 +13,10 @@ npm i melperjs
13
13
 
14
14
  ## Documentation
15
15
 
16
- Full API reference lives in the [docs folder](docs/index.md):
16
+ Full API reference lives in the [docs folder](docs/docs.md):
17
17
 
18
- - [General Functions](docs/general.md) — `melperjs` (browser-safe)
19
- - [Node.js Functions](docs/node.md) — `melperjs/node`
18
+ - [General Functions](docs/index.md) — browser-safe helpers (`melperjs`)
19
+ - [Node.js Functions](docs/node.md) — Node-only helpers (`melperjs/node`)
20
20
 
21
21
  ## License
22
22
 
package/docs/docs.md ADDED
@@ -0,0 +1,27 @@
1
+ # Documentation
2
+
3
+ `melperjs` is a small utility library split into two entry points:
4
+
5
+ - **Core module** (`melperjs`) — browser-safe helpers. No Node-only APIs, no `crypto`, no `fs`. Safe to import from any
6
+ JavaScript environment.
7
+ - **Node module** (`melperjs/node`) — Node.js-specific helpers built on `crypto`, `fs`, `child_process`, and `os`.
8
+ Importing this in a browser will fail.
9
+
10
+ ## Usage
11
+
12
+ ```javascript
13
+ // ES Module
14
+ import * as helper from "melperjs";
15
+ import * as nodeHelper from "melperjs/node";
16
+
17
+ // CommonJS
18
+ const helper = require("melperjs");
19
+ const nodeHelper = require("melperjs/node");
20
+ ```
21
+
22
+ Both forms are supported via dual ESM/CJS builds.
23
+
24
+ ## Sections
25
+
26
+ - [General Functions](index.md) — browser-safe helpers (`melperjs`)
27
+ - [Node.js Functions](./node.md) — Node-only helpers (`melperjs/node`)
package/docs/index.md CHANGED
@@ -1,27 +1,411 @@
1
- # Documentation
1
+ # General Functions
2
2
 
3
- `melperjs` is a small utility library split into two entry points:
3
+ Browser-safe utilities exported from `melperjs`. No Node.js APIs are used here every function runs in the browser and in Node.js without polyfills.
4
4
 
5
- - **Core module** (`melperjs`) — browser-safe helpers. No Node-only APIs, no `crypto`, no `fs`. Safe to import from any
6
- JavaScript environment.
7
- - **Node module** (`melperjs/node`) — Node.js-specific helpers built on `crypto`, `fs`, `child_process`, and `os`.
8
- Importing this in a browser will fail.
5
+ ## Constants
9
6
 
10
- ## Usage
7
+ `CONSTANTS` bundles a few character sets and integer bounds that other functions in this module rely on. Useful when you need the same alphabets in your own code.
11
8
 
12
- ```javascript
13
- // ES Module
14
- import * as helper from "melperjs";
15
- import * as nodeHelper from "melperjs/node";
9
+ - `CONSTANTS.LOWER_CASE` — lowercase ASCII letters (`a-z`).
10
+ - `CONSTANTS.UPPER_CASE` — uppercase ASCII letters (`A-Z`).
11
+ - `CONSTANTS.HEXADECIMAL` hex digits (`0-9a-f`).
12
+ - `CONSTANTS.NUMBERS` decimal digits (`0-9`).
13
+ - `CONSTANTS.INT32_MIN` — `-2147483648`.
14
+ - `CONSTANTS.INT32_MAX` — `2147483647`.
16
15
 
17
- // CommonJS
18
- const helper = require("melperjs");
19
- const nodeHelper = require("melperjs/node");
20
- ```
16
+ ## Errors
21
17
 
22
- Both forms are supported via dual ESM/CJS builds.
18
+ ### Exception(message, response = {}, name = null)
23
19
 
24
- ## Sections
20
+ Builds a standard `Error` with two extra attached fields (`response`, custom `name`) so error handlers can carry HTTP-style context without subclassing. A null/empty `response` is normalized to `{}`.
25
21
 
26
- - [General Functions](./general.md) — browser-safe helpers (`melperjs`)
27
- - [Node.js Functions](./node.md) — Node-only helpers (`melperjs/node`)
22
+ - **Parameters:**
23
+ - `message` (String): Human-readable error message.
24
+ - `response` (Object): Arbitrary payload attached as `error.response`.
25
+ - `name` (String|null): Overrides `error.name`. Defaults to `"Exception"`.
26
+ - **Returns:** `Error` with `.response` and `.name` populated.
27
+
28
+ ## Time & Async
29
+
30
+ ### time()
31
+
32
+ Current Unix timestamp in seconds (integer).
33
+
34
+ - **Returns:** Seconds since the epoch.
35
+
36
+ ### sleepMs(milliseconds)
37
+
38
+ Promise that resolves after a delay, measured in milliseconds.
39
+
40
+ - **Parameters:**
41
+ - `milliseconds` (Number): Delay in ms.
42
+ - **Returns:** `Promise<void>`.
43
+
44
+ ### sleep(seconds)
45
+
46
+ Same as `sleepMs` but the delay is given in seconds.
47
+
48
+ - **Parameters:**
49
+ - `seconds` (Number): Delay in seconds.
50
+ - **Returns:** `Promise<void>`.
51
+
52
+ ### promiseTimeout(milliseconds, promise)
53
+
54
+ Races a promise against a timer. If the promise doesn't settle in time the result rejects; either way the timer is cleared.
55
+
56
+ - **Parameters:**
57
+ - `milliseconds` (Number): Maximum wait time before rejecting.
58
+ - `promise` (Promise): The work to await.
59
+ - **Returns:** Settles with the inner promise's value, or rejects with `Error("Promise timed out after Xms")`.
60
+
61
+ ### promiseSilent(promise)
62
+
63
+ Awaits a promise but swallows both the resolved value and any rejection. Handy for fire-and-forget work where you only care about the side effects.
64
+
65
+ - **Parameters:**
66
+ - `promise` (Promise): The promise to consume silently.
67
+ - **Returns:** `Promise<undefined>` that always resolves.
68
+
69
+ ### forever(delayMs, task, onError = null, onFinally = null)
70
+
71
+ Runs `task` in an infinite loop with a delay between iterations. Errors are routed to `onError`; `onFinally` runs after every iteration regardless of outcome. Any of the three callbacks can return a new positive number to update `delayMs` on the fly (useful for adaptive polling).
72
+
73
+ Errors thrown from `task` are caught and routed to `onError`; the loop keeps running. Errors thrown from `onError` propagate out and stop the loop — useful for soft shutdown by throwing on a stop signal. Errors thrown from `onFinally` are caught and ignored so that observability/cleanup failures cannot kill the worker.
74
+
75
+ - **Parameters:**
76
+ - `delayMs` (Number): Initial delay in milliseconds between iterations. Must be a positive finite number.
77
+ - `task` (Function): Async function to invoke each iteration. Exceptions are caught and forwarded to `onError`.
78
+ - `onError` (Function): Called with the caught error when `task` throws. Throwing from here aborts the loop.
79
+ - `onFinally` (Function): Called after every iteration (success or failure). Errors thrown here are swallowed.
80
+ - **Returns:** Promise that never resolves on its own; it rejects when `delayMs` validation fails or when `onError` throws.
81
+ - **Throws:** When `delayMs` is not a positive finite number.
82
+
83
+ ### retry(task, maxAttempts = 1, onError = null, {delayMs = 0, backoffFactor = 1} = {})
84
+
85
+ Calls `task` up to `maxAttempts` times, returning the first successful result. Optionally waits between retries with an exponential backoff (delay grows by `delayMs * backoffFactor^(attempt-1)`).
86
+
87
+ - **Parameters:**
88
+ - `task` (Function): Async function to attempt.
89
+ - `maxAttempts` (Number): Total attempt count (1 = no retries). Default `1`.
90
+ - `onError` (Function): Called as `(error, attempt)` after each failed attempt.
91
+ - `options.delayMs` (Number): Base delay between retries in ms. `0` disables delay.
92
+ - `options.backoffFactor` (Number): Multiplier applied per attempt. `1` keeps delay constant; `2` doubles each retry.
93
+ - **Returns:** The first non-throwing result of `task`.
94
+ - **Throws:** The last error after `maxAttempts` failures.
95
+
96
+ ## Strings
97
+
98
+ ### isValidURL(url)
99
+
100
+ Tests whether the input parses as a valid URL via the `URL` constructor.
101
+
102
+ - **Parameters:**
103
+ - `url` (String): Candidate URL.
104
+ - **Returns:** `Boolean`.
105
+
106
+ ### splitTrim(string, separator = null)
107
+
108
+ Splits a string, trims each piece, and drops empty results. Default separator is `\r?\n` (any newline).
109
+
110
+ - **Parameters:**
111
+ - `string` (String): Source text.
112
+ - `separator` (String|RegExp|null): Custom delimiter; `null` falls back to newlines.
113
+ - **Returns:** Array of non-empty trimmed strings.
114
+
115
+ ### pascalCase(string)
116
+
117
+ Converts arbitrary text to `PascalCase` (uses lodash internally).
118
+
119
+ - **Parameters:**
120
+ - `string` (String): Input text.
121
+ - **Returns:** PascalCase string.
122
+
123
+ ### titleCase(string, separator = " ")
124
+
125
+ Capitalizes the first letter of each word delimited by `separator`. Other characters are preserved as-is.
126
+
127
+ - **Parameters:**
128
+ - `string` (String): Input text.
129
+ - `separator` (String): Word boundary. Defaults to a single space.
130
+ - **Returns:** Title-cased string.
131
+
132
+ ### limitString(string, limit = 35, omission = "...")
133
+
134
+ Truncates a string if it exceeds `limit` characters and appends `omission`. Strings shorter than the limit are returned unchanged.
135
+
136
+ - **Parameters:**
137
+ - `string` (String): Input text.
138
+ - `limit` (Number): Maximum length of the result (including `omission`).
139
+ - `omission` (String): Suffix used when truncation happens.
140
+ - **Returns:** Possibly truncated string.
141
+
142
+ ### safeString(string)
143
+
144
+ Strips HTML tags via the `xss` library and additionally removes the body of dangerous block tags (`<script>`, `<style>`, `<iframe>`, `<object>`, `<embed>`, `<form>`) so leftover CSS/markup cannot leak as text. CSS attribute sanitization is also disabled (no `<style>` attribute support). Intended for rendering untrusted text safely; not a substitute for a full HTML sanitizer like DOMPurify.
145
+
146
+ - **Parameters:**
147
+ - `string` (String): Untrusted text.
148
+ - **Returns:** Sanitized string with no allowed tags.
149
+
150
+ ### shuffleString(string)
151
+
152
+ Randomly reorders the characters in a string using lodash's `shuffle` (Fisher-Yates).
153
+
154
+ - **Parameters:**
155
+ - `string` (String): Source string.
156
+ - **Returns:** Shuffled string of the same length.
157
+
158
+ ## Random (non-cryptographic, Math.random)
159
+
160
+ ### randomBoolean()
161
+
162
+ Returns a random `true` or `false` with uniform probability.
163
+
164
+ - **Returns:** `Boolean`.
165
+
166
+ ### randomString(length, useNumbers = true, useUppercase = false)
167
+
168
+ Generates a random string from a configurable character set.
169
+
170
+ - **Parameters:**
171
+ - `length` (Number): Output length.
172
+ - `useNumbers` (Boolean): Include digits `0-9`.
173
+ - `useUppercase` (Boolean): Include uppercase letters.
174
+ - **Returns:** Random string.
175
+
176
+ ### randomHex(length)
177
+
178
+ Generates a random hexadecimal string.
179
+
180
+ - **Parameters:**
181
+ - `length` (Number): Output length.
182
+ - **Returns:** Hex string of the requested length.
183
+
184
+ ### randomInteger(min, max)
185
+
186
+ Returns a random integer in `[min, max)`. If called with a single argument it is treated as `max` with `min = 0` (e.g., `randomInteger(10)` returns `0..9`).
187
+
188
+ - **Parameters:**
189
+ - `min` (Number): Inclusive lower bound, or `max` when called with one argument.
190
+ - `max` (Number): Exclusive upper bound.
191
+ - **Returns:** Integer in `[min, max)`.
192
+ - **Throws:** When inputs are not numbers, or when `max <= min`.
193
+
194
+ ### randomUuid(useDashes = true)
195
+
196
+ Generates a random UUID v4-shaped string. Not suitable for security tokens; use `secureRandomUuid` instead.
197
+
198
+ - **Parameters:**
199
+ - `useDashes` (Boolean): When `false`, dashes are stripped.
200
+ - **Returns:** UUID string.
201
+
202
+ ### randomWeighted(object)
203
+
204
+ Picks a random key from `object` with probability proportional to its weight. Returns `undefined` for empty or nullish input.
205
+
206
+ - **Parameters:**
207
+ - `object` (Object): Map of key → positive weight.
208
+ - **Returns:** Selected key, or `undefined`.
209
+
210
+ ### randomElement(object)
211
+
212
+ Picks a random value from an array or from an object's own enumerable values. Returns `undefined` for empty or nullish input.
213
+
214
+ - **Parameters:**
215
+ - `object` (Array|Object): Source collection.
216
+ - **Returns:** A random value, or `undefined`.
217
+
218
+ ## Deterministic Random (seeded)
219
+
220
+ ### mulberry32(seed)
221
+
222
+ Returns a deterministic PRNG (Mulberry32) seeded by a 32-bit integer or by a string (hashed internally to 32 bits). Each call to the returned function produces a `[0, 1)` float. Very fast, but only 32 bits of state — not for cryptographic use.
223
+
224
+ - **Parameters:**
225
+ - `seed` (Number|String): Seed value.
226
+ - **Returns:** Function that returns a `Number` in `[0, 1)` per call.
227
+
228
+ ### seedHex(seed, length)
229
+
230
+ Builds a deterministic hex string of the requested length from a seed via `mulberry32`. Same seed always yields the same output. Useful for short, repeatable identifiers (e.g., proxy session stickiness).
231
+
232
+ - **Parameters:**
233
+ - `seed` (Any): Seed value (coerced to string).
234
+ - `length` (Number): Output length in hex characters. Required.
235
+ - **Returns:** Hex string.
236
+
237
+ ## Predicates
238
+
239
+ ### checkEmpty(value)
240
+
241
+ Like lodash's `isEmpty` but additionally treats `0` (numeric zero) as empty.
242
+
243
+ - **Parameters:**
244
+ - `value` (Any): Value to test.
245
+ - **Returns:** `Boolean`.
246
+
247
+ ### isInt32(value)
248
+
249
+ Tests whether `value` is an integer within the signed 32-bit range.
250
+
251
+ - **Parameters:**
252
+ - `value` (Any): Value to test.
253
+ - **Returns:** `Boolean`.
254
+
255
+ ### isPositiveNumber(value)
256
+
257
+ Tests whether `value` is a finite positive number (excludes `NaN`, `Infinity`, non-numbers, `0`, and negatives).
258
+
259
+ - **Parameters:**
260
+ - `value` (Any): Value to test.
261
+ - **Returns:** `Boolean`.
262
+
263
+ ## Objects
264
+
265
+ ### coerceObjectNumbers(object)
266
+
267
+ Walks an object's own enumerable keys and converts string values that match a numeric pattern (e.g., `"1.5"`, `"-3"`, `"1e3"`) to `Number`. Non-string values and non-strict numeric strings (e.g., `"12abc"`, `"1,000"`) are left untouched. Mutates the input.
268
+
269
+ - **Parameters:**
270
+ - `object` (Object): Object to coerce in place.
271
+ - **Returns:** The same `object`.
272
+
273
+ ### coerceObjectIntegers(object)
274
+
275
+ Same as `coerceObjectNumbers` but only converts whole integer strings via `parseInt` (e.g., `"002"` → `2`, `"-7"` → `-7`). Mutates the input.
276
+
277
+ - **Parameters:**
278
+ - `object` (Object): Object to coerce in place.
279
+ - **Returns:** The same `object`.
280
+
281
+ ### findNodeByKey(key, node, pair = null)
282
+
283
+ Depth-first search through a nested object for the first node that owns `key`. If `pair` is provided, the node's value at `key` must equal `pair` (strict equality, supports falsy values like `false` / `0` / `""`).
284
+
285
+ - **Parameters:**
286
+ - `key` (String): Property name to find.
287
+ - `node` (Object): Tree to search.
288
+ - `pair` (Any): Optional value constraint. `null` means "match any value".
289
+ - **Returns:** The matching node, or `null` if not found.
290
+
291
+ ### waitForProperty(object, property, timeout, interval = 100)
292
+
293
+ Polls `object` until it owns `property`, then resolves with the property's value. Rejects after `timeout` milliseconds.
294
+
295
+ - **Parameters:**
296
+ - `object` (Object): Object to watch.
297
+ - `property` (String): Property name to wait for.
298
+ - `timeout` (Number): Maximum wait time in milliseconds.
299
+ - `interval` (Number): Poll interval in milliseconds.
300
+ - **Returns:** `Promise` resolving to the property's value.
301
+ - **Throws:** When the property does not appear within `timeout`.
302
+
303
+ ### shuffleObject(object)
304
+
305
+ Returns a new object whose entries are in random order (the underlying iteration order is the only thing being shuffled).
306
+
307
+ - **Parameters:**
308
+ - `object` (Object): Source object.
309
+ - **Returns:** New object with the same keys/values in shuffled order.
310
+
311
+ ### objectStringify(object)
312
+
313
+ Recursively walks an object and converts every leaf value to `String(value)`. Nested objects and arrays are descended into; mutates the input.
314
+
315
+ - **Parameters:**
316
+ - `object` (Object): Object to mutate.
317
+ - **Returns:** The same `object`.
318
+
319
+ ## Cookies
320
+
321
+ ### cookiesFromResponse(response, decodeValues = false)
322
+
323
+ Parses the `Set-Cookie` headers off a response-like object (compatible with Node `http`, fetch responses, or anything with `headers["set-cookie"]`) and returns a flat `{name: value}` map via `set-cookie-parser`.
324
+
325
+ - **Parameters:**
326
+ - `response` (Object): Response-like with parsed headers.
327
+ - `decodeValues` (Boolean): Whether to URL-decode cookie values.
328
+ - **Returns:** Map of cookie name → value.
329
+
330
+ ### cookiesToHeader(cookies)
331
+
332
+ Serializes a `{name: value}` map into a `Cookie:` header string (`name=value` pairs joined with `"; "`). Null/undefined values are dropped.
333
+
334
+ - **Parameters:**
335
+ - `cookies` (Object): Map of cookie name → value.
336
+ - **Returns:** Cookie header string, or `""` for empty/missing input.
337
+
338
+ ### cookiesFromHeader(header)
339
+
340
+ Parses a single `Cookie:` header string into a `{name: value}` map. Pieces without `=` are skipped; multiple `=` inside a value are preserved.
341
+
342
+ - **Parameters:**
343
+ - `header` (String): Cookie header value.
344
+ - **Returns:** Map of cookie name → value. Empty input returns `{}`.
345
+
346
+ ## HTTP Helpers
347
+
348
+ ### isTransientHttpCode(httpCode)
349
+
350
+ Flags HTTP status codes that are typically transient or worth retrying (missing/`NaN`, `100`, `402`, `407`, `460-469`, anything `≥ 500`).
351
+
352
+ - **Parameters:**
353
+ - `httpCode` (Number|null|undefined): Status code to inspect.
354
+ - **Returns:** `Boolean`.
355
+
356
+ ### getResponseError(error, limit = 200)
357
+
358
+ Extracts a short error description from an HTTP error-like object. Prefers `error.response.status|error.response.data`, then `error.response.data`, then `error.message`. Truncates the result to `limit` characters via `limitString`.
359
+
360
+ - **Parameters:**
361
+ - `error` (Error): Error from an HTTP client.
362
+ - `limit` (Number): Maximum length of the returned string.
363
+ - **Returns:** Trimmed error description.
364
+
365
+ ## Proxy Helpers
366
+
367
+ ### normalizeProxy(proxy, protocol = "http")
368
+
369
+ Normalizes a wide range of proxy formats into a canonical `protocol://[user:pass@]host:port` URL. Supports:
370
+
371
+ - `host:port`
372
+ - `host:port:user:pass` (auth appended)
373
+ - `user:pass:host:port` (auth prepended; auto-detected via numeric port pattern)
374
+ - `host:portStart:portEnd:user:pass` (random port in range, inclusive)
375
+ - `user:pass:host:portStart:portEnd` (auth prepended, random port in range)
376
+ - `user:pass@host:port`
377
+ - `user:pass@host:portStart:portEnd` (random port in range)
378
+ - Any of the above prefixed with `scheme://` (`http`, `https`, `socks5`, `socks5h`, …)
379
+
380
+ Returns `null` for empty or non-string input. Does not crash on unparseable input — returns it as-is wrapped with `protocol://`.
381
+
382
+ - **Parameters:**
383
+ - `proxy` (String): Source proxy string.
384
+ - `protocol` (String): Default protocol when none is present in the input.
385
+ - **Returns:** Canonical proxy URL, or `null` when input is empty/missing.
386
+
387
+ ### parseProxy(proxy, protocol = "http")
388
+
389
+ Normalizes `proxy` via `normalizeProxy`, then decomposes it into structured fields. Returns `null` when normalization fails (empty input).
390
+
391
+ - **Parameters:**
392
+ - `proxy` (String): Source proxy string.
393
+ - `protocol` (String): Default protocol when none is present in the input.
394
+ - **Returns:** `{protocol, host, port, auth?: {username, password}}` or `null`.
395
+
396
+ ### proxyValue(rawProxy, replacements = {})
397
+
398
+ Picks a random proxy from a newline-separated list, normalizes it, and applies placeholder substitution.
399
+
400
+ `{SESSION}` is a built-in placeholder:
401
+
402
+ - If `SESSION` is not provided, it is autofilled with a non-secure `randomHex(8)`.
403
+ - If `SESSION` is a string, it is treated as a seed and replaced via `seedHex(seed, 8)` (deterministic).
404
+ - If `SESSION` is a function, the function is called per invocation.
405
+
406
+ Any other key in `replacements` is also substituted (`{KEY}` → value). For non-SESSION entries: functions are called, strings are used literally.
407
+
408
+ - **Parameters:**
409
+ - `rawProxy` (String): Newline-separated proxy list.
410
+ - `replacements` (Object): Placeholder values keyed by placeholder name.
411
+ - **Returns:** Final proxy URL string, or `null` if the list is empty.
package/docs/node.md CHANGED
@@ -7,11 +7,11 @@ and will not run in a browser.
7
7
 
8
8
  All `secureRandom*` helpers use Node's `crypto` module (`crypto.randomInt`, `crypto.randomBytes`, `crypto.randomUUID`).
9
9
  Use these for session tokens, API keys, nonces, and anything security-sensitive. For non-secure / faster equivalents,
10
- see the `random*` family in [General Functions](./general.md).
10
+ see the `random*` family in [General Functions](index.md).
11
11
 
12
12
  ### secureRandomBoolean()
13
13
 
14
- Returns `true` or `false` with cryptographically uniform probability.
14
+ Returns a cryptographically random `true` or `false` with uniform probability.
15
15
 
16
16
  - **Returns:** `Boolean`.
17
17
 
@@ -35,16 +35,17 @@ Generates a cryptographically random hexadecimal string.
35
35
 
36
36
  ### secureRandomInteger(min, max)
37
37
 
38
- Returns a cryptographically random integer in `[min, max)`. Thin wrapper over `crypto.randomInt`.
38
+ Returns a cryptographically random integer in `[min, max)`. If called with a single argument it is treated as `max` with `min = 0` (e.g., `secureRandomInteger(10)` returns `0..9`).
39
39
 
40
40
  - **Parameters:**
41
- - `min` (Number): Inclusive lower bound.
41
+ - `min` (Number): Inclusive lower bound, or `max` when called with one argument.
42
42
  - `max` (Number): Exclusive upper bound.
43
43
  - **Returns:** Integer in `[min, max)`.
44
+ - **Throws:** When inputs are not numbers, or when `max <= min`.
44
45
 
45
46
  ### secureRandomUuid(useDashes = true)
46
47
 
47
- Generates a cryptographically random UUID v4 via `crypto.randomUUID()`. Suitable for security tokens.
48
+ Generates a cryptographically random UUID v4 string. Suitable for security tokens.
48
49
 
49
50
  - **Parameters:**
50
51
  - `useDashes` (Boolean): When `false`, dashes are stripped.
@@ -52,17 +53,15 @@ Generates a cryptographically random UUID v4 via `crypto.randomUUID()`. Suitable
52
53
 
53
54
  ### secureRandomWeighted(object)
54
55
 
55
- Picks a key from `object` with probability proportional to its weight, using `crypto.randomInt` for selection. Weights
56
- must be positive integers.
56
+ Picks a cryptographically random key from `object` with probability proportional to its weight. Returns `undefined` for empty or nullish input.
57
57
 
58
58
  - **Parameters:**
59
59
  - `object` (Object): Map of key → positive integer weight.
60
- - **Returns:** Selected key.
60
+ - **Returns:** Selected key, or `undefined`.
61
61
 
62
62
  ### secureRandomElement(object)
63
63
 
64
- Picks a cryptographically random value from an array or from an object's own enumerable values. Returns `undefined` for
65
- empty or nullish input.
64
+ Picks a cryptographically random value from an array or from an object's own enumerable values. Returns `undefined` for empty or nullish input.
66
65
 
67
66
  - **Parameters:**
68
67
  - `object` (Array|Object): Source collection.
@@ -146,57 +145,6 @@ Verifies that `plainText` (with the same `key`) matches a previously generated b
146
145
  - `options.preHash` (Boolean): Must match the `preHash` used for `bcryptHash`. Default `true`.
147
146
  - **Returns:** `Boolean` indicating match.
148
147
 
149
- ## Proxy Helpers
150
-
151
- ### normalizeProxy(proxy, protocol = "http")
152
-
153
- Normalizes a wide range of proxy formats into a canonical `protocol://[user:pass@]host:port` URL. Supports:
154
-
155
- - `host:port`
156
- - `host:port:user:pass` (auth appended)
157
- - `user:pass:host:port` (auth prepended; auto-detected via numeric port pattern)
158
- - `host:portStart:portEnd:user:pass` (random port in range, inclusive)
159
- - `user:pass:host:portStart:portEnd` (auth prepended, random port in range)
160
- - `user:pass@host:port`
161
- - `user:pass@host:portStart:portEnd` (random port in range)
162
- - Any of the above prefixed with `scheme://` (`http`, `https`, `socks5`, `socks5h`, …)
163
-
164
- Returns `null` for empty or non-string input. Does not crash on unparseable input — returns it as-is wrapped with
165
- `protocol://`.
166
-
167
- - **Parameters:**
168
- - `proxy` (String): Source proxy string.
169
- - `protocol` (String): Default protocol when none is present in the input.
170
- - **Returns:** Canonical proxy URL, or `null` when input is empty/missing.
171
-
172
- ### parseProxy(proxy, protocol = "http")
173
-
174
- Normalizes `proxy` via `normalizeProxy`, then decomposes it into structured fields. Returns `null` when normalization
175
- fails (empty input).
176
-
177
- - **Parameters:**
178
- - `proxy` (String): Source proxy string.
179
- - `protocol` (String): Default protocol when none is present in the input.
180
- - **Returns:** `{protocol, host, port, auth?: {username, password}}` or `null`.
181
-
182
- ### proxyValue(rawProxy, replacements = {})
183
-
184
- Picks a random proxy from a newline-separated list, normalizes it, and applies placeholder substitution.
185
-
186
- `{SESSION}` is a built-in placeholder:
187
-
188
- - If `SESSION` is not provided, it is autofilled with a non-secure `randomHex(8)`.
189
- - If `SESSION` is a string, it is treated as a seed and replaced via `seedHex(seed, 8)` (deterministic).
190
- - If `SESSION` is a function, the function is called per invocation.
191
-
192
- Any other key in `replacements` is also substituted (`{KEY}` → value). For non-SESSION entries: functions are called,
193
- strings are used literally.
194
-
195
- - **Parameters:**
196
- - `rawProxy` (String): Newline-separated proxy list.
197
- - `replacements` (Object): Placeholder values keyed by placeholder name.
198
- - **Returns:** Final proxy URL string, or `null` if the list is empty.
199
-
200
148
  ## File I/O (JSON)
201
149
 
202
150
  ### readJsonFile(filePath, defaultValue = {})