core-services-sdk 1.3.3 → 1.3.5

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.
@@ -0,0 +1,43 @@
1
+ import { describe, it, expect } from 'vitest'
2
+
3
+ import { normalizeToArray } from '../../src/core/normalize-to-array.js'
4
+
5
+ describe('normalizeToArray', () => {
6
+ it('should return an empty array for undefined', () => {
7
+ expect(normalizeToArray(undefined)).toEqual([])
8
+ })
9
+
10
+ it('should return an empty array for null', () => {
11
+ expect(normalizeToArray(null)).toEqual([])
12
+ })
13
+
14
+ it('should split a comma-separated string and trim each value', () => {
15
+ expect(normalizeToArray('a,b, c , ,d')).toEqual(['a', 'b', 'c', 'd'])
16
+ })
17
+
18
+ it('should handle string with extra commas and spaces', () => {
19
+ expect(normalizeToArray(' , a , ,b,, ,c ,')).toEqual(['a', 'b', 'c'])
20
+ })
21
+
22
+ it('should trim and filter empty values from an array of strings', () => {
23
+ expect(normalizeToArray([' a ', 'b', '', ' ', 'c'])).toEqual([
24
+ 'a',
25
+ 'b',
26
+ 'c',
27
+ ])
28
+ })
29
+
30
+ it('should convert non-string/non-array values to string and split by comma', () => {
31
+ expect(normalizeToArray(123)).toEqual(['123'])
32
+ expect(normalizeToArray(true)).toEqual(['true'])
33
+ expect(normalizeToArray({})).toEqual(['[object Object]'])
34
+ })
35
+
36
+ it('should handle an array of non-string values', () => {
37
+ expect(normalizeToArray([1, ' 2 ', null, undefined, true])).toEqual(['2'])
38
+ })
39
+
40
+ it('should preserve order of values after normalization', () => {
41
+ expect(normalizeToArray([' b ', 'a', ' c '])).toEqual(['b', 'a', 'c'])
42
+ })
43
+ })
@@ -0,0 +1,93 @@
1
+ import { describe, it, expect } from 'vitest'
2
+
3
+ import {
4
+ generateCode,
5
+ generateCodeAlpha,
6
+ generateCodeDigits,
7
+ generateCodeAlphaNumeric,
8
+ generateCodeAlphaNumericSymbols,
9
+ OTP_GENERATOR_TYPES,
10
+ } from '../../src/core/otp-generators.js'
11
+
12
+ const charsetForType = {
13
+ [OTP_GENERATOR_TYPES.numeric]: /^[0-9]+$/,
14
+ [OTP_GENERATOR_TYPES.alpha]: /^[a-zA-Z]+$/,
15
+ [OTP_GENERATOR_TYPES.symbols]: /^[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]+$/,
16
+ [OTP_GENERATOR_TYPES.alphaLower]: /^[a-z]+$/,
17
+ [OTP_GENERATOR_TYPES.alphaUpper]: /^[A-Z]+$/,
18
+ [OTP_GENERATOR_TYPES.alphanumeric]: /^[a-zA-Z0-9]+$/,
19
+ [OTP_GENERATOR_TYPES.alphanumericSymbols]:
20
+ /^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{}|;:,.<>?]+$/,
21
+ [OTP_GENERATOR_TYPES.any]: /^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{}|;:,.<>?]+$/,
22
+ }
23
+
24
+ describe('generateCode', () => {
25
+ it('generates code with correct length', () => {
26
+ const code = generateCode({ length: 10, type: 'numeric' })
27
+ expect(code).toHaveLength(10)
28
+ })
29
+
30
+ it('uses fallback to default type when type is not provided', () => {
31
+ const code = generateCode()
32
+ expect(code).toMatch(/^[0-9]+$/)
33
+ })
34
+
35
+ it('throws error for invalid length', () => {
36
+ expect(() => generateCode({ length: 0 })).toThrow(/length must be a number/)
37
+ expect(() => generateCode({ length: 100 })).toThrow(
38
+ /length must be a number/,
39
+ )
40
+ })
41
+
42
+ it('throws error for invalid charset (non-string)', () => {
43
+ // @ts-ignore
44
+ expect(() => generateCode({ charset: 123 })).toThrow(
45
+ /charset must be a string/,
46
+ )
47
+ })
48
+
49
+ it('throws error for empty charset', () => {
50
+ expect(() => generateCode({ charset: '' })).toThrow(
51
+ /charset must not be empty/,
52
+ )
53
+ })
54
+
55
+ it('throws error for unknown type', () => {
56
+ expect(() => generateCode({ type: 'unknown_type' })).toThrow(
57
+ /type must be one of:/,
58
+ )
59
+ })
60
+
61
+ it('respects custom charset', () => {
62
+ const code = generateCode({ length: 5, charset: 'ABC' })
63
+ expect(code).toMatch(/^[ABC]+$/)
64
+ expect(code.length).toBe(5)
65
+ })
66
+
67
+ for (const [type, regex] of Object.entries(charsetForType)) {
68
+ it(`generates ${type} OTP correctly`, () => {
69
+ const code = generateCode({ length: 8, type })
70
+ expect(code).toMatch(regex)
71
+ })
72
+ }
73
+ })
74
+
75
+ describe('Shortcuts', () => {
76
+ it('generateCodeAlpha produces alphabetic code', () => {
77
+ expect(generateCodeAlpha(6)).toMatch(/^[a-zA-Z]{6}$/)
78
+ })
79
+
80
+ it('generateCodeDigits produces numeric code', () => {
81
+ expect(generateCodeDigits(6)).toMatch(/^[0-9]{6}$/)
82
+ })
83
+
84
+ it('generateCodeAlphaNumeric produces alphanumeric code', () => {
85
+ expect(generateCodeAlphaNumeric(6)).toMatch(/^[a-zA-Z0-9]{6}$/)
86
+ })
87
+
88
+ it('generateCodeAlphaNumericSymbols includes symbols', () => {
89
+ expect(generateCodeAlphaNumericSymbols(6)).toMatch(
90
+ /^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{}|;:,.<>?]{6}$/,
91
+ )
92
+ })
93
+ })
@@ -0,0 +1,41 @@
1
+ // @ts-nocheck
2
+ import { describe, it, expect } from 'vitest'
3
+
4
+ import { isValidRegex } from '../../src/core/regex-utils.js'
5
+
6
+ describe('isValidRegex', () => {
7
+ it('returns true for valid regex strings', () => {
8
+ expect(isValidRegex('^[a-z]+$')).toBe(true)
9
+ expect(isValidRegex('\\d{3}-\\d{2}-\\d{4}')).toBe(true)
10
+ expect(isValidRegex('^\\w+@[a-zA-Z_]+?\\.[a-zA-Z]{2,3}$')).toBe(true)
11
+ expect(isValidRegex('.*')).toBe(true)
12
+ expect(isValidRegex('^$')).toBe(true)
13
+ })
14
+
15
+ it('returns true for RegExp objects', () => {
16
+ expect(isValidRegex(/^[a-z]+$/)).toBe(true)
17
+ expect(isValidRegex(/\d{3}/)).toBe(true)
18
+ expect(isValidRegex(/abc/i)).toBe(true)
19
+ })
20
+
21
+ it('returns false for invalid regex strings', () => {
22
+ expect(isValidRegex('[')).toBe(false)
23
+ expect(isValidRegex('(')).toBe(false)
24
+ expect(isValidRegex('\\')).toBe(false)
25
+ expect(isValidRegex('[a-z')).toBe(false)
26
+ expect(isValidRegex('(abc')).toBe(false)
27
+ })
28
+
29
+ it('returns false for invalid types', () => {
30
+ expect(isValidRegex(undefined)).toBe(false)
31
+ expect(isValidRegex(null)).toBe(false)
32
+ expect(isValidRegex(123)).toBe(false)
33
+ expect(isValidRegex({})).toBe(false)
34
+ expect(isValidRegex([])).toBe(false)
35
+ expect(isValidRegex(true)).toBe(false)
36
+ })
37
+
38
+ it('returns true for an empty string (valid regex)', () => {
39
+ expect(isValidRegex('')).toBe(true) // equivalent to: new RegExp('')
40
+ })
41
+ })
@@ -0,0 +1,78 @@
1
+ import { describe, it, expect } from 'vitest'
2
+
3
+ import {
4
+ sanitizeObject,
5
+ sanitizeUndefinedFields,
6
+ sanitizeObjectAllowProps,
7
+ sanitizeObjectDisallowProps,
8
+ } from '../../src/core/sanitize-objects.js'
9
+
10
+ describe('sanitizeObject', () => {
11
+ it('filters object based on provided filter function', () => {
12
+ const result = sanitizeObject({ a: 1, b: 2, c: 3 }, ([key]) => key !== 'b')
13
+ expect(result).toEqual({ a: 1, c: 3 })
14
+ })
15
+
16
+ it('returns empty object when no entries pass the filter', () => {
17
+ const result = sanitizeObject({ a: 1 }, () => false)
18
+ expect(result).toEqual({})
19
+ })
20
+
21
+ it('returns full object when all entries pass the filter', () => {
22
+ const input = { a: 1, b: 2 }
23
+ const result = sanitizeObject(input, () => true)
24
+ expect(result).toEqual(input)
25
+ })
26
+ })
27
+
28
+ describe('sanitizeUndefinedFields', () => {
29
+ it('removes properties with undefined values', () => {
30
+ const result = sanitizeUndefinedFields({ a: 1, b: undefined, c: null })
31
+ expect(result).toEqual({ a: 1, c: null })
32
+ })
33
+
34
+ it('returns empty object if all values are undefined', () => {
35
+ const result = sanitizeUndefinedFields({ a: undefined, b: undefined })
36
+ expect(result).toEqual({})
37
+ })
38
+
39
+ it('does not remove null or falsy (but defined) values', () => {
40
+ const result = sanitizeUndefinedFields({ a: null, b: 0, c: false, d: '' })
41
+ expect(result).toEqual({ a: null, b: 0, c: false, d: '' })
42
+ })
43
+ })
44
+
45
+ describe('sanitizeObjectAllowProps', () => {
46
+ it('keeps only allowed fields', () => {
47
+ const result = sanitizeObjectAllowProps({ a: 1, b: 2, c: 3 }, ['a', 'c'])
48
+ expect(result).toEqual({ a: 1, c: 3 })
49
+ })
50
+
51
+ it('returns empty object if allowedFields is empty', () => {
52
+ const result = sanitizeObjectAllowProps({ a: 1, b: 2 }, [])
53
+ expect(result).toEqual({})
54
+ })
55
+
56
+ it('ignores fields not present in the object', () => {
57
+ const result = sanitizeObjectAllowProps({ a: 1 }, ['a', 'b', 'c'])
58
+ expect(result).toEqual({ a: 1 })
59
+ })
60
+ })
61
+
62
+ describe('sanitizeObjectDisallowProps', () => {
63
+ it('removes disallowed fields from object', () => {
64
+ const result = sanitizeObjectDisallowProps({ a: 1, b: 2, c: 3 }, ['b'])
65
+ expect(result).toEqual({ a: 1, c: 3 })
66
+ })
67
+
68
+ it('returns full object if disallowedFields is empty', () => {
69
+ const input = { a: 1, b: 2 }
70
+ const result = sanitizeObjectDisallowProps(input, [])
71
+ expect(result).toEqual(input)
72
+ })
73
+
74
+ it('removes all properties if all are disallowed', () => {
75
+ const result = sanitizeObjectDisallowProps({ a: 1, b: 2 }, ['a', 'b'])
76
+ expect(result).toEqual({})
77
+ })
78
+ })
@@ -0,0 +1,130 @@
1
+ import { describe, it, expect } from 'vitest'
2
+
3
+ import {
4
+ getSalt,
5
+ encrypt,
6
+ getSaltHex,
7
+ isPasswordMatch,
8
+ getEncryptedBuffer,
9
+ } from '../../src/crypto/crypto.js'
10
+
11
+ const examplePassword = 'S3cretP@ssword'
12
+ const examplePrivateKey = 'my-private-key'
13
+
14
+ describe('getSalt', () => {
15
+ it('returns a Buffer of the correct length', () => {
16
+ const salt = getSalt(16)
17
+ expect(Buffer.isBuffer(salt)).toBe(true)
18
+ expect(salt.length).toBe(16)
19
+ })
20
+ })
21
+
22
+ describe('getSaltHex', () => {
23
+ it('returns a hex string of expected length', () => {
24
+ const saltHex = getSaltHex(16)
25
+ expect(typeof saltHex).toBe('string')
26
+ expect(saltHex.length).toBe(32) // 16 bytes → 32 hex chars
27
+ expect(/^[0-9a-f]+$/i.test(saltHex)).toBe(true)
28
+ })
29
+ })
30
+
31
+ describe('getEncryptedBuffer', () => {
32
+ it('returns a Buffer of the correct derived key length', async () => {
33
+ const salt = 'abc123'
34
+ const buffer = await getEncryptedBuffer({
35
+ expression: examplePassword,
36
+ salt,
37
+ length: 64,
38
+ })
39
+ expect(Buffer.isBuffer(buffer)).toBe(true)
40
+ expect(buffer.length).toBe(64)
41
+ })
42
+ })
43
+
44
+ describe('encrypt', () => {
45
+ it('returns a hex string from encrypted input', async () => {
46
+ const salt = 'abc123'
47
+ const encrypted = await encrypt({
48
+ expression: examplePassword,
49
+ salt,
50
+ passwordPrivateKey: examplePrivateKey,
51
+ })
52
+ expect(typeof encrypted).toBe('string')
53
+ expect(encrypted.length).toBeGreaterThan(0)
54
+ expect(/^[0-9a-f]+$/i.test(encrypted)).toBe(true)
55
+ })
56
+
57
+ it('produces different output when private key changes', async () => {
58
+ const salt = 'abc123'
59
+
60
+ const encrypted1 = await encrypt({
61
+ expression: examplePassword,
62
+ salt,
63
+ passwordPrivateKey: 'A',
64
+ })
65
+
66
+ const encrypted2 = await encrypt({
67
+ expression: examplePassword,
68
+ salt,
69
+ passwordPrivateKey: 'B',
70
+ })
71
+
72
+ expect(encrypted1).not.toEqual(encrypted2)
73
+ })
74
+ })
75
+
76
+ describe('isPasswordMatch', () => {
77
+ it('returns true when password matches encrypted value', async () => {
78
+ const salt = getSaltHex(16)
79
+ const encrypted = await encrypt({
80
+ expression: examplePassword,
81
+ salt,
82
+ passwordPrivateKey: examplePrivateKey,
83
+ })
84
+
85
+ const result = await isPasswordMatch({
86
+ salt,
87
+ password: examplePassword,
88
+ encryptedPassword: encrypted,
89
+ passwordPrivateKey: examplePrivateKey,
90
+ })
91
+
92
+ expect(result).toBe(true)
93
+ })
94
+
95
+ it('returns false when password does not match', async () => {
96
+ const salt = getSaltHex(16)
97
+ const encrypted = await encrypt({
98
+ expression: examplePassword,
99
+ salt,
100
+ passwordPrivateKey: examplePrivateKey,
101
+ })
102
+
103
+ const result = await isPasswordMatch({
104
+ salt,
105
+ password: 'wrong-password',
106
+ encryptedPassword: encrypted,
107
+ passwordPrivateKey: examplePrivateKey,
108
+ })
109
+
110
+ expect(result).toBe(false)
111
+ })
112
+
113
+ it('returns false when private key is incorrect', async () => {
114
+ const salt = getSaltHex(16)
115
+ const encrypted = await encrypt({
116
+ expression: examplePassword,
117
+ salt,
118
+ passwordPrivateKey: 'correct-key',
119
+ })
120
+
121
+ const result = await isPasswordMatch({
122
+ salt,
123
+ password: examplePassword,
124
+ encryptedPassword: encrypted,
125
+ passwordPrivateKey: 'wrong-key',
126
+ })
127
+
128
+ expect(result).toBe(false)
129
+ })
130
+ })
@@ -0,0 +1,73 @@
1
+ // @ts-nocheck
2
+ import { describe, it, expect } from 'vitest'
3
+
4
+ import { encryptPassword } from '../../src/crypto/encryption.js'
5
+
6
+ describe('encryptPassword', () => {
7
+ const password = 'MyS3cretP@ss'
8
+ const privateKey = 'abc123'
9
+ const saltLength = 16
10
+
11
+ it('returns salt and password in expected format', async () => {
12
+ const result = await encryptPassword(
13
+ { password },
14
+ { saltLength, passwordPrivateKey: privateKey },
15
+ )
16
+
17
+ expect(typeof result).toBe('object')
18
+ expect(typeof result.salt).toBe('string')
19
+ expect(typeof result.password).toBe('string')
20
+
21
+ expect(result.salt.length).toBe(saltLength * 2) // because it's hex
22
+ expect(result.salt).toMatch(/^[0-9a-f]+$/i)
23
+ expect(result.password).toMatch(/^[0-9a-f]+$/i)
24
+ })
25
+
26
+ it('produces different output for the same password (due to different salts)', async () => {
27
+ const result1 = await encryptPassword(
28
+ { password },
29
+ { saltLength, passwordPrivateKey: privateKey },
30
+ )
31
+
32
+ const result2 = await encryptPassword(
33
+ { password },
34
+ { saltLength, passwordPrivateKey: privateKey },
35
+ )
36
+
37
+ expect(result1.password).not.toEqual(result2.password)
38
+ expect(result1.salt).not.toEqual(result2.salt)
39
+ })
40
+
41
+ it('produces different output when passwordPrivateKey is changed', async () => {
42
+ const result1 = await encryptPassword(
43
+ { password },
44
+ { saltLength, passwordPrivateKey: 'key1' },
45
+ )
46
+
47
+ const result2 = await encryptPassword(
48
+ { password },
49
+ { saltLength, passwordPrivateKey: 'key2' },
50
+ )
51
+
52
+ expect(result1.password).not.toEqual(result2.password)
53
+ })
54
+
55
+ it('works without passwordPrivateKey', async () => {
56
+ const result = await encryptPassword({ password }, { saltLength })
57
+
58
+ expect(result).toHaveProperty('salt')
59
+ expect(result).toHaveProperty('password')
60
+ })
61
+
62
+ it('throws if password is missing', async () => {
63
+ await expect(() =>
64
+ encryptPassword({}, { saltLength, passwordPrivateKey: privateKey }),
65
+ ).rejects.toThrow()
66
+ })
67
+
68
+ it('throws if saltLength is missing', async () => {
69
+ await expect(() =>
70
+ encryptPassword({ password }, { passwordPrivateKey: privateKey }),
71
+ ).rejects.toThrow()
72
+ })
73
+ })
@@ -0,0 +1,72 @@
1
+ import { describe, it, expect } from 'vitest'
2
+
3
+ import {
4
+ generateId,
5
+ generateUserId,
6
+ generateTenantId,
7
+ generatePrefixedId,
8
+ generatePermissionId,
9
+ generateCorrelationId,
10
+ generateVerificationId,
11
+ generateRolePermissionsId,
12
+ } from '../../src/ids/generators.js'
13
+ import { ID_PREFIXES } from '../../src/ids/prefixes.js'
14
+
15
+ const UUID_V4_REGEX =
16
+ /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
17
+
18
+ const testPrefixFunction = (fn, expectedPrefix) => {
19
+ const id = fn()
20
+ expect(typeof id).toBe('string')
21
+ const [prefix, uuid] = id.split('_')
22
+ expect(prefix).toBe(expectedPrefix)
23
+ expect(uuid).toMatch(UUID_V4_REGEX)
24
+ }
25
+
26
+ describe('generateId', () => {
27
+ it('generates a valid UUID v4', () => {
28
+ const id = generateId()
29
+ expect(typeof id).toBe('string')
30
+ expect(id).toMatch(UUID_V4_REGEX)
31
+ })
32
+
33
+ it('generates unique UUIDs', () => {
34
+ const ids = new Set(Array.from({ length: 10 }, () => generateId()))
35
+ expect(ids.size).toBe(10)
36
+ })
37
+ })
38
+
39
+ describe('generatePrefixedId', () => {
40
+ it('generates an ID with the correct prefix', () => {
41
+ const prefixed = generatePrefixedId('test')
42
+ const [prefix, uuid] = prefixed.split('_')
43
+ expect(prefix).toBe('test')
44
+ expect(uuid).toMatch(UUID_V4_REGEX)
45
+ })
46
+ })
47
+
48
+ describe('generate*Id functions', () => {
49
+ it('generateUserId returns ID with usr_ prefix', () => {
50
+ testPrefixFunction(generateUserId, ID_PREFIXES.USER)
51
+ })
52
+
53
+ it('generateTenantId returns ID with tnt_ prefix', () => {
54
+ testPrefixFunction(generateTenantId, ID_PREFIXES.TENANT)
55
+ })
56
+
57
+ it('generatePermissionId returns ID with prm_ prefix', () => {
58
+ testPrefixFunction(generatePermissionId, ID_PREFIXES.PERMISSION)
59
+ })
60
+
61
+ it('generateCorrelationId returns ID with crln_ prefix', () => {
62
+ testPrefixFunction(generateCorrelationId, ID_PREFIXES.CORRELATION)
63
+ })
64
+
65
+ it('generateVerificationId returns ID with vrf_ prefix', () => {
66
+ testPrefixFunction(generateVerificationId, ID_PREFIXES.VERIFICATION)
67
+ })
68
+
69
+ it('generateRolePermissionsId returns ID with role_ prefix', () => {
70
+ testPrefixFunction(generateRolePermissionsId, ID_PREFIXES.ROLE_PERMISSIONS)
71
+ })
72
+ })
@@ -0,0 +1,42 @@
1
+ // @ts-nocheck
2
+ import { describe, it, expect } from 'vitest'
3
+
4
+ import { ID_PREFIXES } from '../../src/ids/prefixes.js'
5
+
6
+ describe('ID_PREFIXES', () => {
7
+ it('contains expected keys and values', () => {
8
+ expect(ID_PREFIXES).toEqual({
9
+ USER: 'usr',
10
+ TENANT: 'tnt',
11
+ PERMISSION: 'prm',
12
+ CORRELATION: 'crln',
13
+ VERIFICATION: 'vrf',
14
+ ROLE_PERMISSIONS: 'role',
15
+ })
16
+ })
17
+
18
+ it('has string values for all keys', () => {
19
+ Object.values(ID_PREFIXES).forEach((value) => {
20
+ expect(typeof value).toBe('string')
21
+ })
22
+ })
23
+
24
+ it('has unique values', () => {
25
+ const values = Object.values(ID_PREFIXES)
26
+ const unique = new Set(values)
27
+ expect(unique.size).toBe(values.length)
28
+ })
29
+
30
+ it('is frozen (immutable)', () => {
31
+ expect(Object.isFrozen(ID_PREFIXES)).toBe(true)
32
+
33
+ // Try to mutate
34
+ try {
35
+ ID_PREFIXES.USER = 'hacked'
36
+ } catch (_) {
37
+ // Ignore error in strict mode
38
+ }
39
+
40
+ expect(ID_PREFIXES.USER).toBe('usr')
41
+ })
42
+ })
@@ -0,0 +1,64 @@
1
+ import { describe, it, expect, vi } from 'vitest'
2
+ import { getLogger } from '../../src/logger/get-logger.js'
3
+
4
+ describe('getLogger', () => {
5
+ it('returns a default pino logger when called with undefined', () => {
6
+ const logger = getLogger(undefined)
7
+ expect(typeof logger.info).toBe('function')
8
+ // @ts-ignore
9
+ expect(logger.level).toBe('info')
10
+ })
11
+
12
+ it('returns a default pino logger when called with true', () => {
13
+ const logger = getLogger(true)
14
+ expect(typeof logger.info).toBe('function')
15
+ // @ts-ignore
16
+ expect(logger.level).toBe('info')
17
+ })
18
+
19
+ it('returns a pino logger when called with { logger: true } and optional level', () => {
20
+ const logger = getLogger({ logger: true, level: 'debug' })
21
+ expect(typeof logger.debug).toBe('function')
22
+ // @ts-ignore
23
+ expect(logger.level).toBe('debug')
24
+ })
25
+
26
+ it('returns the custom logger when provided and valid', () => {
27
+ const mockLogger = {
28
+ info: vi.fn(),
29
+ warn: vi.fn(),
30
+ error: vi.fn(),
31
+ debug: vi.fn(),
32
+ }
33
+
34
+ const result = getLogger({ logger: mockLogger })
35
+ expect(result).toBe(mockLogger)
36
+ })
37
+
38
+ it('returns the dummy logger when logger is invalid', () => {
39
+ const invalidLogger = { info: () => {}, warn: () => {} } // missing 'error' and 'debug'
40
+ const logger = getLogger({ logger: invalidLogger })
41
+
42
+ expect(logger.info).toBeDefined()
43
+ expect(logger.warn).toBeDefined()
44
+ expect(logger.error).toBeDefined()
45
+ expect(logger.debug).toBeDefined()
46
+
47
+ // Check that it's the dummy logger (no-op)
48
+ expect(() => logger.info('hello')).not.toThrow()
49
+ // @ts-ignore
50
+ expect(logger.info()).toBeUndefined()
51
+ })
52
+
53
+ it('returns the dummy logger when called with invalid object', () => {
54
+ const result = getLogger({ someOtherKey: 123 })
55
+ expect(result.info).toBeDefined()
56
+ expect(result.warn).toBeDefined()
57
+ })
58
+
59
+ it('logs a message when using internal pino', () => {
60
+ const logger = getLogger({ logger: true, level: 'warn' })
61
+ // @ts-ignore
62
+ expect(logger.level).toBe('warn')
63
+ })
64
+ })
@@ -1,10 +0,0 @@
1
- /**
2
- * @typedef {object} Reply
3
- * @property {(code: number) => Reply} status - Sets the HTTP status code
4
- * @property {(payload: any) => void} send - Sends the response
5
- */
6
-
7
- /**
8
- * @typedef {object} Logger
9
- * @property {(message: string, ...args: any[]) => void} error - Logs an error message
10
- */