core-services-sdk 1.3.75 → 1.3.77

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.75",
3
+ "version": "1.3.77",
4
4
  "main": "src/index.js",
5
5
  "type": "module",
6
6
  "types": "types/index.d.ts",
@@ -307,3 +307,105 @@ export function formatEnvReport(report) {
307
307
  report.success ? 'All variables are valid.' : 'Some variables are invalid.',
308
308
  ].join('\n')
309
309
  }
310
+
311
+ /**
312
+ * Validates environment variables end-to-end and builds a full report.
313
+ *
314
+ * This function:
315
+ * - validates values using the schema definition
316
+ * - builds a structured report (including masking secrets)
317
+ * - formats a printable output
318
+ *
319
+ * @param {Record<string, Object>} definition
320
+ * Environment schema definition.
321
+ *
322
+ * @param {Record<string, any>} values
323
+ * Raw environment values (e.g. process.env).
324
+ *
325
+ * @param {{
326
+ * mask?: (value: any) => string
327
+ * }} [options]
328
+ *
329
+ * @returns {{
330
+ * success: boolean,
331
+ * validation: {
332
+ * success: boolean,
333
+ * data?: Record<string, any>,
334
+ * summary?: Record<string, string[]>
335
+ * },
336
+ * report: {
337
+ * success: boolean,
338
+ * params: Array<{
339
+ * key: string,
340
+ * value: any,
341
+ * displayValue: string,
342
+ * secret: boolean,
343
+ * valid: boolean,
344
+ * errors?: string[]
345
+ * }>
346
+ * },
347
+ * output: string
348
+ * }}
349
+ */
350
+ export function validateAndReportEnv(definition, values, options = {}) {
351
+ const { mask } = options
352
+
353
+ const validation = validateEnv(definition, values)
354
+ const report = buildEnvReport(definition, values, validation, mask)
355
+ const output = formatEnvReport(report)
356
+
357
+ return {
358
+ success: validation.success,
359
+ validation,
360
+ report,
361
+ output,
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Validates environment variables and prepares
367
+ * a printable table output.
368
+ *
369
+ * No side effects. Does NOT print.
370
+ *
371
+ * @param {Record<string, Object>} definition
372
+ * @param {Record<string, any>} values
373
+ * @param {{
374
+ * mask?: (value: any) => string
375
+ * }} [options]
376
+ *
377
+ * @returns {{
378
+ * success: boolean,
379
+ * table: string,
380
+ * validation: {
381
+ * success: boolean,
382
+ * data?: Record<string, any>,
383
+ * summary?: Record<string, string[]>
384
+ * },
385
+ * report: {
386
+ * success: boolean,
387
+ * params: Array<{
388
+ * key: string,
389
+ * value: any,
390
+ * displayValue: string,
391
+ * secret: boolean,
392
+ * valid: boolean,
393
+ * errors?: string[]
394
+ * }>
395
+ * }
396
+ * }}
397
+ */
398
+ export function prepareEnvValidation(definition, values, options = {}) {
399
+ const { mask } = options
400
+
401
+ const validation = validateEnv(definition, values)
402
+ const report = buildEnvReport(definition, values, validation, mask)
403
+ const table = formatEnvReport(report)
404
+
405
+ return {
406
+ success: validation.success,
407
+ table,
408
+ validation,
409
+ report,
410
+ }
411
+ }
@@ -0,0 +1,139 @@
1
+ // @ts-nocheck
2
+ import { validateAndReportEnv } from '../../src/env/env-validation.js'
3
+
4
+ // mask example
5
+ const mask = (value) => {
6
+ if (value == null) {
7
+ return '******'
8
+ }
9
+
10
+ const str = String(value)
11
+ if (str.length <= 4) {
12
+ return '****'
13
+ }
14
+
15
+ return `${str.slice(0, 2)}****${str.slice(-2)}`
16
+ }
17
+
18
+ /**
19
+ * Definitions
20
+ */
21
+ const definition = {
22
+ PORT: {
23
+ type: 'number',
24
+ required: true,
25
+ int: true,
26
+ min: 1,
27
+ max: 65535,
28
+ },
29
+
30
+ TIMEOUT: {
31
+ type: 'number',
32
+ min: 100,
33
+ max: 10000,
34
+ },
35
+
36
+ RETRIES: {
37
+ type: 'number',
38
+ int: true,
39
+ min: 0,
40
+ },
41
+
42
+ DEBUG: {
43
+ type: 'boolean',
44
+ },
45
+
46
+ MODE: {
47
+ type: 'string',
48
+ enum: ['development', 'production'],
49
+ },
50
+
51
+ API_KEY: {
52
+ type: 'string',
53
+ secret: true,
54
+ },
55
+ }
56
+
57
+ /**
58
+ * Values scenarios
59
+ */
60
+ const scenarios = [
61
+ {
62
+ title: '✅ All valid values',
63
+ values: {
64
+ PORT: 3000,
65
+ TIMEOUT: 500,
66
+ RETRIES: 3,
67
+ DEBUG: false,
68
+ MODE: 'development',
69
+ API_KEY: 'secret123',
70
+ },
71
+ },
72
+ {
73
+ title: '❌ Number too small (PORT)',
74
+ values: {
75
+ PORT: 0,
76
+ TIMEOUT: 500,
77
+ RETRIES: 3,
78
+ DEBUG: true,
79
+ MODE: 'production',
80
+ API_KEY: 'secret123',
81
+ },
82
+ },
83
+ {
84
+ title: '❌ Number too large (TIMEOUT)',
85
+ values: {
86
+ PORT: 3000,
87
+ TIMEOUT: 20000,
88
+ RETRIES: 1,
89
+ DEBUG: false,
90
+ MODE: 'development',
91
+ API_KEY: 'secret123',
92
+ },
93
+ },
94
+ {
95
+ title: '❌ Invalid number (string)',
96
+ values: {
97
+ PORT: 'abc',
98
+ TIMEOUT: 500,
99
+ RETRIES: 2,
100
+ DEBUG: false,
101
+ MODE: 'development',
102
+ API_KEY: 'secret123',
103
+ },
104
+ },
105
+ {
106
+ title: '❌ Invalid enum (MODE)',
107
+ values: {
108
+ PORT: 3000,
109
+ TIMEOUT: 500,
110
+ RETRIES: 2,
111
+ DEBUG: false,
112
+ MODE: 'prod',
113
+ API_KEY: 'secret123',
114
+ },
115
+ },
116
+ {
117
+ title: '✅ Boolean coercion + missing secret',
118
+ values: {
119
+ PORT: '8080',
120
+ TIMEOUT: '1000',
121
+ RETRIES: '0',
122
+ DEBUG: 'true',
123
+ MODE: 'production',
124
+ },
125
+ },
126
+ ]
127
+
128
+ /**
129
+ * Run scenarios
130
+ */
131
+ for (const scenario of scenarios) {
132
+ console.log('\n===================================================')
133
+ console.log(scenario.title)
134
+ console.log('===================================================\n')
135
+
136
+ const result = validateAndReportEnv(definition, scenario.values, { mask })
137
+
138
+ console.log(result.output)
139
+ }
@@ -0,0 +1,86 @@
1
+ // @ts-nocheck
2
+ import { prepareEnvValidation } from '../../src/env/env-validation.js'
3
+
4
+ const mask = (value) => {
5
+ if (value == null) {
6
+ return '******'
7
+ }
8
+
9
+ const str = String(value)
10
+ if (str.length <= 4) {
11
+ return '****'
12
+ }
13
+
14
+ return `${str.slice(0, 2)}****${str.slice(-2)}`
15
+ }
16
+
17
+ const definition = {
18
+ PORT: {
19
+ type: 'number',
20
+ required: true,
21
+ int: true,
22
+ min: 1,
23
+ max: 65535,
24
+ },
25
+ TIMEOUT: {
26
+ type: 'number',
27
+ min: 100,
28
+ max: 10000,
29
+ },
30
+ DEBUG: {
31
+ type: 'boolean',
32
+ },
33
+ MODE: {
34
+ type: 'string',
35
+ enum: ['development', 'production'],
36
+ },
37
+ API_KEY: {
38
+ type: 'string',
39
+ secret: true,
40
+ },
41
+ }
42
+
43
+ const scenarios = [
44
+ {
45
+ title: '✅ All valid values',
46
+ values: {
47
+ PORT: 3000,
48
+ TIMEOUT: 500,
49
+ DEBUG: false,
50
+ MODE: 'development',
51
+ API_KEY: 'secret123',
52
+ },
53
+ },
54
+ {
55
+ title: '❌ Invalid port',
56
+ values: {
57
+ PORT: 0,
58
+ TIMEOUT: 500,
59
+ MODE: 'production',
60
+ },
61
+ },
62
+ {
63
+ title: '❌ Invalid enum',
64
+ values: {
65
+ PORT: 3000,
66
+ TIMEOUT: 500,
67
+ MODE: 'prod',
68
+ API_KEY: 'secret123',
69
+ },
70
+ },
71
+ ]
72
+
73
+ for (const scenario of scenarios) {
74
+ console.log('\n===================================================')
75
+ console.log(scenario.title)
76
+ console.log('===================================================\n')
77
+
78
+ const result = prepareEnvValidation(definition, scenario.values, { mask })
79
+
80
+ // פה הבחירה שלך מה לעשות עם זה
81
+ console.log(result.table)
82
+
83
+ if (!result.success) {
84
+ console.log('⚠️ Scenario failed validation')
85
+ }
86
+ }
@@ -0,0 +1,84 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { prepareEnvValidation } from '../../src/env/env-validation.js'
3
+
4
+ describe('prepareEnvValidation', () => {
5
+ const definition = {
6
+ PORT: {
7
+ type: 'number',
8
+ required: true,
9
+ int: true,
10
+ min: 1,
11
+ max: 65535,
12
+ },
13
+ MODE: {
14
+ type: 'string',
15
+ enum: ['development', 'production'],
16
+ required: true,
17
+ },
18
+ API_KEY: {
19
+ type: 'string',
20
+ secret: true,
21
+ },
22
+ }
23
+
24
+ it('returns success and a printable table when values are valid', () => {
25
+ const values = {
26
+ PORT: '3000',
27
+ MODE: 'development',
28
+ API_KEY: 'secret',
29
+ }
30
+
31
+ const result = prepareEnvValidation(definition, values, { mask })
32
+
33
+ expect(result.success).toBe(true)
34
+ expect(result.validation.success).toBe(true)
35
+
36
+ expect(result.table).toContain('Environment variables')
37
+ expect(result.table).toContain('PORT')
38
+ expect(result.table).toContain('MODE')
39
+ expect(result.table).toContain('API_KEY')
40
+
41
+ expect(result.table).toContain('OK')
42
+ expect(result.table).toContain('****')
43
+ expect(result.table).not.toContain('secret')
44
+ })
45
+
46
+ it('returns failure and error table when required value is missing', () => {
47
+ const values = {
48
+ MODE: 'production',
49
+ }
50
+
51
+ const result = prepareEnvValidation(definition, values)
52
+
53
+ expect(result.success).toBe(false)
54
+ expect(result.validation.success).toBe(false)
55
+
56
+ expect(result.table).toContain('ERROR')
57
+ expect(result.table).toContain('PORT')
58
+ })
59
+
60
+ it('coerces number values correctly', () => {
61
+ const values = {
62
+ PORT: '8080',
63
+ MODE: 'production',
64
+ API_KEY: 'x',
65
+ }
66
+
67
+ const result = prepareEnvValidation(definition, values)
68
+
69
+ expect(result.success).toBe(true)
70
+ expect(result.validation.data.PORT).toBe(8080)
71
+ })
72
+
73
+ it('returns a table string even on failure', () => {
74
+ const values = {
75
+ PORT: 0,
76
+ MODE: 'development',
77
+ }
78
+
79
+ const result = prepareEnvValidation(definition, values)
80
+
81
+ expect(typeof result.table).toBe('string')
82
+ expect(result.table.length).toBeGreaterThan(0)
83
+ })
84
+ })
@@ -0,0 +1,104 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { validateAndReportEnv } from '../../src/env/env-validation.js'
3
+
4
+ describe('validateAndReportEnv', () => {
5
+ const schema = {
6
+ FOO: {
7
+ type: 'string',
8
+ required: true,
9
+ },
10
+ BAR: {
11
+ type: 'number',
12
+ required: true,
13
+ int: true,
14
+ },
15
+ SECRET: {
16
+ type: 'string',
17
+ required: true,
18
+ secret: true,
19
+ },
20
+ OPTIONAL: {
21
+ type: 'string',
22
+ required: false,
23
+ default: 'hello',
24
+ },
25
+ }
26
+
27
+ it('returns success result when all variables are valid', () => {
28
+ const env = {
29
+ FOO: 'test',
30
+ BAR: '42',
31
+ SECRET: 'super-secret',
32
+ }
33
+
34
+ const result = validateAndReportEnv(schema, env)
35
+
36
+ expect(result.success).toBe(true)
37
+
38
+ expect(result.validation.success).toBe(true)
39
+ expect(result.validation.data).toEqual({
40
+ FOO: 'test',
41
+ BAR: 42,
42
+ SECRET: 'super-secret',
43
+ OPTIONAL: 'hello',
44
+ })
45
+
46
+ expect(result.report.success).toBe(true)
47
+ expect(result.report.params).toHaveLength(4)
48
+
49
+ expect(result.output).toContain('Environment variables')
50
+ expect(result.output).toContain('OK')
51
+ })
52
+
53
+ it('returns failure result when required variable is missing', () => {
54
+ const env = {
55
+ BAR: '10',
56
+ SECRET: 'x',
57
+ }
58
+
59
+ const result = validateAndReportEnv(schema, env)
60
+
61
+ expect(result.success).toBe(false)
62
+
63
+ expect(result.validation.success).toBe(false)
64
+ expect(result.validation.summary).toHaveProperty('FOO')
65
+
66
+ const fooParam = result.report.params.find((p) => p.key === 'FOO')
67
+ expect(fooParam.valid).toBe(false)
68
+ expect(fooParam.errors.length).toBeGreaterThan(0)
69
+
70
+ expect(result.output).toContain('ERROR')
71
+ expect(result.output).toContain('FOO')
72
+ })
73
+
74
+ it('masks secret values in output', () => {
75
+ const env = {
76
+ FOO: 'test',
77
+ BAR: '1',
78
+ SECRET: 'dont-print-me',
79
+ }
80
+
81
+ const mask = () => '***'
82
+
83
+ const result = validateAndReportEnv(schema, env, { mask })
84
+
85
+ const secretParam = result.report.params.find((p) => p.key === 'SECRET')
86
+
87
+ expect(secretParam.displayValue).toBe('***')
88
+ expect(result.output).toContain('***')
89
+ expect(result.output).not.toContain('dont-print-me')
90
+ })
91
+
92
+ it('coerces and validates types correctly', () => {
93
+ const env = {
94
+ FOO: 'abc',
95
+ BAR: '5',
96
+ SECRET: 'x',
97
+ }
98
+
99
+ const result = validateAndReportEnv(schema, env)
100
+
101
+ expect(result.success).toBe(true)
102
+ expect(result.validation.data.BAR).toBe(5)
103
+ })
104
+ })
@@ -155,3 +155,127 @@ export function formatEnvReport(report: {
155
155
  errors?: string[]
156
156
  }>
157
157
  }): string
158
+ /**
159
+ * Validates environment variables end-to-end and builds a full report.
160
+ *
161
+ * This function:
162
+ * - validates values using the schema definition
163
+ * - builds a structured report (including masking secrets)
164
+ * - formats a printable output
165
+ *
166
+ * @param {Record<string, Object>} definition
167
+ * Environment schema definition.
168
+ *
169
+ * @param {Record<string, any>} values
170
+ * Raw environment values (e.g. process.env).
171
+ *
172
+ * @param {{
173
+ * mask?: (value: any) => string
174
+ * }} [options]
175
+ *
176
+ * @returns {{
177
+ * success: boolean,
178
+ * validation: {
179
+ * success: boolean,
180
+ * data?: Record<string, any>,
181
+ * summary?: Record<string, string[]>
182
+ * },
183
+ * report: {
184
+ * success: boolean,
185
+ * params: Array<{
186
+ * key: string,
187
+ * value: any,
188
+ * displayValue: string,
189
+ * secret: boolean,
190
+ * valid: boolean,
191
+ * errors?: string[]
192
+ * }>
193
+ * },
194
+ * output: string
195
+ * }}
196
+ */
197
+ export function validateAndReportEnv(
198
+ definition: Record<string, any>,
199
+ values: Record<string, any>,
200
+ options?: {
201
+ mask?: (value: any) => string
202
+ },
203
+ ): {
204
+ success: boolean
205
+ validation: {
206
+ success: boolean
207
+ data?: Record<string, any>
208
+ summary?: Record<string, string[]>
209
+ }
210
+ report: {
211
+ success: boolean
212
+ params: Array<{
213
+ key: string
214
+ value: any
215
+ displayValue: string
216
+ secret: boolean
217
+ valid: boolean
218
+ errors?: string[]
219
+ }>
220
+ }
221
+ output: string
222
+ }
223
+ /**
224
+ * Validates environment variables and prepares
225
+ * a printable table output.
226
+ *
227
+ * No side effects. Does NOT print.
228
+ *
229
+ * @param {Record<string, Object>} definition
230
+ * @param {Record<string, any>} values
231
+ * @param {{
232
+ * mask?: (value: any) => string
233
+ * }} [options]
234
+ *
235
+ * @returns {{
236
+ * success: boolean,
237
+ * table: string,
238
+ * validation: {
239
+ * success: boolean,
240
+ * data?: Record<string, any>,
241
+ * summary?: Record<string, string[]>
242
+ * },
243
+ * report: {
244
+ * success: boolean,
245
+ * params: Array<{
246
+ * key: string,
247
+ * value: any,
248
+ * displayValue: string,
249
+ * secret: boolean,
250
+ * valid: boolean,
251
+ * errors?: string[]
252
+ * }>
253
+ * }
254
+ * }}
255
+ */
256
+ export function prepareEnvValidation(
257
+ definition: Record<string, any>,
258
+ values: Record<string, any>,
259
+ options?: {
260
+ mask?: (value: any) => string
261
+ },
262
+ ): {
263
+ success: boolean
264
+ table: string
265
+ validation: {
266
+ success: boolean
267
+ data?: Record<string, any>
268
+ summary?: Record<string, string[]>
269
+ }
270
+ report: {
271
+ success: boolean
272
+ params: Array<{
273
+ key: string
274
+ value: any
275
+ displayValue: string
276
+ secret: boolean
277
+ valid: boolean
278
+ errors?: string[]
279
+ }>
280
+ }
281
+ }