@carecard/validate 3.1.21 → 3.1.23

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,179 @@
1
+ # Codex Instructions For pkg-validate
2
+
3
+ These instructions apply to the `pkg-validate` repository. This file is self-contained:
4
+ it includes the workspace-level instructions that were previously read from
5
+ `/Users/pankajpriscilla/SO_CareCardCa/.codex/AGENTS.md`, followed by
6
+ repository-specific guidance. Removing the workspace-level `.codex/AGENTS.md`
7
+ must not change the rules for this repository.
8
+
9
+ ## Embedded Workspace Instructions
10
+
11
+ These instructions apply to the whole workspace. The workspace is a collection of independent repositories, not one monorepo. Treat each `api-*`, `pkg-*`, and `app-dashboard` directory as its own project with its own package scripts, Git status, and test commands.
12
+
13
+ ### Non-Negotiable Instructions
14
+
15
+ - **Never use TypeScript type `any`.** Always use specific domain types, generics, `unknown` with proper narrowing, or existing project types.
16
+ - **Always follow the owner's coding style.** Preserve the existing style in the file and repository you are editing.
17
+ - **Always follow the owner's naming conventions.** Use meaningful function, variable, file, test, and type names that match the surrounding code.
18
+ - **Always follow the existing project structure.** Put code, tests, docs, services, validation, transforms, components, and helpers where the current repository already expects them.
19
+ - **Always use Test-Driven Development.** Write or update focused tests first, verify they fail for the missing behavior when practical, then implement the code.
20
+ - **Never suppress errors, TypeScript errors, linter warnings, or failing tests.** Do not add `eslint-disable`, `@ts-ignore`, broad catches, empty catches, or other suppression unless the user explicitly requests it. Handle the issue properly.
21
+ - **Do not add new dependencies unless they are clearly necessary.** If a dependency might be needed, stop and ask for confirmation first, with a clear reason, tradeoff, and why existing code cannot reasonably solve it.
22
+ - **Before finalizing any response for a repository, run every script in that repository's `.husky` directory.** Do not bypass hooks. If a `.husky` script fails, fix the underlying issue and rerun it. If it cannot run because of environment constraints, report the exact script and reason.
23
+
24
+ ### Core Coding Principles
25
+
26
+ - Prefer minimal dependencies. Do not add libraries or frameworks unless the existing stack cannot reasonably solve the problem.
27
+ - Prefer implementing core logic directly with readable code over adding abstractions or packages.
28
+ - Explain architectural tradeoffs before major changes, especially changes that affect shared packages, API contracts, security, persistence, authentication, or frontend/backend boundaries.
29
+ - Favor readable, maintainable code over short clever code.
30
+ - Preserve the existing project style, file structure, naming style, module system, and test framework.
31
+ - Use Test-Driven Development: write or update focused tests first, then implement the code.
32
+ - Use meaningful function and variable names. Names should expose intent and domain behavior.
33
+ - Use specific types everywhere. Do not use `any`.
34
+ - Keep changes scoped and easy to review. Avoid unrelated formatting churn or opportunistic refactors.
35
+ - Use postgres functions and stored procedures instead of raw SQL.
36
+ - Use postgres and database search and other functionalities instead of doing it in controllers.
37
+ - Use different type postgres searches, like fuzzy search, trigram search, full-text search, and vector search.
38
+ - When possible, push the complexity of data saving, edit and access to the database.
39
+
40
+ ### Repo Workflow
41
+
42
+ - Work from the specific project directory you are changing, such as `api-auth`, `api-contact-us`, `api-institutions`, `pkg-common-util`, or `app-dashboard`.
43
+ - Check local status inside the affected project before editing. These directories are independent Git repositories.
44
+ - Do not revert or overwrite changes you did not make.
45
+ - Before finishing a code change, run the relevant tests and lint/format checks for the affected project.
46
+ - Before finalizing any response after code changes, run all validation commands required by the affected repository. This includes relevant package scripts, all commands in `.husky` hooks, and all scripts or documented validation commands in `.junie`.
47
+ - When a project has a `.junie` directory, read the applicable `.junie` guidance for that repository before editing. Before the final response, run every executable script in `.junie` and every validation/test command explicitly documented there. Fix any issues those commands report before finalizing.
48
+ - When a project has files in `.husky`, run every direct script in `.husky` before finishing. Fix any issue they report before finalizing. Never skip, bypass, or silence these scripts.
49
+ - If a required `.junie` or `.husky` command cannot be run because of a missing dependency, unavailable service, credentials, or environment limitation, clearly report the exact command, the failure reason, and the remaining risk in the final response.
50
+ - Avoid editing generated or heavy-output directories such as `node_modules`, `dist`, `coverage`, `.next`, `logs`, and generated stores unless the task explicitly requires it.
51
+
52
+ ### Backend Microservices
53
+
54
+ The `api-*` directories are independent Express/Postgres backend services. Most JavaScript services use CommonJS, Mocha, Supertest, Docker Compose database tests, `@carecard/*` packages, and `sub-apps` controller/router/model patterns. TypeScript services such as `api-contact-us` and `api-template-ts` use Jest or TypeScript tooling and should keep their existing TS style.
55
+
56
+ - Keep service-specific controllers thin. Controllers should read as a clear workflow: parse input, authorize, validate, call domain/model logic, build response, and pass errors to `next`.
57
+ - Extract multiline chunks into descriptively named functions in the appropriate `controllerLib`, `commonLib`, `sub-apps/lib`, model helper, or shared `pkg-*` package.
58
+ - Avoid defining reusable workflow, validation, mapping, response, authorization, parsing, or domain helpers in the same controller/app file where they are immediately used.
59
+ - Prefer straightforward sequencing of named helper calls over deeply nested conditionals.
60
+ - Preserve current behavior unless fixing a clear bug, security issue, or documented contract problem.
61
+ - Keep application setup files such as `app.js`, `app.ts`, `bin/www`, and routers focused on composition and wiring.
62
+ - Use existing Express middleware patterns: `requestContext`, CORS configuration, Helmet, cookie parsing, body-size limits, rate limits where already present, routers, 404 handling, logging middleware, and centralized error handlers.
63
+ - Use structured, actionable logging for important application events, external calls, state transitions, failures, and security-relevant actions.
64
+ - Do not log secrets, tokens, passwords, credentials, personal identifiers, full request payloads, or stack traces in user-facing responses.
65
+ - Keep logs useful for production monitoring. Avoid noisy logs that fire on every trivial branch unless they are request/access logs already established by the service.
66
+
67
+ ### Shared Packages And API Contracts
68
+
69
+ The `pkg-*` directories are reusable CareCard packages. Shared API response, error, authentication, JWT, and validation behavior belongs there when it is common across services.
70
+
71
+ - Prefer `@carecard/common-util`, `@carecard/auth-util`, `@carecard/jwt-read`, and `@carecard/validate` over duplicated local implementations.
72
+ - For API responses and errors, use the standardized `@carecard/common-util` behavior where possible: `requestContext`, `sendResponse`, `createError`, `notFound404`, `appErrorHandler`, error throw helpers, case converters, and `ApiErrorType`.
73
+ - Do not create or maintain duplicated common response/error helpers inside each `api-*` service. If a reusable capability is missing, add it to the correct `pkg-*` package and update callers.
74
+ - Keep service-local response code limited to service-specific mapping or wiring.
75
+ - Preserve the standard response shape expected by the dashboard: `success`, `status`, `statusCode`, `code`, `message`, `data`, `error`, `details`, and `meta`.
76
+ - Include request/correlation context where available through `requestId`, `traceId`, and `meta`.
77
+ - Error responses must be safe for users and useful for debugging without exposing secrets, tokens, credentials, stack traces, or sensitive personal data.
78
+ - Map validation, authentication, authorization, not-found, conflict, bad input, file, and unexpected failures to distinct machine-readable codes.
79
+ - Prefer current direct exports from shared packages over deprecated nested exports. For example, prefer direct `@carecard/jwt-read` function names and direct `@carecard/auth-util` helpers.
80
+
81
+ ### Validation Rules
82
+
83
+ - Keep request-boundary validation close to the API/controller layer.
84
+ - Use `validateWhitelistProperties()` once per validation boundary unless there is a specific documented reason to validate defensively again.
85
+ - Avoid hidden duplicate validation across controller and library layers for the same logical payload.
86
+ - Keep domain/library functions focused on domain behavior and assume validated inputs when called from validated controller paths.
87
+ - If a public/shared library function still needs defensive validation, document why and avoid repeating the exact same validation already done by the caller.
88
+ - Preserve validation behavior for invalid, missing, extra, and valid fields.
89
+ - Pay attention to nested fields, dot-notation paths, camelCase/snake_case conversion, and frontend response transforms.
90
+
91
+ ### Tests
92
+
93
+ - Write or update tests before implementation whenever changing behavior.
94
+ - Testing is mandatory before finalizing code changes. Do not stop after implementation if tests, `.junie`, or `.husky` checks remain unrun.
95
+ - Keep tests readable and domain-specific. Prefer explicit helper names over generic test utilities that hide important behavior.
96
+ - Use existing test frameworks and layouts:
97
+ - JavaScript `api-*`: usually Mocha, Supertest, `test/index.test.js`, and Docker-backed Postgres scripts.
98
+ - TypeScript `api-*`: usually Jest and `tests/index.test.ts`.
99
+ - `pkg-*`: Mocha plus TypeScript type tests where present.
100
+ - `app-dashboard`: Vitest, React Testing Library, mock API tests, and Selenium for end-to-end flows.
101
+ - For database tests, use existing seed, migration, rollback, and cleanup patterns. Keep tests isolated and make cleanup reliable even after failures.
102
+ - Add tests for API success responses, validation errors, auth/authz errors, JWT errors, not-found/conflict cases, and unexpected error handling when those paths change.
103
+ - For frontend changes, test validation, transforms, query/mutation wrappers, components, and user-visible flows at the narrowest practical level first.
104
+ - If any test or repository check fails, fix the issue and rerun the failing command. Only finalize with failing checks when the failure is unrelated to the change or blocked by environment constraints, and document that explicitly.
105
+
106
+ ### Dashboard Frontend
107
+
108
+ `app-dashboard` is a Next.js App Router TypeScript app using MUI, React Query, `next-intl`, and shared CareCard utilities. It consumes `api-auth`, `api-institutions`, `api-contact-us`, and `api-user-profiles` through service modules.
109
+
110
+ - Keep backend URL definitions centralized in `src/services/api.routes.ts`.
111
+ - Keep fetch behavior centralized in `src/services/common/api`, especially `appFetch`, `api.client`, and `parseApiResponse`.
112
+ - Services should return typed app/domain objects or typed form states, not raw fetch responses.
113
+ - Keep validation in `*.validation.ts`, API calls in `*.queries.ts` or mutation helpers, mapping in `*.transform.ts`, and orchestration in `*.service.ts`.
114
+ - Preserve the standardized `ApiResponse` parsing behavior for both current backend responses and legacy/non-standard responses.
115
+ - Do not expose JWTs, session contents, or sensitive backend details in client components or logs.
116
+ - Respect `basePath: '/secure'`, server actions, middleware session renewal, mock API mode, and existing i18n message patterns.
117
+ - Use existing MUI and app component patterns. Do not introduce a new UI framework.
118
+
119
+ ### Dependency And Version Guidance
120
+
121
+ - Keep CareCard package usage consistent with the service being changed.
122
+ - When standardizing response/error behavior, prefer `@carecard/common-util` `3.1.15` because it contains response and error functions aligned with `api-auth`.
123
+ - If package version changes are required, update lockfiles and verify affected services.
124
+ - Avoid broad dependency upgrades as part of feature or refactor work unless the task is specifically about dependencies.
125
+
126
+ ### Security Requirements
127
+
128
+ - Treat authentication, authorization, JWT, password, email confirmation, recovery, file upload, CORS, rate limits, and error response behavior as security-sensitive.
129
+ - Never log or return secrets, tokens, passwords, credentials, private keys, full JWT payloads, or sensitive personal data.
130
+ - Use safe error messages for users and structured details only when they do not reveal sensitive implementation or data.
131
+ - Keep body-size limits, Helmet, CORS allow-lists, and rate-limit behavior intact unless a task explicitly changes them.
132
+ - Document remaining security concerns that require product, infrastructure, or deployment decisions.
133
+
134
+ ## Repository-Specific Instructions
135
+
136
+ ### Non-Negotiable Instructions
137
+
138
+ - Never use TypeScript type `any`. Use specific value, record, validator, option, result, generic, or `unknown` types with narrowing.
139
+ - Always follow this repository's coding style, naming conventions, and CommonJS project structure.
140
+ - Always use Test-Driven Development: add or update the relevant Mocha or type tests before changing behavior.
141
+ - Never suppress errors, linter warnings, TypeScript errors, or failing tests. Handle the underlying issue.
142
+ - Do not add new dependencies unless they are absolutely needed. Ask for confirmation first with the reason and tradeoff.
143
+ - Before finalizing work in this repository, run every script in `.husky/` and fix anything they report.
144
+
145
+ ### Package Shape
146
+
147
+ - Keep `index.js` as the centralized public export surface.
148
+ - Keep TypeScript declarations in `index.d.ts` aligned with every public export in `index.js`.
149
+ - Keep direct validators in `lib/validate.js`.
150
+ - Keep key-based property sanitization in `lib/validateProperties.js`.
151
+ - Keep whitelist, nested-path, casing, flattening, and CareCard bad-input behavior in `lib/validateWhitelistProperties.js`.
152
+ - Preserve the package's CommonJS module style unless the repository is intentionally migrated.
153
+ - Keep the deprecated `validate` namespace export backward-compatible while preferring direct top-level exports in new code.
154
+
155
+ ### Validation Rules
156
+
157
+ - Low-level validators should be deterministic predicate functions that return `true` or `false`.
158
+ - Password failure-message helpers should return `null` for valid input and a user-readable string for invalid input.
159
+ - `validateProperties` should return a new sanitized object and omit unknown or invalid fields without mutating the input.
160
+ - `validateWhitelistProperties` should reject missing or invalid required fields with CareCard `BAD_INPUT` errors through `@carecard/common-util`.
161
+ - Optional whitelist fields should be ignored when absent and rejected when present but invalid.
162
+ - Preserve supported snake_case and camelCase field aliases unless a task explicitly changes the API contract.
163
+ - Preserve nested dot-path handling, the maximum nesting depth, maximum path count, optional snake_case conversion, and flattening behavior.
164
+ - Avoid broad regular expressions or validation changes without focused tests for accepted values, rejected values, length limits, and edge cases.
165
+
166
+ ### Types And API Contracts
167
+
168
+ - Model input and output records, whitelist options, flattened output behavior, validators, and failure-message helpers explicitly in `index.d.ts`.
169
+ - When existing declarations are too loose, improve them with specific types as part of the touched change instead of adding new loose types.
170
+ - Update `test/types.test.ts` whenever public types, exports, options, return values, or validators change.
171
+ - Keep runtime exports, README examples, and type declarations in sync.
172
+
173
+ ### Tests
174
+
175
+ - Use Mocha for runtime tests under `test/`.
176
+ - Use `test/types.test.ts` for TypeScript declaration coverage through `npm run test:types`.
177
+ - Add focused tests for valid input, invalid input, missing fields, optional fields, array handling, nested paths, casing conversion, flattening, and error messages when those areas change.
178
+ - Keep tests deterministic and avoid relying on real external services.
179
+ - Before pushing or finalizing, run `.husky/pre-commit`; it runs lint fixing, formatting, and `npm run test:All`.
@@ -0,0 +1,14 @@
1
+ # Full repository owner
2
+ * @singh-pankaj-k
3
+
4
+ # Repository workflow and ownership metadata
5
+ .github/ @singh-pankaj-k
6
+ README.md @singh-pankaj-k
7
+ package.json @singh-pankaj-k
8
+ package-lock.json @singh-pankaj-k
9
+
10
+ # Package source, declarations, and tests
11
+ index.js @singh-pankaj-k
12
+ index.d.ts @singh-pankaj-k
13
+ lib/ @singh-pankaj-k
14
+ test/ @singh-pankaj-k
@@ -23,6 +23,8 @@ on:
23
23
  push:
24
24
  branches:
25
25
  - 'feature/**'
26
+ - 'feat/**'
27
+ - 'improvement/**'
26
28
  - 'releases/**'
27
29
  - 'release*'
28
30
  - 'hotfix/**'
@@ -30,12 +32,15 @@ on:
30
32
  - 'fix/**'
31
33
  - 'main-*'
32
34
  - 'main-**'
35
+ - 'data**'
36
+ - 'data/**'
33
37
  paths-ignore:
34
38
  - '**.md'
35
39
  workflow_dispatch:
36
40
 
37
41
  permissions:
38
42
  contents: read
43
+ issues: write
39
44
  pull-requests: write
40
45
 
41
46
  jobs:
@@ -84,6 +89,8 @@ jobs:
84
89
  HEAD: ${{ steps.target.outputs.head }}
85
90
  BASE: ${{ steps.target.outputs.base }}
86
91
  REPO: ${{ github.repository }}
92
+ PR_ASSIGNEE: ${{ github.actor }}
93
+ PR_REVIEWER: singh-pankaj-k
87
94
  run: |
88
95
  set -euo pipefail
89
96
 
@@ -98,17 +105,73 @@ jobs:
98
105
  --jq '.[0].number' || true)
99
106
 
100
107
  if [[ -n "${EXISTING:-}" ]]; then
101
- echo "An open PR already exists for $HEAD -> $BASE (#$EXISTING). Nothing to do."
102
- exit 0
108
+ echo "An open PR already exists for $HEAD -> $BASE (#$EXISTING). Updating PR metadata."
109
+ PR_NUMBER="$EXISTING"
110
+ else
111
+ TITLE="Draft: merge \`$HEAD\` into \`$BASE\`"
112
+ BODY=$'Auto-created draft PR for branch `'"$HEAD"$'`.\n\nTarget base: `'"$BASE"$'`\n\nMark this PR as ready for review when you want it to be reviewed/merged.'
113
+
114
+ gh pr create \
115
+ --repo "$REPO" \
116
+ --draft \
117
+ --base "$BASE" \
118
+ --head "$HEAD" \
119
+ --title "$TITLE" \
120
+ --body "$BODY"
121
+
122
+ PR_NUMBER=$(gh pr list \
123
+ --repo "$REPO" \
124
+ --state open \
125
+ --head "$HEAD" \
126
+ --base "$BASE" \
127
+ --json number \
128
+ --jq '.[0].number')
103
129
  fi
104
130
 
105
- TITLE="Draft: merge \`$HEAD\` into \`$BASE\`"
106
- BODY=$'Auto-created draft PR for branch `'"$HEAD"$'`.\n\nTarget base: `'"$BASE"$'`\n\nMark this PR as ready for review when you want it to be reviewed/merged.'
131
+ gh pr edit "$PR_NUMBER" \
132
+ --repo "$REPO" \
133
+ --add-assignee "$PR_ASSIGNEE"
107
134
 
108
- gh pr create \
135
+ PR_AUTHOR=$(gh pr view "$PR_NUMBER" \
109
136
  --repo "$REPO" \
110
- --draft \
111
- --base "$BASE" \
112
- --head "$HEAD" \
113
- --title "$TITLE" \
114
- --body "$BODY"
137
+ --json author \
138
+ --jq '.author.login')
139
+
140
+ if [[ "$PR_AUTHOR" == "$PR_REVIEWER" ]]; then
141
+ echo "Skipping reviewer request because $PR_REVIEWER is the PR author."
142
+ else
143
+ gh pr edit "$PR_NUMBER" \
144
+ --repo "$REPO" \
145
+ --add-reviewer "$PR_REVIEWER"
146
+ fi
147
+
148
+ - name: Assign matching issue ticket (best effort)
149
+ if: steps.target.outputs.skip == 'false'
150
+ env:
151
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
152
+ HEAD: ${{ steps.target.outputs.head }}
153
+ REPO: ${{ github.repository }}
154
+ PR_ASSIGNEE: ${{ github.actor }}
155
+ run: |
156
+ set -euo pipefail
157
+
158
+ TICKET_NUMBER=""
159
+ if [[ "$HEAD" =~ (^|/)(iss|issue|issues)[/-]?#?([0-9]+)([^0-9]|$) ]]; then
160
+ TICKET_NUMBER="${BASH_REMATCH[3]}"
161
+ fi
162
+
163
+ if [[ -z "$TICKET_NUMBER" ]]; then
164
+ echo "No GitHub issue ticket number found in branch '$HEAD'. Skipping ticket assignment."
165
+ exit 0
166
+ fi
167
+
168
+ if ! gh issue view "$TICKET_NUMBER" --repo "$REPO" --json number >/dev/null 2>&1; then
169
+ echo "GitHub issue #$TICKET_NUMBER was not found. Skipping ticket assignment."
170
+ exit 0
171
+ fi
172
+
173
+ if gh issue edit "$TICKET_NUMBER" --repo "$REPO" --add-assignee "$PR_ASSIGNEE"; then
174
+ echo "Assigned issue ticket #$TICKET_NUMBER to $PR_ASSIGNEE."
175
+ else
176
+ echo "::warning::Could not assign issue ticket #$TICKET_NUMBER to $PR_ASSIGNEE."
177
+ fi
@@ -1,17 +1,54 @@
1
1
  name: CI
2
2
 
3
3
  on:
4
+ workflow_dispatch:
4
5
  push:
6
+ branches:
7
+ - main
8
+ - develop
9
+ - development
10
+ - dev*
11
+ - feature/**
12
+ - feat/**
13
+ - improvement/**
14
+ - releases/**
15
+ - release*
16
+ - hotfix/**
17
+ - iss/**
18
+ - fix/**
19
+ - data**
20
+ - data/**
21
+ paths-ignore:
22
+ - '**.md'
5
23
  pull_request:
24
+ types: [opened, synchronize, reopened, ready_for_review]
25
+ branches:
26
+ - main
27
+ - develop
28
+ - development
29
+ - dev*
30
+ - feature/**
31
+ - feat/**
32
+ - improvement/**
33
+ - releases/**
34
+ - release*
35
+ - hotfix/**
36
+ - iss/**
37
+ - fix/**
38
+ - data**
39
+ - data/**
40
+ paths-ignore:
41
+ - '**.md'
6
42
 
7
43
  jobs:
8
44
  test:
9
45
  runs-on: ubuntu-latest
10
46
 
11
47
  steps:
12
- - uses: actions/checkout@v4
48
+ - name: Checkout repository
49
+ uses: actions/checkout@v4
13
50
 
14
- - name: Use Node.js
51
+ - name: Set up Node.js
15
52
  uses: actions/setup-node@v4
16
53
  with:
17
54
  node-version: '25'
@@ -20,5 +57,8 @@ jobs:
20
57
  - name: Install dependencies
21
58
  run: npm ci
22
59
 
23
- - name: Run tests and coverage
60
+ - name: Run tests
24
61
  run: npm run test:All
62
+
63
+ - name: Run tests with coverage
64
+ run: npm run test:coverage
package/index.d.ts CHANGED
@@ -70,6 +70,8 @@ export function isValidIntegerString(str: any): boolean;
70
70
  export function isValidUuidString(str: any): boolean;
71
71
  /** Checks if the string contains only alphanumeric characters, spaces, underscores, or hyphens. */
72
72
  export function isCharactersString(str: any): boolean;
73
+ /** Checks if the string is a valid street address format. */
74
+ export function isStreetString(str: any): boolean;
73
75
  /** Checks if the string is a valid name format. */
74
76
  export function isNameString(str: any): boolean;
75
77
  /** Checks if the string is safe for search queries. */
@@ -104,8 +106,12 @@ export function isBoolValue(inputValue: any): boolean;
104
106
  export function isPostalCodeString(inputString: any): boolean;
105
107
  /** Checks if the string contains only allowed "safe" characters. */
106
108
  export function isSafeString(str: any): boolean;
109
+ /** Checks if the value is non-empty text up to the supported maximum length. */
110
+ export function isTextString(str: any): boolean;
107
111
  /** Checks if a string exists within a given array of strings (case-insensitive). */
108
112
  export function isInStringArray(StringArray: string[], inputString: any): boolean;
113
+ /** Checks if the string is one of the supported user role request statuses. */
114
+ export function isUserRoleRequestStatusString(inputString: any): boolean;
109
115
  /** Checks if the string is a valid country code (e.g., +1). */
110
116
  export function isCountryCodeString(str: any): boolean;
111
117
  /** Checks if the string is a valid domain name. */
@@ -131,6 +137,7 @@ export const validate: {
131
137
  isValidIntegerString: typeof isValidIntegerString;
132
138
  isValidUuidString: typeof isValidUuidString;
133
139
  isCharactersString: typeof isCharactersString;
140
+ isStreetString: typeof isStreetString;
134
141
  isNameString: typeof isNameString;
135
142
  isSafeSearchString: typeof isSafeSearchString;
136
143
  isEmailString: typeof isEmailString;
@@ -148,7 +155,9 @@ export const validate: {
148
155
  isBoolValue: typeof isBoolValue;
149
156
  isPostalCodeString: typeof isPostalCodeString;
150
157
  isSafeString: typeof isSafeString;
158
+ isTextString: typeof isTextString;
151
159
  isInStringArray: typeof isInStringArray;
160
+ isUserRoleRequestStatusString: typeof isUserRoleRequestStatusString;
152
161
  isCountryCodeString: typeof isCountryCodeString;
153
162
  isValidDomainName: typeof isValidDomainName;
154
163
  isValidTimestampzString: typeof isValidTimestampzString;
package/lib/validate.js CHANGED
@@ -36,6 +36,15 @@ const isCharactersString = str => {
36
36
  return /^[\da-zA-Z _-]+$/.test(str);
37
37
  };
38
38
 
39
+ const isStreetString = str => {
40
+ if (typeof str !== 'string' || str.trim().length === 0 || str.length > 1000) {
41
+ return false;
42
+ }
43
+ const value = str.trim();
44
+ const streetRegex = /^(?![,_-])[0-9a-zA-Z\s,./#-]+$/;
45
+ return streetRegex.test(value);
46
+ };
47
+
39
48
  const isNameString = str => {
40
49
  if (typeof str !== 'string' || str.length === 0 || str.length > 1000) {
41
50
  return false;
@@ -147,6 +156,10 @@ const isSafeString = str => {
147
156
  return /^[\da-zA-Z-_.,#*'()[\]: ]+$/.test(str);
148
157
  };
149
158
 
159
+ const isTextString = str => {
160
+ return typeof str === 'string' && str.length > 0 && str.length <= 10000;
161
+ };
162
+
150
163
  const isInStringArray = (StringArray, inputString) => {
151
164
  if (isNameString(inputString)) {
152
165
  return StringArray.includes(inputString.toLowerCase().trim());
@@ -155,6 +168,11 @@ const isInStringArray = (StringArray, inputString) => {
155
168
  return false;
156
169
  };
157
170
 
171
+ const isUserRoleRequestStatusString = inputString => {
172
+ const statuses = ['pending', 'approved', 'rejected', 'cancelled', 'expired', 'hidden', 'on_hold', 'in_progress', 'info_needed'];
173
+ return isInStringArray(statuses, inputString);
174
+ };
175
+
158
176
  const isCountryCodeString = str => {
159
177
  if (typeof str !== 'string' || str.length === 0 || str.length > 4) return false;
160
178
 
@@ -204,6 +222,7 @@ module.exports = {
204
222
  isValidIntegerString,
205
223
  isValidUuidString,
206
224
  isCharactersString,
225
+ isStreetString,
207
226
  isNameString,
208
227
  isSafeSearchString,
209
228
  isEmailString,
@@ -221,7 +240,9 @@ module.exports = {
221
240
  isBoolValue,
222
241
  isPostalCodeString,
223
242
  isSafeString,
243
+ isTextString,
224
244
  isInStringArray,
245
+ isUserRoleRequestStatusString,
225
246
  isCountryCodeString,
226
247
  isValidDomainName,
227
248
  isValidTimestampzString,
@@ -19,6 +19,9 @@ const {
19
19
  isBoolValue,
20
20
  isValidUrl,
21
21
  isValidArrayOfStrings,
22
+ isStreetString,
23
+ isTextString,
24
+ isUserRoleRequestStatusString,
22
25
  } = require('./validate');
23
26
 
24
27
  function validateProperties(obj = {}) {
@@ -62,7 +65,8 @@ function validateProperties(obj = {}) {
62
65
  case 'entityType':
63
66
  case 'action_type':
64
67
  case 'actionType':
65
- case 'street':
68
+ case 'approved_by_role':
69
+ case 'approvedByRole':
66
70
  case 'city':
67
71
  case 'state':
68
72
  case 'country':
@@ -71,6 +75,11 @@ function validateProperties(obj = {}) {
71
75
  returnObj[key] = value;
72
76
  }
73
77
  break;
78
+ case 'street':
79
+ if (isStreetString(value)) {
80
+ returnObj[key] = value;
81
+ }
82
+ break;
74
83
  case 'postal_code':
75
84
  case 'postalCode':
76
85
  if (isCharactersString(value)) {
@@ -159,10 +168,34 @@ function validateProperties(obj = {}) {
159
168
  case 'changedBy':
160
169
  case 'request_id':
161
170
  case 'requestId':
171
+ case 'approved_by_user_id':
172
+ case 'approvedByUserId':
162
173
  if (isValidUuidString(value)) {
163
174
  returnObj[key] = value;
164
175
  }
165
176
  break;
177
+ case 'requested_by_name':
178
+ case 'requestedByName':
179
+ case 'requested_by_email':
180
+ case 'requestedByEmail':
181
+ case 'requested_by_phone':
182
+ case 'requestedByPhone':
183
+ case 'approved_by_name':
184
+ case 'approvedByName':
185
+ case 'approved_by_email':
186
+ case 'approvedByEmail':
187
+ case 'approved_by_phone':
188
+ case 'approvedByPhone':
189
+ if (isTextString(value)) {
190
+ returnObj[key] = value;
191
+ }
192
+ break;
193
+ case 'approved_status':
194
+ case 'approvedStatus':
195
+ if (isUserRoleRequestStatusString(value)) {
196
+ returnObj[key] = value;
197
+ }
198
+ break;
166
199
  case 'period':
167
200
  if (isCharactersString(value)) {
168
201
  returnObj[key] = value;
@@ -224,10 +257,14 @@ function validateProperties(obj = {}) {
224
257
  break;
225
258
  case 'expires_at':
226
259
  case 'expiresAt':
260
+ case 'starts_at':
261
+ case 'startsAt':
227
262
  case 'start_time':
228
263
  case 'startTime':
229
264
  case 'end_time':
230
265
  case 'endTime':
266
+ case 'approved_at':
267
+ case 'approvedAt':
231
268
  if (isValidTimestampzString(value) || isValidTimestampString(value)) {
232
269
  returnObj[key] = value;
233
270
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carecard/validate",
3
- "version": "3.1.21",
3
+ "version": "3.1.23",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/CareCard-ca/pkg-validate.git"
package/readme.md CHANGED
@@ -42,6 +42,7 @@ a string on failure and `null` on success.
42
42
  | `isValidIntegerString(value)` | Digit-only string, 1 to 20 chars. No signs or decimals. |
43
43
  | `isValidUuidString(value)` | Canonical UUID string in `8-4-4-4-12` format, case-insensitive. |
44
44
  | `isCharactersString(value)` | 1 to 1000 chars containing letters, numbers, spaces, `_`, or `-`. |
45
+ | `isStreetString(value)` | Non-empty street-like string up to 1000 chars using letters, numbers, spaces, `,`, `.`, `/`, `#`, or `-`, and not starting with `,`, `_`, or `-`. |
45
46
  | `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. |
46
47
  | `isSafeSearchString(value)` | Trimmed string that starts with a letter and then uses letters, numbers, spaces, `_`, `-`, `.`, `,`, `'`, `(`, `)`, or `@`. |
47
48
  | `isEmailString(value)` | Email-like string up to 320 chars using the package email regex. |
@@ -94,25 +95,26 @@ validateProperties(input);
94
95
  Keys are matched exactly. Both snake_case and camelCase variants are listed
95
96
  where the package supports both.
96
97
 
97
- | Validator | Keys |
98
- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
99
- | `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_type`, `documentType`, `reason`, `street`, `city`, `state`, `country`, `type` |
100
- | `isCharactersString` | `postal_code`, `postalCode`, `period` |
101
- | `isBoolValue` | `is_primary`, `isPrimary`, `active` |
102
- | `isSafeSearchString` | `search_string`, `searchString` |
103
- | `isString6To16CharacterLong` and `isSimplePasswordString` | `password`, `new_password`, `newPassword` |
104
- | `isString6To16CharacterLong` and `isPasswordString` | `strong_password`, `strongPassword` |
105
- | `isEmailString` | `email` |
106
- | `isPhoneNumber` | `phone_number`, `phoneNumber` |
107
- | `isUrlSafeString` | `token`, `email_confirm_token`, `emailConfirmToken`, `verification_token`, `verificationToken` |
108
- | `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` |
109
- | `isValidIntegerString` | `offset_number`, `offsetNumber`, `number_of_orders`, `numberOfOrders`, `price`, `from`, `number` |
110
- | `isValidJsonString` on the raw value | `about` |
111
- | `isValidJsonString(JSON.stringify(value))` | `weight`, `dimensions`, `permission`, `scope_data`, `scopeData`, `meta_data`, `metaData` |
112
- | `isValidArrayOfStrings` | `aliases` |
113
- | `isImageUrl` or `isValidUrl` | `image_url`, `imageUrl`, `website`, `file_url`, `fileUrl` |
114
- | `isValidDomainName` | `domain_name`, `domainName`, `domain`, `email_domain`, `emailDomain`, `email_domain_name`, `emailDomainName` |
115
- | `isValidTimestampzString` or `isValidTimestampString` | `expires_at`, `expiresAt` |
98
+ | Validator | Keys |
99
+ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
100
+ | `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_type`, `documentType`, `reason`, `entity_type`, `entityType`, `action_type`, `actionType`, `city`, `state`, `country`, `type` |
101
+ | `isStreetString` | `street` |
102
+ | `isCharactersString` | `postal_code`, `postalCode`, `period` |
103
+ | `isBoolValue` | `is_primary`, `isPrimary`, `active` |
104
+ | `isSafeSearchString` | `search_string`, `searchString` |
105
+ | `isString6To16CharacterLong` and `isSimplePasswordString` | `password`, `new_password`, `newPassword` |
106
+ | `isString6To16CharacterLong` and `isPasswordString` | `strong_password`, `strongPassword` |
107
+ | `isEmailString` | `email` |
108
+ | `isPhoneNumber` | `phone_number`, `phoneNumber` |
109
+ | `isUrlSafeString` | `token`, `email_confirm_token`, `emailConfirmToken`, `verification_token`, `verificationToken` |
110
+ | `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
+ | `isValidIntegerString` | `offset_number`, `offsetNumber`, `number_of_orders`, `numberOfOrders`, `price`, `from`, `number`, `limit`, `offset` |
112
+ | `isValidJsonString` on the raw value | `about` |
113
+ | `isValidJsonString(JSON.stringify(value))` | `weight`, `dimensions`, `permission`, `scope_data`, `scopeData`, `meta_data`, `metaData` |
114
+ | `isValidArrayOfStrings` | `aliases` |
115
+ | `isImageUrl` or `isValidUrl` | `image_url`, `imageUrl`, `website`, `file_url`, `fileUrl` |
116
+ | `isValidDomainName` | `domain_name`, `domainName`, `domain`, `email_domain`, `emailDomain`, `email_domain_name`, `emailDomainName` |
117
+ | `isValidTimestampzString` or `isValidTimestampString` | `expires_at`, `expiresAt`, `start_time`, `startTime`, `end_time`, `endTime` |
116
118
 
117
119
  ## `validateWhitelistProperties(inputObject, requiredProperties, options)`
118
120