melperjs 17.0.0 → 17.1.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/dist/node.mjs ADDED
@@ -0,0 +1,142 @@
1
+ import { CONSTANTS, checkEmpty } from "./general.mjs";
2
+ import fs, { promises } from "fs";
3
+ import path from "path";
4
+ import crypto from "crypto";
5
+ import { networkInterfaces } from "os";
6
+ import { exec, execFileSync } from "child_process";
7
+ import { promisify } from "util";
8
+ import bcrypt from "bcryptjs";
9
+ //#region src/node.js
10
+ const execAsync = promisify(exec);
11
+ function secureRandomBoolean() {
12
+ return secureRandomInteger(2) === 1;
13
+ }
14
+ function secureRandomString(length, useNumbers = true, useUppercase = false) {
15
+ let characters = CONSTANTS.LOWER_CASE;
16
+ if (useUppercase) characters += CONSTANTS.UPPER_CASE;
17
+ if (useNumbers) characters += CONSTANTS.NUMBERS;
18
+ let result = "";
19
+ for (let i = 0; i < length; i++) result += characters[secureRandomInteger(0, characters.length)];
20
+ return result;
21
+ }
22
+ function secureRandomHex(length) {
23
+ return crypto.randomBytes(Math.ceil(length / 2)).toString("hex").slice(0, length);
24
+ }
25
+ function secureRandomInteger(min, max = void 0) {
26
+ return crypto.randomInt(min, max);
27
+ }
28
+ function secureRandomUuid(useDashes = true) {
29
+ const uuid = crypto.randomUUID();
30
+ return useDashes ? uuid : uuid.replaceAll("-", "");
31
+ }
32
+ function secureRandomWeighted(object) {
33
+ if (checkEmpty(object)) return void 0;
34
+ const elements = Object.keys(object);
35
+ const weights = Object.values(object);
36
+ const randomNum = secureRandomInteger(0, weights.reduce((sum, weight) => sum + weight, 0));
37
+ let weightSum = 0;
38
+ for (let i = 0; i < elements.length; i++) {
39
+ weightSum += weights[i];
40
+ if (randomNum < weightSum) return elements[i];
41
+ }
42
+ }
43
+ function secureRandomElement(object) {
44
+ if (checkEmpty(object)) return void 0;
45
+ const values = Array.isArray(object) ? object : Object.values(object);
46
+ if (values.length === 0) return void 0;
47
+ return values[secureRandomInteger(0, values.length)];
48
+ }
49
+ function uuidFromSeed(seed, useDashes = true) {
50
+ const hash = crypto.createHash("md5").update(seed).digest();
51
+ hash[6] = hash[6] & 15 | 48;
52
+ hash[8] = hash[8] & 63 | 128;
53
+ const hex = hash.toString("hex");
54
+ if (!useDashes) return hex;
55
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
56
+ }
57
+ function hash(algorithm, data) {
58
+ return crypto.createHash(algorithm).update(data).digest("hex");
59
+ }
60
+ function md5(data) {
61
+ return hash("md5", data);
62
+ }
63
+ function sha256(data) {
64
+ return hash("sha256", data);
65
+ }
66
+ function base64Encode(data) {
67
+ return Buffer.from(data).toString("base64");
68
+ }
69
+ function base64Decode(data, encoding = "utf8") {
70
+ return Buffer.from(data, "base64").toString(encoding);
71
+ }
72
+ function bcryptHash(plainText, { key = "", strength = 12, preHash = true } = {}) {
73
+ let input = plainText + key;
74
+ if (preHash) input = sha256(input);
75
+ return bcrypt.hashSync(input, strength);
76
+ }
77
+ function bcryptVerify(plainText, hash, { key = "", preHash = true } = {}) {
78
+ let input = plainText + key;
79
+ if (preHash) input = sha256(input);
80
+ return bcrypt.compareSync(input, hash);
81
+ }
82
+ async function readJsonFile(filePath, defaultValue = {}) {
83
+ try {
84
+ const data = await promises.readFile(filePath, "utf8");
85
+ return JSON.parse(data);
86
+ } catch {
87
+ return defaultValue;
88
+ }
89
+ }
90
+ function readJsonFileSync(filePath, defaultValue = {}) {
91
+ try {
92
+ const data = fs.readFileSync(filePath, "utf8");
93
+ return JSON.parse(data);
94
+ } catch {
95
+ return defaultValue;
96
+ }
97
+ }
98
+ function writeJsonFile(filePath, data) {
99
+ const jsonData = JSON.stringify(data);
100
+ return promises.writeFile(filePath, jsonData, "utf8");
101
+ }
102
+ function writeJsonFileSync(filePath, data) {
103
+ const jsonData = JSON.stringify(data);
104
+ return fs.writeFileSync(filePath, jsonData, "utf8");
105
+ }
106
+ async function clearDirectory(directoryPath, keepDir = true) {
107
+ await promises.rm(directoryPath, {
108
+ recursive: true,
109
+ force: true
110
+ });
111
+ if (keepDir) await promises.mkdir(directoryPath, { recursive: true });
112
+ }
113
+ function createNumberedDirs(mainDirectory, start = 0, end = 9) {
114
+ fs.mkdirSync(mainDirectory, { recursive: true });
115
+ for (let i = start; i <= end; i++) fs.mkdirSync(path.join(mainDirectory, `${i}`), { recursive: true });
116
+ }
117
+ async function executeCommand(command) {
118
+ const { stdout } = await execAsync(command);
119
+ return stdout.trim();
120
+ }
121
+ function hostIp() {
122
+ for (const list of Object.values(networkInterfaces())) for (const alias of list) if (alias.family === "IPv4" && alias.address !== "127.0.0.1" && !alias.address.startsWith("192.168.") && !alias.internal) return alias.address;
123
+ return "127.0.0.1";
124
+ }
125
+ function gitVersion() {
126
+ try {
127
+ const raw = execFileSync("git", [
128
+ "show",
129
+ "-s",
130
+ "--format=%ct",
131
+ "HEAD"
132
+ ], { encoding: "utf8" }).trim();
133
+ const timestamp = parseInt(raw, 10);
134
+ if (isNaN(timestamp)) return "1.0";
135
+ const iso = (/* @__PURE__ */ new Date(timestamp * 1e3)).toISOString();
136
+ return `${iso.slice(2, 4)}${iso.slice(5, 7)}${iso.slice(8, 10)}.${iso.slice(11, 13)}${iso.slice(14, 16)}`;
137
+ } catch {
138
+ return "1.0";
139
+ }
140
+ }
141
+ //#endregion
142
+ export { base64Decode, base64Encode, bcryptHash, bcryptVerify, clearDirectory, createNumberedDirs, executeCommand, gitVersion, hash, hostIp, md5, readJsonFile, readJsonFileSync, secureRandomBoolean, secureRandomElement, secureRandomHex, secureRandomInteger, secureRandomString, secureRandomUuid, secureRandomWeighted, sha256, uuidFromSeed, writeJsonFile, writeJsonFileSync };
@@ -1,10 +1,9 @@
1
1
  # Documentation
2
2
 
3
- `melperjs` is a small utility library split into two entry points:
3
+ `melperjs` is a lightweight utility library split into two entry points:
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`.
5
+ - **Core module** (`melperjs`) — browser-safe helpers. Safe to import from any JavaScript environment.
6
+ - **Node module** (`melperjs/node`) — Node.js-specific helpers built on `crypto`, `fs`, `child_process`, `os`, and more.
8
7
  Importing this in a browser will fail.
9
8
 
10
9
  ## Usage
@@ -23,5 +22,5 @@ Both forms are supported via dual ESM/CJS builds.
23
22
 
24
23
  ## Sections
25
24
 
26
- - [General Functions](index.md) — browser-safe helpers (`melperjs`)
25
+ - [General Functions](general.md) — browser-safe helpers (`melperjs`)
27
26
  - [Node.js Functions](./node.md) — Node-only helpers (`melperjs/node`)
@@ -288,17 +288,17 @@ Depth-first search through a nested object for the first node that owns `key`. I
288
288
  - `pair` (Any): Optional value constraint. `null` means "match any value".
289
289
  - **Returns:** The matching node, or `null` if not found.
290
290
 
291
- ### waitForProperty(object, property, timeout, interval = 100)
291
+ ### waitForProperty(object, property, timeoutMs, interval = 100)
292
292
 
293
293
  Polls `object` until it owns `property`, then resolves with the property's value. Rejects after `timeout` milliseconds.
294
294
 
295
295
  - **Parameters:**
296
296
  - `object` (Object): Object to watch.
297
297
  - `property` (String): Property name to wait for.
298
- - `timeout` (Number): Maximum wait time in milliseconds.
298
+ - `timeoutMs` (Number): Maximum wait time in milliseconds.
299
299
  - `interval` (Number): Poll interval in milliseconds.
300
300
  - **Returns:** `Promise` resolving to the property's value.
301
- - **Throws:** When the property does not appear within `timeout`.
301
+ - **Throws:** When the property does not appear within `timeoutMs`.
302
302
 
303
303
  ### shuffleObject(object)
304
304
 
package/docs/node.md CHANGED
@@ -7,7 +7,7 @@ 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](index.md).
10
+ see the `random*` family in [General Functions](general.md).
11
11
 
12
12
  ### secureRandomBoolean()
13
13
 
package/package.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "melperjs",
3
+ "version": "17.1.0",
3
4
  "description": "A compact JavaScript utility library for strings, objects, tokens, hashing, cookies, proxies, file I/O, shell, and more.",
4
5
  "keywords": [
5
6
  "melperjs",
@@ -24,37 +25,40 @@
24
25
  "file-system",
25
26
  "shell"
26
27
  ],
28
+ "homepage": "https://github.com/mahelbir/melperjs#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/mahelbir/melperjs/issues"
31
+ },
27
32
  "repository": {
28
33
  "type": "git",
29
34
  "url": "git+https://github.com/mahelbir/melperjs.git"
30
35
  },
31
- "author": "Mahmuthan Elbir",
32
36
  "license": "MIT",
37
+ "author": "Mahmuthan Elbir",
33
38
  "type": "module",
34
- "files": [
35
- "lib/**/*",
36
- "docs/**/*"
37
- ],
38
- "private": false,
39
- "publishConfig": {
40
- "access": "public"
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
41
  },
42
+ "sideEffects": false,
42
43
  "exports": {
43
44
  ".": {
44
- "import": "./lib/esm/index.mjs",
45
- "require": "./lib/cjs/index.cjs"
45
+ "import": "./dist/general.mjs",
46
+ "require": "./dist/general.cjs"
46
47
  },
47
48
  "./node": {
48
- "import": "./lib/esm/node.mjs",
49
- "require": "./lib/cjs/node.cjs"
49
+ "import": "./dist/node.mjs",
50
+ "require": "./dist/node.cjs"
50
51
  }
51
52
  },
53
+ "files": [
54
+ "dist/**/*",
55
+ "docs/**/*"
56
+ ],
52
57
  "scripts": {
53
- "build:esm": "npx cross-env BABEL_ENV=esm babel ./src --out-dir ./lib/esm --out-file-extension .mjs",
54
- "build:cjs": "npx cross-env BABEL_ENV=cjs babel ./src --out-dir ./lib/cjs --out-file-extension .cjs",
55
- "build": "npm run build:esm && npm run build:cjs",
56
- "test": "node --test 'tests/**/*.test.js'",
57
- "prepublishOnly": "npm run build && npm test"
58
+ "build": "tsdown",
59
+ "test": "node --test",
60
+ "prepublishOnly": "npm run build && npm test",
61
+ "relock": "rm -rf node_modules package-lock.json && NODE_ENV= npm install --include=dev --include=optional"
58
62
  },
59
63
  "dependencies": {
60
64
  "bcryptjs": "^3.0.3",
@@ -63,12 +67,9 @@
63
67
  "xss": "^1.0.15"
64
68
  },
65
69
  "devDependencies": {
66
- "@babel/cli": "^7.28.6",
67
- "@babel/core": "^7.29.0",
68
- "@babel/preset-env": "^7.29.5",
69
- "babel-plugin-replace-import-extension": "^1.1.5",
70
- "babel-plugin-transform-import-meta": "^2.3.3",
71
- "cross-env": "^10.1.0"
70
+ "tsdown": "^0.22.0"
72
71
  },
73
- "version": "17.0.0"
72
+ "publishConfig": {
73
+ "access": "public"
74
+ }
74
75
  }