@medplum/core 0.9.35 → 0.9.36

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.
Files changed (50) hide show
  1. package/dist/cjs/client.d.ts +14 -5
  2. package/dist/cjs/fhirlexer/index.d.ts +2 -0
  3. package/dist/cjs/fhirlexer/parse.d.ts +31 -0
  4. package/dist/cjs/fhirlexer/tokenize.d.ts +14 -0
  5. package/dist/cjs/fhirmapper/atoms.d.ts +67 -0
  6. package/dist/cjs/fhirmapper/parse.d.ts +7 -0
  7. package/dist/cjs/fhirmapper/tokenize.d.ts +2 -0
  8. package/dist/cjs/fhirpath/atoms.d.ts +2 -7
  9. package/dist/cjs/fhirpath/functions.d.ts +2 -1
  10. package/dist/cjs/fhirpath/parse.d.ts +8 -5
  11. package/dist/cjs/fhirpath/tokenize.d.ts +3 -4
  12. package/dist/cjs/fhirpath/utils.d.ts +1 -1
  13. package/dist/cjs/index.js +310 -272
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/index.min.js +1 -1
  16. package/dist/cjs/index.min.js.map +1 -1
  17. package/dist/cjs/types.d.ts +4 -0
  18. package/dist/esm/client.d.ts +14 -5
  19. package/dist/esm/client.js +58 -45
  20. package/dist/esm/client.js.map +1 -1
  21. package/dist/esm/fhirlexer/index.d.ts +2 -0
  22. package/dist/esm/fhirlexer/parse.d.ts +31 -0
  23. package/dist/esm/fhirlexer/parse.js +105 -0
  24. package/dist/esm/fhirlexer/parse.js.map +1 -0
  25. package/dist/esm/fhirlexer/tokenize.d.ts +14 -0
  26. package/dist/esm/fhirlexer/tokenize.js +212 -0
  27. package/dist/esm/fhirlexer/tokenize.js.map +1 -0
  28. package/dist/esm/fhirmapper/atoms.d.ts +67 -0
  29. package/dist/esm/fhirmapper/parse.d.ts +7 -0
  30. package/dist/esm/fhirmapper/tokenize.d.ts +2 -0
  31. package/dist/esm/fhirpath/atoms.d.ts +2 -7
  32. package/dist/esm/fhirpath/atoms.js.map +1 -1
  33. package/dist/esm/fhirpath/functions.d.ts +2 -1
  34. package/dist/esm/fhirpath/functions.js.map +1 -1
  35. package/dist/esm/fhirpath/parse.d.ts +8 -5
  36. package/dist/esm/fhirpath/parse.js +57 -169
  37. package/dist/esm/fhirpath/parse.js.map +1 -1
  38. package/dist/esm/fhirpath/tokenize.d.ts +3 -4
  39. package/dist/esm/fhirpath/tokenize.js +5 -180
  40. package/dist/esm/fhirpath/tokenize.js.map +1 -1
  41. package/dist/esm/fhirpath/utils.d.ts +1 -1
  42. package/dist/esm/fhirpath/utils.js.map +1 -1
  43. package/dist/esm/index.js +2 -2
  44. package/dist/esm/index.min.js +1 -1
  45. package/dist/esm/index.min.js.map +1 -1
  46. package/dist/esm/outcomes.js +1 -1
  47. package/dist/esm/outcomes.js.map +1 -1
  48. package/dist/esm/types.d.ts +4 -0
  49. package/dist/esm/types.js.map +1 -1
  50. package/package.json +3 -3
@@ -1,5 +1,9 @@
1
1
  import { Bundle, ElementDefinition, SearchParameter, StructureDefinition } from '@medplum/fhirtypes';
2
2
  import { SearchParameterDetails } from './searchparams';
3
+ export interface TypedValue {
4
+ readonly type: string;
5
+ readonly value: any;
6
+ }
3
7
  /**
4
8
  * List of property types.
5
9
  * http://www.hl7.org/fhir/valueset-defined-types.html
@@ -461,6 +461,10 @@ export declare class MedplumClient extends EventTarget {
461
461
  * @returns Promise to the authentication response.
462
462
  */
463
463
  startGoogleLogin(loginRequest: GoogleLoginRequest): Promise<LoginAuthenticationResponse>;
464
+ getCodeChallenge(loginRequest: LoginRequest | GoogleLoginRequest): {
465
+ codeChallenge?: string;
466
+ codeChallengeMethod?: string;
467
+ };
464
468
  /**
465
469
  * Signs out locally.
466
470
  * Does not invalidate tokens with the server.
@@ -623,7 +627,7 @@ export declare class MedplumClient extends EventTarget {
623
627
  * @param id The resource ID.
624
628
  * @returns The resource if available; undefined otherwise.
625
629
  */
626
- readResource<K extends ResourceType>(resourceType: K, id: string): ReadablePromise<ExtractResource<K>>;
630
+ readResource<K extends ResourceType>(resourceType: K, id: string, options?: RequestInit): ReadablePromise<ExtractResource<K>>;
627
631
  /**
628
632
  * Reads a resource by `Reference`.
629
633
  *
@@ -643,7 +647,7 @@ export declare class MedplumClient extends EventTarget {
643
647
  * @param reference The FHIR reference object.
644
648
  * @returns The resource if available; undefined otherwise.
645
649
  */
646
- readReference<T extends Resource>(reference: Reference<T>): ReadablePromise<T>;
650
+ readReference<T extends Resource>(reference: Reference<T>, options?: RequestInit): ReadablePromise<T>;
647
651
  /**
648
652
  * Returns a cached schema for a resource type.
649
653
  * If the schema is not cached, returns undefined.
@@ -681,7 +685,7 @@ export declare class MedplumClient extends EventTarget {
681
685
  * @param id The resource ID.
682
686
  * @returns Promise to the resource history.
683
687
  */
684
- readHistory<K extends ResourceType>(resourceType: K, id: string): ReadablePromise<Bundle<ExtractResource<K>>>;
688
+ readHistory<K extends ResourceType>(resourceType: K, id: string, options?: RequestInit): ReadablePromise<Bundle<ExtractResource<K>>>;
685
689
  /**
686
690
  * Reads a specific version of a resource by resource type, ID, and version ID.
687
691
  *
@@ -699,14 +703,14 @@ export declare class MedplumClient extends EventTarget {
699
703
  * @param id The resource ID.
700
704
  * @returns The resource if available; undefined otherwise.
701
705
  */
702
- readVersion<K extends ResourceType>(resourceType: K, id: string, vid: string): ReadablePromise<ExtractResource<K>>;
706
+ readVersion<K extends ResourceType>(resourceType: K, id: string, vid: string, options?: RequestInit): ReadablePromise<ExtractResource<K>>;
703
707
  /**
704
708
  *
705
709
  * @category Read
706
710
  * @param id The Patient Id
707
711
  * @returns A Bundle of all Resources related to the Patient
708
712
  */
709
- readPatientEverything(id: string): ReadablePromise<Bundle>;
713
+ readPatientEverything(id: string, options?: RequestInit): ReadablePromise<Bundle>;
710
714
  /**
711
715
  * Creates a new FHIR resource.
712
716
  *
@@ -1094,6 +1098,11 @@ export declare class MedplumClient extends EventTarget {
1094
1098
  * @returns Promise to the response body as a blob.
1095
1099
  */
1096
1100
  download(url: URL | string, options?: RequestInit): Promise<Blob>;
1101
+ /**
1102
+ * Starts a new PKCE flow.
1103
+ * These PKCE values are stateful, and must survive redirects and page refreshes.
1104
+ */
1105
+ startPkce(): Promise<void>;
1097
1106
  /**
1098
1107
  * Processes an OAuth authorization code.
1099
1108
  * See: https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest
@@ -10,7 +10,7 @@ import { createReference, arrayBufferToBase64 } from './utils.js';
10
10
 
11
11
  // PKCE auth based on:
12
12
  // https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
13
- var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_createPdf, _MedplumClient_storage, _MedplumClient_requestCache, _MedplumClient_cacheTime, _MedplumClient_baseUrl, _MedplumClient_clientId, _MedplumClient_authorizeUrl, _MedplumClient_tokenUrl, _MedplumClient_logoutUrl, _MedplumClient_onUnauthenticated, _MedplumClient_accessToken, _MedplumClient_refreshToken, _MedplumClient_refreshPromise, _MedplumClient_profilePromise, _MedplumClient_profile, _MedplumClient_config, _MedplumClient_addLogin, _MedplumClient_refreshProfile, _MedplumClient_getCacheEntry, _MedplumClient_setCacheEntry, _MedplumClient_request, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_startPkce, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
13
+ var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_createPdf, _MedplumClient_storage, _MedplumClient_requestCache, _MedplumClient_cacheTime, _MedplumClient_baseUrl, _MedplumClient_clientId, _MedplumClient_authorizeUrl, _MedplumClient_tokenUrl, _MedplumClient_logoutUrl, _MedplumClient_onUnauthenticated, _MedplumClient_accessToken, _MedplumClient_refreshToken, _MedplumClient_refreshPromise, _MedplumClient_profilePromise, _MedplumClient_profile, _MedplumClient_config, _MedplumClient_addLogin, _MedplumClient_refreshProfile, _MedplumClient_getCacheEntry, _MedplumClient_setCacheEntry, _MedplumClient_request, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
14
14
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
15
15
  const DEFAULT_SCOPE = 'launch/patient openid fhirUser offline_access user/*.*';
16
16
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
@@ -279,8 +279,8 @@ class MedplumClient extends EventTarget {
279
279
  */
280
280
  startNewUser(newUserRequest) {
281
281
  return __awaiter(this, void 0, void 0, function* () {
282
- yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
283
- return this.post('auth/newuser', Object.assign(Object.assign({}, newUserRequest), { codeChallengeMethod: 'S256', codeChallenge: __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeChallenge') }));
282
+ yield this.startPkce();
283
+ return this.post('auth/newuser', Object.assign(Object.assign({}, newUserRequest), { codeChallengeMethod: 'S256', codeChallenge: sessionStorage.getItem('codeChallenge') }));
284
284
  });
285
285
  }
286
286
  /**
@@ -318,10 +318,9 @@ class MedplumClient extends EventTarget {
318
318
  startLogin(loginRequest) {
319
319
  var _a, _b;
320
320
  return __awaiter(this, void 0, void 0, function* () {
321
- if (!loginRequest.codeChallenge || !loginRequest.codeChallengeMethod) {
322
- yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
323
- }
324
- return this.post('auth/login', Object.assign(Object.assign({}, loginRequest), { clientId: (_a = loginRequest.clientId) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _MedplumClient_clientId, "f"), scope: (_b = loginRequest.scope) !== null && _b !== void 0 ? _b : DEFAULT_SCOPE, codeChallengeMethod: loginRequest.codeChallengeMethod || 'S256', codeChallenge: loginRequest.codeChallenge || __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeChallenge') }));
321
+ const { codeChallenge, codeChallengeMethod } = this.getCodeChallenge(loginRequest);
322
+ return this.post('auth/login', Object.assign(Object.assign({}, loginRequest), { clientId: (_a = loginRequest.clientId) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _MedplumClient_clientId, "f"), scope: (_b = loginRequest.scope) !== null && _b !== void 0 ? _b : DEFAULT_SCOPE, codeChallengeMethod,
323
+ codeChallenge }));
325
324
  });
326
325
  }
327
326
  /**
@@ -335,12 +334,27 @@ class MedplumClient extends EventTarget {
335
334
  startGoogleLogin(loginRequest) {
336
335
  var _a, _b;
337
336
  return __awaiter(this, void 0, void 0, function* () {
338
- if (!loginRequest.codeChallenge || !loginRequest.codeChallengeMethod) {
339
- yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
340
- }
341
- return this.post('auth/google', Object.assign(Object.assign({}, loginRequest), { clientId: (_a = loginRequest.clientId) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _MedplumClient_clientId, "f"), scope: (_b = loginRequest.scope) !== null && _b !== void 0 ? _b : DEFAULT_SCOPE, codeChallengeMethod: loginRequest.codeChallengeMethod || 'S256', codeChallenge: loginRequest.codeChallenge || __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeChallenge') }));
337
+ const { codeChallenge, codeChallengeMethod } = this.getCodeChallenge(loginRequest);
338
+ return this.post('auth/google', Object.assign(Object.assign({}, loginRequest), { clientId: (_a = loginRequest.clientId) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _MedplumClient_clientId, "f"), scope: (_b = loginRequest.scope) !== null && _b !== void 0 ? _b : DEFAULT_SCOPE, codeChallengeMethod,
339
+ codeChallenge }));
342
340
  });
343
341
  }
342
+ getCodeChallenge(loginRequest) {
343
+ if (loginRequest.codeChallenge) {
344
+ return {
345
+ codeChallenge: loginRequest.codeChallenge,
346
+ codeChallengeMethod: loginRequest.codeChallengeMethod,
347
+ };
348
+ }
349
+ const codeChallenge = sessionStorage.getItem('codeChallenge');
350
+ if (codeChallenge) {
351
+ return {
352
+ codeChallenge,
353
+ codeChallengeMethod: 'S256',
354
+ };
355
+ }
356
+ return {};
357
+ }
344
358
  /**
345
359
  * Signs out locally.
346
360
  * Does not invalidate tokens with the server.
@@ -570,8 +584,8 @@ class MedplumClient extends EventTarget {
570
584
  * @param id The resource ID.
571
585
  * @returns The resource if available; undefined otherwise.
572
586
  */
573
- readResource(resourceType, id) {
574
- return this.get(this.fhirUrl(resourceType, id));
587
+ readResource(resourceType, id, options = {}) {
588
+ return this.get(this.fhirUrl(resourceType, id), options);
575
589
  }
576
590
  /**
577
591
  * Reads a resource by `Reference`.
@@ -592,7 +606,7 @@ class MedplumClient extends EventTarget {
592
606
  * @param reference The FHIR reference object.
593
607
  * @returns The resource if available; undefined otherwise.
594
608
  */
595
- readReference(reference) {
609
+ readReference(reference, options = {}) {
596
610
  const refString = reference === null || reference === void 0 ? void 0 : reference.reference;
597
611
  if (!refString) {
598
612
  return new ReadablePromise(Promise.reject(new Error('Missing reference')));
@@ -601,7 +615,7 @@ class MedplumClient extends EventTarget {
601
615
  if (!resourceType || !id) {
602
616
  return new ReadablePromise(Promise.reject(new Error('Invalid reference')));
603
617
  }
604
- return this.readResource(resourceType, id);
618
+ return this.readResource(resourceType, id, options);
605
619
  }
606
620
  /**
607
621
  * Returns a cached schema for a resource type.
@@ -685,8 +699,8 @@ class MedplumClient extends EventTarget {
685
699
  * @param id The resource ID.
686
700
  * @returns Promise to the resource history.
687
701
  */
688
- readHistory(resourceType, id) {
689
- return this.get(this.fhirUrl(resourceType, id, '_history'));
702
+ readHistory(resourceType, id, options = {}) {
703
+ return this.get(this.fhirUrl(resourceType, id, '_history'), options);
690
704
  }
691
705
  /**
692
706
  * Reads a specific version of a resource by resource type, ID, and version ID.
@@ -705,8 +719,8 @@ class MedplumClient extends EventTarget {
705
719
  * @param id The resource ID.
706
720
  * @returns The resource if available; undefined otherwise.
707
721
  */
708
- readVersion(resourceType, id, vid) {
709
- return this.get(this.fhirUrl(resourceType, id, '_history', vid));
722
+ readVersion(resourceType, id, vid, options = {}) {
723
+ return this.get(this.fhirUrl(resourceType, id, '_history', vid), options);
710
724
  }
711
725
  /**
712
726
  *
@@ -714,8 +728,8 @@ class MedplumClient extends EventTarget {
714
728
  * @param id The Patient Id
715
729
  * @returns A Bundle of all Resources related to the Patient
716
730
  */
717
- readPatientEverything(id) {
718
- return this.get(this.fhirUrl('Patient', id, '$everything'));
731
+ readPatientEverything(id, options = {}) {
732
+ return this.get(this.fhirUrl('Patient', id, '$everything'), options);
719
733
  }
720
734
  /**
721
735
  * Creates a new FHIR resource.
@@ -1225,28 +1239,36 @@ class MedplumClient extends EventTarget {
1225
1239
  return response.blob();
1226
1240
  });
1227
1241
  }
1242
+ /**
1243
+ * Starts a new PKCE flow.
1244
+ * These PKCE values are stateful, and must survive redirects and page refreshes.
1245
+ */
1246
+ startPkce() {
1247
+ return __awaiter(this, void 0, void 0, function* () {
1248
+ const pkceState = getRandomString();
1249
+ sessionStorage.setItem('pkceState', pkceState);
1250
+ const codeVerifier = getRandomString();
1251
+ sessionStorage.setItem('codeVerifier', codeVerifier);
1252
+ const arrayHash = yield encryptSHA256(codeVerifier);
1253
+ const codeChallenge = arrayBufferToBase64(arrayHash).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
1254
+ sessionStorage.setItem('codeChallenge', codeChallenge);
1255
+ });
1256
+ }
1228
1257
  /**
1229
1258
  * Processes an OAuth authorization code.
1230
1259
  * See: https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest
1231
1260
  * @param code The authorization code received by URL parameter.
1232
1261
  */
1233
1262
  processCode(code) {
1234
- const pkceState = __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('pkceState');
1235
- if (!pkceState) {
1236
- this.clear();
1237
- throw new Error('Invalid PCKE state');
1238
- }
1239
- const codeVerifier = __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeVerifier');
1240
- if (!codeVerifier) {
1241
- this.clear();
1242
- throw new Error('Invalid PCKE code verifier');
1243
- }
1244
1263
  const formBody = new URLSearchParams();
1245
1264
  formBody.set('grant_type', 'authorization_code');
1246
1265
  formBody.set('client_id', __classPrivateFieldGet(this, _MedplumClient_clientId, "f"));
1247
- formBody.set('code_verifier', codeVerifier);
1248
1266
  formBody.set('code', code);
1249
1267
  formBody.set('redirect_uri', getBaseUrl());
1268
+ const codeVerifier = sessionStorage.getItem('codeVerifier');
1269
+ if (codeVerifier) {
1270
+ formBody.set('code_verifier', codeVerifier);
1271
+ }
1250
1272
  return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_fetchTokens).call(this, formBody);
1251
1273
  }
1252
1274
  /**
@@ -1370,27 +1392,17 @@ _MedplumClient_fetch = new WeakMap(), _MedplumClient_createPdf = new WeakMap(),
1370
1392
  return Promise.reject(error);
1371
1393
  });
1372
1394
  });
1373
- }, _MedplumClient_startPkce = function _MedplumClient_startPkce() {
1374
- return __awaiter(this, void 0, void 0, function* () {
1375
- const pkceState = getRandomString();
1376
- __classPrivateFieldGet(this, _MedplumClient_storage, "f").setString('pkceState', pkceState);
1377
- const codeVerifier = getRandomString();
1378
- __classPrivateFieldGet(this, _MedplumClient_storage, "f").setString('codeVerifier', codeVerifier);
1379
- const arrayHash = yield encryptSHA256(codeVerifier);
1380
- const codeChallenge = arrayBufferToBase64(arrayHash).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
1381
- __classPrivateFieldGet(this, _MedplumClient_storage, "f").setString('codeChallenge', codeChallenge);
1382
- });
1383
1395
  }, _MedplumClient_requestAuthorization = function _MedplumClient_requestAuthorization() {
1384
1396
  return __awaiter(this, void 0, void 0, function* () {
1385
- yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
1397
+ yield this.startPkce();
1386
1398
  const url = new URL(__classPrivateFieldGet(this, _MedplumClient_authorizeUrl, "f"));
1387
1399
  url.searchParams.set('response_type', 'code');
1388
- url.searchParams.set('state', __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('pkceState'));
1400
+ url.searchParams.set('state', sessionStorage.getItem('pkceState'));
1389
1401
  url.searchParams.set('client_id', __classPrivateFieldGet(this, _MedplumClient_clientId, "f"));
1390
1402
  url.searchParams.set('redirect_uri', getBaseUrl());
1391
1403
  url.searchParams.set('scope', DEFAULT_SCOPE);
1392
1404
  url.searchParams.set('code_challenge_method', 'S256');
1393
- url.searchParams.set('code_challenge', __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeChallenge'));
1405
+ url.searchParams.set('code_challenge', sessionStorage.getItem('codeChallenge'));
1394
1406
  window.location.assign(url.toString());
1395
1407
  });
1396
1408
  }, _MedplumClient_refresh = function _MedplumClient_refresh() {
@@ -1415,6 +1427,7 @@ _MedplumClient_fetch = new WeakMap(), _MedplumClient_createPdf = new WeakMap(),
1415
1427
  method: 'POST',
1416
1428
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1417
1429
  body: formBody,
1430
+ credentials: 'include',
1418
1431
  })
1419
1432
  .then((response) => {
1420
1433
  if (!response.ok) {