@kikiutils/shared 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +142 -0
- package/dist/consola.cjs +35 -0
- package/dist/consola.cjs.map +1 -0
- package/dist/consola.d.ts +24 -0
- package/dist/consola.d.ts.map +1 -0
- package/dist/consola.mjs +32 -0
- package/dist/consola.mjs.map +1 -0
- package/dist/crypto-hash.cjs +60 -0
- package/dist/crypto-hash.cjs.map +1 -0
- package/dist/crypto-hash.d.ts +26 -0
- package/dist/crypto-hash.d.ts.map +1 -0
- package/dist/crypto-hash.mjs +49 -0
- package/dist/crypto-hash.mjs.map +1 -0
- package/dist/datetime.cjs +131 -0
- package/dist/datetime.cjs.map +1 -0
- package/dist/datetime.d.ts +79 -0
- package/dist/datetime.d.ts.map +1 -0
- package/dist/datetime.mjs +127 -0
- package/dist/datetime.mjs.map +1 -0
- package/dist/enum.cjs +65 -0
- package/dist/enum.cjs.map +1 -0
- package/dist/enum.d.ts +43 -0
- package/dist/enum.d.ts.map +1 -0
- package/dist/enum.mjs +62 -0
- package/dist/enum.mjs.map +1 -0
- package/dist/env.cjs +54 -0
- package/dist/env.cjs.map +1 -0
- package/dist/env.d.ts +40 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.mjs +51 -0
- package/dist/env.mjs.map +1 -0
- package/dist/general.cjs +8 -0
- package/dist/general.cjs.map +1 -0
- package/dist/general.d.ts +27 -0
- package/dist/general.d.ts.map +1 -0
- package/dist/general.mjs +6 -0
- package/dist/general.mjs.map +1 -0
- package/dist/hash.cjs +27 -0
- package/dist/hash.cjs.map +1 -0
- package/dist/hash.d.ts +17 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.mjs +22 -0
- package/dist/hash.mjs.map +1 -0
- package/dist/math.cjs +37 -0
- package/dist/math.cjs.map +1 -0
- package/dist/math.d.ts +43 -0
- package/dist/math.d.ts.map +1 -0
- package/dist/math.mjs +35 -0
- package/dist/math.mjs.map +1 -0
- package/dist/number.cjs +31 -0
- package/dist/number.cjs.map +1 -0
- package/dist/number.d.ts +20 -0
- package/dist/number.d.ts.map +1 -0
- package/dist/number.mjs +29 -0
- package/dist/number.mjs.map +1 -0
- package/dist/pino.cjs +42 -0
- package/dist/pino.cjs.map +1 -0
- package/dist/pino.d.ts +24 -0
- package/dist/pino.d.ts.map +1 -0
- package/dist/pino.mjs +39 -0
- package/dist/pino.mjs.map +1 -0
- package/dist/random.cjs +30 -0
- package/dist/random.cjs.map +1 -0
- package/dist/random.d.ts +21 -0
- package/dist/random.d.ts.map +1 -0
- package/dist/random.mjs +28 -0
- package/dist/random.mjs.map +1 -0
- package/dist/string.cjs +44 -0
- package/dist/string.cjs.map +1 -0
- package/dist/string.d.ts +21 -0
- package/dist/string.d.ts.map +1 -0
- package/dist/string.mjs +42 -0
- package/dist/string.mjs.map +1 -0
- package/package.json +82 -0
- package/src/consola.ts +27 -0
- package/src/crypto-hash.ts +60 -0
- package/src/datetime.ts +154 -0
- package/src/enum.ts +60 -0
- package/src/env.ts +49 -0
- package/src/general.ts +29 -0
- package/src/hash.ts +25 -0
- package/src/math.ts +56 -0
- package/src/number.ts +29 -0
- package/src/pino.ts +37 -0
- package/src/random.ts +31 -0
- package/src/string.ts +49 -0
package/dist/string.mjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const DIGITS = '0123456789';
|
|
2
|
+
const LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';
|
|
3
|
+
const UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
4
|
+
const CHARSETS = {
|
|
5
|
+
'alphabetic': LOWERCASE + UPPERCASE,
|
|
6
|
+
'alphanumeric': DIGITS + LOWERCASE + UPPERCASE,
|
|
7
|
+
'lowercase': LOWERCASE,
|
|
8
|
+
'lowercase-numeric': DIGITS + LOWERCASE,
|
|
9
|
+
'numeric': DIGITS,
|
|
10
|
+
'uppercase': UPPERCASE,
|
|
11
|
+
'uppercase-numeric': DIGITS + UPPERCASE,
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Generates a random string of a given length using a specified character set.
|
|
15
|
+
*
|
|
16
|
+
* @param {number} length - The length of the string to generate. Must be a positive integer.
|
|
17
|
+
* @param {RandomStringMode} [mode] - The character set to use.
|
|
18
|
+
* @returns {string} The generated random string.
|
|
19
|
+
*
|
|
20
|
+
* @throws {Error} If the length is not a positive integer or the mode is unsupported.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { randomString } from '@kikiutils/shared/string';
|
|
25
|
+
*
|
|
26
|
+
* console.log(randomString(8)); // e.g. 'aZbXwTyQ' (alphabetic)
|
|
27
|
+
* console.log(randomString(6, 'numeric')); // e.g. '402398'
|
|
28
|
+
* console.log(randomString(10, 'alphanumeric')); // e.g. 'a9Z4pQ8xY2'
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
function randomString(length, mode = 'alphabetic') {
|
|
32
|
+
if (!Number.isInteger(length) || length <= 0) {
|
|
33
|
+
throw new Error(`Invalid length: ${length}. Must be a positive integer.`);
|
|
34
|
+
}
|
|
35
|
+
const charset = CHARSETS[mode];
|
|
36
|
+
if (!charset)
|
|
37
|
+
throw new Error(`Unsupported mode: ${mode}`);
|
|
38
|
+
return Array.from({ length }, () => charset[Math.floor(Math.random() * charset.length)]).join('');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { randomString };
|
|
42
|
+
//# sourceMappingURL=string.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string.mjs","sources":["../src/string.ts"],"sourcesContent":["export type RandomStringMode =\n | 'alphabetic'\n | 'alphanumeric'\n | 'lowercase'\n | 'lowercase-numeric'\n | 'numeric'\n | 'uppercase'\n | 'uppercase-numeric';\n\nconst DIGITS = '0123456789';\nconst LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';\nconst UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\nconst CHARSETS: Record<RandomStringMode, string> = {\n 'alphabetic': LOWERCASE + UPPERCASE,\n 'alphanumeric': DIGITS + LOWERCASE + UPPERCASE,\n 'lowercase': LOWERCASE,\n 'lowercase-numeric': DIGITS + LOWERCASE,\n 'numeric': DIGITS,\n 'uppercase': UPPERCASE,\n 'uppercase-numeric': DIGITS + UPPERCASE,\n};\n\n/**\n * Generates a random string of a given length using a specified character set.\n *\n * @param {number} length - The length of the string to generate. Must be a positive integer.\n * @param {RandomStringMode} [mode] - The character set to use.\n * @returns {string} The generated random string.\n *\n * @throws {Error} If the length is not a positive integer or the mode is unsupported.\n *\n * @example\n * ```typescript\n * import { randomString } from '@kikiutils/shared/string';\n *\n * console.log(randomString(8)); // e.g. 'aZbXwTyQ' (alphabetic)\n * console.log(randomString(6, 'numeric')); // e.g. '402398'\n * console.log(randomString(10, 'alphanumeric')); // e.g. 'a9Z4pQ8xY2'\n * ```\n */\nexport function randomString(length: number, mode: RandomStringMode = 'alphabetic') {\n if (!Number.isInteger(length) || length <= 0) {\n throw new Error(`Invalid length: ${length}. Must be a positive integer.`);\n }\n\n const charset = CHARSETS[mode];\n if (!charset) throw new Error(`Unsupported mode: ${mode}`);\n return Array.from({ length }, () => charset[Math.floor(Math.random() * charset.length)]).join('');\n}\n"],"names":[],"mappings":"AASA,MAAM,MAAM,GAAG,YAAY;AAC3B,MAAM,SAAS,GAAG,4BAA4B;AAC9C,MAAM,SAAS,GAAG,4BAA4B;AAC9C,MAAM,QAAQ,GAAqC;IAC/C,YAAY,EAAE,SAAS,GAAG,SAAS;AACnC,IAAA,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;AAC9C,IAAA,WAAW,EAAE,SAAS;IACtB,mBAAmB,EAAE,MAAM,GAAG,SAAS;AACvC,IAAA,SAAS,EAAE,MAAM;AACjB,IAAA,WAAW,EAAE,SAAS;IACtB,mBAAmB,EAAE,MAAM,GAAG,SAAS;CAC1C;AAED;;;;;;;;;;;;;;;;;AAiBG;SACa,YAAY,CAAC,MAAc,EAAE,OAAyB,YAAY,EAAA;AAC9E,IAAA,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE;AAC1C,QAAA,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAA,6BAAA,CAA+B,CAAC;;AAG7E,IAAA,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC;AAC9B,IAAA,IAAI,CAAC,OAAO;AAAE,QAAA,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAA,CAAE,CAAC;AAC1D,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AACrG;;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kikiutils/shared",
|
|
3
|
+
"version": "9.0.0",
|
|
4
|
+
"description": "A lightweight modular utility library for JavaScript and TypeScript, offering secure hashing, flexible logging, date utilities, Vue/web helpers, and more.",
|
|
5
|
+
"author": "kiki-kanri",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/kikiutils/node-shared.git"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"browser",
|
|
13
|
+
"consola",
|
|
14
|
+
"crypto",
|
|
15
|
+
"datetime",
|
|
16
|
+
"enum",
|
|
17
|
+
"env",
|
|
18
|
+
"hashing",
|
|
19
|
+
"javascript",
|
|
20
|
+
"logging",
|
|
21
|
+
"math",
|
|
22
|
+
"node",
|
|
23
|
+
"pino",
|
|
24
|
+
"string",
|
|
25
|
+
"typescript",
|
|
26
|
+
"url",
|
|
27
|
+
"utilities",
|
|
28
|
+
"utils",
|
|
29
|
+
"vue",
|
|
30
|
+
"web"
|
|
31
|
+
],
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"exports": {
|
|
34
|
+
"./*": {
|
|
35
|
+
"types": "./dist/*.d.ts",
|
|
36
|
+
"import": "./dist/*.mjs",
|
|
37
|
+
"require": "./dist/*.cjs"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"./dist",
|
|
42
|
+
"./src"
|
|
43
|
+
],
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18.12.1"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "ts-project-builder './src/**/*.ts' --clean --sourcemaps",
|
|
49
|
+
"bumplog": "changelogen --bump --hideAuthorEmail",
|
|
50
|
+
"lint": "eslint",
|
|
51
|
+
"lint:fix": "eslint --fix",
|
|
52
|
+
"prepack": "pnpm run build",
|
|
53
|
+
"release": "pnpm run lint && pnpm run test && pnpm run build && changelogen --hideAuthorEmail --push --release && npm publish",
|
|
54
|
+
"test": "tsc -p ./tsconfig.test-check.json && cross-env TZ=UTC jest --coverage",
|
|
55
|
+
"typecheck": "tsc --noEmit"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@kikiutils/changelogen": "^0.8.0",
|
|
59
|
+
"@kikiutils/eslint-config": "^1.0.1",
|
|
60
|
+
"@kikiutils/tsconfigs": "^5.0.1",
|
|
61
|
+
"@noble/hashes": "^1.8.0",
|
|
62
|
+
"@types/jest": "^29.5.14",
|
|
63
|
+
"@types/node": "^22.15.3",
|
|
64
|
+
"consola": "^3.4.2",
|
|
65
|
+
"cross-env": "^7.0.3",
|
|
66
|
+
"date-fns": "^4.1.0",
|
|
67
|
+
"decimal.js": "^10.5.0",
|
|
68
|
+
"jest": "^29.7.0",
|
|
69
|
+
"millify": "^6.1.0",
|
|
70
|
+
"pino": "^9.6.0",
|
|
71
|
+
"pino-pretty": "^13.0.0",
|
|
72
|
+
"ts-jest": "^29.3.2",
|
|
73
|
+
"ts-project-builder": "5.0.1",
|
|
74
|
+
"typescript": "^5.8.3"
|
|
75
|
+
},
|
|
76
|
+
"pnpm": {
|
|
77
|
+
"onlyBuiltDependencies": [
|
|
78
|
+
"esbuild",
|
|
79
|
+
"unrs-resolver"
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
}
|
package/src/consola.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createConsola } from 'consola';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A consola logger instance.
|
|
5
|
+
*
|
|
6
|
+
* The logger's level is determined based on the `CONSOLA_LOGGER_LEVEL` and `NODE_ENV` environment variables.
|
|
7
|
+
* If `CONSOLA_LOGGER_LEVEL` is set, it will be used; otherwise, if `NODE_ENV` is `production`,
|
|
8
|
+
* the level will be set to `0`.
|
|
9
|
+
*
|
|
10
|
+
* To manually change the level, assign the desired level to `logger.level`.
|
|
11
|
+
*
|
|
12
|
+
* See available levels [here](https://github.com/unjs/consola?tab=readme-ov-file#log-level).
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import logger from '@kikiutils/shared/consola';
|
|
17
|
+
*
|
|
18
|
+
* logger.info('test'); // ℹ test 3:56:30 AM
|
|
19
|
+
*
|
|
20
|
+
* // Manually change the level
|
|
21
|
+
* logger.level = 3;
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export const consolaLogger = createConsola();
|
|
25
|
+
export const logger = consolaLogger;
|
|
26
|
+
if (process.env.CONSOLA_LOGGER_LEVEL !== undefined) consolaLogger.level = +process.env.CONSOLA_LOGGER_LEVEL;
|
|
27
|
+
else consolaLogger.level = process.env.NODE_ENV === 'production' ? 0 : consolaLogger.level;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file provides a set of functions for creating hash digests using different algorithms and bit lengths.
|
|
3
|
+
* It includes functions for generating SHA-3 hash digests with bit lengths of 224, 256, 384, and 512,
|
|
4
|
+
* as well as a function for generating MD5 hash digests.
|
|
5
|
+
* These functions use the Node.js crypto module to generate the hashes.
|
|
6
|
+
* Can only be used in Node.js/Deno/Bun runtimes.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { cryptoSha3256 } from '@kikiutils/shared/crypto-hash';
|
|
11
|
+
*
|
|
12
|
+
* console.log(cryptoSha3256('test')); // 36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
17
|
+
import type {
|
|
18
|
+
BinaryLike,
|
|
19
|
+
BinaryToTextEncoding,
|
|
20
|
+
} from 'node:crypto';
|
|
21
|
+
|
|
22
|
+
export function cryptoMd5(data: BinaryLike, outputEncoding: BinaryToTextEncoding = 'hex') {
|
|
23
|
+
return createHash('md5').update(data).digest(outputEncoding);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function cryptoMd5ToBuffer(data: BinaryLike) {
|
|
27
|
+
return createHash('md5').update(data).digest();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function cryptoSha3224(data: BinaryLike, outputEncoding: BinaryToTextEncoding = 'hex') {
|
|
31
|
+
return createHash('sha3-224').update(data).digest(outputEncoding);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function cryptoSha3224ToBuffer(data: BinaryLike) {
|
|
35
|
+
return createHash('sha3-224').update(data).digest();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function cryptoSha3256(data: BinaryLike, outputEncoding: BinaryToTextEncoding = 'hex') {
|
|
39
|
+
return createHash('sha3-256').update(data).digest(outputEncoding);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function cryptoSha3256ToBuffer(data: BinaryLike) {
|
|
43
|
+
return createHash('sha3-256').update(data).digest();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function cryptoSha3384(data: BinaryLike, outputEncoding: BinaryToTextEncoding = 'hex') {
|
|
47
|
+
return createHash('sha3-384').update(data).digest(outputEncoding);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function cryptoSha3384ToBuffer(data: BinaryLike) {
|
|
51
|
+
return createHash('sha3-384').update(data).digest();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function cryptoSha3512(data: BinaryLike, outputEncoding: BinaryToTextEncoding = 'hex') {
|
|
55
|
+
return createHash('sha3-512').update(data).digest(outputEncoding);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function cryptoSha3512ToBuffer(data: BinaryLike) {
|
|
59
|
+
return createHash('sha3-512').update(data).digest();
|
|
60
|
+
}
|
package/src/datetime.ts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {
|
|
2
|
+
format as dateFnsFormat,
|
|
3
|
+
endOfDay,
|
|
4
|
+
endOfMonth,
|
|
5
|
+
endOfWeek,
|
|
6
|
+
startOfDay,
|
|
7
|
+
startOfMonth,
|
|
8
|
+
startOfWeek,
|
|
9
|
+
subDays,
|
|
10
|
+
subMonths,
|
|
11
|
+
subWeeks,
|
|
12
|
+
} from 'date-fns';
|
|
13
|
+
import type {
|
|
14
|
+
DateArg,
|
|
15
|
+
Day,
|
|
16
|
+
FormatOptions,
|
|
17
|
+
} from 'date-fns';
|
|
18
|
+
|
|
19
|
+
export type DateRangeType = 'lastMonth' | 'lastWeek' | 'thisMonth' | 'thisWeek' | 'today' | 'yesterday';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Formats a given date, timestamp, or date string into a specified format.
|
|
23
|
+
*
|
|
24
|
+
* This function is a wrapper around `date-fns/format`.
|
|
25
|
+
*
|
|
26
|
+
* @param {DateArg<Date>} date - The input date to format. Can be a Date object, a timestamp, or a string.
|
|
27
|
+
* @param {string} [format] - The target format string.
|
|
28
|
+
* @param {FormatOptions} [options] - Optional formatting options passed to `date-fns/format`.
|
|
29
|
+
* @returns {string} The formatted date string.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { formatDate } from '@kikiutils/shared/datetime';
|
|
34
|
+
*
|
|
35
|
+
* // Format a Date object
|
|
36
|
+
* console.log(formatDate(new Date(), 'yyyy-MM-dd')); // 2024-07-10
|
|
37
|
+
*
|
|
38
|
+
* // Format a timestamp
|
|
39
|
+
* console.log(formatDate(1657814400000, 'yyyy-MM-dd')); // 2022-07-15
|
|
40
|
+
*
|
|
41
|
+
* // Format a date string
|
|
42
|
+
* console.log(formatDate('2024-07-10T00:00:00Z', 'yyyy-MM-dd')); // 2024-07-10
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @see https://date-fns.org/docs/format
|
|
46
|
+
*/
|
|
47
|
+
export function formatDate(date: DateArg<Date> & {}, format: string = 'yyyy-MM-dd HH:mm:ss', options?: FormatOptions) {
|
|
48
|
+
return dateFnsFormat(date, format, options);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get the date range (start and end) based on a given date and range type.
|
|
53
|
+
*
|
|
54
|
+
* Supports common range types like 'lastMonth', 'lastWeek', 'thisMonth', 'thisWeek', 'today', and 'yesterday'.
|
|
55
|
+
*
|
|
56
|
+
* @param {Date} date - The reference date.
|
|
57
|
+
* @param {DateRangeType} type - The range type to compute.
|
|
58
|
+
* @param {object} [options] - Optional settings.
|
|
59
|
+
* @param {boolean} [options.setEndDateToNextDayStart] - If true, set `endDate` to 00:00:00.000 of the next day.
|
|
60
|
+
* @param {Day} [options.weekStartsOn] - The start day of the week (0 = Sunday, 1 = Monday, ..., 6 = Saturday).
|
|
61
|
+
* @returns {{ startDate: Date, endDate: Date }} An object with `startDate` and `endDate`.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* import { getDateRangeFromDate } from '@kikiutils/shared/datetime';
|
|
66
|
+
*
|
|
67
|
+
* // Get the date range for last month
|
|
68
|
+
* const date = new Date('2023-07-01');
|
|
69
|
+
* console.log(getDateRangeFromDate(date, 'lastMonth'));
|
|
70
|
+
* // { startDate: 2023-06-01T00:00:00.000Z, endDate: 2023-06-30T23:59:59.999Z }
|
|
71
|
+
*
|
|
72
|
+
* // Get this week's range with Sunday as the first day
|
|
73
|
+
* console.log(getDateRangeFromDate(date, 'thisWeek', { weekStartsOn: 0 }));
|
|
74
|
+
* // { startDate: 2023-06-25T00:00:00.000Z, endDate: 2023-07-01T23:59:59.999Z }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function getDateRangeFromDate(
|
|
78
|
+
date: Date,
|
|
79
|
+
type: DateRangeType,
|
|
80
|
+
options?: {
|
|
81
|
+
setEndDateToNextDayStart?: boolean;
|
|
82
|
+
weekStartsOn?: Day;
|
|
83
|
+
},
|
|
84
|
+
) {
|
|
85
|
+
let endDate: Date;
|
|
86
|
+
let startDate: Date;
|
|
87
|
+
switch (type) {
|
|
88
|
+
case 'lastMonth':
|
|
89
|
+
{
|
|
90
|
+
const lastMonth = subMonths(date, 1);
|
|
91
|
+
endDate = endOfMonth(lastMonth);
|
|
92
|
+
startDate = startOfMonth(lastMonth);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
break;
|
|
96
|
+
case 'lastWeek':
|
|
97
|
+
{
|
|
98
|
+
const lastWeek = subWeeks(date, 1);
|
|
99
|
+
endDate = endOfWeek(lastWeek, { weekStartsOn: options?.weekStartsOn ?? 1 });
|
|
100
|
+
startDate = startOfWeek(lastWeek, { weekStartsOn: options?.weekStartsOn ?? 1 });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
break;
|
|
104
|
+
case 'thisMonth':
|
|
105
|
+
endDate = endOfMonth(date);
|
|
106
|
+
startDate = startOfMonth(date);
|
|
107
|
+
break;
|
|
108
|
+
case 'thisWeek':
|
|
109
|
+
endDate = endOfWeek(date, { weekStartsOn: options?.weekStartsOn ?? 1 });
|
|
110
|
+
startDate = startOfWeek(date, { weekStartsOn: options?.weekStartsOn ?? 1 });
|
|
111
|
+
break;
|
|
112
|
+
case 'today':
|
|
113
|
+
endDate = endOfDay(date);
|
|
114
|
+
startDate = startOfDay(date);
|
|
115
|
+
break;
|
|
116
|
+
case 'yesterday':
|
|
117
|
+
{
|
|
118
|
+
const yesterday = subDays(date, 1);
|
|
119
|
+
endDate = endOfDay(yesterday);
|
|
120
|
+
startDate = startOfDay(yesterday);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
break;
|
|
124
|
+
default: throw new Error(`Unsupported date range type: ${type}.`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (options?.setEndDateToNextDayStart) endDate.setHours(24, 0, 0, 0);
|
|
128
|
+
return {
|
|
129
|
+
endDate,
|
|
130
|
+
startDate,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Returns a `Date` object set to midnight (00:00:00) of today, with an optional day offset.
|
|
136
|
+
*
|
|
137
|
+
* @param {number} [offsetDays] - Number of days to offset from today. Can be negative.
|
|
138
|
+
* @returns {Date} A `Date` object at 00:00:00 of the offset day.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* import { getMidnightDateFromToday } from '@kikiutils/shared/datetime';
|
|
143
|
+
*
|
|
144
|
+
* console.log(getMidnightDateFromToday()); // today at 00:00:00
|
|
145
|
+
* console.log(getMidnightDateFromToday(3)); // 3 days from today at 00:00:00
|
|
146
|
+
* console.log(getMidnightDateFromToday(-1)); // yesterday at 00:00:00
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export function getMidnightDateFromToday(offsetDays: number = 0) {
|
|
150
|
+
const date = new Date();
|
|
151
|
+
date.setDate(date.getDate() + offsetDays);
|
|
152
|
+
date.setHours(0, 0, 0, 0);
|
|
153
|
+
return date;
|
|
154
|
+
}
|
package/src/enum.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the numeric values from an enumeration-like object.
|
|
3
|
+
*
|
|
4
|
+
* @param {Record<number | string, number | string>} data - The enumeration-like object to extract numeric values from.
|
|
5
|
+
* The keys can be numbers or strings, and the values can be numbers or strings.
|
|
6
|
+
* @returns {number[]} An array of numeric values extracted from the object.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { getEnumNumberValues } from '@kikiutils/shared/enum';
|
|
11
|
+
*
|
|
12
|
+
* enum RecordType {
|
|
13
|
+
* Receive = 0,
|
|
14
|
+
* Send = 1,
|
|
15
|
+
* Unknown = 'unknown'
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* console.log(getEnumNumberValues(RecordType)); // [0, 1]
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function getEnumNumberValues(data: Record<number | string, number | string>) {
|
|
22
|
+
return Object.values(data).filter((value) => typeof value === 'number');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Extracts the string values from an enumeration-like object.
|
|
27
|
+
*
|
|
28
|
+
* @param {Record<number | string, number | string>} data - The enumeration-like object to extract string values from.
|
|
29
|
+
* The keys can be numbers or strings, and the values can be numbers or strings.
|
|
30
|
+
* @returns {string[]} An array of string values extracted from the object.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* import { getEnumStringValues } from '@kikiutils/shared/enum';
|
|
35
|
+
*
|
|
36
|
+
* enum RecordType {
|
|
37
|
+
* Receive = 0,
|
|
38
|
+
* Send = 1,
|
|
39
|
+
* Unknown = 'unknown'
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* console.log(getEnumStringValues(RecordType)); // ['unknown']
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function getEnumStringValues(data: Record<number | string, number | string>) {
|
|
46
|
+
const keys: string[] = [];
|
|
47
|
+
const keysCount: Record<string, number> = {};
|
|
48
|
+
const values: any[] = [];
|
|
49
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
50
|
+
keys.push(key);
|
|
51
|
+
values.push(value);
|
|
52
|
+
if (typeof value !== 'string') return;
|
|
53
|
+
keysCount[key] = (keysCount[key] ?? 0) + 1;
|
|
54
|
+
keysCount[value] = (keysCount[value] ?? 0) + 1;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return values.filter((value) => {
|
|
58
|
+
return typeof value === 'string' && (!keys.includes(value) || (keysCount[value] && keysCount[value] > 1));
|
|
59
|
+
});
|
|
60
|
+
}
|
package/src/env.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for handling missing environment variables.
|
|
3
|
+
*
|
|
4
|
+
* Extends the built-in `Error` class and includes the missing key.
|
|
5
|
+
*
|
|
6
|
+
* @extends {Error}
|
|
7
|
+
*/
|
|
8
|
+
export class EnvironmentNotFoundError extends Error {
|
|
9
|
+
readonly key: string;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new EnvironmentNotFoundError.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} key - The missing environment variable key.
|
|
15
|
+
*/
|
|
16
|
+
constructor(key: string) {
|
|
17
|
+
super(`Missing environment variable: ${key}`);
|
|
18
|
+
this.key = key;
|
|
19
|
+
this.name = this.constructor.name;
|
|
20
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Retrieves the value of an environment variable, or throws an error if not set.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} key - The environment variable key to check.
|
|
28
|
+
* @returns {string} The value of the environment variable.
|
|
29
|
+
* @throws {EnvironmentNotFoundError} If the environment variable is not defined.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { checkAndGetEnvValue } from '@kikiutils/shared/env';
|
|
34
|
+
*
|
|
35
|
+
* // When the environment variable 'API_KEY' is set:
|
|
36
|
+
* console.log(checkAndGetEnvValue('API_KEY')); // value of API_KEY
|
|
37
|
+
*
|
|
38
|
+
* // When the environment variable 'API_KEY' is not set:
|
|
39
|
+
* try {
|
|
40
|
+
* const apiKey = checkAndGetEnvValue('API_KEY');
|
|
41
|
+
* } catch (error) {
|
|
42
|
+
* console.error(error); // Missing environment variable: API_KEY
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function checkAndGetEnvValue(key: string): string {
|
|
47
|
+
if (!process.env[key]) throw new EnvironmentNotFoundError(key);
|
|
48
|
+
return process.env[key];
|
|
49
|
+
}
|
package/src/general.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the first value from an array or returns the value itself if it's not an array.
|
|
3
|
+
*
|
|
4
|
+
* - If `value` is an array, returns the first element.
|
|
5
|
+
* - If `value` is not an array, returns `value` directly.
|
|
6
|
+
* - If the result is `null` or `undefined`, and `defaultValue` is provided, returns `defaultValue` instead.
|
|
7
|
+
*
|
|
8
|
+
* @template T - The type of the input value(s).
|
|
9
|
+
* @template D - The type of the default value (if provided).
|
|
10
|
+
*
|
|
11
|
+
* @param {T | T[]} value - A single value or an array of values.
|
|
12
|
+
* @param {D} [defaultValue] - A fallback value if the result is `null` or `undefined`.
|
|
13
|
+
* @returns {T | D | undefined} The first value or the fallback.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { extractFirstValue } from '@kikiutils/shared/general';
|
|
18
|
+
*
|
|
19
|
+
* console.log(extractFirstValue([1, 2, 3])); // 1
|
|
20
|
+
* console.log(extractFirstValue('hello')); // hello
|
|
21
|
+
* console.log(extractFirstValue([], 'default')); // default
|
|
22
|
+
* console.log(extractFirstValue(undefined, 'fallback')); // fallback
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function extractFirstValue<T>(value: T | T[]): T | undefined;
|
|
26
|
+
export function extractFirstValue<T, D>(value: T | T[], defaultValue: D): D | NonNullable<T>;
|
|
27
|
+
export function extractFirstValue<T, D>(value: T | T[], defaultValue?: D) {
|
|
28
|
+
return (Array.isArray(value) ? value[0] : value) ?? defaultValue;
|
|
29
|
+
}
|
package/src/hash.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file provides a set of functions for creating SHA-3 hash digests using different bit lengths (224, 256, 384, 512).
|
|
3
|
+
* These functions use the [@noble/hashes](https://github.com/paulmillr/noble-hashes) library to generate the hashes.
|
|
4
|
+
* Can be used in the browser, mainly for Nuxt/Vue and other frameworks compiled and executed in the browser.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { sha3256 } from '@kikiutils/shared/hash';
|
|
9
|
+
*
|
|
10
|
+
* console.log(sha3256('test')); // 36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
sha3_224,
|
|
16
|
+
sha3_256,
|
|
17
|
+
sha3_384,
|
|
18
|
+
sha3_512,
|
|
19
|
+
} from '@noble/hashes/sha3';
|
|
20
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
21
|
+
|
|
22
|
+
export const sha3224 = (data: string | Uint8Array) => bytesToHex(sha3_224(data));
|
|
23
|
+
export const sha3256 = (data: string | Uint8Array) => bytesToHex(sha3_256(data));
|
|
24
|
+
export const sha3384 = (data: string | Uint8Array) => bytesToHex(sha3_384(data));
|
|
25
|
+
export const sha3512 = (data: string | Uint8Array) => bytesToHex(sha3_512(data));
|
package/src/math.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Decimal } from 'decimal.js';
|
|
2
|
+
|
|
3
|
+
type CalculableValue = Decimal.Value | { toString: () => string };
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Options for configuring the output of `toPercentageString`.
|
|
7
|
+
*/
|
|
8
|
+
export interface ToPercentageStringOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Number of decimal places to include in the result.
|
|
11
|
+
* @default 2
|
|
12
|
+
*/
|
|
13
|
+
decimalPlaces?: number;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Whether to include the '%' symbol in the result.
|
|
17
|
+
* @default true
|
|
18
|
+
*/
|
|
19
|
+
withSymbol?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Converts a fraction (numerator / denominator) into a percentage string.
|
|
24
|
+
*
|
|
25
|
+
* - Uses `decimal.js` for precise decimal calculations.
|
|
26
|
+
* - Supports custom decimal places and optional percentage symbol.
|
|
27
|
+
* - Returns `'0.00%'` if result is `NaN` or division is invalid.
|
|
28
|
+
*
|
|
29
|
+
* @param {CalculableValue} molecular - The numerator of the fraction.
|
|
30
|
+
* @param {CalculableValue} denominator - The denominator of the fraction.
|
|
31
|
+
* @param {ToPercentageStringOptions} [options] - Optional output settings.
|
|
32
|
+
* @returns {string} Formatted percentage string.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { toPercentageString } from '@kikiutils/shared/math';
|
|
37
|
+
*
|
|
38
|
+
* console.log(toPercentageString(50, 200)); // 25.00%
|
|
39
|
+
* console.log(toPercentageString(50, 200, { withSymbol: false })); // 25.00
|
|
40
|
+
* console.log(toPercentageString(50, 200, { decimalPlaces: 1 })); // 25.0%
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function toPercentageString(
|
|
44
|
+
molecular: CalculableValue,
|
|
45
|
+
denominator: CalculableValue,
|
|
46
|
+
options?: ToPercentageStringOptions,
|
|
47
|
+
) {
|
|
48
|
+
const molecularDecimal = new Decimal(molecular.toString());
|
|
49
|
+
const denominatorDecimal = new Decimal(denominator.toString());
|
|
50
|
+
const calculationResult = molecularDecimal.div(denominatorDecimal);
|
|
51
|
+
const result = calculationResult.isNaN()
|
|
52
|
+
? '0.00'
|
|
53
|
+
: calculationResult.times(100).toFixed(options?.decimalPlaces ?? 2);
|
|
54
|
+
|
|
55
|
+
return options?.withSymbol ?? true ? `${result}%` : result;
|
|
56
|
+
}
|
package/src/number.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { millify } from 'millify';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts a large number into a compact, human-readable string using `millify`.
|
|
5
|
+
*
|
|
6
|
+
* Applies lowercase units (e.g. 'k', 'm') and default precision of 2, unless overridden.
|
|
7
|
+
*
|
|
8
|
+
* @param {number} value - The number to format.
|
|
9
|
+
* @param {Parameters<typeof millify>[1]} [options] - Optional configuration passed to `millify`.
|
|
10
|
+
* @returns {string} The compact number string.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { toCompactNumberString } from '@kikiutils/shared/number';
|
|
15
|
+
*
|
|
16
|
+
* console.log(toCompactNumberString(1234567)); // 1.23m
|
|
17
|
+
* console.log(toCompactNumberString(1234567, { precision: 3 })); // 1.235m
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function toCompactNumberString(value: number, options?: Parameters<typeof millify>[1]) {
|
|
21
|
+
return millify(
|
|
22
|
+
value,
|
|
23
|
+
{
|
|
24
|
+
lowercase: true,
|
|
25
|
+
precision: 2,
|
|
26
|
+
...options,
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
}
|
package/src/pino.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { pino } from 'pino';
|
|
2
|
+
import { PinoPretty } from 'pino-pretty';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Configure pinoPretty to enhance the log output.
|
|
6
|
+
*/
|
|
7
|
+
const stream = PinoPretty({
|
|
8
|
+
colorize: true, // Enable colored output for better readability
|
|
9
|
+
ignore: 'hostname,pid', // Exclude 'hostname' and 'pid' fields from the logs
|
|
10
|
+
translateTime: 'SYS:yyyy-mm-dd HH:MM:ss.l', // Format the timestamp in 'yyyy-mm-dd HH:MM:ss.l' format
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A pino logger instance with the configured stream.
|
|
15
|
+
*
|
|
16
|
+
* The logger's level is determined based on the `PINO_LOGGER_LEVEL` and `NODE_ENV` environment variables.
|
|
17
|
+
* If `PINO_LOGGER_LEVEL` is set, it will be used; otherwise, if `NODE_ENV` is `production`,
|
|
18
|
+
* the level will be set to `error`.
|
|
19
|
+
*
|
|
20
|
+
* To manually change the level, assign the desired level to `logger.level`.
|
|
21
|
+
*
|
|
22
|
+
* See available levels [here](https://getpino.io/#/docs/api?id=level-string).
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import logger from '@kikiutils/shared/pino';
|
|
27
|
+
*
|
|
28
|
+
* logger.info('test'); // [2024-07-11 12:12:30.085] INFO: test
|
|
29
|
+
*
|
|
30
|
+
* // Manually change the level
|
|
31
|
+
* logger.level = 'info';
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export const pinoLogger = pino({}, stream);
|
|
35
|
+
export const logger = pinoLogger;
|
|
36
|
+
// eslint-disable-next-line style/max-len
|
|
37
|
+
pinoLogger.level = process.env.PINO_LOGGER_LEVEL || (process.env.NODE_ENV === 'production' ? 'error' : pinoLogger.level);
|