core-services-sdk 1.3.22 → 1.3.23
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/package.json +6 -3
- package/src/index.js +1 -0
- package/src/util/index.js +12 -0
- package/src/util/mask-sensitive.js +78 -0
- package/tests/rabbit-mq/rabbit-mq.test.js +1 -0
- package/tests/util/mask-sensitive.unit.test.js +79 -0
- package/tsconfig.json +9 -0
- package/types/core/combine-unique-arrays.d.ts +1 -0
- package/types/core/index.d.ts +7 -0
- package/types/core/normalize-min-max.d.ts +10 -0
- package/types/core/normalize-phone-number.d.ts +48 -0
- package/types/core/normalize-to-array.d.ts +1 -0
- package/types/core/otp-generators.d.ts +56 -0
- package/types/core/regex-utils.d.ts +1 -0
- package/types/core/sanitize-objects.d.ts +4 -0
- package/types/crypto/crypto.d.ts +18 -0
- package/types/crypto/encryption.d.ts +6 -0
- package/types/crypto/index.d.ts +2 -0
- package/types/fastify/error-codes.d.ts +29 -0
- package/types/fastify/error-handlers/with-error-handling.d.ts +15 -0
- package/types/fastify/index.d.ts +2 -0
- package/types/http/HttpError.d.ts +82 -0
- package/types/http/http-method.d.ts +7 -0
- package/types/http/http.d.ts +36 -0
- package/types/http/index.d.ts +4 -0
- package/types/http/responseType.d.ts +20 -0
- package/types/ids/generators.d.ts +10 -0
- package/types/ids/index.d.ts +2 -0
- package/types/ids/prefixes.d.ts +34 -0
- package/types/index.d.ts +11 -0
- package/types/logger/get-logger.d.ts +23 -0
- package/types/logger/index.d.ts +1 -0
- package/types/mailer/index.d.ts +2 -0
- package/types/mailer/mailer.service.d.ts +21 -0
- package/types/mailer/transport.factory.d.ts +48 -0
- package/types/mongodb/connect.d.ts +4 -0
- package/types/mongodb/index.d.ts +3 -0
- package/types/mongodb/initialize-mongodb.d.ts +13 -0
- package/types/mongodb/validate-mongo-uri.d.ts +15 -0
- package/types/rabbit-mq/index.d.ts +1 -0
- package/types/rabbit-mq/rabbit-mq.d.ts +40 -0
- package/types/templates/index.d.ts +1 -0
- package/types/templates/template-loader.d.ts +3 -0
- package/types/util/index.d.ts +7 -0
- package/types/util/mask-sensitive.d.ts +2 -0
- package/vitest.config.js +13 -3
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "core-services-sdk",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.23",
|
|
4
4
|
"main": "src/index.js",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"types": "types/index.d.ts",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"lint": "eslint .",
|
|
8
9
|
"lint:fix": "eslint . --fix",
|
|
9
10
|
"test": "vitest run --coverage",
|
|
10
11
|
"format": "prettier --write .",
|
|
11
|
-
"bump": "node ./scripts/bump-version.js"
|
|
12
|
+
"bump": "node ./scripts/bump-version.js",
|
|
13
|
+
"build:types": "tsc --declaration --allowJs --emitDeclarationOnly --outDir types ./src/index.js"
|
|
12
14
|
},
|
|
13
15
|
"repository": {
|
|
14
16
|
"type": "git",
|
|
@@ -45,7 +47,8 @@
|
|
|
45
47
|
"eslint-plugin-prettier": "^5.5.1",
|
|
46
48
|
"path": "^0.12.7",
|
|
47
49
|
"prettier": "^3.6.2",
|
|
50
|
+
"typescript": "^5.9.2",
|
|
48
51
|
"url": "^0.11.4",
|
|
49
52
|
"vitest": "^3.2.4"
|
|
50
53
|
}
|
|
51
|
-
}
|
|
54
|
+
}
|
package/src/index.js
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mask middle of a primitive value while keeping left/right edges.
|
|
3
|
+
* @param {string|number|boolean|null|undefined} value
|
|
4
|
+
* @param {string} [fill='•']
|
|
5
|
+
* @param {number} [maskLen=3]
|
|
6
|
+
* @param {number} [left=4]
|
|
7
|
+
* @param {number} [right=4]
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
export const maskSingle = (
|
|
11
|
+
value,
|
|
12
|
+
fill = '•',
|
|
13
|
+
maskLen = 3,
|
|
14
|
+
left = 4,
|
|
15
|
+
right = 4,
|
|
16
|
+
) => {
|
|
17
|
+
if (value == null) {
|
|
18
|
+
return ''
|
|
19
|
+
}
|
|
20
|
+
const str = String(value)
|
|
21
|
+
if (str.length === 0) {
|
|
22
|
+
return ''
|
|
23
|
+
}
|
|
24
|
+
const m = Math.max(1, maskLen)
|
|
25
|
+
|
|
26
|
+
if (str.length <= left + right) {
|
|
27
|
+
if (str.length === 1) {
|
|
28
|
+
return fill
|
|
29
|
+
}
|
|
30
|
+
if (str.length === 2) {
|
|
31
|
+
return str[0] + fill.repeat(2) // "ab" -> "a••"
|
|
32
|
+
}
|
|
33
|
+
return str.slice(0, 1) + fill.repeat(m) + str.slice(-1)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return str.slice(0, left) + fill.repeat(m) + str.slice(-right)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Recursively mask values in strings, numbers, booleans, arrays, and objects.
|
|
41
|
+
* @param {string|number|boolean|Array|Object|null|undefined} value
|
|
42
|
+
* @param {string} [fill='•']
|
|
43
|
+
* @param {number} [maskLen=3]
|
|
44
|
+
* @param {number} [left=4]
|
|
45
|
+
* @param {number} [right=4]
|
|
46
|
+
* @returns {string|Array|Object}
|
|
47
|
+
*/
|
|
48
|
+
export const mask = (value, fill = '•', maskLen = 3, left = 4, right = 4) => {
|
|
49
|
+
const type = typeof value
|
|
50
|
+
|
|
51
|
+
if (value instanceof Date) {
|
|
52
|
+
const isoDate = value.toISOString()
|
|
53
|
+
return maskSingle(isoDate, '', isoDate.length, 0, 0)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (value == null || (value && ['string', 'number'].includes(type))) {
|
|
57
|
+
return maskSingle(value, fill, maskLen, left, right)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (type === 'boolean') {
|
|
61
|
+
return maskSingle(value, '', 0, 0, 0)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (Array.isArray(value)) {
|
|
65
|
+
return value.map((aValue) => mask(aValue, fill, maskLen, left, right))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof value === 'object') {
|
|
69
|
+
return Object.fromEntries(
|
|
70
|
+
Object.entries(value).map(([prop, propValue]) => [
|
|
71
|
+
prop,
|
|
72
|
+
mask(propValue, fill, maskLen, left, right),
|
|
73
|
+
]),
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return value
|
|
78
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { mask, maskSingle } from '../../src/util/index.js'
|
|
4
|
+
|
|
5
|
+
describe('maskSingle', () => {
|
|
6
|
+
it('masks middle of a regular string (length == left+right)', () => {
|
|
7
|
+
expect(maskSingle('abcdefgh')).toBe('a•••h')
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('masks numbers with default settings', () => {
|
|
11
|
+
expect(maskSingle(12345678)).toBe('1•••8')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('masks booleans', () => {
|
|
15
|
+
expect(maskSingle(true)).toBe('t•••e')
|
|
16
|
+
expect(maskSingle(false)).toBe('f•••e')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('masks very short strings correctly', () => {
|
|
20
|
+
expect(maskSingle('ab')).toBe('a••b'.slice(0, 3)) // will produce 'a••'
|
|
21
|
+
expect(maskSingle('a')).toBe('•')
|
|
22
|
+
expect(maskSingle('')).toBe('')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('respects custom fill and mask length', () => {
|
|
26
|
+
expect(maskSingle('abcdefgh', '*', 5)).toBe('a*****h')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('ensures maskLen is at least 1', () => {
|
|
30
|
+
expect(maskSingle('abcdefgh', '*', 0)).toBe('a*h')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('returns empty string for null/undefined', () => {
|
|
34
|
+
expect(maskSingle(null)).toBe('')
|
|
35
|
+
expect(maskSingle(undefined)).toBe('')
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
describe('mask', () => {
|
|
40
|
+
it('masks primitives (string, number, boolean)', () => {
|
|
41
|
+
expect(mask('abcdefgh')).toBe('a•••h')
|
|
42
|
+
expect(mask(12345678)).toBe('1•••8')
|
|
43
|
+
expect(mask(true)).toBe('true')
|
|
44
|
+
expect(mask(false)).toBe('false')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('returns empty string for null/undefined', () => {
|
|
48
|
+
expect(mask(null)).toBe('')
|
|
49
|
+
expect(mask(undefined)).toBe('')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('masks arrays recursively', () => {
|
|
53
|
+
expect(mask(['abcdefgh', 12345678])).toEqual(['a•••h', '1•••8'])
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('masks objects recursively', () => {
|
|
57
|
+
expect(mask({ a: 'abcdefgh', b: 12345678 })).toEqual({
|
|
58
|
+
a: 'a•••h',
|
|
59
|
+
b: '1•••8',
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('masks nested objects/arrays recursively', () => {
|
|
64
|
+
const input = { arr: ['abcdefgh', { num: 12345678 }] }
|
|
65
|
+
const expected = { arr: ['a•••h', { num: '1•••8' }] }
|
|
66
|
+
expect(mask(input)).toEqual(expected)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('handles Date instances by returning full ISO string', () => {
|
|
70
|
+
const d = new Date('2025-08-15T12:34:56.789Z')
|
|
71
|
+
expect(mask(d)).toBe(d.toISOString())
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('respects custom fill and mask length in recursive calls', () => {
|
|
75
|
+
const input = { val: 'abcdefgh' }
|
|
76
|
+
const expected = { val: 'a*****h' }
|
|
77
|
+
expect(mask(input, '*', 5)).toEqual(expected)
|
|
78
|
+
})
|
|
79
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function combineUniqueArrays(...lists: Array<any>[]): Array<any>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./regex-utils.js";
|
|
2
|
+
export * from "./otp-generators.js";
|
|
3
|
+
export * from "./sanitize-objects.js";
|
|
4
|
+
export * from "./normalize-min-max.js";
|
|
5
|
+
export * from "./normalize-to-array.js";
|
|
6
|
+
export * from "./combine-unique-arrays.js";
|
|
7
|
+
export * from "./normalize-phone-number.js";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Resolve libphonenumber regardless of interop shape */
|
|
2
|
+
export function getLib(): any;
|
|
3
|
+
export function phoneUtil(): any;
|
|
4
|
+
/**
|
|
5
|
+
* Parse & validate an international number (must start with '+').
|
|
6
|
+
* @param {string} input
|
|
7
|
+
* @returns {{e164:string,national:string,international:string,regionCode:string|undefined,type:number}}
|
|
8
|
+
* @throws {Error} If the number is invalid
|
|
9
|
+
*/
|
|
10
|
+
export function normalizePhoneOrThrowIntl(input: string): {
|
|
11
|
+
e164: string;
|
|
12
|
+
national: string;
|
|
13
|
+
international: string;
|
|
14
|
+
regionCode: string | undefined;
|
|
15
|
+
type: number;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Parse & validate a national number using a region hint.
|
|
19
|
+
* @param {string} input
|
|
20
|
+
* @param {string} defaultRegion
|
|
21
|
+
* @returns {{e164:string,national:string,international:string,regionCode:string|undefined,type:number}}
|
|
22
|
+
* @throws {Error} If the number is invalid
|
|
23
|
+
*/
|
|
24
|
+
export function normalizePhoneOrThrowWithRegion(input: string, defaultRegion: string): {
|
|
25
|
+
e164: string;
|
|
26
|
+
national: string;
|
|
27
|
+
international: string;
|
|
28
|
+
regionCode: string | undefined;
|
|
29
|
+
type: number;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Smart normalization:
|
|
33
|
+
* - If input starts with '+', parse as international.
|
|
34
|
+
* - Otherwise require a defaultRegion and parse as national.
|
|
35
|
+
* @param {string} input
|
|
36
|
+
* @param {{ defaultRegion?: string }} [opts]
|
|
37
|
+
* @returns {{e164:string,national:string,international:string,regionCode:string|undefined,type:number}}
|
|
38
|
+
* @throws {Error} If invalid or defaultRegion is missing for non-international input
|
|
39
|
+
*/
|
|
40
|
+
export function normalizePhoneOrThrow(input: string, opts?: {
|
|
41
|
+
defaultRegion?: string;
|
|
42
|
+
}): {
|
|
43
|
+
e164: string;
|
|
44
|
+
national: string;
|
|
45
|
+
international: string;
|
|
46
|
+
regionCode: string | undefined;
|
|
47
|
+
type: number;
|
|
48
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function normalizeToArray(value: any): string[];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a one-time password (OTP) code based on a specified type or character set.
|
|
3
|
+
*
|
|
4
|
+
* @param {Object} [options={}] - The options object.
|
|
5
|
+
* @param {number} [options.length=4] - The desired length of the generated code (1-30).
|
|
6
|
+
* @param {string} [options.type='numeric'] - The type of characters to use. One of:
|
|
7
|
+
* 'any', 'alpha', 'numeric', 'symbols', 'alphaLower', 'alphaUpper', 'alphanumeric', 'alphanumericSymbols'.
|
|
8
|
+
* @param {string} [options.charset] - A custom string of characters to use instead of the predefined types.
|
|
9
|
+
* @returns {string} The generated code.
|
|
10
|
+
* @throws {Error} If the length is not a number between 1 and 30.
|
|
11
|
+
* @throws {Error} If charset is provided and is not a non-empty string.
|
|
12
|
+
* @throws {Error} If the type is invalid and no valid charset is provided.
|
|
13
|
+
*/
|
|
14
|
+
export function generateCode({ length, type, charset }?: {
|
|
15
|
+
length?: number;
|
|
16
|
+
type?: string;
|
|
17
|
+
charset?: string;
|
|
18
|
+
}): string;
|
|
19
|
+
/**
|
|
20
|
+
* Generates an OTP code using alphabetic characters (both lowercase and uppercase).
|
|
21
|
+
*
|
|
22
|
+
* @param {number} [length=4] - The desired length of the code.
|
|
23
|
+
* @returns {string} The generated code.
|
|
24
|
+
*/
|
|
25
|
+
export function generateCodeAlpha(length?: number): string;
|
|
26
|
+
/**
|
|
27
|
+
* Generates an OTP code using only numeric digits (0-9).
|
|
28
|
+
*
|
|
29
|
+
* @param {number} [length=4] - The desired length of the code.
|
|
30
|
+
* @returns {string} The generated code.
|
|
31
|
+
*/
|
|
32
|
+
export function generateCodeDigits(length?: number): string;
|
|
33
|
+
/**
|
|
34
|
+
* Generates an OTP code using alphabetic characters and digits.
|
|
35
|
+
*
|
|
36
|
+
* @param {number} [length=4] - The desired length of the code.
|
|
37
|
+
* @returns {string} The generated code.
|
|
38
|
+
*/
|
|
39
|
+
export function generateCodeAlphaNumeric(length?: number): string;
|
|
40
|
+
/**
|
|
41
|
+
* Generates an OTP code using alphabetic characters, digits, and symbols.
|
|
42
|
+
*
|
|
43
|
+
* @param {number} [length=4] - The desired length of the code.
|
|
44
|
+
* @returns {string} The generated code.
|
|
45
|
+
*/
|
|
46
|
+
export function generateCodeAlphaNumericSymbols(length?: number): string;
|
|
47
|
+
export const OTP_GENERATOR_TYPES: Readonly<{
|
|
48
|
+
any: "any";
|
|
49
|
+
alpha: "alpha";
|
|
50
|
+
numeric: "numeric";
|
|
51
|
+
symbols: "symbols";
|
|
52
|
+
alphaLower: "alphaLower";
|
|
53
|
+
alphaUpper: "alphaUpper";
|
|
54
|
+
alphanumeric: "alphanumeric";
|
|
55
|
+
alphanumericSymbols: "alphanumericSymbols";
|
|
56
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function isValidRegex(pattern: string | RegExp): boolean;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export function sanitizeObject(obj: any, filter: (entry: [string, any]) => boolean): any;
|
|
2
|
+
export function sanitizeUndefinedFields(obj: any): any;
|
|
3
|
+
export function sanitizeObjectAllowProps(obj: any, allowedFields?: string[]): any;
|
|
4
|
+
export function sanitizeObjectDisallowProps(obj: any, disallowedFields?: string[]): any;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function getSalt(length: number): Buffer;
|
|
2
|
+
export function getSaltHex(length: number): string;
|
|
3
|
+
export function getEncryptedBuffer({ salt, expression, length, }: {
|
|
4
|
+
expression: string;
|
|
5
|
+
salt: string;
|
|
6
|
+
length?: number;
|
|
7
|
+
}): Promise<Buffer>;
|
|
8
|
+
export function encrypt({ salt, expression, passwordPrivateKey }: {
|
|
9
|
+
expression: string;
|
|
10
|
+
salt: string;
|
|
11
|
+
passwordPrivateKey?: string;
|
|
12
|
+
}): Promise<string>;
|
|
13
|
+
export function isPasswordMatch({ salt, password, encryptedPassword, passwordPrivateKey, }: {
|
|
14
|
+
salt: string;
|
|
15
|
+
password: string;
|
|
16
|
+
encryptedPassword: string;
|
|
17
|
+
passwordPrivateKey?: string;
|
|
18
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A reusable generic error object representing a server-side failure (HTTP 500).
|
|
3
|
+
* Useful as a fallback error descriptor for unhandled or unexpected failures.
|
|
4
|
+
*
|
|
5
|
+
* @typedef {Object} GeneralError
|
|
6
|
+
* @property {number} httpStatusCode - The HTTP status code (500).
|
|
7
|
+
* @property {string} httpStatusText - The human-readable status text ("Internal Server Error").
|
|
8
|
+
* @property {string} code - An application-specific error code in the format "GENERAL.<StatusText>".
|
|
9
|
+
*/
|
|
10
|
+
/** @type {GeneralError} */
|
|
11
|
+
export const GENERAL_ERROR: GeneralError;
|
|
12
|
+
/**
|
|
13
|
+
* A reusable generic error object representing a server-side failure (HTTP 500).
|
|
14
|
+
* Useful as a fallback error descriptor for unhandled or unexpected failures.
|
|
15
|
+
*/
|
|
16
|
+
export type GeneralError = {
|
|
17
|
+
/**
|
|
18
|
+
* - The HTTP status code (500).
|
|
19
|
+
*/
|
|
20
|
+
httpStatusCode: number;
|
|
21
|
+
/**
|
|
22
|
+
* - The human-readable status text ("Internal Server Error").
|
|
23
|
+
*/
|
|
24
|
+
httpStatusText: string;
|
|
25
|
+
/**
|
|
26
|
+
* - An application-specific error code in the format "GENERAL.<StatusText>".
|
|
27
|
+
*/
|
|
28
|
+
code: string;
|
|
29
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function withErrorHandling(log: object, defaultError: HttpError): (funcToInvoke: () => Promise<any>) => Promise<any>;
|
|
2
|
+
export function withErrorHandlingReply({ reply, log, defaultError }: {
|
|
3
|
+
reply: Reply;
|
|
4
|
+
log: Logger;
|
|
5
|
+
defaultError?: HttpError;
|
|
6
|
+
}): (funcToInvoke: any) => Promise<any>;
|
|
7
|
+
export function replyOnErrorOnly({ reply, log, defaultError }: {
|
|
8
|
+
reply: Reply;
|
|
9
|
+
log: Logger;
|
|
10
|
+
defaultError?: HttpError;
|
|
11
|
+
}): (funcToInvoke: any) => Promise<any>;
|
|
12
|
+
export type Reply = import("fastify").FastifyReply;
|
|
13
|
+
export type Request = import("fastify").FastifyRequest;
|
|
14
|
+
export type Logger = import("pino").Logger;
|
|
15
|
+
import { HttpError } from '../../http/HttpError.js';
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a custom HTTP error with optional status code, status text, error code, and extra metadata.
|
|
3
|
+
* Useful for consistent error handling across services.
|
|
4
|
+
*/
|
|
5
|
+
export class HttpError extends Error {
|
|
6
|
+
/**
|
|
7
|
+
* Checks if a given object is an instance of `HttpError`.
|
|
8
|
+
*
|
|
9
|
+
* @param {*} instance - The object to check.
|
|
10
|
+
* @returns {boolean} True if `instance` is an instance of `HttpError`.
|
|
11
|
+
*/
|
|
12
|
+
static isInstanceOf(instance: any): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Checks if the error is an instance of `HttpError` or has similar shape.
|
|
15
|
+
*
|
|
16
|
+
* @param {object} error
|
|
17
|
+
* @returns {error is HttpError}
|
|
18
|
+
*/
|
|
19
|
+
static isHttpError(error: object): error is HttpError;
|
|
20
|
+
/**
|
|
21
|
+
* Creates an HttpError from a generic Error instance or returns it if already an HttpError.
|
|
22
|
+
*
|
|
23
|
+
* @param {Error | HttpError} error
|
|
24
|
+
* @returns {HttpError}
|
|
25
|
+
*/
|
|
26
|
+
static FromError(error: Error | HttpError): HttpError;
|
|
27
|
+
/**
|
|
28
|
+
* Creates an instance of HttpError.
|
|
29
|
+
*
|
|
30
|
+
* @param {Object} [error] - Optional error object.
|
|
31
|
+
* @param {string | number} [error.code] - Application-specific error code.
|
|
32
|
+
* @param {string} [error.message] - Custom error message.
|
|
33
|
+
* @param {number} [error.httpStatusCode] - HTTP status code (e.g., 404, 500).
|
|
34
|
+
* @param {string} [error.httpStatusText] - Optional human-readable HTTP status text.
|
|
35
|
+
* @param {object} [error.extendInfo] - Optional extended metadata for diagnostics.
|
|
36
|
+
*/
|
|
37
|
+
constructor(error?: {
|
|
38
|
+
code?: string | number;
|
|
39
|
+
message?: string;
|
|
40
|
+
httpStatusCode?: number;
|
|
41
|
+
httpStatusText?: string;
|
|
42
|
+
extendInfo?: object;
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* @type {string | number | undefined}
|
|
46
|
+
* A short application-specific error code (e.g., "INVALID_INPUT" or a numeric code).
|
|
47
|
+
*/
|
|
48
|
+
code: string | number | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* @type {number | undefined}
|
|
51
|
+
* HTTP status code associated with the error (e.g., 400, 500).
|
|
52
|
+
*/
|
|
53
|
+
httpStatusCode: number | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* @type {string | undefined}
|
|
56
|
+
* Human-readable HTTP status text (e.g., "Bad Request").
|
|
57
|
+
*/
|
|
58
|
+
httpStatusText: string | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* @type {object | undefined}
|
|
61
|
+
* Optional metadata for debugging/logging (e.g., request ID, user ID, retryAfter).
|
|
62
|
+
*/
|
|
63
|
+
extendInfo: object | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Converts the error to a plain object (useful for logging or sending as JSON).
|
|
66
|
+
*
|
|
67
|
+
* @returns {{
|
|
68
|
+
* code: string | number | undefined,
|
|
69
|
+
* message: string,
|
|
70
|
+
* httpStatusCode: number | undefined,
|
|
71
|
+
* httpStatusText: string | undefined,
|
|
72
|
+
* extendInfo?: object
|
|
73
|
+
* }}
|
|
74
|
+
*/
|
|
75
|
+
toJSON(): {
|
|
76
|
+
code: string | number | undefined;
|
|
77
|
+
message: string;
|
|
78
|
+
httpStatusCode: number | undefined;
|
|
79
|
+
httpStatusText: string | undefined;
|
|
80
|
+
extendInfo?: object;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function get({ url, headers, expectedType, }: {
|
|
2
|
+
url: any;
|
|
3
|
+
headers?: {};
|
|
4
|
+
expectedType?: "json";
|
|
5
|
+
}): Promise<any>;
|
|
6
|
+
export function post({ url, body, headers, expectedType, }: {
|
|
7
|
+
url: any;
|
|
8
|
+
body: any;
|
|
9
|
+
headers?: {};
|
|
10
|
+
expectedType?: "json";
|
|
11
|
+
}): Promise<any>;
|
|
12
|
+
export function put({ url, body, headers, expectedType, }: {
|
|
13
|
+
url: any;
|
|
14
|
+
body: any;
|
|
15
|
+
headers?: {};
|
|
16
|
+
expectedType?: "json";
|
|
17
|
+
}): Promise<any>;
|
|
18
|
+
export function patch({ url, body, headers, expectedType, }: {
|
|
19
|
+
url: any;
|
|
20
|
+
body: any;
|
|
21
|
+
headers?: {};
|
|
22
|
+
expectedType?: "json";
|
|
23
|
+
}): Promise<any>;
|
|
24
|
+
export function deleteApi({ url, body, headers, expectedType, }: {
|
|
25
|
+
url: any;
|
|
26
|
+
body: any;
|
|
27
|
+
headers?: {};
|
|
28
|
+
expectedType?: "json";
|
|
29
|
+
}): Promise<any>;
|
|
30
|
+
export namespace http {
|
|
31
|
+
export { get };
|
|
32
|
+
export { put };
|
|
33
|
+
export { post };
|
|
34
|
+
export { patch };
|
|
35
|
+
export { deleteApi };
|
|
36
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* *
|
|
3
|
+
*/
|
|
4
|
+
export type ResponseType = string;
|
|
5
|
+
/**
|
|
6
|
+
* Enum representing supported response types for HTTP client parsing.
|
|
7
|
+
*
|
|
8
|
+
* @readonly
|
|
9
|
+
* @enum {string}
|
|
10
|
+
* @property {string} xml - XML response (parsed using xml2js).
|
|
11
|
+
* @property {string} json - JSON response (parsed via JSON.parse).
|
|
12
|
+
* @property {string} text - Plain text response.
|
|
13
|
+
* @property {string} file - Binary file or blob (not automatically parsed).
|
|
14
|
+
*/
|
|
15
|
+
export const ResponseType: Readonly<{
|
|
16
|
+
xml: "xml";
|
|
17
|
+
json: "json";
|
|
18
|
+
text: "text";
|
|
19
|
+
file: "file";
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function generateId(): string;
|
|
2
|
+
export function generatePrefixedId(prefix: string): string;
|
|
3
|
+
export function generateUserId(): string;
|
|
4
|
+
export function generateTenantId(): string;
|
|
5
|
+
export function generatePermissionId(): string;
|
|
6
|
+
export function generateCorrelationId(): string;
|
|
7
|
+
export function generateVerificationId(): string;
|
|
8
|
+
export function generateRolePermissionsId(): string;
|
|
9
|
+
export function generateOnboardingId(): string;
|
|
10
|
+
export function generateSessionId(): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mapping of entity types to their unique ID prefixes.
|
|
3
|
+
*
|
|
4
|
+
* These prefixes are prepended to ULIDs to create consistent and identifiable IDs across the system.
|
|
5
|
+
* For example: 'usr_01HZY3M7K4FJ9A8Q4Y1ZB5NX3T'
|
|
6
|
+
*/
|
|
7
|
+
export type ID_PREFIXES = string;
|
|
8
|
+
/**
|
|
9
|
+
* Mapping of entity types to their unique ID prefixes.
|
|
10
|
+
*
|
|
11
|
+
* These prefixes are prepended to ULIDs to create consistent and identifiable IDs across the system.
|
|
12
|
+
* For example: 'usr_01HZY3M7K4FJ9A8Q4Y1ZB5NX3T'
|
|
13
|
+
*
|
|
14
|
+
* @readonly
|
|
15
|
+
* @enum {string}
|
|
16
|
+
*/
|
|
17
|
+
export const ID_PREFIXES: Readonly<{
|
|
18
|
+
/** User entity ID prefix */
|
|
19
|
+
USER: "usr";
|
|
20
|
+
/** Tenant entity ID prefix */
|
|
21
|
+
TENANT: "tnt";
|
|
22
|
+
/** Permission entity ID prefix */
|
|
23
|
+
PERMISSION: "prm";
|
|
24
|
+
/** Correlation ID prefix (e.g., for tracing requests) */
|
|
25
|
+
CORRELATION: "crln";
|
|
26
|
+
/** Verification entity ID prefix (e.g., email/phone code) */
|
|
27
|
+
VERIFICATION: "vrf";
|
|
28
|
+
/** Role-permissions mapping ID prefix */
|
|
29
|
+
ROLE_PERMISSIONS: "role";
|
|
30
|
+
/** Onboarding mapping ID prefix */
|
|
31
|
+
ONBOARDING: "onb";
|
|
32
|
+
/** Session mapping ID prefix */
|
|
33
|
+
SESSION: "sess";
|
|
34
|
+
}>;
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from "./core/index.js";
|
|
2
|
+
export * from "./crypto/index.js";
|
|
3
|
+
export * from "./fastify/index.js";
|
|
4
|
+
export * from "./http/index.js";
|
|
5
|
+
export * from "./ids/index.js";
|
|
6
|
+
export * from "./mongodb/index.js";
|
|
7
|
+
export * from "./logger/index.js";
|
|
8
|
+
export * from "./mailer/index.js";
|
|
9
|
+
export * from "./rabbit-mq/index.js";
|
|
10
|
+
export * from "./templates/index.js";
|
|
11
|
+
export * from "./util/index.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function getLogger(option: true | any | undefined): import("pino").Logger | typeof dummyLogger;
|
|
2
|
+
declare namespace dummyLogger {
|
|
3
|
+
function info(): void;
|
|
4
|
+
function warn(): void;
|
|
5
|
+
function trace(): void;
|
|
6
|
+
function debug(): void;
|
|
7
|
+
function error(): void;
|
|
8
|
+
function fatal(): void;
|
|
9
|
+
function levels(): void;
|
|
10
|
+
function silent(): void;
|
|
11
|
+
function child(): {
|
|
12
|
+
info: () => void;
|
|
13
|
+
warn: () => void;
|
|
14
|
+
trace: () => void;
|
|
15
|
+
debug: () => void;
|
|
16
|
+
error: () => void;
|
|
17
|
+
fatal: () => void;
|
|
18
|
+
levels: () => void;
|
|
19
|
+
silent: () => void;
|
|
20
|
+
child(): /*elided*/ any;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./get-logger.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class Mailer {
|
|
2
|
+
/**
|
|
3
|
+
* @param {object} transporter - Nodemailer transporter instance
|
|
4
|
+
*/
|
|
5
|
+
constructor(transporter: object);
|
|
6
|
+
transporter: any;
|
|
7
|
+
/**
|
|
8
|
+
* Send an email
|
|
9
|
+
*/
|
|
10
|
+
send({ to, subject, html, text, from, cc, bcc, replyTo, attachments }: {
|
|
11
|
+
to: any;
|
|
12
|
+
subject: any;
|
|
13
|
+
html: any;
|
|
14
|
+
text: any;
|
|
15
|
+
from: any;
|
|
16
|
+
cc: any;
|
|
17
|
+
bcc: any;
|
|
18
|
+
replyTo: any;
|
|
19
|
+
attachments: any;
|
|
20
|
+
}): Promise<any>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory for creating email transporters based on configuration.
|
|
3
|
+
*/
|
|
4
|
+
export class TransportFactory {
|
|
5
|
+
/**
|
|
6
|
+
* Create a Nodemailer transporter
|
|
7
|
+
*
|
|
8
|
+
* @param {object} config - Transport configuration object
|
|
9
|
+
* @param {'smtp' | 'gmail' | 'sendgrid' | 'ses'} config.type - Type of email transport
|
|
10
|
+
*
|
|
11
|
+
* For type 'smtp':
|
|
12
|
+
* @param {string} config.host - SMTP server host
|
|
13
|
+
* @param {number} config.port - SMTP server port
|
|
14
|
+
* @param {boolean} config.secure - Use TLS
|
|
15
|
+
* @param {{ user: string, pass: string }} config.auth - SMTP auth credentials
|
|
16
|
+
*
|
|
17
|
+
* For type 'gmail':
|
|
18
|
+
* @param {{ user: string, pass: string }} config.auth - Gmail credentials
|
|
19
|
+
*
|
|
20
|
+
* For type 'sendgrid':
|
|
21
|
+
* @param {string} config.apiKey - SendGrid API key
|
|
22
|
+
*
|
|
23
|
+
* For type 'ses':
|
|
24
|
+
* @param {string} config.accessKeyId - AWS access key
|
|
25
|
+
* @param {string} config.secretAccessKey - AWS secret
|
|
26
|
+
* @param {string} config.region - AWS region
|
|
27
|
+
*
|
|
28
|
+
* @returns {import('nodemailer').Transporter | typeof import('@sendgrid/mail')}
|
|
29
|
+
*/
|
|
30
|
+
static create(config: {
|
|
31
|
+
type: "smtp" | "gmail" | "sendgrid" | "ses";
|
|
32
|
+
host: string;
|
|
33
|
+
port: number;
|
|
34
|
+
secure: boolean;
|
|
35
|
+
auth: {
|
|
36
|
+
user: string;
|
|
37
|
+
pass: string;
|
|
38
|
+
};
|
|
39
|
+
auth: {
|
|
40
|
+
user: string;
|
|
41
|
+
pass: string;
|
|
42
|
+
};
|
|
43
|
+
apiKey: string;
|
|
44
|
+
accessKeyId: string;
|
|
45
|
+
secretAccessKey: string;
|
|
46
|
+
region: string;
|
|
47
|
+
}): any | typeof import("@sendgrid/mail");
|
|
48
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function initializeMongoDb({ config, collectionNames }: {
|
|
2
|
+
config: {
|
|
3
|
+
uri: string;
|
|
4
|
+
options: {
|
|
5
|
+
dbName: string;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
collectionNames: Record<string, string>;
|
|
9
|
+
}): Promise<Record<string, import("mongodb").Collection> & {
|
|
10
|
+
withTransaction: <T>(action: ({
|
|
11
|
+
session: import("mongodb").ClientSession;
|
|
12
|
+
})) => Promise<T>;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates whether a given string is a properly formatted MongoDB URI.
|
|
3
|
+
*
|
|
4
|
+
* Supports both standard (`mongodb://`) and SRV (`mongodb+srv://`) protocols.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} uri - The URI string to validate.
|
|
7
|
+
* @returns {boolean} `true` if the URI is a valid MongoDB connection string, otherwise `false`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* isValidMongoUri('mongodb://localhost:27017/mydb') // true
|
|
11
|
+
* isValidMongoUri('mongodb+srv://cluster.example.com/test') // true
|
|
12
|
+
* isValidMongoUri('http://localhost') // false
|
|
13
|
+
* isValidMongoUri('') // false
|
|
14
|
+
*/
|
|
15
|
+
export function isValidMongoUri(uri: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./rabbit-mq.js";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function connectQueueService({ host, log }: {
|
|
2
|
+
host: string;
|
|
3
|
+
log: import("pino").Logger;
|
|
4
|
+
}): Promise<amqp.Connection>;
|
|
5
|
+
export function createChannel({ host, log }: {
|
|
6
|
+
host: string;
|
|
7
|
+
log: import("pino").Logger;
|
|
8
|
+
}): Promise<amqp.Channel>;
|
|
9
|
+
export function subscribeToQueue({ log, queue, channel, prefetch, onReceive, nackOnError, }: {
|
|
10
|
+
channel: any;
|
|
11
|
+
queue: string;
|
|
12
|
+
onReceive: (data: any, correlationId?: string) => Promise<void>;
|
|
13
|
+
log: import("pino").Logger;
|
|
14
|
+
nackOnError?: boolean;
|
|
15
|
+
prefetch?: number;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
export function initializeQueue({ host, log }: {
|
|
18
|
+
host: string;
|
|
19
|
+
log: import("pino").Logger;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
publish: (queue: string, data: any, correlationId?: string) => Promise<boolean>;
|
|
22
|
+
subscribe: (options: {
|
|
23
|
+
queue: string;
|
|
24
|
+
onReceive: (data: any, correlationId?: string) => Promise<void>;
|
|
25
|
+
nackOnError?: boolean;
|
|
26
|
+
}) => Promise<void>;
|
|
27
|
+
channel: amqp.Channel;
|
|
28
|
+
}>;
|
|
29
|
+
export function rabbitUriFromEnv(env: {
|
|
30
|
+
RABBIT_HOST: string;
|
|
31
|
+
RABBIT_PORT: string | number;
|
|
32
|
+
RABBIT_USERNAME: string;
|
|
33
|
+
RABBIT_PASSWORD: string;
|
|
34
|
+
RABBIT_PROTOCOL?: string;
|
|
35
|
+
}): string;
|
|
36
|
+
export type Log = {
|
|
37
|
+
info: (obj: any, msg?: string) => void;
|
|
38
|
+
error: (obj: any, msg?: string) => void;
|
|
39
|
+
debug: (obj: any, msg?: string) => void;
|
|
40
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./template-loader.js";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export function isItFile(filePathOrString: string): Promise<boolean>;
|
|
2
|
+
export function getTemplateContent(maybeFilePathOrString: string): Promise<string>;
|
|
3
|
+
export function loadTemplates(templateSet: Record<string, string>): Promise<Record<string, (params: Record<string, any>) => string>>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export function maskSingle(value: string | number | boolean | null | undefined, fill?: string, maskLen?: number, left?: number, right?: number): string;
|
|
2
|
+
export function mask(value: string | number | boolean | any[] | any | null | undefined, fill?: string, maskLen?: number, left?: number, right?: number): string | any[] | any;
|
package/vitest.config.js
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import { defineConfig } from 'vitest/config'
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
2
4
|
test: {
|
|
3
5
|
testTimeout: 30000,
|
|
4
6
|
hookTimeout: 30000,
|
|
7
|
+
exclude: [
|
|
8
|
+
'node_modules',
|
|
9
|
+
'types/**',
|
|
10
|
+
'**/*.d.ts',
|
|
11
|
+
'**/index.js',
|
|
12
|
+
'vitest.config.js',
|
|
13
|
+
],
|
|
5
14
|
coverage: {
|
|
6
|
-
|
|
15
|
+
include: ['src/**/*.js'],
|
|
16
|
+
exclude: ['types/**', '**/*.d.ts', '**/index.js', 'vitest.config.js'],
|
|
7
17
|
},
|
|
8
18
|
},
|
|
9
|
-
}
|
|
19
|
+
})
|