-
Notifications
You must be signed in to change notification settings - Fork 68
RELEASE moving get appointments to lambdas + canvas fixes #3960
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-292 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
feat(ehr): moving get-appointments for Canvas to lambda
WalkthroughThis update introduces a new system for retrieving and managing EHR environment credentials and secrets, centralizing environment-specific logic into dedicated modules. It adds new Lambda infrastructure for appointment retrieval, enhances error handling (notably for FHIR validation), and refactors client creation to return additional metadata. Internal API routes for JWT token and practice secret retrieval are added, and legacy static configuration accessors are removed. Changes
Sequence Diagram(s)Dynamic EHR Secret RetrievalsequenceDiagram
participant API as API Route
participant getSecrets as getSecrets (core)
participant EnvModule as EHR Env Module
participant Config as Config
API->>getSecrets: getSecrets({ehr, cxId, practiceId})
getSecrets->>EnvModule: getEhrEnv({cxId, practiceId})
EnvModule->>Config: getEnvVar(s)
Config-->>EnvModule: env value(s)
EnvModule-->>getSecrets: { environment, clientKey, clientSecret } or { environment, apiKey }
getSecrets-->>API: EHR secrets
Appointment Retrieval via LambdasequenceDiagram
participant API as API Route
participant Handler as EhrGetAppointmentsHandler
participant Lambda as getAppointments Lambda
participant Direct as EhrGetAppointmentsDirect
API->>Handler: getAppointments(request)
alt Cloud
Handler->>Lambda: Invoke Lambda with request
Lambda->>Direct: getAppointments(request)
Direct->>...: Fetch appointments from EHR
Direct-->>Lambda: Appointments[]
Lambda-->>Handler: Appointments[]
else Dev
Handler->>Direct: getAppointments(request)
Direct->>...: Fetch appointments from EHR
Direct-->>Handler: Appointments[]
end
Handler-->>API: Appointments[]
Enhanced Error Handling for FHIR ValidationsequenceDiagram
participant Client as EHR Client
participant makeRequest as makeRequest Utility
participant FHIR as FHIR API
Client->>makeRequest: makeRequest(params)
makeRequest->>FHIR: HTTP Request
FHIR-->>makeRequest: Error Response (OperationOutcome)
makeRequest->>makeRequest: isFhirValidationError(error)
alt Is FHIR Validation Error
makeRequest-->>Client: Throw NotFoundError
else
makeRequest-->>Client: Throw original error
end
Possibly related PRs
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error code ERR_SSL_WRONG_VERSION_NUMBER ✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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: 4
🧹 Nitpick comments (3)
packages/core/src/external/ehr/canvas/environment.ts (1)
14-22
: Consider extracting the key construction pattern.The key construction follows a consistent pattern (
${cxId}_${practiceId}_suffix
) that's repeated three times. Consider extracting this into a helper function to reduce duplication and improve maintainability.+function buildCanvasConfigKey(cxId: string, practiceId: string, suffix: string): string { + return `${cxId}_${practiceId}_${suffix}`; +} + export function getCanvasEnv({ cxId, practiceId, }: EhrPerPracticeParams): EhrEnvAndClientCredentials<CanvasEnv> { const rawClientsMap = Config.getCanvasClientKeyAndSecretMap(); if (!rawClientsMap) throw new MetriportError("Canvas secrets map not set"); const clientMap = cxClientKeyAndSecretMapSecretSchema.safeParse(JSON.parse(rawClientsMap)); if (!clientMap.success) throw new MetriportError("Canvas clients map has invalid format"); - const env = `${cxId}_${practiceId}_env`; + const env = buildCanvasConfigKey(cxId, practiceId, "env"); const envEntry = clientMap.data[env]; - const key = `${cxId}_${practiceId}_key`; + const key = buildCanvasConfigKey(cxId, practiceId, "key"); const keyEntry = clientMap.data[key]; - const secret = `${cxId}_${practiceId}_secret`; + const secret = buildCanvasConfigKey(cxId, practiceId, "secret"); const secretEntry = clientMap.data[secret];packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts (1)
15-17
: Interface design enables polymorphism but consider method naming.The generic interface design is good for extensibility. However, consider whether the method name
getAppointments
could be more specific since it's handling different appointment methods internally.If this interface will handle multiple distinct appointment retrieval strategies, consider renaming to
handleAppointmentRequest
or similar to reflect the method dispatching:export interface EhrGetAppointmentsHandler { - getAppointments<T extends Appointment>(request: GetAppointmentsRequest): Promise<T[]>; + handleAppointmentRequest<T extends Appointment>(request: GetAppointmentsRequest): Promise<T[]>; }packages/infra/lib/ehr-nested-stack.ts (1)
266-296
: Fix method naming and verify bucket permissions.The implementation follows the established pattern, but there's a minor naming issue and the bucket permissions should be verified.
- private setupGetAppointmentslambda(ownProps: { + private setupGetAppointmentsLambda(ownProps: {Also verify that
grantWrite
permissions are sufficient for theehrResponsesBucket
usage pattern.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (73)
packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts
(1 hunks)packages/api/src/external/ehr/athenahealth/shared.ts
(1 hunks)packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
(3 hunks)packages/api/src/external/ehr/canvas/shared.ts
(1 hunks)packages/api/src/external/ehr/eclinicalworks/shared.ts
(1 hunks)packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts
(1 hunks)packages/api/src/external/ehr/elation/shared.ts
(4 hunks)packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts
(3 hunks)packages/api/src/external/ehr/healthie/shared.ts
(2 hunks)packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts
(1 hunks)packages/api/src/external/ehr/shared/utils/appointment.ts
(1 hunks)packages/api/src/external/ehr/shared/utils/client.ts
(4 hunks)packages/api/src/routes/ehr/canvas/patient-webhook.ts
(1 hunks)packages/api/src/routes/ehr/elation/appointment-webhook.ts
(1 hunks)packages/api/src/routes/ehr/elation/patient-webhook.ts
(1 hunks)packages/api/src/routes/ehr/healthie/appointment-webhook.ts
(1 hunks)packages/api/src/routes/ehr/healthie/patient-webhook.ts
(1 hunks)packages/api/src/routes/ehr/util.ts
(1 hunks)packages/api/src/routes/internal/ehr/index.ts
(2 hunks)packages/api/src/routes/internal/ehr/practice.ts
(1 hunks)packages/api/src/routes/internal/jwt-token/index.ts
(2 hunks)packages/api/src/routes/internal/jwt-token/token.ts
(1 hunks)packages/api/src/shared/config.ts
(0 hunks)packages/core/src/external/aws/lambda.ts
(1 hunks)packages/core/src/external/ehr/api/get-client-key-and-secret.ts
(1 hunks)packages/core/src/external/ehr/api/get-token-info.ts
(1 hunks)packages/core/src/external/ehr/athenahealth/environment.ts
(1 hunks)packages/core/src/external/ehr/athenahealth/index.ts
(3 hunks)packages/core/src/external/ehr/canvas/command/get-appointments.ts
(1 hunks)packages/core/src/external/ehr/canvas/data.ts
(0 hunks)packages/core/src/external/ehr/canvas/environment.ts
(1 hunks)packages/core/src/external/ehr/canvas/index.ts
(5 hunks)packages/core/src/external/ehr/canvas/shared.ts
(1 hunks)packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts
(1 hunks)packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts
(1 hunks)packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-factory.ts
(1 hunks)packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts
(1 hunks)packages/core/src/external/ehr/command/get-secrets.ts
(1 hunks)packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts
(1 hunks)packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-factory.ts
(1 hunks)packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts
(1 hunks)packages/core/src/external/ehr/eclinicalworks/environment.ts
(1 hunks)packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-cloud.ts
(1 hunks)packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-factory.ts
(1 hunks)packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-local.ts
(1 hunks)packages/core/src/external/ehr/elation/environment.ts
(1 hunks)packages/core/src/external/ehr/elation/index.ts
(3 hunks)packages/core/src/external/ehr/environment.ts
(1 hunks)packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-cloud.ts
(1 hunks)packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-factory.ts
(1 hunks)packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-local.ts
(1 hunks)packages/core/src/external/ehr/healthie/environment.ts
(1 hunks)packages/core/src/external/ehr/healthie/index.ts
(3 hunks)packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-cloud.ts
(1 hunks)packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-r 9E81 esource-diff-bundles-factory.ts
(1 hunks)packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-local.ts
(1 hunks)packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-cloud.ts
(1 hunks)packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-factory.ts
(1 hunks)packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-local.ts
(1 hunks)packages/core/src/external/ehr/shared.ts
(6 hunks)packages/core/src/util/config.ts
(1 hunks)packages/infra/lib/api-stack.ts
(4 hunks)packages/infra/lib/api-stack/api-service.ts
(4 hunks)packages/infra/lib/ehr-nested-stack.ts
(10 hunks)packages/lambdas/src/ehr/compute-resource-diff-bundles.ts
(1 hunks)packages/lambdas/src/ehr/elation/elation-link-patient.ts
(1 hunks)packages/lambdas/src/ehr/get-appointments.ts
(1 hunks)packages/lambdas/src/ehr/healthie/healthie-link-patient.ts
(1 hunks)packages/lambdas/src/ehr/refresh-ehr-bundles.ts
(1 hunks)packages/lambdas/src/ehr/sync-patient.ts
(1 hunks)packages/lambdas/src/shared/ehr.ts
(1 hunks)packages/shared/src/domain/jwt-token.ts
(1 hunks)packages/shared/src/interface/external/ehr/fhir-resource.ts
(1 hunks)
💤 Files with no reviewable changes (2)
- packages/api/src/shared/config.ts
- packages/core/src/external/ehr/canvas/data.ts
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.ts`: - Use the Onion Pattern to organize a package's code in layers - Try to use immutable code and avoid sharing state across different functions, objects, and systems - Try...
**/*.ts
: - Use the Onion Pattern to organize a package's code in layers
- Try to use immutable code and avoid sharing state across different functions, objects, and systems
- Try to build code that's idempotent whenever possible
- Prefer functional programming style functions: small, deterministic, 1 input, 1 output
- Minimize coupling / dependencies
- Avoid modifying objects received as parameter
- Only add comments to code to explain why something was done, not how it works
- Naming
- classes, enums:
PascalCase
- constants, variables, functions:
camelCase
- file names:
kebab-case
- table and column names:
snake_case
- Use meaningful names, so whoever is reading the code understands what it means
- Don’t use negative names, like
notEnabled
, preferisDisabled
- For numeric values, if the type doesn’t convey the unit, add the unit to the name
- Typescript
- Use types
- Prefer
const
instead oflet
- Avoid
any
and casting fromany
to other types- Type predicates: only applicable to narrow down the type, not to force a complete type conversion
- Prefer deconstructing parameters for functions instead of multiple parameters that might be of
the same type- Don’t use
null
inside the app, only on code interacting with external interfaces/services,
like DB and HTTP; convert toundefined
before sending inwards into the code- Use
async/await
instead of.then()
- Use the strict equality operator
===
, don’t use abstract equality operator==
- When calling a Promise-returning function asynchronously (i.e., not awaiting), use
.catch()
to
handle errors (seeprocessAsyncError
andemptyFunction
depending on the case)- Date and Time
- Always use
buildDayjs()
to createdayjs
instances- Prefer
dayjs.duration(...)
to create duration consts and keep them asduration
- Prefer Nullish Coalesce (??) than the OR operator (||) to provide a default value
- Avoid creating arrow functions
- Use truthy syntax instead of
in
- i.e.,if (data.link)
notif ('link' in data)
- Error handling
- Pass the original error as the new one’s
cause
so the stack trace is persisted- Error messages should have a static message - add dynamic data to MetriportError's
additionalInfo
prop- Avoid sending multiple events to Sentry for a single error
- Global constants and variables
- Move literals to constants declared after imports when possible (avoid magic numbers)
- Avoid shared, global objects
- Avoid using
console.log
andconsole.error
in packages other than utils, infra and shared,
and try to useout().log
instead- Avoid multi-line logs
- don't send objects as a second parameter to
console.log()
orout().log()
- don't create multi-line strings when using
JSON.stringify()
- Use
eslint
to enforce code style- Use
prettier
to format code- max column length is 100 chars
- multi-line comments use
/** */
- scripts: top-level comments go after the import
packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-factory.ts
packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-factory.ts
packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-factory.ts
packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-cloud.ts
packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-factory.ts
packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-cloud.ts
packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts
packages/shared/src/domain/jwt-token.ts
packages/api/src/routes/ehr/healthie/patient-webhook.ts
packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-cloud.ts
packages/api/src/routes/ehr/util.ts
packages/api/src/routes/ehr/canvas/patient-webhook.ts
packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-local.ts
packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-factory.ts
packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-local.ts
packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-local.ts
packages/lambdas/src/ehr/elation/elation-link-patient.ts
packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-cloud.ts
packages/api/src/routes/ehr/elation/appointment-webhook.ts
packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts
packages/lambdas/src/ehr/healthie/healthie-link-patient.ts
packages/core/src/external/ehr/healthie/index.ts
packages/api/src/routes/ehr/elation/patient-webhook.ts
packages/api/src/routes/ehr/healthie/appointment-webhook.ts
packages/api/src/external/ehr/shared/utils/appointment.ts
packages/lambdas/src/ehr/sync-patient.ts
packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts
packages/api/src/routes/internal/ehr/index.ts
packages/api/src/routes/internal/jwt-token/index.ts
packages/core/src/external/ehr/canvas/shared.ts
packages/lambdas/src/shared/ehr.ts
packages/api/src/routes/internal/jwt-token/token.ts
packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts
packages/infra/lib/api-stack.ts
packages/core/src/external/ehr/athenahealth/environment.ts
packages/api/src/external/ehr/eclinicalworks/shared.ts
packages/core/src/external/ehr/athenahealth/index.ts
packages/lambdas/src/ehr/compute-resource-diff-bundles.ts
packages/core/src/external/ehr/elation/index.ts
packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts
packages/lambdas/src/ehr/get-appointments.ts
packages/core/src/external/ehr/eclinicalworks/environment.ts
packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts
packages/core/src/external/aws/lambda.ts
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-factory.ts
packages/api/src/routes/internal/ehr/practice.ts
packages/core/src/external/ehr/canvas/command/get-appointments.ts
packages/core/src/external/ehr/canvas/environment.ts
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts
packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-local.ts
packages/core/src/external/ehr/api/get-token-info.ts
packages/shared/src/interface/external/ehr/fhir-resource.ts
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts
packages/lambdas/src/ehr/refresh-ehr-bundles.ts
packages/core/src/external/ehr/elation/environment.ts
packages/infra/lib/api-stack/api-service.ts
packages/core/src/external/ehr/api/get-client-key-and-secret.ts
packages/api/src/external/ehr/elation/shared.ts
packages/api/src/external/ehr/healthie/shared.ts
packages/core/src/external/ehr/healthie/environment.ts
packages/api/src/external/ehr/athenahealth/shared.ts
packages/api/src/external/ehr/canvas/shared.ts
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts
packages/core/src/external/ehr/shared.ts
packages/core/src/external/ehr/environment.ts
packages/core/src/external/ehr/command/get-secrets.ts
packages/infra/lib/ehr-nested-stack.ts
packages/core/src/external/ehr/canvas/index.ts
packages/api/src/external/ehr/shared/utils/client.ts
packages/core/src/util/config.ts
🧠 Learnings (4)
packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts (1)
Learnt from: thomasyopes
PR: metriport/metriport#3427
File: packages/core/src/external/ehr/api/sync-patient.ts:16-55
Timestamp: 2025-03-11T20:42:46.516Z
Learning: In the patient synchronization architecture, the flow follows this pattern: (1) `ehr-sync-patient-cloud.ts` sends messages to an SQS queue, (2) the `ehr-sync-patient` Lambda consumes these messages, and (3) the Lambda uses the `syncPatient` function to make the API calls to process the patient data.
packages/lambdas/src/ehr/sync-patient.ts (1)
Learnt from: thomasyopes
PR: metriport/metriport#3427
File: packages/core/src/external/ehr/api/sync-patient.ts:16-55
Timestamp: 2025-03-11T20:42:46.516Z
Learning: In the patient synchronization architecture, the flow follows this pattern: (1) `ehr-sync-patient-cloud.ts` sends messages to an SQS queue, (2) the `ehr-sync-patient` Lambda consumes these messages, and (3) the Lambda uses the `syncPatient` function to make the API calls to process the patient data.
packages/lambdas/src/ehr/get-appointments.ts (1)
Learnt from: thomasyopes
PR: metriport/metriport#3873
File: packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts:40-43
Timestamp: 2025-05-29T16:53:26.064Z
Learning: The EHR get-appointments Lambda function is designed to always return parseable JSON responses, so additional error handling for JSON.parse() is not required when processing its results.
packages/core/src/external/ehr/healthie/environment.ts (1)
Learnt from: thomasyopes
PR: metriport/metriport#3771
File: packages/api/src/routes/internal/ehr/healthie/secret-key.ts:24-31
Timestamp: 2025-05-01T16:11:28.575Z
Learning: The function `getHealthieSecretKeyInfo` in the Healthie EHR integration throws appropriate MetriportErrors when required data is missing, so it will never return undefined or an empty object.
🧬 Code Graph Analysis (18)
packages/api/src/routes/ehr/util.ts (1)
packages/shared/src/index.ts (1)
BadRequestError
(40-40)
packages/core/src/external/ehr/healthie/index.ts (2)
packages/shared/src/index.ts (1)
sleep
(13-13)packages/core/src/external/ehr/shared.ts (1)
paginateWaitTime
(35-35)
packages/api/src/external/ehr/shared/utils/appointment.ts (1)
packages/shared/src/common/date.ts (1)
buildDayjs
(70-72)
packages/api/src/routes/internal/ehr/index.ts (1)
packages/api/src/routes/internal/ehr/middleware.ts (1)
processEhrId
(6-11)
packages/core/src/external/ehr/athenahealth/environment.ts (3)
packages/core/src/external/ehr/environment.ts (1)
EhrEnvAndClientCredentials
(9-13)packages/core/src/external/ehr/athenahealth/index.ts (2)
AthenaEnv
(95-95)isAthenaEnv
(96-98)packages/core/src/util/config.ts (1)
Config
(9-254)
packages/core/src/external/ehr/athenahealth/index.ts (2)
packages/shared/src/index.ts (1)
sleep
(13-13)packages/core/src/external/ehr/shared.ts (1)
paginateWaitTime
(35-35)
packages/core/src/external/ehr/elation/index.ts (2)
packages/shared/src/index.ts (1)
sleep
(13-13)packages/core/src/external/ehr/shared.ts (1)
paginateWaitTime
(35-35)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-factory.ts (3)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts (1)
EhrGetAppointmentsHandler
(15-17)packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (1)
EhrGetAppointmentsDirect
(11-19)packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts (1)
EhrGetAppointmentsCloud
(11-43)
packages/core/src/external/ehr/api/get-token-info.ts (4)
packages/shared/src/domain/jwt-token.ts (1)
JwtTokenInfo
(1-5)packages/core/src/util/config.ts (1)
Config
(9-254)packages/shared/src/net/retry.ts (1)
executeWithNetworkRetries
(108-135)packages/core/src/external/ehr/api/api-shared.ts (1)
validateAndLogResponse
(13-20)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (2)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts (4)
EhrGetAppointmentsHandler
(15-17)Appointment
(19-19)GetAppointmentsRequest
(3-11)GetAppointmentsClientRequest
(13-13)packages/shared/src/index.ts (1)
BadRequestError
(40-40)
packages/core/src/external/ehr/elation/environment.ts (4)
packages/core/src/util/config.ts (2)
getElationEnv
(233-235)Config
(9-254)packages/core/src/external/ehr/environment.ts (2)
EhrPerPracticeParams
(26-26)EhrEnvAndClientCredentials
(9-13)packages/core/src/external/ehr/elation/index.ts (2)
ElationEnv
(56-56)isElationEnv
(57-59)packages/shared/src/domain/secrets.ts (1)
cxClientKeyAndSecretMapSecretSchema
(3-3)
packages/api/src/external/ehr/elation/shared.ts (2)
packages/core/src/external/ehr/environment.ts (1)
EhrPerPracticeParams
(26-26)packages/core/src/external/ehr/elation/index.ts (1)
ElationEnv
(56-56)
packages/api/src/external/ehr/healthie/shared.ts (4)
packages/core/src/external/ehr/environment.ts (1)
EhrPerPracticeParams
(26-26)packages/core/src/external/ehr/healthie/index.ts (1)
HealthieEnv
(46-46)packages/core/src/external/ehr/healthie/environment.ts (1)
getHealthieEnv
(6-23)packages/core/src/util/config.ts (1)
getHealthieEnv
(244-246)
packages/api/src/external/ehr/athenahealth/shared.ts (4)
packages/core/src/external/ehr/environment.ts (1)
EhrPerPracticeParams
(26-26)packages/core/src/external/ehr/athenahealth/index.ts (1)
AthenaEnv
(95-95)packages/api/src/external/ehr/shared/utils/client.ts (1)
createEhrClient
(38-72)packages/core/src/external/ehr/athenahealth/environment.ts (1)
getAthenaEnv
(6-20)
packages/core/src/external/ehr/environment.ts (6)
packages/core/src/external/ehr/athenahealth/index.ts (1)
AthenaEnv
(95-95)packages/core/src/external/ehr/elation/index.ts (1)
ElationEnv
(56-56)packages/core/src/external/ehr/canvas/index.ts (1)
CanvasEnv
(82-82)packages/core/src/external/ehr/healthie/index.ts (1)
HealthieEnv
(46-46)packages/core/src/external/ehr/eclinicalworks/index.ts (1)
EClinicalWorksEnv
(15-15)packages/shared/src/domain/jwt-token.ts (1)
JwtTokenInfo
(1-5)
packages/core/src/external/ehr/command/get-secrets.ts (5)
packages/core/src/external/ehr/environment.ts (4)
EhrPerPracticeParams
(26-26)EhrEnvAndClientCredentials
(9-13)EhrEnv
(8-8)EhrEnvAndApiKey
(15-18)packages/shared/src/interface/external/ehr/source.ts (1)
EhrSource
(9-9)packages/core/src/external/ehr/canvas/environment.ts (1)
getCanvasEnv
(6-28)packages/core/src/external/ehr/athenahealth/environment.ts (1)
getAthenaEnv
(6-20)packages/shared/src/index.ts (1)
BadRequestError
(40-40)
packages/core/src/external/ehr/canvas/index.ts (2)
packages/shared/src/index.ts (1)
sleep
(13-13)packages/core/src/external/ehr/shared.ts (1)
paginateWaitTime
(35-35)
packages/api/src/external/ehr/shared/utils/client.ts (2)
packages/core/src/external/ehr/environment.ts (1)
EhrClientTwoLeggedAuthParams
(21-24)packages/api/src/command/jwt-token.ts (1)
findOrCreateJwtToken
(11-21)
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: check-pr / lint-build-test
- GitHub Check: check-pr / lint-build-test
- GitHub Check: check-pr / lint-build-test
- GitHub Check: check-pr / lint-build-test
- GitHub Check: check-pr / lint-build-test
- GitHub Check: Analyze (javascript)
- GitHub Check: secrets_cdk_stack / deploy
- GitHub Check: ihe_stack / deploy
- GitHub Check: infra-api-lambdas / deploy
- GitHub Check: mllp-server / deploy
- GitHub Check: api / deploy
🔇 Additional comments (121)
packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-factory.ts (1)
1-1
: Import path updated correctly
The relative path forConfig
has been adjusted to reflect the directory restructure. All usages remain consistent with coding conventions.packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-cloud.ts (1)
3-4
: Relative imports for Config and SQSClient corrected
The import paths forConfig
andSQSClient
now point to their new locations. The change aligns with the reorganized folder structure and requires no further adjustments.packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-factory.ts (1)
1-1
: Config import path aligned with new structure
Updated the relative path forConfig
to match the directory move, maintaining consistency across EHR integrations.packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-factory.ts (1)
1-1
: Adjusted Config import relative path
The import path forConfig
has been shortened by one directory level to reflect the module reorganization.packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-factory.ts (1)
1-1
: Config import path simplification approved
Removed an extra directory in the import path forConfig
, consistent with other modules in this PR.packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-local.ts (1)
3-3
: Import path updated to reflect new module structure
The relative path now correctly targets theapi/link-patient
under the reorganizedcommand
directory.packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts (1)
3-4
: Deepened relative imports align with directory refactor
The updated paths forSQSClient
andConfig
correctly follow the newcommand
subdirectory hierarchy and maintain consistency with other EHR modules.packages/api/src/routes/ehr/healthie/appointment-webhook.ts (1)
1-1
: Adjusted import to new command factory location
The path forbuildEhrSyncPatientHandler
now matches the reorganizedcommand/sync-patient
layout.packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-cloud.ts (1)
3-4
: Import paths updated to new command hierarchy
The deeper relative imports forSQSClient
andConfig
correctly mirror the refactored directory structure undercommand/link-patient
.packages/api/src/routes/ehr/canvas/patient-webhook.ts (1)
1-1
: Updated sync-patient factory import path
The import forbuildEhrSyncPatientHandler
now targets thecommand/sync-patient
namespace, keeping it consistent with other EHR integrations.packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-cloud.ts (1)
3-4
: Imports updated correctly after directory restructure
The revised relative paths forSQSClient
andConfig
align with the new directory layout and maintain consistency with other EHR command modules.packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-factory.ts (1)
1-1
: Corrected theConfig
import path
The update to"../../../../util/config"
properly reflects the moved directory depth without affecting functionality.packages/api/src/routes/ehr/util.ts (1)
15-17
: Added braces for the multi-lineif
block
Wrapping thethrow
in braces improves readability and avoids potential errors when extending the block.packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-cloud.ts (1)
3-4
: Adjusted import paths forConfig
andSQSClient
The shortened import paths correctly match the reorganized module structure without altering logic.packages/api/src/routes/ehr/healthie/patient-webhook.ts (1)
1-1
: Updated import to new sync-patient factory location
Importing from"@metriport/core/external/ehr/command/sync-patient/ehr-sync-patient-factory"
aligns with the relocated module and retains all existing functionality.packages/api/src/routes/ehr/elation/appointment-webhook.ts (1)
1-1
: Align import path with command directory restructure.The
buildEhrSyncPatientHandler
import has been correctly updated to the newcommand/sync-patient
location, matching the broader EHR module reorganization.packages/api/src/routes/ehr/elation/patient-webhook.ts (1)
1-1
: Align import path with command directory restructure.The
buildEhrSyncPatientHandler
import is now pointing tocommand/sync-patient
, consistent with other EHR sync-patient handlers.packages/shared/src/domain/jwt-token.ts (1)
4-4
: Extend JwtTokenInfo with optionalid
.Adding the optional
id
property aligns with downstream enhancements in token retrieval and management routes.packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-local.ts (1)
3-3
: Correct relative import forlinkPatient
.Adjusted the path to
../../../api/link-patient
to reflect the new directory structure undercommand
.packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts (1)
2-2
: Update import for sync-patient handler.The import of
buildEhrSyncPatientHandler
now correctly references thecommand/sync-patient
factory, aligning with the refactor across EHR integrations.packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts (1)
2-2
:✅ Verification successful
Verify the updated import path exists.
The import path has been updated to remove the
bundle/
directory segment. Ensure the module exists at the new location and the restructuring is complete.
🏁 Script executed:
#!/bin/bash # Description: Verify the new import path exists and the old path no longer exists. # Check if the new path exists fd -t f "ehr-refresh-ehr-bundles-factory.ts" packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ # Check if old path still exists (should not) fd -t f "ehr-refresh-ehr-bundles-factory.ts" packages/core/src/external/ehr/bundle/job/create-resource-diff-bundles/steps/refresh/Length of output: 540
Import path validation successful
The file
ehr-refresh-ehr-bundles-factory.ts
exists at the new location and the old path has been removed. No further action is required.• packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts: import path is correct and up to date.
packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts (1)
2-2
:✅ Verification successful
Verify the updated relative import path is correct.
The relative import path has been updated from
../api/sync-patient
to../../api/sync-patient
, suggesting a directory restructuring. Ensure the target module exists at the expected location relative to this file.
🏁 Script executed:
#!/bin/bash # Description: Verify the relative import path resolves correctly. # Check the current file location and verify the target exists current_file="packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts" target_relative_to_current="../../api/sync-patient" # Calculate absolute path and check if target exists fd -t f "sync-patient.ts" packages/core/src/external/ehr/api/Length of output: 257
Import path verified
The filepackages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts
correctly imports from../../api/sync-patient
. The target modulepackages/core/src/external/ehr/api/sync-patient.ts
exists and resolves as expected. No further action required.packages/api/src/routes/internal/ehr/index.ts (2)
17-17
: LGTM! Route follows established patterns.The new practice route correctly uses the
processEhrId
middleware and follows the same pattern as the existing patient route. The route structure is consistent and properly configured.
8-8
:✅ Verification successful
Verify the practice module exists.
The new import follows the established pattern. Ensure the practice module is implemented.
🏁 Script executed:
#!/bin/bash # Description: Verify the practice module exists at the expected location. fd -t f "practice.ts" packages/api/src/routes/internal/ehr/Length of output: 108
Practice module import verified
The
practice.ts
file exists atpackages/api/src/routes/internal/ehr/practice.ts
and follows the established middleware and routing patterns. No further changes needed—this addition can be approved.packages/api/src/routes/internal/jwt-token/index.ts (2)
18-20
: LGTM! Proper route ordering with clear documentation.The placement of the token route at the end with the "MUST GO LAST" comment is correct for Express routing. This ensures the shared route doesn't interfere with the EHR-specific routes above it. The root path mounting is appropriate for catch-all or fallback behavior.
7-7
:✅ Verification successful
Verify the token module exists.
The new import follows the established pattern. Ensure the token module is implemented.
🏁 Script executed:
#!/bin/bash # Description: Verify the token module exists at the expected location. fd -t f "token.ts" packages/api/src/routes/internal/jwt-token/Length of output: 114
token.ts module verified
The
token.ts
file exists atpackages/api/src/routes/internal/jwt-token/token.ts
, so the import is valid. The fallback route with"MUST GO LAST"
should indeed be registered after the EHR-specific routes to avoid unintended catches.No further action required.
packages/lambdas/src/ehr/elation/elation-link-patient.ts (2)
1-2
: Approve command module import paths
TheProcessLinkPatientRequest
andElationLinkPatientLocal
imports now correctly reference the newcommand/link-patient
directory structure.
6-10
: Approve shared utility import adjustments
All shared utilities (capture
,parseLinkPatient
,getEnvOrFail
,prefixedLog
,getSingleMessageOrFail
) are now imported from the updated../../shared
path.packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-local.ts (1)
3-6
: Approve import path realignment for refresh step
The relative imports forrefreshEhrBundle
, job entry status,BundleType
, andcreateOrReplaceBundleOnS3
have been updated to reflect the new flattenedjob/create-resource-diff-bundles/steps/refresh
layout.packages/lambdas/src/ehr/healthie/healthie-link-patient.ts (2)
1-2
: Approve command module import paths
ProcessLinkPatientRequest
andHealthieLinkPatientLocal
now correctly point to the reorganizedcommand/link-patient
directory.
6-10
: Approve shared utility import adjustments
Shared helpers (capture
,parseLinkPatient
,getEnvOrFail
,prefixedLog
,getSingleMessageOrFail
) are now imported from the updated../../shared
path, matching the project structure.packages/lambdas/src/ehr/sync-patient.ts (2)
1-2
: Approve command module import paths
Updated imports forProcessSyncPatientRequest
andEhrSyncPatientLocal
to the newcommand/sync-patient
directory.
6-10
: Approve shared utility import adjustments
Relative imports forcapture
,parseSyncPatient
,getEnvOrFail
,prefixedLog
, andgetSingleMessageOrFail
now correctly use the../shared
path.packages/core/src/external/aws/lambda.ts (2)
7-7
: Approve explicitLambdaClient
type alias
Introducingexport type LambdaClient = AWS.Lambda
clarifies the client type across the codebase.
13-13
: Approve explicit return type formakeLambdaClient
Specifying: LambdaClient
onmakeLambdaClient
ensures consistent, self-documented typing for AWS Lambda client creation.packages/core/src/external/ehr/elation/index.ts (1)
8-8
: LGTM! Excellent addition of API rate limiting.The implementation of pagination throttling with a 1-second delay is a best practice that prevents overwhelming the Elation API and reduces the risk of rate limiting errors. The use of a centrally defined
paginateWaitTime
constant maintains consistency across all EHR integrations.Also applies to: 43-43, 266-266
packages/lambdas/src/ehr/refresh-ehr-bundles.ts (1)
1-2
: LGTM! Clean import path reorganization.The import path updates correctly reflect the restructuring of core external EHR modules and shared utilities. This maintains consistency with the broader codebase reorganization mentioned in the PR objectives.
Also applies to: 6-10
packages/core/src/external/ehr/athenahealth/index.ts (1)
15-15
: LGTM! Consistent rate limiting implementation.The addition of pagination throttling aligns perfectly with the same enhancement made across other EHR integrations (Elation, Canvas, Healthie). Using the shared
paginateWaitTime
constant ensures uniform behavior and maintains the 1-second delay standard.Also applies to: 78-78, 893-893
packages/core/src/external/ehr/healthie/index.ts (1)
1-1
: LGTM! Completes the consistent rate limiting pattern.This finalizes the uniform implementation of pagination throttling across all EHR integrations. The 1-second delay before each paginated request in the
paginateAppointments
function will help prevent API rate limiting issues while maintaining consistency with the AthenaHealth, Canvas, and Elation implementations.Also applies to: 27-33, 273-273
packages/lambdas/src/ehr/compute-resource-diff-bundles.ts (1)
1-10
: LGTM! Import path updates align with directory restructuring.The import path changes correctly reflect the directory restructuring mentioned in the AI summary, moving from
@metriport/core/external/ehr/bundle/job/
to@metriport/core/external/ehr/job/
and adjusting relative paths from./shared/
to../shared/
.packages/api/src/external/ehr/shared/utils/appointment.ts (1)
57-57
: LGTM! Logic fix ensures consistent time range calculation.The change correctly applies the
offset
to theendRange
calculation, ensuring bothstartRange
andendRange
are consistently offset from the current datetime. This fixes the previous inconsistency where onlystartRange
was offset.packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-local.ts (1)
4-11
: LGTM! Import path updates reflect directory restructuring.The relative import paths have been correctly updated to use fewer directory levels, maintaining the same imported entities while aligning with the broader directory reorganization.
packages/api/src/routes/internal/jwt-token/token.ts (1)
1-28
: LGTM! Well-structured internal JWT token retrieval endpoint.The implementation follows Express and TypeScript best practices:
- Proper use of middleware (
requestLogger
,asyncHandler
)- Correct parameter validation with
getFrom("params").orFail()
- Appropriate error handling delegation
- Good JSDoc documentation
- Follows coding guidelines for naming conventions
Since this is an internal endpoint (as indicated by the
/internal/
prefix), the direct token exposure is acceptable for internal service-to-service communication.packages/lambdas/src/shared/ehr.ts (1)
1-3
: LGTM! Import path reorganization improves code structure.The import path updates to include the "command" directory segment align with the broader reorganization across EHR integrations. This change enhances modularity and follows good organizational practices.
packages/infra/lib/api-stack.ts (4)
463-463
: Correctly destructures the new appointments Lambda.The getAppointmentsLambda is properly extracted from the EhrNestedStack to be used in the API service integration.
479-479
: Proper resource dependency injection.Passing ehrResponsesBucket to the EhrNestedStack constructor enables the new Lambda to access the required S3 bucket.
592-592
: Well-integrated Lambda into API service.The ehrGetAppointmentsLambda is correctly passed to createAPIService, enabling the API to invoke this Lambda for appointment operations.
691-691
: Correctly includes Lambda in environment setup.Adding ehrGetAppointmentsLambda to the lambdasToGetApiUrl array ensures it receives the API_URL environment variable for proper communication.
packages/core/src/external/ehr/eclinicalworks/environment.ts (1)
1-16
: Excellent implementation of centralized environment configuration.This function properly:
- Validates environment configuration with type guards
- Uses static error messages with dynamic data in
additionalInfo
(following coding guidelines)- Follows functional programming style: small, deterministic, single purpose
- Centralizes environment logic for better maintainability
- Uses consistent error handling with
MetriportError
The implementation aligns well with the coding guidelines and the broader refactoring to centralize environment management across EHR integrations.
packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts (1)
1-2
: LGTM! Import path updates support better code organization.The updated import paths for
buildEhrSyncPatientHandler
andbuildElationLinkPatientHandler
reflect the new command directory structure, enhancing modularity and consistency across EHR integrations.packages/core/src/external/ehr/athenahealth/environment.ts (1)
6-20
: LGTM! Well-structured environment validation function.The implementation follows coding guidelines well with proper error handling, static error messages, and type safety. The use of early returns with guard clauses makes the code readable and maintainable.
packages/core/src/external/ehr/canvas/shared.ts (1)
7-30
: LGTM! Clean implementation of centralized client creation.The function properly uses the centralized secret retrieval pattern and handles optional token information correctly. The async/await usage and parameter destructuring follow the coding guidelines well.
packages/api/src/external/ehr/eclinicalworks/shared.ts (1)
1-3
: LGTM! Consistent refactoring to centralized environment management.The updated imports and usage of the centralized
getEClinicalWorksEnv
function aligns well with the broader refactoring pattern across EHR integrations. This improves modularity and consistency.Also applies to: 12-12
packages/api/src/routes/internal/ehr/practice.ts (3)
1-12
: LGTM: Clean imports and proper dependencies.The imports are well-organized and include all necessary dependencies for the router implementation. Good use of proper TypeScript types and utilities.
26-44
: LGTM: Solid parameter validation and error handling.The endpoint implementation follows good practices:
- Proper parameter extraction and validation using utility functions
- Type-safe EHR source validation with meaningful error messages
- UUID validation for cxId
- Appropriate error context in BadRequestError
- Clean response structure
The logic flow is clear and handles edge cases appropriately.
37-41
:❌ Incorrect review comment
Verify that
getSecrets
function is awaited properly.The
getSecrets
function call appears to be missingawait
keyword. If this function returns a Promise, it should be awaited to ensure proper error handling and response timing.
🏁 Script executed:
#!/bin/bash # Check if getSecrets function returns a Promise that should be awaited ast-grep --pattern $'export function getSecrets($_) { $$$ }'Length of output: 63
🏁 Script executed:
#!/bin/bash # Show how getSecrets is imported in practice.ts rg -n "getSecrets" -n packages/api/src/routes/internal/ehr/practice.ts # Locate the definition/declaration of getSecrets anywhere in the repo rg -n "getSecrets" -nLength of output: 2735
🏁 Script executed:
#!/bin/bash # Display the import section of practice.ts to identify getSecrets source sed -n '1,50p' packages/api/src/routes/internal/ehr/practice.tsLength of output: 1612
🏁 Script executed:
#!/bin/bash # Show the implementation of getSecrets in the core package sed -n '1,200p' packages/core/src/external/ehr/command/get-secrets.tsLength of output: 2178
🏁 Script executed:
#!/bin/bash # Check if environment getters return Promises (async) or synchronous values # Search for getCanvasEnv definition rg -n "export .*function getCanvasEnv" -n packages/core/src/external/ehr/canvas/environment.ts # Search for getAthenaEnv definition rg -n "export .*function getAthenaEnv" -n packages/core/src/external/ehr/athena/environment.ts # Search for getElationEnv definition rg -n "export .*function getElationEnv" -n packages/core/src/external/ehr/elation/environment.ts # Search for getHealthieEnv definition rg -n "export .*function getHealthieEnv" -n packages/core/src/external/ehr/healthie/environment.tsLength of output: 588
🏁 Script executed:
#!/bin/bash # Inspect environment provider implementations for async/sync signatures echo "----- Canvas Environment -----" sed -n '1,200p' packages/core/src/external/ehr/canvas/environment.ts echo "----- Athenahealth Environment -----" sed -n '1,200p' packages/core/src/external/ehr/athenahealth/environment.ts echo "----- Elation Environment -----" sed -n '1,200p' packages/core/src/external/ehr/elation/environment.ts echo "----- Healthie Environment -----" sed -n '1,200p' packages/core/src/external/ehr/healthie/environment.ts # Check for any 'async' keyword usage in environment files echo "----- Async Keywords in Canvas -----" grep -R "async " -n packages/core/src/external/ehr/canvas/environment.ts || true echo "----- Async Keywords in Athenahealth -----" grep -R "async " -n packages/core/src/external/ehr/athenahealth/environment.ts || true echo "----- Async Keywords in Elation -----" grep -R "async " -n packages/core/src/external/ehr/elation/environment.ts || true echo "----- Async Keywords in Healthie -----" grep -R "async " -n packages/core/src/external/ehr/healthie/environment.ts || trueLength of output: 5929
getSecrets is synchronous – no
await
needed
ThegetSecrets
imported from@metriport/core/external/ehr/command/get-secrets
returns its result directly (via synchronous handlers likegetCanvasEnv
,getAthenaEnv
, etc.), not a Promise. Calling it withoutawait
is correct—no changes required.Likely an incorrect or invalid review comment.
packages/core/src/external/ehr/canvas/environment.ts (3)
6-9
: LGTM: Clean function signature with proper typing.The function uses proper destructuring of parameters and returns a well-typed result. Good use of generic types for environment credentials.
10-13
: LGTM: Proper configuration retrieval and validation.Good use of early return with meaningful error messages and proper JSON parsing with schema validation using zod.
20-22
: LGTM: Appropriate error handling for missing credentials.The validation ensures all required credentials are present before proceeding, with a clear error message when any are missing.
packages/infra/lib/api-stack/api-service.ts (3)
116-116
: LGTM: Proper parameter addition to function signature.The
ehrGetAppointmentsLambda
parameter is correctly added to both the function signature and the destructured parameters list, following the established pattern for other Lambda integrations.Also applies to: 161-161
299-299
: LGTM: Correct environment variable configuration.The environment variable
EHR_GET_APPOINTMENTS_LAMBDA_NAME
is properly set using the Lambda's function name, following the naming convention used by other Lambda integrations in the same file.
451-451
: LGTM: Proper IAM permission granting.The
grantInvoke
call correctly grants the Fargate service permission to invoke the EHR appointments Lambda, consistent with how other Lambda permissions are handled in this file.packages/core/src/external/ehr/api/get-token-info.ts (5)
12-16
: LGTM: Clear function documentation.The JSDoc comment clearly describes the function's purpose and parameters. Good documentation practice.
17-20
: LGTM: Proper setup with logging and API configuration.Good use of structured logging with context and proper axios configuration using centralized config. The URL construction is clear and follows REST conventions.
22-24
: LGTM: Proper use of retry mechanism.The implementation correctly wraps the axios call in
executeWithNetworkRetries
to handle transient network failures, which is essential for external API calls.
26-29
: LGTM: Proper response transformation.The response data is correctly transformed to match the
JwtTokenInfo
type, with proper date parsing for the expiration field. Good type safety practices.
30-38
: LGTM: Comprehensive error handling.Excellent error handling with:
- Proper logging with context
- Meaningful error messages
- Error cause preservation
- Rich additional context for debugging
- Proper error transformation to MetriportError
Follows the coding guidelines for error handling perfectly.
packages/core/src/external/ehr/canvas/command/get-appointments.ts (2)
11-20
: Excellent input validation with comprehensive error context.The validation logic properly checks for required
fromDate
andtoDate
parameters and provides detailed context in the error. The use of optional chaining for date serialization in the error context is well-handled.
21-28
: Clean and functional implementation following best practices.The function follows the coding guidelines well:
- Uses
async/await
instead of.then()
- Implements functional programming style (small, deterministic, single purpose)
- Properly handles optional
tokenId
parameter with conditional spreading- Returns the result directly without unnecessary variable assignments
packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts (2)
1-1
: Import path reorganization looks good.The updated import paths to include the
command
subdirectory improve code organization and align with the modular structure being implemented across EHR integrations.Also applies to: 3-3
36-36
:❌ Incorrect review comment
Verify the behavioral change in appointment lookup window.
The changes modify the 48hr appointment lookup behavior:
- Previously: 2-day look-forward with 1-day offset
- Now: 1-day look-forward with 1-day offset
This reduces the appointment retrieval window from 2 days to 1 day. Please confirm this change is intentional and aligns with business requirements.
Also applies to: 222-223
🏁 Script executed:
#!/bin/bash # Description: Check if similar changes were made to other EHR appointment lookup logic # Expected: Find other files with similar 48hr appointment lookup patterns # Search for similar appointment lookup patterns in other EHR integrations rg -A 5 -B 5 "Appointments48hr|appointmentsLookForward.*48" --type ts # Search for usage of getLookForwardTimeRangeWithOffset to see the pattern rg -A 3 -B 2 "getLookForwardTimeRangeWithOffset" --type tsLength of output: 8819
🏁 Script executed:
#!/bin/bash # Locate the definition and usage of appointmentsLookForward and oneDayOffset rg -n "appointmentsLookForward" -A 3 -B 3 --type ts rg -n "oneDayOffset" -A 3 -B 3 --type ts # Inspect getLookForwardTimeRangeWithOffset implementation sed -n '1,200p' packages/api/src/external/ehr/shared/utils/appointment.ts | sed -n '1,200!d'Length of output: 9669
🏁 Script executed:
#!/bin/bash # Show the implementation of getLookForwardTimeRangeWithOffset to confirm how lookForward and offset are applied rg -n "export function getLookForwardTimeRangeWithOffset" -A 30 --type ts packages/api/src/external/ehr/shared/utils/appointment.tsLength of output: 707
No change to appointment lookup window—logic remains intentional
The Healthie command still uses a 1-day look-forward with a 1-day offset to fetch two 24 hr segments (0–24 hr forAppointments
, 24–48 hr forAppointments48hr
). This matches the implementation in all other EHR integrations and aligns with the original design. You can ignore the suggestion of a reduced window.Likely an incorrect or invalid review comment.
packages/core/src/external/ehr/api/get-client-key-and-secret.ts (1)
18-45
: Excellent implementation following all coding guidelines.The function demonstrates several best practices:
- Generic design with Zod schema validation for type safety
- Proper error handling with static messages and detailed context
- Network retries for resilience (
executeWithNetworkRetries
)- Appropriate logging and response validation
- Uses
async/await
consistently- Error context includes all relevant information for debugging
The implementation is clean, reusable, and follows the coding guidelines perfectly.
packages/lambdas/src/ehr/get-appointments.ts (1)
18-34
: Well-structured Lambda handler following best practices.The handler implementation demonstrates good practices:
- Proper capture initialization and wrapping
- Performance measurement with timing logs
- Appropriate error context setting
- Clean separation of concerns with direct handler usage
packages/core/src/external/ehr/canvas/index.ts (4)
14-20
: LGTM! Proper imports for pagination throttling.The imports correctly add the necessary utilities (
sleep
andpaginateWaitTime
) to implement rate limiting for paginated API requests.Also applies to: 67-67
777-777
: Excellent addition of rate limiting for FHIR resource pagination.The sleep delay prevents overwhelming the Canvas API with rapid successive requests, improving reliability and preventing potential rate limiting issues.
866-869
: Good fix for appointment query parameter construction.Using
urlParams.append()
explicitly ensures both date filters (fromDate
andtoDate
) are properly included as separate query parameters, which is more reliable than conditional object inclusion.
883-883
: Consistent rate limiting applied to appointment pagination.The sleep delay maintains consistency with FHIR resource pagination throttling, ensuring uniform rate limiting across all Canvas API paginated endpoints.
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts (3)
1-3
: LGTM! Updated imports for centralized appointment handling.The import changes properly reflect the refactor to use standardized EHR operation handlers, improving modularity and consistency across EHR integrations.
Also applies to: 8-8, 22-22
99-102
: Good update to use enhanced client creation function.The new client creation function properly returns the
tokenId
metadata required by the centralized appointment handler, supporting the architectural improvements.
108-116
: Excellent refactor to use centralized appointment handler.The handler-based approach improves consistency across EHR integrations and allows for flexible implementation routing (direct vs Lambda-based) while maintaining the same functionality and interface.
packages/core/src/external/ehr/elation/environment.ts (2)
6-26
: Well-implemented environment and credential retrieval.The function properly validates the environment configuration, constructs appropriate lookup keys, and includes comprehensive error handling for missing or invalid data. The pattern is consistent with other EHR integrations.
28-34
: Proper implementation of client map retrieval and validation.The function correctly uses Zod's
safeParse
for JSON validation and includes appropriate error handling for missing or malformed configuration data.packages/shared/src/interface/external/ehr/fhir-resource.ts (1)
47-59
: Well-structured FHIR OperationOutcome schemas.The schemas correctly model FHIR OperationOutcome resources according to the specification, with proper nested structures for issue details and appropriate typing. These will enhance error detection and handling in EHR operations.
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts (2)
11-20
: LGTM! Well-implemented dependency injection pattern.The constructor properly implements dependency injection with sensible defaults, following the coding guidelines for avoiding
null
and using proper fallback logic.
22-42
: 🛠️ Refactor suggestionConsider adding error handling for JSON parsing.
The implementation correctly uses
executeWithNetworkRetries
for resilience and follows async/await patterns. However,JSON.parse(resultPayload)
on line 40 could throw an error if the Lambda returns malformed JSON.Consider wrapping the JSON parsing in a try-catch block:
- return JSON.parse(resultPayload); + try { + return JSON.parse(resultPayload); + } catch (error) { + throw new MetriportError("Failed to parse Lambda response", error, { + lambdaName: this.ehrGetAppointmentsLambdaName, + resultPayload, + }); + }⛔ Skipped due to learnings
Learnt from: thomasyopes PR: metriport/metriport#3608 File: packages/lambdas/src/ehr-compute-resource-diff-bundles.ts:58-62 Timestamp: 2025-04-23T19:00:49.707Z Learning: For Lambda functions in the metriport codebase, the team prefers to let the default Lambda error handling catch JSON parsing errors rather than adding explicit try/catch blocks.
Learnt from: thomasyopes PR: metriport/metriport#3873 File: packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts:40-43 Timestamp: 2025-05-29T16:53:26.064Z Learning: The EHR get-appointments Lambda function is designed to always return parseable JSON responses, so additional error handling for JSON.parse() is not required when processing its results.
packages/core/src/external/ehr/healthie/environment.ts (2)
6-23
: LGTM! Excellent environment validation and error handling.The function properly validates the environment setting and implements comprehensive error handling with detailed context. The API key lookup pattern using the composite key format is well-implemented.
25-31
: LGTM! Proper schema validation and error handling.The function correctly uses schema validation to ensure data integrity and provides clear error messages when validation fails. This follows the coding guidelines for type safety and proper error handling.
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (1)
25-35
: LGTM! Excellent extensible mapping pattern.The mapping approach provides a clean, extensible way to add new appointment methods while maintaining type safety at the mapping level. The error handling is appropriate and provides useful context.
packages/api/src/external/ehr/elation/shared.ts (2)
3-5
: LGTM! Proper centralization of environment logic.The import changes correctly utilize the new centralized environment modules, improving modularity and consistency across EHR integrations.
98-114
: LGTM! Excellent refactoring with improved flexibility.The split into two functions provides both the enriched version with metadata (
createElationClientWithTokenIdAndEnvironment
) and a simplified wrapper (createElationClient
) for backwards compatibility. This follows the coding guidelines for modularity and maintains a clean API surface.packages/api/src/external/ehr/healthie/shared.ts (3)
3-5
: Approve the centralized environment imports.The import refactoring properly centralizes environment and credential retrieval logic, following the established pattern across other EHR integrations. This improves maintainability and reduces code duplication.
80-90
: LGTM! Function follows the established pattern.The
createHealthieClientWithEnvironment
function correctly:
- Uses proper TypeScript typing with explicit return type
- Follows the async/await pattern from coding guidelines
- Returns both client and environment metadata for enhanced functionality
- Maintains consistency with similar functions in other EHR integrations
92-97
: Approve the simplified client creation wrapper.The simplified
createHealthieClient
function provides a clean API for cases where only the client instance is needed, while internally leveraging the enhanced function. This maintains backward compatibility and follows the DRY principle.packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts (2)
3-11
: Well-structured request type with proper optional fields.The
GetAppointmentsRequest
type is well-designed with:
- Clear, meaningful property names following camelCase convention
- Appropriate use of optional properties for flexible querying
- Proper typing with Date objects for temporal fields
13-13
: Good use of utility type for client request.Using
Omit
to deriveGetAppointmentsClientRequest
fromGetAppointmentsRequest
follows the DRY principle and maintains type consistency.packages/api/src/external/ehr/canvas/shared.ts (3)
1-5
: Approve the import consolidation.The imports properly leverage the centralized environment module and shared utilities, reducing code duplication and improving maintainability across EHR integrations.
7-16
: Excellent use of generic utility function.The function correctly leverages the generic
createEhrClient
utility with proper type parameters. The implementation follows the coding guidelines by:
- Using proper TypeScript generics
- Following async/await pattern
- Providing explicit return type annotations
18-23
: Good API design with simplified wrapper.The simplified wrapper maintains a clean API while internally using the enhanced function. This follows the principle of providing both detailed and simplified interfaces based on use case requirements.
packages/api/src/external/ehr/athenahealth/shared.ts (3)
1-5
: Consistent import pattern across EHR integrations.The imports follow the same centralized pattern as other EHR integrations (Canvas, Healthie), promoting consistency and maintainability across the codebase.
7-16
: Proper implementation of the established pattern.The
createAthenaClientWithTokenIdAndEnvironment
function correctly:
- Uses the generic
createEhrClient
utility with appropriate type parameters- Passes
undefined
for params since AthenaHealth doesn't need per-practice parameters for environment retrieval- Maintains type safety with explicit generic type arguments
18-24
: Clean wrapper function maintains API simplicity.The simplified
createAthenaClient
function provides a clean interface while leveraging the enhanced implementation internally. The pattern is consistent across all EHR integrations in this PR.packages/core/src/external/ehr/command/get-secrets.ts (3)
21-30
: LGTM! Well-structured secret retrieval abstraction.The main function provides a clean interface for dynamically retrieving secrets based on EHR type. The delegation pattern is well-implemented with proper type safety.
39-48
: Good type guard implementation for supported EHR sources.The explicit exclusion of
eclinicalworks
and the type guard function provide clear boundaries for which EHR sources support dynamic secret retrieval.
52-65
: Proper error handling in the handler lookup.The mapping approach with explicit error handling for missing handlers is well-implemented. The
BadRequestError
with additional context is appropriate for this scenario.packages/api/src/external/ehr/shared/utils/client.ts (3)
29-29
: Good enhancement to include token ID in JWT token info.Adding the token
id
provides valuable metadata for token tracking and management.
51-52
: Approve function signature update for better type safety.The updated parameter type
EhrClientTwoLeggedAuthParams<Env>
and enhanced return type provide better type safety and more useful metadata.
65-71
: Good practice to capture and return token metadata.Storing the full token object and returning the token ID along with client and environment provides useful metadata for downstream operations.
packages/core/src/external/ehr/environment.ts (2)
8-18
: Excellent centralization of environment and credential types.The union types and generic type definitions provide a consistent interface across all EHR providers while maintaining type safety.
20-26
: Well-designed client authentication parameter types.The combination of JWT token info, practice ID, and environment credentials in a single type provides all necessary parameters for client creation.
packages/core/src/external/ehr/shared.ts (5)
43-54
: Well-defined schemas for secret retrieval validation.The Zod schemas provide proper validation for both OAuth and API key-based secret responses.
169-180
: Excellent error handling for S3 upload failures.Wrapping S3 operations in try-catch blocks prevents S3 failures from breaking the main request flow while still logging the errors for debugging.
185-192
: Good practice to chain errors with original cause.Passing the original error as the
cause
parameter preserves the full stack trace, which is valuable for debugging.
247-257
: Well-implemented FHIR validation error detection.The function properly parses FHIR OperationOutcome responses and identifies validation errors by checking for error severity and the validation prefix.
269-275
: Correct classification of FHIR validation errors as non-retriable.Including FHIR validation errors in the non-retriable category prevents unnecessary retry loops for validation failures that won't resolve with retries.
packages/infra/lib/ehr-nested-stack.ts (5)
23-23
: LGTM: New getAppointments Lambda configuration follows established patterns.The configuration is consistent with other Lambda settings, uses appropriate timeout (15 minutes) and memory allocation (1024 MB), and follows the new nested entry path structure.
Also applies to: 30-38, 151-151
42-42
: LGTM: Entry path reorganization improves structure.Moving all Lambda entries under the
ehr/
folder creates better organization and consistency across the EHR-related Lambda functions.Also applies to: 63-63, 84-84, 106-106, 131-131
103-103
: Verify timeout increases don't impact dependent systems.The Lambda timeouts have been increased to 15 minutes and alarm durations to 2 hours. Ensure these changes don't negatively impact downstream systems or SLA requirements.
Also applies to: 112-112, 128-128, 137-137
165-165
: LGTM: Optional bucket property properly typed.The
ehrResponsesBucket
is correctly typed as optional, which aligns with its conditional usage in the setup method.
170-170
: LGTM: Constructor integration follows established patterns.The Lambda property declaration and setup call are consistent with other Lambda configurations in the class.
Also applies to: 188-195
packages/core/src/util/config.ts (2)
212-214
: LGTM: Lambda name getter follows established pattern.The method correctly uses
getEnvVarOrFail
indicating this environment variable is required, which is appropriate for infrastructure dependencies.
223-253
: LGTM: EHR environment getters properly implemented.All new methods follow consistent patterns:
- Use
getEnvVar
(optional) appropriately for configuration that may not be present in all environments- Follow consistent naming conventions for environment variables
- Cover comprehensive EHR system configurations (AthenaHealth, Elation, Canvas, Healthie, EClinicalWorks)
- Method names use proper camelCase as per coding guidelines
Issues:
Description
Testing
Check each PR.
Release Plan
master
Summary by CodeRabbit