-
Notifications
You must be signed in to change notification settings - Fork 67
feat(ehr): moving get-appointments for Canvas to lambda #3873
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
base: develop
Are you sure you want to change the base?
Conversation
Ref: ENG-292 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
## Walkthrough
This update introduces a new, modular architecture for EHR appointment retrieval and secrets management, adds Lambda-based appointment fetching, and unifies EHR client creation for multiple vendors. It includes new route handlers for internal secrets and token retrieval, refactors import paths, and removes obsolete Canvas test data generators. Several new types, schemas, and error handling improvements are also added.
## Changes
| File(s) / Path(s) | Change Summary |
|-----------------------------------------------------------------------------------------------------|---------------|
| api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts<br>api/src/external/ehr/elation/command/process-patients-from-appointments.ts<br>api/src/routes/ehr/canvas/patient-webhook.ts<br>api/src/routes/ehr/elation/appointment-webhook.ts<br>api/src/routes/ehr/elation/patient-webhook.ts<br>api/src/routes/ehr/healthie/appointment-webhook.ts<br>api/src/routes/ehr/healthie/patient-webhook.ts<br>lambdas/src/ehr-sync-patient.ts<br>lambdas/src/elation-link-patient.ts<br>lambdas/src/healthie-link-patient.ts<br>lambdas/src/shared/ehr.ts | Refactored import paths for handler factories and request types to new `command` subdirectories. |
| api/src/external/ehr/athenahealth/shared.ts<br>api/src/external/ehr/canvas/shared.ts<br>api/src/external/ehr/elation/shared.ts<br>api/src/external/ehr/healthie/shared.ts | Unified EHR client creation: split into `{createXClientWithTokenIdAndEnvironment, createXClient}` pairs; made environment getter functions exported. |
| api/src/external/ehr/canvas/command/process-patients-from-appointments.ts | Refactored to use new appointment handler abstraction and updated client creation. |
| api/src/external/ehr/healthie/command/process-patients-from-appointments.ts | Updated appointment window calculation logic and refactored import paths. |
| api/src/external/ehr/shared/command/secrets/get-secrets.ts | Added new `getSecrets` function to unify EHR secrets retrieval. |
| api/src/external/ehr/shared/utils/appointment.ts | Fixed time range calculation in `getLookForwardTimeRangeWithOffset`. |
| api/src/external/ehr/shared/utils/client.ts | Made `EhrEnv` exported; `createEhrClient` now returns client, tokenId, and environment. |
| api/src/routes/ehr/util.ts | Added braces to conditional for clarity; no logic change. |
| api/src/routes/internal/ehr/index.ts | Added new `/practice` route for internal EHR endpoints. |
| api/src/routes/internal/ehr/practice.ts | New router: GET `/internal/ehr/:id/secrets` for EHR/practice secrets retrieval. |
| api/src/routes/internal/jwt-token/index.ts | Added new `/token` route for JWT token operations. |
| api/src/routes/internal/jwt-token/token.ts | New router: GET `/internal/token/:id` for JWT token retrieval by ID. |
| core/src/external/aws/lambda.ts | Added `LambdaClient` type alias; made return type explicit for `makeLambdaClient`. |
| core/src/external/ehr/api/get-client-key-and-secret.ts | Added `getSecrets` function for EHR API secrets retrieval. |
| core/src/external/ehr/api/get-token-info.ts | Added `getTokenInfo` function for JWT token info retrieval. |
| core/src/external/ehr/canvas/command/get-appointments.ts | Added `getAppointments` function for Canvas appointment retrieval. |
| core/src/external/ehr/canvas/data.ts | Deleted: removed test/demo FHIR bundle and resource generators. |
| core/src/external/ehr/canvas/shared.ts | Added `createCanvasClient` for Canvas API client instantiation with token info. |
| core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts | New class: Lambda-based appointment retrieval handler. |
| core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts | New class: Direct appointment retrieval handler and handler map. |
| core/src/external/ehr/command/get-appointments/ehr-get-appointments-factory.ts | New factory function to select appointment handler based on environment. |
| core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts | New types/interfaces for appointment retrieval and handler abstraction. |
| core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts<br>core/src/external/ehr/command/sync-patient/ehr-sync-patient-factory.ts<br>core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts<br>core/src/external/ehr/elation/command/link-patient/elation-link-patient-cloud.ts<br>core/src/external/ehr/elation/command/link-patient/elation-link-patient-factory.ts<br>core/src/external/ehr/elation/command/link-patient/elation-link-patient-local.ts<br>core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-cloud.ts<br>core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-factory.ts<br>core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-local.ts | Refactored import paths for configuration and utility modules. |
| core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-cloud.ts<br>core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-factory.ts<br>core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-local.ts<br>core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-cloud.ts<br>core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-factory.ts<br>core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-local.ts | Refactored import paths for job/bundle modules. |
| api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts | Refactored import path for refresh bundles handler. |
| lambdas/src/ehr-compute-resource-diff-bundles.ts<br>lambdas/src/ehr-refresh-ehr-bundles.ts | Refactored import paths for job/bundle modules. |
| core/src/external/ehr/shared.ts | Improved S3 error handling; added Zod schemas/types for OAuth and API key secrets. |
| core/src/util/config.ts | Added `getEhrGetAppointmentsLambdaName` method to `Config`. |
| infra/lib/api-stack.ts | Added `ehrGetAppointmentsLambda` to API stack and environment. |
| infra/lib/api-stack/api-service.ts | Added `ehrGetAppointmentsLambda` parameter, environment variable, and permissions. |
| infra/lib/ehr-nested-stack.ts | Added support for `getAppointments` Lambda, new settings, and permissions. |
| lambdas/src/ehr-get-appointments.ts | New Lambda handler for appointment retrieval via SQS. |
| lambdas/src/shared/ehr.ts | Added Zod schema for appointment retrieval requests. |
| shared/src/domain/jwt-token.ts | Added optional `id` to `JwtTokenInfo` type. |
## Sequence Diagram(s)
### EHR Appointment Retrieval (New Lambda-Based Flow)
```mermaid
sequenceDiagram
participant API_Service
participant Lambda (ehr-get-appointments)
participant EHR_AppointmentsHandler
participant EHR_System
API_Service->>Lambda: SQS message (appointment request)
Lambda->>Lambda: Parse & validate message
Lambda->>EHR_AppointmentsHandler: getAppointments(params)
EHR_AppointmentsHandler->>EHR_System: Fetch appointments (API call)
EHR_System-->>EHR_AppointmentsHandler: Appointment data
EHR_AppointmentsHandler-->>Lambda: Appointment data
Lambda-->>API_Service: Return appointment data EHR Secrets Retrieval (Internal Route)sequenceDiagram
participant Internal_Client
participant API_Service
participant getSecrets Handler
participant EHR_SecretsProvider
Internal_Client->>API_Service: GET /internal/ehr/:id/secrets?cxId=...&practiceId=...
API_Service->>getSecrets Handler: getSecrets({ehr, cxId, practiceId})
getSecrets Handler->>EHR_SecretsProvider: Fetch secrets (by EHR type)
EHR_SecretsProvider-->>getSecrets Handler: Secrets (OAuth or API key)
getSecrets Handler-->>API_Service: Secrets
API_Service-->>Internal_Client: JSON response
Possibly related PRs
|
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>
@@ -220,7 +219,7 @@ async function getAppointmentsFromApi({ | |||
} | |||
if (lookupMode === LookupModes.Appointments48hr) { | |||
const { startRange, endRange } = getLookForwardTimeRangeWithOffset({ | |||
lookForward: appointmentsLookForward48hr, | |||
lookForward: appointmentsLookForward, |
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.
offset is now applied to both dates so it's now just a 1day look-forward + 1day offset
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>
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: 11
♻️ Duplicate comments (1)
packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts (1)
222-224
: LGTM! Standardized appointment lookup duration.The change to use
appointmentsLookForward
for the 48hr lookup mode (with an offset) standardizes the approach to time range calculations across different modes.
🧹 Nitpick comments (6)
packages/core/src/external/ehr/lambdas/elation/link-patient/elation-link-patient-local.ts (1)
3-3
: Consistent import path update forlinkPatient
.
The import has been updated to reflect the new lambdas directory structure. Ensure this relative path remains valid and consider using a path alias (e.g.,@metriport/api
) to prevent brittle deep-relative imports when refactoring folder layouts.packages/api/src/routes/internal/ehr/practice.ts (1)
13-15
: Incorrect HTTP method in documentationThe JSDoc comment specifies a POST endpoint, but the implementation uses a GET endpoint.
-/** - * POST /internal/ehr/:ehrId/practice/:id/secrets - * +/** + * GET /internal/ehr/:ehrId/practice/:id/secrets + *packages/lambdas/src/ehr-get-appointments.ts (2)
18-19
: Address the TODO comment regarding Sentry wrapperThe TODO comment indicates that the Sentry wrapping should be moved to the capture.wrapHandler() function.
Consider replacing the direct Sentry.AWSLambda.wrapHandler with your own utility:
-// TODO move to capture.wrapHandler() -export const handler = Sentry.AWSLambda.wrapHandler(async (event: SQSEvent) => { +export const handler = capture.wrapHandler(async (event: SQSEvent) => {
27-28
: Consider simplifying with destructuring assignmentYou could destructure properties directly from parseBody() to avoid the intermediate variable.
- const parsedBody = parseBody(message.body); - const { ehr, cxId, practiceId } = parsedBody; + const { ehr, cxId, practiceId, ...rest } = parseBody(message.body);packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-cloud.ts (1)
8-46
: Fix typo in filename path.The file is located in a directory with a misspelled name:
appoinment/get-appoinemtns/
should beappointment/get-appointments/
.packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments.ts (1)
21-25
: Fix typo in enum value.The enum value contains a typo: "canvasGetAppoinemtns" should be "canvasGetAppointments".
export enum AppointmentMethods { - canvasGetAppointments = "canvasGetAppoinemtns", + canvasGetAppointments = "canvasGetAppointments", }Also note that the folder path in the file location contains the same typo ("get-appoinemtns" instead of "get-appointments").
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (56)
packages/api/src/command/jwt-token.ts
(1 hunks)packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts
(1 hunks)packages/api/src/external/ehr/athenahealth/shared.ts
(3 hunks)packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
(3 hunks)packages/api/src/external/ehr/canvas/shared.ts
(2 hunks)packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts
(1 hunks)packages/api/src/external/ehr/elation/shared.ts
(3 hunks)packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts
(2 hunks)packages/api/src/external/ehr/healthie/shared.ts
(1 hunks)packages/api/src/external/ehr/shared/command/secrets/get-secrets.ts
(1 hunks)packages/api/src/external/ehr/shared/utils/appointment.ts
(1 hunks)packages/api/src/external/ehr/shared/utils/client.ts
(6 hunks)packages/api/src/external/ehr/shared/utils/secrets.ts
(1 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/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/index.ts
(5 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/index.ts
(4 hunks)packages/core/src/external/ehr/elation/index.ts
(3 hunks)packages/core/src/external/ehr/healthie/index.ts
(3 hunks)packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-cloud.ts
(1 hunks)packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-factory.ts
(1 hunks)packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-local.ts
(1 hunks)packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments.ts
(1 hunks)packages/core/src/external/ehr/lambdas/elation/link-patient/elation-link-patient-cloud.ts
(1 hunks)packages/core/src/external/ehr/lambdas/elation/link-patient/elation-link-patient-factory.ts
(1 hunks)packages/core/src/external/ehr/lambdas/elation/link-patient/elation-link-patient-local.ts
(1 hunks)packages/core/src/external/ehr/lambdas/healthie/link-patient/healthie-link-patient-cloud.ts
(1 hunks)packages/core/src/external/ehr/lambdas/healthie/link-patient/healthie-link-patient-factory.ts
(1 hunks)packages/core/src/external/ehr/lambdas/healthie/link-patient/healthie-link-patient-local.ts
(1 hunks)packages/core/src/external/ehr/lambdas/sync-patient/ehr-sync-patient-cloud.ts
(1 hunks)packages/core/src/external/ehr/lambdas/sync-patient/ehr-sync-patient-factory.ts
(1 hunks)packages/core/src/external/ehr/lambdas/sync-patient/ehr-sync-patient-local.ts
(1 hunks)packages/core/src/external/ehr/shared.ts
(1 hunks)packages/core/src/util/config.ts
(1 hunks)packages/infra/lib/api-stack.ts
(3 hunks)packages/infra/lib/api-stack/api-service.ts
(4 hunks)packages/infra/lib/ehr-nested-stack.ts
(5 hunks)packages/lambdas/src/ehr-get-appointments.ts
(1 hunks)packages/lambdas/src/ehr-sync-patient.ts
(1 hunks)packages/lambdas/src/elation-link-patient.ts
(1 hunks)packages/lambdas/src/healthie-link-patient.ts
(1 hunks)packages/lambdas/src/shared/ehr.ts
(2 hunks)packages/shared/src/domain/jwt-token.ts
(1 hunks)
💤 Files with no reviewable changes (1)
- 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/lambdas/sync-patient/ehr-sync-patient-factory.ts
packages/api/src/routes/ehr/util.ts
packages/lambdas/src/elation-link-patient.ts
packages/lambdas/src/ehr-sync-patient.ts
packages/api/src/external/ehr/shared/utils/appointment.ts
packages/core/src/external/ehr/lambdas/sync-patient/ehr-sync-patient-cloud.ts
packages/core/src/external/ehr/lambdas/elation/link-patient/elation-link-patient-factory.ts
packages/core/src/external/ehr/lambdas/healthie/link-patient/healthie-link-patient-local.ts
packages/api/src/routes/ehr/canvas/patient-webhook.ts
packages/api/src/routes/ehr/elation/patient-webhook.ts
packages/api/src/routes/ehr/elation/appointment-webhook.ts
packages/api/src/routes/internal/jwt-token/index.ts
packages/core/src/external/ehr/lambdas/sync-patient/ehr-sync-patient-local.ts
packages/core/src/external/ehr/lambdas/healthie/link-patient/healthie-link-patient-cloud.ts
packages/api/src/routes/ehr/healthie/patient-webhook.ts
packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts
packages/lambdas/src/shared/ehr.ts
packages/api/src/routes/ehr/healthie/appointment-webhook.ts
packages/core/src/external/ehr/lambdas/elation/link-patient/elation-link-patient-cloud.ts
packages/shared/src/domain/jwt-token.ts
packages/infra/lib/api-stack.ts
packages/api/src/routes/internal/jwt-token/token.ts
packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts
packages/lambdas/src/healthie-link-patient.ts
packages/core/src/external/ehr/api/get-token-info.ts
packages/api/src/routes/internal/ehr/index.ts
packages/core/src/external/aws/lambda.ts
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-factory.ts
packages/core/src/util/config.ts
packages/api/src/external/ehr/healthie/shared.ts
packages/lambdas/src/ehr-get-appointments.ts
packages/infra/lib/api-stack/api-service.ts
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
packages/api/src/command/jwt-token.ts
packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts
packages/api/src/routes/internal/ehr/practice.ts
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments.ts
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-local.ts
packages/core/src/external/ehr/canvas/command/get-appointments.ts
packages/api/src/external/ehr/shared/utils/secrets.ts
packages/api/src/external/ehr/shared/command/secrets/get-secrets.ts
packages/core/src/external/ehr/api/get-client-key-and-secret.ts
packages/core/src/external/ehr/lambdas/elation/link-patient/elation-link-patient-local.ts
packages/core/src/external/ehr/elation/index.ts
packages/core/src/external/ehr/healthie/index.ts
packages/core/src/external/ehr/athenahealth/index.ts
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-cloud.ts
packages/core/src/external/ehr/lambdas/healthie/link-patient/healthie-link-patient-factory.ts
packages/api/src/external/ehr/elation/shared.ts
packages/api/src/external/ehr/canvas/shared.ts
packages/core/src/external/ehr/canvas/index.ts
packages/api/src/external/ehr/shared/utils/client.ts
packages/infra/lib/ehr-nested-stack.ts
packages/core/src/external/ehr/shared.ts
packages/api/src/external/ehr/athenahealth/shared.ts
🧠 Learnings (3)
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/core/src/external/ehr/lambdas/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/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.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.
🧬 Code Graph Analysis (20)
packages/api/src/routes/ehr/util.ts (1)
packages/shared/src/index.ts (1)
BadRequestError
(39-39)
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/jwt-token/token.ts (1)
packages/api/src/command/jwt-token.ts (1)
getJwtTokenByIdOrFail
(66-70)
packages/core/src/external/ehr/api/get-token-info.ts (5)
packages/shared/src/domain/jwt-token.ts (1)
JwtTokenInfo
(1-5)packages/core/src/util/config.ts (1)
Config
(9-225)packages/shared/src/net/retry.ts (1)
executeWithNetworkRetries
(108-135)packages/core/src/external/ehr/api/api-shared.ts (1)
validateAndLogResponse
(13-20)packages/shared/src/index.ts (1)
errorToString
(42-42)
packages/api/src/routes/internal/ehr/index.ts (1)
packages/api/src/routes/internal/ehr/middleware.ts (1)
processEhrId
(6-11)
packages/api/src/external/ehr/healthie/shared.ts (3)
packages/api/src/shared/config.ts (1)
A3E2 getHealthieEnv
(344-346)packages/api/src/external/ehr/shared/utils/client.ts (2)
EhrPerPracticeParams
(30-30)EhrEnvAndApiKey
(19-22)packages/core/src/external/ehr/healthie/index.ts (1)
HealthieEnv
(47-47)
packages/lambdas/src/ehr-get-appointments.ts (5)
packages/lambdas/src/shared/capture.ts (1)
capture
(18-103)packages/lambdas/src/shared/sqs.ts (1)
getSingleMessageOrFail
(62-83)packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-local.ts (1)
EhrGetAppointmentsLocal
(7-12)packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments.ts (1)
GetAppointmentsRequest
(6-15)packages/lambdas/src/shared/ehr.ts (1)
ehrGetAppointmentsSchema
(92-101)
packages/api/src/command/jwt-token.ts (2)
packages/api/src/domain/jwt-token.ts (1)
JwtToken
(30-30)packages/shared/src/index.ts (1)
NotFoundError
(41-41)
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments.ts (2)
packages/shared/src/interface/external/ehr/source.ts (1)
EhrSource
(8-8)packages/shared/src/index.ts (1)
BadRequestError
(39-39)
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-local.ts (1)
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments.ts (3)
EhrGetAppointmentsHandler
(17-19)GetAppointmentsRequest
(6-15)getEhrGetAppointmentsHandler
(47-56)
packages/core/src/external/ehr/canvas/command/get-appointments.ts (6)
packages/core/src/external/ehr/canvas/index.ts (1)
getAppointments
(860-915)packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments.ts (1)
GetAppointmentsClientRequest
(21-21)packages/shared/src/index.ts (1)
BadRequestError
(39-39)packages/core/src/external/ehr/api/get-token-info.ts (1)
getTokenInfo
(17-39)packages/core/src/external/ehr/api/get-client-key-and-secret.ts (1)
getSecrets
(17-44)packages/core/src/external/ehr/shared.ts (2)
GetSecretsOauthResult
(43-43)getSecretsOauthSchema
(39-42)
packages/api/src/external/ehr/shared/utils/secrets.ts (7)
packages/api/src/external/ehr/shared/utils/client.ts (4)
EhrEnv
(12-12)EhrPerPracticeParams
(30-30)EhrEnvAndClientCredentials
(13-17)EhrEnvAndApiKey
(19-22)packages/shared/src/interface/external/ehr/source.ts (1)
EhrSource
(8-8)packages/api/src/external/ehr/canvas/shared.ts (1)
getCanvasEnv
(11-37)packages/api/src/external/ehr/athenahealth/shared.ts (1)
getAthenaEnv
(15-29)packages/api/src/external/ehr/elation/shared.ts (1)
getElationEnv
(86-106)packages/api/src/external/ehr/healthie/shared.ts (1)
getHealthieEnv
(84-101)packages/shared/src/index.ts (1)
BadRequestError
(39-39)
packages/api/src/external/ehr/shared/command/secrets/get-secrets.ts (4)
packages/core/src/external/ehr/api/get-client-key-and-secret.ts (1)
getSecrets
(17-44)packages/api/src/external/ehr/shared/utils/client.ts (4)
EhrPerPracticeParams
(30-30)EhrEnvAndClientCredentials
(13-17)EhrEnv
(12-12)EhrEnvAndApiKey
(19-22)packages/shared/src/interface/external/ehr/source.ts (1)
EhrSource
(8-8)packages/api/src/external/ehr/shared/utils/secrets.ts (1)
getSecretsFunction
(28-34)
packages/core/src/external/ehr/api/get-client-key-and-secret.ts (4)
packages/core/src/external/ehr/api/api-shared.ts (2)
ApiBaseParams
(5-11)validateAndLogResponse
(13-20)packages/core/src/util/config.ts (1)
Config
(9-225)packages/shared/src/net/retry.ts (1)
executeWithNetworkRetries
(108-135)packages/shared/src/index.ts (1)
errorToString
(42-42)
packages/core/src/external/ehr/elation/index.ts (1)
packages/core/src/external/ehr/shared.ts (2)
GetSecretsOauthFunction
(50-50)processOauthSecrets
(53-76)
packages/core/src/external/ehr/athenahealth/index.ts (1)
packages/core/src/external/ehr/shared.ts (2)
GetSecretsOauthFunction
(50-50)processOauthSecrets
(53-76)
packages/api/src/external/ehr/elation/shared.ts (2)
packages/api/src/external/ehr/shared/utils/client.ts (1)
EhrPerPracticeParams
(30-30)packages/core/src/external/ehr/elation/index.ts (1)
ElationEnv
(56-56)
packages/api/src/external/ehr/shared/utils/client.ts (2)
packages/core/src/external/ehr/healthie/index.ts (1)
HealthieEnv
(47-47)packages/api/src/command/jwt-token.ts (1)
findOrCreateJwtToken
(11-21)
packages/core/src/external/ehr/shared.ts (3)
packages/shared/src/interface/external/ehr/source.ts (1)
EhrSource
(8-8)packages/core/src/external/ehr/api/get-client-key-and-secret.ts (1)
getSecrets
(17-44)packages/shared/src/domain/jwt-token.ts (1)
JwtTokenInfo
(1-5)
packages/api/src/external/ehr/athenahealth/shared.ts (2)
packages/api/src/external/ehr/shared/utils/client.ts (2)
EhrEnvAndClientCredentials
(13-17)EhrPerPracticeParams
(30-30)packages/core/src/external/ehr/athenahealth/index.ts (1)
AthenaEnv
(95-95)
⏰ Context from checks skipped due to timeout of 90000ms (7)
- GitHub Check: check-branch
- 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)
🔇 Additional comments (95)
packages/core/src/external/ehr/lambdas/sync-patient/ehr-sync-patient-factory.ts (1)
1-1
: Import path update looks goodThe Config import path has been properly updated to reflect the new directory structure.
packages/core/src/external/ehr/lambdas/elation/link-patient/elation-link-patient-factory.ts (1)
1-1
: Import path update looks goodThe Config import path has been correctly updated to reflect the new directory structure.
packages/core/src/external/ehr/lambdas/sync-patient/ehr-sync-patient-cloud.ts (1)
3-4
: Import paths correctly updatedBoth import paths have been properly adjusted to reflect the new directory structure.
packages/api/src/routes/ehr/elation/appointment-webhook.ts (1)
1-1
: Align import to new Lambda factory location.
ThebuildEhrSyncPatientHandler
path correctly points to thelambdas
subdirectory. Confirm that the factory export signature hasn't changed and that error handling remains consistent when invoking the new handler.packages/api/src/routes/ehr/canvas/patient-webhook.ts (1)
1-1
:✅ Verification successful
Update sync handler import for Canvas.
ImportingbuildEhrSyncPatientHandler
from thelambdas
directory aligns with the Canvas refactor. Verify that this handler logic supports appointment retrieval for Canvas (e.g.,buildEhrGetAppointmentsHandler
elsewhere) and that no residual direct client calls remain.Run this to locate the new appointments handler and ensure it's wired correctly:
🏁 Script executed:
#!/bin/bash rg -g "*.ts" "buildEhrGetAppointmentsHandler" -LLength of output: 815
Import Update Verified
- Confirmed that
buildEhrSyncPatientHandler
is correctly imported from
@metriport/core/external/ehr/lambdas/sync-patient/ehr-sync-patient-factory
.- Located
buildEhrGetAppointmentsHandler
in
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-factory.ts
and saw it wired in
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
.- No direct EHR client calls remain in
packages/api/src/routes/ehr/canvas/patient-webhook.ts
.Everything aligns with the Canvas refactor. Approved.
packages/api/src/routes/ehr/healthie/patient-webhook.ts (1)
1-1
: Consistent import path refactoring for Healthie sync handler.
The import now targets thelambdas
-based sync factory. Please ensure that CI’s type-checker catches any mismatches if the factory’s API changed, and update documentation/comments if the handler signature was modified.packages/lambdas/src/ehr-sync-patient.ts (1)
1-2
:✅ Verification successful
Adopt new lambdas module paths for local sync handler.
TheProcessSyncPatientRequest
andEhrSyncPatientLocal
imports have been updated to thelambdas
directory. Verify thatehr-sync-patient-local.ts
still exports the expected classes and run a scan to catch any lingering legacy imports:
🏁 Script executed:
#!/bin/bash rg -g "*.ts" "@metriport/core/external/ehr/sync-patient/" --filesLength of output: 148
I suspect the initial ripgrep invocation targeted a non‐existent directory. Let’s instead scan all
.ts
files for the legacy import string:
🏁 Script executed:
#!/bin/bash # Find any remaining imports from the old path rg '@metriport/core/external/ehr/sync-patient/' -g '*.ts'Length of output: 57
🏁 Script executed:
#!/bin/bash # Locate the new local sync handler file and inspect its exports fd -e ts 'ehr-sync-patient-local.ts' --exec sed -n '1,50p' {}Length of output: 769
🏁 Script executed:
#!/bin/bash # Inspect ehr-sync-patient.ts in both the lambdas package (under review) and the external core package for file in $(fd -e ts 'ehr-sync-patient.ts'); do echo "=== $file ===" sed -n '1,50p' "$file" doneLength of output: 2985
Approved: Lambdas imports updated and no legacy references found
Verified thatehr-sync-patient-local.ts
still exportsEhrSyncPatientLocal
andProcessSyncPatientRequest
, and a repo-wide search returned no remaining imports from the old@metriport/core/external/ehr/sync-patient/
path. All looks correct.packages/api/src/routes/ehr/elation/patient-webhook.ts (1)
1-1
: Consistent import path update for lambda-based handler
The import path has been correctly updated to reference the newlambdas
directory for the EHR sync-patient factory. This aligns with the overall refactor to centralize Lambda handlers.packages/lambdas/src/elation-link-patient.ts (1)
1-2
: Align imports with new lambda module structure
TheProcessLinkPatientRequest
andElationLinkPatientLocal
imports now point to thelambdas
subdirectory, matching the reorganization across EHR handlers.packages/api/src/routes/ehr/util.ts (1)
15-17
: Add explicit braces for clarity
Wrapping the throw statement in{}
improves readability and aligns with the project’s style of always using braces around conditional blocks, even single-line ones.packages/core/src/external/ehr/lambdas/sync-patient/ehr-sync-patient-local.ts (1)
2-2
: Update relative import to reflect directory restructure
The import forsyncPatient
now uses the correct relative path after moving handlers underlambdas
. This keeps module resolution accurate with the new folder layout.packages/core/src/external/ehr/lambdas/elation/link-patient/elation-link-patient-cloud.ts (1)
3-4
: Correct deep relative imports for AWS utilities
TheSQSClient
andConfig
imports have been updated to the deeper relative paths underexternal/aws
andutil
. This matches the refactored directory structure for cloud handlers.packages/api/src/routes/ehr/healthie/appointment-webhook.ts (1)
1-1
: Import path updated to new lambdas directory
The import forbuildEhrSyncPatientHandler
has been adjusted to point at@metriport/core/external/ehr/lambdas/sync-patient/...
. This aligns with the reorganized folder structure—please verify that all similar EHR route handlers use the updated path to prevent resolution errors.packages/core/src/external/ehr/lambdas/healthie/link-patient/healthie-link-patient-local.ts (1)
3-3
: Corrected relative import forlinkPatient
ThelinkPatient
import path has been updated to match the relocated API module under thelambdas
directory. Confirm that this reference resolves correctly and remove any stale imports if present.packages/core/src/external/ehr/lambdas/healthie/link-patient/healthie-link-patient-factory.ts (1)
1-1
: AdjustedConfig
import path
TheConfig
import now traverses one additional directory level to accommodate the newlambdas
layout. Ensure consistency with other factory modules and thatutil/config
remains reachable from this location.packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts (1)
2-2
: Updated sync-patient factory import
The import forbuildEhrSyncPatientHandler
now points to thelambdas/sync-patient
path under@metriport/core
. This reflects the new architecture—please double-check that all AthenaHealth and other EHR modules have received the same update.packages/shared/src/domain/jwt-token.ts (1)
4-4
: ExtendJwtTokenInfo
type with optionalid
Introducing an optionalid
property enables identifying JWT tokens by their unique identifier, supporting the newgetJwtTokenById
API and related command functions. This change is backward-compatible and aligns with the enhanced token-management flow.packages/lambdas/src/healthie-link-patient.ts (1)
1-2
: Import paths updated correctly to match relocated lambda code structure.The import paths now properly point to the new location under the
lambdas
subdirectory, which aligns with the PR objective of relocating linking and syncing lambda code into a dedicated lambdas folder.packages/core/src/external/ehr/lambdas/healthie/link-patient/healthie-link-patient-cloud.ts (1)
3-4
: Import paths correctly adjusted for new file location.The imports have been updated with proper relative paths after moving the file into the new
lambdas
directory structure. This maintains the correct module resolution and adheres to the project's modular architecture.packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts (1)
1-2
: Import paths properly updated to use handlers from the new lambdas structure.The import paths now correctly reference the handlers from the reorganized
lambdas
subdirectory, maintaining consistent implementation with the code refactoring across the codebase.packages/core/src/util/config.ts (1)
215-217
: New config method added for EHR appointments lambda.The addition of
getEhrGetAppointmentsLambdaName()
properly supports the new lambda connector for retrieving EHR appointments, following the established pattern for config methods in this class.packages/api/src/routes/internal/jwt-token/index.ts (2)
6-6
: LGTM!The token import and subsequent route registration in line 17 add a shared JWT token functionality to the router.
16-17
: Good implementation of shared token routesAdding the token routes at the root path is a clean way to organize shared JWT token functionality that applies across EHR types.
packages/api/src/routes/internal/ehr/index.ts (2)
8-8
: LGTM!The practice import follows the established pattern for EHR route modules.
17-17
: Good implementation of practice routesThis route registration correctly uses the
processEhrId
middleware to validate and extract the EHR ID parameter before passing control to the practice router, following the same pattern as the existing patient routes.packages/infra/lib/api-stack.ts (3)
424-424
: LGTM!Properly destructuring the get appointments Lambda from the EHR nested stack.
558-558
: Good integration with API serviceThe appointments Lambda is correctly passed to the API service creation function.
663-663
: Consistent environment variable configurationThis correctly adds the appointments Lambda to the list of Lambdas that need the API_URL environment variable.
packages/api/src/routes/internal/jwt-token/token.ts (1)
18-26
: LGTM! Route handler implementation is clean and follows best practices.The route handler correctly extracts the token ID from parameters with validation, retrieves the token using the appropriate command function, and returns it with the correct HTTP status code.
packages/api/src/external/ehr/healthie/shared.ts (1)
84-87
: LGTM! Exporting this function supports the new Lambda architecture.The change to export
getHealthieEnv
aligns with the PR objective of supporting Lambda-based appointment handling. The function provides the necessary environment and API key information for the EHR client.packages/api/src/command/jwt-token.ts (2)
52-61
: LGTM! Well-implemented token retrieval by ID function.The
getJwtTokenById
function follows the established pattern in the file with proper documentation and error handling. The implementation is clean and focused.
63-70
: LGTM! Fail-safe wrapper follows established pattern.The
getJwtTokenByIdOrFail
function properly implements the "OrFail" pattern used throughout the codebase, with appropriate error handling and documentation.packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts (1)
2-3
: LGTM! Updated imports align with the new Lambda folder structure.The import paths now correctly point to the new dedicated lambdas directories, supporting the PR's objective of better code organization.
packages/infra/lib/api-stack/api-service.ts (1)
115-115
: Good addition of the EHR appointments Lambda infrastructure!The changes properly integrate the new
ehrGetAppointmentsLambda
into the API service:
- Added as a parameter to the
createAPIService
function- Correctly placed in the expected order in the parameter list
- Lambda name included as an environment variable for the Fargate service
- Task role granted permission to invoke the Lambda
This follows the established pattern for other Lambda integrations in this file.
Also applies to: 161-161, 305-305, 450-450
packages/core/src/external/ehr/api/get-token-info.ts (1)
1-39
: Well-implemented token retrieval with proper error handling.This function follows best practices:
- Uses network retries for resilience
- Properly transforms the API response
- Includes contextual error information
- Uses appropriate logging
The implementation aligns with the functional programming style preferred in the codebase.
packages/lambdas/src/shared/ehr.ts (2)
1-4
: Good update to Lambda import paths.The import paths have been properly updated to reference the new location of the lambdas code, which aligns with the PR objective of relocating the linking and syncing lambda code to a dedicated lambdas folder.
92-101
: Well-structured Zod schema for appointment requests.The schema properly validates:
- EHR source from an enumeration
- Required string fields (environment, method, tokenId, cxId, practiceId)
- Optional date fields with type coercion
This provides strong type safety for the appointment Lambda handler.
packages/api/src/external/ehr/shared/command/secrets/get-secrets.ts (1)
1-26
: Well-implemented secrets retrieval functionThis function follows good practices by providing a clear interface for retrieving EHR secrets while delegating the implementation details to source-specific functions. The return type union correctly handles both OAuth client credentials and API key scenarios.
packages/api/src/routes/internal/ehr/practice.ts (1)
23-38
: LGTM - Secure implementation of secrets retrieval endpointThe endpoint appropriately validates all parameters before proceeding, using proper error handling for invalid inputs. The response is correctly formatted with appropriate HTTP status codes.
packages/lambdas/src/ehr-get-appointments.ts (2)
12-13
: Good practice placing Sentry initialization earlyInitializing capture as early as possible in the file ensures all errors are properly tracked.
41-50
: Good input validation with descriptive error messagesThe parseBody function properly validates the message structure and content with clear error messages at each step.
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-local.ts (1)
7-12
: Clean implementation of handler interfaceThe class follows a good pattern by implementing the interface and delegating to the appropriate handler based on EHR source and method. The parameter spreading keeps the code clean and maintainable.
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts (2)
99-102
: LGTM: Good use of destructuring for client creationThe updated client creation method now returns
tokenId
andenvironment
alongside the client, which allows for more flexible use of these values.
108-118
: LGTM: Good refactoring to use handler-based approachThe appointment fetching logic now uses a handler built by
buildEhrGetAppointmentsHandler()
instead of directly calling a method on the client. This improves modularity and testability by decoupling the appointment fetching logic from the client implementation.packages/core/src/external/ehr/api/get-client-key-and-secret.ts (2)
8-8
: LGTM: Good type definitionWell-defined type that properly omits fields not needed for fetching secrets.
17-44
: LGTM: Well-implemented function for retrieving secretsThis function follows good practices:
- Uses network retries for resilience
- Proper error handling with context
- Strong typing with Zod schema validation
- Clear logging
The implementation is secure and robust.
packages/core/src/external/ehr/canvas/index.ts (2)
109-109
: LGTM: Good addition of dynamic secrets retrievalAdding a callback function for dynamic secrets retrieval allows for more flexible credential management.
133-142
: LGTM: Improved OAuth secrets handlingThe
fetchTwoLeggedAuthToken
method now usesprocessOauthSecrets
to dynamically retrieve OAuth client credentials. This approach is more secure and flexible than hardcoding credentials or storing them directly in configuration.packages/core/src/external/ehr/canvas/command/get-appointments.ts (1)
13-26
: LGTM: Good parameter validationThe function properly validates required parameters and provides detailed error context.
packages/api/src/external/ehr/shared/utils/secrets.ts (4)
1-12
: Well-structured imports.The imports are nicely organized, bringing in necessary error handling, EHR source definitions, and environment-specific secrets retrieval functions for different EHR systems. The local import of client types is appropriately placed last.
14-19
: Good type definitions for different secrets functions.The type definitions create a clear contract for functions that retrieve different types of secrets:
OauthSecretsFunction
for OAuth client credentialsApiKeySecretsFunction
for API key-based authenticationSecretsFunction
as a union type, providing a unified interfaceThis design enables flexibility while maintaining type safety.
21-26
: Good use of a lookup table for secrets functions.The record maps each EHR source to its corresponding secret retrieval function, making it easy to extend with additional EHR sources in the future.
28-34
: Well-implemented utility function with proper error handling.The
getSecretsFunction
implementation appropriately checks for the existence of a secrets function and throws a meaningful error when none is found. This ensures that callers receive clear feedback when trying to fetch secrets for an unsupported EHR.packages/core/src/external/ehr/elation/index.ts (4)
40-44
: Good import additions for secret management.Adding
GetSecretsOauthFunction
andprocessOauthSecrets
imports supports the dynamic secret retrieval mechanism being implemented.
73-73
: Well-typed new class property for secret retrieval.The
getSecrets
property is correctly typed as an optional function, allowing the API to work both with static configuration and dynamic secret retrieval.
81-82
: Good initialization of the getSecrets property.Initializing
this.getS F438 ecrets
from the config ensures the class can access the dynamic secret retrieval function provided during instantiation.
94-125
: Improved token retrieval with dynamic secrets management.The refactored
fetchTwoLeggedAuthToken
method now usesprocessOauthSecrets
to obtain credentials, making the authentication process more flexible. This change:
- Supports retrieving credentials at runtime
- Maintains backward compatibility with static credentials
- Properly handles the case when neither is available
The code correctly constructs a partial secrets object with existing credentials (if any) and passes it along with the getSecrets function to the processor.
packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-cloud.ts (3)
1-9
: Good imports with proper error handling utilities.The imports bring in network retry functionality, configuration management, and Lambda client utilities needed for cloud-based appointment retrieval.
11-20
: Well-designed class with proper dependency injection.The
EhrGetAppointmentsCloud
class:
- Implements the required handler interface
- Accepts the Lambda function name as a required parameter
- Supports optional region and Lambda client parameters
- Initializes the Lambda client appropriately when not provided
This design follows good dependency injection principles, making the class more testable.
22-45
: Robust implementation of the getAppointments method.The
getAppointments
method:
- Logs operation details
- Properly serializes the request parameters
- Uses network retries for resilience
- Handles error cases in the Lambda response
- Returns an empty array as a fallback
- Correctly parses and returns the result
The implementation is resilient to various failure modes while maintaining type safety.
packages/core/src/external/ehr/athenahealth/index.ts (4)
75-79
: Good import additions for secret management.Adding
GetSecretsOauthFunction
andprocessOauthSecrets
imports prepares the class for dynamic secret retrieval.
151-151
: Well-typed new class property for secret retrieval.The
getSecrets
property is correctly typed as an optional function, allowing the API to work with both static and dynamic credential retrieval.
160-161
: Good initialization of the getSecrets property.Initializing
this.getSecrets
from the config ensures the class can access the dynamic secret retrieval function provided during instantiation.
173-207
: Improved token retrieval with dynamic secrets management.The refactored
fetchTwoLeggedAuthToken
method now usesprocessOauthSecrets
to obtain credentials dynamically. This change:
- Supports retrieving credentials at runtime
- Maintains backward compatibility with static credentials
- Properly handles credential absence
- Uses the retrieved credentials correctly in the auth header
This implementation ensures secure and flexible credential management for AthenaHealth API authentication.
packages/api/src/external/ehr/elation/shared.ts (3)
86-106
: Export of environment retrieval function is a good enhancementThis is a positive change that makes the
getElationEnv
function accessible to other modules, which is necessary for the new Lambda-based appointment retrieval architecture being implemented in this PR.
124-133
: Function return type enhancement improves flexibilityGood refactoring to return additional metadata (tokenId and environment) alongside the client. This enriched return value supports the new appointment fetching Lambda functionality while maintaining the core functionality.
135-140
: Backward compatibility wrapper preserves API contractThe new function preserves the original interface by delegating to the enriched function and returning only the client. This follows good API design principles by minimizing impact on existing code while enabling new functionality.
packages/api/src/external/ehr/canvas/shared.ts (3)
3-3
: Improved token source management through centralizationImporting
canvasClientSource
from a shared module rather than defining constants locally improves maintainability by centralizing token source definitions.
39-48
: Enhanced client creation function with metadataThe enriched return type now includes tokenId and environment alongside the Canvas client, enabling more flexible API interactions for the new appointment lambda architecture.
50-55
: Backward compatibility is correctly maintainedThis function preserves the original interface by extracting just the client part from the enriched function, minimizing impact on existing code while supporting new appointment fetching functionality.
packages/api/src/external/ehr/athenahealth/shared.ts (3)
15-29
: Export of environment getter improves module accessibilityMaking
getAthenaEnv
exported allows other modules to access environment configuration, aligning with similar changes in other EHR modules and supporting the new architecture.
31-40
: Enhanced client creation with metadata supports Lambda architectureThe function now returns additional context (tokenId and environment) alongside the client, following the same pattern used in other EHR integrations to support the new appointment fetching infrastructure.
42-47
: Backward compatibility function maintains API contractThis wrapper function maintains the original API contract by delegating to the new function and returning only the client, which is a good practice for maintaining compatibility with existing code.
packages/infra/lib/ehr-nested-stack.ts (5)
22-22
: Well-defined type for Lambda settingsGood refactoring to create a specific type for Lambda settings using TypeScript's
Pick
utility type, making the code more maintainable and type-safe.
32-40
: Appropriate Lambda configuration for appointment retrievalThe configuration for the new appointment retrieval Lambda function is well-defined with a 12-minute timeout and 4GB memory allocation, which should be sufficient for the expected workload.
171-171
: Clean addition of Lambda property to stack classAdding a readonly property for the new Lambda function to the EhrNestedStack class follows good object-oriented design principles by clearly exposing the resource to clients of the class.
189-195
: Proper Lambda initialization in constructorThe initialization call in the constructor follows the established pattern in this class, maintaining consistency with the rest of the codebase.
266-292
: Well-structured Lambda setup methodThe implementation follows the same pattern as other Lambda setup methods in the class, with appropriate configuration for environment variables, layers, VPC settings, and alarms. Unlike other Lambdas in this stack, this one doesn't create an SQS queue or event source, which is appropriate for its intended use case.
packages/api/src/external/ehr/shared/utils/client.ts (6)
4-4
: Import from Healthie module looks good.This import is necessary to add support for the Healthie EHR environment type.
12-12
: EHR environment type correctly extended.Adding
HealthieEnv
to theEhrEnv
union type properly extends the system to support the new Healthie EHR source.
24-24
: Type rename improves clarity.Renaming from
EhrClient
toEhrOauthClient
more accurately reflects that these are OAuth-based clients, which is appropriate since the Healthie client uses API key authentication instead of OAuth.
46-47
: Token ID added to support Lambda functions.Adding the token ID to the returned information provides necessary context for the new Lambda-based architecture where tokens need to be referenced by ID.
69-69
: Enhanced return type provides better context.The expanded return type including
tokenId
andenvironment
provides richer information to consumers of this function, which is needed for the Lambda-based appointment retrieval system.
82-88
: Token persistence and return structure look good.Using
findOrCreateJwtToken
appropriately persists the token information. The return structure provides all necessary data for downstream consumers.Note: The
environment.environment
access pattern suggests a nested environment property. While this works, it could be simplified in a future refactoring if appropriate.packages/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments.ts (3)
1-19
: Well-structured imports and type definitions.The imports and type definitions provide a clear foundation for the appointment retrieval system. The
GetAppointmentsRequest
includes all necessary fields, and theEhrGetAppointmentsHandler
interface defines a clean contract with generic typing.
27-45
: Extensible mapping structure for EHR appointment handlers.The map structure provides a clear framework for associating EHR sources and methods with their handler implementations. This architecture allows for easy addition of new sources and methods in the future.
47-56
: Well-implemented handler retrieval function.The
getEhrGetAppointmentsHandler
function provides a type-safe way to retrieve the appropriate handler for a given EHR source and method. The error handling is appropriate, providing context about the requested handler in the error message.packages/core/src/external/ehr/healthie/index.ts (4)
27-33
: Good utility imports to support dynamic secret retrieval.The updated imports bring in necessary utilities for implementing the dynamic secret retrieval pattern, consistent with other EHR implementations.
37-41
: Interface properly updated for dynamic secrets.The
HealthieApiConfig
interface is correctly extended to support optional API key with dynamic retrieval via agetSecrets
function. This aligns with the PR objective of retrieving secrets per practice to support Lambda operations.
56-56
: Class correctly stores secret retrieval function.Adding the
getSecrets
field and initializing it in the constructor provides the necessary state for dynamic secret retrieval.Also applies to: 64-64
74-86
: Robust initialization with dynamic secret retrieval.The updated
initialize
method correctly implements the dynamic secret retrieval pattern:
- First checks if API key is directly provided
- If not, verifies a
getSecrets
function exists- Throws a clear error if neither is available
- Otherwise, uses
getSecrets
to dynamically retrieve the API keyThis implementation is robust and provides clear error messaging.
packages/core/src/external/ehr/shared.ts (4)
39-48
: Well-defined schemas for secret validation.Using Zod schemas for OAuth and API key secrets provides runtime validation and type safety, ensuring that secret data structures are consistent and complete throughout the system.
50-51
: Clear function types for secret retrieval.These function types establish a consistent contract for secret retrieval functions, making the system more maintainable and extensible.
53-76
: Robust OAuth secret processing function.The
processOauthSecrets
function implements a robust pattern for handling OAuth credentials:
- Use provided credentials if available
- Fall back to dynamic retrieval if a
getSecrets
function exists- Provide clear error messages when requirements aren't met
This centralizes the logic and reduces duplication across different EHR client implementations.
81-83
: Interface properly updated for dynamic secret retrieval.Making
clientKey
andclientSecret
optional and adding thegetSecrets
function toApiConfig
reflects the new pattern for credential management, supporting both direct provision and dynamic retrieval.
...ges/core/src/external/ehr/lambdas/appoinment/get-appoinemtns/ehr-get-appointments-factory.ts
Outdated
Show resolved
Hide resolved
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
Outdated
Show resolved
Hide resolved
packages/core/src/external/ehr/canvas/command/get-appointments.ts
Outdated
Show resolved
Hide resolved
packages/core/src/external/ehr/canvas/command/get-appointments.ts
Outdated
Show resolved
Hide resolved
packages/core/src/external/ehr/canvas/command/get-appointments.ts
Outdated
Show resolved
Hide resolved
packages/core/src/external/ehr/canvas/command/get-appointments.ts
Outdated
Show resolved
Hide resolved
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: 3
🧹 Nitpick comments (3)
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments-local.ts (1)
7-12
: Implementation looks good, but consider optimization for future scalabilityThe EhrGetAppointmentsLocal class follows a good implementation pattern for the interface. It correctly destructures the request and delegates to the appropriate handler.
For future scalability, consider adding error logging specifically for this local implementation. When more EHR sources are added, having detailed logs here will help with troubleshooting:
async getAppointments<T>({ ehr, method, ...params }: GetAppointmentsRequest): Promise<T[]> { + const { log } = out(`EhrGetAppointmentsLocal - ehr ${ehr}, method ${method}`); const handler = getEhrGetAppointmentsHandler<T>(ehr, method); + log(`Handler found, executing with params`); return await handler({ ...params }); }packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments.ts (2)
27-36
: Consider a more maintainable type definition approachThe current
GetAppointmentsMap
type definition will require manual updates each time a new EHR source is added.Consider using a more dynamic type generation approach:
- export type GetAppointmentsMap = { - [EhrSources.athena]: undefined; - [EhrSources.elation]: undefined; - [EhrSources.healthie]: undefined; - [EhrSources.canvas]: { - [AppointmentMethods.canvasGetAppointments]: ( - params: GetAppointmentsClientRequest - ) => Promise<SlimBookedAppointment[]>; - }; - }; + export type EhrMethodHandler = (params: GetAppointmentsClientRequest) => Promise<unknown[]>; + + export type EhrMethodsMap = { + [method in AppointmentMethods]?: EhrMethodHandler; + }; + + export type GetAppointmentsMap = { + [source in EhrSource]?: EhrMethodsMap; + };This approach will be more scalable as you add more EHR sources and methods in the future, without requiring repetitive type definitions.
47-56
: Handler lookup function is well-implemented with proper error handlingThe
getEhrGetAppointmentsHandler
function correctly handles the lookup and error case.Consider adding a type guard to improve the explicitness of the type casting:
export function getEhrGetAppointmentsHandler<T>( ehr: EhrSource, method: AppointmentMethods ): (params: GetAppointmentsClientRequest) => Promise<T[]> { const handler = ehrGetAppointmentsMap[ehr]?.[method]; if (!handler) { throw new BadRequestError(`No get appointments handler found`, undefined, { ehr, method }); } - return handler as (params: GetAppointmentsClientRequest) => Promise<T[]>; + return ((params: GetAppointmentsClientRequest) => { + return handler(params) as Promise<T[]>; + }); }This makes the type conversion more explicit and controlled, though the current implementation is also valid.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (10)
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
(3 hunks)packages/api/src/routes/internal/jwt-token/token.ts
(1 hunks)packages/core/src/external/aws/lambda.ts
(1 hunks)packages/core/src/external/ehr/canvas/command/get-appointments.ts
(1 hunks)packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments-cloud.ts
(1 hunks)packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments-factory.ts
(1 hunks)packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments-local.ts
(1 hunks)packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments.ts
(1 hunks)packages/lambdas/src/ehr-get-appointments.ts
(1 hunks)packages/lambdas/src/shared/ehr.ts
(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments-factory.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
- packages/core/src/external/aws/lambda.ts
- packages/api/src/routes/internal/jwt-token/token.ts
- packages/lambdas/src/shared/ehr.ts
- packages/core/src/external/ehr/canvas/command/get-appointments.ts
- packages/lambdas/src/ehr-get-appointments.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/lambdas/appointment/get-appointments/ehr-get-appointments-cloud.ts
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments-local.ts
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments.ts
🧬 Code Graph Analysis (2)
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments-cloud.ts (3)
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments.ts (2)
EhrGetAppointmentsHandler
(17-19)GetAppointmentsRequest
(6-15)packages/core/src/external/aws/lambda.ts (3)
LambdaClient
(7-7)makeLambdaClient
(13-19)defaultLambdaInvocationResponseHandler
(26-35)packages/shared/src/net/retry.ts (1)
executeWithNetworkRetries
(108-135)
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments.ts (3)
packages/shared/src/interface/external/ehr/source.ts (1)
EhrSource
(8-8)packages/lambdas/src/ehr-get-appointments.ts (1)
handler
(19-39)packages/shared/src/index.ts (1)
BadRequestError
(39-39)
🔇 Additional comments (2)
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments-cloud.ts (1)
11-20
: Constructor implementation follows best practicesThe constructor correctly initializes the Lambda client with either the provided client or creates a new one with appropriate region configuration.
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments.ts (1)
6-21
: Type definitions look good with clear interface contractThe request type definitions and handler interface are well-structured with appropriate typing.
...ges/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments-cloud.ts
Outdated
Show resolved
Hide resolved
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments.ts
Outdated
Show resolved
Hide resolved
packages/core/src/external/ehr/lambdas/appointment/get-appointments/ehr-get-appointments.ts
Outdated
Show resolved
Hide resolved
Ref: ENG-199 Ref: #1040 Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Done for core. For testing, I can't run the "create token on the fly" code as it's setup right now to always generate a token on the API first before calling the new lambda. This will start getting used once we refresh the bundles in "real-time" from the refresh lambda (downstream PR). |
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: 0
🧹 Nitpick comments (2)
packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-cloud.ts (1)
41-42
: Consider type safety for JSON parsing.The JSON.parse operation could throw if the Lambda returns invalid JSON. Consider adding error handling or type validation.
- if (!result) return []; - return JSON.parse(result); + if (!result) return []; + try { + return JSON.parse(result); + } catch (error) { + throw new Error(`Failed to parse Lambda response`, { cause: error }); + }packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-direct.ts (1)
57-57
: Verify type casting safety.The type assertion
as (params: GetAppointmentsClientRequest) => Promise<T[]>
assumes the handler matches the expected signature. While this should be safe due to the type-safe map design, consider if additional runtime validation would be beneficial.The current implementation should be safe due to the strongly-typed map, but if you want extra safety:
- return handler as (params: GetAppointmentsClientRequest) => Promise<T[]>; + // Type assertion is safe here due to strongly-typed map design + return handler as (params: GetAppointmentsClientRequest) => Promise<T[]>;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (22)
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
(3 hunks)packages/api/src/external/ehr/shared/utils/client.ts
(4 hunks)packages/api/src/external/ehr/shared/utils/secrets.ts
(1 hunks)packages/api/src/routes/internal/jwt-token/index.ts
(1 hunks)packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-cloud.ts
(1 hunks)packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-direct.ts
(1 hunks)packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-factory.ts
(1 hunks)packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments.ts
(1 hunks)packages/core/src/external/ehr/command/elation/link-patient/elation-link-patient-cloud.ts
(1 hunks)packages/core/src/external/ehr/command/elation/link-patient/elation-link-patient-factory.ts
(1 hunks)packages/core/src/external/ehr/command/elation/link-patient/elation-link-patient-local.ts
(1 hunks)packages/core/src/external/ehr/command/healthie/link-patient/healthie-link-patient-cloud.ts
(1 hunks)packages/core/src/external/ehr/command/healthie/link-patient/healthie-link-patient-factory.ts
(1 hunks)packages/core/src/external/ehr/command/healthie/link-patient/healthie-link-patient-local.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/lambdas/src/ehr-get-appointments.ts
(1 hunks)packages/lambdas/src/ehr-sync-patient.ts
(1 hunks)packages/lambdas/src/elation-link-patient.ts
(1 hunks)packages/lambdas/src/healthie-link-patient.ts
(1 hunks)packages/lambdas/src/shared/ehr.ts
(2 hunks)
✅ Files skipped from review due to trivial changes (10)
- packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts
- packages/core/src/external/ehr/command/healthie/link-patient/healthie-link-patient-cloud.ts
- packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts
- packages/core/src/external/ehr/command/healthie/link-patient/healthie-link-patient-local.ts
- packages/core/src/external/ehr/command/healthie/link-patient/healthie-link-patient-factory.ts
- packages/core/src/external/ehr/command/elation/link-patient/elation-link-patient-factory.ts
- packages/core/src/external/ehr/command/elation/link-patient/elation-link-patient-local.ts
- packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-factory.ts
- packages/core/src/external/ehr/command/elation/link-patient/elation-link-patient-cloud.ts
- packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments.ts
🚧 Files skipped from review as they are similar to previous changes (9)
- packages/lambdas/src/healthie-link-patient.ts
- packages/api/src/routes/internal/jwt-token/index.ts
- packages/lambdas/src/elation-link-patient.ts
- packages/lambdas/src/ehr-sync-patient.ts
- packages/lambdas/src/ehr-get-appointments.ts
- packages/lambdas/src/shared/ehr.ts
- packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
- packages/api/src/external/ehr/shared/utils/client.ts
- packages/api/src/external/ehr/shared/utils/secrets.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/command/appointment/get-appointments/ehr-get-appointments-factory.ts
packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-cloud.ts
packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-direct.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
- 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)
🔇 Additional comments (7)
packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-factory.ts (2)
6-12
: LGTM! Clean factory pattern implementation.The factory function correctly implements environment-based handler selection with clear separation between development and production environments. The implementation follows the coding guidelines with proper camelCase naming and functional programming principles.
10-11
:✅ Verification successful
Verify Config.getEhrGetAppointmentsLambdaName() error handling.
Ensure that
Config.getEhrGetAppointmentsLambdaName()
properly handles cases where the Lambda name is not configured, as this could cause runtime failures in production.
🏁 Script executed:
#!/bin/bash # Description: Check how Config.getEhrGetAppointmentsLambdaName() handles missing configuration # Expected: Should find error handling or default value logic ast-grep --pattern 'getEhrGetAppointmentsLambdaName() { $$$ }'Length of output: 66
🏁 Script executed:
#!/bin/bash # Locate the definition and usage of getEhrGetAppointmentsLambdaName in the codebase rg -n "getEhrGetAppointmentsLambdaName" -C3 .Length of output: 1443
🏁 Script executed:
#!/bin/bash # Inspect the implementation of getEnvVarOrFail to confirm its error handling behavior rg -n "getEnvVarOrFail" -C5 packages/core/src/util/config.tsLength of output: 6893
🏁 Script executed:
#!/bin/bash # Inspect getEnvVarOrFail implementation for error handling behavior rg -n "getEnvVarOrFail" -C5 packages/core/src/util/env-var.tsLength of output: 877
No action needed: Config.getEhrGetAppointmentsLambdaName already fails fast on missing config
The factory method delegates togetEnvVarOrFail("EHR_GET_APPOINTMENTS_LAMBDA_NAME")
, which throws a clear error if the env var is undefined or empty. This ensures the Lambda name is always present at runtime.packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-cloud.ts (2)
14-20
: Well-designed constructor with dependency injection.The constructor properly handles optional parameters with sensible defaults. The dependency injection pattern allows for testing while maintaining clean defaults for production use.
22-44
: Robust Lambda invocation with proper error handling.The implementation correctly uses:
- Network retries for resilience
- Synchronous Lambda invocation
- Proper logging with customer context
- Default response handler for error processing
- Graceful handling of empty results
The async/await pattern and error handling follow the coding guidelines.
packages/core/src/external/ehr/command/appointment/get-appointments/ehr-get-appointments-direct.ts (3)
8-14
: Clean implementation with proper validation.The method correctly:
- Validates appointment methods using type guards
- Delegates to appropriate handlers
- Uses destructuring for clean parameter handling
- Follows functional programming principles
19-25
: Well-designed enum and validation pattern.The enum follows PascalCase naming for the enum itself and camelCase for values. The type guard function properly validates method strings against the enum values.
27-47
: Excellent type-safe handler mapping design.The handler map provides:
- Complete coverage of all EHR sources
- Type safety with specific method signatures
- Clear indication of unsupported sources with
undefined
- Proper typing for Canvas implementation
This design makes it easy to add new handlers while maintaining type safety.
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>
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
Outdated
Show resolved
Hide resolved
… 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>
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: 3
🔭 Outside diff range comments (1)
packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-local.ts (1)
88-90
: 🛠️ Refactor suggestionFix multi-line logging to comply with coding guidelines.
The current logging approach violates the coding guideline that states "Avoid multi-line logs". The log message spans multiple lines which should be consolidated.
Apply this diff to fix the logging:
- out( - `computeResourceDiffBundles - metriportPatientId ${metriportPatientId} ehrPatientId ${ehrPatientId} resourceType ${resourceType}` - ).log(`Error creating metriport and ehr bundles. Cause: ${errorToString(error)}`); + out().log( + `computeResourceDiffBundles - metriportPatientId ${metriportPatientId} ehrPatientId ${ehrPatientId} resourceType ${resourceType} - Error creating metriport and ehr bundles. Cause: ${errorToString(error)}` + );
🧹 Nitpick comments (1)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (1)
12-18
: Consider type safety improvement for handler result casting.The type casting
as T[]
on line 17 assumes the handler always returns compatible types. While this may work with current handlers, it could become unsafe if handlers return incompatible appointment types in the future.Consider adding runtime validation or using more specific typing to ensure type safety:
async getAppointments<T extends Appointment>({ method, ...params }: GetAppointmentsRequest): Promise<T[]> { const handler = getEhrGetAppointmentsHandler(method); - return (await handler({ ...params })) as T[]; + const result = await handler({ ...params }); + // Consider adding runtime validation here if needed + return result as T[]; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (26)
packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
(3 hunks)packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts
(1 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/core/src/external/ehr/canvas/command/get-appointments.ts
(1 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/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/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/index.ts
(1 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-resource-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
(3 hunks)packages/lambdas/src/ehr-get-appointments.ts
(1 hunks)packages/lambdas/src/shared/ehr.ts
(2 hunks)
✅ Files skipped from review due to trivial changes (13)
- packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-factory.ts
- packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-cloud.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-local.ts
- packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-factory.ts
- packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-cloud.ts
- packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-factory.ts
- packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-cloud.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-local.ts
- packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-local.ts
- packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts
- packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts
- packages/core/src/external/ehr/healthie/index.ts
- packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
- packages/core/src/external/ehr/canvas/command/get-appointments.ts
- packages/lambdas/src/ehr-get-appointments.ts
- packages/core/src/external/ehr/shared.ts
- packages/lambdas/src/shared/ehr.ts
- packages/api/src/external/ehr/healthie/shared.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-local.ts
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-factory.ts
packages/core/src/external/ehr/canvas/shared.ts
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts
🧬 Code Graph Analysis (3)
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-45)
packages/core/src/external/ehr/canvas/shared.ts (2)
packages/core/src/external/ehr/shared.ts (1)
getSecretsOauthSchema
(38-42)packages/core/src/external/ehr/api/get-token-info.ts (1)
getTokenInfo
(17-39)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (3)
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/lambdas/src/ehr-get-appointments.ts (1)
handler
(18-38)packages/shared/src/index.ts (1)
BadRequestError
(40-40)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: check-pr / lint-build-test
- GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
packages/core/src/external/ehr/canvas/shared.ts (1)
7-30
: LGTM! Clean implementation with good parameter destructuring.The function correctly implements the Canvas client creation pattern:
- Proper parameter destructuring following coding guidelines
- Appropriate conditional token info fetching
- Clean integration with the secrets and token info APIs
The error handling is appropriately delegated to the underlying
getSecrets
andgetTokenInfo
functions, which will bubble up any failures with proper context.packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts (1)
11-20
: LGTM! Good use of dependency injection pattern.The constructor properly implements dependency injection for the Lambda client with sensible defaults:
- Uses provided client or creates one with appropriate region configuration
- Follows the coding guidelines for constructor parameter handling
- Maintains good separation of concerns
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (1)
25-35
: LGTM! Excellent extensible mapping pattern with proper error handling.The implementation provides:
- Clean mapping from appointment methods to handlers
- Proper error handling with contextual information
- Extensible design for adding new appointment methods
- Good use of
BadRequestError
with method context for debuggingThis pattern makes it easy to add support for additional EHR systems in the future.
...hr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-local.ts
Show resolved
Hide resolved
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-factory.ts
Show resolved
Hide resolved
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts
Show resolved
Hide resolved
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>
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: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
packages/lambdas/src/ehr-compute-resource-diff-bundles.ts
(1 hunks)packages/lambdas/src/ehr-refresh-ehr-bundles.ts
(1 hunks)packages/lambdas/src/elation-link-patient.ts
(1 hunks)packages/lambdas/src/healthie-link-patient.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- packages/lambdas/src/ehr-refresh-ehr-bundles.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/lambdas/src/elation-link-patient.ts
- packages/lambdas/src/healthie-link-patient.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/lambdas/src/ehr-compute-resource-diff-bundles.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
- 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)
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>
… 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>
const result = await this.lambdaClient | ||
.invoke({ | ||
FunctionName: this.ehrGetAppointmentsLambdaName, | ||
InvocationType: "RequestResponse", | ||
Payload: payload, | ||
}) | ||
.promise() | ||
.then( | ||
defaultLambdaInvocationResponseHandler({ | ||
lambdaName: this.ehrGetAppointmentsLambdaName, | ||
}) | ||
); |
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.
We shouldn't mix promise chaining with await-based code. I added an item in the code standards about this (should have it there a long time ago! 😄)
const ehrGetAppointmentsMap: AppointmentMethodsMap = { | ||
[AppointmentMethods.canvasGetAppointments]: getAppointmentsCanvas, | ||
}; |
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.
This is not ideal, as we're adding EHR-specific information in the global EHR code.
Not a blocker for now, but I'd create an issue to map this and add a TODO here.
Example of solution: could have a "setup" step/function so that each EHR implementation is required to pass certain functions to that code, and that effectively initializes the EHR global code so it can direct the execution flow to said functions based on the context/parameters of the execution.
export enum AppointmentMethods { | ||
canvasGetAppointments = "canvasGetAppointments", | ||
} |
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.
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.
Can't we move this to core and have the respective env functions there as well? None require DB access, so that's one less hit to the API and we keep the EHR code mode concentrated in core.
syncPatient: QueueAndLambdaSettings; | ||
elationLinkPatient: QueueAndLambdaSettings; | ||
healthieLinkPatient: QueueAndLambdaSettings; | ||
computeResourceDiffBundles: QueueAndLambdaSettings; | ||
refreshEhrBundles: QueueAndLambdaSettings; | ||
} { | ||
const getAppointmentsLambdaTimeout = Duration.minutes(12); |
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.
OOC, why 12 and not 15min? Super close to the limit, might as well give it more time so it doesn't fail after 12 min?
name: "EhrGetAppointments", | ||
entry: "ehr-get-appointments", | ||
lambda: { | ||
memory: 4096, |
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.
Needs that much RAM? No worries if it does, just wondering about the thought process, as this impact cost.
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.
I thought we had an example, but it's just a lambda's CSS. Could try w/ branch to staging, this would set an important improvement for code organization.
I thought I tried this but I don't remember now. This seem promising.
// Automatically set by AWS | ||
const lambdaName = getEnvOrFail("AWS_LAMBDA_FUNCTION_NAME"); | ||
|
||
// TODO move to capture.wrapHandler() |
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.
remove left-over
const message = getSingleMessageOrFail(event.Records, lambdaName); | ||
if (!message) return; | ||
|
||
console.log(`Running with unparsed body: ${message.body}`); |
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.
need to log the body?
const { method, cxId, practiceId } = parsedBody; | ||
|
||
const log = prefixedLog(`method ${method}, cxId ${cxId}, practiceId ${practiceId}`); | ||
log(`Parsed: ${JSON.stringify(parsedBody)}`); |
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.
ditto
Ref: ENG-292
Issues:
Dependencies
Description
ENTRYPONT: Canvas
process-patients-from-appointments.ts
Testing
Release Plan
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Chores