@medplum/cli 2.0.17 → 2.0.19

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
@@ -16,260 +16,9 @@ Or add as a package dependency:
16
16
  npm install @medplum/cli
17
17
  ```
18
18
 
19
- ## Authentication
20
-
21
- Use one of these authentication options:
22
-
23
- 1. Stored credentials in `~/.medplum/credentials`. You can use the `medplum login` command (see below) to automatically create this file.
24
- 2. Client credentials in environment variables `MEDPLUM_CLIENT_ID` and `MEDPLUM_CLIENT_SECRET`. `dotenv` is enabled, so you can store them in a `.env` file.
25
-
26
19
  ## Usage
27
20
 
28
- If installed globally, you can use the `medplum` command directly:
29
-
30
- ```bash
31
- medplum <command> <args>
32
- ```
33
-
34
- If installed as a package dependency, you can use the `medplum` command via `npx`:
35
-
36
- ```bash
37
- npx medplum <command> <args>
38
- ```
39
-
40
- By default, the `medplum` command uses the Medplum hosted API at "https://api.medplum.com". If you want to use the `medplum` command against your own self-hosted server, you can use the `MEDPLUM_BASE_URL` environment variable. `dotenv` is enabled, so you can store this value in a `.env` file.
41
-
42
- ### Auth
43
-
44
- #### `login`
45
-
46
- The `login` command opens a web browser to a Medplum authentication page.
47
-
48
- On successful login, the command writes credentials to disk at `~/.medplum/credentials`.
49
-
50
- The `medplum` command will then load those credentials on all future runs.
51
-
52
- Example:
53
-
54
- ```bash
55
- medplum login
56
- ```
57
-
58
- #### `whoami`
59
-
60
- The `whoami` command displays whether the client is authenticated, and, if so, the name of the current user and current Medplum project.
61
-
62
- ```bash
63
- medplum whoami
64
- ```
65
-
66
- ### RESTful Operations
67
-
68
- The `medplum` command can be used as a convenient tool for basic Medplum CRUD and RESTful operations.
69
-
70
- While all API endpoints are available to any command line HTTP client such as `curl` or `wget`, there are a few advantages to using the `medplum` command:
71
-
72
- 1. Authentication and credentials - login once using the `login` command, and the `Authorization` header will be set automatically.
73
- 2. URL prefixes - adds the base URL (i.e., "https://api.medplum.com") and FHIR path prefix (i.e., "fhir/R4/").
74
- 3. Pretty print - formats the JSON with spaces and newlines.
75
- 4. Medplum extended mode - adds the `X-Medplum` HTTP header for private Medplum fields.
76
-
77
- #### `get`
78
-
79
- Makes an HTTP `GET` request.
80
-
81
- ```bash
82
- medplum get <url>
83
- ```
84
-
85
- Example: Search for patients:
86
-
87
- ```bash
88
- medplum get 'Patient?name=homer'
89
- ```
90
-
91
- Example: Read patient by ID:
92
-
93
- ```bash
94
- medplum get Patient/$id
95
- ```
96
-
97
- #### `post`
98
-
99
- Makes an HTTP `POST` request.
100
-
101
- ```bash
102
- medplum post <url> <body>
103
- ```
104
-
105
- Example: Create a patient:
106
-
107
- ```bash
108
- medplum post Patient '{"resourceType":"Patient","name":[{"family":"Simpson"}]}'
109
- ```
110
-
111
- Example: Invoke a FHIR operation:
112
-
113
- ```bash
114
- medplum post 'Patient/$validate' '{"resourceType":"Patient","name":[{"family":"Simpson"}]}'
115
- ```
116
-
117
- #### `put`
118
-
119
- Makes an HTTP `PUT` request.
120
-
121
- ```bash
122
- medplum put <url> <body>
123
- ```
124
-
125
- Example: Update a patient:
126
-
127
- ```bash
128
- medplum put Patient/$id '{"resourceType":"Patient","name":[{"family":"Simpson"}]}'
129
- ```
130
-
131
- #### `patch`
132
-
133
- Makes an HTTP `PATCH` request.
134
-
135
- ```bash
136
- medplum patch <url> <body>
137
- ```
138
-
139
- Example: Update a patient with [JSONPatch](https://jsonpatch.com/):
140
-
141
- ```bash
142
- medplum patch Patient/$id '[{"op":"add","path":"/active","value":[true]}]'
143
- ```
144
-
145
- #### `delete`
146
-
147
- Makes an HTTP `DELETE` request.
148
-
149
- ```bash
150
- medplum delete <url>
151
- ```
152
-
153
- Example: Delete patient by ID:
154
-
155
- ```bash
156
- medplum delete Patient/$id
157
- ```
158
-
159
- ### Bots
160
-
161
- #### Bots Config file
162
-
163
- Create a Medplum config file called `medplum.config.json`:
164
-
165
- ```json
166
- {
167
- "bots": [
168
- {
169
- "name": "hello-world",
170
- "id": "f0465c2e-11d4-4c36-b834-8e86f7472b4b",
171
- "source": "src/index.ts",
172
- "dist": "dist/index.js"
173
- }
174
- ]
175
- }
176
- ```
177
-
178
- The `name` property is a friendly name you can use to reference the Bot in commands.
179
-
180
- The `id` property refers to the Bot ID in your Medplum project.
181
-
182
- 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.
183
-
184
- 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.
185
-
186
- #### save-bot
187
-
188
- Updates the `code` value on a `Bot` resource
189
-
190
- Syntax:
191
-
192
- ```bash
193
- npx medplum save-bot <bot name>
194
- ```
195
-
196
- Example:
197
-
198
- ```bash
199
- npx medplum save-bot hello-world
200
- ```
201
-
202
- #### deploy-bot
203
-
204
- Deploys the Bot code
205
-
206
- Syntax:
207
-
208
- ```bash
209
- npx medplum deploy-bot <bot name>
210
- ```
211
-
212
- Example:
213
-
214
- ```bash
215
- npx medplum-deploy-bot <bot name>
216
- ```
217
-
218
- ## Bots Example
219
-
220
- Create a Medplum config file `medplum.config.json`:
221
-
222
- ```json
223
- {
224
- "bots": [
225
- {
226
- "name": "hello-world",
227
- "id": "f0465c2e-11d4-4c36-b834-8e86f7472b4b",
228
- "source": "src/hello-world.ts",
229
- "dist": "dist/hello-world.js"
230
- }
231
- ]
232
- }
233
- ```
234
-
235
- Replace the sample `id` with your Bot's ID.
236
-
237
- Write your bot in `src/hello-world.ts`. This can be TypeScript. It can reference `@medplum/core` and `node-fetch`:
238
-
239
- ```ts
240
- import { MedplumClient } from '@medplum/core';
241
- import { Resource } from '@medplum/fhirtypes';
242
-
243
- export async function handler(medplum: MedplumClient, event: BotEvent): Promise<any> {
244
- console.log('Hello world');
245
- }
246
- ```
247
-
248
- You can use the Medplum CLI to save it:
249
-
250
- ```bash
251
- npx medplum save-bot hello-world
252
- ```
253
-
254
- Compile with vanilla `tsc` (no bundler required)
255
-
256
- ```bash
257
- npx tsc
258
- ```
259
-
260
- The result will be JavaScript output in `dist/hello-world.js`:
261
-
262
- ```javascript
263
- export async function handler(medplum, input) {
264
- console.log('Hello world');
265
- }
266
- ```
267
-
268
- You can then use the Medplum CLI to deploy it.
269
-
270
- ```bash
271
- npx medplum deploy-bot hello-world
272
- ```
21
+ See <https://www.medplum.com/docs/cli> for usage.
273
22
 
274
23
  ## About Medplum
275
24
 
@@ -5,10 +5,16 @@ var core = require('@medplum/core');
5
5
  var commander = require('commander');
6
6
  var dotenv = require('dotenv');
7
7
  var clientCloudformation = require('@aws-sdk/client-cloudformation');
8
+ var clientCloudfront = require('@aws-sdk/client-cloudfront');
8
9
  var clientEcs = require('@aws-sdk/client-ecs');
9
- var path = require('path');
10
+ var clientS3 = require('@aws-sdk/client-s3');
11
+ var fastGlob = require('fast-glob');
10
12
  var fs = require('fs');
13
+ var fetch$1 = require('node-fetch');
11
14
  var os = require('os');
15
+ var path = require('path');
16
+ var promises = require('stream/promises');
17
+ var tar = require('tar');
12
18
  var child_process = require('child_process');
13
19
  var http = require('http');
14
20
 
@@ -29,6 +35,7 @@ async function startLogin(medplum) {
29
35
  loginUrl.searchParams.set('redirect_uri', redirectUri);
30
36
  loginUrl.searchParams.set('scope', 'openid');
31
37
  loginUrl.searchParams.set('response_type', 'code');
38
+ loginUrl.searchParams.set('prompt', 'login');
32
39
  await openBrowser(loginUrl.toString());
33
40
  }
34
41
  async function startWebServer(medplum) {
@@ -95,70 +102,26 @@ function printMe(medplum) {
95
102
  }
96
103
  }
97
104
 
98
- const aws = new commander.Command('aws').description('Commands to manage AWS resources');
99
- const client = new clientCloudformation.CloudFormationClient({});
105
+ const cloudFormationClient = new clientCloudformation.CloudFormationClient({});
106
+ const cloudFrontClient = new clientCloudfront.CloudFrontClient({});
107
+ const ecsClient = new clientEcs.ECSClient({});
108
+ const s3Client = new clientS3.S3Client({});
100
109
  const tagKey = 'medplum:environment';
101
- aws
102
- .command('list')
103
- .description('List Medplum AWS CloudFormation stacks')
104
- .action(async () => {
105
- const stackSummaries = await listStacks();
106
- for (const stackSummary of stackSummaries) {
107
- const stackName = stackSummary.StackName;
108
- const details = await getStackDetails(stackName);
109
- if (!details) {
110
- continue;
111
- }
112
- printStackDetails(details);
113
- console.log('');
114
- }
115
- });
116
- aws
117
- .command('describe')
118
- .description('Describe a Medplum AWS CloudFormation stack by tag')
119
- .argument('<tag>')
120
- .action(async (tag) => {
121
- const details = await getStackByTag(tag);
122
- if (!details) {
123
- console.log('Stack not found');
124
- return;
125
- }
126
- printStackDetails(details);
127
- });
128
- aws
129
- .command('update-server')
130
- .description('Update the server image')
131
- .argument('<tag>')
132
- .action(async (tag) => {
133
- const details = await getStackByTag(tag);
134
- if (!details) {
135
- console.log('Stack not found');
136
- return;
137
- }
138
- const ecsCluster = details.ecsCluster?.PhysicalResourceId;
139
- if (!ecsCluster) {
140
- console.log('ECS Cluster not found');
141
- return;
142
- }
143
- const ecsService = getEcsServiceName(details.ecsService);
144
- if (!ecsService) {
145
- console.log('ECS Service not found');
146
- return;
147
- }
148
- const client = new clientEcs.ECSClient({});
149
- await client.send(new clientEcs.UpdateServiceCommand({
150
- cluster: ecsCluster,
151
- service: ecsService,
152
- forceNewDeployment: true,
153
- }));
154
- console.log(`Service "${ecsService}" updated successfully.`);
155
- });
156
- async function listStacks() {
157
- const listResult = await client.send(new clientCloudformation.ListStacksCommand({}));
110
+ /**
111
+ * Returns a list of all AWS CloudFormation stacks (both Medplum and non-Medplum).
112
+ * @returns List of AWS CloudFormation stacks.
113
+ */
114
+ async function getAllStacks() {
115
+ const listResult = await cloudFormationClient.send(new clientCloudformation.ListStacksCommand({}));
158
116
  return (listResult.StackSummaries?.filter((s) => s.StackName && s.StackStatus !== 'DELETE_COMPLETE') || []);
159
117
  }
118
+ /**
119
+ * Returns Medplum stack details for the given tag.
120
+ * @param tag The Medplum stack tag.
121
+ * @returns The Medplum stack details.
122
+ */
160
123
  async function getStackByTag(tag) {
161
- const stackSummaries = await listStacks();
124
+ const stackSummaries = await getAllStacks();
162
125
  for (const stackSummary of stackSummaries) {
163
126
  const stackName = stackSummary.StackName;
164
127
  const details = await getStackDetails(stackName);
@@ -168,15 +131,20 @@ async function getStackByTag(tag) {
168
131
  }
169
132
  return undefined;
170
133
  }
134
+ /**
135
+ * Returns Medplum stack details for the given stack name.
136
+ * @param stackName The CloudFormation stack name.
137
+ * @returns The Medplum stack details.
138
+ */
171
139
  async function getStackDetails(stackName) {
172
140
  const describeStacksCommand = new clientCloudformation.DescribeStacksCommand({ StackName: stackName });
173
- const stackDetails = await client.send(describeStacksCommand);
174
- const stack = stackDetails.Stacks && stackDetails.Stacks[0];
141
+ const stackDetails = await cloudFormationClient.send(describeStacksCommand);
142
+ const stack = stackDetails?.Stacks?.[0];
175
143
  const medplumTag = stack?.Tags?.find((tag) => tag.Key === tagKey);
176
144
  if (!medplumTag) {
177
145
  return undefined;
178
146
  }
179
- const stackResources = await client.send(new clientCloudformation.DescribeStackResourcesCommand({ StackName: stackName }));
147
+ const stackResources = await cloudFormationClient.send(new clientCloudformation.DescribeStackResourcesCommand({ StackName: stackName }));
180
148
  if (!stackResources.StackResources) {
181
149
  return undefined;
182
150
  }
@@ -199,9 +167,17 @@ async function getStackDetails(stackName) {
199
167
  resource.LogicalResourceId?.startsWith('StorageStorageBucket')) {
200
168
  result.storageBucket = resource;
201
169
  }
170
+ else if (resource.ResourceType === 'AWS::CloudFront::Distribution' &&
171
+ resource.LogicalResourceId?.startsWith('FrontEndAppDistribution')) {
172
+ result.appDistribution = resource;
173
+ }
202
174
  }
203
175
  return result;
204
176
  }
177
+ /**
178
+ * Prints the given Medplum stack details to stdout.
179
+ * @param details The Medplum stack details.
180
+ */
205
181
  function printStackDetails(details) {
206
182
  console.log(`Medplum Tag: ${details.tag}`);
207
183
  console.log(`Stack Name: ${details.stack.StackName}`);
@@ -212,10 +188,45 @@ function printStackDetails(details) {
212
188
  console.log(`App Bucket: ${details.appBucket?.PhysicalResourceId}`);
213
189
  console.log(`Storage Bucket: ${details.storageBucket?.PhysicalResourceId}`);
214
190
  }
191
+ /**
192
+ * Parses the ECS service name from the given AWS ECS service resource.
193
+ * @param resource The AWS ECS service resource.
194
+ * @returns The ECS service name.
195
+ */
215
196
  function getEcsServiceName(resource) {
216
197
  return resource?.PhysicalResourceId?.split('/')?.pop() || '';
217
198
  }
218
199
 
200
+ /**
201
+ * The AWS "describe" command prints details about a Medplum CloudFormation stack.
202
+ *
203
+ * @param tag The Medplum stack tag.
204
+ */
205
+ async function describeStacksCommand(tag) {
206
+ const details = await getStackByTag(tag);
207
+ if (!details) {
208
+ console.log('Stack not found');
209
+ return;
210
+ }
211
+ printStackDetails(details);
212
+ }
213
+
214
+ /**
215
+ * The AWS "list" command prints summary details about all Medplum CloudFormation stacks.
216
+ */
217
+ async function listStacksCommand() {
218
+ const stackSummaries = await getAllStacks();
219
+ for (const stackSummary of stackSummaries) {
220
+ const stackName = stackSummary.StackName;
221
+ const details = await getStackDetails(stackName);
222
+ if (!details) {
223
+ continue;
224
+ }
225
+ printStackDetails(details);
226
+ console.log('');
227
+ }
228
+ }
229
+
219
230
  function prettyPrint(input) {
220
231
  console.log(JSON.stringify(input, null, 2));
221
232
  }
@@ -295,8 +306,9 @@ function readBotConfigs(botName) {
295
306
  }
296
307
  return botConfigs;
297
308
  }
298
- function readConfig() {
299
- const content = readFileContents('medplum.config.json');
309
+ function readConfig(tagName) {
310
+ const fileName = tagName ? `medplum.${tagName}.config.json` : 'medplum.config.json';
311
+ const content = readFileContents(fileName);
300
312
  if (!content) {
301
313
  return undefined;
302
314
  }
@@ -320,6 +332,265 @@ function addBotToConfig(botConfig) {
320
332
  function escapeRegex(str) {
321
333
  return str.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
322
334
  }
335
+ /**
336
+ * Creates a safe tar extractor that limits the number of files and total size.
337
+ *
338
+ * Expanding archive files without controlling resource consumption is security-sensitive
339
+ *
340
+ * See: https://sonarcloud.io/organizations/medplum/rules?open=typescript%3AS5042&rule_key=typescript%3AS5042
341
+ *
342
+ * @param destinationDir The destination directory where all files will be extracted.
343
+ * @returns A tar file extractor.
344
+ */
345
+ function safeTarExtractor(destinationDir) {
346
+ const MAX_FILES = 100;
347
+ const MAX_SIZE = 10 * 1024 * 1024; // 10 MB
348
+ let fileCount = 0;
349
+ let totalSize = 0;
350
+ return tar.x({
351
+ cwd: destinationDir,
352
+ filter: (_path, entry) => {
353
+ fileCount++;
354
+ if (fileCount > MAX_FILES) {
355
+ throw new Error('Tar extractor reached max number of files');
356
+ }
357
+ totalSize += entry.size;
358
+ if (totalSize > MAX_SIZE) {
359
+ throw new Error('Tar extractor reached max size');
360
+ }
361
+ return true;
362
+ },
363
+ });
364
+ }
365
+
366
+ /**
367
+ * The AWS "update-app" command updates the Medplum app in a Medplum CloudFormation stack to the latest version.
368
+ * @param tag The Medplum stack tag.
369
+ */
370
+ async function updateAppCommand(tag) {
371
+ const config = readConfig(tag);
372
+ if (!config) {
373
+ console.log('Config not found');
374
+ return;
375
+ }
376
+ const details = await getStackByTag(tag);
377
+ if (!details) {
378
+ console.log('Stack not found');
379
+ return;
380
+ }
381
+ const appBucket = details.appBucket;
382
+ if (!appBucket) {
383
+ console.log('App bucket not found');
384
+ return;
385
+ }
386
+ const tmpDir = await downloadNpmPackage('@medplum/app', 'latest');
387
+ // Replace variables in the app
388
+ replaceVariables(tmpDir, {
389
+ MEDPLUM_BASE_URL: config.baseUrl,
390
+ MEDPLUM_CLIENT_ID: config.clientId || '',
391
+ GOOGLE_CLIENT_ID: config.googleClientId || '',
392
+ RECAPTCHA_SITE_KEY: config.recaptchaSiteKey || '',
393
+ MEDPLUM_REGISTER_ENABLED: config.registerEnabled ? 'true' : 'false',
394
+ });
395
+ // Upload the app to S3 with correct content-type and cache-control
396
+ await uploadAppToS3(tmpDir, appBucket.PhysicalResourceId);
397
+ // Create a CloudFront invalidation to clear any cached resources
398
+ if (details.appDistribution?.PhysicalResourceId) {
399
+ await createInvalidation(details.appDistribution.PhysicalResourceId);
400
+ }
401
+ console.log('Done');
402
+ }
403
+ /**
404
+ * Returns NPM package metadata for a given package name.
405
+ * See: https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#getpackageversion
406
+ * @param packageName The npm package name.
407
+ */
408
+ async function getNpmPackageMetadata(packageName, version) {
409
+ const url = `https://registry.npmjs.org/${packageName}/${version}`;
410
+ const response = await fetch$1(url);
411
+ return response.json();
412
+ }
413
+ /**
414
+ * Downloads and extracts an NPM package.
415
+ * @param packageName The NPM package name.
416
+ * @param version The NPM package version or "latest".
417
+ * @returns Path to temporary directory where the package was downloaded and extracted.
418
+ */
419
+ async function downloadNpmPackage(packageName, version) {
420
+ const packageMetadata = await getNpmPackageMetadata(packageName, version);
421
+ const tarballUrl = packageMetadata.dist.tarball;
422
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tarball-'));
423
+ try {
424
+ const response = await fetch$1(tarballUrl);
425
+ const extractor = safeTarExtractor(tmpDir);
426
+ await promises.pipeline(response.body, extractor);
427
+ return path.join(tmpDir, 'package', 'dist');
428
+ }
429
+ catch (error) {
430
+ fs.rmSync(tmpDir, { recursive: true, force: true });
431
+ throw error;
432
+ }
433
+ }
434
+ /**
435
+ * Replaces variables in all JS files in the given folder.
436
+ * @param folderName The folder name of the files.
437
+ * @param replacements The collection of variable placeholders and replacements.
438
+ */
439
+ function replaceVariables(folderName, replacements) {
440
+ for (const item of fs.readdirSync(folderName, { withFileTypes: true })) {
441
+ const itemPath = path.join(folderName, item.name);
442
+ if (item.isDirectory()) {
443
+ replaceVariables(itemPath, replacements);
444
+ }
445
+ else if (item.isFile() && itemPath.endsWith('.js')) {
446
+ replaceVariablesInFile(itemPath, replacements);
447
+ }
448
+ }
449
+ }
450
+ /**
451
+ * Replaces variables in the JS file.
452
+ * @param fileName The file name.
453
+ * @param replacements The collection of variable placeholders and replacements.
454
+ */
455
+ function replaceVariablesInFile(fileName, replacements) {
456
+ let contents = fs.readFileSync(fileName, 'utf-8');
457
+ for (const [placeholder, replacement] of Object.entries(replacements)) {
458
+ contents = contents.replaceAll(`process.env.${placeholder}`, `'${replacement}'`);
459
+ }
460
+ fs.writeFileSync(fileName, contents);
461
+ }
462
+ /**
463
+ * Uploads the app to S3.
464
+ * Ensures correct content-type and cache-control for each file.
465
+ * @param tmpDir The temporary directory where the app is located.
466
+ * @param bucketName The destination S3 bucket name.
467
+ */
468
+ async function uploadAppToS3(tmpDir, bucketName) {
469
+ // Manually iterate and upload files
470
+ // Automatic content-type detection is not reliable on Microsoft Windows
471
+ // So we explicitly set content-type
472
+ const uploadPatterns = [
473
+ // Cached
474
+ // These files generally have a hash, so they can be cached forever
475
+ // It is important to upload them first to avoid broken references from index.html
476
+ ['css/**/*.css', 'text/css', true],
477
+ ['css/**/*.css.map', 'application/json', true],
478
+ ['img/**/*.png', 'image/png', true],
479
+ ['img/**/*.svg', 'image/svg+xml', true],
480
+ ['js/**/*.js', 'application/javascript', true],
481
+ ['js/**/*.js.map', 'application/json', true],
482
+ ['js/**/*.txt', 'text/plain', true],
483
+ ['favicon.ico', 'image/vnd.microsoft.icon', true],
484
+ ['robots.txt', 'text/plain', true],
485
+ ['workbox-*.js', 'application/javascript', true],
486
+ ['workbox-*.js.map', 'application/json', true],
487
+ // Not cached
488
+ ['manifest.webmanifest', 'application/manifest+json', false],
489
+ ['service-worker.js', 'application/javascript', false],
490
+ ['service-worker.js.map', 'application/json', false],
491
+ ['index.html', 'text/html', false],
492
+ ];
493
+ for (const uploadPattern of uploadPatterns) {
494
+ await uploadFolderToS3({
495
+ rootDir: tmpDir,
496
+ bucketName,
497
+ fileNamePattern: uploadPattern[0],
498
+ contentType: uploadPattern[1],
499
+ cached: uploadPattern[2],
500
+ });
501
+ }
502
+ }
503
+ /**
504
+ * Uploads a directory of files to S3.
505
+ * @param options The upload options such as bucket name, content type, and cache control.
506
+ */
507
+ async function uploadFolderToS3(options) {
508
+ const items = fastGlob.sync(options.fileNamePattern, { cwd: options.rootDir });
509
+ for (const item of items) {
510
+ await uploadFileToS3(path.join(options.rootDir, item), options);
511
+ }
512
+ }
513
+ /**
514
+ * Uploads a file to S3.
515
+ * @param filePath The file path.
516
+ * @param options The upload options such as bucket name, content type, and cache control.
517
+ */
518
+ async function uploadFileToS3(filePath, options) {
519
+ const fileStream = fs.createReadStream(filePath);
520
+ const s3Key = filePath
521
+ .substring(options.rootDir.length + 1)
522
+ .split(path.sep)
523
+ .join('/');
524
+ const putObjectParams = {
525
+ Bucket: options.bucketName,
526
+ Key: s3Key,
527
+ Body: fileStream,
528
+ ContentType: options.contentType,
529
+ CacheControl: options.cached ? 'public, max-age=31536000' : 'no-cache, no-store, must-revalidate',
530
+ };
531
+ console.log(`Uploading ${s3Key} to ${options.bucketName}...`);
532
+ await s3Client.send(new clientS3.PutObjectCommand(putObjectParams));
533
+ }
534
+ /**
535
+ * Creates a CloudFront invalidation to clear the cache for all files.
536
+ * This is not strictly necessary, but it helps to ensure that the latest version of the app is served.
537
+ * In a perfect world, every deploy is clean, and hashed resources should be cached forever.
538
+ * However, we do not recalculate hashes after variable replacements.
539
+ * So if variables change, we need to invalidate the cache.
540
+ * @param distributionId The CloudFront distribution ID.
541
+ */
542
+ async function createInvalidation(distributionId) {
543
+ const response = await cloudFrontClient.send(new clientCloudfront.CreateInvalidationCommand({
544
+ DistributionId: distributionId,
545
+ InvalidationBatch: {
546
+ CallerReference: `invalidate-all-${Date.now()}`,
547
+ Paths: {
548
+ Quantity: 1,
549
+ Items: ['/*'],
550
+ },
551
+ },
552
+ }));
553
+ console.log(`Created invalidation with ID: ${response.Invalidation?.Id}`);
554
+ }
555
+
556
+ /**
557
+ * The AWS "update-server" command updates the Medplum server in a Medplum CloudFormation stack.
558
+ * @param tag The Medplum stack tag.
559
+ * @returns
560
+ */
561
+ async function updateServerCommand(tag) {
562
+ const details = await getStackByTag(tag);
563
+ if (!details) {
564
+ console.log('Stack not found');
565
+ return;
566
+ }
567
+ const ecsCluster = details.ecsCluster?.PhysicalResourceId;
568
+ if (!ecsCluster) {
569
+ console.log('ECS Cluster not found');
570
+ return;
571
+ }
572
+ const ecsService = getEcsServiceName(details.ecsService);
573
+ if (!ecsService) {
574
+ console.log('ECS Service not found');
575
+ return;
576
+ }
577
+ await ecsClient.send(new clientEcs.UpdateServiceCommand({
578
+ cluster: ecsCluster,
579
+ service: ecsService,
580
+ forceNewDeployment: true,
581
+ }));
582
+ console.log(`Service "${ecsService}" updated successfully.`);
583
+ }
584
+
585
+ const aws = new commander.Command('aws').description('Commands to manage AWS resources');
586
+ aws.command('list').description('List Medplum AWS CloudFormation stacks').action(listStacksCommand);
587
+ aws
588
+ .command('describe')
589
+ .description('Describe a Medplum AWS CloudFormation stack by tag')
590
+ .argument('<tag>')
591
+ .action(describeStacksCommand);
592
+ aws.command('update-server').description('Update the server image').argument('<tag>').action(updateServerCommand);
593
+ aws.command('update-app').description('Update the app site').argument('<tag>').action(updateAppCommand);
323
594
 
324
595
  const bot = new commander.Command('bot');
325
596
  // Commands to deprecate
@@ -409,6 +680,34 @@ project
409
680
  .action(async (projectId) => {
410
681
  await switchProject(exports.medplum, projectId);
411
682
  });
683
+ project
684
+ .command('invite')
685
+ .description('Invite a member to your current project (run npx medplum project current to confirm)')
686
+ .arguments('<firstName> <lastName> <email>')
687
+ .option('--send-email', 'If you want to send the email when inviting the user')
688
+ .option('--admin', 'If the user you are inviting is an admin')
689
+ .addOption(new commander.Option('-r, --role <role>', 'Role of user')
690
+ .choices(['Practitioner', 'Patient', 'RelatedPerson'])
691
+ .default('Practitioner'))
692
+ .action(async (firstName, lastName, email, options) => {
693
+ const login = exports.medplum.getActiveLogin();
694
+ if (!login) {
695
+ throw new Error('Unauthenticated: run `npx medplum login` to login');
696
+ }
697
+ if (!login.project?.reference) {
698
+ throw new Error('No current project to invite user to');
699
+ }
700
+ const projectId = login.project.reference.split('/')[1];
701
+ const inviteBody = {
702
+ resourceType: options.role,
703
+ firstName,
704
+ lastName,
705
+ email,
706
+ sendEmail: !!options.sendEmail,
707
+ admin: !!options.admin,
708
+ };
709
+ await inviteUser(projectId, inviteBody);
710
+ });
412
711
  async function switchProject(medplum, projectId) {
413
712
  const logins = medplum.getLogins();
414
713
  const login = logins.find((login) => login.project?.reference?.includes(projectId));
@@ -420,6 +719,18 @@ async function switchProject(medplum, projectId) {
420
719
  console.log(`Switched to project ${projectId}\n`);
421
720
  }
422
721
  }
722
+ async function inviteUser(projectId, inviteBody) {
723
+ try {
724
+ await exports.medplum.invite(projectId, inviteBody);
725
+ if (inviteBody.sendEmail) {
726
+ console.log('Email sent');
727
+ }
728
+ console.log('See your users at https://app.medplum.com/admin/users');
729
+ }
730
+ catch (err) {
731
+ console.log('Error while sending invite ' + err);
732
+ }
733
+ }
423
734
 
424
735
  const deleteObject = new commander.Command('delete');
425
736
  const get = new commander.Command('get');
@@ -518,7 +829,7 @@ async function main(medplumClient, argv) {
518
829
  }
519
830
  try {
520
831
  const index = new commander.Command('medplum').description('Command to access Medplum CLI');
521
- index.version('0.1.0');
832
+ index.version(core.MEDPLUM_VERSION);
522
833
  // Auth commands
523
834
  index.addCommand(login);
524
835
  index.addCommand(whoami);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../src/auth.ts","../../../src/aws.ts","../../../src/utils.ts","../../../src/bots.ts","../../../src/projects.ts","../../../src/rest.ts","../../../src/storage.ts","../../../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { medplum } from '.';\nimport { MedplumClient, getDisplayString, normalizeErrorString } from '@medplum/core';\nimport { platform } from 'os';\nimport { exec } from 'child_process';\nimport { createServer } from 'http';\n\nconst clientId = 'medplum-cli';\nconst redirectUri = 'http://localhost:9615';\n\nexport const login = new Command('login');\nexport const whoami = new Command('whoami');\n\nlogin.action(async () => {\n await startLogin(medplum);\n});\n\nwhoami.action(() => {\n printMe(medplum);\n});\n\nasync function startLogin(medplum: MedplumClient): Promise<void> {\n await startWebServer(medplum);\n\n const loginUrl = new URL('/oauth2/authorize', medplum.getBaseUrl());\n loginUrl.searchParams.set('client_id', clientId);\n loginUrl.searchParams.set('redirect_uri', redirectUri);\n loginUrl.searchParams.set('scope', 'openid');\n loginUrl.searchParams.set('response_type', 'code');\n await openBrowser(loginUrl.toString());\n}\n\nasync function startWebServer(medplum: MedplumClient): Promise<void> {\n const server = createServer(async (req, res) => {\n const url = new URL(req.url as string, 'http://localhost:9615');\n const code = url.searchParams.get('code');\n if (url.pathname === '/' && code) {\n try {\n const profile = await medplum.processCode(code, { clientId, redirectUri });\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end(`Signed in as ${getDisplayString(profile)}. You may close this window.`);\n } catch (err) {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end(`Error: ${normalizeErrorString(err)}`);\n } finally {\n server.close();\n }\n } else {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n }\n }).listen(9615);\n}\n\n/**\n * Opens a web browser to the specified URL.\n * See: https://hasinthaindrajee.medium.com/browser-sso-for-cli-applications-b0be743fa656\n * @param url The URL to open.\n */\nasync function openBrowser(url: string): Promise<void> {\n const os = platform();\n let cmd = undefined;\n switch (os) {\n case 'openbsd':\n case 'linux':\n cmd = `xdg-open '${url}'`;\n break;\n case 'darwin':\n cmd = `open '${url}'`;\n break;\n case 'win32':\n cmd = `cmd /c start \"\" \"${url}\"`;\n break;\n default:\n throw new Error('Unsupported platform: ' + os);\n }\n exec(cmd);\n}\n\n/**\n * Prints the current user and project.\n * @param medplum The Medplum client.\n */\nfunction printMe(medplum: MedplumClient): void {\n const loginState = medplum.getActiveLogin();\n if (loginState) {\n console.log(`Server: ${medplum.getBaseUrl()}`);\n console.log(`Profile: ${loginState.profile?.display} (${loginState.profile?.reference})`);\n console.log(`Project: ${loginState.project?.display} (${loginState.project?.reference})`);\n } else {\n console.log('Not logged in');\n }\n}\n","import {\n CloudFormationClient,\n DescribeStackResourcesCommand,\n DescribeStacksCommand,\n ListStacksCommand,\n Stack,\n StackResource,\n StackSummary,\n} from '@aws-sdk/client-cloudformation';\nimport { ECSClient, UpdateServiceCommand } from '@aws-sdk/client-ecs';\nimport { Command } from 'commander';\n\ninterface MedplumStackDetails {\n stack: Stack;\n tag: string;\n ecsCluster?: StackResource;\n ecsService?: StackResource;\n appBucket?: StackResource;\n storageBucket?: StackResource;\n}\n\nexport const aws = new Command('aws').description('Commands to manage AWS resources');\nconst client = new CloudFormationClient({});\nconst tagKey = 'medplum:environment';\n\naws\n .command('list')\n .description('List Medplum AWS CloudFormation stacks')\n .action(async () => {\n const stackSummaries = await listStacks();\n for (const stackSummary of stackSummaries) {\n const stackName = stackSummary.StackName;\n const details = await getStackDetails(stackName);\n if (!details) {\n continue;\n }\n printStackDetails(details);\n console.log('');\n }\n });\n\naws\n .command('describe')\n .description('Describe a Medplum AWS CloudFormation stack by tag')\n .argument('<tag>')\n .action(async (tag) => {\n const details = await getStackByTag(tag);\n if (!details) {\n console.log('Stack not found');\n return;\n }\n printStackDetails(details);\n });\n\naws\n .command('update-server')\n .description('Update the server image')\n .argument('<tag>')\n .action(async (tag) => {\n const details = await getStackByTag(tag);\n if (!details) {\n console.log('Stack not found');\n return;\n }\n const ecsCluster = details.ecsCluster?.PhysicalResourceId;\n if (!ecsCluster) {\n console.log('ECS Cluster not found');\n return;\n }\n const ecsService = getEcsServiceName(details.ecsService);\n if (!ecsService) {\n console.log('ECS Service not found');\n return;\n }\n const client = new ECSClient({});\n await client.send(\n new UpdateServiceCommand({\n cluster: ecsCluster,\n service: ecsService,\n forceNewDeployment: true,\n })\n );\n console.log(`Service \"${ecsService}\" updated successfully.`);\n });\n\nasync function listStacks(): Promise<(StackSummary & { StackName: string })[]> {\n const listResult = await client.send(new ListStacksCommand({}));\n return (\n (listResult.StackSummaries?.filter((s) => s.StackName && s.StackStatus !== 'DELETE_COMPLETE') as (StackSummary & {\n StackName: string;\n })[]) || []\n );\n}\n\nasync function getStackByTag(tag: string): Promise<MedplumStackDetails | undefined> {\n const stackSummaries = await listStacks();\n for (const stackSummary of stackSummaries) {\n const stackName = stackSummary.StackName;\n const details = await getStackDetails(stackName);\n if (details?.tag === tag) {\n return details;\n }\n }\n return undefined;\n}\n\nasync function getStackDetails(stackName: string): Promise<MedplumStackDetails | undefined> {\n const describeStacksCommand = new DescribeStacksCommand({ StackName: stackName });\n const stackDetails = await client.send(describeStacksCommand);\n const stack = stackDetails.Stacks && stackDetails.Stacks[0];\n const medplumTag = stack?.Tags?.find((tag) => tag.Key === tagKey);\n if (!medplumTag) {\n return undefined;\n }\n\n const stackResources = await client.send(new DescribeStackResourcesCommand({ StackName: stackName }));\n if (!stackResources.StackResources) {\n return undefined;\n }\n\n const result: MedplumStackDetails = {\n stack: stack as Stack,\n tag: medplumTag.Value as string,\n };\n\n for (const resource of stackResources.StackResources) {\n if (resource.ResourceType === 'AWS::ECS::Cluster') {\n result.ecsCluster = resource;\n } else if (resource.ResourceType === 'AWS::ECS::Service') {\n result.ecsService = resource;\n } else if (\n resource.ResourceType === 'AWS::S3::Bucket' &&\n resource.LogicalResourceId?.startsWith('FrontEndAppBucket')\n ) {\n result.appBucket = resource;\n } else if (\n resource.ResourceType === 'AWS::S3::Bucket' &&\n resource.LogicalResourceId?.startsWith('StorageStorageBucket')\n ) {\n result.storageBucket = resource;\n }\n }\n\n return result;\n}\n\nfunction printStackDetails(details: MedplumStackDetails): void {\n console.log(`Medplum Tag: ${details.tag}`);\n console.log(`Stack Name: ${details.stack.StackName}`);\n console.log(`Stack ID: ${details.stack.StackId}`);\n console.log(`Status: ${details.stack.StackStatus}`);\n console.log(`ECS Cluster: ${details.ecsCluster?.PhysicalResourceId}`);\n console.log(`ECS Service: ${getEcsServiceName(details.ecsService)}`);\n console.log(`App Bucket: ${details.appBucket?.PhysicalResourceId}`);\n console.log(`Storage Bucket: ${details.storageBucket?.PhysicalResourceId}`);\n}\n\nfunction getEcsServiceName(resource: StackResource | undefined): string | undefined {\n return resource?.PhysicalResourceId?.split('/')?.pop() || '';\n}\n","import { MedplumClient } from '@medplum/core';\nimport { resolve } from 'path';\nimport { existsSync, readFileSync, writeFile } from 'fs';\nimport { Bot, OperationOutcome } from '@medplum/fhirtypes';\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 function prettyPrint(input: unknown): void {\n console.log(JSON.stringify(input, null, 2));\n}\n\nexport async 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 if (!updateResult) {\n console.log('Bot not modified');\n } else {\n console.log('Success! New bot version: ' + updateResult.meta?.versionId);\n }\n } catch (err) {\n console.log('Update error: ', err);\n }\n}\n\nexport async 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\nexport async function createBot(medplum: MedplumClient, argv: string[]): Promise<void> {\n if (argv.length < 4) {\n console.log(`Error: command needs to be npx medplum <new-bot-name> <project-id> <source-file> <dist-file>`);\n return;\n }\n const botName = argv[0];\n const projectId = argv[1];\n const sourceFile = argv[2];\n const distFile = argv[3];\n\n try {\n const body = {\n name: botName,\n description: '',\n };\n const newBot = await medplum.post('admin/projects/' + projectId + '/bot', body);\n const bot = await medplum.readResource('Bot', newBot.id);\n\n const botConfig = {\n name: botName,\n id: newBot.id,\n source: sourceFile,\n dist: distFile,\n };\n await saveBot(medplum, botConfig as MedplumBotConfig, bot);\n console.log(`Success! Bot created: ${bot.id}`);\n\n addBotToConfig(botConfig);\n } catch (err) {\n console.log('Error while creating new bot: ' + err);\n }\n}\n\nexport function readBotConfigs(botName: string): MedplumBotConfig[] {\n const regExBotName = new RegExp('^' + escapeRegex(botName).replace(/\\\\\\*/g, '.*') + '$');\n const botConfigs = readConfig()?.bots?.filter((b) => regExBotName.test(b.name));\n if (!botConfigs) {\n return [];\n }\n return botConfigs;\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\nfunction addBotToConfig(botConfig: MedplumBotConfig): void {\n const config = readConfig();\n config?.bots?.push(botConfig);\n writeFile('medplum.config.json', JSON.stringify(config), () => {\n console.log(`Bot added to config: ${botConfig.id}`);\n });\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[/\\-\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n}\n","import { Command } from 'commander';\nimport { medplum } from '.';\nimport { createBot, deployBot, readBotConfigs, saveBot } from './utils';\nimport { MedplumClient } from '@medplum/core';\n\nexport const bot = new Command('bot');\n\n// Commands to deprecate\nexport const saveBotDeprecate = new Command('save-bot');\nexport const deployBotDeprecate = new Command('deploy-bot');\nexport const createBotDeprecate = new Command('create-bot');\n\nbot\n .command('save')\n .description('Saving the bot')\n .argument('<botName>')\n .action(async (botName) => {\n await botWrapper(medplum, botName);\n });\n\nbot\n .command('deploy')\n .description('Deploy the app to AWS')\n .argument('<botName>')\n .action(async (botName) => {\n await botWrapper(medplum, botName, true);\n });\n\nbot\n .command('create')\n .arguments('<botName> <projectId> <sourceFile> <distFile>')\n .description('Creating a bot')\n .action(async (botName, projectId, sourceFile, distFile) => {\n await createBot(medplum, [botName, projectId, sourceFile, distFile]);\n });\n\nexport async function botWrapper(medplum: MedplumClient, botName: string, deploy = false): Promise<void> {\n const botConfigs = readBotConfigs(botName);\n for (const botConfig of botConfigs) {\n const bot = await medplum.readResource('Bot', botConfig.id);\n await saveBot(medplum, botConfig, bot);\n if (deploy) {\n await deployBot(medplum, botConfig, bot);\n }\n }\n console.log(`Number of bots deployed: ${botConfigs.length}`);\n}\n\n// Deprecate bot commands\nsaveBotDeprecate\n .description('Saves the bot')\n .argument('<botName>')\n .action(async (botName) => {\n await botWrapper(medplum, botName);\n });\n\ndeployBotDeprecate\n .description('Deploy the bot to AWS')\n .argument('<botName>')\n .action(async (botName) => {\n await botWrapper(medplum, botName, true);\n });\n\ncreateBotDeprecate\n .arguments('<botName> <projectId> <sourceFile> <distFile>')\n .description('Creates and saves the bot')\n .action(async (botName, projectId, sourceFile, distFile) => {\n await createBot(medplum, [botName, projectId, sourceFile, distFile]);\n });\n","import { Command } from 'commander';\nimport { medplum } from '.';\nimport { MedplumClient, LoginState } from '@medplum/core';\n\nexport const project = new Command('project');\n\nproject\n .command('list')\n .description('List of current projects')\n .action(async () => {\n projectList(medplum);\n });\n\nfunction projectList(medplum: MedplumClient): void {\n const logins = medplum.getLogins();\n\n const projects = logins\n .map((login: LoginState) => `${login.project.display} (${login.project.reference})`)\n .join('\\n\\n');\n\n console.log(projects);\n}\n\nproject\n .command('current')\n .description('Project you are currently on')\n .action(() => {\n const login = medplum.getActiveLogin();\n if (!login) {\n throw new Error('Unauthenticated: run `npx medplum login` to login');\n }\n console.log(`${login.project.display} (${login.project.reference})`);\n });\n\nproject\n .command('switch')\n .description('Switching to another project from the current one')\n .argument('<projectId>')\n .action(async (projectId) => {\n await switchProject(medplum, projectId);\n });\n\nasync function switchProject(medplum: MedplumClient, projectId: string): Promise<void> {\n const logins = medplum.getLogins();\n const login = logins.find((login: LoginState) => login.project?.reference?.includes(projectId));\n if (!login) {\n console.log(`Error: project ${projectId} not found. Make sure you are added as a user to this project`);\n } else {\n await medplum.setActiveLogin(login);\n console.log(`Switched to project ${projectId}\\n`);\n }\n}\n","import { convertToTransactionBundle } from '@medplum/core';\nimport { Command } from 'commander';\nimport { medplum } from '.';\nimport { prettyPrint } from './utils';\n\nexport const deleteObject = new Command('delete');\nexport const get = new Command('get');\nexport const patch = new Command('patch');\nexport const post = new Command('post');\nexport const put = new Command('put');\n\ndeleteObject.argument('<url>', 'Resource/$id').action(async (url) => {\n prettyPrint(await medplum.delete(cleanUrl(url)));\n});\n\nget\n .argument('<url>', 'Resource/$id')\n .option('--as-transaction', 'Print out the bundle as a transaction type')\n .action(async (url, options) => {\n const response = await medplum.get(cleanUrl(url));\n if (options.asTransaction) {\n prettyPrint(convertToTransactionBundle(response));\n } else {\n prettyPrint(response);\n }\n });\n\npatch.arguments('<url> <body>').action(async (url, body) => {\n prettyPrint(await medplum.patch(cleanUrl(url), parseBody(body)));\n});\n\npost.arguments('<url> <body>').action(async (url, body) => {\n prettyPrint(await medplum.post(cleanUrl(url), parseBody(body)));\n});\n\nput.arguments('<url> <body>').action(async (url, body) => {\n prettyPrint(await medplum.put(cleanUrl(url), parseBody(body)));\n});\n\nfunction parseBody(input: string | undefined): any {\n if (!input) {\n return undefined;\n }\n try {\n return JSON.parse(input);\n } catch (err) {\n return input;\n }\n}\n\nexport function cleanUrl(input: string): string {\n const knownPrefixes = ['admin/', 'auth/', 'fhir/R4'];\n if (knownPrefixes.some((p) => input.startsWith(p))) {\n // If the URL starts with a known prefix, return it as-is\n return input;\n }\n // Otherwise, default to FHIR\n return 'fhir/R4/' + input;\n}\n","import { ClientStorage } from '@medplum/core';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { homedir } from 'os';\nimport { resolve } from 'path';\n\nexport class FileSystemStorage extends ClientStorage {\n private readonly dirName: string;\n private readonly fileName: string;\n\n constructor() {\n super();\n this.dirName = resolve(homedir(), '.medplum');\n this.fileName = resolve(this.dirName, 'credentials');\n }\n\n clear(): void {\n this.writeFile({});\n }\n\n getString(key: string): string | undefined {\n return this.readFile()?.[key];\n }\n\n setString(key: string, value: string | undefined): void {\n const data = this.readFile() || {};\n if (value) {\n data[key] = value;\n } else {\n delete data[key];\n }\n this.writeFile(data);\n }\n\n private readFile(): Record<string, string> | undefined {\n if (existsSync(this.fileName)) {\n return JSON.parse(readFileSync(this.fileName, 'utf8'));\n }\n return undefined;\n }\n\n private writeFile(data: Record<string, string>): void {\n if (!existsSync(this.dirName)) {\n mkdirSync(this.dirName);\n }\n writeFileSync(this.fileName, JSON.stringify(data, null, 2), 'utf8');\n }\n}\n","import { MedplumClient, normalizeErrorString } from '@medplum/core';\nimport { Command } from 'commander';\nimport dotenv from 'dotenv';\nimport { login, whoami } from './auth';\nimport { aws } from './aws';\nimport { bot, createBotDeprecate, deployBotDeprecate, saveBotDeprecate } from './bots';\nimport { project } from './projects';\nimport { deleteObject, get, patch, post, put } from './rest';\nimport { FileSystemStorage } from './storage';\n\nexport let medplum: MedplumClient;\n\nexport async function main(medplumClient: MedplumClient, argv: string[]): Promise<void> {\n medplum = medplumClient;\n\n // Legacy support for MEDPLUM_CLIENT_ID and MEDPLUM_CLIENT_SECRET environment variables\n const clientId = process.env['MEDPLUM_CLIENT_ID'];\n const clientSecret = process.env['MEDPLUM_CLIENT_SECRET'];\n if (clientId && clientSecret) {\n await medplum.startClientLogin(clientId, clientSecret);\n }\n try {\n const index = new Command('medplum').description('Command to access Medplum CLI');\n index.version('0.1.0');\n\n // Auth commands\n index.addCommand(login);\n index.addCommand(whoami);\n\n // REST commands\n index.addCommand(get);\n index.addCommand(post);\n index.addCommand(patch);\n index.addCommand(put);\n index.addCommand(deleteObject);\n\n // Project\n index.addCommand(project);\n\n // Bot Commands\n index.addCommand(bot);\n\n // Deprecated Bot Commands\n index.addCommand(saveBotDeprecate);\n index.addCommand(deployBotDeprecate);\n index.addCommand(createBotDeprecate);\n\n // AWS commands\n index.addCommand(aws);\n\n await index.parseAsync(argv);\n } catch (err) {\n console.error('Error: ' + normalizeErrorString(err));\n }\n}\n\nif (require.main === module) {\n dotenv.config();\n const baseUrl = process.env['MEDPLUM_BASE_URL'] || 'https://api.medplum.com/';\n const medplumClient = new MedplumClient({\n fetch,\n baseUrl,\n storage: new FileSystemStorage(),\n onUnauthenticated: onUnauthenticated,\n });\n main(medplumClient, process.argv).catch((err) => console.error('Unhandled error:', err));\n}\n\nfunction onUnauthenticated(): void {\n console.log('Unauthenticated: run `npx medplum login` to sign in');\n}\n"],"names":["Command","medplum","createServer","getDisplayString","normalizeErrorString","os","platform","exec","CloudFormationClient","ECSClient","UpdateServiceCommand","ListStacksCommand","DescribeStacksCommand","DescribeStackResourcesCommand","path","resolve","existsSync","readFileSync","writeFile","convertToTransactionBundle","ClientStorage","homedir","mkdirSync","writeFileSync","MedplumClient"],"mappings":";;;;;;;;;;;;;;AAOA,MAAM,QAAQ,GAAG,aAAa,CAAC;AAC/B,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAErC,MAAM,KAAK,GAAG,IAAIA,iBAAO,CAAC,OAAO,CAAC,CAAC;AACnC,MAAM,MAAM,GAAG,IAAIA,iBAAO,CAAC,QAAQ,CAAC,CAAC;AAE5C,KAAK,CAAC,MAAM,CAAC,YAAW;AACtB,IAAA,MAAM,UAAU,CAACC,eAAO,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,CAAC,MAAK;IACjB,OAAO,CAACA,eAAO,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEH,eAAe,UAAU,CAAC,OAAsB,EAAA;AAC9C,IAAA,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;AAE9B,IAAA,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,mBAAmB,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACpE,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACjD,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IACvD,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;AACnD,IAAA,MAAM,WAAW,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,eAAe,cAAc,CAAC,OAAsB,EAAA;IAClD,MAAM,MAAM,GAAGC,iBAAY,CAAC,OAAO,GAAG,EAAE,GAAG,KAAI;QAC7C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAa,EAAE,uBAAuB,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC1C,QAAA,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,IAAI,EAAE;YAChC,IAAI;AACF,gBAAA,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC3E,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;gBACrD,GAAG,CAAC,GAAG,CAAC,CAAgB,aAAA,EAAAC,qBAAgB,CAAC,OAAO,CAAC,CAA8B,4BAAA,CAAA,CAAC,CAAC;AAClF,aAAA;AAAC,YAAA,OAAO,GAAG,EAAE;gBACZ,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;gBACrD,GAAG,CAAC,GAAG,CAAC,CAAU,OAAA,EAAAC,yBAAoB,CAAC,GAAG,CAAC,CAAE,CAAA,CAAC,CAAC;AAChD,aAAA;AAAS,oBAAA;gBACR,MAAM,CAAC,KAAK,EAAE,CAAC;AAChB,aAAA;AACF,SAAA;AAAM,aAAA;YACL,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;AACrD,YAAA,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AACtB,SAAA;AACH,KAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAClB,CAAC;AAED;;;;AAIG;AACH,eAAe,WAAW,CAAC,GAAW,EAAA;AACpC,IAAA,MAAMC,IAAE,GAAGC,WAAQ,EAAE,CAAC;IACtB,IAAI,GAAG,GAAG,SAAS,CAAC;AACpB,IAAA,QAAQD,IAAE;AACR,QAAA,KAAK,SAAS,CAAC;AACf,QAAA,KAAK,OAAO;AACV,YAAA,GAAG,GAAG,CAAA,UAAA,EAAa,GAAG,CAAA,CAAA,CAAG,CAAC;YAC1B,MAAM;AACR,QAAA,KAAK,QAAQ;AACX,YAAA,GAAG,GAAG,CAAA,MAAA,EAAS,GAAG,CAAA,CAAA,CAAG,CAAC;YACtB,MAAM;AACR,QAAA,KAAK,OAAO;AACV,YAAA,GAAG,GAAG,CAAA,iBAAA,EAAoB,GAAG,CAAA,CAAA,CAAG,CAAC;YACjC,MAAM;AACR,QAAA;AACE,YAAA,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAGA,IAAE,CAAC,CAAC;AAClD,KAAA;IACDE,kBAAI,CAAC,GAAG,CAAC,CAAC;AACZ,CAAC;AAED;;;AAGG;AACH,SAAS,OAAO,CAAC,OAAsB,EAAA;AACrC,IAAA,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;AAC5C,IAAA,IAAI,UAAU,EAAE;QACd,OAAO,CAAC,GAAG,CAAC,CAAY,SAAA,EAAA,OAAO,CAAC,UAAU,EAAE,CAAE,CAAA,CAAC,CAAC;AAChD,QAAA,OAAO,CAAC,GAAG,CAAC,CAAY,SAAA,EAAA,UAAU,CAAC,OAAO,EAAE,OAAO,CAAA,EAAA,EAAK,UAAU,CAAC,OAAO,EAAE,SAAS,CAAA,CAAA,CAAG,CAAC,CAAC;AAC1F,QAAA,OAAO,CAAC,GAAG,CAAC,CAAY,SAAA,EAAA,UAAU,CAAC,OAAO,EAAE,OAAO,CAAA,EAAA,EAAK,UAAU,CAAC,OAAO,EAAE,SAAS,CAAA,CAAA,CAAG,CAAC,CAAC;AAC3F,KAAA;AAAM,SAAA;AACL,QAAA,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAC9B,KAAA;AACH;;ACvEO,MAAM,GAAG,GAAG,IAAIP,iBAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,kCAAkC,CAAC,CAAC;AACtF,MAAM,MAAM,GAAG,IAAIQ,yCAAoB,CAAC,EAAE,CAAC,CAAC;AAC5C,MAAM,MAAM,GAAG,qBAAqB,CAAC;AAErC,GAAG;KACA,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,YAAW;AACjB,IAAA,MAAM,cAAc,GAAG,MAAM,UAAU,EAAE,CAAC;AAC1C,IAAA,KAAK,MAAM,YAAY,IAAI,cAAc,EAAE;AACzC,QAAA,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC;AACzC,QAAA,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,OAAO,EAAE;YACZ,SAAS;AACV,SAAA;QACD,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC3B,QAAA,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACjB,KAAA;AACH,CAAC,CAAC,CAAC;AAEL,GAAG;KACA,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,oDAAoD,CAAC;KACjE,QAAQ,CAAC,OAAO,CAAC;AACjB,KAAA,MAAM,CAAC,OAAO,GAAG,KAAI;AACpB,IAAA,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC/B,OAAO;AACR,KAAA;IACD,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEL,GAAG;KACA,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,yBAAyB,CAAC;KACtC,QAAQ,CAAC,OAAO,CAAC;AACjB,KAAA,MAAM,CAAC,OAAO,GAAG,KAAI;AACpB,IAAA,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC/B,OAAO;AACR,KAAA;AACD,IAAA,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,kBAAkB,CAAC;IAC1D,IAAI,CAAC,UAAU,EAAE;AACf,QAAA,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO;AACR,KAAA;IACD,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACzD,IAAI,CAAC,UAAU,EAAE;AACf,QAAA,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO;AACR,KAAA;AACD,IAAA,MAAM,MAAM,GAAG,IAAIC,mBAAS,CAAC,EAAE,CAAC,CAAC;AACjC,IAAA,MAAM,MAAM,CAAC,IAAI,CACf,IAAIC,8BAAoB,CAAC;AACvB,QAAA,OAAO,EAAE,UAAU;AACnB,QAAA,OAAO,EAAE,UAAU;AACnB,QAAA,kBAAkB,EAAE,IAAI;AACzB,KAAA,CAAC,CACH,CAAC;AACF,IAAA,OAAO,CAAC,GAAG,CAAC,YAAY,UAAU,CAAA,uBAAA,CAAyB,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC;AAEL,eAAe,UAAU,GAAA;AACvB,IAAA,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAIC,sCAAiB,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,QACG,UAAU,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,WAAW,KAAK,iBAAiB,CAEvF,IAAI,EAAE,EACX;AACJ,CAAC;AAED,eAAe,aAAa,CAAC,GAAW,EAAA;AACtC,IAAA,MAAM,cAAc,GAAG,MAAM,UAAU,EAAE,CAAC;AAC1C,IAAA,KAAK,MAAM,YAAY,IAAI,cAAc,EAAE;AACzC,QAAA,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC;AACzC,QAAA,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC;AACjD,QAAA,IAAI,OAAO,EAAE,GAAG,KAAK,GAAG,EAAE;AACxB,YAAA,OAAO,OAAO,CAAC;AAChB,SAAA;AACF,KAAA;AACD,IAAA,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,eAAe,eAAe,CAAC,SAAiB,EAAA;IAC9C,MAAM,qBAAqB,GAAG,IAAIC,0CAAqB,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;IAClF,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;AAC9D,IAAA,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5D,IAAA,MAAM,UAAU,GAAG,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;IAClE,IAAI,CAAC,UAAU,EAAE;AACf,QAAA,OAAO,SAAS,CAAC;AAClB,KAAA;AAED,IAAA,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAIC,kDAA6B,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AACtG,IAAA,IAAI,CAAC,cAAc,CAAC,cAAc,EAAE;AAClC,QAAA,OAAO,SAAS,CAAC;AAClB,KAAA;AAED,IAAA,MAAM,MAAM,GAAwB;AAClC,QAAA,KAAK,EAAE,KAAc;QACrB,GAAG,EAAE,UAAU,CAAC,KAAe;KAChC,CAAC;AAEF,IAAA,KAAK,MAAM,QAAQ,IAAI,cAAc,CAAC,cAAc,EAAE;AACpD,QAAA,IAAI,QAAQ,CAAC,YAAY,KAAK,mBAAmB,EAAE;AACjD,YAAA,MAAM,CAAC,UAAU,GAAG,QAAQ,CAAC;AAC9B,SAAA;AAAM,aAAA,IAAI,QAAQ,CAAC,YAAY,KAAK,mBAAmB,EAAE;AACxD,YAAA,MAAM,CAAC,UAAU,GAAG,QAAQ,CAAC;AAC9B,SAAA;AAAM,aAAA,IACL,QAAQ,CAAC,YAAY,KAAK,iBAAiB;AAC3C,YAAA,QAAQ,CAAC,iBAAiB,EAAE,UAAU,CAAC,mBAAmB,CAAC,EAC3D;AACA,YAAA,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC;AAC7B,SAAA;AAAM,aAAA,IACL,QAAQ,CAAC,YAAY,KAAK,iBAAiB;AAC3C,YAAA,QAAQ,CAAC,iBAAiB,EAAE,UAAU,CAAC,sBAAsB,CAAC,EAC9D;AACA,YAAA,MAAM,CAAC,aAAa,GAAG,QAAQ,CAAC;AACjC,SAAA;AACF,KAAA;AAED,IAAA,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,iBAAiB,CAAC,OAA4B,EAAA;IACrD,OAAO,CAAC,GAAG,CAAC,CAAA,iBAAA,EAAoB,OAAO,CAAC,GAAG,CAAE,CAAA,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,CAAoB,iBAAA,EAAA,OAAO,CAAC,KAAK,CAAC,SAAS,CAAE,CAAA,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,CAAoB,iBAAA,EAAA,OAAO,CAAC,KAAK,CAAC,OAAO,CAAE,CAAA,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,CAAoB,iBAAA,EAAA,OAAO,CAAC,KAAK,CAAC,WAAW,CAAE,CAAA,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,CAAoB,iBAAA,EAAA,OAAO,CAAC,UAAU,EAAE,kBAAkB,CAAE,CAAA,CAAC,CAAC;AAC1E,IAAA,OAAO,CAAC,GAAG,CAAC,CAAA,iBAAA,EAAoB,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAE,CAAA,CAAC,CAAC;IACzE,OAAO,CAAC,GAAG,CAAC,CAAoB,iBAAA,EAAA,OAAO,CAAC,SAAS,EAAE,kBAAkB,CAAE,CAAA,CAAC,CAAC;IACzE,OAAO,CAAC,GAAG,CAAC,CAAoB,iBAAA,EAAA,OAAO,CAAC,aAAa,EAAE,kBAAkB,CAAE,CAAA,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAmC,EAAA;AAC5D,IAAA,OAAO,QAAQ,EAAE,kBAAkB,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAC/D;;AC/IM,SAAU,WAAW,CAAC,KAAc,EAAA;AACxC,IAAA,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC;AAEM,eAAe,OAAO,CAAC,OAAsB,EAAE,SAA2B,EAAE,GAAQ,EAAA;IACzF,MAAM,IAAI,GAAG,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,CAAC,IAAI,EAAE;QACT,OAAO;AACR,KAAA;IAED,IAAI;AACF,QAAA,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;AACpC,QAAA,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC;AAChD,YAAA,GAAG,GAAG;YACN,IAAI;AACL,SAAA,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,EAAE;AACjB,YAAA,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AACjC,SAAA;AAAM,aAAA;YACL,OAAO,CAAC,GAAG,CAAC,4BAA4B,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AAC1E,SAAA;AACF,KAAA;AAAC,IAAA,OAAO,GAAG,EAAE;AACZ,QAAA,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;AACpC,KAAA;AACH,CAAC;AAEM,eAAe,SAAS,CAAC,OAAsB,EAAE,SAA2B,EAAE,GAAQ,EAAA;AAC3F,IAAA,MAAM,IAAI,GAAG,gBAAgB,CAAC,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;IAClE,IAAI,CAAC,IAAI,EAAE;QACT,OAAO;AACR,KAAA;IAED,IAAI;AACF,QAAA,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChC,MAAM,YAAY,IAAI,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAY,EAAE,SAAS,CAAC,EAAE;YAC5F,IAAI;AACL,SAAA,CAAC,CAAqB,CAAC;AACxB,QAAA,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AACzE,KAAA;AAAC,IAAA,OAAO,GAAG,EAAE;AACZ,QAAA,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;AACpC,KAAA;AACH,CAAC;AAEM,eAAe,SAAS,CAAC,OAAsB,EAAE,IAAc,EAAA;AACpE,IAAA,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AACnB,QAAA,OAAO,CAAC,GAAG,CAAC,CAAA,4FAAA,CAA8F,CAAC,CAAC;QAC5G,OAAO;AACR,KAAA;AACD,IAAA,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACxB,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAC1B,IAAA,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3B,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEzB,IAAI;AACF,QAAA,MAAM,IAAI,GAAG;AACX,YAAA,IAAI,EAAE,OAAO;AACb,YAAA,WAAW,EAAE,EAAE;SAChB,CAAC;AACF,QAAA,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,iBAAiB,GAAG,SAAS,GAAG,MAAM,EAAE,IAAI,CAAC,CAAC;AAChF,QAAA,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAEzD,QAAA,MAAM,SAAS,GAAG;AAChB,YAAA,IAAI,EAAE,OAAO;YACb,EAAE,EAAE,MAAM,CAAC,EAAE;AACb,YAAA,MAAM,EAAE,UAAU;AAClB,YAAA,IAAI,EAAE,QAAQ;SACf,CAAC;QACF,MAAM,OAAO,CAAC,OAAO,EAAE,SAA6B,EAAE,GAAG,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,CAAA,sBAAA,EAAyB,GAAG,CAAC,EAAE,CAAE,CAAA,CAAC,CAAC;QAE/C,cAAc,CAAC,SAAS,CAAC,CAAC;AAC3B,KAAA;AAAC,IAAA,OAAO,GAAG,EAAE;AACZ,QAAA,OAAO,CAAC,GAAG,CAAC,gCAAgC,GAAG,GAAG,CAAC,CAAC;AACrD,KAAA;AACH,CAAC;AAEK,SAAU,cAAc,CAAC,OAAe,EAAA;IAC5C,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;IACzF,MAAM,UAAU,GAAG,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAChF,IAAI,CAAC,UAAU,EAAE;AACf,QAAA,OAAO,EAAE,CAAC;AACX,KAAA;AACD,IAAA,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,UAAU,GAAA;AACjB,IAAA,MAAM,OAAO,GAAG,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;IACxD,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,OAAO,SAAS,CAAC;AAClB,KAAA;AACD,IAAA,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAgB,EAAA;IACxC,MAAMC,MAAI,GAAGC,YAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC9C,IAAA,IAAI,CAACC,aAAU,CAACF,MAAI,CAAC,EAAE;AACrB,QAAA,OAAO,CAAC,GAAG,CAAC,8BAA8B,GAAGA,MAAI,CAAC,CAAC;AACnD,QAAA,OAAO,EAAE,CAAC;AACX,KAAA;AACD,IAAA,OAAOG,eAAY,CAACH,MAAI,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,cAAc,CAAC,SAA2B,EAAA;AACjD,IAAA,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,IAAA,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9BI,YAAS,CAAC,qBAAqB,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAK;QAC5D,OAAO,CAAC,GAAG,CAAC,CAAA,qBAAA,EAAwB,SAAS,CAAC,EAAE,CAAE,CAAA,CAAC,CAAC;AACtD,KAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,GAAW,EAAA;IAC9B,OAAO,GAAG,CAAC,OAAO,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;AACvD;;AC3HO,MAAM,GAAG,GAAG,IAAIlB,iBAAO,CAAC,KAAK,CAAC,CAAC;AAEtC;AACO,MAAM,gBAAgB,GAAG,IAAIA,iBAAO,CAAC,UAAU,CAAC,CAAC;AACjD,MAAM,kBAAkB,GAAG,IAAIA,iBAAO,CAAC,YAAY,CAAC,CAAC;AACrD,MAAM,kBAAkB,GAAG,IAAIA,iBAAO,CAAC,YAAY,CAAC,CAAC;AAE5D,GAAG;KACA,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,gBAAgB,CAAC;KAC7B,QAAQ,CAAC,WAAW,CAAC;AACrB,KAAA,MAAM,CAAC,OAAO,OAAO,KAAI;AACxB,IAAA,MAAM,UAAU,CAACC,eAAO,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEL,GAAG;KACA,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,uBAAuB,CAAC;KACpC,QAAQ,CAAC,WAAW,CAAC;AACrB,KAAA,MAAM,CAAC,OAAO,OAAO,KAAI;IACxB,MAAM,UAAU,CAACA,eAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEL,GAAG;KACA,OAAO,CAAC,QAAQ,CAAC;KACjB,SAAS,CAAC,+CAA+C,CAAC;KAC1D,WAAW,CAAC,gBAAgB,CAAC;KAC7B,MAAM,CAAC,OAAO,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,KAAI;AACzD,IAAA,MAAM,SAAS,CAACA,eAAO,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;AACvE,CAAC,CAAC,CAAC;AAEE,eAAe,UAAU,CAAC,OAAsB,EAAE,OAAe,EAAE,MAAM,GAAG,KAAK,EAAA;AACtF,IAAA,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;AAC3C,IAAA,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE;AAClC,QAAA,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;QAC5D,MAAM,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;AACvC,QAAA,IAAI,MAAM,EAAE;YACV,MAAM,SAAS,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;AAC1C,SAAA;AACF,KAAA;IACD,OAAO,CAAC,GAAG,CAAC,CAAA,yBAAA,EAA4B,UAAU,CAAC,MAAM,CAAE,CAAA,CAAC,CAAC;AAC/D,CAAC;AAED;AACA,gBAAgB;KACb,WAAW,CAAC,eAAe,CAAC;KAC5B,QAAQ,CAAC,WAAW,CAAC;AACrB,KAAA,MAAM,CAAC,OAAO,OAAO,KAAI;AACxB,IAAA,MAAM,UAAU,CAACA,eAAO,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEL,kBAAkB;KACf,WAAW,CAAC,uBAAuB,CAAC;KACpC,QAAQ,CAAC,WAAW,CAAC;AACrB,KAAA,MAAM,CAAC,OAAO,OAAO,KAAI;IACxB,MAAM,UAAU,CAACA,eAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEL,kBAAkB;KACf,SAAS,CAAC,+CAA+C,CAAC;KAC1D,WAAW,CAAC,2BAA2B,CAAC;KACxC,MAAM,CAAC,OAAO,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,KAAI;AACzD,IAAA,MAAM,SAAS,CAACA,eAAO,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;AACvE,CAAC,CAAC;;AChEG,MAAM,OAAO,GAAG,IAAID,iBAAO,CAAC,SAAS,CAAC,CAAC;AAE9C,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,0BAA0B,CAAC;KACvC,MAAM,CAAC,YAAW;IACjB,WAAW,CAACC,eAAO,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC;AAEL,SAAS,WAAW,CAAC,OAAsB,EAAA;AACzC,IAAA,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAEnC,MAAM,QAAQ,GAAG,MAAM;AACpB,SAAA,GAAG,CAAC,CAAC,KAAiB,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC;SACnF,IAAI,CAAC,MAAM,CAAC,CAAC;AAEhB,IAAA,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACxB,CAAC;AAED,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,8BAA8B,CAAC;KAC3C,MAAM,CAAC,MAAK;AACX,IAAA,MAAM,KAAK,GAAGA,eAAO,CAAC,cAAc,EAAE,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE;AACV,QAAA,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;AACtE,KAAA;AACD,IAAA,OAAO,CAAC,GAAG,CAAC,CAAG,EAAA,KAAK,CAAC,OAAO,CAAC,OAAO,CAAA,EAAA,EAAK,KAAK,CAAC,OAAO,CAAC,SAAS,CAAA,CAAA,CAAG,CAAC,CAAC;AACvE,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,mDAAmD,CAAC;KAChE,QAAQ,CAAC,aAAa,CAAC;AACvB,KAAA,MAAM,CAAC,OAAO,SAAS,KAAI;AAC1B,IAAA,MAAM,aAAa,CAACA,eAAO,EAAE,SAAS,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEL,eAAe,aAAa,CAAC,OAAsB,EAAE,SAAiB,EAAA;AACpE,IAAA,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAiB,KAAK,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IAChG,IAAI,CAAC,KAAK,EAAE;AACV,QAAA,OAAO,CAAC,GAAG,CAAC,kBAAkB,SAAS,CAAA,6DAAA,CAA+D,CAAC,CAAC;AACzG,KAAA;AAAM,SAAA;AACL,QAAA,MAAM,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AACpC,QAAA,OAAO,CAAC,GAAG,CAAC,uBAAuB,SAAS,CAAA,EAAA,CAAI,CAAC,CAAC;AACnD,KAAA;AACH;;AC9CO,MAAM,YAAY,GAAG,IAAID,iBAAO,CAAC,QAAQ,CAAC,CAAC;AAC3C,MAAM,GAAG,GAAG,IAAIA,iBAAO,CAAC,KAAK,CAAC,CAAC;AAC/B,MAAM,KAAK,GAAG,IAAIA,iBAAO,CAAC,OAAO,CAAC,CAAC;AACnC,MAAM,IAAI,GAAG,IAAIA,iBAAO,CAAC,MAAM,CAAC,CAAC;AACjC,MAAM,GAAG,GAAG,IAAIA,iBAAO,CAAC,KAAK,CAAC,CAAC;AAEtC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,KAAI;AAClE,IAAA,WAAW,CAAC,MAAMC,eAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC;AAEH,GAAG;AACA,KAAA,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;AACjC,KAAA,MAAM,CAAC,kBAAkB,EAAE,4CAA4C,CAAC;AACxE,KAAA,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,KAAI;AAC7B,IAAA,MAAM,QAAQ,GAAG,MAAMA,eAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,IAAI,OAAO,CAAC,aAAa,EAAE;AACzB,QAAA,WAAW,CAACkB,+BAA0B,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnD,KAAA;AAAM,SAAA;QACL,WAAW,CAAC,QAAQ,CAAC,CAAC;AACvB,KAAA;AACH,CAAC,CAAC,CAAC;AAEL,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,EAAE,IAAI,KAAI;AACzD,IAAA,WAAW,CAAC,MAAMlB,eAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,EAAE,IAAI,KAAI;AACxD,IAAA,WAAW,CAAC,MAAMA,eAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,EAAE,IAAI,KAAI;AACvD,IAAA,WAAW,CAAC,MAAMA,eAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC,CAAC,CAAC;AAEH,SAAS,SAAS,CAAC,KAAyB,EAAA;IAC1C,IAAI,CAAC,KAAK,EAAE;AACV,QAAA,OAAO,SAAS,CAAC;AAClB,KAAA;IACD,IAAI;AACF,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC1B,KAAA;AAAC,IAAA,OAAO,GAAG,EAAE;AACZ,QAAA,OAAO,KAAK,CAAC;AACd,KAAA;AACH,CAAC;AAEK,SAAU,QAAQ,CAAC,KAAa,EAAA;IACpC,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AACrD,IAAA,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE;;AAElD,QAAA,OAAO,KAAK,CAAC;AACd,KAAA;;IAED,OAAO,UAAU,GAAG,KAAK,CAAC;AAC5B;;ACrDM,MAAO,iBAAkB,SAAQmB,kBAAa,CAAA;AAIlD,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAGL,YAAO,CAACM,UAAO,EAAE,EAAE,UAAU,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,GAAGN,YAAO,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;KACtD;IAED,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;KACpB;AAED,IAAA,SAAS,CAAC,GAAW,EAAA;QACnB,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAC,CAAC;KAC/B;IAED,SAAS,CAAC,GAAW,EAAE,KAAyB,EAAA;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;AACnC,QAAA,IAAI,KAAK,EAAE;AACT,YAAA,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AACnB,SAAA;AAAM,aAAA;AACL,YAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAClB,SAAA;AACD,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;KACtB;IAEO,QAAQ,GAAA;AACd,QAAA,IAAIC,aAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAC7B,YAAA,OAAO,IAAI,CAAC,KAAK,CAACC,eAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;AACxD,SAAA;AACD,QAAA,OAAO,SAAS,CAAC;KAClB;AAEO,IAAA,SAAS,CAAC,IAA4B,EAAA;AAC5C,QAAA,IAAI,CAACD,aAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAC7B,YAAAM,YAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACzB,SAAA;AACD,QAAAC,gBAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;KACrE;AACF;;ACpCUtB,yBAAuB;AAE3B,eAAe,IAAI,CAAC,aAA4B,EAAE,IAAc,EAAA;IACrEA,eAAO,GAAG,aAAa,CAAC;;IAGxB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IAC1D,IAAI,QAAQ,IAAI,YAAY,EAAE;QAC5B,MAAMA,eAAO,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;AACxD,KAAA;IACD,IAAI;AACF,QAAA,MAAM,KAAK,GAAG,IAAID,iBAAO,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,+BAA+B,CAAC,CAAC;AAClF,QAAA,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;;AAGvB,QAAA,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACxB,QAAA,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;;AAGzB,QAAA,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACtB,QAAA,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AACvB,QAAA,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACxB,QAAA,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACtB,QAAA,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;;AAG/B,QAAA,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;;AAG1B,QAAA,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;;AAGtB,QAAA,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACnC,QAAA,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;AACrC,QAAA,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;;AAGrC,QAAA,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAEtB,QAAA,MAAM,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAC9B,KAAA;AAAC,IAAA,OAAO,GAAG,EAAE;QACZ,OAAO,CAAC,KAAK,CAAC,SAAS,GAAGI,yBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;AACtD,KAAA;AACH,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE;IAC3B,MAAM,CAAC,MAAM,EAAE,CAAC;IAChB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,0BAA0B,CAAC;AAC9E,IAAA,MAAM,aAAa,GAAG,IAAIoB,kBAAa,CAAC;QACtC,KAAK;QACL,OAAO;QACP,OAAO,EAAE,IAAI,iBAAiB,EAAE;AAChC,QAAA,iBAAiB,EAAE,iBAAiB;AACrC,KAAA,CAAC,CAAC;IACH,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,CAAC;AAC1F,CAAA;AAED,SAAS,iBAAiB,GAAA;AACxB,IAAA,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;AACrE;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../src/auth.ts","../../../src/aws/utils.ts","../../../src/aws/describe.ts","../../../src/aws/list.ts","../../../src/utils.ts","../../../src/aws/update-app.ts","../../../src/aws/update-server.ts","../../../src/aws/index.ts","../../../src/bots.ts","../../../src/project.ts","../../../src/rest.ts","../../../src/storage.ts","../../../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { medplum } from '.';\nimport { MedplumClient, getDisplayString, normalizeErrorString } from '@medplum/core';\nimport { platform } from 'os';\nimport { exec } from 'child_process';\nimport { createServer } from 'http';\n\nconst clientId = 'medplum-cli';\nconst redirectUri = 'http://localhost:9615';\n\nexport const login = new Command('login');\nexport const whoami = new Command('whoami');\n\nlogin.action(async () => {\n await startLogin(medplum);\n});\n\nwhoami.action(() => {\n printMe(medplum);\n});\n\nasync function startLogin(medplum: MedplumClient): Promise<void> {\n await startWebServer(medplum);\n\n const loginUrl = new URL('/oauth2/authorize', medplum.getBaseUrl());\n loginUrl.searchParams.set('client_id', clientId);\n loginUrl.searchParams.set('redirect_uri', redirectUri);\n loginUrl.searchParams.set('scope', 'openid');\n loginUrl.searchParams.set('response_type', 'code');\n loginUrl.searchParams.set('prompt', 'login');\n await openBrowser(loginUrl.toString());\n}\n\nasync function startWebServer(medplum: MedplumClient): Promise<void> {\n const server = createServer(async (req, res) => {\n const url = new URL(req.url as string, 'http://localhost:9615');\n const code = url.searchParams.get('code');\n if (url.pathname === '/' && code) {\n try {\n const profile = await medplum.processCode(code, { clientId, redirectUri });\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end(`Signed in as ${getDisplayString(profile)}. You may close this window.`);\n } catch (err) {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end(`Error: ${normalizeErrorString(err)}`);\n } finally {\n server.close();\n }\n } else {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n }\n }).listen(9615);\n}\n\n/**\n * Opens a web browser to the specified URL.\n * See: https://hasinthaindrajee.medium.com/browser-sso-for-cli-applications-b0be743fa656\n * @param url The URL to open.\n */\nasync function openBrowser(url: string): Promise<void> {\n const os = platform();\n let cmd = undefined;\n switch (os) {\n case 'openbsd':\n case 'linux':\n cmd = `xdg-open '${url}'`;\n break;\n case 'darwin':\n cmd = `open '${url}'`;\n break;\n case 'win32':\n cmd = `cmd /c start \"\" \"${url}\"`;\n break;\n default:\n throw new Error('Unsupported platform: ' + os);\n }\n exec(cmd);\n}\n\n/**\n * Prints the current user and project.\n * @param medplum The Medplum client.\n */\nfunction printMe(medplum: MedplumClient): void {\n const loginState = medplum.getActiveLogin();\n if (loginState) {\n console.log(`Server: ${medplum.getBaseUrl()}`);\n console.log(`Profile: ${loginState.profile?.display} (${loginState.profile?.reference})`);\n console.log(`Project: ${loginState.project?.display} (${loginState.project?.reference})`);\n } else {\n console.log('Not logged in');\n }\n}\n","import {\n CloudFormationClient,\n DescribeStackResourcesCommand,\n DescribeStacksCommand,\n ListStacksCommand,\n Stack,\n StackResource,\n StackSummary,\n} from '@aws-sdk/client-cloudformation';\nimport { CloudFrontClient } from '@aws-sdk/client-cloudfront';\nimport { ECSClient } from '@aws-sdk/client-ecs';\nimport { S3Client } from '@aws-sdk/client-s3';\n\nexport interface MedplumStackDetails {\n stack: Stack;\n tag: string;\n ecsCluster?: StackResource;\n ecsService?: StackResource;\n appBucket?: StackResource;\n appDistribution?: StackResource;\n storageBucket?: StackResource;\n}\n\nexport const cloudFormationClient = new CloudFormationClient({});\nexport const cloudFrontClient = new CloudFrontClient({});\nexport const ecsClient = new ECSClient({});\nexport const s3Client = new S3Client({});\nexport const tagKey = 'medplum:environment';\n\n/**\n * Returns a list of all AWS CloudFormation stacks (both Medplum and non-Medplum).\n * @returns List of AWS CloudFormation stacks.\n */\nexport async function getAllStacks(): Promise<(StackSummary & { StackName: string })[]> {\n const listResult = await cloudFormationClient.send(new ListStacksCommand({}));\n return (\n (listResult.StackSummaries?.filter((s) => s.StackName && s.StackStatus !== 'DELETE_COMPLETE') as (StackSummary & {\n StackName: string;\n })[]) || []\n );\n}\n\n/**\n * Returns Medplum stack details for the given tag.\n * @param tag The Medplum stack tag.\n * @returns The Medplum stack details.\n */\nexport async function getStackByTag(tag: string): Promise<MedplumStackDetails | undefined> {\n const stackSummaries = await getAllStacks();\n for (const stackSummary of stackSummaries) {\n const stackName = stackSummary.StackName;\n const details = await getStackDetails(stackName);\n if (details?.tag === tag) {\n return details;\n }\n }\n return undefined;\n}\n\n/**\n * Returns Medplum stack details for the given stack name.\n * @param stackName The CloudFormation stack name.\n * @returns The Medplum stack details.\n */\nexport async function getStackDetails(stackName: string): Promise<MedplumStackDetails | undefined> {\n const describeStacksCommand = new DescribeStacksCommand({ StackName: stackName });\n const stackDetails = await cloudFormationClient.send(describeStacksCommand);\n const stack = stackDetails?.Stacks?.[0];\n const medplumTag = stack?.Tags?.find((tag) => tag.Key === tagKey);\n if (!medplumTag) {\n return undefined;\n }\n\n const stackResources = await cloudFormationClient.send(new DescribeStackResourcesCommand({ StackName: stackName }));\n if (!stackResources.StackResources) {\n return undefined;\n }\n\n const result: MedplumStackDetails = {\n stack: stack as Stack,\n tag: medplumTag.Value as string,\n };\n\n for (const resource of stackResources.StackResources) {\n if (resource.ResourceType === 'AWS::ECS::Cluster') {\n result.ecsCluster = resource;\n } else if (resource.ResourceType === 'AWS::ECS::Service') {\n result.ecsService = resource;\n } else if (\n resource.ResourceType === 'AWS::S3::Bucket' &&\n resource.LogicalResourceId?.startsWith('FrontEndAppBucket')\n ) {\n result.appBucket = resource;\n } else if (\n resource.ResourceType === 'AWS::S3::Bucket' &&\n resource.LogicalResourceId?.startsWith('StorageStorageBucket')\n ) {\n result.storageBucket = resource;\n } else if (\n resource.ResourceType === 'AWS::CloudFront::Distribution' &&\n resource.LogicalResourceId?.startsWith('FrontEndAppDistribution')\n ) {\n result.appDistribution = resource;\n }\n }\n\n return result;\n}\n\n/**\n * Prints the given Medplum stack details to stdout.\n * @param details The Medplum stack details.\n */\nexport function printStackDetails(details: MedplumStackDetails): void {\n console.log(`Medplum Tag: ${details.tag}`);\n console.log(`Stack Name: ${details.stack.StackName}`);\n console.log(`Stack ID: ${details.stack.StackId}`);\n console.log(`Status: ${details.stack.StackStatus}`);\n console.log(`ECS Cluster: ${details.ecsCluster?.PhysicalResourceId}`);\n console.log(`ECS Service: ${getEcsServiceName(details.ecsService)}`);\n console.log(`App Bucket: ${details.appBucket?.PhysicalResourceId}`);\n console.log(`Storage Bucket: ${details.storageBucket?.PhysicalResourceId}`);\n}\n\n/**\n * Parses the ECS service name from the given AWS ECS service resource.\n * @param resource The AWS ECS service resource.\n * @returns The ECS service name.\n */\nexport function getEcsServiceName(resource: StackResource | undefined): string | undefined {\n return resource?.PhysicalResourceId?.split('/')?.pop() || '';\n}\n","import { getStackByTag, printStackDetails } from './utils';\n\n/**\n * The AWS \"describe\" command prints details about a Medplum CloudFormation stack.\n *\n * @param tag The Medplum stack tag.\n */\nexport async function describeStacksCommand(tag: string): Promise<void> {\n const details = await getStackByTag(tag);\n if (!details) {\n console.log('Stack not found');\n return;\n }\n printStackDetails(details);\n}\n","import { getAllStacks, getStackDetails, printStackDetails } from './utils';\n\n/**\n * The AWS \"list\" command prints summary details about all Medplum CloudFormation stacks.\n */\nexport async function listStacksCommand(): Promise<void> {\n const stackSummaries = await getAllStacks();\n for (const stackSummary of stackSummaries) {\n const stackName = stackSummary.StackName;\n const details = await getStackDetails(stackName);\n if (!details) {\n continue;\n }\n printStackDetails(details);\n console.log('');\n }\n}\n","import { MedplumClient } from '@medplum/core';\nimport { Bot, OperationOutcome } from '@medplum/fhirtypes';\nimport { existsSync, readFileSync, writeFile } from 'fs';\nimport { resolve } from 'path';\nimport internal from 'stream';\nimport tar from 'tar';\n\ninterface MedplumConfig {\n readonly baseUrl?: string;\n readonly clientId?: string;\n readonly googleClientId?: string;\n readonly recaptchaSiteKey?: string;\n readonly registerEnabled?: boolean;\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 function prettyPrint(input: unknown): void {\n console.log(JSON.stringify(input, null, 2));\n}\n\nexport async 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 if (!updateResult) {\n console.log('Bot not modified');\n } else {\n console.log('Success! New bot version: ' + updateResult.meta?.versionId);\n }\n } catch (err) {\n console.log('Update error: ', err);\n }\n}\n\nexport async 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\nexport async function createBot(medplum: MedplumClient, argv: string[]): Promise<void> {\n if (argv.length < 4) {\n console.log(`Error: command needs to be npx medplum <new-bot-name> <project-id> <source-file> <dist-file>`);\n return;\n }\n const botName = argv[0];\n const projectId = argv[1];\n const sourceFile = argv[2];\n const distFile = argv[3];\n\n try {\n const body = {\n name: botName,\n description: '',\n };\n const newBot = await medplum.post('admin/projects/' + projectId + '/bot', body);\n const bot = await medplum.readResource('Bot', newBot.id);\n\n const botConfig = {\n name: botName,\n id: newBot.id,\n source: sourceFile,\n dist: distFile,\n };\n await saveBot(medplum, botConfig as MedplumBotConfig, bot);\n console.log(`Success! Bot created: ${bot.id}`);\n\n addBotToConfig(botConfig);\n } catch (err) {\n console.log('Error while creating new bot: ' + err);\n }\n}\n\nexport function readBotConfigs(botName: string): MedplumBotConfig[] {\n const regExBotName = new RegExp('^' + escapeRegex(botName).replace(/\\\\\\*/g, '.*') + '$');\n const botConfigs = readConfig()?.bots?.filter((b) => regExBotName.test(b.name));\n if (!botConfigs) {\n return [];\n }\n return botConfigs;\n}\n\nexport function readConfig(tagName?: string): MedplumConfig | undefined {\n const fileName = tagName ? `medplum.${tagName}.config.json` : 'medplum.config.json';\n const content = readFileContents(fileName);\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\nfunction addBotToConfig(botConfig: MedplumBotConfig): void {\n const config = readConfig();\n config?.bots?.push(botConfig);\n writeFile('medplum.config.json', JSON.stringify(config), () => {\n console.log(`Bot added to config: ${botConfig.id}`);\n });\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[/\\-\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n}\n\n/**\n * Creates a safe tar extractor that limits the number of files and total size.\n *\n * Expanding archive files without controlling resource consumption is security-sensitive\n *\n * See: https://sonarcloud.io/organizations/medplum/rules?open=typescript%3AS5042&rule_key=typescript%3AS5042\n *\n * @param destinationDir The destination directory where all files will be extracted.\n * @returns A tar file extractor.\n */\nexport function safeTarExtractor(destinationDir: string): internal.Writable {\n const MAX_FILES = 100;\n const MAX_SIZE = 10 * 1024 * 1024; // 10 MB\n\n let fileCount = 0;\n let totalSize = 0;\n\n return tar.x({\n cwd: destinationDir,\n filter: (_path, entry) => {\n fileCount++;\n if (fileCount > MAX_FILES) {\n throw new Error('Tar extractor reached max number of files');\n }\n\n totalSize += entry.size;\n if (totalSize > MAX_SIZE) {\n throw new Error('Tar extractor reached max size');\n }\n\n return true;\n },\n });\n}\n","import { CreateInvalidationCommand } from '@aws-sdk/client-cloudfront';\nimport { PutObjectCommand } from '@aws-sdk/client-s3';\nimport fastGlob from 'fast-glob';\nimport { createReadStream, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'fs';\nimport fetch from 'node-fetch';\nimport { tmpdir } from 'os';\nimport { join, sep } from 'path';\nimport { pipeline } from 'stream/promises';\nimport { readConfig, safeTarExtractor } from '../utils';\nimport { cloudFrontClient, getStackByTag, s3Client } from './utils';\n\n/**\n * The AWS \"update-app\" command updates the Medplum app in a Medplum CloudFormation stack to the latest version.\n * @param tag The Medplum stack tag.\n */\nexport async function updateAppCommand(tag: string): Promise<void> {\n const config = readConfig(tag);\n if (!config) {\n console.log('Config not found');\n return;\n }\n const details = await getStackByTag(tag);\n if (!details) {\n console.log('Stack not found');\n return;\n }\n const appBucket = details.appBucket;\n if (!appBucket) {\n console.log('App bucket not found');\n return;\n }\n\n const tmpDir = await downloadNpmPackage('@medplum/app', 'latest');\n\n // Replace variables in the app\n replaceVariables(tmpDir, {\n MEDPLUM_BASE_URL: config.baseUrl as string,\n MEDPLUM_CLIENT_ID: config.clientId || '',\n GOOGLE_CLIENT_ID: config.googleClientId || '',\n RECAPTCHA_SITE_KEY: config.recaptchaSiteKey || '',\n MEDPLUM_REGISTER_ENABLED: config.registerEnabled ? 'true' : 'false',\n });\n\n // Upload the app to S3 with correct content-type and cache-control\n await uploadAppToS3(tmpDir, appBucket.PhysicalResourceId as string);\n\n // Create a CloudFront invalidation to clear any cached resources\n if (details.appDistribution?.PhysicalResourceId) {\n await createInvalidation(details.appDistribution.PhysicalResourceId);\n }\n\n console.log('Done');\n}\n\n/**\n * Returns NPM package metadata for a given package name.\n * See: https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#getpackageversion\n * @param packageName The npm package name.\n */\nasync function getNpmPackageMetadata(packageName: string, version: string): Promise<any> {\n const url = `https://registry.npmjs.org/${packageName}/${version}`;\n const response = await fetch(url);\n return response.json();\n}\n\n/**\n * Downloads and extracts an NPM package.\n * @param packageName The NPM package name.\n * @param version The NPM package version or \"latest\".\n * @returns Path to temporary directory where the package was downloaded and extracted.\n */\nasync function downloadNpmPackage(packageName: string, version: string): Promise<string> {\n const packageMetadata = await getNpmPackageMetadata(packageName, version);\n const tarballUrl = packageMetadata.dist.tarball as string;\n const tmpDir = mkdtempSync(join(tmpdir(), 'tarball-'));\n try {\n const response = await fetch(tarballUrl);\n const extractor = safeTarExtractor(tmpDir);\n await pipeline(response.body, extractor);\n return join(tmpDir, 'package', 'dist');\n } catch (error) {\n rmSync(tmpDir, { recursive: true, force: true });\n throw error;\n }\n}\n\n/**\n * Replaces variables in all JS files in the given folder.\n * @param folderName The folder name of the files.\n * @param replacements The collection of variable placeholders and replacements.\n */\nfunction replaceVariables(folderName: string, replacements: Record<string, string>): void {\n for (const item of readdirSync(folderName, { withFileTypes: true })) {\n const itemPath = join(folderName, item.name);\n if (item.isDirectory()) {\n replaceVariables(itemPath, replacements);\n } else if (item.isFile() && itemPath.endsWith('.js')) {\n replaceVariablesInFile(itemPath, replacements);\n }\n }\n}\n\n/**\n * Replaces variables in the JS file.\n * @param fileName The file name.\n * @param replacements The collection of variable placeholders and replacements.\n */\nfunction replaceVariablesInFile(fileName: string, replacements: Record<string, string>): void {\n let contents = readFileSync(fileName, 'utf-8');\n for (const [placeholder, replacement] of Object.entries(replacements)) {\n contents = contents.replaceAll(`process.env.${placeholder}`, `'${replacement}'`);\n }\n writeFileSync(fileName, contents);\n}\n\n/**\n * Uploads the app to S3.\n * Ensures correct content-type and cache-control for each file.\n * @param tmpDir The temporary directory where the app is located.\n * @param bucketName The destination S3 bucket name.\n */\nasync function uploadAppToS3(tmpDir: string, bucketName: string): Promise<void> {\n // Manually iterate and upload files\n // Automatic content-type detection is not reliable on Microsoft Windows\n // So we explicitly set content-type\n const uploadPatterns: [string, string, boolean][] = [\n // Cached\n // These files generally have a hash, so they can be cached forever\n // It is important to upload them first to avoid broken references from index.html\n ['css/**/*.css', 'text/css', true],\n ['css/**/*.css.map', 'application/json', true],\n ['img/**/*.png', 'image/png', true],\n ['img/**/*.svg', 'image/svg+xml', true],\n ['js/**/*.js', 'application/javascript', true],\n ['js/**/*.js.map', 'application/json', true],\n ['js/**/*.txt', 'text/plain', true],\n ['favicon.ico', 'image/vnd.microsoft.icon', true],\n ['robots.txt', 'text/plain', true],\n ['workbox-*.js', 'application/javascript', true],\n ['workbox-*.js.map', 'application/json', true],\n\n // Not cached\n ['manifest.webmanifest', 'application/manifest+json', false],\n ['service-worker.js', 'application/javascript', false],\n ['service-worker.js.map', 'application/json', false],\n ['index.html', 'text/html', false],\n ];\n for (const uploadPattern of uploadPatterns) {\n await uploadFolderToS3({\n rootDir: tmpDir,\n bucketName,\n fileNamePattern: uploadPattern[0],\n contentType: uploadPattern[1],\n cached: uploadPattern[2],\n });\n }\n}\n\n/**\n * Uploads a directory of files to S3.\n * @param options The upload options such as bucket name, content type, and cache control.\n */\nasync function uploadFolderToS3(options: {\n rootDir: string;\n bucketName: string;\n fileNamePattern: string;\n contentType: string;\n cached: boolean;\n}): Promise<void> {\n const items = fastGlob.sync(options.fileNamePattern, { cwd: options.rootDir });\n for (const item of items) {\n await uploadFileToS3(join(options.rootDir, item), options);\n }\n}\n\n/**\n * Uploads a file to S3.\n * @param filePath The file path.\n * @param options The upload options such as bucket name, content type, and cache control.\n */\nasync function uploadFileToS3(\n filePath: string,\n options: {\n rootDir: string;\n bucketName: string;\n contentType: string;\n cached: boolean;\n }\n): Promise<void> {\n const fileStream = createReadStream(filePath);\n const s3Key = filePath\n .substring(options.rootDir.length + 1)\n .split(sep)\n .join('/');\n\n const putObjectParams = {\n Bucket: options.bucketName,\n Key: s3Key,\n Body: fileStream,\n ContentType: options.contentType,\n CacheControl: options.cached ? 'public, max-age=31536000' : 'no-cache, no-store, must-revalidate',\n };\n\n console.log(`Uploading ${s3Key} to ${options.bucketName}...`);\n await s3Client.send(new PutObjectCommand(putObjectParams));\n}\n\n/**\n * Creates a CloudFront invalidation to clear the cache for all files.\n * This is not strictly necessary, but it helps to ensure that the latest version of the app is served.\n * In a perfect world, every deploy is clean, and hashed resources should be cached forever.\n * However, we do not recalculate hashes after variable replacements.\n * So if variables change, we need to invalidate the cache.\n * @param distributionId The CloudFront distribution ID.\n */\nasync function createInvalidation(distributionId: string): Promise<void> {\n const response = await cloudFrontClient.send(\n new CreateInvalidationCommand({\n DistributionId: distributionId,\n InvalidationBatch: {\n CallerReference: `invalidate-all-${Date.now()}`,\n Paths: {\n Quantity: 1,\n Items: ['/*'],\n },\n },\n })\n );\n console.log(`Created invalidation with ID: ${response.Invalidation?.Id}`);\n}\n","import { UpdateServiceCommand } from '@aws-sdk/client-ecs';\nimport { ecsClient, getEcsServiceName, getStackByTag } from './utils';\n\n/**\n * The AWS \"update-server\" command updates the Medplum server in a Medplum CloudFormation stack.\n * @param tag The Medplum stack tag.\n * @returns\n */\nexport async function updateServerCommand(tag: string): Promise<void> {\n const details = await getStackByTag(tag);\n if (!details) {\n console.log('Stack not found');\n return;\n }\n const ecsCluster = details.ecsCluster?.PhysicalResourceId;\n if (!ecsCluster) {\n console.log('ECS Cluster not found');\n return;\n }\n const ecsService = getEcsServiceName(details.ecsService);\n if (!ecsService) {\n console.log('ECS Service not found');\n return;\n }\n await ecsClient.send(\n new UpdateServiceCommand({\n cluster: ecsCluster,\n service: ecsService,\n forceNewDeployment: true,\n })\n );\n console.log(`Service \"${ecsService}\" updated successfully.`);\n}\n","import { Command } from 'commander';\nimport { describeStacksCommand } from './describe';\nimport { listStacksCommand } from './list';\nimport { updateAppCommand } from './update-app';\nimport { updateServerCommand } from './update-server';\n\nexport const aws = new Command('aws').description('Commands to manage AWS resources');\n\naws.command('list').description('List Medplum AWS CloudFormation stacks').action(listStacksCommand);\n\naws\n .command('describe')\n .description('Describe a Medplum AWS CloudFormation stack by tag')\n .argument('<tag>')\n .action(describeStacksCommand);\n\naws.command('update-server').description('Update the server image').argument('<tag>').action(updateServerCommand);\n\naws.command('update-app').description('Update the app site').argument('<tag>').action(updateAppCommand);\n","import { Command } from 'commander';\nimport { medplum } from '.';\nimport { createBot, deployBot, readBotConfigs, saveBot } from './utils';\nimport { MedplumClient } from '@medplum/core';\n\nexport const bot = new Command('bot');\n\n// Commands to deprecate\nexport const saveBotDeprecate = new Command('save-bot');\nexport const deployBotDeprecate = new Command('deploy-bot');\nexport const createBotDeprecate = new Command('create-bot');\n\nbot\n .command('save')\n .description('Saving the bot')\n .argument('<botName>')\n .action(async (botName) => {\n await botWrapper(medplum, botName);\n });\n\nbot\n .command('deploy')\n .description('Deploy the app to AWS')\n .argument('<botName>')\n .action(async (botName) => {\n await botWrapper(medplum, botName, true);\n });\n\nbot\n .command('create')\n .arguments('<botName> <projectId> <sourceFile> <distFile>')\n .description('Creating a bot')\n .action(async (botName, projectId, sourceFile, distFile) => {\n await createBot(medplum, [botName, projectId, sourceFile, distFile]);\n });\n\nexport async function botWrapper(medplum: MedplumClient, botName: string, deploy = false): Promise<void> {\n const botConfigs = readBotConfigs(botName);\n for (const botConfig of botConfigs) {\n const bot = await medplum.readResource('Bot', botConfig.id);\n await saveBot(medplum, botConfig, bot);\n if (deploy) {\n await deployBot(medplum, botConfig, bot);\n }\n }\n console.log(`Number of bots deployed: ${botConfigs.length}`);\n}\n\n// Deprecate bot commands\nsaveBotDeprecate\n .description('Saves the bot')\n .argument('<botName>')\n .action(async (botName) => {\n await botWrapper(medplum, botName);\n });\n\ndeployBotDeprecate\n .description('Deploy the bot to AWS')\n .argument('<botName>')\n .action(async (botName) => {\n await botWrapper(medplum, botName, true);\n });\n\ncreateBotDeprecate\n .arguments('<botName> <projectId> <sourceFile> <distFile>')\n .description('Creates and saves the bot')\n .action(async (botName, projectId, sourceFile, distFile) => {\n await createBot(medplum, [botName, projectId, sourceFile, distFile]);\n });\n","import { Command, Option } from 'commander';\nimport { medplum } from '.';\nimport { MedplumClient, LoginState, InviteBody } from '@medplum/core';\n\nexport const project = new Command('project');\n\nproject\n .command('list')\n .description('List of current projects')\n .action(async () => {\n projectList(medplum);\n });\n\nfunction projectList(medplum: MedplumClient): void {\n const logins = medplum.getLogins();\n\n const projects = logins\n .map((login: LoginState) => `${login.project.display} (${login.project.reference})`)\n .join('\\n\\n');\n\n console.log(projects);\n}\n\nproject\n .command('current')\n .description('Project you are currently on')\n .action(() => {\n const login = medplum.getActiveLogin();\n if (!login) {\n throw new Error('Unauthenticated: run `npx medplum login` to login');\n }\n console.log(`${login.project.display} (${login.project.reference})`);\n });\n\nproject\n .command('switch')\n .description('Switching to another project from the current one')\n .argument('<projectId>')\n .action(async (projectId) => {\n await switchProject(medplum, projectId);\n });\n\nproject\n .command('invite')\n .description('Invite a member to your current project (run npx medplum project current to confirm)')\n .arguments('<firstName> <lastName> <email>')\n .option('--send-email', 'If you want to send the email when inviting the user')\n .option('--admin', 'If the user you are inviting is an admin')\n .addOption(\n new Option('-r, --role <role>', 'Role of user')\n .choices(['Practitioner', 'Patient', 'RelatedPerson'])\n .default('Practitioner')\n )\n .action(async (firstName, lastName, email, options) => {\n const login = medplum.getActiveLogin();\n if (!login) {\n throw new Error('Unauthenticated: run `npx medplum login` to login');\n }\n if (!login.project?.reference) {\n throw new Error('No current project to invite user to');\n }\n\n const projectId = login.project.reference.split('/')[1];\n const inviteBody: InviteBody = {\n resourceType: options.role,\n firstName,\n lastName,\n email,\n sendEmail: !!options.sendEmail,\n admin: !!options.admin,\n };\n await inviteUser(projectId, inviteBody);\n });\n\nasync function switchProject(medplum: MedplumClient, projectId: string): Promise<void> {\n const logins = medplum.getLogins();\n const login = logins.find((login: LoginState) => login.project?.reference?.includes(projectId));\n if (!login) {\n console.log(`Error: project ${projectId} not found. Make sure you are added as a user to this project`);\n } else {\n await medplum.setActiveLogin(login);\n console.log(`Switched to project ${projectId}\\n`);\n }\n}\n\nasync function inviteUser(projectId: string, inviteBody: InviteBody): Promise<void> {\n try {\n await medplum.invite(projectId, inviteBody);\n if (inviteBody.sendEmail) {\n console.log('Email sent');\n }\n console.log('See your users at https://app.medplum.com/admin/users');\n } catch (err) {\n console.log('Error while sending invite ' + err);\n }\n}\n","import { convertToTransactionBundle } from '@medplum/core';\nimport { Command } from 'commander';\nimport { medplum } from '.';\nimport { prettyPrint } from './utils';\n\nexport const deleteObject = new Command('delete');\nexport const get = new Command('get');\nexport const patch = new Command('patch');\nexport const post = new Command('post');\nexport const put = new Command('put');\n\ndeleteObject.argument('<url>', 'Resource/$id').action(async (url) => {\n prettyPrint(await medplum.delete(cleanUrl(url)));\n});\n\nget\n .argument('<url>', 'Resource/$id')\n .option('--as-transaction', 'Print out the bundle as a transaction type')\n .action(async (url, options) => {\n const response = await medplum.get(cleanUrl(url));\n if (options.asTransaction) {\n prettyPrint(convertToTransactionBundle(response));\n } else {\n prettyPrint(response);\n }\n });\n\npatch.arguments('<url> <body>').action(async (url, body) => {\n prettyPrint(await medplum.patch(cleanUrl(url), parseBody(body)));\n});\n\npost.arguments('<url> <body>').action(async (url, body) => {\n prettyPrint(await medplum.post(cleanUrl(url), parseBody(body)));\n});\n\nput.arguments('<url> <body>').action(async (url, body) => {\n prettyPrint(await medplum.put(cleanUrl(url), parseBody(body)));\n});\n\nfunction parseBody(input: string | undefined): any {\n if (!input) {\n return undefined;\n }\n try {\n return JSON.parse(input);\n } catch (err) {\n return input;\n }\n}\n\nexport function cleanUrl(input: string): string {\n const knownPrefixes = ['admin/', 'auth/', 'fhir/R4'];\n if (knownPrefixes.some((p) => input.startsWith(p))) {\n // If the URL starts with a known prefix, return it as-is\n return input;\n }\n // Otherwise, default to FHIR\n return 'fhir/R4/' + input;\n}\n","import { ClientStorage } from '@medplum/core';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { homedir } from 'os';\nimport { resolve } from 'path';\n\nexport class FileSystemStorage extends ClientStorage {\n private readonly dirName: string;\n private readonly fileName: string;\n\n constructor() {\n super();\n this.dirName = resolve(homedir(), '.medplum');\n this.fileName = resolve(this.dirName, 'credentials');\n }\n\n clear(): void {\n this.writeFile({});\n }\n\n getString(key: string): string | undefined {\n return this.readFile()?.[key];\n }\n\n setString(key: string, value: string | undefined): void {\n const data = this.readFile() || {};\n if (value) {\n data[key] = value;\n } else {\n delete data[key];\n }\n this.writeFile(data);\n }\n\n private readFile(): Record<string, string> | undefined {\n if (existsSync(this.fileName)) {\n return JSON.parse(readFileSync(this.fileName, 'utf8'));\n }\n return undefined;\n }\n\n private writeFile(data: Record<string, string>): void {\n if (!existsSync(this.dirName)) {\n mkdirSync(this.dirName);\n }\n writeFileSync(this.fileName, JSON.stringify(data, null, 2), 'utf8');\n }\n}\n","import { MEDPLUM_VERSION, MedplumClient, normalizeErrorString } from '@medplum/core';\nimport { Command } from 'commander';\nimport dotenv from 'dotenv';\nimport { login, whoami } from './auth';\nimport { aws } from './aws/index';\nimport { bot, createBotDeprecate, deployBotDeprecate, saveBotDeprecate } from './bots';\nimport { project } from './project';\nimport { deleteObject, get, patch, post, put } from './rest';\nimport { FileSystemStorage } from './storage';\n\nexport let medplum: MedplumClient;\n\nexport async function main(medplumClient: MedplumClient, argv: string[]): Promise<void> {\n medplum = medplumClient;\n\n // Legacy support for MEDPLUM_CLIENT_ID and MEDPLUM_CLIENT_SECRET environment variables\n const clientId = process.env['MEDPLUM_CLIENT_ID'];\n const clientSecret = process.env['MEDPLUM_CLIENT_SECRET'];\n if (clientId && clientSecret) {\n await medplum.startClientLogin(clientId, clientSecret);\n }\n try {\n const index = new Command('medplum').description('Command to access Medplum CLI');\n index.version(MEDPLUM_VERSION);\n\n // Auth commands\n index.addCommand(login);\n index.addCommand(whoami);\n\n // REST commands\n index.addCommand(get);\n index.addCommand(post);\n index.addCommand(patch);\n index.addCommand(put);\n index.addCommand(deleteObject);\n\n // Project\n index.addCommand(project);\n\n // Bot Commands\n index.addCommand(bot);\n\n // Deprecated Bot Commands\n index.addCommand(saveBotDeprecate);\n index.addCommand(deployBotDeprecate);\n index.addCommand(createBotDeprecate);\n\n // AWS commands\n index.addCommand(aws);\n\n await index.parseAsync(argv);\n } catch (err) {\n console.error('Error: ' + normalizeErrorString(err));\n }\n}\n\nif (require.main === module) {\n dotenv.config();\n const baseUrl = process.env['MEDPLUM_BASE_URL'] || 'https://api.medplum.com/';\n const medplumClient = new MedplumClient({\n fetch,\n baseUrl,\n storage: new FileSystemStorage(),\n onUnauthenticated: onUnauthenticated,\n });\n main(medplumClient, process.argv).catch((err) => console.error('Unhandled error:', err));\n}\n\nfunction onUnauthenticated(): void {\n console.log('Unauthenticated: run `npx medplum login` to sign in');\n}\n"],"names":["Command","medplum","createServer","getDisplayString","normalizeErrorString","os","platform","exec","CloudFormationClient","CloudFrontClient","ECSClient","S3Client","ListStacksCommand","DescribeStacksCommand","DescribeStackResourcesCommand","path","resolve","existsSync","readFileSync","writeFile","fetch","mkdtempSync","join","tmpdir","pipeline","rmSync","readdirSync","writeFileSync","createReadStream","sep","PutObjectCommand","CreateInvalidationCommand","UpdateServiceCommand","Option","convertToTransactionBundle","ClientStorage","homedir","mkdirSync","MEDPLUM_VERSION","MedplumClient"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medplum/cli",
3
- "version": "2.0.17",
3
+ "version": "2.0.19",
4
4
  "description": "Medplum Command Line Interface",
5
5
  "author": "Medplum <hello@medplum.com>",
6
6
  "license": "Apache-2.0",
@@ -17,19 +17,23 @@
17
17
  "test": "jest"
18
18
  },
19
19
  "dependencies": {
20
- "@aws-sdk/client-cloudformation": "3.319.0",
21
- "@aws-sdk/client-ecs": "3.319.0",
22
- "@aws-sdk/client-s3": "3.319.0",
20
+ "@aws-sdk/client-cloudformation": "3.332.0",
21
+ "@aws-sdk/client-cloudfront": "3.332.0",
22
+ "@aws-sdk/client-ecs": "3.332.0",
23
+ "@aws-sdk/client-s3": "3.332.0",
23
24
  "@medplum/core": "*",
24
25
  "aws-sdk-client-mock": "2.1.1",
25
26
  "commander": "10.0.1",
26
27
  "dotenv": "16.0.3",
27
- "node-fetch": "2.6.9"
28
+ "fast-glob": "3.2.12",
29
+ "node-fetch": "2.6.9",
30
+ "tar": "6.1.14"
28
31
  },
29
32
  "devDependencies": {
30
33
  "@medplum/fhirtypes": "*",
31
34
  "@medplum/mock": "*",
32
- "@types/node-fetch": "2.6.3"
35
+ "@types/node-fetch": "2.6.3",
36
+ "@types/tar": "6.1.5"
33
37
  },
34
38
  "bin": {
35
39
  "medplum": "./dist/cjs/index.cjs"