@carecard/validate 3.1.23 → 3.1.25
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/.agents/config.toml +2 -0
- package/.agents/skills/carecard-workspace-standards/SKILL.md +401 -0
- package/.agents/skills/carecard-workspace-standards/agents/openai.yaml +4 -0
- package/.agents/skills/github-pr-create-update/SKILL.md +188 -0
- package/.agents/skills/github-pr-create-update/agents/openai.yaml +5 -0
- package/.agents/skills/github-pr-merge-cleanup/SKILL.md +175 -0
- package/.agents/skills/github-pr-merge-cleanup/agents/openai.yaml +5 -0
- package/.agents/skills/logged-in-user-profile-page/SKILL.md +33 -0
- package/.agents/skills/logged-in-user-profile-page/agents/openai.yaml +4 -0
- package/.agents/skills/pkg-validate-validation-library/SKILL.md +200 -0
- package/.agents/skills/pkg-validate-validation-library/agents/openai.yaml +4 -0
- package/.agents/skills/software-design-patterns-and-clean-code/SKILL.md +73 -0
- package/.codex/AGENTS.md +1 -0
- package/.codex/config.toml +2 -0
- package/.github/workflows/ci.yml +2 -2
- package/index.d.ts +21 -0
- package/index.js +2 -0
- package/lib/validate.js +6 -0
- package/lib/validateNewUserRoleRequest.js +79 -0
- package/lib/validateProperties.js +14 -0
- package/package.json +19 -7
- package/readme.md +14 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
error: { throwBadInputError },
|
|
5
|
+
} = require('@carecard/common-util');
|
|
6
|
+
const { isUserRoleRequestRoleString } = require('./validate');
|
|
7
|
+
|
|
8
|
+
const DEFAULT_USER_ROLE_REQUEST_ROLE = 'student';
|
|
9
|
+
const REQUIRE_SCOPE_WHEN_ROLE_OR_SCOPE_PRESENT = 'whenRoleOrScopePresent';
|
|
10
|
+
|
|
11
|
+
function validateNewUserRoleRequestObject(roleRequest = {}, options = {}) {
|
|
12
|
+
const normalized = normalizeNewUserRoleRequestObject(roleRequest);
|
|
13
|
+
const defaultRole = Object.prototype.hasOwnProperty.call(options, 'defaultRole') ? options.defaultRole : DEFAULT_USER_ROLE_REQUEST_ROLE;
|
|
14
|
+
const requireScope = Object.prototype.hasOwnProperty.call(options, 'requireScope') ? options.requireScope : true;
|
|
15
|
+
|
|
16
|
+
if (normalized.role_name === undefined && defaultRole !== undefined) {
|
|
17
|
+
normalized.role_name = defaultRole;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (normalized.role_name !== undefined && !isUserRoleRequestRoleString(normalized.role_name)) {
|
|
21
|
+
throwBadInputError({
|
|
22
|
+
userMessage: 'Invalid property: role.role',
|
|
23
|
+
details: { role: 'Role requests are limited to student, intern, or volunteer' },
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (shouldRequireScope(normalized, requireScope)) {
|
|
28
|
+
requireNewUserRoleRequestScope(normalized);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return normalized;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function normalizeNewUserRoleRequestObject(roleRequest) {
|
|
35
|
+
const normalized = { ...roleRequest };
|
|
36
|
+
|
|
37
|
+
assignAlias(normalized, 'role_name', 'roleName');
|
|
38
|
+
assignAlias(normalized, 'role_name', 'role');
|
|
39
|
+
assignAlias(normalized, 'institution_id', 'institutionId');
|
|
40
|
+
assignAlias(normalized, 'campus_id', 'campusId');
|
|
41
|
+
assignAlias(normalized, 'program_id', 'programId');
|
|
42
|
+
|
|
43
|
+
delete normalized.roleName;
|
|
44
|
+
delete normalized.role;
|
|
45
|
+
delete normalized.institutionId;
|
|
46
|
+
delete normalized.campusId;
|
|
47
|
+
delete normalized.programId;
|
|
48
|
+
|
|
49
|
+
return normalized;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function assignAlias(target, canonicalKey, aliasKey) {
|
|
53
|
+
if (target[canonicalKey] === undefined && target[aliasKey] !== undefined) {
|
|
54
|
+
target[canonicalKey] = target[aliasKey];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function shouldRequireScope(roleRequest, requireScope) {
|
|
59
|
+
if (requireScope === true) return true;
|
|
60
|
+
if (requireScope !== REQUIRE_SCOPE_WHEN_ROLE_OR_SCOPE_PRESENT) return false;
|
|
61
|
+
|
|
62
|
+
return roleRequest.role_name !== undefined || roleRequest.institution_id !== undefined || roleRequest.campus_id !== undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function requireNewUserRoleRequestScope(roleRequest) {
|
|
66
|
+
if (!roleRequest.institution_id) {
|
|
67
|
+
throwBadInputError({ userMessage: 'Missing property: role.institutionId' });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!roleRequest.campus_id) {
|
|
71
|
+
throwBadInputError({ userMessage: 'Missing property: role.campusId' });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
DEFAULT_USER_ROLE_REQUEST_ROLE,
|
|
77
|
+
REQUIRE_SCOPE_WHEN_ROLE_OR_SCOPE_PRESENT,
|
|
78
|
+
validateNewUserRoleRequestObject,
|
|
79
|
+
};
|
|
@@ -22,6 +22,8 @@ const {
|
|
|
22
22
|
isStreetString,
|
|
23
23
|
isTextString,
|
|
24
24
|
isUserRoleRequestStatusString,
|
|
25
|
+
isUserRoleRequestRoleString,
|
|
26
|
+
isCountryCodeString,
|
|
25
27
|
} = require('./validate');
|
|
26
28
|
|
|
27
29
|
function validateProperties(obj = {}) {
|
|
@@ -123,6 +125,12 @@ function validateProperties(obj = {}) {
|
|
|
123
125
|
returnObj[key] = value;
|
|
124
126
|
}
|
|
125
127
|
break;
|
|
128
|
+
case 'country_code':
|
|
129
|
+
case 'countryCode':
|
|
130
|
+
if (isCountryCodeString(value)) {
|
|
131
|
+
returnObj[key] = value;
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
126
134
|
case 'token':
|
|
127
135
|
case 'email_confirm_token':
|
|
128
136
|
case 'emailConfirmToken':
|
|
@@ -196,6 +204,12 @@ function validateProperties(obj = {}) {
|
|
|
196
204
|
returnObj[key] = value;
|
|
197
205
|
}
|
|
198
206
|
break;
|
|
207
|
+
case 'user_role_request_role':
|
|
208
|
+
case 'userRoleRequestRole':
|
|
209
|
+
if (isUserRoleRequestRoleString(value)) {
|
|
210
|
+
returnObj[key] = value;
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
199
213
|
case 'period':
|
|
200
214
|
if (isCharactersString(value)) {
|
|
201
215
|
returnObj[key] = value;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carecard/validate",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.25",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/CareCard-ca/pkg-validate.git"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"test": "mocha --recursive",
|
|
13
13
|
"test:types": "tsc --noEmit && echo \"\\n ✔ Type tests passed: tsc --noEmit reported 0 errors across index.d.ts and test/**/*.ts\\n\"",
|
|
14
14
|
"test:coverage": "tsc --noEmit && export NODE_ENV=test && nyc mocha --recursive",
|
|
15
|
-
"test:All": "npm run test && npm run test:types",
|
|
15
|
+
"test:All": "npm run test:coverage && npm run test:types",
|
|
16
16
|
"format": "prettier --write .",
|
|
17
17
|
"format:check": "prettier --check .",
|
|
18
18
|
"prepare": "husky",
|
|
@@ -27,17 +27,29 @@
|
|
|
27
27
|
"license": "ISC",
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/mocha": "10.0.10",
|
|
30
|
-
"@types/node": "25.
|
|
30
|
+
"@types/node": "25.9.1",
|
|
31
31
|
"eslint": "9.39.4",
|
|
32
32
|
"husky": "9.1.7",
|
|
33
|
-
"lint-staged": "17.0.
|
|
34
|
-
"mocha": "11.7.
|
|
33
|
+
"lint-staged": "17.0.5",
|
|
34
|
+
"mocha": "11.7.6",
|
|
35
35
|
"nyc": "18.0.0",
|
|
36
36
|
"prettier": "3.8.3",
|
|
37
37
|
"ts-node": "10.9.2",
|
|
38
|
-
"typescript": "
|
|
38
|
+
"typescript": "6.0.3"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@carecard/common-util": "
|
|
41
|
+
"@carecard/common-util": "3.1.15"
|
|
42
|
+
},
|
|
43
|
+
"nyc": {
|
|
44
|
+
"all": true,
|
|
45
|
+
"include": [
|
|
46
|
+
"index.js",
|
|
47
|
+
"lib/**/*.js"
|
|
48
|
+
],
|
|
49
|
+
"check-coverage": true,
|
|
50
|
+
"branches": 100,
|
|
51
|
+
"functions": 100,
|
|
52
|
+
"lines": 100,
|
|
53
|
+
"statements": 100
|
|
42
54
|
}
|
|
43
55
|
}
|
package/readme.md
CHANGED
|
@@ -106,6 +106,7 @@ where the package supports both.
|
|
|
106
106
|
| `isString6To16CharacterLong` and `isPasswordString` | `strong_password`, `strongPassword` |
|
|
107
107
|
| `isEmailString` | `email` |
|
|
108
108
|
| `isPhoneNumber` | `phone_number`, `phoneNumber` |
|
|
109
|
+
| `isCountryCodeString` | `country_code`, `countryCode` |
|
|
109
110
|
| `isUrlSafeString` | `token`, `email_confirm_token`, `emailConfirmToken`, `verification_token`, `verificationToken` |
|
|
110
111
|
| `isValidUuidString` | `uuid`, `item_id`, `itemId`, `user_id`, `userId`, `address_id`, `addressId`, `image_id`, `imageId`, `order_id`, `orderId`, `category_id`, `categoryId`, `parent_id`, `parentId`, `college_id`, `collegeId`, `campus_id`, `campusId`, `program_id`, `programId`, `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` |
|
|
111
112
|
| `isValidIntegerString` | `offset_number`, `offsetNumber`, `number_of_orders`, `numberOfOrders`, `price`, `from`, `number`, `limit`, `offset` |
|
|
@@ -363,3 +364,16 @@ npm run format:check
|
|
|
363
364
|
|
|
364
365
|
CI runs on Node.js 25 and executes `npm run test:All`. Publishing to npm happens
|
|
365
366
|
from `main` through the `Publish to npm` GitHub workflow.
|
|
367
|
+
|
|
368
|
+
## Auth Boundary
|
|
369
|
+
|
|
370
|
+
Validation protects request shape, not authorization. `ms-auth` owns its
|
|
371
|
+
auth-table RLS contract: normal users are self-row only, JWT `roles: ["ad"]`
|
|
372
|
+
is the auth super-admin signal, and public auth flows use narrow system
|
|
373
|
+
contexts. Do not use validators as a replacement for service RLS or database
|
|
374
|
+
context checks.
|
|
375
|
+
|
|
376
|
+
Docs that mention `ms-auth` controller internals should use concise action
|
|
377
|
+
names such as `loginUser`, `registerUser`, `getUserDetail`, and `renewJwt`.
|
|
378
|
+
Access level is conveyed by route middleware and endpoint placement, not by
|
|
379
|
+
`public`/`protected`/`admin`/`Handler` suffixes.
|