@medplum/cli 0.9.6 → 0.9.9

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 CHANGED
@@ -10,80 +10,129 @@ Add as a dependency:
10
10
  npm install @medplum/cli
11
11
  ```
12
12
 
13
+ ## Config file
14
+
15
+ Create a Medplum config file called `medplum.config.json`:
16
+
17
+ ```json
18
+ {
19
+ "bots": [
20
+ {
21
+ "name": "hello-world",
22
+ "id": "f0465c2e-11d4-4c36-b834-8e86f7472b4b",
23
+ "source": "src/index.ts",
24
+ "dist": "dist/index.js"
25
+ }
26
+ ]
27
+ }
28
+ ```
29
+
30
+ The `name` property is a friendly name you can use to reference the Bot in commands.
31
+
32
+ The `id` property refers to the Bot ID in your Medplum project.
33
+
34
+ The `source` property is the file path to the original source. When you "save" the Bot, the contents of this file will be saved to the Bot `code` property. This file can be JavaScript or TypeScript.
35
+
36
+ The `dist` property is the optional file path to the compiled source. If omitted, the command falls back to using the `source` property. When you "deploy" the Bot, the contents of this file will be deployed to the Bot runtime. This file must be JavaScript.
37
+
13
38
  ## Usage
14
39
 
15
40
  Syntax:
16
41
 
17
42
  ```bash
18
- medplum <command> <args>
43
+ npx medplum <command> <args>
19
44
  ```
20
45
 
21
- At present, there is only one command called `deploy-bot`. Syntax:
46
+ ### save-bot
47
+
48
+ Updates the `code` value on a `Bot` resource
49
+
50
+ Syntax:
22
51
 
23
52
  ```bash
24
- medplum deploy-bot <filename> <bot-id>
53
+ npx medplum save-bot <bot name>
25
54
  ```
26
55
 
27
56
  Example:
28
57
 
29
58
  ```bash
30
- medplum deploy-bot dist/hello-world.js e54fa800-02ab-41be-8d48-8c027dd85ccc
59
+ npx medplum save-bot hello-world
31
60
  ```
32
61
 
33
- In practice, consider adding the command to the `"scripts"` section of your package.json:
62
+ ### deploy-bot
34
63
 
35
- ```json
36
- "scripts": {
37
- "build": "tsc",
38
- "deploy:hello-world": "medplum deploy-bot dist/hello-world.js e54fa800-02ab-41be-8d48-8c0200000000"
39
- },
64
+ Deploys the Bot code
65
+
66
+ Syntax:
67
+
68
+ ```bash
69
+ npx medplum deploy-bot <bot name>
40
70
  ```
41
71
 
42
- Then, from the command line, run:
72
+ Example:
43
73
 
44
74
  ```bash
45
- npm run deploy:hello-world
75
+ npx medplum-deploy-bot <bot name>
46
76
  ```
47
77
 
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.
78
+ ## Authentication
79
+
80
+ Authentication requires client credentials in environment variables `MEDPLUM_CLIENT_ID` and `MEDPLUM_CLIENT_SECRET`. This supports most use cases, including secrets from CI/CD. `dotenv` is enabled, so you can store them in a `.env` file.
49
81
 
50
82
  ## Example
51
83
 
52
- Write your bot. This can be TypeScript. It can reference `@medplum/core` and `node-fetch`:
84
+ Create a Medplum config file `medplum.config.json`:
85
+
86
+ ```json
87
+ {
88
+ "bots": [
89
+ {
90
+ "name": "hello-world",
91
+ "id": "f0465c2e-11d4-4c36-b834-8e86f7472b4b",
92
+ "source": "src/hello-world.ts",
93
+ "dist": "dist/hello-world.js"
94
+ }
95
+ ]
96
+ }
97
+ ```
98
+
99
+ Replace the sample `id` with your Bot's ID.
100
+
101
+ Write your bot in `src/hello-world.ts`. This can be TypeScript. It can reference `@medplum/core` and `node-fetch`:
53
102
 
54
103
  ```ts
55
104
  import { MedplumClient } from '@medplum/core';
56
105
  import { Resource } from '@medplum/fhirtypes';
57
106
 
58
- export async function handler(medplum: MedplumClient, input: Resource): Promise<any> {
107
+ export async function handler(medplum: MedplumClient, event: BotEvent): Promise<any> {
59
108
  console.log('Hello world');
60
109
  }
61
110
  ```
62
111
 
63
- Compile with vanilla `tsc` (no build tools required)
112
+ You can use the Medplum CLI to save it:
64
113
 
65
114
  ```bash
66
- npx tsc
115
+ npx medplum save-bot hello-world
67
116
  ```
68
117
 
69
- Or:
118
+ Compile with vanilla `tsc` (no bundler required)
70
119
 
71
120
  ```bash
72
- npm run build
121
+ npx tsc
73
122
  ```
74
123
 
75
- You get sensible plain old JavaScript output:
124
+ The result will be JavaScript output in `dist/hello-world.js`:
76
125
 
77
126
  ```javascript
78
127
  export async function handler(medplum, input) {
79
- console.log('Hello world');
128
+ console.log('Hello world');
80
129
  }
81
130
  ```
82
131
 
83
132
  You can then use the Medplum CLI to deploy it.
84
133
 
85
134
  ```bash
86
- npm run deploy:hello-world
135
+ npx medplum deploy-bot hello-world
87
136
  ```
88
137
 
89
138
  ## About Medplum
package/dist/index.js CHANGED
@@ -26,8 +26,11 @@ function main(medplum, argv) {
26
26
  return;
27
27
  }
28
28
  const command = argv[2];
29
- if (command === 'deploy-bot') {
30
- yield deployBot(medplum, argv);
29
+ if (command === 'save-bot') {
30
+ yield runBotCommands(medplum, argv, ['save']);
31
+ }
32
+ else if (command === 'deploy-bot') {
33
+ yield runBotCommands(medplum, argv, ['save', 'deploy']);
31
34
  }
32
35
  else {
33
36
  console.log(`Unknown command: ${command}`);
@@ -35,43 +38,91 @@ function main(medplum, argv) {
35
38
  });
36
39
  }
37
40
  exports.main = main;
38
- function deployBot(medplum, argv) {
39
- var _a;
41
+ function runBotCommands(medplum, argv, commands) {
40
42
  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
+ if (argv.length < 4) {
44
+ console.log(`Usage: medplum ${argv[2]} <bot-name>`);
43
45
  return;
44
46
  }
45
- const botId = argv[4];
46
- if (!botId) {
47
- console.log('Error: Bot ID is not set');
47
+ const botName = argv[3];
48
+ const botConfig = readBotConfig(botName);
49
+ if (!botConfig) {
50
+ console.log(`Error: ${botName} not found`);
48
51
  return;
49
52
  }
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
+ const bot = yield medplum.readResource('Bot', botConfig.id);
54
+ if (!bot) {
55
+ console.log('Error: Bot does not exist: ' + botConfig.id);
53
56
  return;
54
57
  }
55
- const bot = yield medplum.readResource('Bot', botId);
56
- if (!bot) {
57
- console.log('Error: Bot does not exist: ' + botId);
58
+ if (commands.includes('save')) {
59
+ yield saveBot(medplum, botConfig, bot);
60
+ }
61
+ if (commands.includes('deploy')) {
62
+ yield deployBot(medplum, botConfig, bot);
63
+ }
64
+ });
65
+ }
66
+ function saveBot(medplum, botConfig, bot) {
67
+ var _a;
68
+ return __awaiter(this, void 0, void 0, function* () {
69
+ const code = readFileContents(botConfig.source);
70
+ if (!code) {
58
71
  return;
59
72
  }
60
73
  try {
61
74
  console.log('Update bot code.....');
62
- const result = yield medplum.updateResource(Object.assign(Object.assign({}, bot), { code: (0, fs_1.readFileSync)(filePath, 'utf8') }));
63
- console.log('Success! New bot version: ' + ((_a = result.meta) === null || _a === void 0 ? void 0 : _a.versionId));
75
+ const updateResult = yield medplum.updateResource(Object.assign(Object.assign({}, bot), { code }));
76
+ console.log('Success! New bot version: ' + ((_a = updateResult.meta) === null || _a === void 0 ? void 0 : _a.versionId));
64
77
  }
65
78
  catch (err) {
66
79
  console.log('Update error: ', err);
67
80
  }
68
81
  });
69
82
  }
83
+ function deployBot(medplum, botConfig, bot) {
84
+ var _a, _b, _c, _d;
85
+ return __awaiter(this, void 0, void 0, function* () {
86
+ const code = readFileContents((_a = botConfig.dist) !== null && _a !== void 0 ? _a : botConfig.source);
87
+ if (!code) {
88
+ return;
89
+ }
90
+ try {
91
+ console.log('Deploying bot...');
92
+ const deployResult = (yield medplum.post(medplum.fhirUrl('Bot', bot.id, '$deploy'), {
93
+ code,
94
+ }));
95
+ console.log('Deploy result: ' + ((_d = (_c = (_b = deployResult.issue) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.details) === null || _d === void 0 ? void 0 : _d.text));
96
+ }
97
+ catch (err) {
98
+ console.log('Deploy error: ', err);
99
+ }
100
+ });
101
+ }
102
+ function readBotConfig(botName) {
103
+ var _a, _b;
104
+ return (_b = (_a = readConfig()) === null || _a === void 0 ? void 0 : _a.bots) === null || _b === void 0 ? void 0 : _b.find((b) => b.name === botName);
105
+ }
106
+ function readConfig() {
107
+ const content = readFileContents('medplum.config.json');
108
+ if (!content) {
109
+ return undefined;
110
+ }
111
+ return JSON.parse(content);
112
+ }
113
+ function readFileContents(fileName) {
114
+ const path = (0, path_1.resolve)(process.cwd(), fileName);
115
+ if (!(0, fs_1.existsSync)(path)) {
116
+ console.log('Error: File does not exist: ' + path);
117
+ return '';
118
+ }
119
+ return (0, fs_1.readFileSync)(path, 'utf8');
120
+ }
70
121
  if (require.main === module) {
71
122
  dotenv_1.default.config();
72
123
  const medplum = new core_1.MedplumClient({ fetch: node_fetch_1.default });
73
124
  medplum
74
- .clientCredentials(process.env['MEDPLUM_CLIENT_ID'], process.env['MEDPLUM_CLIENT_SECRET'])
125
+ .startClientLogin(process.env['MEDPLUM_CLIENT_ID'], process.env['MEDPLUM_CLIENT_SECRET'])
75
126
  .then(() => {
76
127
  main(medplum, process.argv).catch((err) => console.error('Unhandled error:', err));
77
128
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,wCAA8C;AAE9C,oDAA4B;AAC5B,2BAA8C;AAC9C,4DAA+B;AAC/B,+BAA+B;AAE/B,SAAsB,IAAI,CAAC,OAAsB,EAAE,IAAc;;QAC/D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;YACnB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACxC,OAAO;SACR;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,OAAO,KAAK,YAAY,EAAE;YAC5B,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;SAChC;aAAM;YACL,OAAO,CAAC,GAAG,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;SAC5C;IACH,CAAC;CAAA;AAZD,oBAYC;AAED,SAAe,SAAS,CAAC,OAAsB,EAAE,IAAc;;;QAC7D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;YACnB,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;YAC7D,OAAO;SACR;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,EAAE;YACV,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACxC,OAAO;SACR;QAED,MAAM,QAAQ,GAAG,IAAA,cAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,IAAI,CAAC,IAAA,eAAU,EAAC,QAAQ,CAAC,EAAE;YACzB,OAAO,CAAC,GAAG,CAAC,kCAAkC,GAAG,QAAQ,CAAC,CAAC;YAC3D,OAAO;SACR;QAED,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,YAAY,CAAM,KAAK,EAAE,KAAK,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,EAAE;YACR,OAAO,CAAC,GAAG,CAAC,6BAA6B,GAAG,KAAK,CAAC,CAAC;YACnD,OAAO;SACR;QAED,IAAI;YACF,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACpC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,iCACtC,GAAG,KACN,IAAI,EAAE,IAAA,iBAAY,EAAC,QAAQ,EAAE,MAAM,CAAC,IACpC,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAG,MAAA,MAAM,CAAC,IAAI,0CAAE,SAAS,CAAA,CAAC,CAAC;SACpE;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;SACpC;;CACF;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE;IAC3B,gBAAM,CAAC,MAAM,EAAE,CAAC;IAChB,MAAM,OAAO,GAAG,IAAI,oBAAa,CAAC,EAAE,KAAK,EAAL,oBAAK,EAAE,CAAC,CAAC;IAC7C,OAAO;SACJ,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAW,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAW,CAAC;SAC7G,IAAI,CAAC,GAAG,EAAE;QACT,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;CACN","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 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\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('Success! New bot version: ' + result.meta?.versionId);\n } catch (err) {\n console.log('Update error: ', err);\n }\n}\n\nif (require.main === module) {\n dotenv.config();\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"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,wCAA8C;AAE9C,oDAA4B;AAC5B,2BAA8C;AAC9C,4DAA+B;AAC/B,+BAA+B;AAa/B,SAAsB,IAAI,CAAC,OAAsB,EAAE,IAAc;;QAC/D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;YACnB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACxC,OAAO;SACR;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,OAAO,KAAK,UAAU,EAAE;YAC1B,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;SAC/C;aAAM,IAAI,OAAO,KAAK,YAAY,EAAE;YACnC,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;SACzD;aAAM;YACL,OAAO,CAAC,GAAG,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;SAC5C;IACH,CAAC;CAAA;AAdD,oBAcC;AAED,SAAe,cAAc,CAAC,OAAsB,EAAE,IAAc,EAAE,QAAkB;;QACtF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;YACnB,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;YACpD,OAAO;SACR;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,SAAS,EAAE;YACd,OAAO,CAAC,GAAG,CAAC,UAAU,OAAO,YAAY,CAAC,CAAC;YAC3C,OAAO;SACR;QAED,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,YAAY,CAAM,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,GAAG,EAAE;YACR,OAAO,CAAC,GAAG,CAAC,6BAA6B,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;YAC1D,OAAO;SACR;QAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;YAC7B,MAAM,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;SACxC;QAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YAC/B,MAAM,SAAS,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;SAC1C;IACH,CAAC;CAAA;AAED,SAAe,OAAO,CAAC,OAAsB,EAAE,SAA2B,EAAE,GAAQ;;;QAClF,MAAM,IAAI,GAAG,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE;YACT,OAAO;SACR;QAED,IAAI;YACF,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACpC,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,cAAc,iCAC5C,GAAG,KACN,IAAI,IACJ,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAG,MAAA,YAAY,CAAC,IAAI,0CAAE,SAAS,CAAA,CAAC,CAAC;SAC1E;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;SACpC;;CACF;AAED,SAAe,SAAS,CAAC,OAAsB,EAAE,SAA2B,EAAE,GAAQ;;;QACpF,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAA,SAAS,CAAC,IAAI,mCAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QAClE,IAAI,CAAC,IAAI,EAAE;YACT,OAAO;SACR;QAED,IAAI;YACF,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;YAChC,MAAM,YAAY,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAY,EAAE,SAAS,CAAC,EAAE;gBAC5F,IAAI;aACL,CAAC,CAAqB,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAG,MAAA,MAAA,MAAA,YAAY,CAAC,KAAK,0CAAG,CAAC,CAAC,0CAAE,OAAO,0CAAE,IAAI,CAAA,CAAC,CAAC;SACzE;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;SACpC;;CACF;AAED,SAAS,aAAa,CAAC,OAAe;;IACpC,OAAO,MAAA,MAAA,UAAU,EAAE,0CAAE,IAAI,0CAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,UAAU;IACjB,MAAM,OAAO,GAAG,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;IACxD,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO,SAAS,CAAC;KAClB;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,IAAI,GAAG,IAAA,cAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC9C,IAAI,CAAC,IAAA,eAAU,EAAC,IAAI,CAAC,EAAE;QACrB,OAAO,CAAC,GAAG,CAAC,8BAA8B,GAAG,IAAI,CAAC,CAAC;QACnD,OAAO,EAAE,CAAC;KACX;IACD,OAAO,IAAA,iBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE;IAC3B,gBAAM,CAAC,MAAM,EAAE,CAAC;IAChB,MAAM,OAAO,GAAG,IAAI,oBAAa,CAAC,EAAE,KAAK,EAAL,oBAAK,EAAE,CAAC,CAAC;IAC7C,OAAO;SACJ,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAW,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAW,CAAC;SAC5G,IAAI,CAAC,GAAG,EAAE;QACT,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;CACN","sourcesContent":["#!/usr/bin/env node\nimport { MedplumClient } from '@medplum/core';\nimport { Bot, OperationOutcome } from '@medplum/fhirtypes';\nimport dotenv from 'dotenv';\nimport { existsSync, readFileSync } from 'fs';\nimport fetch from 'node-fetch';\nimport { resolve } from 'path';\n\ninterface MedplumConfig {\n readonly bots?: MedplumBotConfig[];\n}\n\ninterface MedplumBotConfig {\n readonly name: string;\n readonly id: string;\n readonly source: string;\n readonly dist?: string;\n}\n\nexport async function main(medplum: MedplumClient, argv: string[]): Promise<void> {\n if (argv.length < 3) {\n console.log('Usage: medplum <command>');\n return;\n }\n\n const command = argv[2];\n if (command === 'save-bot') {\n await runBotCommands(medplum, argv, ['save']);\n } else if (command === 'deploy-bot') {\n await runBotCommands(medplum, argv, ['save', 'deploy']);\n } else {\n console.log(`Unknown command: ${command}`);\n }\n}\n\nasync function runBotCommands(medplum: MedplumClient, argv: string[], commands: string[]): Promise<void> {\n if (argv.length < 4) {\n console.log(`Usage: medplum ${argv[2]} <bot-name>`);\n return;\n }\n\n const botName = argv[3];\n const botConfig = readBotConfig(botName);\n if (!botConfig) {\n console.log(`Error: ${botName} not found`);\n return;\n }\n\n const bot = await medplum.readResource<Bot>('Bot', botConfig.id);\n if (!bot) {\n console.log('Error: Bot does not exist: ' + botConfig.id);\n return;\n }\n\n if (commands.includes('save')) {\n await saveBot(medplum, botConfig, bot);\n }\n\n if (commands.includes('deploy')) {\n await deployBot(medplum, botConfig, bot);\n }\n}\n\nasync function saveBot(medplum: MedplumClient, botConfig: MedplumBotConfig, bot: Bot): Promise<void> {\n const code = readFileContents(botConfig.source);\n if (!code) {\n return;\n }\n\n try {\n console.log('Update bot code.....');\n const updateResult = await medplum.updateResource({\n ...bot,\n code,\n });\n console.log('Success! New bot version: ' + updateResult.meta?.versionId);\n } catch (err) {\n console.log('Update error: ', err);\n }\n}\n\nasync function deployBot(medplum: MedplumClient, botConfig: MedplumBotConfig, bot: Bot): Promise<void> {\n const code = readFileContents(botConfig.dist ?? botConfig.source);\n if (!code) {\n return;\n }\n\n try {\n console.log('Deploying bot...');\n const deployResult = (await medplum.post(medplum.fhirUrl('Bot', bot.id as string, '$deploy'), {\n code,\n })) as OperationOutcome;\n console.log('Deploy result: ' + deployResult.issue?.[0]?.details?.text);\n } catch (err) {\n console.log('Deploy error: ', err);\n }\n}\n\nfunction readBotConfig(botName: string): MedplumBotConfig | undefined {\n return readConfig()?.bots?.find((b) => b.name === botName);\n}\n\nfunction readConfig(): MedplumConfig | undefined {\n const content = readFileContents('medplum.config.json');\n if (!content) {\n return undefined;\n }\n return JSON.parse(content);\n}\n\nfunction readFileContents(fileName: string): string | undefined {\n const path = resolve(process.cwd(), fileName);\n if (!existsSync(path)) {\n console.log('Error: File does not exist: ' + path);\n return '';\n }\n return readFileSync(path, 'utf8');\n}\n\nif (require.main === module) {\n dotenv.config();\n const medplum = new MedplumClient({ fetch });\n medplum\n .startClientLogin(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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medplum/cli",
3
- "version": "0.9.6",
3
+ "version": "0.9.9",
4
4
  "description": "Medplum Command Line Interface",
5
5
  "author": "Medplum <hello@medplum.com>",
6
6
  "license": "Apache-2.0",
@@ -16,13 +16,13 @@
16
16
  "test": "jest"
17
17
  },
18
18
  "dependencies": {
19
- "@medplum/core": "0.9.6",
19
+ "@medplum/core": "0.9.9",
20
20
  "dotenv": "16.0.1",
21
21
  "node-fetch": "2.6.7"
22
22
  },
23
23
  "devDependencies": {
24
- "@medplum/fhirtypes": "0.9.6",
25
- "@medplum/mock": "0.9.6"
24
+ "@medplum/fhirtypes": "0.9.9",
25
+ "@medplum/mock": "0.9.9"
26
26
  },
27
27
  "bin": {
28
28
  "medplum": "./dist/index.js"