@carecard/validate 3.23.0 → 3.24.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/readme.md CHANGED
@@ -8,10 +8,14 @@ Non-negotiable root-cause solution rule: Always identify and solve the verified
8
8
  services. It exposes individual value validators, a bulk property sanitizer, and
9
9
  a whitelist validator for request-like payloads.
10
10
 
11
- The package returns booleans from the low-level validators, strips unknown or
12
- invalid values from `validateProperties`, and throws CareCard `BAD_INPUT` errors
13
- from `validateWhitelistProperties` when required or provided whitelist values do
14
- not pass validation.
11
+ The package returns booleans from general low-level validators, returns a
12
+ structured result from the single `validatePassword` policy boundary, strips
13
+ unknown or invalid values from `validateProperties`, and throws CareCard
14
+ `BAD_INPUT` errors from `validateWhitelistProperties` when required or provided
15
+ whitelist values do not pass validation.
16
+
17
+ Use Node.js 24.20.0. The package accepts compatible Node.js releases from
18
+ 24.20.0 up to, but not including, Node.js 25.
15
19
 
16
20
  ## Development Rule
17
21
 
@@ -36,11 +40,19 @@ npm install @carecard/validate
36
40
  ## Importing
37
41
 
38
42
  ```js
39
- const { validate, validateProperties, validateWhitelistProperties, isEmailString, isValidUuidString } = require('@carecard/validate');
43
+ const {
44
+ validate,
45
+ validatePassword,
46
+ validateProperties,
47
+ validateWhitelistProperties,
48
+ isEmailString,
49
+ isValidUuidString,
50
+ } = require('@carecard/validate');
40
51
  ```
41
52
 
42
- The validators are available both as top-level exports and under the deprecated
43
- `validate` namespace.
53
+ General validators are available both as top-level exports and under the
54
+ deprecated `validate` namespace. `validatePassword` is intentionally available
55
+ only as one direct export.
44
56
 
45
57
  ```js
46
58
  isEmailString('jane@example.com'); // true
@@ -49,43 +61,37 @@ validate.isEmailString('jane@example.com'); // true
49
61
 
50
62
  ## Direct Validators
51
63
 
52
- Every direct validator returns `true` or `false`. Failure message helpers return
53
- a string on failure and `null` on success.
54
-
55
- | Function | Accepted value |
56
- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
57
- | `isImageUrl(value)` | Non-empty string up to 2048 chars using letters, numbers, `-`, `_`, `.`, and `/`. Intended for safe image/file paths. |
58
- | `isInteger(value)` | JavaScript integer number. String numbers are rejected. |
59
- | `isValidJsonString(value)` | Non-empty string up to 10000 chars that parses to a non-null JSON object or array. JSON primitives are rejected. |
60
- | `isValidIntegerString(value)` | Digit-only string, 1 to 20 chars. No signs or decimals. |
61
- | `isValidUuidString(value)` | Canonical UUID string in `8-4-4-4-12` format, case-insensitive. |
62
- | `isCharactersString(value)` | 1 to 1000 chars containing letters, numbers, spaces, `_`, or `-`. |
63
- | `isStreetString(value)` | Non-empty street-like string up to 1000 chars using letters, numbers, spaces, `,`, `.`, `/`, `#`, or `-`, and not starting with `,`, `_`, or `-`. |
64
- | `isNameString(value)` | 1 to 1000 char string that starts with a letter and uses letters, numbers, spaces, `_`, `-`, `.`, `,`, `'`, `(`, or `)`. Leading/trailing spaces are trimmed before pattern validation. |
65
- | `isSafeSearchString(value)` | Trimmed string that starts with a letter and then uses letters, numbers, spaces, `_`, `-`, `.`, `,`, `'`, `(`, `)`, or `@`. |
66
- | `isEmailString(value)` | Email-like string up to 320 chars using the package email regex. |
67
- | `isJwtString(value)` | Non-blank JWT-like string up to 8192 chars that starts with `eyJ` and contains only letters, numbers, `-`, `_`, and `.`. |
68
- | `isPasswordString(value)` | 6 to 32 chars from letters, numbers, and `!@#$%^&*_-`, with at least one alphanumeric char and one listed special char. |
69
- | `isSimplePasswordString(value)` | 6 to 32 chars from letters, numbers, and `!@#$%^&*_-`. |
70
- | `isPasswordStringFailureMessage(value)` | `null` when `isPasswordString` passes, otherwise a human-readable failure message. |
71
- | `isSimplePasswordStringFailureMessage(value)` | `null` when `isSimplePasswordString` passes, otherwise a human-readable failure message. |
72
- | `isUsernameString(value)` | 1 to 200 alphanumeric chars. |
73
- | `isPhoneNumber(value)` | North American 10-digit phone number with optional parentheses around the area code and optional space, `-`, or `.` separators. |
74
- | `isUrlSafeString(value)` | Non-blank string up to 2048 chars using letters, numbers, `-`, `_`, and `.`. |
75
- | `isString6To24CharacterLong(value)` | String with length from 6 to 24. |
76
- | `isString6To16CharacterLong(value)` | String with length from 6 to 16. |
77
- | `isProvinceString(value)` | `ON` or `QC`, case-insensitive. |
78
- | `isBoolValue(value)` | Boolean `true`/`false` or strings `"true"`/`"false"`. |
79
- | `isPostalCodeString(value)` | Canadian postal code format, case-insensitive, with optional middle space. |
80
- | `isSafeString(value)` | 1 to 10000 chars using letters, numbers, spaces, `-`, `_`, `.`, `,`, `#`, `*`, `'`, `(`, `)`, `[`, `]`, or `:`. |
81
- | `isInStringArray(array, value)` | `value`, after lowercase/trim validation as a name string, is included in the supplied array. |
82
- | `isCountryCodeString(value)` | Country dialing code in `+1` to `+999` format. |
83
- | `isValidDomainName(value)` | Domain name with at least one dot, valid DNS-like labels, and max total length 253. |
84
- | `isValidTimestampzString(value)` | ISO 8601 timestamp with `Z` or `+/-HH:MM` timezone offset. |
85
- | `isValidTimestampString(value)` | ISO 8601 timestamp without timezone offset. |
86
- | `isValidDateString(value)` | ISO date in `YYYY-MM-DD` format. |
87
- | `isValidUrl(value)` | Absolute `http://` or `https://` URL up to 2048 chars. |
88
- | `isValidArrayOfStrings(value)` | Array where every element passes `isSafeString`. |
64
+ General direct validators return `true` or `false`.
65
+
66
+ | Function | Accepted value |
67
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
68
+ | `isImageUrl(value)` | Non-empty string up to 2048 chars using letters, numbers, `-`, `_`, `.`, and `/`. Intended for safe image/file paths. |
69
+ | `isInteger(value)` | JavaScript integer number. String numbers are rejected. |
70
+ | `isValidJsonString(value)` | Non-empty string up to 10000 chars that parses to a non-null JSON object or array. JSON primitives are rejected. |
71
+ | `isValidIntegerString(value)` | Digit-only string, 1 to 20 chars. No signs or decimals. |
72
+ | `isValidUuidString(value)` | Canonical UUID string in `8-4-4-4-12` format, case-insensitive. |
73
+ | `isCharactersString(value)` | 1 to 1000 chars containing letters, numbers, spaces, `_`, or `-`. |
74
+ | `isStreetString(value)` | Non-empty street-like string up to 1000 chars using letters, numbers, spaces, `,`, `.`, `/`, `#`, or `-`, and not starting with `,`, `_`, or `-`. |
75
+ | `isNameString(value)` | 1 to 1000 char string that starts with a letter and uses letters, numbers, spaces, `_`, `-`, `.`, `,`, `'`, `(`, or `)`. Leading/trailing spaces are trimmed before pattern validation. |
76
+ | `isSafeSearchString(value)` | Trimmed string that starts with a letter and then uses letters, numbers, spaces, `_`, `-`, `.`, `,`, `'`, `(`, `)`, or `@`. |
77
+ | `isEmailString(value)` | Email-like string up to 320 chars using the package email regex. |
78
+ | `isJwtString(value)` | Non-blank JWT-like string up to 8192 chars that starts with `eyJ` and contains only letters, numbers, `-`, `_`, and `.`. |
79
+ | `validatePassword(value)` | A well-formed Unicode password from 15 to 128 code points after NFC normalization that is not an exact case-sensitive blocklist match. Returns a discriminated result with the normalized value or a stable failure reason. All Unicode characters, including spaces and emoji, are permitted without composition rules. |
80
+ | `isUsernameString(value)` | 1 to 200 alphanumeric chars. |
81
+ | `isPhoneNumber(value)` | North American 10-digit phone number with optional parentheses around the area code and optional space, `-`, or `.` separators. |
82
+ | `isUrlSafeString(value)` | Non-blank string up to 2048 chars using letters, numbers, `-`, `_`, and `.`. |
83
+ | `isProvinceString(value)` | `ON` or `QC`, case-insensitive. |
84
+ | `isBoolValue(value)` | Boolean `true`/`false` or strings `"true"`/`"false"`. |
85
+ | `isPostalCodeString(value)` | Canadian postal code format, case-insensitive, with optional middle space. |
86
+ | `isSafeString(value)` | 1 to 10000 chars using letters, numbers, spaces, `-`, `_`, `.`, `,`, `#`, `*`, `'`, `(`, `)`, `[`, `]`, or `:`. |
87
+ | `isInStringArray(array, value)` | `value`, after lowercase/trim validation as a name string, is included in the supplied array. |
88
+ | `isCountryCodeString(value)` | Country dialing code in `+1` to `+999` format. |
89
+ | `isValidDomainName(value)` | Domain name with at least one dot, valid DNS-like labels, and max total length 253. |
90
+ | `isValidTimestampzString(value)` | ISO 8601 timestamp with `Z` or `+/-HH:MM` timezone offset. |
91
+ | `isValidTimestampString(value)` | ISO 8601 timestamp without timezone offset. |
92
+ | `isValidDateString(value)` | ISO date in `YYYY-MM-DD` format. |
93
+ | `isValidUrl(value)` | Absolute `http://` or `https://` URL up to 2048 chars. |
94
+ | `isValidArrayOfStrings(value)` | Array where every element passes `isSafeString`. |
89
95
 
90
96
  ## `validateProperties(obj)`
91
97
 
@@ -96,10 +102,10 @@ argument returns `{}`.
96
102
 
97
103
  ```js
98
104
  const input = {
99
- first_name: 'Jane',
100
- email: 'jane@example.com',
101
- phone_number: '123',
102
- unknown_key: 'ignored',
105
+ first_name: 'Jane',
106
+ email: 'jane@example.com',
107
+ phone_number: '123',
108
+ unknown_key: 'ignored',
103
109
  };
104
110
 
105
111
  validateProperties(input);
@@ -114,30 +120,29 @@ validateProperties(input);
114
120
  Keys are matched exactly. Both snake_case and camelCase variants are listed
115
121
  where the package supports both.
116
122
 
117
- | Validator | Keys |
118
- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
119
- | `isNameString` | `first_name`, `firstName`, `last_name`, `lastName`, `username`, `new_status`, `newStatus`, `description`, `comment`, `status`, `name`, `title`, `brand`, `short_description`, `shortDescription`, `college_name`, `collegeName`, `campus_name`, `campusName`, `role`, `role_id`, `roleId`, `campus`, `institution_name`, `institutionName`, `program_name`, `programName`, `role_name`, `roleName`, `document_name`, `documentName`, `document_required_for_role_name`, `documentRequiredForRoleName`, `reason`, `entity_type`, `entityType`, `action_type`, `actionType`, `city`, `state`, `country`, `type` |
120
- | `isStreetString` | `street` |
121
- | `isCharactersString` | `postal_code`, `postalCode`, `period` |
122
- | `isBoolValue` | `is_primary`, `isPrimary`, `active`, `document_optional`, `documentOptional` |
123
- | `isSafeSearchString` | `search_string`, `searchString` |
124
- | `isString6To16CharacterLong` and `isSimplePasswordString` | `password`, `new_password`, `newPassword` |
125
- | `isString6To16CharacterLong` and `isPasswordString` | `strong_password`, `strongPassword` |
126
- | `isEmailString` | `email` |
127
- | `isPhoneNumber` | `phone_number`, `phoneNumber` |
128
- | `isCountryCodeString` | `country_code`, `countryCode` |
129
- | `isUrlSafeString` | `token`, `email_verification_token`, `emailVerificationToken`, `verification_token`, `verificationToken` |
130
- | `isValidUuidString` | `uuid`, `item_id`, `itemId`, `user_id`, `userId`, `address_id`, `addressId`, `order_id`, `orderId`, `category_id`, `categoryId`, `parent_id`, `parentId`, `college_id`, `collegeId`, `campus_id`, `campusId`, `program_id`, `programId`, `program_term_id`, `programTermId`, `template_id`, `templateId`, `program_template_id`, `programTemplateId`, `user_item_id`, `userItemId`, `user_item_status_id`, `userItemStatusId`, `requirement_item_id`, `requirementItemId`, `program_document_id`, `programDocumentId`, `id`, `institution_id`, `institutionId`, `role_assignment_id`, `roleAssignmentId`, `user_role_id`, `userRoleId`, `phone_number_id`, `phoneNumberId`, `entity_id`, `entityId`, `changed_by`, `changedBy`, `request_id`, `requestId` |
131
- | `isCcIdString` | `cc_id`, `ccId` |
132
- | `isValidIntegerString` | `offset_number`, `offsetNumber`, `number_of_orders`, `numberOfOrders`, `price`, `from`, `number`, `limit`, `offset` |
133
- | `isValidJsonString` on the raw value | `about` |
134
- | `isValidJsonString(JSON.stringify(value))` | `weight`, `dimensions`, `permission`, `scope_data`, `scopeData`, `meta_data`, `metaData`, `metadata` |
135
- | `isTextString` | `document_description`, `documentDescription`, `nick_name`, `nickName`, `requested_by_name`, `requestedByName`, `requested_by_email`, `requestedByEmail`, `requested_by_phone`, `requestedByPhone`, `approved_by_name`, `approvedByName`, `approved_by_email`, `approvedByEmail`, `approved_by_phone`, `approvedByPhone` |
136
- | `isValidArrayOfStrings` | `aliases` |
137
- | `isImageUrl` or `isValidUrl` | `image_url`, `imageUrl`, `website`, `file_url`, `fileUrl` |
138
- | `isValidDomainName` | `domain_name`, `domainName`, `domain`, `email_domain`, `emailDomain`, `email_domain_name`, `emailDomainName` |
139
- | `isValidTimestampzString` or `isValidTimestampString` | `expires_at`, `expiresAt`, `start_time`, `startTime`, `end_time`, `endTime` |
140
- | `isValidDateString` | `effective_start_date`, `effectiveStartDate`, `effective_end_date`, `effectiveEndDate`, `valid_until_date`, `validUntilDate`, `renew_date`, `renewDate` |
123
+ | Validator | Keys |
124
+ | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
125
+ | `isNameString` | `first_name`, `firstName`, `last_name`, `lastName`, `username`, `new_status`, `newStatus`, `description`, `comment`, `status`, `name`, `title`, `brand`, `short_description`, `shortDescription`, `college_name`, `collegeName`, `campus_name`, `campusName`, `role`, `role_id`, `roleId`, `campus`, `institution_name`, `institutionName`, `program_name`, `programName`, `role_name`, `roleName`, `document_name`, `documentName`, `document_required_for_role_name`, `documentRequiredForRoleName`, `reason`, `entity_type`, `entityType`, `action_type`, `actionType`, `city`, `state`, `country`, `type` |
126
+ | `isStreetString` | `street` |
127
+ | `isCharactersString` | `postal_code`, `postalCode`, `period` |
128
+ | `isBoolValue` | `is_primary`, `isPrimary`, `active`, `document_optional`, `documentOptional` |
129
+ | `isSafeSearchString` | `search_string`, `searchString` |
130
+ | `validatePassword` | `password`, `new_password`, `newPassword` |
131
+ | `isEmailString` | `email` |
132
+ | `isPhoneNumber` | `phone_number`, `phoneNumber` |
133
+ | `isCountryCodeString` | `country_code`, `countryCode` |
134
+ | `isUrlSafeString` | `token`, `email_verification_token`, `emailVerificationToken`, `verification_token`, `verificationToken` |
135
+ | `isValidUuidString` | `uuid`, `item_id`, `itemId`, `user_id`, `userId`, `address_id`, `addressId`, `order_id`, `orderId`, `category_id`, `categoryId`, `parent_id`, `parentId`, `college_id`, `collegeId`, `campus_id`, `campusId`, `program_id`, `programId`, `program_term_id`, `programTermId`, `template_id`, `templateId`, `program_template_id`, `programTemplateId`, `user_item_id`, `userItemId`, `user_item_status_id`, `userItemStatusId`, `requirement_item_id`, `requirementItemId`, `program_document_id`, `programDocumentId`, `id`, `institution_id`, `institutionId`, `role_assignment_id`, `roleAssignmentId`, `user_role_id`, `userRoleId`, `phone_number_id`, `phoneNumberId`, `entity_id`, `entityId`, `changed_by`, `changedBy`, `request_id`, `requestId` |
136
+ | `isCcIdString` | `cc_id`, `ccId` |
137
+ | `isValidIntegerString` | `offset_number`, `offsetNumber`, `number_of_orders`, `numberOfOrders`, `price`, `from`, `number`, `limit`, `offset` |
138
+ | `isValidJsonString` on the raw value | `about` |
139
+ | `isValidJsonString(JSON.stringify(value))` | `weight`, `dimensions`, `permission`, `scope_data`, `scopeData`, `meta_data`, `metaData`, `metadata` |
140
+ | `isTextString` | `document_description`, `documentDescription`, `nick_name`, `nickName`, `requested_by_name`, `requestedByName`, `requested_by_email`, `requestedByEmail`, `requested_by_phone`, `requestedByPhone`, `approved_by_name`, `approvedByName`, `approved_by_email`, `approvedByEmail`, `approved_by_phone`, `approvedByPhone` |
141
+ | `isValidArrayOfStrings` | `aliases` |
142
+ | `isImageUrl` or `isValidUrl` | `image_url`, `imageUrl`, `website`, `file_url`, `fileUrl` |
143
+ | `isValidDomainName` | `domain_name`, `domainName`, `domain`, `email_domain`, `emailDomain`, `email_domain_name`, `emailDomainName` |
144
+ | `isValidTimestampzString` or `isValidTimestampString` | `expires_at`, `expiresAt`, `start_time`, `startTime`, `end_time`, `endTime` |
145
+ | `isValidDateString` | `effective_start_date`, `effectiveStartDate`, `effective_end_date`, `effectiveEndDate`, `valid_until_date`, `validUntilDate`, `renew_date`, `renewDate` |
141
146
 
142
147
  ## `validateWhitelistProperties(inputObject, requiredProperties, options)`
143
148
 
@@ -147,14 +152,14 @@ a `Promise<ValidatePropertiesResult>` with the sanitized output.
147
152
 
148
153
  ```js
149
154
  const body = {
150
- first_name: 'Jane',
151
- email: 'jane@example.com',
152
- role: 'Admin',
153
- extra: '<script>',
155
+ first_name: 'Jane',
156
+ email: 'jane@example.com',
157
+ role: 'Admin',
158
+ extra: '<script>',
154
159
  };
155
160
 
156
161
  const out = await validateWhitelistProperties(body, ['first_name', 'email'], {
157
- optionalProperties: ['role'],
162
+ optionalProperties: ['role'],
158
163
  });
159
164
 
160
165
  // {
@@ -182,10 +187,10 @@ The default output preserves the nested shape described by whitelisted dot paths
182
187
 
183
188
  ```js
184
189
  const input = {
185
- user: {
186
- first_name: 'Jane',
187
- contact: { email: 'jane@example.com' },
188
- },
190
+ user: {
191
+ first_name: 'Jane',
192
+ contact: { email: 'jane@example.com' },
193
+ },
189
194
  };
190
195
 
191
196
  await validateWhitelistProperties(input, ['user.first_name', 'user.contact.email']);
@@ -209,16 +214,22 @@ await validateWhitelistProperties(input, ['user.first_name', 'user.contact.email
209
214
  Example with only the default options:
210
215
 
211
216
  ```js
212
- await validateWhitelistProperties({ first_name: 'Jane', email: 'jane@example.com', ignored: 'x' }, ['first_name']);
217
+ await validateWhitelistProperties({ first_name: 'Jane', email: 'jane@example.com', ignored: 'x' }, [
218
+ 'first_name',
219
+ ]);
213
220
  // { first_name: 'Jane' }
214
221
  ```
215
222
 
216
223
  Example with optional properties:
217
224
 
218
225
  ```js
219
- await validateWhitelistProperties({ first_name: 'Jane', phone_number: '4165551234' }, ['first_name'], {
226
+ await validateWhitelistProperties(
227
+ { first_name: 'Jane', phone_number: '4165551234' },
228
+ ['first_name'],
229
+ {
220
230
  optionalProperties: ['phone_number'],
221
- });
231
+ },
232
+ );
222
233
  // { first_name: 'Jane', phone_number: '4165551234' }
223
234
  ```
224
235
 
@@ -241,7 +252,7 @@ Optional paths are ignored when absent, but invalid when present.
241
252
 
242
253
  ```js
243
254
  await validateWhitelistProperties({ first_name: 'Jane', email: 'bad' }, ['first_name'], {
244
- optionalProperties: ['email'],
255
+ optionalProperties: ['email'],
245
256
  });
246
257
  // userMessage: 'Invalid property value: email'
247
258
  ```
@@ -253,13 +264,13 @@ used.
253
264
 
254
265
  ```js
255
266
  const out = await validateWhitelistProperties(
256
- {
257
- user: {
258
- first_name: 'Jane',
259
- contact: { email: 'jane@example.com', ignored: 'x' },
260
- },
267
+ {
268
+ user: {
269
+ first_name: 'Jane',
270
+ contact: { email: 'jane@example.com', ignored: 'x' },
261
271
  },
262
- ['user.first_name', 'user.contact.email'],
272
+ },
273
+ ['user.first_name', 'user.contact.email'],
263
274
  );
264
275
 
265
276
  // {
@@ -290,11 +301,15 @@ This array behavior is intended for repeated scalar fields such as `email` or
290
301
  ### Case Conversion And Flattening
291
302
 
292
303
  ```js
293
- const out = await validateWhitelistProperties({ userInfo: { firstName: 'Jane', phoneNumber: '4165551234' } }, ['userInfo.firstName'], {
304
+ const out = await validateWhitelistProperties(
305
+ { userInfo: { firstName: 'Jane', phoneNumber: '4165551234' } },
306
+ ['userInfo.firstName'],
307
+ {
294
308
  optionalProperties: ['userInfo.phoneNumber'],
295
309
  convertToSnakeCase: true,
296
310
  flattenOutput: true,
297
- });
311
+ },
312
+ );
298
313
 
299
314
  // {
300
315
  // 'user_info.first_name': 'Jane',
@@ -316,7 +331,7 @@ With `flattenOutput: true`, keys are full dot paths by default:
316
331
  ```js
317
332
  const input = { a: { b: { c: { d: { email: 'jane@example.com', name: 'Jane' } } } } };
318
333
  await validateWhitelistProperties(input, ['a.b.c.d.email', 'a.b.c.d.name'], {
319
- flattenOutput: true,
334
+ flattenOutput: true,
320
335
  });
321
336
  // { 'a.b.c.d.email': 'jane@example.com', 'a.b.c.d.name': 'Jane' }
322
337
  ```
@@ -326,8 +341,8 @@ Use `flattenKeyStyle: 'leaf'` to return top-level leaf keys instead:
326
341
  ```js
327
342
  const input = { a: { b: { c: { d: { email: 'jane@example.com', name: 'Jane' } } } } };
328
343
  await validateWhitelistProperties(input, ['a.b.c.d.email', 'a.b.c.d.name'], {
329
- flattenOutput: true,
330
- flattenKeyStyle: 'leaf',
344
+ flattenOutput: true,
345
+ flattenKeyStyle: 'leaf',
331
346
  });
332
347
  // { email: 'jane@example.com', name: 'Jane' }
333
348
  ```
@@ -339,13 +354,13 @@ encountered:
339
354
 
340
355
  ```js
341
356
  const input = {
342
- name: 'Top Level Name',
343
- user: { name: 'Nested Name', email: 'jane@example.com' },
357
+ name: 'Top Level Name',
358
+ user: { name: 'Nested Name', email: 'jane@example.com' },
344
359
  };
345
360
 
346
361
  await validateWhitelistProperties(input, ['name', 'user.name', 'user.email'], {
347
- flattenOutput: true,
348
- flattenKeyStyle: 'leaf',
362
+ flattenOutput: true,
363
+ flattenKeyStyle: 'leaf',
349
364
  });
350
365
  // { name: 'Top Level Name', email: 'jane@example.com' }
351
366
  ```
@@ -355,10 +370,16 @@ await validateWhitelistProperties(input, ['name', 'user.name', 'user.email'], {
355
370
  The package ships `index.d.ts` and declares types for the CommonJS exports.
356
371
 
357
372
  ```ts
358
- import { validateWhitelistProperties, isEmailString, ValidatePropertiesResult } from '@carecard/validate';
373
+ import {
374
+ validateWhitelistProperties,
375
+ isEmailString,
376
+ ValidatePropertiesResult,
377
+ } from '@carecard/validate';
359
378
 
360
379
  const valid: boolean = isEmailString('jane@example.com');
361
- const output: ValidatePropertiesResult = await validateWhitelistProperties({ first_name: 'Jane' }, ['first_name']);
380
+ const output: ValidatePropertiesResult = await validateWhitelistProperties({ first_name: 'Jane' }, [
381
+ 'first_name',
382
+ ]);
362
383
  const maxDepth: 5 = validateWhitelistProperties.MAX_NESTING_DEPTH;
363
384
  ```
364
385
 
@@ -385,7 +406,7 @@ npm run lint
385
406
  npm run format:check
386
407
  ```
387
408
 
388
- CI runs on Node.js 25 and executes `npm run test:All`. Publishing to npm happens
409
+ CI runs on Node.js 24.20.0 and executes `npm run test:All`. Publishing to npm happens
389
410
  from `main` through the `Publish to npm` GitHub workflow.
390
411
 
391
412
  ## Auth Boundary