melperjs 15.0.0 → 16.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/docs/node.md ADDED
@@ -0,0 +1,285 @@
1
+ # Node.js Functions
2
+
3
+ Node-only utilities exported from `melperjs/node`. These rely on Node modules (`crypto`, `fs`, `child_process`, `os`)
4
+ and will not run in a browser.
5
+
6
+ ## Cryptographic Random (CSPRNG)
7
+
8
+ All `secureRandom*` helpers use Node's `crypto` module (`crypto.randomInt`, `crypto.randomBytes`, `crypto.randomUUID`).
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).
11
+
12
+ ### secureRandomBoolean()
13
+
14
+ Returns `true` or `false` with cryptographically uniform probability.
15
+
16
+ - **Returns:** `Boolean`.
17
+
18
+ ### secureRandomString(length, useNumbers = true, useUppercase = false)
19
+
20
+ Generates a cryptographically random string from a configurable character set.
21
+
22
+ - **Parameters:**
23
+ - `length` (Number): Output length.
24
+ - `useNumbers` (Boolean): Include digits `0-9`.
25
+ - `useUppercase` (Boolean): Include uppercase letters.
26
+ - **Returns:** Random string.
27
+
28
+ ### secureRandomHex(length)
29
+
30
+ Generates a cryptographically random hexadecimal string.
31
+
32
+ - **Parameters:**
33
+ - `length` (Number): Output length.
34
+ - **Returns:** Hex string of the requested length.
35
+
36
+ ### secureRandomInteger(min, max)
37
+
38
+ Returns a cryptographically random integer in `[min, max)`. Thin wrapper over `crypto.randomInt`.
39
+
40
+ - **Parameters:**
41
+ - `min` (Number): Inclusive lower bound.
42
+ - `max` (Number): Exclusive upper bound.
43
+ - **Returns:** Integer in `[min, max)`.
44
+
45
+ ### secureRandomUuid(useDashes = true)
46
+
47
+ Generates a cryptographically random UUID v4 via `crypto.randomUUID()`. Suitable for security tokens.
48
+
49
+ - **Parameters:**
50
+ - `useDashes` (Boolean): When `false`, dashes are stripped.
51
+ - **Returns:** UUID string.
52
+
53
+ ### secureRandomWeighted(object)
54
+
55
+ Picks a key from `object` with probability proportional to its weight, using `crypto.randomInt` for selection. Weights
56
+ must be positive integers.
57
+
58
+ - **Parameters:**
59
+ - `object` (Object): Map of key → positive integer weight.
60
+ - **Returns:** Selected key.
61
+
62
+ ### secureRandomElement(object)
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.
66
+
67
+ - **Parameters:**
68
+ - `object` (Array|Object): Source collection.
69
+ - **Returns:** A random value, or `undefined`.
70
+
71
+ ## Deterministic Random (seeded)
72
+
73
+ ### uuidFromSeed(seed, useDashes = true)
74
+
75
+ Builds a deterministic UUID by MD5-hashing the seed and setting RFC 4122 v3 version/variant bits. Same seed always
76
+ yields the same UUID. Use for stable identifiers derived from input data; do not use for unpredictability.
77
+
78
+ - **Parameters:**
79
+ - `seed` (String|Buffer): Seed value hashed with MD5.
80
+ - `useDashes` (Boolean): When `false`, dashes are stripped.
81
+ - **Returns:** UUID string.
82
+
83
+ ## Hashing
84
+
85
+ ### hash(algorithm, data)
86
+
87
+ Computes a hex digest using any algorithm supported by Node's `crypto.createHash`.
88
+
89
+ - **Parameters:**
90
+ - `algorithm` (String): e.g., `"sha1"`, `"sha256"`, `"md5"`.
91
+ - `data` (String|Buffer): Input data.
92
+ - **Returns:** Hex digest.
93
+
94
+ ### md5(data)
95
+
96
+ Shortcut for `hash("md5", data)`.
97
+
98
+ - **Returns:** 32-char hex MD5 digest.
99
+
100
+ ### sha256(data)
101
+
102
+ Shortcut for `hash("sha256", data)`.
103
+
104
+ - **Returns:** 64-char hex SHA-256 digest.
105
+
106
+ ## Encoding
107
+
108
+ ### base64Encode(data)
109
+
110
+ Encodes input to Base64. Strings are treated as UTF-8; pass a `Buffer` for binary data.
111
+
112
+ - **Parameters:**
113
+ - `data` (String|Buffer): Input data.
114
+ - **Returns:** Base64 string.
115
+
116
+ ### base64Decode(data, encoding = 'utf8')
117
+
118
+ Decodes Base64 input to a string using the given output encoding.
119
+
120
+ - **Parameters:**
121
+ - `data` (String): Base64 string.
122
+ - `encoding` (String): Buffer encoding for the result (`'utf8'`, `'hex'`, etc.).
123
+ - **Returns:** Decoded string.
124
+
125
+ ## Bcrypt (Passwords)
126
+
127
+ ### bcryptHash(plainText, {key = "", strength = 12, preHash = true} = {})
128
+
129
+ Hashes plaintext with bcrypt. An optional pre-hash `key` (application-wide secret, sometimes called "pepper") is appended to the plaintext before hashing. `strength` controls the bcrypt cost factor. When `preHash` is `true` (default), the input is SHA-256-hashed first so that very long passwords (bcrypt silently truncates at 72 bytes) are handled safely and uniquely.
130
+
131
+ - **Parameters:**
132
+ - `plainText` (String): Password or other secret to hash.
133
+ - `options.key` (String): Extra secret appended before hashing. Default `""`.
134
+ - `options.strength` (Number): bcrypt cost (rounds). Default `12`.
135
+ - `options.preHash` (Boolean): Pre-hash with SHA-256 before bcrypt. Default `true`. Disable only for back-compat with hashes generated without it.
136
+ - **Returns:** Bcrypt hash string.
137
+
138
+ ### bcryptVerify(plainText, hash, {key = "", preHash = true} = {})
139
+
140
+ Verifies that `plainText` (with the same `key`) matches a previously generated bcrypt hash. `preHash` must match the value used during hashing.
141
+
142
+ - **Parameters:**
143
+ - `plainText` (String): Plaintext to verify.
144
+ - `hash` (String): Bcrypt hash from `bcryptHash`.
145
+ - `options.key` (String): Same `key` used during hashing.
146
+ - `options.preHash` (Boolean): Must match the `preHash` used for `bcryptHash`. Default `true`.
147
+ - **Returns:** `Boolean` indicating match.
148
+
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
+ ## File I/O (JSON)
201
+
202
+ ### readJsonFile(filePath, defaultValue = {})
203
+
204
+ Asynchronously reads a JSON file and parses it. Returns `defaultValue` on any failure (missing file, malformed JSON,
205
+ permission error).
206
+
207
+ - **Parameters:**
208
+ - `filePath` (String): Path to JSON file.
209
+ - `defaultValue` (Any): Fallback when read or parse fails.
210
+ - **Returns:** `Promise` resolving to parsed JSON or `defaultValue`.
211
+
212
+ ### readJsonFileSync(filePath, defaultValue = {})
213
+
214
+ Synchronous version of `readJsonFile`.
215
+
216
+ - **Parameters:**
217
+ - `filePath` (String): Path to JSON file.
218
+ - `defaultValue` (Any): Fallback when read or parse fails.
219
+ - **Returns:** Parsed JSON or `defaultValue`.
220
+
221
+ ### writeJsonFile(filePath, data)
222
+
223
+ Asynchronously writes `data` as JSON. Errors propagate to the caller.
224
+
225
+ - **Parameters:**
226
+ - `filePath` (String): Destination path.
227
+ - `data` (Any): JSON-serializable value.
228
+ - **Returns:** `Promise` that resolves once the file is written.
229
+
230
+ ### writeJsonFileSync(filePath, data)
231
+
232
+ Synchronous version of `writeJsonFile`.
233
+
234
+ - **Parameters:**
235
+ - `filePath` (String): Destination path.
236
+ - `data` (Any): JSON-serializable value.
237
+ - **Returns:** `undefined`.
238
+
239
+ ## File System
240
+
241
+ ### createNumberedDirs(mainDirectory, start = 0, end = 9)
242
+
243
+ Creates `mainDirectory` (recursive) and a numbered subdirectory for each integer in `[start, end]` (inclusive). Existing
244
+ directories are kept.
245
+
246
+ - **Parameters:**
247
+ - `mainDirectory` (String): Parent directory path.
248
+ - `start` (Number): First subdirectory index. Default `0`.
249
+ - `end` (Number): Last subdirectory index. Default `9`.
250
+ - **Returns:** `undefined`.
251
+
252
+ ### clearDirectory(directoryPath, keepDir = true)
253
+
254
+ Recursively removes all files and subdirectories under `directoryPath`. When `keepDir` is `true` (default), the root
255
+ directory itself is preserved (created if missing); when `false`, the root is removed too.
256
+
257
+ - **Parameters:**
258
+ - `directoryPath` (String): Directory to clear.
259
+ - `keepDir` (Boolean): Whether to keep (or recreate) the root directory.
260
+ - **Returns:** `Promise<void>`.
261
+
262
+ ## Process & Network
263
+
264
+ ### executeCommand(command)
265
+
266
+ Runs a shell command (promisified `child_process.exec`) and returns the trimmed stdout. Rejects only on a non-zero exit
267
+ code; output on stderr alone does not reject.
268
+
269
+ - **Parameters:**
270
+ - `command` (String): Shell command line.
271
+ - **Returns:** `Promise<String>` with the command's stdout.
272
+ - **Throws:** When the command exits with a non-zero code.
273
+
274
+ ### hostIp()
275
+
276
+ Returns the first non-loopback, non-internal IPv4 address found in the host's network interfaces, skipping `127.0.0.1`
277
+ and any address starting with `192.168.`. Falls back to `127.0.0.1` if none qualifies.
278
+
279
+ - **Returns:** IPv4 address string.
280
+
281
+ ### gitVersion()
282
+
283
+ Builds a version string from the UTC timestamp of the latest git commit in the current working directory.
284
+
285
+ - **Returns:** `YYMMDD.HHMM` string, or `"1.0"` when git is unavailable or the timestamp cannot be parsed.
@@ -0,0 +1,351 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.CONSTANTS = void 0;
7
+ exports.Exception = Exception;
8
+ exports.checkEmpty = checkEmpty;
9
+ exports.coerceObjectIntegers = coerceObjectIntegers;
10
+ exports.coerceObjectNumbers = coerceObjectNumbers;
11
+ exports.cookiesFromHeader = cookiesFromHeader;
12
+ exports.cookiesFromResponse = cookiesFromResponse;
13
+ exports.cookiesToHeader = cookiesToHeader;
14
+ exports.findNodeByKey = findNodeByKey;
15
+ exports.forever = forever;
16
+ exports.getResponseError = getResponseError;
17
+ exports.isInt32 = isInt32;
18
+ exports.isPositiveNumber = isPositiveNumber;
19
+ exports.isTransientHttpCode = isTransientHttpCode;
20
+ exports.isValidURL = isValidURL;
21
+ exports.limitString = limitString;
22
+ exports.mulberry32 = mulberry32;
23
+ exports.objectStringify = objectStringify;
24
+ exports.pascalCase = pascalCase;
25
+ exports.promiseSilent = promiseSilent;
26
+ exports.promiseTimeout = promiseTimeout;
27
+ exports.randomBoolean = randomBoolean;
28
+ exports.randomElement = randomElement;
29
+ exports.randomHex = randomHex;
30
+ exports.randomInteger = randomInteger;
31
+ exports.randomString = randomString;
32
+ exports.randomUuid = randomUuid;
33
+ exports.randomWeighted = randomWeighted;
34
+ exports.retry = retry;
35
+ exports.safeString = safeString;
36
+ exports.seedHex = seedHex;
37
+ exports.shuffleObject = shuffleObject;
38
+ exports.shuffleString = shuffleString;
39
+ exports.sleep = sleep;
40
+ exports.sleepMs = sleepMs;
41
+ exports.splitTrim = splitTrim;
42
+ exports.time = time;
43
+ exports.titleCase = titleCase;
44
+ exports.waitForProperty = waitForProperty;
45
+ var _xss = _interopRequireDefault(require("xss"));
46
+ var _setCookieParser = _interopRequireDefault(require("set-cookie-parser"));
47
+ var _camelCase = _interopRequireDefault(require("lodash/camelCase.js"));
48
+ var _upperFirst = _interopRequireDefault(require("lodash/upperFirst.js"));
49
+ var _isEmpty = _interopRequireDefault(require("lodash/isEmpty.js"));
50
+ var _shuffle = _interopRequireDefault(require("lodash/shuffle.js"));
51
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
52
+ const CONSTANTS = exports.CONSTANTS = {
53
+ LOWER_CASE: "abcdefghijklmnopqrstuvwxyz",
54
+ UPPER_CASE: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
55
+ HEXADECIMAL: "0123456789abcdef",
56
+ NUMBERS: "0123456789",
57
+ INT32_MIN: -2147483648,
58
+ INT32_MAX: 2147483647
59
+ };
60
+ const NUMBER_PATTERN = /^-?\d+(\.\d+)?(e[+-]?\d+)?$/i;
61
+ const INTEGER_PATTERN = /^-?\d+$/;
62
+ function Exception(message, response = {}, name = null) {
63
+ const error = new Error(message);
64
+ error.name = name || "Exception";
65
+ error.response = response;
66
+ if (checkEmpty(response)) {
67
+ error.response = {};
68
+ }
69
+ return error;
70
+ }
71
+ function time() {
72
+ return Math.floor(Date.now() / 1000);
73
+ }
74
+ function sleepMs(milliseconds) {
75
+ return new Promise(resolve => setTimeout(resolve, milliseconds));
76
+ }
77
+ function sleep(seconds) {
78
+ return sleepMs(seconds * 1000);
79
+ }
80
+ function promiseTimeout(milliseconds, promise) {
81
+ let timer;
82
+ const timeout = new Promise((_, reject) => {
83
+ timer = setTimeout(() => reject(new Error(`Promise timed out after ${milliseconds}ms`)), milliseconds);
84
+ });
85
+ return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
86
+ }
87
+ function promiseSilent(promise) {
88
+ return promise.then(() => {}).catch(() => {});
89
+ }
90
+ async function forever(delayMs, task, onError = null, onFinally = null) {
91
+ if (!isPositiveNumber(delayMs)) throw new Error("delayMs must be a positive number");
92
+ const maybeUpdate = value => {
93
+ if (isPositiveNumber(value)) delayMs = value;
94
+ };
95
+ while (true) {
96
+ try {
97
+ maybeUpdate(await task());
98
+ } catch (error) {
99
+ if (onError) maybeUpdate(await onError(error));
100
+ } finally {
101
+ if (onFinally) {
102
+ try {
103
+ maybeUpdate(await onFinally());
104
+ } catch {}
105
+ }
106
+ await sleepMs(delayMs);
107
+ }
108
+ }
109
+ }
110
+ async function retry(callFn, maxAttempts, errorFn = null, {
111
+ delayMs = 0,
112
+ backoffFactor = 1
113
+ } = {}) {
114
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
115
+ try {
116
+ return await callFn();
117
+ } catch (error) {
118
+ if (errorFn) await errorFn(attempt, error);
119
+ if (attempt >= maxAttempts) throw error;
120
+ if (delayMs > 0) await sleepMs(delayMs * backoffFactor ** (attempt - 1));
121
+ }
122
+ }
123
+ }
124
+ function isValidURL(url) {
125
+ try {
126
+ new URL(url);
127
+ return true;
128
+ } catch {
129
+ return false;
130
+ }
131
+ }
132
+ function splitTrim(string, separator = null) {
133
+ return string.split(separator ?? /\r?\n/).map(item => item.trim()).filter(Boolean);
134
+ }
135
+ function checkEmpty(value) {
136
+ if (typeof value === "number") return value === 0;
137
+ return (0, _isEmpty.default)(value);
138
+ }
139
+ function pascalCase(string) {
140
+ return (0, _upperFirst.default)((0, _camelCase.default)(string));
141
+ }
142
+ function titleCase(string, separator = " ") {
143
+ return (string || "").split(separator).map(_upperFirst.default).join(separator);
144
+ }
145
+ function isInt32(value) {
146
+ return Number.isInteger(value) && value >= CONSTANTS.INT32_MIN && value <= CONSTANTS.INT32_MAX;
147
+ }
148
+ function isPositiveNumber(value) {
149
+ return typeof value === 'number' && Number.isFinite(value) && value > 0;
150
+ }
151
+ function coerceObjectNumbers(object) {
152
+ for (const key of Object.keys(object)) {
153
+ const value = object[key];
154
+ if (typeof value === 'string' && NUMBER_PATTERN.test(value)) {
155
+ object[key] = parseFloat(value);
156
+ }
157
+ }
158
+ return object;
159
+ }
160
+ function coerceObjectIntegers(object) {
161
+ for (const key of Object.keys(object)) {
162
+ const value = object[key];
163
+ if (typeof value === 'string' && INTEGER_PATTERN.test(value)) {
164
+ object[key] = parseInt(value);
165
+ }
166
+ }
167
+ return object;
168
+ }
169
+ function findNodeByKey(key, node, pair = null) {
170
+ if (node && typeof node === 'object') {
171
+ if (Object.hasOwn(node, key) && (pair === null || node[key] === pair)) {
172
+ return node;
173
+ }
174
+ for (const childKey of Object.keys(node)) {
175
+ const result = findNodeByKey(key, node[childKey], pair);
176
+ if (result) return result;
177
+ }
178
+ }
179
+ return null;
180
+ }
181
+ function waitForProperty(object, property, timeout = 5000, interval = 100) {
182
+ return new Promise((resolve, reject) => {
183
+ if (Object.hasOwn(object, property)) {
184
+ resolve(object[property]);
185
+ return;
186
+ }
187
+ const startTime = Date.now();
188
+ const checkProperty = setInterval(() => {
189
+ if (Object.hasOwn(object, property)) {
190
+ clearInterval(checkProperty);
191
+ resolve(object[property]);
192
+ } else if (Date.now() - startTime >= timeout) {
193
+ clearInterval(checkProperty);
194
+ reject(new Error(`Property "${property}" did not appear within ${timeout} milliseconds`));
195
+ }
196
+ }, interval);
197
+ });
198
+ }
199
+ function shuffleObject(object) {
200
+ return Object.fromEntries((0, _shuffle.default)(Object.entries(object)));
201
+ }
202
+ function objectStringify(object) {
203
+ for (const key of Object.keys(object)) {
204
+ const value = object[key];
205
+ if (value !== null && typeof value === 'object') {
206
+ objectStringify(value);
207
+ } else {
208
+ object[key] = String(value);
209
+ }
210
+ }
211
+ return object;
212
+ }
213
+ function limitString(string, limit = 35, omission = "...") {
214
+ string = string || "";
215
+ if (string.length <= limit) return string;
216
+ return string.slice(0, limit - omission.length) + omission;
217
+ }
218
+ function safeString(string) {
219
+ return (0, _xss.default)(string || "", {
220
+ whiteList: {},
221
+ stripIgnoreTag: true,
222
+ stripIgnoreTagBody: ["script", "style", "iframe", "object", "embed", "form"],
223
+ css: false
224
+ });
225
+ }
226
+ function shuffleString(string) {
227
+ return (0, _shuffle.default)(string.split('')).join('');
228
+ }
229
+ function randomBoolean() {
230
+ return Math.random() < 0.5;
231
+ }
232
+ function randomString(length, useNumbers = true, useUppercase = false) {
233
+ let characters = CONSTANTS.LOWER_CASE;
234
+ if (useUppercase) characters += CONSTANTS.UPPER_CASE;
235
+ if (useNumbers) characters += CONSTANTS.NUMBERS;
236
+ let result = '';
237
+ for (let i = 0; i < length; i++) {
238
+ result += characters[Math.random() * characters.length | 0];
239
+ }
240
+ return result;
241
+ }
242
+ function randomHex(length) {
243
+ let result = '';
244
+ for (let i = 0; i < length; i++) {
245
+ result += CONSTANTS.HEXADECIMAL[Math.random() * 16 | 0];
246
+ }
247
+ return result;
248
+ }
249
+ function randomInteger(min, max) {
250
+ if (typeof max === 'undefined') {
251
+ max = min;
252
+ min = 0;
253
+ }
254
+ if (typeof min !== 'number' || typeof max !== 'number') {
255
+ throw new Error('min and max must be numerical values');
256
+ }
257
+ if (max <= min) {
258
+ throw new Error('max must be greater than min');
259
+ }
260
+ return Math.floor(Math.random() * (max - min)) + min;
261
+ }
262
+ function randomUuid(useDashes = true) {
263
+ const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
264
+ const r = Math.random() * 16 | 0;
265
+ return (c === 'x' ? r : r & 0x3 | 0x8).toString(16);
266
+ });
267
+ return useDashes ? uuid : uuid.replaceAll("-", "");
268
+ }
269
+ function randomWeighted(object) {
270
+ const elements = Object.keys(object);
271
+ const weights = Object.values(object);
272
+ const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
273
+ const randomNum = Math.random() * totalWeight;
274
+ let weightSum = 0;
275
+ for (let i = 0; i < elements.length; i++) {
276
+ weightSum += weights[i];
277
+ if (randomNum < weightSum) {
278
+ return elements[i];
279
+ }
280
+ }
281
+ }
282
+ function randomElement(object) {
283
+ if (!object) return undefined;
284
+ const values = Array.isArray(object) ? object : Object.values(object);
285
+ if (values.length === 0) return undefined;
286
+ return values[Math.floor(Math.random() * values.length)];
287
+ }
288
+ function mulberry32(seed) {
289
+ if (typeof seed === "string") {
290
+ let h = 0;
291
+ for (let i = 0; i < seed.length; i++) {
292
+ h = Math.imul(h ^ seed.charCodeAt(i), 2654435761);
293
+ }
294
+ seed = h >>> 0;
295
+ }
296
+ return function () {
297
+ seed = seed + 0x6D2B79F5 | 0;
298
+ let t = seed;
299
+ t = Math.imul(t ^ t >>> 15, t | 1);
300
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
301
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
302
+ };
303
+ }
304
+ function seedHex(seed, length) {
305
+ const rng = mulberry32(String(seed));
306
+ let result = '';
307
+ while (result.length < length) {
308
+ result += Math.floor(rng() * 0x100000000).toString(16).padStart(8, '0');
309
+ }
310
+ return result.slice(0, length);
311
+ }
312
+ function cookiesFromResponse(response, decodeValues = false) {
313
+ const dict = {};
314
+ const cookies = _setCookieParser.default.parse(response, {
315
+ decodeValues
316
+ });
317
+ for (const cookie of cookies) {
318
+ dict[cookie.name] = cookie.value;
319
+ }
320
+ return dict;
321
+ }
322
+ function cookiesToHeader(cookies) {
323
+ if (!cookies) return "";
324
+ return Object.entries(cookies).filter(([, value]) => value !== null && value !== undefined).map(([key, value]) => `${key}=${value}`).join("; ");
325
+ }
326
+ function cookiesFromHeader(header) {
327
+ const cookies = {};
328
+ if (!header) return cookies;
329
+ header.split(';').forEach(cookie => {
330
+ const trimmed = cookie.trim();
331
+ if (!trimmed.includes('=')) return;
332
+ const [key, ...valueParts] = trimmed.split('=');
333
+ const trimmedKey = key.trim();
334
+ if (trimmedKey) {
335
+ cookies[trimmedKey] = valueParts.join('=').trim();
336
+ }
337
+ });
338
+ return cookies;
339
+ }
340
+ function isTransientHttpCode(httpCode) {
341
+ return !httpCode || isNaN(httpCode) || httpCode === 100 || httpCode === 402 || httpCode === 407 || 460 <= httpCode && httpCode < 470 || 500 <= httpCode;
342
+ }
343
+ function getResponseError(error, limit = 200) {
344
+ let response;
345
+ if (error?.response?.status && error.response.data) {
346
+ response = `${error.response.status}|${error.response.data}`;
347
+ } else if (error?.response?.data) {
348
+ response = error.response.data;
349
+ }
350
+ return limitString(response || error.message, limit).trim();
351
+ }