Git Product home page Git Product logo

medplum-demo-bots's Introduction

Medplum

Medplum is a developer platform that enables flexible and rapid development of healthcare apps.

  • Medplum Auth - End-to-end identity solution for easy user authentication, sign-in, and permissions using OAuth, OpenID, and SMART-on-FHIR.
  • Medplum Clinical Data Repository (CDR) - Backend server that hosts your healthcare data in a secure, compliant, and standards-based repository.
  • Medplum API - FHIR-based API for sending, receiving, and manipulating data.
  • Medplum SDK - Client libraries that simplify the process of interacting with the Medplum API.
  • Medplum App - Web application where you can view your data and perform basic editing tasks. You can also use the Medplum App to manage basic workflows.
  • Medplum Bots - Write and run application logic server-side without needing to set up your own server.
  • UI Component Library - React components designed to help you quickly develop custom healthcare applications.

Docs

Contributing

We heartily welcome any and all contributions that match our engineering standards!

That being said, this codebase isn't your typical open-source project because it's not a library or package with a limited scope -- it's our entire product. Our Contributing documentation has all the information you need to get started.

Ground Rules

Contributions and discussion guidelines

By making a contribution to this project, you are deemed to have accepted the Developer Certificate of Origin (DCO).

All conversations and communities on Medplum are expected to follow GitHub's Community Guidelines and Acceptable Use Policies. We expect discussions on issues and pull requests to stay positive, productive, and respectful. Remember: there are real people on the other side of the screen!

Reporting a bug or proposing a new feature

If you found a technical bug on Medplum or have ideas for features we should implement, the issue tracker is the best place to share with us. (click here to open a new issue)

Writing documentation or blog content

Did you learn how to do something using Medplum that wasn't obvious on your first try? By contributing your new knowledge to our documentation, you can help others who might have a similar use case!

Our documentation is hosted on medplum.com/docs, but it is built from Markdown files in our docs package.

For relatively small changes, you can edit files directly from your web browser on Github.dev without needing to clone the repository.

Fixing a bug or implementing a new feature

If you find a bug and open a Pull Request that fixes it, we'll review it as soon as possible to ensure it meets our engineering standards.

If you want to implement a new feature, open an issue first to discuss with us how the feature might work, and to ensure it fits into our roadmap and plans for the app.

If you want to contribute but are unsure how to start, we have a "good first issue" label which is applied to newcomer-friendly issues. Take a look at the full list of good first issues and pick something you like!

Ready to get started writing code? Follow the local setup instructions and jump in!

Codebase

Technologies

With the ground rules out of the way, let's talk about the coarse architecture of this mono repo:

  • Full-stack TypeScript: We use Node.js to power our servers, and React to power our frontend apps. Almost all of the code you'll touch in this codebase will be TypeScript.

Here is a list of all the big technologies we use:

  • PostgreSQL: Data storage
  • Redis: Background jobs and caching
  • Express: API server
  • TypeScript: Type-safe JavaScript
  • React: Frontend React app

Folder structure

medplum/
├── packages
│   ├── agent           # On-premise agent
│   ├── app             # Frontend web app
│   ├── bot-layer       # AWS Lambda Layer for Bots
│   ├── cdk             # AWS CDK infra as code
│   ├── cli             # Command line interface
│   ├── core            # Core shared library
│   ├── definitions     # Data definitions
│   ├── docs            # Documentation
│   ├── examples        # Example code used in documentation
│   ├── expo-polyfills  # Expo polyfills for MedplumClient compatability
│   ├── fhir-router     # FHIR URL router
│   ├── fhirtypes       # FHIR TypeScript definitions
│   ├── generator       # Code generator utilities
│   ├── graphiql        # Preconfigured GraphiQL
│   ├── hl7             # HL7 client and server
│   ├── mock            # Mock FHIR data for testing
│   ├── react           # React component library
│   ├── react-hooks     # React hooks library
│   └── server          # Backend API server
└── scripts             # Helper bash scripts

Thanks

Chromatic

Thanks to Chromatic for providing the visual testing platform that helps us review UI changes and catch visual regressions.

License

Apache 2.0

Copyright © Medplum 2024

FHIR® is a registered trademark of HL7.

SNOMED® is a registered trademark of the International Health Terminology Standards Development Organisation.

LOINC® is a registered trademark of Regenstrief Institute, Inc.

DICOM® is the registered trademark of the National Electrical Manufacturers Association (NEMA).

medplum-demo-bots's People

Contributors

codyebberson avatar dependabot[bot] avatar github-actions[bot] avatar ivansakhman avatar justinko43 avatar rahul1 avatar renovate[bot] avatar reshmakh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

medplum-demo-bots's Issues

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Location: renovate.json
Error type: Invalid JSON (parsing failed)
Message: Syntax error: expecting String near },

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

npm
package.json
  • esbuild 0.18.11
  • @medplum/cli 2.0.25
  • @medplum/core 2.0.25
  • @medplum/fhirtypes 2.0.25
  • @medplum/mock 2.0.25
  • @types/node 20.3.3
  • @types/node-fetch 2.6.4
  • @types/ssh2-sftp-client 9.0.0
  • @typescript-eslint/eslint-plugin 5.61.0
  • @typescript-eslint/parser 5.61.0
  • @vitest/coverage-v8 0.32.4
  • @vitest/ui 0.32.4
  • eslint 8.44.0
  • eslint-config-prettier 8.8.0
  • eslint-plugin-prettier 4.2.1
  • form-data 4.0.0
  • node-fetch 3.3.1
  • pdfmake 0.2.7
  • prettier 2.8.8
  • ssh2-sftp-client 9.1.0
  • stripe 12.11.0
  • typescript 5.1.6
  • vitest 0.32.4

  • Check this box to trigger a request for Renovate to run again on this repository

Need to add devDependencies

Hello,

I've just tried to launch npm run build after npm install and I had the following error :

[email protected] lint
eslint src/

node:internal/modules/esm/resolve:844
throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@medplum/bot-layer' imported from /Users/name/Documents/workspace/medplum-demo-bots/esbuild-script.mjs
at packageResolve (node:internal/modules/esm/resolve:844:9)
at moduleResolve (node:internal/modules/esm/resolve:901:20)
at defaultResolve (node:internal/modules/esm/resolve:1131:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:390:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:359:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:234:38)
at ModuleWrap. (node:internal/modules/esm/module_job:85:39)
at link (node:internal/modules/esm/module_job:84:36) {
code: 'ERR_MODULE_NOT_FOUND'

I've managed to fix it by adding the @medplum/bot-layer to the devDependencies

image

When using HomerSimpson npm run build crashes

Hello,

When I try to use Homer Simpson in my test, then npm run build crashes.

Let me show you what I mean :

Without HomerSimpson

import { MedplumClient } from "@medplum/core";
import { Device } from "@medplum/fhirtypes";

export const createDevice = async (medplum: MedplumClient): Promise<Device> => {
    const device:Device = await  medplum.createResource({
        resourceType: 'Device',
        id: randomInt(100, 1000).toString(),
        patient: { reference: 'Patient/123' }
    });
    return device;
};
 medplum-demo-bots git:(feature/AMA-34) ✗ npm run build

> [email protected] build
> npm run clean && npm run lint && tsc && node --no-warnings esbuild-script.mjs


> [email protected] clean
> rimraf dist


> [email protected] lint
> eslint src/

Build completed successfully!

With HomerSimpson

import { MedplumClient } from "@medplum/core";
import { Device } from "@medplum/fhirtypes";
import { HomerSimpson } from "@medplum/mock";

export const createDevice = async (medplum: MedplumClient): Promise<Device> => {
    const device:Device = await  medplum.createResource({
        resourceType: 'Device',
        id: randomInt(100, 1000).toString(),
        patient: { reference: 'Patient/'+HomerSimpson.id }
    });
    return device;
};
npm run build                            

> [email protected] build
> npm run clean && npm run lint && tsc && node --no-warnings esbuild-script.mjs


> [email protected] clean
> rimraf dist


> [email protected] lint
> eslint src/

✘ [ERROR] Could not resolve "rfc6902"

    node_modules/@medplum/fhir-router/dist/esm/index.mjs:53:61982:
      53 │ ...rom"@medplum/core";import{applyPatch as dc}from"rfc6902";var Hr=class{async searchOne(t){return(await ...
         ╵                                                   ~~~~~~~~~

  You can mark the path "rfc6902" as external to exclude it from the bundle, which will remove this
  error and leave the unresolved path in the bundle.

Build failed: {
  "errors": [
    {
      "id": "",
      "location": {
        "column": 61982,
        "file": "node_modules/@medplum/fhir-router/dist/esm/index.mjs",
        "length": 9,
        "line": 53,
        "lineText": "`))}var zn=class{constructor(t){this._errors=[],this...
        "namespace": "",
        "suggestion": ""
      },
      "notes": [
        {
          "location": null,
          "text": "You can mark the path \"rfc6902\" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle."
        }
      ],
      "pluginName": "",
      "text": "Could not resolve \"rfc6902\""
    }
  ],
  "warnings": []
}

Issues with esbuild-script.mjs

Hello,

I have some issues as soon as I try to install and use aws package.
Indeed when I run the node --no-warnings esbuild-script.mjs (in npm run build).

npm run build

> [email protected] build
> npm run clean && npm run lint && tsc && node esbuild-script.mjs


> [email protected] clean
> rimraf dist


> [email protected] lint
> eslint src/

(node:79545) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
✘ [ERROR] Could not resolve "./auth/httpAuthSchemeProvider"

    node_modules/@aws-sdk/client-lambda/dist-cjs/index.js:223:44:
      223 │ var import_httpAuthSchemeProvider = require("./auth/httpAuthSchemeProvider");
          ╵                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "././runtimeConfig"

    node_modules/@aws-sdk/client-lambda/dist-cjs/index.js:242:35:
      242 │ var import_runtimeConfig = require("././runtimeConfig");
          ╵                                    ~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./middleware-http-auth-scheme"

    node_modules/@smithy/core/dist-es/index.js:1:14:
      1 │ export * from "./middleware-http-auth-scheme";
        ╵               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./middleware-http-signing"

    node_modules/@smithy/core/dist-es/index.js:2:14:
      2 │ export * from "./middleware-http-signing";
        ╵               ~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./submodules/client/index"

    node_modules/@aws-sdk/core/dist-es/index.js:1:14:
      1 │ export * from "./submodules/client/index";
        ╵               ~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./util-identity-and-auth"

    node_modules/@smithy/core/dist-es/index.js:3:14:
      3 │ export * from "./util-identity-and-auth";
        ╵               ~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./adaptors/getEndpointFromConfig"

    node_modules/@smithy/middleware-endpoint/dist-cjs/index.js:101:43:
      101 │ var import_getEndpointFromConfig = require("./adaptors/getEndpointFromConfig");
          ╵                                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./submodules/httpAuthSchemes/index"

    node_modules/@aws-sdk/core/dist-es/index.js:2:14:
      2 │ export * from "./submodules/httpAuthSchemes/index";
        ╵               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./getSmithyContext"

    node_modules/@smithy/core/dist-es/index.js:4:14:
      4 │ export * from "./getSmithyContext";
        ╵               ~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./submodules/protocols/index"

    node_modules/@aws-sdk/core/dist-es/index.js:3:14:
      3 │ export * from "./submodules/protocols/index";
        ╵               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./normalizeProvider"

    node_modules/@smithy/core/dist-es/index.js:5:14:
      5 │ export * from "./normalizeProvider";
        ╵               ~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./isStreamingPayload/isStreamingPayload"

    node_modules/@smithy/middleware-retry/dist-cjs/index.js:299:40:
      299 │ var import_isStreamingPayload = require("./isStreamingPayload/isStreamingPayload");
          ╵                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./protocols/requestBuilder"

    node_modules/@smithy/core/dist-es/index.js:6:14:
      6 │ export * from "./protocols/requestBuilder";
        ╵               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "./pagination/createPaginator"

    node_modules/@smithy/core/dist-es/index.js:7:32:
      7 │ export { createPaginator } from "./pagination/createPaginator";
        ╵                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "././getAwsChunkedEncodingStream"

    node_modules/@smithy/util-stream/dist-cjs/index.js:80:32:
      80 │ __reExport(src_exports, require("././getAwsChunkedEncodingStream"), module.exports);
         ╵                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "././sdk-stream-mixin"

    node_modules/@smithy/util-stream/dist-cjs/index.js:81:32:
      81 │ __reExport(src_exports, require("././sdk-stream-mixin"), module.exports);
         ╵                                 ~~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "././fromBase64"

    node_modules/@smithy/util-base64/dist-cjs/index.js:19:32:
      19 │ __reExport(src_exports, require("././fromBase64"), module.exports);
         ╵                                 ~~~~~~~~~~~~~~~~

✘ [ERROR] Could not resolve "././toBase64"

    node_modules/@smithy/util-base64/dist-cjs/index.js:20:32:
      20 │ __reExport(src_exports, require("././toBase64"), module.exports);
         ╵                                 ~~~~~~~~~~~~~~

Here's my package.json

{
  "name": "medplum-demo-bots",
  "version": "3.1.5",
  "description": "Medplum Demo Bots",
  "license": "Apache-2.0",
  "author": "Medplum <[email protected]>",
  "type": "module",
  "scripts": {
    "build": "npm run clean && npm run lint && tsc && node --no-warnings esbuild-script.mjs",
    "clean": "rimraf dist",
    "lint": "eslint src/",
    "prettier": "prettier --write .",
    "test": "vitest run",
    "test:coverage": "vitest run --coverage",
    "test:ui": "vitest --ui"
  },
  "prettier": {
    "printWidth": 120,
    "singleQuote": true,
    "trailingComma": "es5"
  },
  "eslintConfig": {
    "parserOptions": {
      "project": "./tsconfig.json"
    },
    "extends": [
      "@medplum/eslint-config"
    ],
    "root": true
  },
  "devDependencies": {
    "@medplum/bot-layer": "3.1.8",
    "@medplum/cli": "3.1.8",
    "@medplum/core": "3.1.8",
    "@medplum/eslint-config": "3.1.8",
    "@medplum/fhirtypes": "3.1.8",
    "@medplum/mock": "3.1.8",
    "@types/node": "20.14.6",
    "@types/node-fetch": "2.6.11",
    "@types/ssh2-sftp-client": "9.0.3",
    "@vitest/coverage-v8": "1.6.0",
    "@vitest/ui": "1.6.0",
    "esbuild": "0.21.5",
    "form-data": "4.0.0",
    "glob": "^10.4.2",
    "node-fetch": "3.3.2",
    "pdfmake": "0.2.10",
    "rimraf": "5.0.7",
    "ssh2-sftp-client": "10.0.3",
    "stripe": "15.12.0",
    "typescript": "5.4.5",
    "vitest": "^1.6.0"
  },
  "dependencies": {
    "@aws-sdk/client-lambda": "^3.598.0",
    "@aws-sdk/client-s3": "^3.598.0",
    "@aws-sdk/credential-provider-http": "^3.598.0",
    "@aws-sdk/credential-provider-ini": "^3.598.0",
    "@aws-sdk/credential-provider-web-identity": "^3.598.0",
    "@aws-sdk/s3-request-presigner": "^3.598.0",
    "@smithy/middleware-endpoint": "^3.0.3",
    "@smithy/node-http-handler": "^3.1.0",
    "aws-sdk": "^2.1645.0"
  }
}

And here is a simple bot I've created that shows the issue

import { InvokeCommand, InvokeCommandInput, LambdaClient } from '@aws-sdk/client-lambda';
import { BotEvent, MedplumClient, parseReference } from '@medplum/core';
import { Device, DocumentReference, Reference } from '@medplum/fhirtypes';

export const CALIBRATION_SUCCESS = 'SUCCESS';
export const CALIBRATION_FAILED = 'FAILED';
export const CALIBRATION_ERROR = 'ERROR';

type CalibrationBotEvent = BotEvent & {
    input: {
        device: Reference<Device>;
        documentReference: Reference<DocumentReference>;
    };
};


/*
 * This bot is responsible for running the calibration process.
 * - Run the lambda that handles the calibration verification 
 * - Create an Observation based on the Lambda's return
 * https://apneal.atlassian.net/wiki/spaces/ADA/pages/476545035/Code+Calibration
 */
export async function handler(medplum: MedplumClient, event: CalibrationBotEvent): Promise<any> {

    const lambdaClient = new LambdaClient();
    const invokeParams:InvokeCommandInput = {
        FunctionName: 'arn:aws:lambda:eu-west-3:XXXXXX:function:Calibration',
        InvocationType: "RequestResponse",    
        Payload: JSON.stringify('s3://bucket/file.tar.gz'),
    };
    const response = await lambdaClient.send(new InvokeCommand(invokeParams));
    let observationValue;
    if(response.StatusCode !== 200){
        observationValue = CALIBRATION_ERROR;
    } else {
        const decoder  = new TextDecoder();
        const result = decoder.decode(response.Payload);
        console.log(result);
        if(result === "true") {
            observationValue = CALIBRATION_SUCCESS;
        } else {
            observationValue = CALIBRATION_FAILED;
        }   
    }   

    await medplum.createResource({
        resourceType: 'Observation',
        code: {
            coding: [
                {
                    system: 'https://fhir.apneal.ai/code-system',
                    code: 'calibration',
                    display: 'Calibration status',
                }
            ]
        },
        status: 'final',
        valueString: observationValue,
        subject: event.input.device,
        issued: new Date().toISOString(),
    });

    console.log(event.input.documentReference)
    const document = await medplum.readResource('DocumentReference', parseReference(event.input.documentReference)[1]);
    if(document === undefined){
        throw new Error('DocumentReference not found');
    }

    await medplum.updateResource({
        ...document,
        docStatus: 'final'
    });
    
    return response.Payload;

}

I you have any idea of what is going on here I'd be glad to have your input as it is blocking for me to deploy my bots !

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.