@medplum/cli 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # Medplum Command Line Interface
2
+
3
+ The Medplum CLI (Command Line Interface) is a set of command line tools to quickly deploy Medplum web applications and Medplum bots.
4
+
5
+ ## Installation
6
+
7
+ Add as a dependency:
8
+
9
+ ```bash
10
+ npm install @medplum/cli
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Syntax:
16
+
17
+ ```bash
18
+ medplum <command> <args>
19
+ ```
20
+
21
+ At present, there is only one command called `deploy-bot`. Syntax:
22
+
23
+ ```bash
24
+ medplum deploy-bot <filename> <bot-id>
25
+ ```
26
+
27
+ Example:
28
+
29
+ ```bash
30
+ medplum deploy-bot dist/hello-world.js e54fa800-02ab-41be-8d48-8c027dd85ccc
31
+ ```
32
+
33
+ In practice, consider adding the command to the `"scripts"` section of your package.json:
34
+
35
+ ```json
36
+ "scripts": {
37
+ "build": "tsc",
38
+ "deploy:hello-world": "medplum deploy-bot dist/hello-world.js e54fa800-02ab-41be-8d48-8c0200000000"
39
+ },
40
+ ```
41
+
42
+ Then, from the command line, run:
43
+
44
+ ```bash
45
+ npm run deploy:hello-world
46
+ ```
47
+
48
+ Authentication requires client credentials in the form of environment variables `MEDPLUM_CLIENT_ID` and `MEDPLUM_CLIENT_SECRET`. This supports most use cases, including secrets from CI/CD. `dotenv` is enabled, so you could store them in `.env` file.
49
+
50
+ ## Example
51
+
52
+ Write your bot. This can be TypeScript. It can reference `@medplum/core` and `node-fetch`:
53
+
54
+ ```ts
55
+ import { MedplumClient } from '@medplum/core';
56
+ import { Resource } from '@medplum/fhirtypes';
57
+
58
+ export async function handler(medplum: MedplumClient, input: Resource): Promise<any> {
59
+ console.log('Hello world');
60
+ }
61
+ ```
62
+
63
+ Compile with vanilla `tsc` (no build tools required)
64
+
65
+ ```bash
66
+ npx tsc
67
+ ```
68
+
69
+ Or:
70
+
71
+ ```bash
72
+ npm run build
73
+ ```
74
+
75
+ You get sensible plain old JavaScript output:
76
+
77
+ ```javascript
78
+ export async function handler(medplum, input) {
79
+ console.log('Hello world');
80
+ }
81
+ ```
82
+
83
+ You can then use the Medplum CLI to deploy it.
84
+
85
+ ```bash
86
+ npm run deploy:hello-world
87
+ ```
88
+
89
+ ## About Medplum
90
+
91
+ Medplum is a healthcare platform that helps you quickly develop high-quality compliant applications. Medplum includes a FHIR server, React component library, and developer app.
92
+
93
+ ## License
94
+
95
+ Apache 2.0. Copyright &copy; Medplum 2022
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { MedplumClient } from '@medplum/core';
3
+ export declare function main(medplum: MedplumClient, argv: string[]): Promise<void>;
package/dist/index.js ADDED
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ var __importDefault = (this && this.__importDefault) || function (mod) {
13
+ return (mod && mod.__esModule) ? mod : { "default": mod };
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.main = void 0;
17
+ const core_1 = require("@medplum/core");
18
+ const dotenv_1 = __importDefault(require("dotenv"));
19
+ const fs_1 = require("fs");
20
+ const node_fetch_1 = __importDefault(require("node-fetch"));
21
+ const path_1 = require("path");
22
+ function main(medplum, argv) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ dotenv_1.default.config();
25
+ if (argv.length < 3) {
26
+ console.log('Usage: medplum <command>');
27
+ return;
28
+ }
29
+ const command = argv[2];
30
+ if (command === 'deploy-bot') {
31
+ yield deployBot(medplum, argv);
32
+ }
33
+ else {
34
+ console.log(`Unknown command: ${command}`);
35
+ }
36
+ });
37
+ }
38
+ exports.main = main;
39
+ function deployBot(medplum, argv) {
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ if (argv.length < 5) {
42
+ console.log('Usage: medplum deploy-bot <bot-name> <bot-id>');
43
+ return;
44
+ }
45
+ const botId = argv[4];
46
+ if (!botId) {
47
+ console.log('Error: Bot ID is not set');
48
+ return;
49
+ }
50
+ const filePath = (0, path_1.resolve)(process.cwd(), argv[3]);
51
+ if (!(0, fs_1.existsSync)(filePath)) {
52
+ console.log('Error: Bot file does not exist: ' + filePath);
53
+ return;
54
+ }
55
+ const bot = yield medplum.readResource('Bot', botId);
56
+ if (!bot) {
57
+ console.log('Error: Bot does not exist: ' + botId);
58
+ return;
59
+ }
60
+ console.log(JSON.stringify(bot, null, 2));
61
+ try {
62
+ console.log('Update bot code.....');
63
+ const result = yield medplum.updateResource(Object.assign(Object.assign({}, bot), { code: (0, fs_1.readFileSync)(filePath, 'utf8') }));
64
+ console.log(JSON.stringify(result, null, 2));
65
+ }
66
+ catch (err) {
67
+ console.log('Patch error: ', err);
68
+ }
69
+ });
70
+ }
71
+ if (process.argv[1].includes('medplum') && process.argv[1].includes('cli')) {
72
+ const medplum = new core_1.MedplumClient({ fetch: node_fetch_1.default });
73
+ medplum
74
+ .clientCredentials(process.env['MEDPLUM_CLIENT_ID'], process.env['MEDPLUM_CLIENT_SECRET'])
75
+ .then(() => {
76
+ main(medplum, process.argv).catch((err) => console.error('Unhandled error:', err));
77
+ });
78
+ }
79
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { MedplumClient } from '@medplum/core';\nimport { Bot } from '@medplum/fhirtypes';\nimport dotenv from 'dotenv';\nimport { existsSync, readFileSync } from 'fs';\nimport fetch from 'node-fetch';\nimport { resolve } from 'path';\n\nexport async function main(medplum: MedplumClient, argv: string[]): Promise<void> {\n dotenv.config();\n\n if (argv.length < 3) {\n console.log('Usage: medplum <command>');\n return;\n }\n\n const command = argv[2];\n if (command === 'deploy-bot') {\n await deployBot(medplum, argv);\n } else {\n console.log(`Unknown command: ${command}`);\n }\n}\n\nasync function deployBot(medplum: MedplumClient, argv: string[]): Promise<void> {\n if (argv.length < 5) {\n console.log('Usage: medplum deploy-bot <bot-name> <bot-id>');\n return;\n }\n\n const botId = argv[4];\n if (!botId) {\n console.log('Error: Bot ID is not set');\n return;\n }\n\n const filePath = resolve(process.cwd(), argv[3]);\n if (!existsSync(filePath)) {\n console.log('Error: Bot file does not exist: ' + filePath);\n return;\n }\n\n const bot = await medplum.readResource<Bot>('Bot', botId);\n if (!bot) {\n console.log('Error: Bot does not exist: ' + botId);\n return;\n }\n console.log(JSON.stringify(bot, null, 2));\n\n try {\n console.log('Update bot code.....');\n const result = await medplum.updateResource({\n ...bot,\n code: readFileSync(filePath, 'utf8'),\n });\n console.log(JSON.stringify(result, null, 2));\n } catch (err) {\n console.log('Patch error: ', err);\n }\n}\n\nif (process.argv[1].includes('medplum') && process.argv[1].includes('cli')) {\n const medplum = new MedplumClient({ fetch });\n medplum\n .clientCredentials(process.env['MEDPLUM_CLIENT_ID'] as string, process.env['MEDPLUM_CLIENT_SECRET'] as string)\n .then(() => {\n main(medplum, process.argv).catch((err) => console.error('Unhandled error:', err));\n });\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@medplum/cli",
3
+ "version": "0.9.2",
4
+ "description": "Medplum Command Line Interface",
5
+ "author": "Medplum <hello@medplum.com>",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://www.medplum.com/",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/medplum/medplum.git",
11
+ "directory": "packages/cli"
12
+ },
13
+ "scripts": {
14
+ "clean": "rimraf dist",
15
+ "build": "npm run clean && tsc",
16
+ "test": "jest"
17
+ },
18
+ "dependencies": {
19
+ "@medplum/core": "0.9.2",
20
+ "dotenv": "16.0.0",
21
+ "node-fetch": "2.6.7"
22
+ },
23
+ "devDependencies": {
24
+ "@medplum/fhirtypes": "0.9.2",
25
+ "@medplum/mock": "0.9.2"
26
+ },
27
+ "bin": {
28
+ "medplum": "./dist/index.js"
29
+ },
30
+ "keywords": [
31
+ "medplum",
32
+ "fhir",
33
+ "healthcare",
34
+ "interoperability",
35
+ "json",
36
+ "serialization",
37
+ "hl7",
38
+ "standards",
39
+ "clinical",
40
+ "dstu2",
41
+ "stu3",
42
+ "r4",
43
+ "normative"
44
+ ]
45
+ }