-
Notifications
You must be signed in to change notification settings - Fork 72
ENG-200 Ship new CW SDK v2 #4380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref: #000 - api@1.27.15-alpha.0 - @metriport/api-sdk@17.2.0-alpha.0 - @metriport/carequality-cert-runner@1.18.16-alpha.0 - @metriport/commonwell-cert-runner@1.26.18-alpha.0 - @metriport/commonwell-jwt-maker@1.25.0-alpha.0 - @metriport/commonwell-sdk@6.0.0-alpha.0 - @metriport/core@1.25.0-alpha.0 - @metriport/ihe-gateway-sdk@0.19.16-alpha.0 - @metriport/shared@0.25.0-alpha.0 - utils@1.25.14-alpha.0 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref: #000 - api@1.27.16-alpha.0 - @metriport/api-sdk@17.2.1-alpha.0 - @metriport/carequality-cert-runner@1.18.17-alpha.0 - @metriport/carequality-sdk@1.7.1-alpha.0 - @metriport/commonwell-cert-runner@2.0.0-alpha.0 - @metriport/commonwell-jwt-maker@1.25.1-alpha.0 - @metriport/commonwell-sdk@6.0.1-alpha.0 - @metriport/core@1.25.1-alpha.0 - @metriport/eslint-plugin-eslint-rules@1.0.7-alpha.0 - @metriport/fhir-sdk@1.0.6-alpha.0 - @metriport/ihe-gateway-sdk@0.19.17-alpha.0 - infrastructure@1.22.15-alpha.0 - mllp-server@0.3.15-alpha.0 - @metriport/shared@0.25.1-alpha.0 - utils@1.25.15-alpha.0 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref: #000 - api@1.27.15-alpha.0 - @metriport/api-sdk@17.2.0-alpha.0 - @metriport/carequality-cert-runner@1.18.16-alpha.0 - @metriport/commonwell-cert-runner@1.26.18-alpha.0 - @metriport/commonwell-jwt-maker@1.25.0-alpha.0 - @metriport/commonwell-sdk@6.0.0-alpha.0 - @metriport/core@1.25.0-alpha.0 - @metriport/ihe-gateway-sdk@0.19.16-alpha.0 - @metriport/shared@0.25.0-alpha.0 - utils@1.25.14-alpha.0 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
ENG-200 CW v2 SDK
WalkthroughRepository-wide migration of CommonWell imports to a versioned v1 namespace, introduction of a new CommonWell v2 adapter and mocks, substantial refactor and expansion of commonwell-cert-runner (new flows, CLI, server, payloads), major SDK API redesign (clients, interfaces, models), and supporting shared/zod utilities reorganization. Minor config/docs and dependency updates included. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant CLI as Cert Runner CLI
participant OM as OrgManagement (Member API)
participant CW as CommonWell (Org API)
User->>CLI: Run runner
CLI->>OM: Create or load Organization (certs, NPI)
OM-->>CLI: OrgManagementResponse (CommonWell client)
CLI->>CW: Execute flows (patient/link/doc)
CW-->>CLI: Results (IDs, links, docs)
CLI-->>User: Report success/fail per flow
sequenceDiagram
participant Cons as Contributor (CommonWell)
participant Srv as ContributionServer
participant Cw as CommonWell Consumer
participant FS as File System
Cw->>Srv: POST /oauth/token (Basic)
Srv-->>Cw: access_token (Bearer)
Cw->>Srv: GET /oauth/fhir/DocumentReference?patient=...
Srv-->>Cw: Bundle[DocumentReference(url=/Binary/:id)]
Cw->>Srv: GET /oauth/fhir/Binary/:id (Bearer)
Srv-->>Cw: Binary(data)
Cw->>FS: Save contents
sequenceDiagram
participant CW as CommonWell API
participant Flow as DocumentConsumption Flow
participant FS as File System
Flow->>CW: createOrUpdatePatient
CW-->>Flow: PatientCollection (id)
Flow->>CW: queryDocuments(patientId)
CW-->>Flow: DocumentReference[]
loop docs
Flow->>CW: retrieveDocument(url, stream)
CW-->>Flow: {contentType, size}
Flow->>FS: Write file(s)
end
Flow->>CW: deletePatient(ids)
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120+ minutes Possibly related PRs
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Ref eng-200 Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
…repo ENG-513 Move CW folders to commonwell-v1 on api and core
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 49
🔭 Outside diff range comments (17)
packages/commonwell-jwt-maker/package.json (1)
13-15
: Add atag
topublishConfig
for pre-releasesTo prevent this alpha from being published under
latest
, updatepackages/commonwell-jwt-maker/package.json
:"publishConfig": { "access": "public", + "tag": "alpha" },
No other packages currently define a
publishConfig.tag
, so this introduces the convention for alpha builds. If your release pipeline already applies a tag, you can ignore this.packages/api/src/external/commonwell-v1/admin/recreate-patients-at-hies.ts (1)
150-153
: Bug: Unconditionally deleting the “old” patient can delete the newly created patientAfter creating the new CW patient, the code deletes
originalCWPatientId
unconditionally, even whenoriginalCWPatientId === newCWPatientId
. In that case, you’d delete the patient you just created/updated.Guard the deletion:
- // remove old patient - log(`Deleting old patient from CW...`); - await commonWell.deletePatient(queryMeta, originalCWPatientId); + // remove old patient only if IDs differ + if (originalCWPatientId !== newCWPatientId) { + log(`Deleting old patient from CW...`); + await commonWell.deletePatient(queryMeta, originalCWPatientId); + } else { + log(`Skipping deletion: original and new CW patient IDs match.`); + }packages/api/src/external/commonwell-v1/mock.ts (1)
393-395
: Method signature mismatch: resetPatientLink missing parameters
CommonWellAPI.resetPatientLink
is invoked elsewhere asresetPatientLink(meta, personId, patientId)
, but the mock defines it with no parameters. This risks interface non-compliance and runtime confusion in tests.Align the signature:
- async resetPatientLink(): Promise<void> { + async resetPatientLink( + meta: sdk.RequestMetadata, + personId: string, + patientId: string + ): Promise<void> { return; }packages/api/src/external/commonwell-v1/link/shared.ts (3)
100-100
: Fix logical operator usage in filter condition.The current expression
isLOLA2 || isLOLA3
evaluates totrue
due to both functions being truthy, causing all network links to pass the filter instead of filtering for LOLA2 or LOLA3 links.Apply this fix to use the logical OR correctly:
- const validLola2or3Links = networkLinks.flatMap(filterTruthy).filter(isLOLA2 || isLOLA3); + const validLola2or3Links = networkLinks.flatMap(filterTruthy).filter(link => isLOLA2(link) || isLOLA3(link));
101-101
: Fix logical operator usage in filter condition.Same issue as Line 100 - the expression
isLOLA2 || isLOLA3
will always evaluate totrue
, causing incorrect filtering behavior.Apply this fix:
- const invalidLola2or3Links = invalidLinks.flatMap(filterTruthy).filter(isLOLA2 || isLOLA3); + const invalidLola2or3Links = invalidLinks.flatMap(filterTruthy).filter(link => isLOLA2(link) || isLOLA3(link));
216-216
: Improve type safety and handle undefined gender code.The current code accesses
patient?.details.gender.code
without null-checking thegender
property, which could cause runtime errors ifgender
is undefined.Apply this fix to improve safety:
- const genderCode = patient?.details.gender.code; + const genderCode = patient?.details.gender?.code;packages/api/src/external/commonwell-v1/proxy/cw-process-request.ts (1)
42-42
: Bug: _count filter is silently ignoredallowedQueryParams excludes "_count" and applyFilterParams reads "count" instead of "_count". As a result, the requested count limit is never applied.
Apply:
-const allowedQueryParams = ["status", "date", "_summary"]; +const allowedQueryParams = ["status", "date", "_summary", "_count"];export function applyFilterParams( docRefs: DocumentReference[], params: URLSearchParams ): DocumentReference[] { const date = params.get("date"); - const countParam = params.get("count"); + const countStr = params.get("_count"); const status = params.get("status"); @@ - if (countParam) { - const count = parseInt(countParam); + if (countStr) { + const count = parseInt(countStr); if (!isNaN(count)) { filteredDocRefs = filteredDocRefs.slice(0, count); } }Also applies to: 203-249
packages/lambdas/src/cw-enhanced-coverage-link-patients.ts (1)
118-131
: Bug: patientIds and cqOrgIds validations are inverted (should be arrays), breaking Input contractThe lambda expects lists of patient IDs and CQ org IDs (per the file’s description and typical Input shape for link flows). Current checks reject arrays and allow non-arrays — this will cause runtime failures and/or incorrect payloads passed downstream.
Fix the validations to accept non-empty arrays and ensure 'done' is boolean. Also prefer MetriportError with additional context, consistent with your error handling guidelines.
Apply this diff:
- const patientIds = body.patientIds; - if (!patientIds) throw new Error(`Missing patientIds in body`); - if (Array.isArray(patientIds)) throw new Error(`Invalid patientIds in body`); + const patientIds = body.patientIds; + if (!Array.isArray(patientIds) || patientIds.length === 0) { + throw new MetriportError("Invalid patientIds in body", undefined, { body: stringify(body) }); + } - const cqOrgIds = body.cqOrgIds; - if (!cqOrgIds) throw new Error(`Missing cqOrgIds in body`); - if (Array.isArray(cqOrgIds)) throw new Error(`Invalid cqOrgIds in body`); + const cqOrgIds = body.cqOrgIds; + if (!Array.isArray(cqOrgIds) || cqOrgIds.length === 0) { + throw new MetriportError("Invalid cqOrgIds in body", undefined, { body: stringify(body) }); + } - const done = body.done; - if (done == undefined) throw new Error(`Missing 'done' in body`); + const done = body.done; + if (typeof done !== "boolean") { + throw new MetriportError("Missing or invalid 'done' in body", undefined, { body: stringify(body) }); + } if (done) return { cxId, cxOrgOID, patientIds, done }; return { cxId, cxOrgOID, patientIds, cqOrgIds, done };packages/shared/src/common/date.ts (1)
42-53
: validateDateOfBirth may throw instead of returning false (uses throwing validator by default)The function claims to return true/false, but the default validateIsPastOrPresent throws on future dates. This will propagate an exception instead of returning false.
Use the safe validator by default and guard against thrown validators.
Apply this diff:
const { - validateDateIsAfter1900: _validateDateIsAfter1900 = validateDateIsAfter1900, - validateIsPastOrPresent: _validateIsPastOrPresent = validateIsPastOrPresent, + validateDateIsAfter1900: _validateDateIsAfter1900 = validateDateIsAfter1900, + validateIsPastOrPresent: _validateIsPastOrPresent = validateIsPastOrPresentSafe, } = options || {}; - return ( - _validateDateIsAfter1900(parsedDate.format(ISO_DATE)) && - _validateIsPastOrPresent(parsedDate.format(ISO_DATE)) - ); + const iso = parsedDate.format(ISO_DATE); + const after1900 = _validateDateIsAfter1900(iso); + let pastOrPresent = false; + try { + pastOrPresent = _validateIsPastOrPresent(iso); + } catch { + pastOrPresent = false; + } + return after1900 && pastOrPresent;If you want, I can add unit tests covering valid DOB, future date, invalid strings, and override hooks.
packages/api/src/external/hie/set-doc-query-progress.ts (1)
215-224
: Fix aggregation precedence: failed should override completedCurrent order returns "completed" even if any source failed (as long as some completed). Prefer:
- processing > failed > completed
Apply this diff:
export function aggregateStatus(docQueryProgress: DocumentQueryStatus[]): DocumentQueryStatus { const hasProcessing = docQueryProgress.some(status => status === "processing"); const hasFailed = docQueryProgress.some(status => status === "failed"); const hasCompleted = docQueryProgress.some(status => status === "completed"); - if (hasProcessing) return "processing"; - if (hasCompleted) return "completed"; - if (hasFailed) return "failed"; - return "completed"; + if (hasProcessing) return "processing"; + if (hasFailed) return "failed"; + if (hasCompleted) return "completed"; + return "completed"; }packages/api/src/external/fhir-converter/converter.ts (1)
27-30
: Use strict checks; avoid abstract inequalityPer guidelines, avoid
!=
. Also no need to union withundefined
in the param type.Apply this diff:
-export function isConvertible(mimeType?: string | undefined): boolean { - // TODO move to core's isMimeTypeXML() - return mimeType != null && ["text/xml", "application/xml"].includes(mimeType); -} +export function isConvertible(mimeType?: string): boolean { + // TODO move to core's isMimeTypeXML() + return typeof mimeType === "string" && ["text/xml", "application/xml"].includes(mimeType); +}packages/api/src/external/commonwell-v1/document/shared.ts (1)
26-35
: Fix filename composition to avoid 'undefined' segment and extra underscoreIf
display
is undefined, the template currently injects the string "undefined" into the filename and also always adds an underscore after the prefix. Make the display segment optional and only append the trailing underscore when present.Apply this diff:
export function getFileName(patient: Patient, doc: Document): string { const prefix = "document_" + patient.id; - const display = doc.content?.type?.coding?.length - ? doc.content?.type.coding[0]?.display - : undefined; + const display = doc.content?.type?.coding?.[0]?.display?.trim(); const suffix = getSuffix(doc.id); const extension = getFileExtension(doc.content?.mimeType); - const fileName = `${prefix}_${display ? display + "_" : display}${suffix}${extension}`; + const displaySegment = display ? `${display}_` : ""; + const fileName = `${prefix}_${displaySegment}${suffix}${extension}`; return fileName.replace(/\s/g, "-"); }packages/utils/src/commonwell/cq-org-builder.ts (1)
4-10
: Update resultFilename to use v1 path in CQ Org BuilderThe builder is currently writing to the non-versioned JSON, but the v1 get-orgs importer reads from the versioned folder. We need to align them:
• File: packages/utils/src/commonwell/cq-org-builder.ts
– Line 34: change the output path to point atcommonwell-v1
instead ofcommonwell
Suggested diff:
--- a/packages/utils/src/commonwell/cq-org-builder.ts +++ b/packages/utils/src/commonwell/cq-org-builder.ts @@ 34c34 -const resultFilename = `../../packages/core/src/external/commonwell/cq-bridge/cq-org-list.json`; +const resultFilename = `../../packages/core/src/external/commonwell-v1/cq-bridge/cq-org-list.json`;After updating, rerun the builder and verify that
packages/core/src/external/commonwell-v1/cq-bridge/cq-org-list.json
is correctly overwritten and in sync with getOrgs.packages/api/src/external/commonwell-v1/document/document-query.ts (1)
314-316
: Use organization name with organizationQueryMeta in document-query.tsThe vast majority of v1 call sites pass the org name (e.g.
initiator.name
) intoorganizationQueryMeta
, and core tests assume that signature. Indocument-query.ts
you’re passing the raw OID instead, which is inconsistent and likely incorrect.• File: packages/api/src/external/commonwell-v1/document/document-query.ts
Line 315Suggested change:
- const queryMeta = organizationQueryMeta(initiator.oid, { npi: initiator.npi }); + const queryMeta = organizationQueryMeta(initiator.name, { npi: initiator.npi });packages/lambdas/src/cw-session-management.ts (1)
50-55
: Avoid logging secrets and credentials (security/PII concern)Logging secret ARNs and usernames can leak sensitive information into CloudWatch/Sentry logs. Remove or mask these values.
Apply this diff to redact/remove sensitive logs:
- console.log( - `Running with cookieSecretArn: ${cookieSecretArn}, ` + - `codeChallengeSecretArn: ${codeChallengeSecretArn}, ` + - `baseUrl: ${baseUrl}` - ); + console.log(`Starting CW session management`, { baseUrl });- console.log(`...username ${username}, password 🤫`); + console.log(`Credentials loaded`);Also applies to: 68-70
packages/commonwell-sdk/src/models/certificates.ts (1)
28-33
: Remove_links
from CertificateResp mocks and adjust tests
SincecertificateRespSchema
now only includes thecertificates
array, any mock or test that returns or asserts_links
on aCertificateResp
will fail. Please update all call sites accordingly:
- packages/api/src/external/commonwell-v1/mock.ts
- In the
addCertificateToOrg
mock, remove the_links
property and return an object shaped like{ certificates: [{ purpose: … }] }
.- packages/api/src/external/commonwell-v1/tests/cw.register-facility.test.ts
- Change the
.mockImplementation(() => Promise.resolve({} as CertificateResp))
to return a validCertificateResp
, e.g.Promise.resolve({ certificates: [] })
.- Audit
packages/api
for any other mocks or consumers that return or reference_links
on certificate responses and update them to match the new schema.packages/commonwell-cert-runner/src/env.ts (1)
25-26
: Harden CONTRIB_SERVER_PORT parsing (radix + NaN check)Ensure radix is specified and fail fast on invalid ports.
Apply this diff:
-export const contribServerPort = parseInt(getEnvOrFail("CONTRIB_SERVER_PORT")); +const contribServerPortRaw = getEnvOrFail("CONTRIB_SERVER_PORT"); +export const contribServerPort = Number.parseInt(contribServerPortRaw, 10); +if (Number.isNaN(contribServerPort)) { + throw new Error(`Invalid CONTRIB_SERVER_PORT: ${contribServerPortRaw}`); +}
@@ -32,6 +32,7 @@ | |||
"@metriport/api-sdk": "file:packages/api-sdk", | |||
"@metriport/carequality-sdk": "file:packages/carequality-sdk", | |||
"@metriport/commonwell-sdk": "file:packages/commonwell-sdk", | |||
"@metriport/commonwell-sdk-v1": "npm:@metriport/commonwell-sdk@^5.9.11", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Alias introduction for v1 SDK — verify import usage
Adding "@metriport/commonwell-sdk-v1" via the npm alias is the right approach to decouple v1 from the local v2 workspace. Please verify that all v1-intended imports use this alias and that no v1 code still imports "@metriport/commonwell-sdk".
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Imports of v1 alias (expected to be present):"
rg -nP -C2 'from\s+[\"\']@metriport/commonwell-sdk-v1[\"\']' --type ts
echo
echo "Stray imports to the unversioned SDK within v1 code (should be zero):"
rg -nP -C3 'from\s+[\"\']@metriport/commonwell-sdk[\"\']' --type ts \
| gawk 'BEGIN{bad=0} /external\/commonwell-v1/ {print; bad=1} END{exit bad}'
Length of output: 238
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "🔍 Checking for imports of the v1 alias (@metriport/commonwell-sdk-v1):"
rg -nP -C2 "from\s+['\"]@metriport/commonwell-sdk-v1['\"]" --type ts || true
echo
echo "🔍 Checking for stray imports of the unversioned SDK (@metriport/commonwell-sdk):"
rg -nP -C2 "from\s+['\"]@metriport/commonwell-sdk['\"]" --type ts || true
Length of output: 30452
Alias introduction for v1 SDK — stray unversioned imports detected
We still have numerous imports of the unversioned @metriport/commonwell-sdk
in code that targets v1. All v1-intended imports must use the new @metriport/commonwell-sdk-v1
alias. Please update the following areas:
• packages/commonwell-cert-runner/src/…
• packages/utils/src/commonwell/…
• packages/lambdas/src/document-downloader.ts
• packages/commonwell-jwt-maker/src/index.ts
For example, in each affected file:
-import { CommonWellAPI } from "@metriport/commonwell-sdk";
+import { CommonWellAPI } from "@metriport/commonwell-sdk-v1";
Once updated, verify there are no remaining @metriport/commonwell-sdk
imports in v1 code.
Committable suggestion skipped: line range outside the PR's diff.
import { CommonWell } from "@metriport/commonwell-sdk-v1/client/commonwell"; | ||
import { Organization } from "@metriport/commonwell-sdk-v1/models/organization"; | ||
import { CertificateResp } from "@metriport/commonwell-sdk-v1/models/certificates"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
CW SDK import migration to v1 looks consistent; please verify no lingering v0 imports
The switch to v1 paths for the CommonWell client and models aligns with the PR-wide migration.
Run this script to ensure there are no remaining imports from the non-v1 SDK across the repo:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Checking for any lingering imports from @metriport/commonwell-sdk (non -v1)..."
rg -nP '@metriport/commonwell-sdk(?!-v1)' -g '!**/node_modules/**' -S || true
echo "Checking for any remaining internal imports pointing to external/commonwell (non -v1)..."
rg -nP 'external/commonwell(?!-v1)' -S || true
Length of output: 12497
🔍 Remaining v0 CommonWell SDK imports found
I ran the grep script and discovered multiple lingering @metriport/commonwell-sdk
references across the repo. To complete the v0→v1 migration, please update these to @metriport/commonwell-sdk-v1
(or document why they remain on v0):
• packages/utils/src/commonwell/coverage-assessment.ts
• packages/utils/src/commonwell/migrate-patients.ts
• packages/utils/src/commonwell/delete-network-links.ts
• packages/utils/src/commonwell/cq-org-builder.ts
• packages/lambdas/src/document-downloader.ts
• packages/commonwell-cert-runner/src//*.ts
• packages/commonwell-jwt-maker/src/index.ts
• packages/api/src/external/commonwell-v2//*.ts
• packages/shared/src/net/tests/axios.ts (fixture paths in compiled code)
🤖 Prompt for AI Agents
In
packages/api/src/external/commonwell-v1/__tests__/cw.register-facility.test.ts
around lines 5 to 7, the test still imports from the old
@metriport/commonwell-sdk package; update these imports to
@metriport/commonwell-sdk-v1 (or add a brief comment explaining why v0 must
remain) and then search the repo for any remaining @metriport/commonwell-sdk
references (the review lists specific files) and change them to
@metriport/commonwell-sdk-v1 or document exceptions; after changes, update
package.json dependencies if needed, run the grep/test suite to ensure no
lingering references, and fix any compiled fixture paths that still point to v0.
import { | ||
CommonWellAPI, | ||
organizationQueryMeta, | ||
RequestMetadata, | ||
} from "@metriport/commonwell-sdk-v1"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Prefer type-only imports for types from the v1 SDK
CommonWellAPI
and RequestMetadata
are types; importing them with import type
avoids pulling them into the runtime bundle and aligns with TS best practices. Keep organizationQueryMeta
as a value import.
Apply this diff:
-import {
- CommonWellAPI,
- organizationQueryMeta,
- RequestMetadata,
-} from "@metriport/commonwell-sdk-v1";
+import type { CommonWellAPI, RequestMetadata } from "@metriport/commonwell-sdk-v1";
+import { organizationQueryMeta } from "@metriport/commonwell-sdk-v1";
Run this script to ensure there are no lingering non-v1 SDK imports and that the v1 alias is present:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching for non-v1 CommonWell SDK imports..."
rg -nP -C2 --type ts --type tsx --type js \
$'from\\s+[\'"]@metriport/commonwell-sdk(?!-v1)[\'"]|require\\([\'"]@metriport/commonwell-sdk(?!-v1)[\'"]\\)'
echo
echo "Verifying v1 alias/dependency is declared in packages/api/package.json..."
rg -nC2 '"@metriport/commonwell-sdk-v1"' packages/api/package.json || {
echo "Missing @metriport/commonwell-sdk-v1 alias/dependency in packages/api/package.json"; exit 1;
}
Length of output: 308
I’ve updated the import-search to use glob patterns instead of unrecognized --type=tsx
. Let’s re-run verification:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching for non-v1 CommonWell SDK imports in .ts, .tsx, .js files..."
rg -nP -C2 -g '*.ts' -g '*.tsx' -g '*.js' \
'from\s+["'\'']@metriport/commonwell-sdk(?!-v1)["'\'']|require\(["'\'']@metriport/commonwell-sdk(?!-v1)["'\'']\)'
echo
echo "Verifying @metriport/commonwell-sdk-v1 is declared in packages/api/package.json..."
rg -nC2 '"@metriport/commonwell-sdk-v1"' packages/api/package.json || {
echo "Missing @metriport/commonwell-sdk-v1 alias/dependency in packages/api/package.json"
exit 1
}
Length of output: 13523
Prefer type-only imports for v1 SDK types
We’ve confirmed that in packages/api/src/external/commonwell-v1/admin/shared.ts
there are no stray non-v1 imports and that "@metriport/commonwell-sdk-v1"
is declared in packages/api/package.json
. Please update the imports as follows to keep types out of the runtime bundle:
-import {
- CommonWellAPI,
- organizationQueryMeta,
- RequestMetadata,
-} from "@metriport/commonwell-sdk-v1";
+import type { CommonWellAPI, RequestMetadata } from "@metriport/commonwell-sdk-v1";
+import { organizationQueryMeta } from "@metriport/commonwell-sdk-v1";
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
import { | |
CommonWellAPI, | |
organizationQueryMeta, | |
RequestMetadata, | |
} from "@metriport/commonwell-sdk-v1"; | |
import type { CommonWellAPI, RequestMetadata } from "@metriport/commonwell-sdk-v1"; | |
import { organizationQueryMeta } from "@metriport/commonwell-sdk-v1"; |
🤖 Prompt for AI Agents
In packages/api/src/external/commonwell-v1/admin/shared.ts around lines 1-5, the
current import from "@metriport/commonwell-sdk-v1" pulls types into the runtime
bundle; change it to a type-only import (use "import type { CommonWellAPI,
organizationQueryMeta, RequestMetadata } from
\"@metriport/commonwell-sdk-v1\";") so these symbols are erased at compile time
and do not end up in the runtime bundle.
import { getAndUpdateCWOrgAndMetriportOrg } from "../../../external/commonwell-v1/command/create-or-update-cw-organization"; | ||
import { getParsedOrgOrFail } from "../../../external/commonwell-v1/organization"; | ||
import { cwOrgActiveSchema } from "../../../external/commonwell-v1/shared"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
LGTM: imports migrated to commonwell-v1.
Import paths look correct and scoped to v1.
To ensure there are no lingering imports to the unversioned path elsewhere, run:
Also applies to: 22-22
🏁 Script executed:
#!/bin/bash
# Find any remaining imports from external/commonwell (non-v1/v2)
rg -nP -C2 'external/commonwell(?!-v1|-v2)'
Length of output: 3220
Update remaining unversioned external/commonwell reference
A hard-coded path in packages/utils/src/commonwell/cq-org-builder.ts
still points at the unversioned directory:
- File: packages/utils/src/commonwell/cq-org-builder.ts
Line 34:This should be updated to reference the v1 path, for example:const resultFilename = `../../packages/core/src/external/commonwell/cq-bridge/cq-org-list.json`;
const resultFilename = `../../packages/core/src/external/commonwell-v1/cq-bridge/cq-org-list.json`;
Please update this (and any similar literals) to use the versioned directory.
🤖 Prompt for AI Agents
In packages/utils/src/commonwell/cq-org-builder.ts around line 34, the code uses
an unversioned relative path ("../../packages/core/src/external/commonwell/...")
for cq-bridge output; change the literal to point to the versioned directory
(e.g.
"../../packages/core/src/external/commonwell-v1/cq-bridge/cq-org-list.json").
Also search the repository for any other hard-coded
"../../packages/core/src/external/commonwell" literals and update them to
"../../packages/core/src/external/commonwell-v1" (or the appropriate v1 path) so
all references use the versioned directory.
CW_MEMBER_CERTIFICATE="-----BEGIN CERTIFICATE----- | ||
... | ||
-----END CERTIFICATE-----" | ||
COMMONWELL_MEMBER_OID=1.3.6.1.4.1.18.12.29.2022.945 | ||
COMMONWELL_ORG_PRIVATE_KEY="-----BEGIN PRIVATE KEY----- | ||
CW_MEMBER_PRIVATE_KEY="-----BEGIN PRIVATE KEY----- | ||
... | ||
-----END PRIVATE KEY-----" | ||
COMMONWELL_ORG_CERTIFICATE="-----BEGIN CERTIFICATE----- | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Prevent secret scanners from flagging the README and avoid multiline .env pitfalls.
Inline PEM examples trigger gitleaks and many .env loaders don’t support multiline values. Recommend base64 or file-path variables instead.
-CW_MEMBER_CERTIFICATE="-----BEGIN CERTIFICATE-----
-...
------END CERTIFICATE-----"
-CW_MEMBER_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
-...
------END PRIVATE KEY-----"
+# Prefer base64 or file paths to avoid multiline .env issues and secret scanners
+# Option A (base64):
+CW_MEMBER_CERTIFICATE_BASE64=REPLACE_WITH_BASE64_CERT
+CW_MEMBER_PRIVATE_KEY_BASE64=REPLACE_WITH_BASE64_KEY
+# Option B (file paths):
+CW_MEMBER_CERTIFICATE_PATH=/path/to/member-cert.pem
+CW_MEMBER_PRIVATE_KEY_PATH=/path/to/member-key.pem
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
CW_MEMBER_CERTIFICATE="-----BEGIN CERTIFICATE----- | |
... | |
-----END CERTIFICATE-----" | |
COMMONWELL_MEMBER_OID=1.3.6.1.4.1.18.12.29.2022.945 | |
COMMONWELL_ORG_PRIVATE_KEY="-----BEGIN PRIVATE KEY----- | |
CW_MEMBER_PRIVATE_KEY="-----BEGIN PRIVATE KEY----- | |
... | |
-----END PRIVATE KEY-----" | |
COMMONWELL_ORG_CERTIFICATE="-----BEGIN CERTIFICATE----- | |
``` | |
# Prefer base64 or file paths to avoid multiline .env issues and secret scanners | |
# Option A (base64): | |
CW_MEMBER_CERTIFICATE_BASE64=REPLACE_WITH_BASE64_CERT | |
CW_MEMBER_PRIVATE_KEY_BASE64=REPLACE_WITH_BASE64_KEY | |
# Option B (file paths): | |
CW_MEMBER_CERTIFICATE_PATH=/path/to/member-cert.pem | |
CW_MEMBER_PRIVATE_KEY_PATH=/path/to/member-key.pem |
🤖 Prompt for AI Agents
In packages/commonwell-cert-runner/README.md around lines 102 to 108, the README
currently embeds inline PEM blocks for CW_MEMBER_CERTIFICATE and
CW_MEMBER_PRIVATE_KEY which can trigger secret scanners and break .env parsers;
replace these inline multiline PEM examples with either base64-encoded values or
examples that point to file paths (e.g., CW_MEMBER_CERTIFICATE_BASE64 or
CW_MEMBER_CERT_PATH) and update the usage notes to show how to decode the base64
into files or how to reference the file path at runtime, plus add a short note
recommending storing real secrets in a secure vault or environment-specific
files excluded from repo.
const duration = Date.now() - ingestionStart; | ||
metrics.ingestion = { duration, timestamp: new Date() }; | ||
log(`Done in ${duration} ms`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix shadowing/redeclaration: local duration
collides with imported dayjs plugin
You import the dayjs duration
plugin (Line 7) and then redeclare const duration
locally (Line 92). This will fail to compile with an identifier collision. Rename the local variable to avoid the clash and clarify units.
Apply this diff:
- const duration = Date.now() - ingestionStart;
- metrics.ingestion = { duration, timestamp: new Date() };
- log(`Done in ${duration} ms`);
+ const ingestionDurationMs = Date.now() - ingestionStart;
+ metrics.ingestion = { duration: ingestionDurationMs, timestamp: new Date() };
+ log(`Done in ${ingestionDurationMs} ms`);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const duration = Date.now() - ingestionStart; | |
metrics.ingestion = { duration, timestamp: new Date() }; | |
log(`Done in ${duration} ms`); | |
const ingestionDurationMs = Date.now() - ingestionStart; | |
metrics.ingestion = { duration: ingestionDurationMs, timestamp: new Date() }; | |
log(`Done in ${ingestionDurationMs} ms`); |
🤖 Prompt for AI Agents
In packages/lambdas/src/sqs-to-opensearch-xml.ts around lines 92 to 94, the
local const named `duration` collides with the imported dayjs `duration` plugin;
rename the local variable (for example to `ingestionDurationMs` or `durationMs`)
and update its usages (metrics.ingestion = { duration, ... } → metrics.ingestion
= { duration: ingestionDurationMs, ... } and log(`Done in ${duration} ms`) →
log(`Done in ${ingestionDurationMs} ms`)) so the identifier no longer shadows
the imported plugin and the units remain clear.
const existingLevels = startFrom.split(".").map(Number); | ||
|
||
if (existingLevels.length > amountOfLevels) { | ||
throw new Error( | ||
`startFrom OID has ${existingLevels.length} levels, but amountOfLevels is ${amountOfLevels}` | ||
); | ||
} | ||
|
||
const levelsNeeded = amountOfLevels - existingLevels.length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Validate startFrom components are integers and within range
Protect against non-numeric parts producing NaN and ensure arcs fall within the configured range.
Apply this diff:
- const existingLevels = startFrom.split(".").map(Number);
+ const existingLevels = startFrom.split(".").map(part => {
+ const n = Number(part);
+ if (!Number.isInteger(n)) {
+ throw new Error(`startFrom contains a non-integer component: "${part}"`);
+ }
+ if (n < range.min || n > range.max) {
+ throw new Error(
+ `startFrom component ${n} is out of range [${range.min}, ${range.max}]`
+ );
+ }
+ return n;
+ });
🤖 Prompt for AI Agents
In packages/shared/src/common/__tests__/oid.ts around lines 25 to 33, validate
that each component of startFrom.split('.') is a numeric integer and within the
allowed arc range before computing levelsNeeded: parse each part with Number(),
ensure Number.isInteger(value) and not NaN, and if any part fails throw a clear
Error listing the offending component and index; additionally check each integer
is >= 0 and < the configured max arcs per level (replace "configured max arcs"
with the actual config variable used in the module) and throw if out of range;
only after these checks compute existingLevels and levelsNeeded.
describe("invalid ISO dates", () => { | ||
const invalidDates = [ | ||
"0195-01-01", | ||
"2023-13-01", // invalid month | ||
"2023-00-01", // invalid month | ||
"2023-01-32", // invalid day | ||
"2023-01-00", // invalid day | ||
"2023-02-30", // invalid day for February | ||
"2023-04-31", // invalid day for April | ||
"2023-1-01", // missing leading zero in month | ||
"2023-01-1", // missing leading zero in day | ||
"2023/01/01", // wrong separator | ||
"01-01-2023", // wrong format | ||
// "2023-01-01T00:00:00Z", // includes time | ||
// "2023-01-01 00:00:00", // includes time | ||
"2023-1-1", // missing leading zeros | ||
"23-01-01", // short year | ||
"2023-01", // missing day | ||
"2023", // missing month and day | ||
"", // empty string | ||
"invalid-date", | ||
]; | ||
|
||
test.each(invalidDates)("should not match invalid ISO date: %s", date => { | ||
expect(ISO_DATE_REGEX.test(date)).toBe(false); | ||
expect(() => isoDateSchema.parse(date)).toThrow(); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Regex anchoring gap allows false positives (time suffixes, prefixes) — expand tests and fix regex
Current regexes accept substrings due to missing anchors/grouping:
- ISO_DATE_REGEX lacks ^ and $ entirely (date.ts:10-11).
- US_DATE_REGEX places ^ and $ only on the first/last alternation, not the whole alternation (date.ts:16-17), effectively behaving like
^A|B|C|D$
.
This means strings like "2023-01-01T00:00:00Z" or "foo01/01/2023bar" can pass. Your test file currently comments out time-suffixed invalid cases, which hides this bug.
Action:
- Enable invalid cases with time suffixes in this test.
- Add prefix/suffix contamination cases.
- Anchor and group the regexes in date.ts.
Enable the "includes time" cases and add prefix/suffix contamination checks:
const invalidDates = [
"0195-01-01",
"2023-13-01", // invalid month
"2023-00-01", // invalid month
"2023-01-32", // invalid day
"2023-01-00", // invalid day
"2023-02-30", // invalid day for February
"2023-04-31", // invalid day for April
"2023-1-01", // missing leading zero in month
"2023-01-1", // missing leading zero in day
"2023/01/01", // wrong separator
"01-01-2023", // wrong format
- // "2023-01-01T00:00:00Z", // includes time
- // "2023-01-01 00:00:00", // includes time
+ "2023-01-01T00:00:00Z", // includes time
+ "2023-01-01 00:00:00", // includes time
+ "foo2023-01-01", // prefix contamination
+ "2023-01-01bar", // suffix contamination
"2023-1-1", // missing leading zeros
"23-01-01", // short year
"2023-01", // missing day
"2023", // missing month and day
"", // empty string
"invalid-date",
];
const invalidDates = [
"13/01/2023", // invalid month
"00/01/2023", // invalid month
"01/32/2023", // invalid day
"01/00/2023", // invalid day
"02/30/2023", // invalid day for February
"04/31/2023", // invalid day for April
"1/01/2023", // missing leading zero in month
"01/1/2023", // missing leading zero in day
"2023-01-01", // wrong format
"2023/01/01", // wrong separator
"01-01-2023", // wrong separator
"01/01/23", // short year
- // "01/01/2023T00:00:00Z", // includes time
- // "01/01/2023 00:00:00", // includes time
+ "01/01/2023T00:00:00Z", // includes time
+ "01/01/2023 00:00:00", // includes time
+ "foo01/01/2023", // prefix contamination
+ "01/01/2023bar", // suffix contamination
"01/2023", // missing day
"2023", // missing month and day
"", // empty string
"invalid-date",
];
Also update the production regexes in packages/shared/src/external/zod/date.ts:
Outside this file (for maintainers applying the fix), consider:
- export const ISO_DATE_REGEX =
- /(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)/;
+ export const ISO_DATE_REGEX =
+ /^(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)$/;
- export const US_DATE_REGEX =
- /^(?:0[1-9]|1[0-2])\/(?:0[1-9]|1\d|2[0-8])\/(?:[1-9]\d{3})|(?:0[13-9]|1[0-2])\/(?:29|30)\/(?:[1-9]\d{3})|(?:0[13578]|1[02])\/31\/(?:[1-9]\d{3})|02\/29\/(?:(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26]))|(?:[2468][048]|[13579][26])00)$/;
+ export const US_DATE_REGEX =
+ /^(?:(?:0[1-9]|1[0-2])\/(?:0[1-9]|1\d|2[0-8])\/(?:[1-9]\d{3})|(?:0[13-9]|1[0-2])\/(?:29|30)\/(?:[1-9]\d{3})|(?:0[13578]|1[02])\/31\/(?:[1-9]\d{3})|02\/29\/(?:(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26]))|(?:[2468][048]|[13579][26])00))$/;
Also applies to: 72-99
🏁 Script executed:
#!/bin/bash
set -e
echo "== ISO_DATE_REGEX definition =="
rg -n 'export const ISO_DATE_REGEX' -C3 packages/shared
echo
echo "== US_DATE_REGEX definition =="
rg -n 'export const US_DATE_REGEX' -C3 packages/shared
echo
echo "== invalidDates in iso-date.test.ts =="
rg -n 'const invalidDates' -C5 packages/shared/src/external/zod/__tests__/iso-date.test.ts
Length of output: 2815
Anchor regexes to match full strings and expand invalid-date tests
The current ISO_DATE_REGEX (date.ts:11–12) is unanchored, and US_DATE_REGEX (date.ts:17–18) only anchors the first and last alternation, allowing partial matches (e.g. "2023-01-01T00:00:00Z"
or "foo01/01/2023bar"
). The tests in iso-date.test.ts
haven’t been updated to catch these gaps.
• In packages/shared/src/external/zod/date.ts
:
- Wrap the entire ISO_DATE_REGEX in
^…$
. - Group the US_DATE_REGEX alternation in a non-capturing
(?:… )
and place^
/$
outside.
• In packages/shared/src/external/zod/__tests__/iso-date.test.ts
:
- Under
describe("invalid ISO dates")
(≈ line 23), uncomment and include:
“2023-01-01T00:00:00Z”
“2023-01-01 00:00:00”
Add contamination cases:
“foo2023-01-01”
“2023-01-01bar”
• In the same test file under describe("invalid US dates")
(≈ line 72):
- Include analogous time-suffix and contamination cases:
“01/01/2023T00:00:00Z”, “01/01/2023 00:00:00”, “foo01/01/2023”, “01/01/2023bar”
Example diffs:
--- a/packages/shared/src/external/zod/date.ts
+++ b/packages/shared/src/external/zod/date.ts
@@ -11,7 +11,7 @@
-export const ISO_DATE_REGEX =
- /(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|…)-02-29)/;
+export const ISO_DATE_REGEX =
+ /^(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|…)-02-29)$/;
@@ -17,7 +17,7 @@
-export const US_DATE_REGEX =
- /^(?:0[1-9]|1[0-2])\/…|02\/29\/…$/;
+export const US_DATE_REGEX =
+ /^(?:(?:0[1-9]|1[0-2])\/…|02\/29\/…)$/;
--- a/packages/shared/src/external/zod/__tests__/iso-date.test.ts
+++ b/packages/shared/src/external/zod/__tests__/iso-date.test.ts
@@ describe("invalid ISO dates")
- // "2023-01-01T00:00:00Z", // includes time
- // "2023-01-01 00:00:00", // includes time
+ "2023-01-01T00:00:00Z", // includes time
+ "2023-01-01 00:00:00", // includes time
+ "foo2023-01-01", // prefix contamination
+ "2023-01-01bar", // suffix contamination
@@ describe("invalid US dates")
- // "01/01/2023T00:00:00Z", // includes time
- // "01/01/2023 00:00:00", // includes time
+ "01/01/2023T00:00:00Z", // includes time
+ "01/01/2023 00:00:00", // includes time
+ "foo01/01/2023", // prefix contamination
+ "01/01/2023bar", // suffix contamination
These changes will ensure your regexes cannot be bypassed by extra prefixes/suffixes or time components.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/shared/src/external/zod/__tests__/iso-date.test.ts around lines
23–50 and the related regex definitions in
packages/shared/src/external/zod/date.ts (ISO_DATE_REGEX at ~lines 11–12 and
US_DATE_REGEX at ~lines 17–18): the ISO regex must be anchored to the full
string and the US regex alternation must be grouped and anchored so partial
matches or trailing/leading contamination/time-suffixes are rejected; fix
date.ts by wrapping ISO_DATE_REGEX with ^...$ and change US_DATE_REGEX to use a
non-capturing group (?: ... ) with ^ and $ outside, then update this test file
by uncommenting and including "2023-01-01T00:00:00Z" and "2023-01-01 00:00:00"
in the invalid ISO dates and adding contamination cases "foo2023-01-01" and
"2023-01-01bar"; also update the invalid US dates block (~line 72) to include
"01/01/2023T00:00:00Z", "01/01/2023 00:00:00", "foo01/01/2023", and
"01/01/2023bar" so the tests catch prefix/suffix and time-component bypasses.
@@ -8,6 +8,7 @@ export { emptyFunction } from "./common/general"; | |||
export { metriportOrganization } from "./common/metriport-organization"; | |||
export { isValidUrl } from "./common/net"; | |||
export { normalizeOid } from "./common/normalize-oid"; | |||
export { makeOid } from "./common/__tests__/oid"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Do not export from a test-only path (tests) — move makeOid into production code
Exporting from ./common/tests/oid risks publish/build failures (test dirs are commonly excluded) and leaks test helpers into the public API. Move makeOid into a non-test module (e.g., ./common/oid.ts) and export from there.
Apply this change to the export:
-export { makeOid } from "./common/__tests__/oid";
+export { makeOid } from "./common/oid";
Follow-up:
- Create packages/shared/src/common/oid.ts and move the implementation from tests/oid.ts into it.
- Keep tests in tests/oid.test.ts targeting the new production path.
Verification script to ensure tests is excluded from builds (and would currently break this export):
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Inspecting shared package tsconfig for __tests__ exclusions..."
rg -n '__tests__' packages/shared/tsconfig*.json || true
echo "Inspecting shared package.json for published files (looking for dist-only publishing)..."
rg -n '"files"\s*:' packages/shared/package.json -n || true
rg -n '"exports"\s*:' packages/shared/package.json -n || true
echo "Listing any runtime imports referencing __tests__ from shared..."
rg -n '__tests__' packages/shared/src/index.ts || true
echo "Done."
Length of output: 832
Do not export from a test-only path — move makeOid
into production code
Exporting makeOid
from ./common/__tests__/oid
risks build or publish failures (test directories are often excluded) and unintentionally exposes test helpers in your public API. Please:
- Create a new production module at
packages/shared/src/common/oid.ts
and move the implementation from
packages/shared/src/common/__tests__/oid.ts
into it. - Update the test file to import from the new path:
packages/shared/src/common/__tests__/oid.test.ts
→packages/shared/src/common/oid.ts
- Change the public export in
packages/shared/src/index.ts
-export { makeOid } from "./common/__tests__/oid";
+export { makeOid } from "./common/oid";
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export { makeOid } from "./common/__tests__/oid"; | |
export { makeOid } from "./common/oid"; |
🤖 Prompt for AI Agents
In packages/shared/src/index.ts around line 11 you're exporting makeOid from a
test-only path which can break builds; create a new production module at
packages/shared/src/common/oid.ts and move the implementation from
packages/shared/src/common/__tests__/oid.ts into that file, update the test file
to import from the new path (packages/shared/src/common/__tests__/oid.test.ts
should import from ../oid or ../../common/oid as appropriate), and change the
public export in packages/shared/src/index.ts to export { makeOid } from
"./common/oid" (remove the export from the __tests__ path).
@@ -55,6 +55,7 @@ | |||
"@langchain/community": "^0.3.16", | |||
"@langchain/core": "^0.3.19", | |||
"@metriport/api-sdk": "file:packages/api-sdk", | |||
"@metriport/commonwell-sdk": "5.9.11", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Confirm which CW surface utils consumes; add v1 alias here if utils imports it
If any code in utils imports "@metriport/commonwell-sdk-v1", this package should also declare the alias dependency; otherwise isolated installs/builds of utils will fail to resolve it (don’t rely on cross-package alias leakage). Also consider using a caret range to allow compatible patch updates.
-
If utils needs v1 imports, add:
"@metriport/commonwell-sdk-v1": "npm:@metriport/commonwell-sdk@^5.9.11" -
If utils directly targets the non-versioned SDK (intentionally), keeping "@metriport/commonwell-sdk": "5.9.11" is fine, though you may prefer "^5.9.11" for patch upgrades.
Run this to verify import usage within utils:
If results include @metriport/commonwell-sdk-v1, add the alias to dependencies here. If results include only @metriport/commonwell-sdk, no change needed beyond optionally switching to ^5.9.11.
🏁 Script executed:
#!/bin/bash
# Find CW SDK imports within utils and show context
rg -nP --type=ts -C3 $'from\\s+[\'"]@metriport/commonwell-sdk(-v1)?[\'"]|import\\([\'"]@metriport/commonwell-sdk(-v1)?[\'"]\\)' packages/utils
Length of output: 2234
No alias needed for @metriport/commonwell-sdk-v1
; just bump to a caret range
After searching packages/utils
, all imports reference "@metriport/commonwell-sdk"
(no -v1
), so you don’t need to add the v1 alias. To allow patch upgrades, update the dependency spec:
--- packages/utils/package.json
@@ dependencies
- "@metriport/commonwell-sdk": "5.9.11",
+ "@metriport/commonwell-sdk": "^5.9.11",
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"@metriport/commonwell-sdk": "5.9.11", | |
"@metriport/commonwell-sdk": "^5.9.11", |
🤖 Prompt for AI Agents
In packages/utils/package.json around line 58, the dependency currently pins
"@metriport/commonwell-sdk" to "5.9.11" and the PR added an unnecessary alias
for "-v1"; remove any alias and update the dependency spec to use a caret range
so patch upgrades are allowed: change the version string to "^5.9.11" for
"@metriport/commonwell-sdk" and do not add a separate
"@metriport/commonwell-sdk-v1" entry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review continued from previous batch...
const isMemberAPI = orgOID === Config.getCWMemberOID(); | ||
if (isMemberAPI) throw new Error("Cannot use the member OID as an organization OID"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use consistent error type and include context
Elsewhere you throw MetriportError with additionalInfo. Do the same here for consistency and better diagnostics.
Apply this diff:
- const isMemberAPI = orgOID === Config.getCWMemberOID();
- if (isMemberAPI) throw new Error("Cannot use the member OID as an organization OID");
+ const isMemberAPI = orgOID === Config.getCWMemberOID();
+ if (isMemberAPI)
+ throw new MetriportError("Cannot use the member OID as an organization OID", undefined, {
+ orgOID,
+ });
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const isMemberAPI = orgOID === Config.getCWMemberOID(); | |
if (isMemberAPI) throw new Error("Cannot use the member OID as an organization OID"); | |
const isMemberAPI = orgOID === Config.getCWMemberOID(); | |
if (isMemberAPI) | |
throw new MetriportError( | |
"Cannot use the member OID as an organization OID", | |
undefined, | |
{ orgOID }, | |
); |
🤖 Prompt for AI Agents
In packages/api/src/external/commonwell-v2/api.ts around lines 60 to 62, replace
the plain Error throw with a MetriportError that uses the same descriptive
message but also sets a suitable error code and includes additionalInfo (e.g., {
orgOID, memberOID: Config.getCWMemberOID() }) so callers and logs get diagnostic
context; ensure MetriportError is imported if not already and preserve existing
stack behavior by constructing the MetriportError with the message and
additionalInfo.
given: demographics?.name?.[0]?.given ?? ["John"], | ||
family: demographics?.name?.[0]?.family ?? ["Doe"], | ||
use: NameUseCodes.usual, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix inconsistent array wrapping for name fields
The given
and family
fields should be strings, not arrays, to match the type definitions and other parts of the codebase.
Apply this diff to fix the inconsistency:
- given: demographics?.name?.[0]?.given ?? ["John"],
- family: demographics?.name?.[0]?.family ?? ["Doe"],
+ given: demographics?.name?.[0]?.given ?? ["John"],
+ family: demographics?.name?.[0]?.family ?? "Doe",
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/api/src/external/commonwell-v2/mock/payloads.ts around lines 33 to
35, the given and family name fields are currently set as arrays but should be
strings to match the type definitions; change them to produce strings (e.g., use
demographics?.name?.[0]?.given?.join(' ') ?? "John" for given and
demographics?.name?.[0]?.family?.join(' ') ?? "Doe" for family) so the fields
are plain strings rather than arrays.
given: ["John"], | ||
family: ["Doe"], | ||
use: "usual", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix inconsistent array wrapping for name fields in createPatientLink
Same issue as above - the given
and family
fields should match the expected types.
Apply this diff:
- given: ["John"],
- family: ["Doe"],
+ given: ["John"],
+ family: "Doe",
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
given: ["John"], | |
family: ["Doe"], | |
use: "usual", | |
given: ["John"], | |
family: "Doe", | |
use: "usual", |
🤖 Prompt for AI Agents
In packages/api/src/external/commonwell-v2/mock/payloads.ts around lines 101 to
103, the name fields in createPatientLink are using inconsistent types; change
the given and family fields to be arrays of strings (e.g., ["John"] and ["Doe"])
so they match the expected types and the rest of the payload structure.
family: ["Doe"], | ||
given: ["John"], | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix inconsistent array wrapping for name fields in createDocument
The name fields in the Patient resource should be consistent with the expected types.
Apply this diff:
- family: ["Doe"],
- given: ["John"],
+ family: "Doe",
+ given: ["John"],
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
family: ["Doe"], | |
given: ["John"], | |
}, | |
family: "Doe", | |
given: ["John"], | |
}, |
🤖 Prompt for AI Agents
In packages/api/src/external/commonwell-v2/mock/payloads.ts around lines 166 to
168, the Patient.name fields are not consistently wrapped as an array of
HumanName objects; update the payload so Patient.name is an array (i.e., wrap
the existing name object in an array) and ensure its family and given properties
remain arrays (family: ["Doe"], given: ["John"]) so the resource matches the
expected FHIR types.
if (contentsFileName.endsWith(".bin")) { | ||
const newFileExtension = getFileExtension(contentType); | ||
fs.renameSync(contentsFileName, `${contentsFileName.replace(".bin", "")}${newFileExtension}`); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Potential file handling issue with rename operation
The file rename operation after download might fail if the file is still being written to or if there are permission issues. Consider adding error handling.
if (contentsFileName.endsWith(".bin")) {
const newFileExtension = getFileExtension(contentType);
- fs.renameSync(contentsFileName, `${contentsFileName.replace(".bin", "")}${newFileExtension}`);
+ const newFileName = `${contentsFileName.replace(".bin", "")}${newFileExtension}`;
+ try {
+ fs.renameSync(contentsFileName, newFileName);
+ console.log(`>>> Renamed file to ${newFileName}`);
+ } catch (renameError) {
+ console.log(`>>> Warning: Could not rename file: ${errorToString(renameError)}`);
+ // File is still saved with .bin extension, which is acceptable
+ }
}
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/commonwell-cert-runner/src/flows/document-consumption.ts around
lines 141 to 144, the synchronous fs.rename call can fail if the file is still
being written or on permission errors; wrap the rename in robust error handling
by ensuring any download/write stream is closed/flushed before renaming, replace
the plain renameSync with a try/catch around an atomic async rename (use
fs.promises.rename) or a small retry/backoff loop, and on failure log the
filename, target name and the caught error then either retry a few times or
surface the error to the caller so callers can handle the failure.
export function makeDemographics(): Omit<Demographics, "identifier"> { | ||
const shouldAddDriversLicense = Math.random() < 0.5; | ||
const driversLicense: PatientIdentifier | undefined = shouldAddDriversLicense | ||
? { | ||
type: "DL", | ||
value: makeId(), | ||
system: caDriversLicenseUri, | ||
use: "secondary", | ||
} | ||
: undefined; | ||
return { | ||
address: [ | ||
{ | ||
use: NameUseCodes.usual, | ||
zip, | ||
country: "USA", | ||
use: AddressUseCodes.home, | ||
postalCode: faker.location.zipCode(), | ||
state: faker.location.state(), | ||
line: [faker.location.streetAddress()], | ||
city: faker.location.city(), | ||
}, | ||
], | ||
name: [ | ||
{ | ||
use: NameUseCodes.usual, | ||
family: [lastName], | ||
given: [firstName], | ||
given: [faker.person.firstName()], | ||
family: [faker.person.lastName()], | ||
}, | ||
], | ||
gender: { | ||
code: gender, | ||
}, | ||
birthDate: dob, | ||
}, | ||
}); | ||
export const makeDocPerson = (init?: PersonDataOnOrg) => { | ||
const docPatient = makeDocPatient(init); | ||
gender: faker.helpers.arrayElement([GenderCodes.M, GenderCodes.F]), | ||
birthDate: faker.date.birthdate().toISOString().split("T")[0], | ||
...(driversLicense ? { identifier: [driversLicense] } : {}), | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix return type to match actual shape (identifier may be present).
makeDemographics sometimes includes identifier (driver’s license), but the return type excludes it. Expose the optional identifier in the type to avoid losing type information and suppressing legit access in callers.
Apply this diff:
-export function makeDemographics(): Omit<Demographics, "identifier"> {
+export function makeDemographics(): Omit<Demographics, "identifier"> &
+ Partial<Pick<Demographics, "identifier">> {
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export function makeDemographics(): Omit<Demographics, "identifier"> { | |
const shouldAddDriversLicense = Math.random() < 0.5; | |
const driversLicense: PatientIdentifier | undefined = shouldAddDriversLicense | |
? { | |
type: "DL", | |
value: makeId(), | |
system: caDriversLicenseUri, | |
use: "secondary", | |
} | |
: undefined; | |
return { | |
address: [ | |
{ | |
use: NameUseCodes.usual, | |
zip, | |
country: "USA", | |
use: AddressUseCodes.home, | |
postalCode: faker.location.zipCode(), | |
state: faker.location.state(), | |
line: [faker.location.streetAddress()], | |
city: faker.location.city(), | |
}, | |
], | |
name: [ | |
{ | |
use: NameUseCodes.usual, | |
family: [lastName], | |
given: [firstName], | |
given: [faker.person.firstName()], | |
family: [faker.person.lastName()], | |
}, | |
], | |
gender: { | |
code: gender, | |
}, | |
birthDate: dob, | |
}, | |
}); | |
export const makeDocPerson = (init?: PersonDataOnOrg) => { | |
const docPatient = makeDocPatient(init); | |
gender: faker.helpers.arrayElement([GenderCodes.M, GenderCodes.F]), | |
birthDate: faker.date.birthdate().toISOString().split("T")[0], | |
...(driversLicense ? { identifier: [driversLicense] } : {}), | |
}; | |
} | |
export function makeDemographics(): Omit<Demographics, "identifier"> & | |
Partial<Pick<Demographics, "identifier">> { | |
const shouldAddDriversLicense = Math.random() < 0.5; | |
const driversLicense: PatientIdentifier | undefined = shouldAddDriversLicense | |
? { | |
type: "DL", | |
value: makeId(), | |
system: caDriversLicenseUri, | |
use: "secondary", | |
} | |
: undefined; | |
return { | |
address: [ | |
{ | |
use: AddressUseCodes.home, | |
postalCode: faker.location.zipCode(), | |
state: faker.location.state(), | |
line: [faker.location.streetAddress()], | |
city: faker.location.city(), | |
}, | |
], | |
name: [ | |
{ | |
use: NameUseCodes.usual, | |
given: [faker.person.firstName()], | |
family: [faker.person.lastName()], | |
}, | |
], | |
gender: faker.helpers.arrayElement([GenderCodes.M, GenderCodes.F]), | |
birthDate: faker.date.birthdate().toISOString().split("T")[0], | |
...(driversLicense ? { identifier: [driversLicense] } : {}), | |
}; | |
} |
🤖 Prompt for AI Agents
In packages/commonwell-cert-runner/src/payloads.ts around lines 58 to 89, the
function return type Omit<Demographics, "identifier"> excludes the optional
identifier that the function can add; change the return type to include an
optional identifier (for example: Omit<Demographics, "identifier"> & {
identifier?: Demographics["identifier"] }) so callers retain correct typing when
identifier is present.
...(demographics.identifier ?? []), | ||
{ | ||
use: "official", | ||
system: `${facilityId}`, | ||
value: makePatientId({ facilityId }), | ||
assigner: memberName, | ||
}, | ||
], | ||
managingOrganization: { | ||
identifier: [ | ||
{ | ||
system: facilityId, | ||
}, | ||
], | ||
}, | ||
}; | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Check PatientIdentifier.assigner type (string vs Reference).
You set assigner: memberName (string). patientIdentifierSchema.assigner commonly is a Reference shape; if it doesn’t accept string, this will fail zod validation.
Run this script to inspect the schema:
🏁 Script executed:
#!/bin/bash
# Show patientIdentifierSchema and referenceInIdentifierSchema to verify assigner type
rg -n -C3 -g '!**/dist/**' -g '!**/build/**' -g '!**/node_modules/**' \
-P 'export\s+const\s+patientIdentifierSchema\s*=\s*z\.object|referenceInIdentifierSchema' \
packages/commonwell-sdk/src/models/identifier.ts
Length of output: 959
Ensure assigner is a Reference, not a raw string
The patientIdentifierSchema
defines assigner
as referenceInIdentifierSchema.nullish()
, i.e. a Reference‐shaped object, not a bare string. As written,
assigner: memberName,
will fail zod validation.
Please update the payload to wrap memberName
in a Reference object. For example:
--- a/packages/commonwell-cert-runner/src/payloads.ts
+++ b/packages/commonwell-cert-runner/src/payloads.ts
@@ lines 101-117
- assigner: memberName,
+ assigner: {
+ display: memberName,
+ },
- File: packages/commonwell-cert-runner/src/payloads.ts
- Lines: ~101–117
🤖 Prompt for AI Agents
packages/commonwell-cert-runner/src/payloads.ts around lines 101 to 117: the
assigner field is currently set to a raw string (memberName) but
patientIdentifierSchema expects a Reference-shaped object; replace the raw
string with a Reference object that wraps memberName (e.g. an object with a
reference property containing the memberName or the appropriate resource type +
id), so assigner becomes a Reference-shaped object matching
referenceInIdentifierSchema.nullish().
line: z.array(z.string()).nullish(), | ||
city: z.string().nullish(), | ||
state: z.string().nullish(), | ||
country: emptyStringToUndefinedSchema, | ||
postalCode: z.string(), | ||
use: emptyStringToUndefinedSchema.pipe(addressUseCodesSchema.nullish()), | ||
type: emptyStringToUndefinedSchema.pipe(addressTypeCodesSchema.nullish()), | ||
period: periodSchema.nullish(), | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Normalization and required fields: strengthen address schema
- city/state currently accept empty strings; align with your emptyStringToUndefined normalization for consistency.
- postalCode is required but z.string() permits empty strings; enforce non-empty.
Apply this diff:
export const addressSchema = z.object({
- line: z.array(z.string()).nullish(),
- city: z.string().nullish(),
- state: z.string().nullish(),
+ line: z.array(z.string()).nullish(),
+ city: emptyStringToUndefinedSchema,
+ state: emptyStringToUndefinedSchema,
country: emptyStringToUndefinedSchema,
- postalCode: z.string(),
+ postalCode: z.string().min(1),
use: emptyStringToUndefinedSchema.pipe(addressUseCodesSchema.nullish()),
type: emptyStringToUndefinedSchema.pipe(addressTypeCodesSchema.nullish()),
period: periodSchema.nullish(),
});
🤖 Prompt for AI Agents
In packages/commonwell-sdk/src/models/address.ts around lines 26 to 34, update
the schema so city and state use the same emptyStringToUndefinedSchema
normalization as country, and make postalCode a non-empty string; specifically
replace city: z.string().nullish() and state: z.string().nullish() with city:
emptyStringToUndefinedSchema and state: emptyStringToUndefinedSchema, and change
postalCode: z.string() to postalCode: z.string().min(1) (or
emptyStringToUndefinedSchema.pipe(z.string().min(1)) if you want to normalize
then enforce non-empty).
export const genderCodesSchema = z.preprocess( | ||
zodToLowerCase, | ||
z | ||
.nativeEnum(GenderCodes) | ||
.or(z.nativeEnum(GenderCodesBackwardsCompatible)) | ||
.or(z.enum(Object.keys(GenderCodes).map(k => k.toLowerCase()) as [string, ...string[]])) | ||
.transform(coerceGender) | ||
); | ||
export type Gender = z.infer<typeof genderCodesSchema>; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: ‘UN’/‘UNK’ codes rejected due to lowercasing before enum check
zodToLowerCase
lowercases inputs, but z.nativeEnum(GenderCodesBackwardsCompatible)
expects "UN"
and not "un"
. Likewise, "UNK"
becomes "unk"
and is not allowed by the union. Because validation fails before .transform(coerceGender)
, these inputs never reach your coercion logic.
Simplify acceptance to “any string -> coerce” to cover all intended inputs:
-export const genderCodesSchema = z.preprocess(
- zodToLowerCase,
- z
- .nativeEnum(GenderCodes)
- .or(z.nativeEnum(GenderCodesBackwardsCompatible))
- .or(z.enum(Object.keys(GenderCodes).map(k => k.toLowerCase()) as [string, ...string[]]))
- .transform(coerceGender)
-);
+export const genderCodesSchema = z.preprocess(
+ zodToLowerCase,
+ z.string().transform(coerceGender)
+);
This relies solely on coerceGender
for validation/normalization, which already supports “f/m/o/u”, “female/male/other/unknown”, “un/undifferentiated”, and “unk/unknown”.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export const genderCodesSchema = z.preprocess( | |
zodToLowerCase, | |
z | |
.nativeEnum(GenderCodes) | |
.or(z.nativeEnum(GenderCodesBackwardsCompatible)) | |
.or(z.enum(Object.keys(GenderCodes).map(k => k.toLowerCase()) as [string, ...string[]])) | |
.transform(coerceGender) | |
); | |
export type Gender = z.infer<typeof genderCodesSchema>; | |
export const genderCodesSchema = z.preprocess( | |
zodToLowerCase, | |
z.string().transform(coerceGender) | |
); | |
export type Gender = z.infer<typeof genderCodesSchema>; |
🤖 Prompt for AI Agents
In packages/commonwell-sdk/src/models/demographics.ts around lines 26 to 35, the
existing z.preprocess lowercases input before checking native enums which causes
valid codes like "UN"/"UNK" to be rejected; instead accept any string and let
coerceGender handle normalization/validation. Replace the current chained
enum/preprocess schema with a simple z.string().transform(coerceGender) (keep
the exported Gender type as z.infer<typeof genderCodesSchema>), removing
zodToLowerCase and the enum unions so all inputs reach coerceGender for
normalization.
Dependencies
See below
Description
Merging these PRs into
develop
:Testing
See each PR ^.
Release Plan
@coderabbitai ignore