8000 RELEASE moving get appointments to lambdas + canvas fixes by thomasyopes · Pull Request #3960 · metriport/metriport · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

RELEASE moving get appointments to lambdas + canvas fixes #3960

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 65 commits into from
Jun 5, 2025
Merged

Conversation

thomasyopes
Copy link
Contributor
@thomasyopes thomasyopes commented Jun 5, 2025

Issues:

Description

Testing

Check each PR.

Release Plan

  • ⚠️ Points to master
  • Merge this

Summary by CodeRabbit

  • New Features
    • Introduced a new API endpoint to retrieve practice secrets for EHR integrations.
    • Added an API endpoint to fetch JWT token details by ID.
    • Enabled appointment retrieval from EHR systems through a new Lambda function and supporting API endpoint.
    • Enhanced support for dynamic secret retrieval for EHR integrations.
  • Improvements
    • Improved error handling and validation for EHR API requests, especially for FHIR validation errors.
    • Added throttling (delays) to paginated EHR API requests to manage request rates.
    • Refactored EHR environment and credential management for better modularity and reliability.
    • Expanded JWT token information to include token IDs.
  • Bug Fixes
    • Corrected date range calculations for appointment lookups.
  • Chores
    • Updated and reorganized import paths and internal structure for better maintainability.
    • Removed deprecated or unused static configuration methods.

Thomas Yopes added 30 commits May 19, 2025 16:55
Ref: ENG-292

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5

Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5

Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5

Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5

Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Thomas Yopes and others added 17 commits June 3, 2025 04:44
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5

Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
… 199-elation-contribution-1.5

Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
Ref: ENG-199

Ref: #1040
Signed-off-by: Thomas Yopes <thomasyopes@Thomass-MBP.attlocal.net>
feat(ehr): moving get-appointments for Canvas to lambda
Copy link
coderabbitai bot commented Jun 5, 2025

Walkthrough

This update introduces a new system for retrieving and managing EHR environment credentials and secrets, centralizing environment-specific logic into dedicated modules. It adds new Lambda infrastructure for appointment retrieval, enhances error handling (notably for FHIR validation), and refactors client creation to return additional metadata. Internal API routes for JWT token and practice secret retrieval are added, and legacy static configuration accessors are removed.

Changes

File(s) / Group Change Summary
packages/api/src/external/ehr/*/shared.ts, packages/api/src/external/ehr/shared/utils/client.ts, packages/core/src/external/ehr/environment.ts, packages/core/src/external/ehr/command/get-secrets.ts, packages/core/src/external/ehr/athenahealth/environment.ts, packages/core/src/external/ehr/canvas/environment.ts, packages/core/src/external/ehr/elation/environment.ts, packages/core/src/external/ehr/healthie/environment.ts, packages/core/src/external/ehr/eclinicalworks/environment.ts Refactored EHR environment and credential retrieval into dedicated modules; removed legacy inline logic; centralized type definitions for EHR environments and client credentials.
packages/api/src/external/ehr/*/shared.ts, packages/api/src/external/ehr/shared/utils/client.ts Updated client creation functions to return additional metadata (tokenId, environment); split into two-step creation (with/without metadata).
packages/api/src/external/ehr/*/command/process-patients-from-appointments.ts, packages/api/src/routes/ehr/*/patient-webhook.ts, packages/api/src/routes/ehr/*/appointment-webhook.ts, packages/api/src/routes/ehr/canvas/patient-webhook.ts, packages/api/src/routes/ehr/util.ts Updated import paths for shared handlers and utilities; minor refactors to control flow (e.g., curly braces).
packages/api/src/external/ehr/shared/utils/appointment.ts Fixed time range calculation to correctly apply offset and look-forward durations.
packages/api/src/routes/internal/ehr/practice.ts, packages/api/src/routes/internal/ehr/index.ts Added new internal route for retrieving practice secrets by EHR and practice ID.
packages/api/src/routes/internal/jwt-token/token.ts, packages/api/src/routes/internal/jwt-token/index.ts Added new internal route for retrieving JWT token info by token ID.
packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts, packages/lambdas/src/ehr/compute-resource-diff-bundles.ts, packages/lambdas/src/ehr/refresh-ehr-bundles.ts, packages/lambdas/src/ehr/sync-patient.ts, packages/lambdas/src/ehr/elation/elation-link-patient.ts, packages/lambdas/src/ehr/healthie/healthie-link-patient.ts, packages/lambdas/src/shared/ehr.ts Updated import paths to reflect new directory structure for commands and shared modules.
packages/core/src/external/ehr/shared.ts, packages/shared/src/interface/external/ehr/fhir-resource.ts Enhanced error handling: added FHIR OperationOutcome schemas, improved detection and handling of FHIR validation errors, and updated error propagation in request utilities.
packages/core/src/external/ehr/command/get-appointments/*, packages/core/src/external/ehr/canvas/command/get-appointments.ts Introduced new appointment retrieval abstraction: command handler interface, direct and Lambda-backed implementations, and factory; added Canvas appointment retrieval logic.
packages/core/src/external/ehr/api/get-client-key-and-secret.ts, packages/core/src/external/ehr/api/get-token-info.ts Added API clients for dynamic retrieval of secrets and token info from external services.
packages/core/src/external/ehr/command/sync-patient/*, packages/core/src/external/ehr/elation/command/link-patient/*, packages/core/src/external/ehr/healthie/command/link-patient/*, packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/* Updated import paths for config and shared utilities to match revised directory structure.
packages/core/src/external/ehr/canvas/data.ts Removed legacy fake FHIR bundle and resource data generators.
packages/core/src/external/ehr/athenahealth/index.ts, packages/core/src/external/ehr/canvas/index.ts, packages/core/src/external/ehr/elation/index.ts, packages/core/src/external/ehr/healthie/index.ts Introduced delays between paginated API requests to throttle request rates.
packages/core/src/util/config.ts, packages/api/src/shared/config.ts Migrated EHR environment variable accessors from API config to core config; removed static methods from API config, added to core config.
packages/core/src/external/aws/lambda.ts Added explicit Lambda client type alias and return type annotation.
packages/shared/src/domain/jwt-token.ts Added optional id property to JwtTokenInfo type.
packages/infra/lib/api-stack.ts, packages/infra/lib/api-stack/api-service.ts, packages/infra/lib/ehr-nested-stack.ts Added new Lambda for appointment retrieval; updated stack and service definitions to wire up Lambda, permissions, and environment variables.
packages/lambdas/src/ehr/get-appointments.ts Added new Lambda handler for appointment retrieval, supporting date parsing and direct handler invocation.

Sequence Diagram(s)

Dynamic EHR Secret Retrieval

sequenceDiagram
    participant API as API Route
    participant getSecrets as getSecrets (core)
    participant EnvModule as EHR Env Module
    participant Config as Config

    API->>getSecrets: getSecrets({ehr, cxId, practiceId})
    getSecrets->>EnvModule: getEhrEnv({cxId, practiceId})
    EnvModule->>Config: getEnvVar(s)
    Config-->>EnvModule: env value(s)
    EnvModule-->>getSecrets: { environment, clientKey, clientSecret } or { environment, apiKey }
    getSecrets-->>API: EHR secrets
Loading

Appointment Retrieval via Lambda

sequenceDiagram
    participant API as API Route
    participant Handler as EhrGetAppointmentsHandler
    participant Lambda as getAppointments Lambda
    participant Direct as EhrGetAppointmentsDirect

    API->>Handler: getAppointments(request)
    alt Cloud
        Handler->>Lambda: Invoke Lambda with request
        Lambda->>Direct: getAppointments(request)
        Direct->>...: Fetch appointments from EHR
        Direct-->>Lambda: Appointments[]
        Lambda-->>Handler: Appointments[]
    else Dev
        Handler->>Direct: getAppointments(request)
        Direct->>...: Fetch appointments from EHR
        Direct-->>Handler: Appointments[]
    end
    Handler-->>API: Appointments[]
Loading

Enhanced Error Handling for FHIR Validation

sequenceDiagram
    participant Client as EHR Client
    participant makeRequest as makeRequest Utility
    participant FHIR as FHIR API

    Client->>makeRequest: makeRequest(params)
    makeRequest->>FHIR: HTTP Request
    FHIR-->>makeRequest: Error Response (OperationOutcome)
    makeRequest->>makeRequest: isFhirValidationError(error)
    alt Is FHIR Validation Error
        makeRequest-->>Client: Throw NotFoundError
    else
        makeRequest-->>Client: Throw original error
    end
Loading

Possibly related PRs

  • metriport/metriport#3682: Introduces patient job management and asynchronous job creation/retrieval for Canvas resource diff bundles, directly related to EHR job and bundle handling refactors in this PR.
  • metriport/metriport#3873: Refactors import paths and client creation for EHR integrations, adds Canvas get-appointments Lambda and related command handler, overlapping with the main code-level changes here.
  • metriport/metriport#3714: Implements job-based Canvas resource diff bundle processing and new API endpoints, integrating with EHR command and job handling logic refactored in this PR.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error code ERR_SSL_WRONG_VERSION_NUMBER
npm error errno ERR_SSL_WRONG_VERSION_NUMBER
npm error request to https://10.0.0.28:4873/punycode/-/punycode-2.3.1.tgz failed, reason: C07C6B38977F0000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:354:
npm error
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-05T16_06_43_687Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate t 6D47 he high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
packages/core/src/external/ehr/canvas/environment.ts (1)

14-22: Consider extracting the key construction pattern.

The key construction follows a consistent pattern (${cxId}_${practiceId}_suffix) that's repeated three times. Consider extracting this into a helper function to reduce duplication and improve maintainability.

+function buildCanvasConfigKey(cxId: string, practiceId: string, suffix: string): string {
+  return `${cxId}_${practiceId}_${suffix}`;
+}
+
 export function getCanvasEnv({
   cxId,
   practiceId,
 }: EhrPerPracticeParams): EhrEnvAndClientCredentials<CanvasEnv> {
   const rawClientsMap = Config.getCanvasClientKeyAndSecretMap();
   if (!rawClientsMap) throw new MetriportError("Canvas secrets map not set");
   const clientMap = cxClientKeyAndSecretMapSecretSchema.safeParse(JSON.parse(rawClientsMap));
   if (!clientMap.success) throw new MetriportError("Canvas clients map has invalid format");
-  const env = `${cxId}_${practiceId}_env`;
+  const env = buildCanvasConfigKey(cxId, practiceId, "env");
   const envEntry = clientMap.data[env];
-  const key = `${cxId}_${practiceId}_key`;
+  const key = buildCanvasConfigKey(cxId, practiceId, "key");
   const keyEntry = clientMap.data[key];
-  const secret = `${cxId}_${practiceId}_secret`;
+  const secret = buildCanvasConfigKey(cxId, practiceId, "secret");
   const secretEntry = clientMap.data[secret];
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts (1)

15-17: Interface design enables polymorphism but consider method naming.

The generic interface design is good for extensibility. However, consider whether the method name getAppointments could be more specific since it's handling different appointment methods internally.

If this interface will handle multiple distinct appointment retrieval strategies, consider renaming to handleAppointmentRequest or similar to reflect the method dispatching:

export interface EhrGetAppointmentsHandler {
-  getAppointments<T extends Appointment>(request: GetAppointmentsRequest): Promise<T[]>;
+  handleAppointmentRequest<T extends Appointment>(request: GetAppointmentsRequest): Promise<T[]>;
}
packages/infra/lib/ehr-nested-stack.ts (1)

266-296: Fix method naming and verify bucket permissions.

The implementation follows the established pattern, but there's a minor naming issue and the bucket permissions should be verified.

-  private setupGetAppointmentslambda(ownProps: {
+  private setupGetAppointmentsLambda(ownProps: {

Also verify that grantWrite permissions are sufficient for the ehrResponsesBucket usage pattern.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9736626 and 498081a.

📒 Files selected for processing (73)
  • packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts (1 hunks)
  • packages/api/src/external/ehr/athenahealth/shared.ts (1 hunks)
  • packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts (3 hunks)
  • packages/api/src/external/ehr/canvas/shared.ts (1 hunks)
  • packages/api/src/external/ehr/eclinicalworks/shared.ts (1 hunks)
  • packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts (1 hunks)
  • packages/api/src/external/ehr/elation/shared.ts (4 hunks)
  • packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts (3 hunks)
  • packages/api/src/external/ehr/healthie/shared.ts (2 hunks)
  • packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts (1 hunks)
  • packages/api/src/external/ehr/shared/utils/appointment.ts (1 hunks)
  • packages/api/src/external/ehr/shared/utils/client.ts (4 hunks)
  • packages/api/src/routes/ehr/canvas/patient-webhook.ts (1 hunks)
  • packages/api/src/routes/ehr/elation/appointment-webhook.ts (1 hunks)
  • packages/api/src/routes/ehr/elation/patient-webhook.ts (1 hunks)
  • packages/api/src/routes/ehr/healthie/appointment-webhook.ts (1 hunks)
  • packages/api/src/routes/ehr/healthie/patient-webhook.ts (1 hunks)
  • packages/api/src/routes/ehr/util.ts (1 hunks)
  • packages/api/src/routes/internal/ehr/index.ts (2 hunks)
  • packages/api/src/routes/internal/ehr/practice.ts (1 hunks)
  • packages/api/src/routes/internal/jwt-token/index.ts (2 hunks)
  • packages/api/src/routes/internal/jwt-token/token.ts (1 hunks)
  • packages/api/src/shared/config.ts (0 hunks)
  • packages/core/src/external/aws/lambda.ts (1 hunks)
  • packages/core/src/external/ehr/api/get-client-key-and-secret.ts (1 hunks)
  • packages/core/src/external/ehr/api/get-token-info.ts (1 hunks)
  • packages/core/src/external/ehr/athenahealth/environment.ts (1 hunks)
  • packages/core/src/external/ehr/athenahealth/index.ts (3 hunks)
  • packages/core/src/external/ehr/canvas/command/get-appointments.ts (1 hunks)
  • packages/core/src/external/ehr/canvas/data.ts (0 hunks)
  • packages/core/src/external/ehr/canvas/environment.ts (1 hunks)
  • packages/core/src/external/ehr/canvas/index.ts (5 hunks)
  • packages/core/src/external/ehr/canvas/shared.ts (1 hunks)
  • packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts (1 hunks)
  • packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (1 hunks)
  • packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-factory.ts (1 hunks)
  • packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts (1 hunks)
  • packages/core/src/external/ehr/command/get-secrets.ts (1 hunks)
  • packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts (1 hunks)
  • packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-factory.ts (1 hunks)
  • packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts (1 hunks)
  • packages/core/src/external/ehr/eclinicalworks/environment.ts (1 hunks)
  • packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-cloud.ts (1 hunks)
  • packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-factory.ts (1 hunks)
  • packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-local.ts (1 hunks)
  • packages/core/src/external/ehr/elation/environment.ts (1 hunks)
  • packages/core/src/external/ehr/elation/index.ts (3 hunks)
  • packages/core/src/external/ehr/environment.ts (1 hunks)
  • packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-cloud.ts (1 hunks)
  • packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-factory.ts (1 hunks)
  • packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-local.ts (1 hunks)
  • packages/core/src/external/ehr/healthie/environment.ts (1 hunks)
  • packages/core/src/external/ehr/healthie/index.ts (3 hunks)
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-cloud.ts (1 hunks)
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-r 9E81 esource-diff-bundles-factory.ts (1 hunks)
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-local.ts (1 hunks)
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-cloud.ts (1 hunks)
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-factory.ts (1 hunks)
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-local.ts (1 hunks)
  • packages/core/src/external/ehr/shared.ts (6 hunks)
  • packages/core/src/util/config.ts (1 hunks)
  • packages/infra/lib/api-stack.ts (4 hunks)
  • packages/infra/lib/api-stack/api-service.ts (4 hunks)
  • packages/infra/lib/ehr-nested-stack.ts (10 hunks)
  • packages/lambdas/src/ehr/compute-resource-diff-bundles.ts (1 hunks)
  • packages/lambdas/src/ehr/elation/elation-link-patient.ts (1 hunks)
  • packages/lambdas/src/ehr/get-appointments.ts (1 hunks)
  • packages/lambdas/src/ehr/healthie/healthie-link-patient.ts (1 hunks)
  • packages/lambdas/src/ehr/refresh-ehr-bundles.ts (1 hunks)
  • packages/lambdas/src/ehr/sync-patient.ts (1 hunks)
  • packages/lambdas/src/shared/ehr.ts (1 hunks)
  • packages/shared/src/domain/jwt-token.ts (1 hunks)
  • packages/shared/src/interface/external/ehr/fhir-resource.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • packages/api/src/shared/config.ts
  • packages/core/src/external/ehr/canvas/data.ts
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.ts`: - Use the Onion Pattern to organize a package's code in layers - Try to use immutable code and avoid sharing state across different functions, objects, and systems - Try...

**/*.ts: - Use the Onion Pattern to organize a package's code in layers

  • Try to use immutable code and avoid sharing state across different functions, objects, and systems
  • Try to build code that's idempotent whenever possible
  • Prefer functional programming style functions: small, deterministic, 1 input, 1 output
  • Minimize coupling / dependencies
  • Avoid modifying objects received as parameter
  • Only add comments to code to explain why something was done, not how it works
  • Naming
    • classes, enums: PascalCase
    • constants, variables, functions: camelCase
    • file names: kebab-case
    • table and column names: snake_case
    • Use meaningful names, so whoever is reading the code understands what it means
    • Don’t use negative names, like notEnabled, prefer isDisabled
    • For numeric values, if the type doesn’t convey the unit, add the unit to the name
  • Typescript
    • Use types
    • Prefer const instead of let
    • Avoid any and casting from any 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 to undefined 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 (see processAsyncError and emptyFunction depending on the case)
    • Date and Time
      • Always use buildDayjs() to create dayjs instances
      • Prefer dayjs.duration(...) to create duration consts and keep them as duration
  • 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) not if ('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 and console.error in packages other than utils, infra and shared,
    and try to use out().log instead
  • Avoid multi-line logs
    • don't send objects as a second parameter to console.log() or out().log()
    • don't create multi-line strings when using JSON.stringify()
  • Use eslint to enforce code style
  • Use prettier to format code
  • max column length is 100 chars
  • multi-line comments use /** */
  • scripts: top-level comments go after the import
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-factory.ts
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-factory.ts
  • packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-factory.ts
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-cloud.ts
  • packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-factory.ts
  • packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-cloud.ts
  • packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts
  • packages/shared/src/domain/jwt-token.ts
  • packages/api/src/routes/ehr/healthie/patient-webhook.ts
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-cloud.ts
  • packages/api/src/routes/ehr/util.ts
  • packages/api/src/routes/ehr/canvas/patient-webhook.ts
  • packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-local.ts
  • packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-factory.ts
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-local.ts
  • packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-local.ts
  • packages/lambdas/src/ehr/elation/elation-link-patient.ts
  • packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-cloud.ts
  • packages/api/src/routes/ehr/elation/appointment-webhook.ts
  • packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts
  • packages/lambdas/src/ehr/healthie/healthie-link-patient.ts
  • packages/core/src/external/ehr/healthie/index.ts
  • packages/api/src/routes/ehr/elation/patient-webhook.ts
  • packages/api/src/routes/ehr/healthie/appointment-webhook.ts
  • packages/api/src/external/ehr/shared/utils/appointment.ts
  • packages/lambdas/src/ehr/sync-patient.ts
  • packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts
  • packages/api/src/routes/internal/ehr/index.ts
  • packages/api/src/routes/internal/jwt-token/index.ts
  • packages/core/src/external/ehr/canvas/shared.ts
  • packages/lambdas/src/shared/ehr.ts
  • packages/api/src/routes/internal/jwt-token/token.ts
  • packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts
  • packages/infra/lib/api-stack.ts
  • packages/core/src/external/ehr/athenahealth/environment.ts
  • packages/api/src/external/ehr/eclinicalworks/shared.ts
  • packages/core/src/external/ehr/athenahealth/index.ts
  • packages/lambdas/src/ehr/compute-resource-diff-bundles.ts
  • packages/core/src/external/ehr/elation/index.ts
  • packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts
  • packages/lambdas/src/ehr/get-appointments.ts
  • packages/core/src/external/ehr/eclinicalworks/environment.ts
  • packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts
  • packages/core/src/external/aws/lambda.ts
  • packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-factory.ts
  • packages/api/src/routes/internal/ehr/practice.ts
  • packages/core/src/external/ehr/canvas/command/get-appointments.ts
  • packages/core/src/external/ehr/canvas/environment.ts
  • packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts
  • packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-local.ts
  • packages/core/src/external/ehr/api/get-token-info.ts
  • packages/shared/src/interface/external/ehr/fhir-resource.ts
  • packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts
  • packages/lambdas/src/ehr/refresh-ehr-bundles.ts
  • packages/core/src/external/ehr/elation/environment.ts
  • packages/infra/lib/api-stack/api-service.ts
  • packages/core/src/external/ehr/api/get-client-key-and-secret.ts
  • packages/api/src/external/ehr/elation/shared.ts
  • packages/api/src/external/ehr/healthie/shared.ts
  • packages/core/src/external/ehr/healthie/environment.ts
  • packages/api/src/external/ehr/athenahealth/shared.ts
  • packages/api/src/external/ehr/canvas/shared.ts
  • packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts
  • packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts
  • packages/core/src/external/ehr/shared.ts
  • packages/core/src/external/ehr/environment.ts
  • packages/core/src/external/ehr/command/get-secrets.ts
  • packages/infra/lib/ehr-nested-stack.ts
  • packages/core/src/external/ehr/canvas/index.ts
  • packages/api/src/external/ehr/shared/utils/client.ts
  • packages/core/src/util/config.ts
🧠 Learnings (4)
packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts (1)
Learnt from: thomasyopes
PR: metriport/metriport#3427
File: packages/core/src/external/ehr/api/sync-patient.ts:16-55
Timestamp: 2025-03-11T20:42:46.516Z
Learning: In the patient synchronization architecture, the flow follows this pattern: (1) `ehr-sync-patient-cloud.ts` sends messages to an SQS queue, (2) the `ehr-sync-patient` Lambda consumes these messages, and (3) the Lambda uses the `syncPatient` function to make the API calls to process the patient data.
packages/lambdas/src/ehr/sync-patient.ts (1)
Learnt from: thomasyopes
PR: metriport/metriport#3427
File: packages/core/src/external/ehr/api/sync-patient.ts:16-55
Timestamp: 2025-03-11T20:42:46.516Z
Learning: In the patient synchronization architecture, the flow follows this pattern: (1) `ehr-sync-patient-cloud.ts` sends messages to an SQS queue, (2) the `ehr-sync-patient` Lambda consumes these messages, and (3) the Lambda uses the `syncPatient` function to make the API calls to process the patient data.
packages/lambdas/src/ehr/get-appointments.ts (1)
Learnt from: thomasyopes
PR: metriport/metriport#3873
File: packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts:40-43
Timestamp: 2025-05-29T16:53:26.064Z
Learning: The EHR get-appointments Lambda function is designed to always return parseable JSON responses, so additional error handling for JSON.parse() is not required when processing its results.
packages/core/src/external/ehr/healthie/environment.ts (1)
Learnt from: thomasyopes
PR: metriport/metriport#3771
File: packages/api/src/routes/internal/ehr/healthie/secret-key.ts:24-31
Timestamp: 2025-05-01T16:11:28.575Z
Learning: The function `getHealthieSecretKeyInfo` in the Healthie EHR integration throws appropriate MetriportErrors when required data is missing, so it will never return undefined or an empty object.
🧬 Code Graph Analysis (18)
packages/api/src/routes/ehr/util.ts (1)
packages/shared/src/index.ts (1)
  • BadRequestError (40-40)
packages/core/src/external/ehr/healthie/index.ts (2)
packages/shared/src/index.ts (1)
  • sleep (13-13)
packages/core/src/external/ehr/shared.ts (1)
  • paginateWaitTime (35-35)
packages/api/src/external/ehr/shared/utils/appointment.ts (1)
packages/shared/src/common/date.ts (1)
  • buildDayjs (70-72)
packages/api/src/routes/internal/ehr/index.ts (1)
packages/api/src/routes/internal/ehr/middleware.ts (1)
  • processEhrId (6-11)
packages/core/src/external/ehr/athenahealth/environment.ts (3)
packages/core/src/external/ehr/environment.ts (1)
  • EhrEnvAndClientCredentials (9-13)
packages/core/src/external/ehr/athenahealth/index.ts (2)
  • AthenaEnv (95-95)
  • isAthenaEnv (96-98)
packages/core/src/util/config.ts (1)
  • Config (9-254)
packages/core/src/external/ehr/athenahealth/index.ts (2)
packages/shared/src/index.ts (1)
  • sleep (13-13)
packages/core/src/external/ehr/shared.ts (1)
  • paginateWaitTime (35-35)
packages/core/src/external/ehr/elation/index.ts (2)
packages/shared/src/index.ts (1)
  • sleep (13-13)
packages/core/src/external/ehr/shared.ts (1)
  • paginateWaitTime (35-35)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-factory.ts (3)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts (1)
  • EhrGetAppointmentsHandler (15-17)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (1)
  • EhrGetAppointmentsDirect (11-19)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts (1)
  • EhrGetAppointmentsCloud (11-43)
packages/core/src/external/ehr/api/get-token-info.ts (4)
packages/shared/src/domain/jwt-token.ts (1)
  • JwtTokenInfo (1-5)
packages/core/src/util/config.ts (1)
  • Config (9-254)
packages/shared/src/net/retry.ts (1)
  • executeWithNetworkRetries (108-135)
packages/core/src/external/ehr/api/api-shared.ts (1)
  • validateAndLogResponse (13-20)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (2)
packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts (4)
  • EhrGetAppointmentsHandler (15-17)
  • Appointment (19-19)
  • GetAppointmentsRequest (3-11)
  • GetAppointmentsClientRequest (13-13)
packages/shared/src/index.ts (1)
  • BadRequestError (40-40)
packages/core/src/external/ehr/elation/environment.ts (4)
packages/core/src/util/config.ts (2)
  • getElationEnv (233-235)
  • Config (9-254)
packages/core/src/external/ehr/environment.ts (2)
  • EhrPerPracticeParams (26-26)
  • EhrEnvAndClientCredentials (9-13)
packages/core/src/external/ehr/elation/index.ts (2)
  • ElationEnv (56-56)
  • isElationEnv (57-59)
packages/shared/src/domain/secrets.ts (1)
  • cxClientKeyAndSecretMapSecretSchema (3-3)
packages/api/src/external/ehr/elation/shared.ts (2)
packages/core/src/external/ehr/environment.ts (1)
  • EhrPerPracticeParams (26-26)
packages/core/src/external/ehr/elation/index.ts (1)
  • ElationEnv (56-56)
packages/api/src/external/ehr/healthie/shared.ts (4)
packages/core/src/external/ehr/environment.ts (1)
  • EhrPerPracticeParams (26-26)
packages/core/src/external/ehr/healthie/index.ts (1)
  • HealthieEnv (46-46)
packages/core/src/external/ehr/healthie/environment.ts (1)
  • getHealthieEnv (6-23)
packages/core/src/util/config.ts (1)
  • getHealthieEnv (244-246)
packages/api/src/external/ehr/athenahealth/shared.ts (4)
packages/core/src/external/ehr/environment.ts (1)
  • EhrPerPracticeParams (26-26)
packages/core/src/external/ehr/athenahealth/index.ts (1)
  • AthenaEnv (95-95)
packages/api/src/external/ehr/shared/utils/client.ts (1)
  • createEhrClient (38-72)
packages/core/src/external/ehr/athenahealth/environment.ts (1)
  • getAthenaEnv (6-20)
packages/core/src/external/ehr/environment.ts (6)
packages/core/src/external/ehr/athenahealth/index.ts (1)
  • AthenaEnv (95-95)
packages/core/src/external/ehr/elation/index.ts (1)
  • ElationEnv (56-56)
packages/core/src/external/ehr/canvas/index.ts (1)
  • CanvasEnv (82-82)
packages/core/src/external/ehr/healthie/index.ts (1)
  • HealthieEnv (46-46)
packages/core/src/external/ehr/eclinicalworks/index.ts (1)
  • EClinicalWorksEnv (15-15)
packages/shared/src/domain/jwt-token.ts (1)
  • JwtTokenInfo (1-5)
packages/core/src/external/ehr/command/get-secrets.ts (5)
packages/core/src/external/ehr/environment.ts (4)
  • EhrPerPracticeParams (26-26)
  • EhrEnvAndClientCredentials (9-13)
  • EhrEnv (8-8)
  • EhrEnvAndApiKey (15-18)
packages/shared/src/interface/external/ehr/source.ts (1)
  • EhrSource (9-9)
packages/core/src/external/ehr/canvas/environment.ts (1)
  • getCanvasEnv (6-28)
packages/core/src/external/ehr/athenahealth/environment.ts (1)
  • getAthenaEnv (6-20)
packages/shared/src/index.ts (1)
  • BadRequestError (40-40)
packages/core/src/external/ehr/canvas/index.ts (2)
packages/shared/src/index.ts (1)
  • sleep (13-13)
packages/core/src/external/ehr/shared.ts (1)
  • paginateWaitTime (35-35)
packages/api/src/external/ehr/shared/utils/client.ts (2)
packages/core/src/external/ehr/environment.ts (1)
  • EhrClientTwoLeggedAuthParams (21-24)
packages/api/src/command/jwt-token.ts (1)
  • findOrCreateJwtToken (11-21)
⏰ Context from checks skipped due to timeout of 90000ms (11)
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: Analyze (javascript)
  • GitHub Check: secrets_cdk_stack / deploy
  • GitHub Check: ihe_stack / deploy
  • GitHub Check: infra-api-lambdas / deploy
  • GitHub Check: mllp-server / deploy
  • GitHub Check: api / deploy
🔇 Additional comments (121)
packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-factory.ts (1)

1-1: Import path updated correctly
The relative path for Config has been adjusted to reflect the directory restructure. All usages remain consistent with coding conventions.

packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-cloud.ts (1)

3-4: Relative imports for Config and SQSClient corrected
The import paths for Config and SQSClient now point to their new locations. The change aligns with the reorganized folder structure and requires no further adjustments.

packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-factory.ts (1)

1-1: Config import path aligned with new structure
Updated the relative path for Config to match the directory move, maintaining consistency across EHR integrations.

packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-factory.ts (1)

1-1: Adjusted Config import relative path
The import path for Config has been shortened by one directory level to reflect the module reorganization.

packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-factory.ts (1)

1-1: Config import path simplification approved
Removed an extra directory in the import path for Config, consistent with other modules in this PR.

packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-local.ts (1)

3-3: Import path updated to reflect new module structure
The relative path now correctly targets the api/link-patient under the reorganized command directory.

packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-cloud.ts (1)

3-4: Deepened relative imports align with directory refactor
The updated paths for SQSClient and Config correctly follow the new command subdirectory hierarchy and maintain consistency with other EHR modules.

packages/api/src/routes/ehr/healthie/appointment-webhook.ts (1)

1-1: Adjusted import to new command factory location
The path for buildEhrSyncPatientHandler now matches the reorganized command/sync-patient layout.

packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-cloud.ts (1)

3-4: Import paths updated to new command hierarchy
The deeper relative imports for SQSClient and Config correctly mirror the refactored directory structure under command/link-patient.

packages/api/src/routes/ehr/canvas/patient-webhook.ts (1)

1-1: Updated sync-patient factory import path
The import for buildEhrSyncPatientHandler now targets the command/sync-patient namespace, keeping it consistent with other EHR integrations.

packages/core/src/external/ehr/healthie/command/link-patient/healthie-link-patient-cloud.ts (1)

3-4: Imports updated correctly after directory restructure
The revised relative paths for SQSClient and Config align with the new directory layout and maintain consistency with other EHR command modules.

packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-factory.ts (1)

1-1: Corrected the Config import path
The update to "../../../../util/config" properly reflects the moved directory depth without affecting functionality.

packages/api/src/routes/ehr/util.ts (1)

15-17: Added braces for the multi-line if block
Wrapping the throw in braces improves readability and avoids potential errors when extending the block.

packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-cloud.ts (1)

3-4: Adjusted import paths for Config and SQSClient
The shortened import paths correctly match the reorganized module structure without altering logic.

packages/api/src/routes/ehr/healthie/patient-webhook.ts (1)

1-1: Updated import to new sync-patient factory location
Importing from "@metriport/core/external/ehr/command/sync-patient/ehr-sync-patient-factory" aligns with the relocated module and retains all existing functionality.

packages/api/src/routes/ehr/elation/appointment-webhook.ts (1)

1-1: Align import path with command directory restructure.

The buildEhrSyncPatientHandler import has been correctly updated to the new command/sync-patient location, matching the broader EHR module reorganization.

packages/api/src/routes/ehr/elation/patient-webhook.ts (1)

1-1: Align import path with command directory restructure.

The buildEhrSyncPatientHandler import is now pointing to command/sync-patient, consistent with other EHR sync-patient handlers.

packages/shared/src/domain/jwt-token.ts (1)

4-4: Extend JwtTokenInfo with optional id.

Adding the optional id property aligns with downstream enhancements in token retrieval and management routes.

packages/core/src/external/ehr/elation/command/link-patient/elation-link-patient-local.ts (1)

3-3: Correct relative import for linkPatient.

Adjusted the path to ../../../api/link-patient to reflect the new directory structure under command.

packages/api/src/external/ehr/athenahealth/command/process-patients-from-appointments.ts (1)

2-2: Update import for sync-patient handler.

The import of buildEhrSyncPatientHandler now correctly references the command/sync-patient factory, aligning with the refactor across EHR integrations.

packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts (1)

2-2:

✅ Verification successful

Verify the updated import path exists.

The import path has been updated to remove the bundle/ directory segment. Ensure the module exists at the new location and the restructuring is complete.


🏁 Script executed:

#!/bin/bash
# Description: Verify the new import path exists and the old path no longer exists.

# Check if the new path exists
fd -t f "ehr-refresh-ehr-bundles-factory.ts" packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/

# Check if old path still exists (should not)
fd -t f "ehr-refresh-ehr-bundles-factory.ts" packages/core/src/external/ehr/bundle/job/create-resource-diff-bundles/steps/refresh/

Length of output: 540


Import path validation successful

The file ehr-refresh-ehr-bundles-factory.ts exists at the new location and the old path has been removed. No further action is required.

• packages/api/src/external/ehr/shared/job/bundle/create-resource-diff-bundles/start-job.ts: import path is correct and up to date.

packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts (1)

2-2:

✅ Verification successful

Verify the updated relative import path is correct.

The relative import path has been updated from ../api/sync-patient to ../../api/sync-patient, suggesting a directory restructuring. Ensure the target module exists at the expected location relative to this file.


🏁 Script executed:

#!/bin/bash
# Description: Verify the relative import path resolves correctly.

# Check the current file location and verify the target exists
current_file="packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts"
target_relative_to_current="../../api/sync-patient"

# Calculate absolute path and check if target exists
fd -t f "sync-patient.ts" packages/core/src/external/ehr/api/

Length of output: 257


Import path verified
The file packages/core/src/external/ehr/command/sync-patient/ehr-sync-patient-local.ts correctly imports from ../../api/sync-patient. The target module packages/core/src/external/ehr/api/sync-patient.ts exists and resolves as expected. No further action required.

packages/api/src/routes/internal/ehr/index.ts (2)

17-17: LGTM! Route follows established patterns.

The new practice route correctly uses the processEhrId middleware and follows the same pattern as the existing patient route. The route structure is consistent and properly configured.


8-8:

✅ Verification successful

Verify the practice module exists.

The new import follows the established pattern. Ensure the practice module is implemented.


🏁 Script executed:

#!/bin/bash
# Description: Verify the practice module exists at the expected location.

fd -t f "practice.ts" packages/api/src/routes/internal/ehr/

Length of output: 108


Practice module import verified

The practice.ts file exists at packages/api/src/routes/internal/ehr/practice.ts and follows the established middleware and routing patterns. No further changes needed—this addition can be approved.

packages/api/src/routes/internal/jwt-token/index.ts (2)

18-20: LGTM! Proper route ordering with clear documentation.

The placement of the token route at the end with the "MUST GO LAST" comment is correct for Express routing. This ensures the shared route doesn't interfere with the EHR-specific routes above it. The root path mounting is appropriate for catch-all or fallback behavior.


7-7:

✅ Verification successful

Verify the token module exists.

The new import follows the established pattern. Ensure the token module is implemented.


🏁 Script executed:

#!/bin/bash
# Description: Verify the token module exists at the expected location.

fd -t f "token.ts" packages/api/src/routes/internal/jwt-token/

Length of output: 114


token.ts module verified

The token.ts file exists at packages/api/src/routes/internal/jwt-token/token.ts, so the import is valid. The fallback route with "MUST GO LAST" should indeed be registered after the EHR-specific routes to avoid unintended catches.

No further action required.

packages/lambdas/src/ehr/elation/elation-link-patient.ts (2)

1-2: Approve command module import paths
The ProcessLinkPatientRequest and ElationLinkPatientLocal imports now correctly reference the new command/link-patient directory structure.


6-10: Approve shared utility import adjustments
All shared utilities (capture, parseLinkPatient, getEnvOrFail, prefixedLog, getSingleMessageOrFail) are now imported from the updated ../../shared path.

packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/refresh/ehr-refresh-ehr-bundles-local.ts (1)

3-6: Approve import path realignment for refresh step
The relative imports for refreshEhrBundle, job entry status, BundleType, and createOrReplaceBundleOnS3 have been updated to reflect the new flattened job/create-resource-diff-bundles/steps/refresh layout.

packages/lambdas/src/ehr/healthie/healthie-link-patient.ts (2)

1-2: Approve command module import paths
ProcessLinkPatientRequest and HealthieLinkPatientLocal now correctly point to the reorganized command/link-patient directory.


6-10: Approve shared utility import adjustments
Shared helpers (capture, parseLinkPatient, getEnvOrFail, prefixedLog, getSingleMessageOrFail) are now imported from the updated ../../shared path, matching the project structure.

packages/lambdas/src/ehr/sync-patient.ts (2)

1-2: Approve command module import paths
Updated imports for ProcessSyncPatientRequest and EhrSyncPatientLocal to the new command/sync-patient directory.


6-10: Approve shared utility import adjustments
Relative imports for capture, parseSyncPatient, getEnvOrFail, prefixedLog, and getSingleMessageOrFail now correctly use the ../shared path.

packages/core/src/external/aws/lambda.ts (2)

7-7: Approve explicit LambdaClient type alias
Introducing export type LambdaClient = AWS.Lambda clarifies the client type across the codebase.


13-13: Approve explicit return type for makeLambdaClient
Specifying : LambdaClient on makeLambdaClient ensures consistent, self-documented typing for AWS Lambda client creation.

packages/core/src/external/ehr/elation/index.ts (1)

8-8: LGTM! Excellent addition of API rate limiting.

The implementation of pagination throttling with a 1-second delay is a best practice that prevents overwhelming the Elation API and reduces the risk of rate limiting errors. The use of a centrally defined paginateWaitTime constant maintains consistency across all EHR integrations.

Also applies to: 43-43, 266-266

packages/lambdas/src/ehr/refresh-ehr-bundles.ts (1)

1-2: LGTM! Clean import path reorganization.

The import path updates correctly reflect the restructuring of core external EHR modules and shared utilities. This maintains consistency with the broader codebase reorganization mentioned in the PR objectives.

Also applies to: 6-10

packages/core/src/external/ehr/athenahealth/index.ts (1)

15-15: LGTM! Consistent rate limiting implementation.

The addition of pagination throttling aligns perfectly with the same enhancement made across other EHR integrations (Elation, Canvas, Healthie). Using the shared paginateWaitTime constant ensures uniform behavior and maintains the 1-second delay standard.

Also applies to: 78-78, 893-893

packages/core/src/external/ehr/healthie/index.ts (1)

1-1: LGTM! Completes the consistent rate limiting pattern.

This finalizes the uniform implementation of pagination throttling across all EHR integrations. The 1-second delay before each paginated request in the paginateAppointments function will help prevent API rate limiting issues while maintaining consistency with the AthenaHealth, Canvas, and Elation implementations.

Also applies to: 27-33, 273-273

packages/lambdas/src/ehr/compute-resource-diff-bundles.ts (1)

1-10: LGTM! Import path updates align with directory restructuring.

The import path changes correctly reflect the directory restructuring mentioned in the AI summary, moving from @metriport/core/external/ehr/bundle/job/ to @metriport/core/external/ehr/job/ and adjusting relative paths from ./shared/ to ../shared/.

packages/api/src/external/ehr/shared/utils/appointment.ts (1)

57-57: LGTM! Logic fix ensures consistent time range calculation.

The change correctly applies the offset to the endRange calculation, ensuring both startRange and endRange are consistently offset from the current datetime. This fixes the previous inconsistency where only startRange was offset.

packages/core/src/external/ehr/job/create-resource-diff-bundles/steps/compute/ehr-compute-resource-diff-bundles-local.ts (1)

4-11: LGTM! Import path updates reflect directory restructuring.

The relative import paths have been correctly updated to use fewer directory levels, maintaining the same imported entities while aligning with the broader directory reorganization.

packages/api/src/routes/internal/jwt-token/token.ts (1)

1-28: LGTM! Well-structured internal JWT token retrieval endpoint.

The implementation follows Express and TypeScript best practices:

  • Proper use of middleware (requestLogger, asyncHandler)
  • Correct parameter validation with getFrom("params").orFail()
  • Appropriate error handling delegation
  • Good JSDoc documentation
  • Follows coding guidelines for naming conventions

Since this is an internal endpoint (as indicated by the /internal/ prefix), the direct token exposure is acceptable for internal service-to-service communication.

packages/lambdas/src/shared/ehr.ts (1)

1-3: LGTM! Import path reorganization improves code structure.

The import path updates to include the "command" directory segment align with the broader reorganization across EHR integrations. This change enhances modularity and follows good organizational practices.

packages/infra/lib/api-stack.ts (4)

463-463: Correctly destructures the new appointments Lambda.

The getAppointmentsLambda is properly extracted from the EhrNestedStack to be used in the API service integration.


479-479: Proper resource dependency injection.

Passing ehrResponsesBucket to the EhrNestedStack constructor enables the new Lambda to access the required S3 bucket.


592-592: Well-integrated Lambda into API service.

The ehrGetAppointmentsLambda is correctly passed to createAPIService, enabling the API to invoke this Lambda for appointment operations.


691-691: Correctly includes Lambda in environment setup.

Adding ehrGetAppointmentsLambda to the lambdasToGetApiUrl array ensures it receives the API_URL environment variable for proper communication.

packages/core/src/external/ehr/eclinicalworks/environment.ts (1)

1-16: Excellent implementation of centralized environment configuration.

This function properly:

  • Validates environment configuration with type guards
  • Uses static error messages with dynamic data in additionalInfo (following coding guidelines)
  • Follows functional programming style: small, deterministic, single purpose
  • Centralizes environment logic for better maintainability
  • Uses consistent error handling with MetriportError

The implementation aligns well with the coding guidelines and the broader refactoring to centralize environment management across EHR integrations.

packages/api/src/external/ehr/elation/command/process-patients-from-appointments.ts (1)

1-2: LGTM! Import path updates support better code organization.

The updated import paths for buildEhrSyncPatientHandler and buildElationLinkPatientHandler reflect the new command directory structure, enhancing modularity and consistency across EHR integrations.

packages/core/src/external/ehr/athenahealth/environment.ts (1)

6-20: LGTM! Well-structured environment validation function.

The implementation follows coding guidelines well with proper error handling, static error messages, and type safety. The use of early returns with guard clauses makes the code readable and maintainable.

packages/core/src/external/ehr/canvas/shared.ts (1)

7-30: LGTM! Clean implementation of centralized client creation.

The function properly uses the centralized secret retrieval pattern and handles optional token information correctly. The async/await usage and parameter destructuring follow the coding guidelines well.

packages/api/src/external/ehr/eclinicalworks/shared.ts (1)

1-3: LGTM! Consistent refactoring to centralized environment management.

The updated imports and usage of the centralized getEClinicalWorksEnv function aligns well with the broader refactoring pattern across EHR integrations. This improves modularity and consistency.

Also applies to: 12-12

packages/api/src/routes/internal/ehr/practice.ts (3)

1-12: LGTM: Clean imports and proper dependencies.

The imports are well-organized and include all necessary dependencies for the router implementation. Good use of proper TypeScript types and utilities.


26-44: LGTM: Solid parameter validation and error handling.

The endpoint implementation follows good practices:

  • Proper parameter extraction and validation using utility functions
  • Type-safe EHR source validation with meaningful error messages
  • UUID validation for cxId
  • Appropriate error context in BadRequestError
  • Clean response structure

The logic flow is clear and handles edge cases appropriately.


37-41:

❌ Incorrect review comment

Verify that getSecrets function is awaited properly.

The getSecrets function call appears to be missing await keyword. If this function returns a Promise, it should be awaited to ensure proper error handling and response timing.


🏁 Script executed:

#!/bin/bash
# Check if getSecrets function returns a Promise that should be awaited
ast-grep --pattern $'export function getSecrets($_) {
  $$$
}'

Length of output: 63


🏁 Script executed:

#!/bin/bash
# Show how getSecrets is imported in practice.ts
rg -n "getSecrets" -n packages/api/src/routes/internal/ehr/practice.ts

# Locate the definition/declaration of getSecrets anywhere in the repo
rg -n "getSecrets" -n

Length of output: 2735


🏁 Script executed:

#!/bin/bash
# Display the import section of practice.ts to identify getSecrets source
sed -n '1,50p' packages/api/src/routes/internal/ehr/practice.ts

Length of output: 1612


🏁 Script executed:

#!/bin/bash
# Show the implementation of getSecrets in the core package
sed -n '1,200p' packages/core/src/external/ehr/command/get-secrets.ts

Length of output: 2178


🏁 Script executed:

#!/bin/bash
# Check if environment getters return Promises (async) or synchronous values

# Search for getCanvasEnv definition
rg -n "export .*function getCanvasEnv" -n packages/core/src/external/ehr/canvas/environment.ts

# Search for getAthenaEnv definition
rg -n "export .*function getAthenaEnv" -n packages/core/src/external/ehr/athena/environment.ts

# Search for getElationEnv definition
rg -n "export .*function getElationEnv" -n packages/core/src/external/ehr/elation/environment.ts

# Search for getHealthieEnv definition
rg -n "export .*function getHealthieEnv" -n packages/core/src/external/ehr/healthie/environment.ts

Length of output: 588


🏁 Script executed:

#!/bin/bash
# Inspect environment provider implementations for async/sync signatures

echo "----- Canvas Environment -----"
sed -n '1,200p' packages/core/src/external/ehr/canvas/environment.ts

echo "----- Athenahealth Environment -----"
sed -n '1,200p' packages/core/src/external/ehr/athenahealth/environment.ts

echo "----- Elation Environment -----"
sed -n '1,200p' packages/core/src/external/ehr/elation/environment.ts

echo "----- Healthie Environment -----"
sed -n '1,200p' packages/core/src/external/ehr/healthie/environment.ts

# Check for any 'async' keyword usage in environment files
echo "----- Async Keywords in Canvas -----"
grep -R "async " -n packages/core/src/external/ehr/canvas/environment.ts || true
echo "----- Async Keywords in Athenahealth -----"
grep -R "async " -n packages/core/src/external/ehr/athenahealth/environment.ts || true
echo "----- Async Keywords in Elation -----"
grep -R "async " -n packages/core/src/external/ehr/elation/environment.ts || true
echo "----- Async Keywords in Healthie -----"
grep -R "async " -n packages/core/src/external/ehr/healthie/environment.ts || true

Length of output: 5929


getSecrets is synchronous – no await needed
The getSecrets imported from @metriport/core/external/ehr/command/get-secrets returns its result directly (via synchronous handlers like getCanvasEnv, getAthenaEnv, etc.), not a Promise. Calling it without await is correct—no changes required.

Likely an incorrect or invalid review comment.

packages/core/src/external/ehr/canvas/environment.ts (3)

6-9: LGTM: Clean function signature with proper typing.

The function uses proper destructuring of parameters and returns a well-typed result. Good use of generic types for environment credentials.


10-13: LGTM: Proper configuration retrieval and validation.

Good use of early return with meaningful error messages and proper JSON parsing with schema validation using zod.


20-22: LGTM: Appropriate error handling for missing credentials.

The validation ensures all required credentials are present before proceeding, with a clear error message when any are missing.

packages/infra/lib/api-stack/api-service.ts (3)

116-116: LGTM: Proper parameter addition to function signature.

The ehrGetAppointmentsLambda parameter is correctly added to both the function signature and the destructured parameters list, following the established pattern for other Lambda integrations.

Also applies to: 161-161


299-299: LGTM: Correct environment variable configuration.

The environment variable EHR_GET_APPOINTMENTS_LAMBDA_NAME is properly set using the Lambda's function name, following the naming convention used by other Lambda integrations in the same file.


451-451: LGTM: Proper IAM permission granting.

The grantInvoke call correctly grants the Fargate service permission to invoke the EHR appointments Lambda, consistent with how other Lambda permissions are handled in this file.

packages/core/src/external/ehr/api/get-token-info.ts (5)

12-16: LGTM: Clear function documentation.

The JSDoc comment clearly describes the function's purpose and parameters. Good documentation practice.


17-20: LGTM: Proper setup with logging and API configuration.

Good use of structured logging with context and proper axios configuration using centralized config. The URL construction is clear and follows REST conventions.


22-24: LGTM: Proper use of retry mechanism.

The implementation correctly wraps the axios call in executeWithNetworkRetries to handle transient network failures, which is essential for external API calls.


26-29: LGTM: Proper response transformation.

The response data is correctly transformed to match the JwtTokenInfo type, with proper date parsing for the expiration field. Good type safety practices.


30-38: LGTM: Comprehensive error handling.

Excellent error handling with:

  • Proper logging with context
  • Meaningful error messages
  • Error cause preservation
  • Rich additional context for debugging
  • Proper error transformation to MetriportError

Follows the coding guidelines for error handling perfectly.

packages/core/src/external/ehr/canvas/command/get-appointments.ts (2)

11-20: Excellent input validation with comprehensive error context.

The validation logic properly checks for required fromDate and toDate parameters and provides detailed context in the error. The use of optional chaining for date serialization in the error context is well-handled.


21-28: Clean and functional implementation following best practices.

The function follows the coding guidelines well:

  • Uses async/await instead of .then()
  • Implements functional programming style (small, deterministic, single purpose)
  • Properly handles optional tokenId parameter with conditional spreading
  • Returns the result directly without unnecessary variable assignments
packages/api/src/external/ehr/healthie/command/process-patients-from-appointments.ts (2)

1-1: Import path reorganization looks good.

The updated import paths to include the command subdirectory improve code organization and align with the modular structure being implemented across EHR integrations.

Also applies to: 3-3


36-36:

❌ Incorrect review comment

Verify the behavioral change in appointment lookup window.

The changes modify the 48hr appointment lookup behavior:

  • Previously: 2-day look-forward with 1-day offset
  • Now: 1-day look-forward with 1-day offset

This reduces the appointment retrieval window from 2 days to 1 day. Please confirm this change is intentional and aligns with business requirements.

Also applies to: 222-223


🏁 Script executed:

#!/bin/bash
# Description: Check if similar changes were made to other EHR appointment lookup logic
# Expected: Find other files with similar 48hr appointment lookup patterns

# Search for similar appointment lookup patterns in other EHR integrations
rg -A 5 -B 5 "Appointments48hr|appointmentsLookForward.*48" --type ts

# Search for usage of getLookForwardTimeRangeWithOffset to see the pattern
rg -A 3 -B 2 "getLookForwardTimeRangeWithOffset" --type ts

Length of output: 8819


🏁 Script executed:

#!/bin/bash
# Locate the definition and usage of appointmentsLookForward and oneDayOffset
rg -n "appointmentsLookForward" -A 3 -B 3 --type ts
rg -n "oneDayOffset" -A 3 -B 3 --type ts

# Inspect getLookForwardTimeRangeWithOffset implementation
sed -n '1,200p' packages/api/src/external/ehr/shared/utils/appointment.ts | sed -n '1,200!d'

Length of output: 9669


🏁 Script executed:

#!/bin/bash
# Show the implementation of getLookForwardTimeRangeWithOffset to confirm how lookForward and offset are applied
rg -n "export function getLookForwardTimeRangeWithOffset" -A 30 --type ts packages/api/src/external/ehr/shared/utils/appointment.ts

Length of output: 707


No change to appointment lookup window—logic remains intentional
The Healthie command still uses a 1-day look-forward with a 1-day offset to fetch two 24 hr segments (0–24 hr for Appointments, 24–48 hr for Appointments48hr). This matches the implementation in all other EHR integrations and aligns with the original design. You can ignore the suggestion of a reduced window.

Likely an incorrect or invalid review comment.

packages/core/src/external/ehr/api/get-client-key-and-secret.ts (1)

18-45: Excellent implementation following all coding guidelines.

The function demonstrates several best practices:

  • Generic design with Zod schema validation for type safety
  • Proper error handling with static messages and detailed context
  • Network retries for resilience (executeWithNetworkRetries)
  • Appropriate logging and response validation
  • Uses async/await consistently
  • Error context includes all relevant information for debugging

The implementation is clean, reusable, and follows the coding guidelines perfectly.

packages/lambdas/src/ehr/get-appointments.ts (1)

18-34: Well-structured Lambda handler following best practices.

The handler implementation demonstrates good practices:

  • Proper capture initialization and wrapping
  • Performance measurement with timing logs
  • Appropriate error context setting
  • Clean separation of concerns with direct handler usage
packages/core/src/external/ehr/canvas/index.ts (4)

14-20: LGTM! Proper imports for pagination throttling.

The imports correctly add the necessary utilities (sleep and paginateWaitTime) to implement rate limiting for paginated API requests.

Also applies to: 67-67


777-777: Excellent addition of rate limiting for FHIR resource pagination.

The sleep delay prevents overwhelming the Canvas API with rapid successive requests, improving reliability and preventing potential rate limiting issues.


866-869: Good fix for appointment query parameter construction.

Using urlParams.append() explicitly ensures both date filters (fromDate and toDate) are properly included as separate query parameters, which is more reliable than conditional object inclusion.


883-883: Consistent rate limiting applied to appointment pagination.

The sleep delay maintains consistency with FHIR resource pagination throttling, ensuring uniform rate limiting across all Canvas API paginated endpoints.

packages/api/src/external/ehr/canvas/command/process-patients-from-appointments.ts (3)

1-3: LGTM! Updated imports for centralized appointment handling.

The import changes properly reflect the refactor to use standardized EHR operation handlers, improving modularity and consistency across EHR integrations.

Also applies to: 8-8, 22-22


99-102: Good update to use enhanced client creation function.

The new client creation function properly returns the tokenId metadata required by the centralized appointment handler, supporting the architectural improvements.


108-116: Excellent refactor to use centralized appointment handler.

The handler-based approach improves consistency across EHR integrations and allows for flexible implementation routing (direct vs Lambda-based) while maintaining the same functionality and interface.

packages/core/src/external/ehr/elation/environment.ts (2)

6-26: Well-implemented environment and credential retrieval.

The function properly validates the environment configuration, constructs appropriate lookup keys, and includes comprehensive error handling for missing or invalid data. The pattern is consistent with other EHR integrations.


28-34: Proper implementation of client map retrieval and validation.

The function correctly uses Zod's safeParse for JSON validation and includes appropriate error handling for missing or malformed configuration data.

packages/shared/src/interface/external/ehr/fhir-resource.ts (1)

47-59: Well-structured FHIR OperationOutcome schemas.

The schemas correctly model FHIR OperationOutcome resources according to the specification, with proper nested structures for issue details and appropriate typing. These will enhance error detection and handling in EHR operations.

packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts (2)

11-20: LGTM! Well-implemented dependency injection pattern.

The constructor properly implements dependency injection with sensible defaults, following the coding guidelines for avoiding null and using proper fallback logic.


22-42: 🛠️ Refactor suggestion

Consider adding error handling for JSON parsing.

The implementation correctly uses executeWithNetworkRetries for resilience and follows async/await patterns. However, JSON.parse(resultPayload) on line 40 could throw an error if the Lambda returns malformed JSON.

Consider wrapping the JSON parsing in a try-catch block:

-      return JSON.parse(resultPayload);
+      try {
+        return JSON.parse(resultPayload);
+      } catch (error) {
+        throw new MetriportError("Failed to parse Lambda response", error, {
+          lambdaName: this.ehrGetAppointmentsLambdaName,
+          resultPayload,
+        });
+      }
⛔ Skipped due to learnings
Learnt from: thomasyopes
PR: metriport/metriport#3608
File: packages/lambdas/src/ehr-compute-resource-diff-bundles.ts:58-62
Timestamp: 2025-04-23T19:00:49.707Z
Learning: For Lambda functions in the metriport codebase, the team prefers to let the default Lambda error handling catch JSON parsing errors rather than adding explicit try/catch blocks.
Learnt from: thomasyopes
PR: metriport/metriport#3873
File: packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-cloud.ts:40-43
Timestamp: 2025-05-29T16:53:26.064Z
Learning: The EHR get-appointments Lambda function is designed to always return parseable JSON responses, so additional error handling for JSON.parse() is not required when processing its results.
packages/core/src/external/ehr/healthie/environment.ts (2)

6-23: LGTM! Excellent environment validation and error handling.

The function properly validates the environment setting and implements comprehensive error handling with detailed context. The API key lookup pattern using the composite key format is well-implemented.


25-31: LGTM! Proper schema validation and error handling.

The function correctly uses schema validation to ensure data integrity and provides clear error messages when validation fails. This follows the coding guidelines for type safety and proper error handling.

packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments-direct.ts (1)

25-35: LGTM! Excellent extensible mapping pattern.

The mapping approach provides a clean, extensible way to add new appointment methods while maintaining type safety at the mapping level. The error handling is appropriate and provides useful context.

packages/api/src/external/ehr/elation/shared.ts (2)

3-5: LGTM! Proper centralization of environment logic.

The import changes correctly utilize the new centralized environment modules, improving modularity and consistency across EHR integrations.


98-114: LGTM! Excellent refactoring with improved flexibility.

The split into two functions provides both the enriched version with metadata (createElationClientWithTokenIdAndEnvironment) and a simplified wrapper (createElationClient) for backwards compatibility. This follows the coding guidelines for modularity and maintains a clean API surface.

packages/api/src/external/ehr/healthie/shared.ts (3)

3-5: Approve the centralized environment imports.

The import refactoring properly centralizes environment and credential retrieval logic, following the established pattern across other EHR integrations. This improves maintainability and reduces code duplication.


80-90: LGTM! Function follows the established pattern.

The createHealthieClientWithEnvironment function correctly:

  • Uses proper TypeScript typing with explicit return type
  • Follows the async/await pattern from coding guidelines
  • Returns both client and environment metadata for enhanced functionality
  • Maintains consistency with similar functions in other EHR integrations

92-97: Approve the simplified client creation wrapper.

The simplified createHealthieClient function provides a clean API for cases where only the client instance is needed, while internally leveraging the enhanced function. This maintains backward compatibility and follows the DRY principle.

packages/core/src/external/ehr/command/get-appointments/ehr-get-appointments.ts (2)

3-11: Well-structured request type with proper optional fields.

The GetAppointmentsRequest type is well-designed with:

  • Clear, meaningful property names following camelCase convention
  • Appropriate use of optional properties for flexible querying
  • Proper typing with Date objects for temporal fields

13-13: Good use of utility type for client request.

Using Omit to derive GetAppointmentsClientRequest from GetAppointmentsRequest follows the DRY principle and maintains type consistency.

packages/api/src/external/ehr/canvas/shared.ts (3)

1-5: Approve the import consolidation.

The imports properly leverage the centralized environment module and shared utilities, reducing code duplication and improving maintainability across EHR integrations.


7-16: Excellent use of generic utility function.

The function correctly leverages the generic createEhrClient utility with proper type parameters. The implementation follows the coding guidelines by:

  • Using proper TypeScript generics
  • Following async/await pattern
  • Providing explicit return type annotations

18-23: Good API design with simplified wrapper.

The simplified wrapper maintains a clean API while internally using the enhanced function. This follows the principle of providing both detailed and simplified interfaces based on use case requirements.

packages/api/src/external/ehr/athenahealth/shared.ts (3)

1-5: Consistent import pattern across EHR integrations.

The imports follow the same centralized pattern as other EHR integrations (Canvas, Healthie), promoting consistency and maintainability across the codebase.


7-16: Proper implementation of the established pattern.

The createAthenaClientWithTokenIdAndEnvironment function correctly:

  • Uses the generic createEhrClient utility with appropriate type parameters
  • Passes undefined for params since AthenaHealth doesn't need per-practice parameters for environment retrieval
  • Maintains type safety with explicit generic type arguments

18-24: Clean wrapper function maintains API simplicity.

The simplified createAthenaClient function provides a clean interface while leveraging the enhanced implementation internally. The pattern is consistent across all EHR integrations in this PR.

packages/core/src/external/ehr/command/get-secrets.ts (3)

21-30: LGTM! Well-structured secret retrieval abstraction.

The main function provides a clean interface for dynamically retrieving secrets based on EHR type. The delegation pattern is well-implemented with proper type safety.


39-48: Good type guard implementation for supported EHR sources.

The explicit exclusion of eclinicalworks and the type guard function provide clear boundaries for which EHR sources support dynamic secret retrieval.


52-65: Proper error handling in the handler lookup.

The mapping approach with explicit error handling for missing handlers is well-implemented. The BadRequestError with additional context is appropriate for this scenario.

packages/api/src/external/ehr/shared/utils/client.ts (3)

29-29: Good enhancement to include token ID in JWT token info.

Adding the token id provides valuable metadata for token tracking and management.


51-52: Approve function signature update for better type safety.

The updated parameter type EhrClientTwoLeggedAuthParams<Env> and enhanced return type provide better type safety and more useful metadata.


65-71: Good practice to capture and return token metadata.

Storing the full token object and returning the token ID along with client and environment provides useful metadata for downstream operations.

packages/core/src/external/ehr/environment.ts (2)

8-18: Excellent centralization of environment and credential types.

The union types and generic type definitions provide a consistent interface across all EHR providers while maintaining type safety.


20-26: Well-designed client authentication parameter types.

The combination of JWT token info, practice ID, and environment credentials in a single type provides all necessary parameters for client creation.

packages/core/src/external/ehr/shared.ts (5)

43-54: Well-defined schemas for secret retrieval validation.

The Zod schemas provide proper validation for both OAuth and API key-based secret responses.


169-180: Excellent error handling for S3 upload failures.

Wrapping S3 operations in try-catch blocks prevents S3 failures from breaking the main request flow while still logging the errors for debugging.


185-192: Good practice to chain errors with original cause.

Passing the original error as the cause parameter preserves the full stack trace, which is valuable for debugging.


247-257: Well-implemented FHIR validation error detection.

The function properly parses FHIR OperationOutcome responses and identifies validation errors by checking for error severity and the validation prefix.


269-275: Correct classification of FHIR validation errors as non-retriable.

Including FHIR validation errors in the non-retriable category prevents unnecessary retry loops for validation failures that won't resolve with retries.

packages/infra/lib/ehr-nested-stack.ts (5)

23-23: LGTM: New getAppointments Lambda configuration follows established patterns.

The configuration is consistent with other Lambda settings, uses appropriate timeout (15 minutes) and memory allocation (1024 MB), and follows the new nested entry path structure.

Also applies to: 30-38, 151-151


42-42: LGTM: Entry path reorganization improves structure.

Moving all Lambda entries under the ehr/ folder creates better organization and consistency across the EHR-related Lambda functions.

Also applies to: 63-63, 84-84, 106-106, 131-131


103-103: Verify timeout increases don't impact dependent systems.

The Lambda timeouts have been increased to 15 minutes and alarm durations to 2 hours. Ensure these changes don't negatively impact downstream systems or SLA requirements.

Also applies to: 112-112, 128-128, 137-137


165-165: LGTM: Optional bucket property properly typed.

The ehrResponsesBucket is correctly typed as optional, which aligns with its conditional usage in the setup method.


170-170: LGTM: Constructor integration follows established patterns.

The Lambda property declaration and setup call are consistent with other Lambda configurations in the class.

Also applies to: 188-195

packages/core/src/util/config.ts (2)

212-214: LGTM: Lambda name getter follows established pattern.

The method correctly uses getEnvVarOrFail indicating this environment variable is required, which is appropriate for infrastructure dependencies.


223-253: LGTM: EHR environment getters properly implemented.

All new methods follow consistent patterns:

  • Use getEnvVar (optional) appropriately for configuration that may not be present in all environments
  • Follow consistent naming conventions for environment variables
  • Cover comprehensive EHR system configurations (AthenaHealth, Elation, Canvas, Healthie, EClinicalWorks)
  • Method names use proper camelCase as per coding guidelines

@thomasyopes thomasyopes added this pull request to the merge queue Jun 5, 2025
Merged via the queue into master with commit ffd8d00 Jun 5, 2025
74 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0