core-services-sdk 1.3.16 → 1.3.18

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "core-services-sdk",
3
- "version": "1.3.16",
3
+ "version": "1.3.18",
4
4
  "main": "src/index.js",
5
5
  "type": "module",
6
6
  "scripts": {
package/src/core/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './regex-utils.js'
2
2
  export * from './otp-generators.js'
3
3
  export * from './sanitize-objects.js'
4
+ export * from './normalize-min-max.js'
4
5
  export * from './normalize-to-array.js'
5
6
  export * from './combine-unique-arrays.js'
6
7
  export * from './normalize-phone-number.js'
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Normalize minimum and maximum numeric policy values against defaults.
3
+ *
4
+ * This utility ensures:
5
+ * - Fallback to `defaultMinMax` if `valuesMinMax` is not provided or invalid.
6
+ * - Both `min` and `max` are clamped to stay within the default range.
7
+ * - Guarantees `min <= max` by adjusting `max` when necessary.
8
+ *
9
+ * @param {{ min: number, max: number }} defaultMinMax
10
+ * The default minimum and maximum values. These act as the allowed range boundaries.
11
+ *
12
+ * @param {{ min?: number, max?: number } | null | undefined} valuesMinMax
13
+ * Custom minimum and/or maximum values. May be partial, null, or undefined.
14
+ * Non-numeric inputs are ignored in favor of the default values.
15
+ *
16
+ * @returns {{ min: number, max: number }}
17
+ * Normalized min and max values that respect the defaults and guarantee a valid range.
18
+ *
19
+ * @example
20
+ * // Within range, keeps given values
21
+ * normalizeMinMax({ min: 8, max: 64 }, { min: 10, max: 32 })
22
+ * // → { min: 10, max: 32 }
23
+ *
24
+ * @example
25
+ * // If min > max, coerces max to be at least min
26
+ * normalizeMinMax({ min: 8, max: 64 }, { min: 60, max: 20 })
27
+ * // → { min: 60, max: 60 }
28
+ *
29
+ * @example
30
+ * // Values outside default range are clamped
31
+ * normalizeMinMax({ min: 8, max: 64 }, { min: 4, max: 100 })
32
+ * // → { min: 8, max: 64 }
33
+ *
34
+ * @example
35
+ * // Missing or invalid input falls back to defaults
36
+ * normalizeMinMax({ min: 8, max: 64 }, null)
37
+ * // → { min: 8, max: 64 }
38
+ */
39
+ export const normalizeMinMax = (defaultMinMax, valuesMinMax) => {
40
+ if (!valuesMinMax || typeof valuesMinMax !== 'object') {
41
+ return { ...defaultMinMax }
42
+ }
43
+
44
+ const { min, max } = valuesMinMax
45
+ const valuesMinMaxFixed = {
46
+ min: typeof min === 'number' ? min : defaultMinMax.min,
47
+ max: typeof max === 'number' ? max : defaultMinMax.max,
48
+ }
49
+
50
+ const minMax = {
51
+ min: Math.min(
52
+ Math.max(valuesMinMaxFixed.min, defaultMinMax.min),
53
+ defaultMinMax.max,
54
+ ),
55
+ max: Math.min(valuesMinMaxFixed.max, defaultMinMax.max),
56
+ }
57
+
58
+ return {
59
+ min: minMax.min,
60
+ max: minMax.min > minMax.max ? minMax.min : minMax.max,
61
+ }
62
+ }
@@ -1,12 +1,16 @@
1
1
  import pino from 'pino'
2
2
 
3
- const requiredMethods = ['info', 'warn', 'error', 'debug']
3
+ const requiredMethods = ['info', 'warn', 'error', 'debug', 'fatal', 'trace']
4
4
 
5
5
  const dummyLogger = {
6
6
  info: () => {},
7
7
  warn: () => {},
8
- error: () => {},
8
+ trace: () => {},
9
9
  debug: () => {},
10
+ error: () => {},
11
+ fatal: () => {},
12
+ levels: () => {},
13
+ silent: () => {},
10
14
  child() {
11
15
  return this
12
16
  },
@@ -0,0 +1,83 @@
1
+ // tests/unit/utils/normalize-min-max.unit.test.js
2
+ import { describe, it, expect } from 'vitest'
3
+ import { normalizeMinMax } from '../../src/core/normalize-min-max.js'
4
+
5
+ describe('normalizeMinMax', () => {
6
+ const defaults = { min: 8, max: 64 }
7
+
8
+ it('returns defaults if valuesMinMax is null', () => {
9
+ expect(normalizeMinMax(defaults, null)).toEqual(defaults)
10
+ })
11
+
12
+ it('returns defaults if valuesMinMax is undefined', () => {
13
+ expect(normalizeMinMax(defaults, undefined)).toEqual(defaults)
14
+ })
15
+
16
+ it('returns defaults if valuesMinMax is not an object', () => {
17
+ // @ts-ignore
18
+ expect(normalizeMinMax(defaults, 'invalid')).toEqual(defaults)
19
+ })
20
+
21
+ it('uses provided values when within range', () => {
22
+ expect(normalizeMinMax(defaults, { min: 10, max: 32 })).toEqual({
23
+ min: 10,
24
+ max: 32,
25
+ })
26
+ })
27
+
28
+ it('clamps values below minimum to default.min', () => {
29
+ expect(normalizeMinMax(defaults, { min: 4, max: 20 })).toEqual({
30
+ min: 8,
31
+ max: 20,
32
+ })
33
+ })
34
+
35
+ it('clamps values above maximum to default.max', () => {
36
+ expect(normalizeMinMax(defaults, { min: 20, max: 100 })).toEqual({
37
+ min: 20,
38
+ max: 64,
39
+ })
40
+ })
41
+
42
+ it('ensures max is not lower than min', () => {
43
+ expect(normalizeMinMax(defaults, { min: 60, max: 20 })).toEqual({
44
+ min: 60,
45
+ max: 60,
46
+ })
47
+ })
48
+
49
+ it('falls back to defaults if min is not a number', () => {
50
+ // @ts-ignore
51
+ expect(normalizeMinMax(defaults, { min: 'abc', max: 32 })).toEqual({
52
+ min: 8,
53
+ max: 32,
54
+ })
55
+ })
56
+
57
+ it('falls back to defaults if max is not a number', () => {
58
+ // @ts-ignore
59
+ expect(normalizeMinMax(defaults, { min: 10, max: 'zzz' })).toEqual({
60
+ min: 10,
61
+ max: 64,
62
+ })
63
+ })
64
+
65
+ it('handles partial input (only min provided)', () => {
66
+ expect(normalizeMinMax(defaults, { min: 12 })).toEqual({
67
+ min: 12,
68
+ max: 64,
69
+ })
70
+ })
71
+
72
+ it('handles partial input (only max provided)', () => {
73
+ expect(normalizeMinMax(defaults, { max: 30 })).toEqual({
74
+ min: 8,
75
+ max: 30,
76
+ })
77
+ })
78
+
79
+ it('returns defaults if both values are invalid', () => {
80
+ // @ts-ignore
81
+ expect(normalizeMinMax(defaults, { min: 'a', max: null })).toEqual(defaults)
82
+ })
83
+ })
@@ -29,34 +29,42 @@ describe('getLogger', () => {
29
29
  warn: vi.fn(),
30
30
  error: vi.fn(),
31
31
  debug: vi.fn(),
32
+ fatal: vi.fn(),
33
+ trace: vi.fn(),
32
34
  }
33
35
 
34
36
  const result = getLogger({ logger: mockLogger })
35
37
  expect(result).toBe(mockLogger)
36
38
  })
37
39
 
38
- it('returns the dummy logger when logger is invalid', () => {
39
- const invalidLogger = { info: () => {}, warn: () => {} } // missing 'error' and 'debug'
40
+ it('returns the dummy logger when logger is invalid (missing methods)', () => {
41
+ const invalidLogger = { info: () => {}, warn: () => {} } // missing required methods
40
42
  const logger = getLogger({ logger: invalidLogger })
41
43
 
42
44
  expect(logger.info).toBeDefined()
43
45
  expect(logger.warn).toBeDefined()
44
46
  expect(logger.error).toBeDefined()
45
47
  expect(logger.debug).toBeDefined()
48
+ expect(logger.fatal).toBeDefined()
49
+ expect(logger.trace).toBeDefined()
46
50
 
47
- // Check that it's the dummy logger (no-op)
51
+ // dummy logger methods are no-ops
48
52
  expect(() => logger.info('hello')).not.toThrow()
49
53
  // @ts-ignore
50
54
  expect(logger.info()).toBeUndefined()
51
55
  })
52
56
 
53
- it('returns the dummy logger when called with invalid object', () => {
57
+ it('returns the dummy logger when called with unrelated object', () => {
54
58
  const result = getLogger({ someOtherKey: 123 })
55
59
  expect(result.info).toBeDefined()
56
60
  expect(result.warn).toBeDefined()
61
+ expect(result.error).toBeDefined()
62
+ expect(result.debug).toBeDefined()
63
+ expect(result.fatal).toBeDefined()
64
+ expect(result.trace).toBeDefined()
57
65
  })
58
66
 
59
- it('logs a message when using internal pino', () => {
67
+ it('logs a message when using internal pino with level warn', () => {
60
68
  const logger = getLogger({ logger: true, level: 'warn' })
61
69
  // @ts-ignore
62
70
  expect(logger.level).toBe('warn')