@medplum/core 2.0.21 → 2.0.23

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 (58) hide show
  1. package/dist/cjs/index.cjs +720 -494
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs/index.min.cjs +1 -1
  4. package/dist/esm/client.mjs +197 -114
  5. package/dist/esm/client.mjs.map +1 -1
  6. package/dist/esm/crypto.mjs +3 -1
  7. package/dist/esm/crypto.mjs.map +1 -1
  8. package/dist/esm/fhirlexer/parse.mjs.map +1 -1
  9. package/dist/esm/fhirlexer/tokenize.mjs +2 -2
  10. package/dist/esm/fhirlexer/tokenize.mjs.map +1 -1
  11. package/dist/esm/fhirpath/atoms.mjs +63 -56
  12. package/dist/esm/fhirpath/atoms.mjs.map +1 -1
  13. package/dist/esm/fhirpath/functions.mjs +370 -252
  14. package/dist/esm/fhirpath/functions.mjs.map +1 -1
  15. package/dist/esm/fhirpath/parse.mjs +4 -2
  16. package/dist/esm/fhirpath/parse.mjs.map +1 -1
  17. package/dist/esm/format.mjs +6 -4
  18. package/dist/esm/format.mjs.map +1 -1
  19. package/dist/esm/hl7.mjs +1 -1
  20. package/dist/esm/hl7.mjs.map +1 -1
  21. package/dist/esm/index.min.mjs +1 -1
  22. package/dist/esm/index.mjs +2 -1
  23. package/dist/esm/index.mjs.map +1 -1
  24. package/dist/esm/jwt.mjs +4 -2
  25. package/dist/esm/jwt.mjs.map +1 -1
  26. package/dist/esm/outcomes.mjs +14 -11
  27. package/dist/esm/outcomes.mjs.map +1 -1
  28. package/dist/esm/schema.mjs +4 -10
  29. package/dist/esm/schema.mjs.map +1 -1
  30. package/dist/esm/search/details.mjs +4 -5
  31. package/dist/esm/search/details.mjs.map +1 -1
  32. package/dist/esm/search/match.mjs +1 -0
  33. package/dist/esm/search/match.mjs.map +1 -1
  34. package/dist/esm/search/search.mjs +1 -1
  35. package/dist/esm/search/search.mjs.map +1 -1
  36. package/dist/esm/storage.mjs +8 -0
  37. package/dist/esm/storage.mjs.map +1 -1
  38. package/dist/esm/types.mjs +1 -0
  39. package/dist/esm/types.mjs.map +1 -1
  40. package/dist/esm/utils.mjs +8 -7
  41. package/dist/esm/utils.mjs.map +1 -1
  42. package/dist/types/client.d.ts +128 -69
  43. package/dist/types/crypto.d.ts +3 -1
  44. package/dist/types/fhirlexer/parse.d.ts +7 -3
  45. package/dist/types/fhirpath/atoms.d.ts +21 -21
  46. package/dist/types/fhirpath/functions.d.ts +2 -2
  47. package/dist/types/fhirpath/parse.d.ts +2 -1
  48. package/dist/types/hl7.d.ts +1 -1
  49. package/dist/types/index.d.ts +1 -0
  50. package/dist/types/jwt.d.ts +2 -1
  51. package/dist/types/outcomes.d.ts +7 -1
  52. package/dist/types/schema.d.ts +4 -10
  53. package/dist/types/search/details.d.ts +0 -1
  54. package/dist/types/search/search.d.ts +1 -1
  55. package/dist/types/storage.d.ts +8 -0
  56. package/dist/types/typeschema/types.d.ts +0 -1
  57. package/dist/types/utils.d.ts +5 -12
  58. package/package.json +1 -1
@@ -4,6 +4,37 @@
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.medplum = global.medplum || {}, global.medplum.core = {})));
5
5
  })(this, (function (exports) { 'use strict';
6
6
 
7
+ /**
8
+ * Decodes a base64 string.
9
+ * Handles both browser and Node environments.
10
+ * @param data The base-64 encoded input string.
11
+ * @returns The decoded string.
12
+ */
13
+ function decodeBase64(data) {
14
+ if (typeof window !== 'undefined') {
15
+ return window.atob(data);
16
+ }
17
+ if (typeof Buffer !== 'undefined') {
18
+ return Buffer.from(data, 'base64').toString('binary');
19
+ }
20
+ throw new Error('Unable to decode base64');
21
+ }
22
+ /**
23
+ * Encodes a base64 string.
24
+ * Handles both browser and Node environments.
25
+ * @param data The unencoded input string.
26
+ * @returns The base-64 encoded string.
27
+ */
28
+ function encodeBase64(data) {
29
+ if (typeof window !== 'undefined') {
30
+ return window.btoa(data);
31
+ }
32
+ if (typeof Buffer !== 'undefined') {
33
+ return Buffer.from(data, 'binary').toString('base64');
34
+ }
35
+ throw new Error('Unable to encode base64');
36
+ }
37
+
7
38
  /**
8
39
  * More on Bundles can be found here
9
40
  * http://hl7.org/fhir/R4/bundle.html
@@ -454,18 +485,20 @@
454
485
  }
455
486
  /**
456
487
  * Returns the input number increased by the `n` units of the specified precision
457
- * @param a The input number
488
+ * @param a The input number.
458
489
  * @param precision The precision in number of digits.
459
- * @param n (default 1) The number of units to add
490
+ * @param n (default 1) The number of units to add.
491
+ * @returns The result of the increment.
460
492
  */
461
493
  function preciseIncrement(a, precision, n = 1) {
462
494
  return (toPreciseInteger$1(a, precision) + n) * Math.pow(10, -precision);
463
495
  }
464
496
  /**
465
497
  * Returns the input number decreased by the `n` units of the specified precision
466
- * @param a The input number
498
+ * @param a The input number.
467
499
  * @param precision The precision in number of digits.
468
- * @param n (default 1) The number of units to subtract
500
+ * @param n (default 1) The number of units to subtract.
501
+ * @returns The result of the decrement.
469
502
  */
470
503
  function preciseDecrement(a, precision, n = 1) {
471
504
  return (toPreciseInteger$1(a, precision) - n) * Math.pow(10, -precision);
@@ -523,7 +556,7 @@
523
556
  /**
524
557
  * Returns a display string for the resource.
525
558
  * @param resource The input resource.
526
- * @return Human friendly display string.
559
+ * @returns Human friendly display string.
527
560
  */
528
561
  function getDisplayString(resource) {
529
562
  if (isProfileResource(resource)) {
@@ -680,7 +713,7 @@
680
713
  }
681
714
  /**
682
715
  * Recursively builds the questionnaire answer items map.
683
- * @param item The current questionnaire response item.
716
+ * @param items The current questionnaire response items.
684
717
  * @param result The cumulative result map.
685
718
  */
686
719
  function buildQuestionnaireAnswerItems(items, result) {
@@ -699,7 +732,6 @@
699
732
  * If multiple identifiers exist with the same system, the first one is returned.
700
733
  *
701
734
  * If the system is not found, then returns undefined.
702
- *
703
735
  * @param resource The resource to check.
704
736
  * @param system The identifier system.
705
737
  * @returns The identifier value if found; otherwise undefined.
@@ -763,8 +795,9 @@
763
795
  * Evaluates JSON key/value pairs for FHIR JSON stringify.
764
796
  * Removes properties with empty string values.
765
797
  * Removes objects with zero properties.
766
- * @param {string} k Property key.
767
- * @param {*} v Property value.
798
+ * @param k Property key.
799
+ * @param v Property value.
800
+ * @returns The replaced value.
768
801
  */
769
802
  function stringifyReplacer(k, v) {
770
803
  return !isArrayKey(k) && isEmpty(v) ? undefined : v;
@@ -794,6 +827,7 @@
794
827
  * Ignores meta.versionId and meta.lastUpdated.
795
828
  * @param object1 The first object.
796
829
  * @param object2 The second object.
830
+ * @param path Optional path string.
797
831
  * @returns True if the objects are equal.
798
832
  */
799
833
  function deepEquals$1(object1, object2, path) {
@@ -859,7 +893,6 @@
859
893
  *
860
894
  * See: https://web.dev/structured-clone/
861
895
  * See: https://stackoverflow.com/questions/40488190/how-is-structured-clone-algorithm-different-from-deep-copy
862
- *
863
896
  * @param input The input to clone.
864
897
  * @returns A deep clone of the input.
865
898
  */
@@ -876,7 +909,7 @@
876
909
  }
877
910
  /**
878
911
  * Returns true if the input is an object.
879
- * @param object The candidate object.
912
+ * @param obj The candidate object.
880
913
  * @returns True if the input is a non-null non-undefined object.
881
914
  */
882
915
  function isObject$1(obj) {
@@ -961,6 +994,7 @@
961
994
  * @param definition The observation definition.
962
995
  * @param patient The patient.
963
996
  * @param value The observation value.
997
+ * @param category Optional interval category restriction.
964
998
  * @returns The observation interval if found; otherwise undefined.
965
999
  */
966
1000
  function findObservationInterval(definition, patient, value, category) {
@@ -1113,6 +1147,7 @@
1113
1147
 
1114
1148
  /**
1115
1149
  * Returns a cryptographically secure random string.
1150
+ * @returns A cryptographically secure random string.
1116
1151
  */
1117
1152
  function getRandomString() {
1118
1153
  const randomItems = new Uint32Array(28);
@@ -1121,7 +1156,8 @@
1121
1156
  }
1122
1157
  /**
1123
1158
  * Encrypts a string with SHA256 encryption.
1124
- * @param str
1159
+ * @param str The unencrypted input string.
1160
+ * @returns The encrypted value in an ArrayBuffer.
1125
1161
  */
1126
1162
  async function encryptSHA256(str) {
1127
1163
  return crypto.subtle.digest('SHA-256', new TextEncoder().encode(str));
@@ -1161,41 +1197,11 @@
1161
1197
  }
1162
1198
  }
1163
1199
 
1164
- /**
1165
- * Decodes a base64 string.
1166
- * Handles both browser and Node environments.
1167
- * @param data The base-64 encoded input string.
1168
- * @returns The decoded string.
1169
- */
1170
- function decodeBase64(data) {
1171
- if (typeof window !== 'undefined') {
1172
- return window.atob(data);
1173
- }
1174
- if (typeof Buffer !== 'undefined') {
1175
- return Buffer.from(data, 'base64').toString('binary');
1176
- }
1177
- throw new Error('Unable to decode base64');
1178
- }
1179
- /**
1180
- * Encodes a base64 string.
1181
- * Handles both browser and Node environments.
1182
- * @param data The unencoded input string.
1183
- * @returns The base-64 encoded string.
1184
- */
1185
- function encodeBase64(data) {
1186
- if (typeof window !== 'undefined') {
1187
- return window.btoa(data);
1188
- }
1189
- if (typeof Buffer !== 'undefined') {
1190
- return Buffer.from(data, 'binary').toString('base64');
1191
- }
1192
- throw new Error('Unable to encode base64');
1193
- }
1194
-
1195
1200
  /**
1196
1201
  * Decodes a section of a JWT.
1197
1202
  * See: https://tools.ietf.org/html/rfc7519
1198
- * @param payload
1203
+ * @param payload The JWT payload string.
1204
+ * @returns Collection of key value claims in the JWT payload.
1199
1205
  */
1200
1206
  function decodePayload(payload) {
1201
1207
  const cleanedPayload = payload.replace(/-/g, '+').replace(/_/g, '/');
@@ -1209,7 +1215,8 @@
1209
1215
  }
1210
1216
  /**
1211
1217
  * Parses the JWT payload.
1212
- * @param token JWT token
1218
+ * @param token JWT token.
1219
+ * @returns Collection of key value claims in the JWT payload.
1213
1220
  */
1214
1221
  function parseJWTPayload(token) {
1215
1222
  const [_header, payload, _signature] = token.split('.');
@@ -1469,18 +1476,21 @@
1469
1476
  * @returns The string representation of the operation outcome.
1470
1477
  */
1471
1478
  function operationOutcomeToString(outcome) {
1472
- const strs = [];
1473
- if (outcome.issue) {
1474
- for (const issue of outcome.issue) {
1475
- let issueStr = issue.details?.text || 'Unknown error';
1476
- if (issue.expression?.length) {
1477
- issueStr += ` (${issue.expression.join(', ')})`;
1478
- }
1479
- strs.push(issueStr);
1480
- }
1481
- }
1479
+ const strs = outcome.issue?.map(operationOutcomeIssueToString) ?? [];
1482
1480
  return strs.length > 0 ? strs.join('; ') : 'Unknown error';
1483
1481
  }
1482
+ /**
1483
+ * Returns a string represenation of the operation outcome issue.
1484
+ * @param issue The operation outcome issue.
1485
+ * @returns The string representation of the operation outcome issue.
1486
+ */
1487
+ function operationOutcomeIssueToString(issue) {
1488
+ let issueStr = issue.details?.text ?? issue.diagnostics ?? 'Unknown error';
1489
+ if (issue.expression?.length) {
1490
+ issueStr += ` (${issue.expression.join(', ')})`;
1491
+ }
1492
+ return issueStr;
1493
+ }
1484
1494
 
1485
1495
  var _a;
1486
1496
  /**
@@ -1604,6 +1614,7 @@
1604
1614
  }
1605
1615
  /**
1606
1616
  * Returns the number of key/value pairs.
1617
+ * @returns The number of key/value pairs.
1607
1618
  */
1608
1619
  get length() {
1609
1620
  return this.data.size;
@@ -1616,12 +1627,16 @@
1616
1627
  }
1617
1628
  /**
1618
1629
  * Returns the current value associated with the given key, or null if the given key does not exist.
1630
+ * @param key The specified storage key.
1631
+ * @returns The current value associated with the given key, or null if the given key does not exist.
1619
1632
  */
1620
1633
  getItem(key) {
1621
1634
  return this.data.get(key) ?? null;
1622
1635
  }
1623
1636
  /**
1624
1637
  * Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
1638
+ * @param key The storage key.
1639
+ * @param value The new value.
1625
1640
  */
1626
1641
  setItem(key, value) {
1627
1642
  if (value) {
@@ -1633,12 +1648,15 @@
1633
1648
  }
1634
1649
  /**
1635
1650
  * Removes the key/value pair with the given key, if a key/value pair with the given key exists.
1651
+ * @param key The storage key.
1636
1652
  */
1637
1653
  removeItem(key) {
1638
1654
  this.data.delete(key);
1639
1655
  }
1640
1656
  /**
1641
1657
  * Returns the name of the nth key, or null if n is greater than or equal to the number of key/value pairs.
1658
+ * @param index The numeric index.
1659
+ * @returns The nth key.
1642
1660
  */
1643
1661
  key(index) {
1644
1662
  return Array.from(this.data.keys())[index];
@@ -6181,6 +6199,7 @@
6181
6199
  }
6182
6200
  /**
6183
6201
  * Indexes PropertySchema from an ElementDefinition.
6202
+ * @param structureDefinition The input StructureDefinition.
6184
6203
  * @param element The input ElementDefinition.
6185
6204
  * @see {@link IndexedStructureDefinition} for more details on indexed StructureDefinitions.
6186
6205
  */
@@ -6417,7 +6436,7 @@
6417
6436
 
6418
6437
  // PKCE auth based on:
6419
6438
  // https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
6420
- const MEDPLUM_VERSION = "2.0.21-87271fa1" ;
6439
+ const MEDPLUM_VERSION = "2.0.23-b244eeae" ;
6421
6440
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
6422
6441
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
6423
6442
  const DEFAULT_CACHE_TIME = 60000; // 60 seconds
@@ -6504,7 +6523,6 @@
6504
6523
  * <head>
6505
6524
  * <meta name="algolia:pageRank" content="100" />
6506
6525
  * </head>
6507
-
6508
6526
  */
6509
6527
  class MedplumClient extends EventTarget {
6510
6528
  constructor(options) {
@@ -6557,6 +6575,16 @@
6557
6575
  getBaseUrl() {
6558
6576
  return this.baseUrl;
6559
6577
  }
6578
+ /**
6579
+ * Returns the current authorize URL.
6580
+ * By default, this is set to `https://api.medplum.com/oauth2/authorize`.
6581
+ * This can be overridden by setting the `authorizeUrl` option when creating the client.
6582
+ * @category HTTP
6583
+ * @returns The current authorize URL.
6584
+ */
6585
+ getAuthorizeUrl() {
6586
+ return this.authorizeUrl;
6587
+ }
6560
6588
  /**
6561
6589
  * Clears all auth state including local storage and session storage.
6562
6590
  * @category Authentication
@@ -6571,12 +6599,14 @@
6571
6599
  * @category Authentication
6572
6600
  */
6573
6601
  clearActiveLogin() {
6602
+ if (this.basicAuth) {
6603
+ return;
6604
+ }
6574
6605
  this.storage.setString('activeLogin', undefined);
6575
6606
  this.requestCache?.clear();
6576
6607
  this.accessToken = undefined;
6577
6608
  this.refreshToken = undefined;
6578
- this.profile = undefined;
6579
- this.config = undefined;
6609
+ this.sessionDetails = undefined;
6580
6610
  this.dispatchEvent({ type: 'change' });
6581
6611
  }
6582
6612
  /**
@@ -6616,7 +6646,6 @@
6616
6646
  * This is a lower level method for custom requests.
6617
6647
  * For common operations, we recommend using higher level methods
6618
6648
  * such as `readResource()`, `search()`, etc.
6619
- *
6620
6649
  * @category HTTP
6621
6650
  * @param url The target URL.
6622
6651
  * @param options Optional fetch options.
@@ -6656,7 +6685,6 @@
6656
6685
  * This is a lower level method for custom requests.
6657
6686
  * For common operations, we recommend using higher level methods
6658
6687
  * such as `createResource()`.
6659
- *
6660
6688
  * @category HTTP
6661
6689
  * @param url The target URL.
6662
6690
  * @param body The content body. Strings and `File` objects are passed directly. Other objects are converted to JSON.
@@ -6681,7 +6709,6 @@
6681
6709
  * This is a lower level method for custom requests.
6682
6710
  * For common operations, we recommend using higher level methods
6683
6711
  * such as `updateResource()`.
6684
- *
6685
6712
  * @category HTTP
6686
6713
  * @param url The target URL.
6687
6714
  * @param body The content body. Strings and `File` objects are passed directly. Other objects are converted to JSON.
@@ -6706,7 +6733,6 @@
6706
6733
  * This is a lower level method for custom requests.
6707
6734
  * For common operations, we recommend using higher level methods
6708
6735
  * such as `patchResource()`.
6709
- *
6710
6736
  * @category HTTP
6711
6737
  * @param url The target URL.
6712
6738
  * @param operations Array of JSONPatch operations.
@@ -6727,13 +6753,12 @@
6727
6753
  * This is a lower level method for custom requests.
6728
6754
  * For common operations, we recommend using higher level methods
6729
6755
  * such as `deleteResource()`.
6730
- *
6731
6756
  * @category HTTP
6732
6757
  * @param url The target URL.
6733
6758
  * @param options Optional fetch options.
6734
6759
  * @returns Promise to the response content.
6735
6760
  */
6736
- delete(url, options = {}) {
6761
+ delete(url, options) {
6737
6762
  url = url.toString();
6738
6763
  this.invalidateUrl(url);
6739
6764
  return this.request('DELETE', url, options);
@@ -6744,53 +6769,54 @@
6744
6769
  * This method is part of the two different user registration flows:
6745
6770
  * 1) New Practitioner and new Project
6746
6771
  * 2) New Patient registration
6747
- *
6748
6772
  * @category Authentication
6749
6773
  * @param newUserRequest Register request including email and password.
6774
+ * @param options Optional fetch options.
6750
6775
  * @returns Promise to the authentication response.
6751
6776
  */
6752
- async startNewUser(newUserRequest) {
6777
+ async startNewUser(newUserRequest, options) {
6753
6778
  const { codeChallengeMethod, codeChallenge } = await this.startPkce();
6754
6779
  return this.post('auth/newuser', {
6755
6780
  ...newUserRequest,
6756
6781
  codeChallengeMethod,
6757
6782
  codeChallenge,
6758
- });
6783
+ }, undefined, options);
6759
6784
  }
6760
6785
  /**
6761
6786
  * Initiates a new project flow.
6762
6787
  *
6763
6788
  * This requires a partial login from `startNewUser` or `startNewGoogleUser`.
6764
- *
6765
6789
  * @param newProjectRequest Register request including email and password.
6790
+ * @param options Optional fetch options.
6766
6791
  * @returns Promise to the authentication response.
6767
6792
  */
6768
- async startNewProject(newProjectRequest) {
6769
- return this.post('auth/newproject', newProjectRequest);
6793
+ async startNewProject(newProjectRequest, options) {
6794
+ return this.post('auth/newproject', newProjectRequest, undefined, options);
6770
6795
  }
6771
6796
  /**
6772
6797
  * Initiates a new patient flow.
6773
6798
  *
6774
6799
  * This requires a partial login from `startNewUser` or `startNewGoogleUser`.
6775
- *
6776
6800
  * @param newPatientRequest Register request including email and password.
6801
+ * @param options Optional fetch options.
6777
6802
  * @returns Promise to the authentication response.
6778
6803
  */
6779
- async startNewPatient(newPatientRequest) {
6780
- return this.post('auth/newpatient', newPatientRequest);
6804
+ async startNewPatient(newPatientRequest, options) {
6805
+ return this.post('auth/newpatient', newPatientRequest, undefined, options);
6781
6806
  }
6782
6807
  /**
6783
6808
  * Initiates a user login flow.
6784
6809
  * @category Authentication
6785
6810
  * @param loginRequest Login request including email and password.
6811
+ * @param options Optional fetch options.
6786
6812
  * @returns Promise to the authentication response.
6787
6813
  */
6788
- async startLogin(loginRequest) {
6814
+ async startLogin(loginRequest, options) {
6789
6815
  return this.post('auth/login', {
6790
6816
  ...(await this.ensureCodeChallenge(loginRequest)),
6791
6817
  clientId: loginRequest.clientId ?? this.clientId,
6792
6818
  scope: loginRequest.scope,
6793
- });
6819
+ }, undefined, options);
6794
6820
  }
6795
6821
  /**
6796
6822
  * Tries to sign in with Google authentication.
@@ -6798,14 +6824,15 @@
6798
6824
  * See: https://developers.google.com/identity/gsi/web/guides/handle-credential-responses-js-functions
6799
6825
  * @category Authentication
6800
6826
  * @param loginRequest Login request including Google credential response.
6827
+ * @param options Optional fetch options.
6801
6828
  * @returns Promise to the authentication response.
6802
6829
  */
6803
- async startGoogleLogin(loginRequest) {
6830
+ async startGoogleLogin(loginRequest, options) {
6804
6831
  return this.post('auth/google', {
6805
6832
  ...(await this.ensureCodeChallenge(loginRequest)),
6806
6833
  clientId: loginRequest.clientId ?? this.clientId,
6807
6834
  scope: loginRequest.scope,
6808
- });
6835
+ }, undefined, options);
6809
6836
  }
6810
6837
  /**
6811
6838
  * Returns the PKCE code challenge and method.
@@ -6836,6 +6863,7 @@
6836
6863
  * This may result in navigating away to the sign in page.
6837
6864
  * @category Authentication
6838
6865
  * @param loginParams Optional login parameters.
6866
+ * @returns The user profile resource if available.
6839
6867
  */
6840
6868
  async signInWithRedirect(loginParams) {
6841
6869
  const urlParams = new URLSearchParams(window.location.search);
@@ -6872,6 +6900,7 @@
6872
6900
  * Exchange an external access token for a Medplum access token.
6873
6901
  * @param token The access token that was generated by the external identity provider.
6874
6902
  * @param clientId The ID of the `ClientApplication` in your Medplum project that will be making the exchange request.
6903
+ * @returns The user profile resource.
6875
6904
  * @category Authentication
6876
6905
  */
6877
6906
  async exchangeExternalAccessToken(token, clientId) {
@@ -6970,14 +6999,13 @@
6970
6999
  * ```
6971
7000
  *
6972
7001
  * See FHIR search for full details: https://www.hl7.org/fhir/search.html
6973
- *
6974
7002
  * @category Search
6975
7003
  * @param resourceType The FHIR resource type.
6976
7004
  * @param query Optional FHIR search query or structured query object. Can be any valid input to the URLSearchParams() constructor.
6977
7005
  * @param options Optional fetch options.
6978
7006
  * @returns Promise to the search result bundle.
6979
7007
  */
6980
- search(resourceType, query, options = {}) {
7008
+ search(resourceType, query, options) {
6981
7009
  const url = this.fhirSearchUrl(resourceType, query);
6982
7010
  const cacheKey = url.toString() + '-search';
6983
7011
  const cached = this.getCacheEntry(cacheKey, options);
@@ -7011,14 +7039,13 @@
7011
7039
  * The return value is the resource, if available; otherwise, undefined.
7012
7040
  *
7013
7041
  * See FHIR search for full details: https://www.hl7.org/fhir/search.html
7014
- *
7015
7042
  * @category Search
7016
7043
  * @param resourceType The FHIR resource type.
7017
7044
  * @param query Optional FHIR search query or structured query object. Can be any valid input to the URLSearchParams() constructor.
7018
7045
  * @param options Optional fetch options.
7019
7046
  * @returns Promise to the first search result.
7020
7047
  */
7021
- searchOne(resourceType, query, options = {}) {
7048
+ searchOne(resourceType, query, options) {
7022
7049
  const url = this.fhirSearchUrl(resourceType, query);
7023
7050
  url.searchParams.set('_count', '1');
7024
7051
  url.searchParams.sort();
@@ -7046,14 +7073,13 @@
7046
7073
  * The return value is an array of resources.
7047
7074
  *
7048
7075
  * See FHIR search for full details: https://www.hl7.org/fhir/search.html
7049
- *
7050
7076
  * @category Search
7051
7077
  * @param resourceType The FHIR resource type.
7052
7078
  * @param query Optional FHIR search query or structured query object. Can be any valid input to the URLSearchParams() constructor.
7053
7079
  * @param options Optional fetch options.
7054
7080
  * @returns Promise to the array of search results.
7055
7081
  */
7056
- searchResources(resourceType, query, options = {}) {
7082
+ searchResources(resourceType, query, options) {
7057
7083
  const url = this.fhirSearchUrl(resourceType, query);
7058
7084
  const cacheKey = url.toString() + '-searchResources';
7059
7085
  const cached = this.getCacheEntry(cacheKey, options);
@@ -7078,14 +7104,13 @@
7078
7104
  * }
7079
7105
  * }
7080
7106
  * ```
7081
- *
7082
7107
  * @category Search
7083
7108
  * @param resourceType The FHIR resource type.
7084
7109
  * @param query Optional FHIR search query or structured query object. Can be any valid input to the URLSearchParams() constructor.
7085
7110
  * @param options Optional fetch options.
7086
- * @returns An async generator, where each result is an array of resources for each page.
7111
+ * @yields An async generator, where each result is an array of resources for each page.
7087
7112
  */
7088
- async *searchResourcePages(resourceType, query, options = {}) {
7113
+ async *searchResourcePages(resourceType, query, options) {
7089
7114
  let url = this.fhirSearchUrl(resourceType, query);
7090
7115
  while (url) {
7091
7116
  const searchParams = new URL(url).searchParams;
@@ -7101,14 +7126,13 @@
7101
7126
  /**
7102
7127
  * Searches a ValueSet resource using the "expand" operation.
7103
7128
  * See: https://www.hl7.org/fhir/operation-valueset-expand.html
7104
- *
7105
7129
  * @category Search
7106
7130
  * @param system The ValueSet system url.
7107
7131
  * @param filter The search string.
7108
7132
  * @param options Optional fetch options.
7109
7133
  * @returns Promise to expanded ValueSet.
7110
7134
  */
7111
- searchValueSet(system, filter, options = {}) {
7135
+ searchValueSet(system, filter, options) {
7112
7136
  const url = this.fhirUrl('ValueSet', '$expand');
7113
7137
  url.searchParams.set('url', system);
7114
7138
  url.searchParams.set('filter', filter);
@@ -7128,8 +7152,7 @@
7128
7152
  /**
7129
7153
  * Returns a cached resource if it is available.
7130
7154
  * @category Caching
7131
- * @param resourceType The FHIR resource type.
7132
- * @param id The FHIR resource ID.
7155
+ * @param reference The FHIR reference.
7133
7156
  * @returns The resource if it is available in the cache; undefined otherwise.
7134
7157
  */
7135
7158
  getCachedReference(reference) {
@@ -7157,14 +7180,13 @@
7157
7180
  * ```
7158
7181
  *
7159
7182
  * See the FHIR "read" operation for full details: https://www.hl7.org/fhir/http.html#read
7160
- *
7161
7183
  * @category Read
7162
7184
  * @param resourceType The FHIR resource type.
7163
7185
  * @param id The resource ID.
7164
7186
  * @param options Optional fetch options.
7165
7187
  * @returns The resource if available; undefined otherwise.
7166
7188
  */
7167
- readResource(resourceType, id, options = {}) {
7189
+ readResource(resourceType, id, options) {
7168
7190
  return this.get(this.fhirUrl(resourceType, id), options);
7169
7191
  }
7170
7192
  /**
@@ -7181,13 +7203,12 @@
7181
7203
  * ```
7182
7204
  *
7183
7205
  * See the FHIR "read" operation for full details: https://www.hl7.org/fhir/http.html#read
7184
- *
7185
7206
  * @category Read
7186
7207
  * @param reference The FHIR reference object.
7187
7208
  * @param options Optional fetch options.
7188
7209
  * @returns The resource if available; undefined otherwise.
7189
7210
  */
7190
- readReference(reference, options = {}) {
7211
+ readReference(reference, options) {
7191
7212
  const refString = reference?.reference;
7192
7213
  if (!refString) {
7193
7214
  return new ReadablePromise(Promise.reject(new Error('Missing reference')));
@@ -7283,14 +7304,13 @@
7283
7304
  * ```
7284
7305
  *
7285
7306
  * See the FHIR "history" operation for full details: https://www.hl7.org/fhir/http.html#history
7286
- *
7287
7307
  * @category Read
7288
7308
  * @param resourceType The FHIR resource type.
7289
7309
  * @param id The resource ID.
7290
7310
  * @param options Optional fetch options.
7291
7311
  * @returns Promise to the resource history.
7292
7312
  */
7293
- readHistory(resourceType, id, options = {}) {
7313
+ readHistory(resourceType, id, options) {
7294
7314
  return this.get(this.fhirUrl(resourceType, id, '_history'), options);
7295
7315
  }
7296
7316
  /**
@@ -7304,7 +7324,6 @@
7304
7324
  * ```
7305
7325
  *
7306
7326
  * See the FHIR "vread" operation for full details: https://www.hl7.org/fhir/http.html#vread
7307
- *
7308
7327
  * @category Read
7309
7328
  * @param resourceType The FHIR resource type.
7310
7329
  * @param id The resource ID.
@@ -7312,7 +7331,7 @@
7312
7331
  * @param options Optional fetch options.
7313
7332
  * @returns The resource if available; undefined otherwise.
7314
7333
  */
7315
- readVersion(resourceType, id, vid, options = {}) {
7334
+ readVersion(resourceType, id, vid, options) {
7316
7335
  return this.get(this.fhirUrl(resourceType, id, '_history', vid), options);
7317
7336
  }
7318
7337
  /**
@@ -7326,13 +7345,12 @@
7326
7345
  * ```
7327
7346
  *
7328
7347
  * See the FHIR "patient-everything" operation for full details: https://hl7.org/fhir/operation-patient-everything.html
7329
- *
7330
7348
  * @category Read
7331
7349
  * @param id The Patient Id
7332
7350
  * @param options Optional fetch options.
7333
7351
  * @returns A Bundle of all Resources related to the Patient
7334
7352
  */
7335
- readPatientEverything(id, options = {}) {
7353
+ readPatientEverything(id, options) {
7336
7354
  return this.get(this.fhirUrl('Patient', id, '$everything'), options);
7337
7355
  }
7338
7356
  /**
@@ -7354,17 +7372,17 @@
7354
7372
  * ```
7355
7373
  *
7356
7374
  * See the FHIR "create" operation for full details: https://www.hl7.org/fhir/http.html#create
7357
- *
7358
7375
  * @category Create
7359
7376
  * @param resource The FHIR resource to create.
7377
+ * @param options Optional fetch options.
7360
7378
  * @returns The result of the create operation.
7361
7379
  */
7362
- createResource(resource) {
7380
+ createResource(resource, options) {
7363
7381
  if (!resource.resourceType) {
7364
7382
  throw new Error('Missing resourceType');
7365
7383
  }
7366
7384
  this.invalidateSearches(resource.resourceType);
7367
- return this.post(this.fhirUrl(resource.resourceType), resource);
7385
+ return this.post(this.fhirUrl(resource.resourceType), resource, undefined, options);
7368
7386
  }
7369
7387
  /**
7370
7388
  * Conditionally create a new FHIR resource only if some equivalent resource does not already exist on the server.
@@ -7400,14 +7418,15 @@
7400
7418
  * The query parameter only contains the search parameters (what would be in the URL following the "?").
7401
7419
  *
7402
7420
  * See the FHIR "conditional create" operation for full details: https://www.hl7.org/fhir/http.html#ccreate
7403
- *
7404
7421
  * @category Create
7405
7422
  * @param resource The FHIR resource to create.
7406
7423
  * @param query The search query for an equivalent resource (should not include resource type or "?").
7424
+ * @param options Optional fetch options.
7407
7425
  * @returns The result of the create operation.
7408
7426
  */
7409
- async createResourceIfNoneExist(resource, query) {
7410
- return ((await this.searchOne(resource.resourceType, query)) ?? this.createResource(resource));
7427
+ async createResourceIfNoneExist(resource, query, options) {
7428
+ return ((await this.searchOne(resource.resourceType, query, options)) ??
7429
+ this.createResource(resource, options));
7411
7430
  }
7412
7431
  /**
7413
7432
  * Creates a FHIR `Binary` resource with the provided data content.
@@ -7426,11 +7445,11 @@
7426
7445
  * ```
7427
7446
  *
7428
7447
  * See the FHIR "create" operation for full details: https://www.hl7.org/fhir/http.html#create
7429
- *
7430
7448
  * @category Create
7431
7449
  * @param data The binary data to upload.
7432
7450
  * @param filename Optional filename for the binary.
7433
7451
  * @param contentType Content type for the binary.
7452
+ * @param onProgress Optional callback for progress events.
7434
7453
  * @returns The result of the create operation.
7435
7454
  */
7436
7455
  createBinary(data, filename, contentType, onProgress) {
@@ -7489,9 +7508,11 @@
7489
7508
  * ```
7490
7509
  *
7491
7510
  * See the pdfmake document definition for full details: https://pdfmake.github.io/docs/0.1/document-definition-object/
7492
- *
7493
7511
  * @category Media
7494
7512
  * @param docDefinition The PDF document definition.
7513
+ * @param filename Optional filename for the PDF binary resource.
7514
+ * @param tableLayouts Optional pdfmake custom table layout.
7515
+ * @param fonts Optional pdfmake custom font dictionary.
7495
7516
  * @returns The result of the create operation.
7496
7517
  */
7497
7518
  async createPdf(docDefinition, filename, tableLayouts, fonts) {
@@ -7505,13 +7526,13 @@
7505
7526
  * Creates a FHIR `Communication` resource with the provided data content.
7506
7527
  *
7507
7528
  * This is a convenience method to handle commmon cases where a `Communication` resource is created with a `payload`.
7508
- *
7509
7529
  * @category Create
7510
7530
  * @param resource The FHIR resource to comment on.
7511
7531
  * @param text The text of the comment.
7532
+ * @param options Optional fetch options.
7512
7533
  * @returns The result of the create operation.
7513
7534
  */
7514
- createComment(resource, text) {
7535
+ createComment(resource, text, options) {
7515
7536
  const profile = this.getProfile();
7516
7537
  let encounter = undefined;
7517
7538
  let subject = undefined;
@@ -7534,7 +7555,7 @@
7534
7555
  sender: profile ? createReference(profile) : undefined,
7535
7556
  sent: new Date().toISOString(),
7536
7557
  payload: [{ contentString: text }],
7537
- });
7558
+ }, options);
7538
7559
  }
7539
7560
  /**
7540
7561
  * Updates a FHIR resource.
@@ -7556,12 +7577,12 @@
7556
7577
  * ```
7557
7578
  *
7558
7579
  * See the FHIR "update" operation for full details: https://www.hl7.org/fhir/http.html#update
7559
- *
7560
7580
  * @category Write
7561
7581
  * @param resource The FHIR resource to update.
7582
+ * @param options Optional fetch options.
7562
7583
  * @returns The result of the update operation.
7563
7584
  */
7564
- async updateResource(resource) {
7585
+ async updateResource(resource, options) {
7565
7586
  if (!resource.resourceType) {
7566
7587
  throw new Error('Missing resourceType');
7567
7588
  }
@@ -7569,7 +7590,7 @@
7569
7590
  throw new Error('Missing id');
7570
7591
  }
7571
7592
  this.invalidateSearches(resource.resourceType);
7572
- let result = await this.put(this.fhirUrl(resource.resourceType, resource.id), resource);
7593
+ let result = await this.put(this.fhirUrl(resource.resourceType, resource.id), resource, undefined, options);
7573
7594
  if (!result) {
7574
7595
  // On 304 not modified, result will be undefined
7575
7596
  // Return the user input instead
@@ -7596,16 +7617,16 @@
7596
7617
  * See the FHIR "update" operation for full details: https://www.hl7.org/fhir/http.html#patch
7597
7618
  *
7598
7619
  * See the JSONPatch specification for full details: https://tools.ietf.org/html/rfc6902
7599
- *
7600
7620
  * @category Write
7601
7621
  * @param resourceType The FHIR resource type.
7602
7622
  * @param id The resource ID.
7603
7623
  * @param operations The JSONPatch operations.
7624
+ * @param options Optional fetch options.
7604
7625
  * @returns The result of the patch operations.
7605
7626
  */
7606
- patchResource(resourceType, id, operations) {
7627
+ patchResource(resourceType, id, operations, options) {
7607
7628
  this.invalidateSearches(resourceType);
7608
- return this.patch(this.fhirUrl(resourceType, id), operations);
7629
+ return this.patch(this.fhirUrl(resourceType, id), operations, options);
7609
7630
  }
7610
7631
  /**
7611
7632
  * Deletes a FHIR resource by resource type and ID.
@@ -7617,16 +7638,16 @@
7617
7638
  * ```
7618
7639
  *
7619
7640
  * See the FHIR "delete" operation for full details: https://www.hl7.org/fhir/http.html#delete
7620
- *
7621
7641
  * @category Delete
7622
7642
  * @param resourceType The FHIR resource type.
7623
7643
  * @param id The resource ID.
7644
+ * @param options Optional fetch options.
7624
7645
  * @returns The result of the delete operation.
7625
7646
  */
7626
- deleteResource(resourceType, id) {
7647
+ deleteResource(resourceType, id, options) {
7627
7648
  this.deleteCacheEntry(this.fhirUrl(resourceType, id).toString());
7628
7649
  this.invalidateSearches(resourceType);
7629
- return this.delete(this.fhirUrl(resourceType, id));
7650
+ return this.delete(this.fhirUrl(resourceType, id), options);
7630
7651
  }
7631
7652
  /**
7632
7653
  * Executes the validate operation with the provided resource.
@@ -7641,12 +7662,12 @@
7641
7662
  * ```
7642
7663
  *
7643
7664
  * See the FHIR "$validate" operation for full details: https://www.hl7.org/fhir/resource-operation-validate.html
7644
- *
7645
7665
  * @param resource The FHIR resource.
7666
+ * @param options Optional fetch options.
7646
7667
  * @returns The validate operation outcome.
7647
7668
  */
7648
- validateResource(resource) {
7649
- return this.post(this.fhirUrl(resource.resourceType, '$validate'), resource);
7669
+ validateResource(resource, options) {
7670
+ return this.post(this.fhirUrl(resource.resourceType, '$validate'), resource, undefined, options);
7650
7671
  }
7651
7672
  /**
7652
7673
  * Executes a bot by ID or Identifier.
@@ -7656,7 +7677,7 @@
7656
7677
  * @param options Optional fetch options.
7657
7678
  * @returns The Bot return value.
7658
7679
  */
7659
- executeBot(idOrIdentifier, body, contentType, options = {}) {
7680
+ executeBot(idOrIdentifier, body, contentType, options) {
7660
7681
  let url;
7661
7682
  if (typeof idOrIdentifier === 'string') {
7662
7683
  const id = idOrIdentifier;
@@ -7716,7 +7737,7 @@
7716
7737
  * @param options Optional fetch options.
7717
7738
  * @returns The FHIR batch/transaction response bundle.
7718
7739
  */
7719
- executeBatch(bundle, options = {}) {
7740
+ executeBatch(bundle, options) {
7720
7741
  return this.post(this.fhirBaseUrl.slice(0, -1), bundle, undefined, options);
7721
7742
  }
7722
7743
  /**
@@ -7753,11 +7774,12 @@
7753
7774
  *
7754
7775
  * See options here: https://nodemailer.com/extras/mailcomposer/
7755
7776
  * @category Media
7756
- * @param options The MailComposer options.
7777
+ * @param email The MailComposer options.
7778
+ * @param options Optional fetch options.
7757
7779
  * @returns Promise to the operation outcome.
7758
7780
  */
7759
- sendEmail(email) {
7760
- return this.post('email/v1/send', email, 'application/json');
7781
+ sendEmail(email, options) {
7782
+ return this.post('email/v1/send', email, 'application/json', options);
7761
7783
  }
7762
7784
  /**
7763
7785
  * Executes a GraphQL query.
@@ -7799,7 +7821,6 @@
7799
7821
  * See the GraphQL documentation for more details: https://graphql.org/learn/
7800
7822
  *
7801
7823
  * See the FHIR GraphQL documentation for FHIR specific details: https://www.hl7.org/fhir/graphql.html
7802
- *
7803
7824
  * @category Read
7804
7825
  * @param query The GraphQL query.
7805
7826
  * @param operationName Optional GraphQL operation name.
@@ -7814,15 +7835,15 @@
7814
7835
  *
7815
7836
  * Executes the $graph operation on this resource to fetch a Bundle of resources linked to the target resource
7816
7837
  * according to a graph definition
7817
-
7818
7838
  * @category Read
7819
7839
  * @param resourceType The FHIR resource type.
7820
7840
  * @param id The resource ID.
7821
7841
  * @param graphName `name` parameter of the GraphDefinition
7842
+ * @param options Optional fetch options.
7822
7843
  * @returns A Bundle
7823
7844
  */
7824
- readResourceGraph(resourceType, id, graphName) {
7825
- return this.get(`${this.fhirUrl(resourceType, id)}/$graph?graph=${graphName}`);
7845
+ readResourceGraph(resourceType, id, graphName, options) {
7846
+ return this.get(`${this.fhirUrl(resourceType, id)}/$graph?graph=${graphName}`, options);
7826
7847
  }
7827
7848
  /**
7828
7849
  * @category Authentication
@@ -7832,11 +7853,16 @@
7832
7853
  return this.storage.getObject('activeLogin');
7833
7854
  }
7834
7855
  /**
7856
+ * Sets the active login.
7857
+ * @param login The new active login state.
7835
7858
  * @category Authentication
7836
7859
  */
7837
7860
  async setActiveLogin(login) {
7838
7861
  this.clearActiveLogin();
7839
7862
  this.accessToken = login.accessToken;
7863
+ if (this.basicAuth) {
7864
+ return;
7865
+ }
7840
7866
  this.refreshToken = login.refreshToken;
7841
7867
  this.storage.setObject('activeLogin', login);
7842
7868
  this.addLogin(login);
@@ -7845,6 +7871,7 @@
7845
7871
  }
7846
7872
  /**
7847
7873
  * Returns the current access token.
7874
+ * @returns The current access token.
7848
7875
  * @category Authentication
7849
7876
  */
7850
7877
  getAccessToken() {
@@ -7852,15 +7879,17 @@
7852
7879
  }
7853
7880
  /**
7854
7881
  * Sets the current access token.
7882
+ * @param accessToken The new access token.
7855
7883
  * @category Authentication
7856
7884
  */
7857
7885
  setAccessToken(accessToken) {
7858
7886
  this.accessToken = accessToken;
7859
7887
  this.refreshToken = undefined;
7860
- this.profile = undefined;
7861
- this.config = undefined;
7888
+ this.sessionDetails = undefined;
7862
7889
  }
7863
7890
  /**
7891
+ * Returns the list of available logins.
7892
+ * @returns The list of available logins.
7864
7893
  * @category Authentication
7865
7894
  */
7866
7895
  getLogins() {
@@ -7873,31 +7902,73 @@
7873
7902
  }
7874
7903
  async refreshProfile() {
7875
7904
  this.profilePromise = new Promise((resolve, reject) => {
7905
+ if (this.basicAuth) {
7906
+ return;
7907
+ }
7876
7908
  this.get('auth/me')
7877
7909
  .then((result) => {
7878
7910
  this.profilePromise = undefined;
7879
- this.profile = result.profile;
7880
- this.config = result.config;
7911
+ this.sessionDetails = result;
7881
7912
  this.dispatchEvent({ type: 'change' });
7882
- resolve(this.profile);
7913
+ resolve(result.profile);
7883
7914
  })
7884
7915
  .catch(reject);
7885
7916
  });
7886
7917
  return this.profilePromise;
7887
7918
  }
7888
7919
  /**
7920
+ * Returns true if the client is waiting for authentication.
7921
+ * @returns True if the client is waiting for authentication.
7889
7922
  * @category Authentication
7890
7923
  */
7891
7924
  isLoading() {
7892
7925
  return !!this.profilePromise;
7893
7926
  }
7894
7927
  /**
7928
+ * Returns true if the current user is authenticated as a super admin.
7929
+ * @returns True if the current user is authenticated as a super admin.
7930
+ * @category Authentication
7931
+ */
7932
+ isSuperAdmin() {
7933
+ return !!this.sessionDetails?.project?.superAdmin;
7934
+ }
7935
+ /**
7936
+ * Returns true if the current user is authenticated as a project admin.
7937
+ * @returns True if the current user is authenticated as a project admin.
7938
+ * @category Authentication
7939
+ */
7940
+ isProjectAdmin() {
7941
+ return !!this.sessionDetails?.membership?.admin;
7942
+ }
7943
+ /**
7944
+ * Returns the current project if available.
7945
+ * @returns The current project if available.
7946
+ * @category User Profile
7947
+ */
7948
+ getProject() {
7949
+ return this.sessionDetails?.project;
7950
+ }
7951
+ /**
7952
+ * Returns the current project membership if available.
7953
+ * @returns The current project membership if available.
7954
+ * @category User Profile
7955
+ */
7956
+ getProjectMembership() {
7957
+ return this.sessionDetails?.membership;
7958
+ }
7959
+ /**
7960
+ * Returns the current user profile resource if available.
7961
+ * This method does not wait for loading promises.
7962
+ * @returns The current user profile resource if available.
7895
7963
  * @category User Profile
7896
7964
  */
7897
7965
  getProfile() {
7898
- return this.profile;
7966
+ return this.sessionDetails?.profile;
7899
7967
  }
7900
7968
  /**
7969
+ * Returns the current user profile resource if available.
7970
+ * This method waits for loading promises.
7971
+ * @returns The current user profile resource if available.
7901
7972
  * @category User Profile
7902
7973
  */
7903
7974
  async getProfileAsync() {
@@ -7907,16 +7978,26 @@
7907
7978
  return this.getProfile();
7908
7979
  }
7909
7980
  /**
7981
+ * Returns the current user configuration if available.
7982
+ * @returns The current user configuration if available.
7910
7983
  * @category User Profile
7911
7984
  */
7912
7985
  getUserConfiguration() {
7913
- return this.config;
7986
+ return this.sessionDetails?.config;
7987
+ }
7988
+ /**
7989
+ * Returns the current user access policy if available.
7990
+ * @returns The current user access policy if available.
7991
+ * @category User Profile
7992
+ */
7993
+ getAccessPolicy() {
7994
+ return this.sessionDetails?.accessPolicy;
7914
7995
  }
7915
7996
  /**
7916
7997
  * Downloads the URL as a blob.
7917
- *
7918
7998
  * @category Read
7919
7999
  * @param url The URL to request.
8000
+ * @param options Optional fetch request init options.
7920
8001
  * @returns Promise to the response body as a blob.
7921
8002
  */
7922
8003
  async download(url, options = {}) {
@@ -7930,12 +8011,13 @@
7930
8011
  /**
7931
8012
  * Upload media to the server and create a Media instance for the uploaded content.
7932
8013
  * @param contents The contents of the media file, as a string, Uint8Array, File, or Blob.
7933
- * @param contentType The media type of the content
7934
- * @param filename The name of the file to be uploaded, or undefined if not applicable
7935
- * @param additionalFields Additional fields for Media
8014
+ * @param contentType The media type of the content.
8015
+ * @param filename The name of the file to be uploaded, or undefined if not applicable.
8016
+ * @param additionalFields Additional fields for Media.
8017
+ * @param options Optional fetch options.
7936
8018
  * @returns Promise that resolves to the created Media
7937
8019
  */
7938
- async uploadMedia(contents, contentType, filename, additionalFields) {
8020
+ async uploadMedia(contents, contentType, filename, additionalFields, options) {
7939
8021
  const binary = await this.createBinary(contents, filename, contentType);
7940
8022
  return this.createResource({
7941
8023
  ...additionalFields,
@@ -7945,11 +8027,10 @@
7945
8027
  url: 'Binary/' + binary.id,
7946
8028
  title: filename,
7947
8029
  },
7948
- });
8030
+ }, options);
7949
8031
  }
7950
8032
  /**
7951
8033
  * Performs Bulk Data Export operation request flow. See The FHIR "Bulk Data Export" for full details: https://build.fhir.org/ig/HL7/bulk-data/export.html#bulk-data-export
7952
- *
7953
8034
  * @param exportLevel Optional export level. Defaults to system level export. 'Group/:id' - Group of Patients, 'Patient' - All Patients.
7954
8035
  * @param resourceTypes A string of comma-delimited FHIR resource types.
7955
8036
  * @param since Resources will be included in the response if their state has changed after the supplied time (e.g. if Resource.meta.lastUpdated is later than the supplied _since time).
@@ -7965,7 +8046,6 @@
7965
8046
  if (since) {
7966
8047
  url.searchParams.set('_since', since);
7967
8048
  }
7968
- options.method = exportLevel ? 'GET' : 'POST';
7969
8049
  this.addFetchOptionsDefaults(options);
7970
8050
  const headers = options.headers;
7971
8051
  headers['Prefer'] = 'respond-async';
@@ -8029,10 +8109,10 @@
8029
8109
  }
8030
8110
  /**
8031
8111
  * Makes an HTTP request.
8032
- * @param {string} method
8033
- * @param {string} url
8034
- * @param {string=} contentType
8035
- * @param {Object=} body
8112
+ * @param method The HTTP method (GET, POST, etc).
8113
+ * @param url The target URL.
8114
+ * @param options Optional fetch request init options.
8115
+ * @returns The JSON content body if available.
8036
8116
  */
8037
8117
  async request(method, url, options = {}) {
8038
8118
  if (this.refreshPromise) {
@@ -8097,9 +8177,7 @@
8097
8177
  let resultResponse;
8098
8178
  const retryDelay = 200;
8099
8179
  while (checkStatus) {
8100
- const fetchOptions = {
8101
- method: 'GET',
8102
- };
8180
+ const fetchOptions = {};
8103
8181
  this.addFetchOptionsDefaults(fetchOptions);
8104
8182
  const statusResponse = await this.fetchWithRetry(statusUrl, fetchOptions);
8105
8183
  if (statusResponse.status !== 202) {
@@ -8175,7 +8253,7 @@
8175
8253
  if (this.accessToken) {
8176
8254
  headers['Authorization'] = 'Bearer ' + this.accessToken;
8177
8255
  }
8178
- if (this.basicAuth) {
8256
+ else if (this.basicAuth) {
8179
8257
  headers['Authorization'] = 'Basic ' + this.basicAuth;
8180
8258
  }
8181
8259
  if (!options.cache) {
@@ -8219,8 +8297,8 @@
8219
8297
  * Otherwise, calls unauthenticated callbacks and rejects.
8220
8298
  * @param method The HTTP method of the original request.
8221
8299
  * @param url The URL of the original request.
8222
- * @param contentType The content type of the original request.
8223
- * @param body The body of the original request.
8300
+ * @param options Optional fetch request init options.
8301
+ * @returns The result of the retry.
8224
8302
  */
8225
8303
  handleUnauthenticated(method, url, options) {
8226
8304
  if (this.refresh()) {
@@ -8236,6 +8314,7 @@
8236
8314
  * Starts a new PKCE flow.
8237
8315
  * These PKCE values are stateful, and must survive redirects and page refreshes.
8238
8316
  * @category Authentication
8317
+ * @returns The PKCE code challenge details.
8239
8318
  */
8240
8319
  async startPkce() {
8241
8320
  const pkceState = getRandomString();
@@ -8250,7 +8329,8 @@
8250
8329
  /**
8251
8330
  * Redirects the user to the login screen for authorization.
8252
8331
  * Clears all auth state including local storage and session storage.
8253
- * See: https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
8332
+ * @param loginParams The authorization login parameters.
8333
+ * @see https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
8254
8334
  */
8255
8335
  async requestAuthorization(loginParams) {
8256
8336
  const loginRequest = await this.ensureCodeChallenge(loginParams || {});
@@ -8269,6 +8349,7 @@
8269
8349
  * See: https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest
8270
8350
  * @param code The authorization code received by URL parameter.
8271
8351
  * @param loginParams Optional login parameters.
8352
+ * @returns The user profile resource.
8272
8353
  * @category Authentication
8273
8354
  */
8274
8355
  processCode(code, loginParams) {
@@ -8287,7 +8368,8 @@
8287
8368
  }
8288
8369
  /**
8289
8370
  * Tries to refresh the auth tokens.
8290
- * See: https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens
8371
+ * @returns The refresh promise if available; otherwise undefined.
8372
+ * @see https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens
8291
8373
  */
8292
8374
  refresh() {
8293
8375
  if (this.refreshPromise) {
@@ -8340,7 +8422,6 @@
8340
8422
  * // Example Search
8341
8423
  * await medplum.searchResources('Patient')
8342
8424
  * ```
8343
- *
8344
8425
  * @category Authentication
8345
8426
  * @param clientId The client ID.
8346
8427
  * @param clientSecret The client secret.
@@ -8354,7 +8435,7 @@
8354
8435
  * Invite a user to a project.
8355
8436
  * @param projectId The project ID.
8356
8437
  * @param body The InviteBody.
8357
- * @returns Promise that returns an invite result or an operation outcome.
8438
+ * @returns Promise that returns a project membership or an operation outcome.
8358
8439
  */
8359
8440
  async invite(projectId, body) {
8360
8441
  return this.post('admin/projects/' + projectId + '/invite', body);
@@ -8363,17 +8444,29 @@
8363
8444
  * Makes a POST request to the tokens endpoint.
8364
8445
  * See: https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
8365
8446
  * @param formBody Token parameters in URL encoded format.
8447
+ * @returns The user profile resource.
8366
8448
  */
8367
8449
  async fetchTokens(formBody) {
8368
- const response = await this.fetch(this.tokenUrl, {
8450
+ const options = {
8369
8451
  method: 'POST',
8370
8452
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
8371
8453
  body: formBody,
8372
8454
  credentials: 'include',
8373
- });
8455
+ };
8456
+ const headers = options.headers;
8457
+ if (this.basicAuth) {
8458
+ headers['Authorization'] = `Basic ${this.basicAuth}`;
8459
+ }
8460
+ const response = await this.fetch(this.tokenUrl, options);
8374
8461
  if (!response.ok) {
8375
8462
  this.clearActiveLogin();
8376
- throw new Error('Failed to fetch tokens');
8463
+ try {
8464
+ const error = await response.json();
8465
+ throw new OperationOutcomeError(badRequest(error.error_description));
8466
+ }
8467
+ catch (err) {
8468
+ throw new OperationOutcomeError(badRequest('Failed to fetch tokens'), err);
8469
+ }
8377
8470
  }
8378
8471
  const tokens = await response.json();
8379
8472
  await this.verifyTokens(tokens);
@@ -8383,7 +8476,8 @@
8383
8476
  * Verifies the tokens received from the auth server.
8384
8477
  * Validates the JWT against the JWKS.
8385
8478
  * See: https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
8386
- * @param tokens
8479
+ * @param tokens The token response.
8480
+ * @returns Promise to complete.
8387
8481
  */
8388
8482
  async verifyTokens(tokens) {
8389
8483
  const token = tokens.access_token;
@@ -8394,7 +8488,14 @@
8394
8488
  throw new Error('Token expired');
8395
8489
  }
8396
8490
  // Verify app_client_id
8397
- if (this.clientId && tokenPayload.client_id !== this.clientId) {
8491
+ // external tokenPayload
8492
+ if (tokenPayload.cid) {
8493
+ if (tokenPayload.cid !== this.clientId) {
8494
+ this.clearActiveLogin();
8495
+ throw new Error('Token was not issued for this audience');
8496
+ }
8497
+ }
8498
+ else if (this.clientId && tokenPayload.client_id !== this.clientId) {
8398
8499
  this.clearActiveLogin();
8399
8500
  throw new Error('Token was not issued for this audience');
8400
8501
  }
@@ -8448,6 +8549,7 @@
8448
8549
  }
8449
8550
  /**
8450
8551
  * Returns the base URL for the current page.
8552
+ * @returns The window origin string.
8451
8553
  * @category HTTP
8452
8554
  */
8453
8555
  function getWindowOrigin() {
@@ -8610,7 +8712,7 @@
8610
8712
  this.keywords = keywords;
8611
8713
  this.operators = operators;
8612
8714
  this.dateTimeLiterals = !!options?.dateTimeLiterals;
8613
- this.symbolRegex = options?.symbolRegex ?? /[$\w]/;
8715
+ this.symbolRegex = options?.symbolRegex ?? /[$\w%]/;
8614
8716
  }
8615
8717
  tokenize() {
8616
8718
  while (this.pos.index < this.str.length) {
@@ -8659,7 +8761,7 @@
8659
8761
  if (c.match(/\w/)) {
8660
8762
  return this.consumeSymbol();
8661
8763
  }
8662
- if (c === '$' && next.match(/\w/)) {
8764
+ if ((c === '$' || c === '%') && next.match(/\w/)) {
8663
8765
  return this.consumeSymbol();
8664
8766
  }
8665
8767
  return this.consumeOperator();
@@ -9209,6 +9311,7 @@
9209
9311
 
9210
9312
  /**
9211
9313
  * Temporary placholder for unimplemented methods.
9314
+ * @returns Empty array.
9212
9315
  */
9213
9316
  const stub = () => [];
9214
9317
  const functions = {
@@ -9220,11 +9323,11 @@
9220
9323
  * Returns true if the input collection is empty ({ }) and false otherwise.
9221
9324
  *
9222
9325
  * See: https://hl7.org/fhirpath/#empty-boolean
9223
- *
9326
+ * @param _context The evaluation context.
9224
9327
  * @param input The input collection.
9225
9328
  * @returns True if the input collection is empty ({ }) and false otherwise.
9226
9329
  */
9227
- empty: (input) => {
9330
+ empty: (_context, input) => {
9228
9331
  return booleanToTypedValue(input.length === 0);
9229
9332
  },
9230
9333
  /**
@@ -9237,14 +9340,14 @@
9237
9340
  * for where(criteria).exists().
9238
9341
  *
9239
9342
  * See: https://hl7.org/fhirpath/#existscriteria-expression-boolean
9240
- *
9241
- * @param input
9242
- * @param criteria
9343
+ * @param context The evaluation context.
9344
+ * @param input The input collection.
9345
+ * @param criteria The evaluation criteria.
9243
9346
  * @returns True if the collection has unknown elements, and false otherwise.
9244
9347
  */
9245
- exists: (input, criteria) => {
9348
+ exists: (context, input, criteria) => {
9246
9349
  if (criteria) {
9247
- return booleanToTypedValue(input.filter((e) => toJsBoolean(criteria.eval([e]))).length > 0);
9350
+ return booleanToTypedValue(input.filter((e) => toJsBoolean(criteria.eval(context, [e]))).length > 0);
9248
9351
  }
9249
9352
  else {
9250
9353
  return booleanToTypedValue(input.length > 0);
@@ -9257,13 +9360,13 @@
9257
9360
  * If the input collection is empty ({ }), the result is true.
9258
9361
  *
9259
9362
  * See: https://hl7.org/fhirpath/#allcriteria-expression-boolean
9260
- *
9363
+ * @param context The evaluation context.
9261
9364
  * @param input The input collection.
9262
9365
  * @param criteria The evaluation criteria.
9263
9366
  * @returns True if for every element in the input collection, criteria evaluates to true.
9264
9367
  */
9265
- all: (input, criteria) => {
9266
- return booleanToTypedValue(input.every((e) => toJsBoolean(criteria.eval([e]))));
9368
+ all: (context, input, criteria) => {
9369
+ return booleanToTypedValue(input.every((e) => toJsBoolean(criteria.eval(context, [e]))));
9267
9370
  },
9268
9371
  /**
9269
9372
  * Takes a collection of Boolean values and returns true if all the items are true.
@@ -9271,12 +9374,11 @@
9271
9374
  * If the input is empty ({ }), the result is true.
9272
9375
  *
9273
9376
  * See: https://hl7.org/fhirpath/#alltrue-boolean
9274
- *
9377
+ * @param _context The evaluation context.
9275
9378
  * @param input The input collection.
9276
- * @param criteria The evaluation criteria.
9277
9379
  * @returns True if all the items are true.
9278
9380
  */
9279
- allTrue: (input) => {
9381
+ allTrue: (_context, input) => {
9280
9382
  for (const value of input) {
9281
9383
  if (!value.value) {
9282
9384
  return booleanToTypedValue(false);
@@ -9289,12 +9391,11 @@
9289
9391
  * If all the items are false, or if the input is empty ({ }), the result is false.
9290
9392
  *
9291
9393
  * See: https://hl7.org/fhirpath/#anytrue-boolean
9292
- *
9394
+ * @param _context The evaluation context.
9293
9395
  * @param input The input collection.
9294
- * @param criteria The evaluation criteria.
9295
9396
  * @returns True if unknown of the items are true.
9296
9397
  */
9297
- anyTrue: (input) => {
9398
+ anyTrue: (_context, input) => {
9298
9399
  for (const value of input) {
9299
9400
  if (value.value) {
9300
9401
  return booleanToTypedValue(true);
@@ -9308,12 +9409,11 @@
9308
9409
  * If the input is empty ({ }), the result is true.
9309
9410
  *
9310
9411
  * See: https://hl7.org/fhirpath/#allfalse-boolean
9311
- *
9412
+ * @param _context The evaluation context.
9312
9413
  * @param input The input collection.
9313
- * @param criteria The evaluation criteria.
9314
9414
  * @returns True if all the items are false.
9315
9415
  */
9316
- allFalse: (input) => {
9416
+ allFalse: (_context, input) => {
9317
9417
  for (const value of input) {
9318
9418
  if (value.value) {
9319
9419
  return booleanToTypedValue(false);
@@ -9326,12 +9426,11 @@
9326
9426
  * If all the items are true, or if the input is empty ({ }), the result is false.
9327
9427
  *
9328
9428
  * See: https://hl7.org/fhirpath/#anyfalse-boolean
9329
- *
9429
+ * @param _context The evaluation context.
9330
9430
  * @param input The input collection.
9331
- * @param criteria The evaluation criteria.
9332
9431
  * @returns True if for every element in the input collection, criteria evaluates to true.
9333
9432
  */
9334
- anyFalse: (input) => {
9433
+ anyFalse: (_context, input) => {
9335
9434
  for (const value of input) {
9336
9435
  if (!value.value) {
9337
9436
  return booleanToTypedValue(true);
@@ -9368,11 +9467,11 @@
9368
9467
  * Returns 0 when the input collection is empty.
9369
9468
  *
9370
9469
  * See: https://hl7.org/fhirpath/#count-integer
9371
- *
9470
+ * @param _context The evaluation context.
9372
9471
  * @param input The input collection.
9373
9472
  * @returns The integer count of the number of items in the input collection.
9374
9473
  */
9375
- count: (input) => {
9474
+ count: (_context, input) => {
9376
9475
  return [{ type: exports.PropertyType.integer, value: input.length }];
9377
9476
  },
9378
9477
  /**
@@ -9386,11 +9485,11 @@
9386
9485
  * preserved in the result.
9387
9486
  *
9388
9487
  * See: https://hl7.org/fhirpath/#distinct-collection
9389
- *
9488
+ * @param _context The evaluation context.
9390
9489
  * @param input The input collection.
9391
9490
  * @returns The integer count of the number of items in the input collection.
9392
9491
  */
9393
- distinct: (input) => {
9492
+ distinct: (_context, input) => {
9394
9493
  const result = [];
9395
9494
  for (const value of input) {
9396
9495
  if (!result.some((e) => e.value === value.value)) {
@@ -9405,12 +9504,12 @@
9405
9504
  * as defined below.
9406
9505
  *
9407
9506
  * See: https://hl7.org/fhirpath/#isdistinct-boolean
9408
- *
9507
+ * @param context The evaluation context.
9409
9508
  * @param input The input collection.
9410
9509
  * @returns The integer count of the number of items in the input collection.
9411
9510
  */
9412
- isDistinct: (input) => {
9413
- return booleanToTypedValue(input.length === functions.distinct(input).length);
9511
+ isDistinct: (context, input) => {
9512
+ return booleanToTypedValue(input.length === functions.distinct(context, input).length);
9414
9513
  },
9415
9514
  /*
9416
9515
  * 5.2 Filtering and projection
@@ -9428,13 +9527,13 @@
9428
9527
  * consistent with singleton evaluation of collections behavior.
9429
9528
  *
9430
9529
  * See: https://hl7.org/fhirpath/#wherecriteria-expression-collection
9431
- *
9530
+ * @param context The evaluation context.
9432
9531
  * @param input The input collection.
9433
- * @param condition The condition atom.
9532
+ * @param criteria The condition atom.
9434
9533
  * @returns A collection containing only those elements in the input collection for which the stated criteria expression evaluates to true.
9435
9534
  */
9436
- where: (input, criteria) => {
9437
- return input.filter((e) => toJsBoolean(criteria.eval([e])));
9535
+ where: (context, input, criteria) => {
9536
+ return input.filter((e) => toJsBoolean(criteria.eval(context, [e])));
9438
9537
  },
9439
9538
  /**
9440
9539
  * Evaluates the projection expression for each item in the input collection.
@@ -9446,9 +9545,13 @@
9446
9545
  * the input collection is empty ({ }), the result is empty as well.
9447
9546
  *
9448
9547
  * See: http://hl7.org/fhirpath/#selectprojection-expression-collection
9548
+ * @param context The evaluation context.
9549
+ * @param input The input collection.
9550
+ * @param criteria The condition atom.
9551
+ * @returns A collection containing only those elements in the input collection for which the stated criteria expression evaluates to true.
9449
9552
  */
9450
- select: (input, criteria) => {
9451
- return input.map((e) => criteria.eval([e])).flat();
9553
+ select: (context, input, criteria) => {
9554
+ return input.map((e) => criteria.eval(context, [e])).flat();
9452
9555
  },
9453
9556
  /**
9454
9557
  * A version of select that will repeat the projection and add it to the output
@@ -9465,8 +9568,12 @@
9465
9568
  * must resolve to the name of a type in a model
9466
9569
  *
9467
9570
  * See: http://hl7.org/fhirpath/#oftypetype-type-specifier-collection
9571
+ * @param _context The evaluation context.
9572
+ * @param input The input collection.
9573
+ * @param criteria The condition atom.
9574
+ * @returns A collection containing only those elements in the input collection that are of the given type or a subclass thereof.
9468
9575
  */
9469
- ofType: (input, criteria) => {
9576
+ ofType: (_context, input, criteria) => {
9470
9577
  return input.filter((e) => e.type === criteria.name);
9471
9578
  },
9472
9579
  /*
@@ -9480,11 +9587,11 @@
9480
9587
  * about cardinality is violated at run-time.
9481
9588
  *
9482
9589
  * See: https://hl7.org/fhirpath/#single-collection
9483
- *
9590
+ * @param _context The evaluation context.
9484
9591
  * @param input The input collection.
9485
9592
  * @returns The single item in the input if there is just one item.
9486
9593
  */
9487
- single: (input) => {
9594
+ single: (_context, input) => {
9488
9595
  if (input.length > 1) {
9489
9596
  throw new Error('Expected input length one for single()');
9490
9597
  }
@@ -9495,11 +9602,11 @@
9495
9602
  * This function is equivalent to item[0], so it will return an empty collection if the input collection has no items.
9496
9603
  *
9497
9604
  * See: https://hl7.org/fhirpath/#first-collection
9498
- *
9605
+ * @param context The evaluation context.
9499
9606
  * @param input The input collection.
9500
9607
  * @returns A collection containing only the first item in the input collection.
9501
9608
  */
9502
- first: (input) => {
9609
+ first: (context, input) => {
9503
9610
  return input.length === 0 ? [] : input.slice(0, 1);
9504
9611
  },
9505
9612
  /**
@@ -9507,11 +9614,11 @@
9507
9614
  * Will return an empty collection if the input collection has no items.
9508
9615
  *
9509
9616
  * See: https://hl7.org/fhirpath/#last-collection
9510
- *
9617
+ * @param context The evaluation context.
9511
9618
  * @param input The input collection.
9512
9619
  * @returns A collection containing only the last item in the input collection.
9513
9620
  */
9514
- last: (input) => {
9621
+ last: (context, input) => {
9515
9622
  return input.length === 0 ? [] : input.slice(input.length - 1, input.length);
9516
9623
  },
9517
9624
  /**
@@ -9519,11 +9626,11 @@
9519
9626
  * Will return an empty collection if the input collection has no items, or only one item.
9520
9627
  *
9521
9628
  * See: https://hl7.org/fhirpath/#tail-collection
9522
- *
9629
+ * @param context The evaluation context.
9523
9630
  * @param input The input collection.
9524
9631
  * @returns A collection containing all but the first item in the input collection.
9525
9632
  */
9526
- tail: (input) => {
9633
+ tail: (context, input) => {
9527
9634
  return input.length === 0 ? [] : input.slice(1, input.length);
9528
9635
  },
9529
9636
  /**
@@ -9533,12 +9640,13 @@
9533
9640
  * If num is less than or equal to zero, the input collection is simply returned.
9534
9641
  *
9535
9642
  * See: https://hl7.org/fhirpath/#skipnum-integer-collection
9536
- *
9643
+ * @param context The evaluation context.
9537
9644
  * @param input The input collection.
9645
+ * @param num The atom representing the number of elements to skip.
9538
9646
  * @returns A collection containing all but the first item in the input collection.
9539
9647
  */
9540
- skip: (input, num) => {
9541
- const numValue = num.eval(input)[0]?.value;
9648
+ skip: (context, input, num) => {
9649
+ const numValue = num.eval(context, input)[0]?.value;
9542
9650
  if (typeof numValue !== 'number') {
9543
9651
  throw new Error('Expected a number for skip(num)');
9544
9652
  }
@@ -9557,12 +9665,13 @@
9557
9665
  * take returns an empty collection.
9558
9666
  *
9559
9667
  * See: https://hl7.org/fhirpath/#takenum-integer-collection
9560
- *
9668
+ * @param context The evaluation context.
9561
9669
  * @param input The input collection.
9670
+ * @param num The atom representing the number of elements to take.
9562
9671
  * @returns A collection containing the first num items in the input collection.
9563
9672
  */
9564
- take: (input, num) => {
9565
- const numValue = num.eval(input)[0]?.value;
9673
+ take: (context, input, num) => {
9674
+ const numValue = num.eval(context, input)[0]?.value;
9566
9675
  if (typeof numValue !== 'number') {
9567
9676
  throw new Error('Expected a number for take(num)');
9568
9677
  }
@@ -9580,12 +9689,16 @@
9580
9689
  * Order of items is not guaranteed to be preserved in the result of this function.
9581
9690
  *
9582
9691
  * See: http://hl7.org/fhirpath/#intersectother-collection-collection
9692
+ * @param context The evaluation context.
9693
+ * @param input The input collection.
9694
+ * @param other The atom representing the collection of elements to intersect.
9695
+ * @returns A collection containing the elements that are in both collections.
9583
9696
  */
9584
- intersect: (input, other) => {
9697
+ intersect: (context, input, other) => {
9585
9698
  if (!other) {
9586
9699
  return input;
9587
9700
  }
9588
- const otherArray = other.eval(input);
9701
+ const otherArray = other.eval(context, input);
9589
9702
  const result = [];
9590
9703
  for (const value of input) {
9591
9704
  if (!result.some((e) => e.value === value.value) && otherArray.some((e) => e.value === value.value)) {
@@ -9601,12 +9714,16 @@
9601
9714
  * e.g. (1 | 2 | 3).exclude(2) returns (1 | 3).
9602
9715
  *
9603
9716
  * See: http://hl7.org/fhirpath/#excludeother-collection-collection
9717
+ * @param context The evaluation context.
9718
+ * @param input The input collection.
9719
+ * @param other The atom representing the collection of elements to exclude.
9720
+ * @returns A collection containing the elements that are in the input collection but not the other collection.
9604
9721
  */
9605
- exclude: (input, other) => {
9722
+ exclude: (context, input, other) => {
9606
9723
  if (!other) {
9607
9724
  return input;
9608
9725
  }
9609
- const otherArray = other.eval(input);
9726
+ const otherArray = other.eval(context, input);
9610
9727
  const result = [];
9611
9728
  for (const value of input) {
9612
9729
  if (!otherArray.some((e) => e.value === value.value)) {
@@ -9628,12 +9745,16 @@
9628
9745
  * In other words, this function returns the distinct list of elements from both inputs.
9629
9746
  *
9630
9747
  * See: http://hl7.org/fhirpath/#unionother-collection
9748
+ * @param context The evaluation context.
9749
+ * @param input The input collection.
9750
+ * @param other The atom representing the collection of elements to merge.
9751
+ * @returns A collection containing the elements that represent the union of both collections.
9631
9752
  */
9632
- union: (input, other) => {
9753
+ union: (context, input, other) => {
9633
9754
  if (!other) {
9634
9755
  return input;
9635
9756
  }
9636
- const otherArray = other.eval(input);
9757
+ const otherArray = other.eval(context, input);
9637
9758
  return removeDuplicates([...input, ...otherArray]);
9638
9759
  },
9639
9760
  /**
@@ -9644,12 +9765,16 @@
9644
9765
  * There is no expectation of order in the resulting collection.
9645
9766
  *
9646
9767
  * See: http://hl7.org/fhirpath/#combineother-collection-collection
9768
+ * @param context The evaluation context.
9769
+ * @param input The input collection.
9770
+ * @param other The atom representing the collection of elements to merge.
9771
+ * @returns A collection containing the elements that represent the combination of both collections including duplicates.
9647
9772
  */
9648
- combine: (input, other) => {
9773
+ combine: (context, input, other) => {
9649
9774
  if (!other) {
9650
9775
  return input;
9651
9776
  }
9652
- const otherArray = other.eval(input);
9777
+ const otherArray = other.eval(context, input);
9653
9778
  return [...input, ...otherArray];
9654
9779
  },
9655
9780
  /*
@@ -9672,23 +9797,23 @@
9672
9797
  * true-result should only be evaluated if the criterion evaluates to true,
9673
9798
  * and otherwise-result should only be evaluated otherwise. For implementations,
9674
9799
  * this means delaying evaluation of the arguments.
9675
- *
9676
- * @param input
9677
- * @param criterion
9678
- * @param trueResult
9679
- * @param otherwiseResult
9680
- * @returns
9800
+ * @param context The evaluation context.
9801
+ * @param input The input collection.
9802
+ * @param criterion The atom representing the conditional.
9803
+ * @param trueResult The atom to be used if the conditional evaluates to true.
9804
+ * @param otherwiseResult Optional atom to be used if the conditional evaluates to false.
9805
+ * @returns The result of the iif function.
9681
9806
  */
9682
- iif: (input, criterion, trueResult, otherwiseResult) => {
9683
- const evalResult = criterion.eval(input);
9807
+ iif: (context, input, criterion, trueResult, otherwiseResult) => {
9808
+ const evalResult = criterion.eval(context, input);
9684
9809
  if (evalResult.length > 1 || (evalResult.length === 1 && typeof evalResult[0].value !== 'boolean')) {
9685
9810
  throw new Error('Expected criterion to evaluate to a Boolean');
9686
9811
  }
9687
9812
  if (toJsBoolean(evalResult)) {
9688
- return trueResult.eval(input);
9813
+ return trueResult.eval(context, input);
9689
9814
  }
9690
9815
  if (otherwiseResult) {
9691
- return otherwiseResult.eval(input);
9816
+ return otherwiseResult.eval(context, input);
9692
9817
  }
9693
9818
  return [];
9694
9819
  },
@@ -9704,11 +9829,11 @@
9704
9829
  * If the item is not one the above types, or the item is a String, Integer, or Decimal, but is not equal to one of the possible values convertible to a Boolean, the result is empty.
9705
9830
  *
9706
9831
  * See: https://hl7.org/fhirpath/#toboolean-boolean
9707
- *
9708
- * @param input
9709
- * @returns
9832
+ * @param _context The evaluation context.
9833
+ * @param input The input collection.
9834
+ * @returns The input converted to boolean value.
9710
9835
  */
9711
- toBoolean: (input) => {
9836
+ toBoolean: (_context, input) => {
9712
9837
  if (input.length === 0) {
9713
9838
  return [];
9714
9839
  }
@@ -9748,15 +9873,15 @@
9748
9873
  * If the input collection is empty, the result is empty.
9749
9874
  *
9750
9875
  * See: http://hl7.org/fhirpath/#convertstoboolean-boolean
9751
- *
9752
- * @param input
9753
- * @returns
9876
+ * @param context The evaluation context.
9877
+ * @param input The input collection.
9878
+ * @returns True if the input can be converted to boolean.
9754
9879
  */
9755
- convertsToBoolean: (input) => {
9880
+ convertsToBoolean: (context, input) => {
9756
9881
  if (input.length === 0) {
9757
9882
  return [];
9758
9883
  }
9759
- return booleanToTypedValue(functions.toBoolean(input).length === 1);
9884
+ return booleanToTypedValue(functions.toBoolean(context, input).length === 1);
9760
9885
  },
9761
9886
  /**
9762
9887
  * Returns the integer representation of the input.
@@ -9775,11 +9900,11 @@
9775
9900
  * If the input collection is empty, the result is empty.
9776
9901
  *
9777
9902
  * See: https://hl7.org/fhirpath/#tointeger-integer
9778
- *
9903
+ * @param _context The evaluation context.
9779
9904
  * @param input The input collection.
9780
9905
  * @returns The string representation of the input.
9781
9906
  */
9782
- toInteger: (input) => {
9907
+ toInteger: (_context, input) => {
9783
9908
  if (input.length === 0) {
9784
9909
  return [];
9785
9910
  }
@@ -9809,15 +9934,15 @@
9809
9934
  * If the input collection is empty, the result is empty.
9810
9935
  *
9811
9936
  * See: https://hl7.org/fhirpath/#convertstointeger-boolean
9812
- *
9937
+ * @param context The evaluation context.
9813
9938
  * @param input The input collection.
9814
- * @returns
9939
+ * @returns True if the input can be converted to an integer.
9815
9940
  */
9816
- convertsToInteger: (input) => {
9941
+ convertsToInteger: (context, input) => {
9817
9942
  if (input.length === 0) {
9818
9943
  return [];
9819
9944
  }
9820
- return booleanToTypedValue(functions.toInteger(input).length === 1);
9945
+ return booleanToTypedValue(functions.toInteger(context, input).length === 1);
9821
9946
  },
9822
9947
  /**
9823
9948
  * If the input collection contains a single item, this function will return a single date if:
@@ -9834,8 +9959,11 @@
9834
9959
  * If the input collection is empty, the result is empty.
9835
9960
  *
9836
9961
  * See: https://hl7.org/fhirpath/#todate-date
9962
+ * @param _context The evaluation context.
9963
+ * @param input The input collection.
9964
+ * @returns The value converted to a date if possible; otherwise empty array.
9837
9965
  */
9838
- toDate: (input) => {
9966
+ toDate: (_context, input) => {
9839
9967
  if (input.length === 0) {
9840
9968
  return [];
9841
9969
  }
@@ -9860,35 +9988,38 @@
9860
9988
  * If the input collection is empty, the result is empty.
9861
9989
  *
9862
9990
  * See: https://hl7.org/fhirpath/#convertstodate-boolean
9991
+ * @param context The evaluation context.
9992
+ * @param input The input collection.
9993
+ * @returns True if the item can be converted to a date.
9863
9994
  */
9864
- convertsToDate: (input) => {
9995
+ convertsToDate: (context, input) => {
9865
9996
  if (input.length === 0) {
9866
9997
  return [];
9867
9998
  }
9868
- return booleanToTypedValue(functions.toDate(input).length === 1);
9999
+ return booleanToTypedValue(functions.toDate(context, input).length === 1);
9869
10000
  },
9870
10001
  /**
9871
- * If the input collection contains a single item, this function will return a single datetime if:
9872
- * 1) the item is a DateTime
9873
- * 2) the item is a Date, in which case the result is a DateTime with the year, month, and day of the Date, and the time components empty (not set to zero)
9874
- * 3) the item is a String and is convertible to a DateTime
9875
- *
9876
- * If the item is not one of the above types, the result is empty.
9877
- *
9878
- * If the item is a String, but the string is not convertible to a DateTime (using the format YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm), the result is empty.
9879
- *
9880
- * If the item contains a partial datetime (e.g. '2012-01-01T10:00'), the result is a partial datetime.
9881
- *
9882
- * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
9883
- *
9884
- * If the input collection is empty, the result is empty.
9885
-
9886
- * See: https://hl7.org/fhirpath/#todatetime-datetime
9887
- *
9888
- * @param input
9889
- * @returns
9890
- */
9891
- toDateTime: (input) => {
10002
+ * If the input collection contains a single item, this function will return a single datetime if:
10003
+ * 1) the item is a DateTime
10004
+ * 2) the item is a Date, in which case the result is a DateTime with the year, month, and day of the Date, and the time components empty (not set to zero)
10005
+ * 3) the item is a String and is convertible to a DateTime
10006
+ *
10007
+ * If the item is not one of the above types, the result is empty.
10008
+ *
10009
+ * If the item is a String, but the string is not convertible to a DateTime (using the format YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm), the result is empty.
10010
+ *
10011
+ * If the item contains a partial datetime (e.g. '2012-01-01T10:00'), the result is a partial datetime.
10012
+ *
10013
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10014
+ *
10015
+ * If the input collection is empty, the result is empty.
10016
+ *
10017
+ * See: https://hl7.org/fhirpath/#todatetime-datetime
10018
+ * @param _context The evaluation context.
10019
+ * @param input The input collection.
10020
+ * @returns The value converted to a datetime if possible; otherwise empty array.
10021
+ */
10022
+ toDateTime: (_context, input) => {
9892
10023
  if (input.length === 0) {
9893
10024
  return [];
9894
10025
  }
@@ -9911,15 +10042,15 @@
9911
10042
  * If the input collection is empty, the result is empty.
9912
10043
  *
9913
10044
  * See: https://hl7.org/fhirpath/#convertstodatetime-boolean
9914
- *
9915
- * @param input
9916
- * @returns
10045
+ * @param context The evaluation context.
10046
+ * @param input The input collection.
10047
+ * @returns True if the item can be converted to a dateTime.
9917
10048
  */
9918
- convertsToDateTime: (input) => {
10049
+ convertsToDateTime: (context, input) => {
9919
10050
  if (input.length === 0) {
9920
10051
  return [];
9921
10052
  }
9922
- return booleanToTypedValue(functions.toDateTime(input).length === 1);
10053
+ return booleanToTypedValue(functions.toDateTime(context, input).length === 1);
9923
10054
  },
9924
10055
  /**
9925
10056
  * If the input collection contains a single item, this function will return a single decimal if:
@@ -9935,11 +10066,11 @@
9935
10066
  * If the input collection is empty, the result is empty.
9936
10067
  *
9937
10068
  * See: https://hl7.org/fhirpath/#decimal-conversion-functions
9938
- *
10069
+ * @param _context The evaluation context.
9939
10070
  * @param input The input collection.
9940
- * @returns
10071
+ * @returns The value converted to a decimal if possible; otherwise empty array.
9941
10072
  */
9942
- toDecimal: (input) => {
10073
+ toDecimal: (_context, input) => {
9943
10074
  if (input.length === 0) {
9944
10075
  return [];
9945
10076
  }
@@ -9956,27 +10087,27 @@
9956
10087
  return [];
9957
10088
  },
9958
10089
  /**
9959
- * If the input collection contains a single item, this function will true if:
9960
- * 1) the item is an Integer or Decimal
9961
- * 2) the item is a String and is convertible to a Decimal
9962
- * 3) the item is a Boolean
9963
- *
9964
- * If the item is not one of the above types, or is not convertible to a Decimal (using the regex format (\\+|-)?\d+(\.\d+)?), the result is false.
9965
- *
9966
- * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
9967
- *
9968
- * If the input collection is empty, the result is empty.
9969
-
9970
- * See: https://hl7.org/fhirpath/#convertstodecimal-boolean
9971
- *
9972
- * @param input The input collection.
9973
- * @returns
9974
- */
9975
- convertsToDecimal: (input) => {
10090
+ * If the input collection contains a single item, this function will true if:
10091
+ * 1) the item is an Integer or Decimal
10092
+ * 2) the item is a String and is convertible to a Decimal
10093
+ * 3) the item is a Boolean
10094
+ *
10095
+ * If the item is not one of the above types, or is not convertible to a Decimal (using the regex format (\\+|-)?\d+(\.\d+)?), the result is false.
10096
+ *
10097
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10098
+ *
10099
+ * If the input collection is empty, the result is empty.
10100
+ *
10101
+ * See: https://hl7.org/fhirpath/#convertstodecimal-boolean
10102
+ * @param context The evaluation context.
10103
+ * @param input The input collection.
10104
+ * @returns The value converted to a decimal if possible; otherwise empty array.
10105
+ */
10106
+ convertsToDecimal: (context, input) => {
9976
10107
  if (input.length === 0) {
9977
10108
  return [];
9978
10109
  }
9979
- return booleanToTypedValue(functions.toDecimal(input).length === 1);
10110
+ return booleanToTypedValue(functions.toDecimal(context, input).length === 1);
9980
10111
  },
9981
10112
  /**
9982
10113
  * If the input collection contains a single item, this function will return a single quantity if:
@@ -9988,11 +10119,11 @@
9988
10119
  * If the item is not one of the above types, the result is empty.
9989
10120
  *
9990
10121
  * See: https://hl7.org/fhirpath/#quantity-conversion-functions
9991
- *
10122
+ * @param _context The evaluation context.
9992
10123
  * @param input The input collection.
9993
- * @returns
10124
+ * @returns The value converted to a quantity if possible; otherwise empty array.
9994
10125
  */
9995
- toQuantity: (input) => {
10126
+ toQuantity: (_context, input) => {
9996
10127
  if (input.length === 0) {
9997
10128
  return [];
9998
10129
  }
@@ -10030,15 +10161,15 @@
10030
10161
  * If the unit argument is provided, it must be the string representation of a UCUM code (or a FHIRPath calendar duration keyword), and is used to determine whether the input quantity can be converted to the given unit, according to the unit conversion rules specified by UCUM. If the input quantity can be converted, the result is true, otherwise, the result is false.
10031
10162
  *
10032
10163
  * See: https://hl7.org/fhirpath/#convertstoquantityunit-string-boolean
10033
- *
10164
+ * @param context The evaluation context.
10034
10165
  * @param input The input collection.
10035
- * @returns
10166
+ * @returns True if the item can be converted to a quantity.
10036
10167
  */
10037
- convertsToQuantity: (input) => {
10168
+ convertsToQuantity: (context, input) => {
10038
10169
  if (input.length === 0) {
10039
10170
  return [];
10040
10171
  }
10041
- return booleanToTypedValue(functions.toQuantity(input).length === 1);
10172
+ return booleanToTypedValue(functions.toQuantity(context, input).length === 1);
10042
10173
  },
10043
10174
  /**
10044
10175
  * Returns the string representation of the input.
@@ -10052,11 +10183,11 @@
10052
10183
  * If the item is not one of the above types, the result is false.
10053
10184
  *
10054
10185
  * See: https://hl7.org/fhirpath/#tostring-string
10055
- *
10186
+ * @param _context The evaluation context.
10056
10187
  * @param input The input collection.
10057
10188
  * @returns The string representation of the input.
10058
10189
  */
10059
- toString: (input) => {
10190
+ toString: (_context, input) => {
10060
10191
  if (input.length === 0) {
10061
10192
  return [];
10062
10193
  }
@@ -10085,15 +10216,15 @@
10085
10216
  * If the input collection is empty, the result is empty.
10086
10217
  *
10087
10218
  * See: https://hl7.org/fhirpath/#tostring-string
10088
- *
10219
+ * @param context The evaluation context.
10089
10220
  * @param input The input collection.
10090
- * @returns
10221
+ * @returns True if the item can be converted to a string
10091
10222
  */
10092
- convertsToString: (input) => {
10223
+ convertsToString: (context, input) => {
10093
10224
  if (input.length === 0) {
10094
10225
  return [];
10095
10226
  }
10096
- return booleanToTypedValue(functions.toString(input).length === 1);
10227
+ return booleanToTypedValue(functions.toString(context, input).length === 1);
10097
10228
  },
10098
10229
  /**
10099
10230
  * If the input collection contains a single item, this function will return a single time if:
@@ -10111,11 +10242,11 @@
10111
10242
  * If the input collection is empty, the result is empty.
10112
10243
  *
10113
10244
  * See: https://hl7.org/fhirpath/#totime-time
10114
- *
10115
- * @param input
10116
- * @returns
10245
+ * @param _context The evaluation context.
10246
+ * @param input The input collection.
10247
+ * @returns The value converted to a time if possible; otherwise empty array.
10117
10248
  */
10118
- toTime: (input) => {
10249
+ toTime: (_context, input) => {
10119
10250
  if (input.length === 0) {
10120
10251
  return [];
10121
10252
  }
@@ -10140,15 +10271,15 @@
10140
10271
  * If the input collection is empty, the result is empty.
10141
10272
  *
10142
10273
  * See: https://hl7.org/fhirpath/#convertstotime-boolean
10143
- *
10144
- * @param input
10145
- * @returns
10274
+ * @param context The evaluation context.
10275
+ * @param input The input collection.
10276
+ * @returns True if the item can be converted to a time.
10146
10277
  */
10147
- convertsToTime: (input) => {
10278
+ convertsToTime: (context, input) => {
10148
10279
  if (input.length === 0) {
10149
10280
  return [];
10150
10281
  }
10151
- return booleanToTypedValue(functions.toTime(input).length === 1);
10282
+ return booleanToTypedValue(functions.toTime(context, input).length === 1);
10152
10283
  },
10153
10284
  /*
10154
10285
  * 5.6. String Manipulation.
@@ -10165,12 +10296,13 @@
10165
10296
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10166
10297
  *
10167
10298
  * See: https://hl7.org/fhirpath/#indexofsubstring-string-integer
10168
- *
10299
+ * @param context The evaluation context.
10169
10300
  * @param input The input collection.
10301
+ * @param substringAtom The substring to search for.
10170
10302
  * @returns The index of the substring.
10171
10303
  */
10172
- indexOf: (input, substringAtom) => {
10173
- return applyStringFunc((str, substring) => str.indexOf(substring), input, substringAtom);
10304
+ indexOf: (context, input, substringAtom) => {
10305
+ return applyStringFunc((str, substring) => str.indexOf(substring), context, input, substringAtom);
10174
10306
  },
10175
10307
  /**
10176
10308
  * Returns the part of the string starting at position start (zero-based). If length is given, will return at most length number of characters from the input string.
@@ -10182,98 +10314,172 @@
10182
10314
  * If an empty length is provided, the behavior is the same as if length had not been provided.
10183
10315
  *
10184
10316
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10185
- *
10317
+ * @param context The evaluation context.
10186
10318
  * @param input The input collection.
10187
- * @returns The index of the substring.
10319
+ * @param startAtom The start index atom.
10320
+ * @param lengthAtom Optional length atom.
10321
+ * @returns The substring.
10188
10322
  */
10189
- substring: (input, startAtom, lengthAtom) => {
10323
+ substring: (context, input, startAtom, lengthAtom) => {
10190
10324
  return applyStringFunc((str, start, length) => {
10191
10325
  const startIndex = start;
10192
10326
  const endIndex = length ? startIndex + length : str.length;
10193
10327
  return startIndex < 0 || startIndex >= str.length ? undefined : str.substring(startIndex, endIndex);
10194
- }, input, startAtom, lengthAtom);
10328
+ }, context, input, startAtom, lengthAtom);
10195
10329
  },
10196
10330
  /**
10331
+ * Returns true when the input string starts with the given prefix.
10197
10332
  *
10333
+ * If prefix is the empty string (''), the result is true.
10334
+ *
10335
+ * If the input collection is empty, the result is empty.
10336
+ *
10337
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10338
+ *
10339
+ * See: https://hl7.org/fhirpath/#startswithprefix-string-boolean
10340
+ * @param context The evaluation context.
10198
10341
  * @param input The input collection.
10199
- * @returns The index of the substring.
10342
+ * @param prefixAtom The prefix substring to test.
10343
+ * @returns True if the input string starts with the given prefix string.
10200
10344
  */
10201
- startsWith: (input, prefixAtom) => {
10202
- return applyStringFunc((str, prefix) => str.startsWith(prefix), input, prefixAtom);
10345
+ startsWith: (context, input, prefixAtom) => {
10346
+ return applyStringFunc((str, prefix) => str.startsWith(prefix), context, input, prefixAtom);
10203
10347
  },
10204
10348
  /**
10349
+ * Returns true when the input string ends with the given suffix.
10350
+ *
10351
+ * If suffix is the empty string (''), the result is true.
10352
+ *
10353
+ * If the input collection is empty, the result is empty.
10354
+ *
10355
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10205
10356
  *
10357
+ * See: https://hl7.org/fhirpath/#endswithsuffix-string-boolean
10358
+ * @param context The evaluation context.
10206
10359
  * @param input The input collection.
10207
- * @returns The index of the substring.
10360
+ * @param suffixAtom The suffix substring to test.
10361
+ * @returns True if the input string ends with the given suffix string.
10208
10362
  */
10209
- endsWith: (input, suffixAtom) => {
10210
- return applyStringFunc((str, suffix) => str.endsWith(suffix), input, suffixAtom);
10363
+ endsWith: (context, input, suffixAtom) => {
10364
+ return applyStringFunc((str, suffix) => str.endsWith(suffix), context, input, suffixAtom);
10211
10365
  },
10212
10366
  /**
10367
+ * Returns true when the given substring is a substring of the input string.
10368
+ *
10369
+ * If substring is the empty string (''), the result is true.
10370
+ *
10371
+ * If the input collection is empty, the result is empty.
10213
10372
  *
10373
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10374
+ *
10375
+ * See: https://hl7.org/fhirpath/#containssubstring-string-boolean
10376
+ * @param context The evaluation context.
10214
10377
  * @param input The input collection.
10215
- * @returns The index of the substring.
10378
+ * @param substringAtom The substring to test.
10379
+ * @returns True if the input string contains the given substring.
10216
10380
  */
10217
- contains: (input, substringAtom) => {
10218
- return applyStringFunc((str, substring) => str.includes(substring), input, substringAtom);
10381
+ contains: (context, input, substringAtom) => {
10382
+ return applyStringFunc((str, substring) => str.includes(substring), context, input, substringAtom);
10219
10383
  },
10220
10384
  /**
10385
+ * Returns the input string with all characters converted to upper case.
10386
+ * If the input collection is empty, the result is empty.
10387
+ *
10388
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10221
10389
  *
10390
+ * See: https://hl7.org/fhirpath/#upper-string
10391
+ * @param context The evaluation context.
10222
10392
  * @param input The input collection.
10223
- * @returns The index of the substring.
10393
+ * @returns The string converted to upper case.
10224
10394
  */
10225
- upper: (input) => {
10226
- return applyStringFunc((str) => str.toUpperCase(), input);
10395
+ upper: (context, input) => {
10396
+ return applyStringFunc((str) => str.toUpperCase(), context, input);
10227
10397
  },
10228
10398
  /**
10399
+ * Returns the input string with all characters converted to lower case.
10400
+ *
10401
+ * If the input collection is empty, the result is empty.
10402
+ *
10403
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10229
10404
  *
10405
+ * See: https://hl7.org/fhirpath/#lower-string
10406
+ * @param context The evaluation context.
10230
10407
  * @param input The input collection.
10231
- * @returns The index of the substring.
10408
+ * @returns The string converted to lower case.
10232
10409
  */
10233
- lower: (input) => {
10234
- return applyStringFunc((str) => str.toLowerCase(), input);
10410
+ lower: (context, input) => {
10411
+ return applyStringFunc((str) => str.toLowerCase(), context, input);
10235
10412
  },
10236
10413
  /**
10414
+ * Returns the input string with all instances of pattern replaced with substitution. If the substitution is the empty string (''),
10415
+ * instances of pattern are removed from the result. If pattern is the empty string (''), every character in the input string is
10416
+ * surrounded by the substitution, e.g. 'abc'.replace('','x') becomes 'xaxbxcx'.
10417
+ *
10418
+ * If the input collection, pattern, or substitution are empty, the result is empty ({ }).
10419
+ *
10420
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10237
10421
  *
10422
+ * See: https://hl7.org/fhirpath/#replacepattern-string-substitution-string-string
10423
+ * @param context The evaluation context.
10238
10424
  * @param input The input collection.
10239
- * @returns The index of the substring.
10425
+ * @param patternAtom The pattern to search for.
10426
+ * @param substitionAtom The substition to replace with.
10427
+ * @returns The string with all instances of the search pattern replaced with the substitution string.
10240
10428
  */
10241
- replace: (input, patternAtom, substitionAtom) => {
10242
- return applyStringFunc((str, pattern, substition) => str.replaceAll(pattern, substition), input, patternAtom, substitionAtom);
10429
+ replace: (context, input, patternAtom, substitionAtom) => {
10430
+ return applyStringFunc((str, pattern, substition) => str.replaceAll(pattern, substition), context, input, patternAtom, substitionAtom);
10243
10431
  },
10244
10432
  /**
10433
+ * Returns true when the value matches the given regular expression. Regular expressions should function consistently, regardless of any culture- and locale-specific settings in the environment, should be case-sensitive, use 'single line' mode and allow Unicode characters.
10434
+ *
10435
+ * If the input collection or regex are empty, the result is empty ({ }).
10245
10436
  *
10437
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10438
+ *
10439
+ * See: https://hl7.org/fhirpath/#matchesregex-string-boolean
10440
+ * @param context The evaluation context.
10246
10441
  * @param input The input collection.
10247
- * @returns The index of the substring.
10442
+ * @param regexAtom The regular expression atom.
10443
+ * @returns True if the input string matches the given regular expression.
10248
10444
  */
10249
- matches: (input, regexAtom) => {
10250
- return applyStringFunc((str, regex) => !!str.match(regex), input, regexAtom);
10445
+ matches: (context, input, regexAtom) => {
10446
+ return applyStringFunc((str, regex) => !!str.match(regex), context, input, regexAtom);
10251
10447
  },
10252
10448
  /**
10449
+ * Matches the input using the regular expression in regex and replaces each match with the substitution string. The substitution may refer to identified match groups in the regular expression.
10253
10450
  *
10451
+ * If the input collection, regex, or substitution are empty, the result is empty ({ }).
10452
+ *
10453
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10454
+ *
10455
+ * See: https://hl7.org/fhirpath/#replacematchesregex-string-substitution-string-string
10456
+ * @param context The evaluation context.
10254
10457
  * @param input The input collection.
10255
- * @returns The index of the substring.
10458
+ * @param regexAtom The regular expression atom.
10459
+ * @param substitionAtom The substition to replace with.
10460
+ * @returns The string with all instances of the search pattern replaced with the substitution string.
10256
10461
  */
10257
- replaceMatches: (input, regexAtom, substitionAtom) => {
10258
- return applyStringFunc((str, pattern, substition) => str.replaceAll(pattern, substition), input, regexAtom, substitionAtom);
10462
+ replaceMatches: (context, input, regexAtom, substitionAtom) => {
10463
+ return applyStringFunc((str, pattern, substition) => str.replaceAll(pattern, substition), context, input, regexAtom, substitionAtom);
10259
10464
  },
10260
10465
  /**
10261
- *
10466
+ * @param context The evaluation context.
10262
10467
  * @param input The input collection.
10263
10468
  * @returns The index of the substring.
10264
10469
  */
10265
- length: (input) => {
10266
- return applyStringFunc((str) => str.length, input);
10470
+ length: (context, input) => {
10471
+ return applyStringFunc((str) => str.length, context, input);
10267
10472
  },
10268
10473
  /**
10269
10474
  * Returns the list of characters in the input string. If the input collection is empty ({ }), the result is empty.
10270
10475
  *
10271
10476
  * See: https://hl7.org/fhirpath/#tochars-collection
10272
- *
10477
+ * @param context The evaluation context.
10273
10478
  * @param input The input collection.
10479
+ * @returns Array of characters.
10274
10480
  */
10275
- toChars: (input) => {
10276
- return applyStringFunc((str) => (str ? str.split('') : undefined), input);
10481
+ toChars: (context, input) => {
10482
+ return applyStringFunc((str) => (str ? str.split('') : undefined), context, input);
10277
10483
  },
10278
10484
  /*
10279
10485
  * 5.7. Math
@@ -10286,12 +10492,12 @@
10286
10492
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10287
10493
  *
10288
10494
  * See: https://hl7.org/fhirpath/#abs-integer-decimal-quantity
10289
- *
10495
+ * @param context The evaluation context.
10290
10496
  * @param input The input collection.
10291
10497
  * @returns A collection containing the result.
10292
10498
  */
10293
- abs: (input) => {
10294
- return applyMathFunc(Math.abs, input);
10499
+ abs: (context, input) => {
10500
+ return applyMathFunc(Math.abs, context, input);
10295
10501
  },
10296
10502
  /**
10297
10503
  * Returns the first integer greater than or equal to the input.
@@ -10301,12 +10507,12 @@
10301
10507
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10302
10508
  *
10303
10509
  * See: https://hl7.org/fhirpath/#ceiling-integer
10304
- *
10510
+ * @param context The evaluation context.
10305
10511
  * @param input The input collection.
10306
10512
  * @returns A collection containing the result.
10307
10513
  */
10308
- ceiling: (input) => {
10309
- return applyMathFunc(Math.ceil, input);
10514
+ ceiling: (context, input) => {
10515
+ return applyMathFunc(Math.ceil, context, input);
10310
10516
  },
10311
10517
  /**
10312
10518
  * Returns e raised to the power of the input.
@@ -10318,12 +10524,12 @@
10318
10524
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10319
10525
  *
10320
10526
  * See: https://hl7.org/fhirpath/#exp-decimal
10321
- *
10527
+ * @param context The evaluation context.
10322
10528
  * @param input The input collection.
10323
10529
  * @returns A collection containing the result.
10324
10530
  */
10325
- exp: (input) => {
10326
- return applyMathFunc(Math.exp, input);
10531
+ exp: (context, input) => {
10532
+ return applyMathFunc(Math.exp, context, input);
10327
10533
  },
10328
10534
  /**
10329
10535
  * Returns the first integer less than or equal to the input.
@@ -10333,12 +10539,12 @@
10333
10539
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10334
10540
  *
10335
10541
  * See: https://hl7.org/fhirpath/#floor-integer
10336
- *
10542
+ * @param context The evaluation context.
10337
10543
  * @param input The input collection.
10338
10544
  * @returns A collection containing the result.
10339
10545
  */
10340
- floor: (input) => {
10341
- return applyMathFunc(Math.floor, input);
10546
+ floor: (context, input) => {
10547
+ return applyMathFunc(Math.floor, context, input);
10342
10548
  },
10343
10549
  /**
10344
10550
  * Returns the natural logarithm of the input (i.e. the logarithm base e).
@@ -10350,12 +10556,12 @@
10350
10556
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10351
10557
  *
10352
10558
  * See: https://hl7.org/fhirpath/#ln-decimal
10353
- *
10559
+ * @param context The evaluation context.
10354
10560
  * @param input The input collection.
10355
10561
  * @returns A collection containing the result.
10356
10562
  */
10357
- ln: (input) => {
10358
- return applyMathFunc(Math.log, input);
10563
+ ln: (context, input) => {
10564
+ return applyMathFunc(Math.log, context, input);
10359
10565
  },
10360
10566
  /**
10361
10567
  * Returns the logarithm base base of the input number.
@@ -10369,12 +10575,13 @@
10369
10575
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10370
10576
  *
10371
10577
  * See: https://hl7.org/fhirpath/#logbase-decimal-decimal
10372
- *
10578
+ * @param context The evaluation context.
10373
10579
  * @param input The input collection.
10580
+ * @param baseAtom The logarithm base.
10374
10581
  * @returns A collection containing the result.
10375
10582
  */
10376
- log: (input, baseAtom) => {
10377
- return applyMathFunc((value, base) => Math.log(value) / Math.log(base), input, baseAtom);
10583
+ log: (context, input, baseAtom) => {
10584
+ return applyMathFunc((value, base) => Math.log(value) / Math.log(base), context, input, baseAtom);
10378
10585
  },
10379
10586
  /**
10380
10587
  * Raises a number to the exponent power. If this function is used with Integers, the result is an Integer. If the function is used with Decimals, the result is a Decimal. If the function is used with a mixture of Integer and Decimal, the Integer is implicitly converted to a Decimal and the result is a Decimal.
@@ -10386,12 +10593,13 @@
10386
10593
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10387
10594
  *
10388
10595
  * See: https://hl7.org/fhirpath/#powerexponent-integer-decimal-integer-decimal
10389
- *
10596
+ * @param context The evaluation context.
10390
10597
  * @param input The input collection.
10598
+ * @param expAtom The exponent power.
10391
10599
  * @returns A collection containing the result.
10392
10600
  */
10393
- power: (input, expAtom) => {
10394
- return applyMathFunc(Math.pow, input, expAtom);
10601
+ power: (context, input, expAtom) => {
10602
+ return applyMathFunc(Math.pow, context, input, expAtom);
10395
10603
  },
10396
10604
  /**
10397
10605
  * Rounds the decimal to the nearest whole number using a traditional round (i.e. 0.5 or higher will round to 1). If specified, the precision argument determines the decimal place at which the rounding will occur. If not specified, the rounding will default to 0 decimal places.
@@ -10405,12 +10613,12 @@
10405
10613
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10406
10614
  *
10407
10615
  * See: https://hl7.org/fhirpath/#roundprecision-integer-decimal
10408
- *
10616
+ * @param context The evaluation context.
10409
10617
  * @param input The input collection.
10410
10618
  * @returns A collection containing the result.
10411
10619
  */
10412
- round: (input) => {
10413
- return applyMathFunc(Math.round, input);
10620
+ round: (context, input) => {
10621
+ return applyMathFunc(Math.round, context, input);
10414
10622
  },
10415
10623
  /**
10416
10624
  * Returns the square root of the input number as a Decimal.
@@ -10424,12 +10632,12 @@
10424
10632
  * Note that this function is equivalent to raising a number of the power of 0.5 using the power() function.
10425
10633
  *
10426
10634
  * See: https://hl7.org/fhirpath/#sqrt-decimal
10427
- *
10635
+ * @param context The evaluation context.
10428
10636
  * @param input The input collection.
10429
10637
  * @returns A collection containing the result.
10430
10638
  */
10431
- sqrt: (input) => {
10432
- return applyMathFunc(Math.sqrt, input);
10639
+ sqrt: (context, input) => {
10640
+ return applyMathFunc(Math.sqrt, context, input);
10433
10641
  },
10434
10642
  /**
10435
10643
  * Returns the integer portion of the input.
@@ -10439,12 +10647,12 @@
10439
10647
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
10440
10648
  *
10441
10649
  * See: https://hl7.org/fhirpath/#truncate-integer
10442
- *
10650
+ * @param context The evaluation context.
10443
10651
  * @param input The input collection.
10444
10652
  * @returns A collection containing the result.
10445
10653
  */
10446
- truncate: (input) => {
10447
- return applyMathFunc((x) => x | 0, input);
10654
+ truncate: (context, input) => {
10655
+ return applyMathFunc((x) => x | 0, context, input);
10448
10656
  },
10449
10657
  /*
10450
10658
  * 5.8. Tree navigation
@@ -10465,11 +10673,12 @@
10465
10673
  * function unchanged.
10466
10674
  *
10467
10675
  * See: https://hl7.org/fhirpath/#tracename-string-projection-expression-collection
10468
- *
10676
+ * @param context The evaluation context.
10469
10677
  * @param input The input collection.
10470
10678
  * @param nameAtom The log name.
10679
+ * @returns The input collection.
10471
10680
  */
10472
- trace: (input, nameAtom) => {
10681
+ trace: (context, input, nameAtom) => {
10473
10682
  console.log('trace', input, nameAtom);
10474
10683
  return input;
10475
10684
  },
@@ -10477,6 +10686,7 @@
10477
10686
  * Returns the current date and time, including timezone offset.
10478
10687
  *
10479
10688
  * See: https://hl7.org/fhirpath/#now-datetime
10689
+ * @returns The current dateTime.
10480
10690
  */
10481
10691
  now: () => {
10482
10692
  return [{ type: exports.PropertyType.dateTime, value: new Date().toISOString() }];
@@ -10485,6 +10695,7 @@
10485
10695
  * Returns the current time.
10486
10696
  *
10487
10697
  * See: https://hl7.org/fhirpath/#timeofday-time
10698
+ * @returns The current time string.
10488
10699
  */
10489
10700
  timeOfDay: () => {
10490
10701
  return [{ type: exports.PropertyType.time, value: new Date().toISOString().substring(11) }];
@@ -10493,6 +10704,7 @@
10493
10704
  * Returns the current date.
10494
10705
  *
10495
10706
  * See: https://hl7.org/fhirpath/#today-date
10707
+ * @returns The current date string.
10496
10708
  */
10497
10709
  today: () => {
10498
10710
  return [{ type: exports.PropertyType.date, value: new Date().toISOString().substring(0, 10) }];
@@ -10504,17 +10716,23 @@
10504
10716
  *
10505
10717
  * IBM FHIR issue: https://github.com/IBM/FHIR/issues/1014
10506
10718
  * IBM FHIR PR: https://github.com/IBM/FHIR/pull/1023
10719
+ * @param context The evaluation context.
10720
+ * @param input The input collection.
10721
+ * @param startAtom The start date/time.
10722
+ * @param endAtom The end date/time.
10723
+ * @param unitsAtom Which units to return ("years", "months", or "days").
10724
+ * @returns The Quantity of time between the two dates.
10507
10725
  */
10508
- between: (input, startAtom, endAtom, unitsAtom) => {
10509
- const startDate = functions.toDateTime(startAtom.eval(input));
10726
+ between: (context, input, startAtom, endAtom, unitsAtom) => {
10727
+ const startDate = functions.toDateTime(context, startAtom.eval(context, input));
10510
10728
  if (startDate.length === 0) {
10511
10729
  throw new Error('Invalid start date');
10512
10730
  }
10513
- const endDate = functions.toDateTime(endAtom.eval(input));
10731
+ const endDate = functions.toDateTime(context, endAtom.eval(context, input));
10514
10732
  if (endDate.length === 0) {
10515
10733
  throw new Error('Invalid end date');
10516
10734
  }
10517
- const unit = unitsAtom.eval(input)[0]?.value;
10735
+ const unit = unitsAtom.eval(context, input)[0]?.value;
10518
10736
  if (unit !== 'years' && unit !== 'months' && unit !== 'days') {
10519
10737
  throw new Error('Invalid units');
10520
10738
  }
@@ -10532,12 +10750,12 @@
10532
10750
  * For implementations with compile-time typing, this requires special-case
10533
10751
  * handling when processing the argument to treat it as a type specifier rather
10534
10752
  * than an identifier expression:
10535
- *
10536
- * @param input
10537
- * @param typeAtom
10538
- * @returns
10753
+ * @param _context The evaluation context.
10754
+ * @param input The input collection.
10755
+ * @param typeAtom The desired type.
10756
+ * @returns True if the input element is of the desired type.
10539
10757
  */
10540
- is: (input, typeAtom) => {
10758
+ is: (_context, input, typeAtom) => {
10541
10759
  let typeName = '';
10542
10760
  if (typeAtom instanceof SymbolAtom) {
10543
10761
  typeName = typeAtom.name;
@@ -10557,12 +10775,12 @@
10557
10775
  * 6.5.3. not() : Boolean
10558
10776
  *
10559
10777
  * Returns true if the input collection evaluates to false, and false if it evaluates to true. Otherwise, the result is empty ({ }):
10560
- *
10561
- * @param input
10562
- * @returns
10778
+ * @param context The evaluation context.
10779
+ * @param input The input collection.
10780
+ * @returns True if the input evaluates to false.
10563
10781
  */
10564
- not: (input) => {
10565
- return functions.toBoolean(input).map((value) => ({ type: exports.PropertyType.boolean, value: !value.value }));
10782
+ not: (context, input) => {
10783
+ return functions.toBoolean(context, input).map((value) => ({ type: exports.PropertyType.boolean, value: !value.value }));
10566
10784
  },
10567
10785
  /*
10568
10786
  * Additional functions
@@ -10571,10 +10789,11 @@
10571
10789
  /**
10572
10790
  * For each item in the collection, if it is a string that is a uri (or canonical or url), locate the target of the reference, and add it to the resulting collection. If the item does not resolve to a resource, the item is ignored and nothing is added to the output collection.
10573
10791
  * The items in the collection may also represent a Reference, in which case the Reference.reference is resolved.
10792
+ * @param _context The evaluation context.
10574
10793
  * @param input The input collection.
10575
- * @returns
10794
+ * @returns The resolved resource.
10576
10795
  */
10577
- resolve: (input) => {
10796
+ resolve: (_context, input) => {
10578
10797
  return input
10579
10798
  .map((e) => {
10580
10799
  const value = e.value;
@@ -10608,10 +10827,11 @@
10608
10827
  },
10609
10828
  /**
10610
10829
  * The as operator can be used to treat a value as a specific type.
10830
+ * @param _context The evaluation context.
10611
10831
  * @param input The input value.
10612
10832
  * @returns The value as the specific type.
10613
10833
  */
10614
- as: (input) => {
10834
+ as: (_context, input) => {
10615
10835
  return input;
10616
10836
  },
10617
10837
  /*
@@ -10627,11 +10847,11 @@
10627
10847
  * https://hl7.org/fhirpath/modelinfo.xsd
10628
10848
  *
10629
10849
  * See: https://hl7.org/fhirpath/#model-information
10630
- *
10850
+ * @param _context The evaluation context.
10631
10851
  * @param input The input collection.
10632
- * @returns
10852
+ * @returns The type of the input value.
10633
10853
  */
10634
- type: (input) => {
10854
+ type: (_context, input) => {
10635
10855
  return input.map(({ value }) => {
10636
10856
  if (typeof value === 'boolean') {
10637
10857
  return { type: exports.PropertyType.BackboneElement, value: { namespace: 'System', name: 'Boolean' } };
@@ -10648,8 +10868,8 @@
10648
10868
  return { type: exports.PropertyType.BackboneElement, value: null };
10649
10869
  });
10650
10870
  },
10651
- conformsTo: (input, systemAtom) => {
10652
- const system = systemAtom.eval(input)[0].value;
10871
+ conformsTo: (context, input, systemAtom) => {
10872
+ const system = systemAtom.eval(context, input)[0].value;
10653
10873
  if (!system.startsWith('http://hl7.org/fhir/StructureDefinition/')) {
10654
10874
  throw new Error('Expected a StructureDefinition URL');
10655
10875
  }
@@ -10663,7 +10883,7 @@
10663
10883
  /*
10664
10884
  * Helper utilities
10665
10885
  */
10666
- function applyStringFunc(func, input, ...argsAtoms) {
10886
+ function applyStringFunc(func, context, input, ...argsAtoms) {
10667
10887
  if (input.length === 0) {
10668
10888
  return [];
10669
10889
  }
@@ -10671,7 +10891,7 @@
10671
10891
  if (typeof value !== 'string') {
10672
10892
  throw new Error('String function cannot be called with non-string');
10673
10893
  }
10674
- const result = func(value, ...argsAtoms.map((atom) => atom && atom.eval(input)?.[0]?.value));
10894
+ const result = func(value, ...argsAtoms.map((atom) => atom && atom.eval(context, input)?.[0]?.value));
10675
10895
  if (result === undefined) {
10676
10896
  return [];
10677
10897
  }
@@ -10680,7 +10900,7 @@
10680
10900
  }
10681
10901
  return [toTypedValue(result)];
10682
10902
  }
10683
- function applyMathFunc(func, input, ...argsAtoms) {
10903
+ function applyMathFunc(func, context, input, ...argsAtoms) {
10684
10904
  if (input.length === 0) {
10685
10905
  return [];
10686
10906
  }
@@ -10690,7 +10910,7 @@
10690
10910
  if (typeof numberInput !== 'number') {
10691
10911
  throw new Error('Math function cannot be called with non-number');
10692
10912
  }
10693
- const result = func(numberInput, ...argsAtoms.map((atom) => atom.eval(input)?.[0]?.value));
10913
+ const result = func(numberInput, ...argsAtoms.map((atom) => atom.eval(context, input)?.[0]?.value));
10694
10914
  const type = quantity ? exports.PropertyType.Quantity : input[0].type;
10695
10915
  const returnValue = quantity ? { ...value, value: result } : result;
10696
10916
  return [{ type, value: returnValue }];
@@ -10712,13 +10932,13 @@
10712
10932
  this.original = original;
10713
10933
  this.child = child;
10714
10934
  }
10715
- eval(context) {
10935
+ eval(context, input) {
10716
10936
  try {
10717
- if (context.length > 0) {
10718
- return context.map((e) => this.child.eval([e])).flat();
10937
+ if (input.length > 0) {
10938
+ return input.map((e) => this.child.eval(context, [e])).flat();
10719
10939
  }
10720
10940
  else {
10721
- return this.child.eval([]);
10941
+ return this.child.eval(context, []);
10722
10942
  }
10723
10943
  }
10724
10944
  catch (error) {
@@ -10748,11 +10968,18 @@
10748
10968
  constructor(name) {
10749
10969
  this.name = name;
10750
10970
  }
10751
- eval(context) {
10971
+ eval(context, input) {
10752
10972
  if (this.name === '$this') {
10753
- return context;
10973
+ return input;
10974
+ }
10975
+ if (this.name.startsWith('%')) {
10976
+ const symbol = context.variables[this.name.slice(1)];
10977
+ if (!symbol) {
10978
+ throw new Error(`Undefined variable ${this.name}`);
10979
+ }
10980
+ return [symbol];
10754
10981
  }
10755
- return context.flatMap((e) => this.evalValue(e)).filter((e) => e?.value !== undefined);
10982
+ return input.flatMap((e) => this.evalValue(e)).filter((e) => e?.value !== undefined);
10756
10983
  }
10757
10984
  evalValue(typedValue) {
10758
10985
  const input = typedValue.value;
@@ -10781,8 +11008,8 @@
10781
11008
  super(operator, child);
10782
11009
  this.impl = impl;
10783
11010
  }
10784
- eval(context) {
10785
- return this.impl(this.child.eval(context));
11011
+ eval(context, input) {
11012
+ return this.impl(this.child.eval(context, input));
10786
11013
  }
10787
11014
  toString() {
10788
11015
  return this.child.toString();
@@ -10792,8 +11019,8 @@
10792
11019
  constructor(left, right) {
10793
11020
  super('as', left, right);
10794
11021
  }
10795
- eval(context) {
10796
- return functions.ofType(this.left.eval(context), this.right);
11022
+ eval(context, input) {
11023
+ return functions.ofType(context, this.left.eval(context, input), this.right);
10797
11024
  }
10798
11025
  }
10799
11026
  class ArithemticOperatorAtom extends InfixOperatorAtom {
@@ -10801,12 +11028,12 @@
10801
11028
  super(operator, left, right);
10802
11029
  this.impl = impl;
10803
11030
  }
10804
- eval(context) {
10805
- const leftEvalResult = this.left.eval(context);
11031
+ eval(context, input) {
11032
+ const leftEvalResult = this.left.eval(context, input);
10806
11033
  if (leftEvalResult.length !== 1) {
10807
11034
  return [];
10808
11035
  }
10809
- const rightEvalResult = this.right.eval(context);
11036
+ const rightEvalResult = this.right.eval(context, input);
10810
11037
  if (rightEvalResult.length !== 1) {
10811
11038
  return [];
10812
11039
  }
@@ -10830,9 +11057,9 @@
10830
11057
  constructor(left, right) {
10831
11058
  super('&', left, right);
10832
11059
  }
10833
- eval(context) {
10834
- const leftValue = this.left.eval(context);
10835
- const rightValue = this.right.eval(context);
11060
+ eval(context, input) {
11061
+ const leftValue = this.left.eval(context, input);
11062
+ const rightValue = this.right.eval(context, input);
10836
11063
  const result = [...leftValue, ...rightValue];
10837
11064
  if (result.length > 0 && result.every((e) => typeof e.value === 'string')) {
10838
11065
  return [{ type: exports.PropertyType.string, value: result.map((e) => e.value).join('') }];
@@ -10844,9 +11071,9 @@
10844
11071
  constructor(left, right) {
10845
11072
  super('contains', left, right);
10846
11073
  }
10847
- eval(context) {
10848
- const leftValue = this.left.eval(context);
10849
- const rightValue = this.right.eval(context);
11074
+ eval(context, input) {
11075
+ const leftValue = this.left.eval(context, input);
11076
+ const rightValue = this.right.eval(context, input);
10850
11077
  return booleanToTypedValue(leftValue.some((e) => e.value === rightValue[0].value));
10851
11078
  }
10852
11079
  }
@@ -10854,9 +11081,9 @@
10854
11081
  constructor(left, right) {
10855
11082
  super('in', left, right);
10856
11083
  }
10857
- eval(context) {
10858
- const leftValue = this.left.eval(context);
10859
- const rightValue = this.right.eval(context);
11084
+ eval(context, input) {
11085
+ const leftValue = this.left.eval(context, input);
11086
+ const rightValue = this.right.eval(context, input);
10860
11087
  return booleanToTypedValue(rightValue.some((e) => e.value === leftValue[0].value));
10861
11088
  }
10862
11089
  }
@@ -10864,8 +11091,8 @@
10864
11091
  constructor(left, right) {
10865
11092
  super('.', left, right);
10866
11093
  }
10867
- eval(context) {
10868
- return this.right.eval(this.left.eval(context));
11094
+ eval(context, input) {
11095
+ return this.right.eval(context, this.left.eval(context, input));
10869
11096
  }
10870
11097
  toString() {
10871
11098
  return `${this.left.toString()}.${this.right.toString()}`;
@@ -10875,9 +11102,9 @@
10875
11102
  constructor(left, right) {
10876
11103
  super('|', left, right);
10877
11104
  }
10878
- eval(context) {
10879
- const leftResult = this.left.eval(context);
10880
- const rightResult = this.right.eval(context);
11105
+ eval(context, input) {
11106
+ const leftResult = this.left.eval(context, input);
11107
+ const rightResult = this.right.eval(context, input);
10881
11108
  return removeDuplicates([...leftResult, ...rightResult]);
10882
11109
  }
10883
11110
  }
@@ -10885,9 +11112,9 @@
10885
11112
  constructor(left, right) {
10886
11113
  super('=', left, right);
10887
11114
  }
10888
- eval(context) {
10889
- const leftValue = this.left.eval(context);
10890
- const rightValue = this.right.eval(context);
11115
+ eval(context, input) {
11116
+ const leftValue = this.left.eval(context, input);
11117
+ const rightValue = this.right.eval(context, input);
10891
11118
  return fhirPathArrayEquals(leftValue, rightValue);
10892
11119
  }
10893
11120
  }
@@ -10895,9 +11122,9 @@
10895
11122
  constructor(left, right) {
10896
11123
  super('!=', left, right);
10897
11124
  }
10898
- eval(context) {
10899
- const leftValue = this.left.eval(context);
10900
- const rightValue = this.right.eval(context);
11125
+ eval(context, input) {
11126
+ const leftValue = this.left.eval(context, input);
11127
+ const rightValue = this.right.eval(context, input);
10901
11128
  return fhirPathNot(fhirPathArrayEquals(leftValue, rightValue));
10902
11129
  }
10903
11130
  }
@@ -10905,9 +11132,9 @@
10905
11132
  constructor(left, right) {
10906
11133
  super('~', left, right);
10907
11134
  }
10908
- eval(context) {
10909
- const leftValue = this.left.eval(context);
10910
- const rightValue = this.right.eval(context);
11135
+ eval(context, input) {
11136
+ const leftValue = this.left.eval(context, input);
11137
+ const rightValue = this.right.eval(context, input);
10911
11138
  return fhirPathArrayEquivalent(leftValue, rightValue);
10912
11139
  }
10913
11140
  }
@@ -10915,9 +11142,9 @@
10915
11142
  constructor(left, right) {
10916
11143
  super('!~', left, right);
10917
11144
  }
10918
- eval(context) {
10919
- const leftValue = this.left.eval(context);
10920
- const rightValue = this.right.eval(context);
11145
+ eval(context, input) {
11146
+ const leftValue = this.left.eval(context, input);
11147
+ const rightValue = this.right.eval(context, input);
10921
11148
  return fhirPathNot(fhirPathArrayEquivalent(leftValue, rightValue));
10922
11149
  }
10923
11150
  }
@@ -10925,8 +11152,8 @@
10925
11152
  constructor(left, right) {
10926
11153
  super('is', left, right);
10927
11154
  }
10928
- eval(context) {
10929
- const leftValue = this.left.eval(context);
11155
+ eval(context, input) {
11156
+ const leftValue = this.left.eval(context, input);
10930
11157
  if (leftValue.length !== 1) {
10931
11158
  return [];
10932
11159
  }
@@ -10944,9 +11171,9 @@
10944
11171
  constructor(left, right) {
10945
11172
  super('and', left, right);
10946
11173
  }
10947
- eval(context) {
10948
- const leftValue = this.left.eval(context);
10949
- const rightValue = this.right.eval(context);
11174
+ eval(context, input) {
11175
+ const leftValue = this.left.eval(context, input);
11176
+ const rightValue = this.right.eval(context, input);
10950
11177
  if (leftValue[0]?.value === true && rightValue[0]?.value === true) {
10951
11178
  return booleanToTypedValue(true);
10952
11179
  }
@@ -10960,12 +11187,12 @@
10960
11187
  constructor(left, right) {
10961
11188
  super('or', left, right);
10962
11189
  }
10963
- eval(context) {
10964
- const leftValue = this.left.eval(context);
11190
+ eval(context, input) {
11191
+ const leftValue = this.left.eval(context, input);
10965
11192
  if (toJsBoolean(leftValue)) {
10966
11193
  return leftValue;
10967
11194
  }
10968
- const rightValue = this.right.eval(context);
11195
+ const rightValue = this.right.eval(context, input);
10969
11196
  if (toJsBoolean(rightValue)) {
10970
11197
  return rightValue;
10971
11198
  }
@@ -10982,9 +11209,9 @@
10982
11209
  constructor(left, right) {
10983
11210
  super('xor', left, right);
10984
11211
  }
10985
- eval(context) {
10986
- const leftResult = this.left.eval(context);
10987
- const rightResult = this.right.eval(context);
11212
+ eval(context, input) {
11213
+ const leftResult = this.left.eval(context, input);
11214
+ const rightResult = this.right.eval(context, input);
10988
11215
  if (leftResult.length === 0 && rightResult.length === 0) {
10989
11216
  return [];
10990
11217
  }
@@ -11004,12 +11231,12 @@
11004
11231
  this.name = name;
11005
11232
  this.args = args;
11006
11233
  }
11007
- eval(context) {
11234
+ eval(context, input) {
11008
11235
  const impl = functions[this.name];
11009
11236
  if (!impl) {
11010
11237
  throw new Error('Unrecognized function: ' + this.name);
11011
11238
  }
11012
- return impl(context, ...this.args);
11239
+ return impl(context, input, ...this.args);
11013
11240
  }
11014
11241
  toString() {
11015
11242
  return `${this.name}(${this.args.map((arg) => arg.toString()).join(', ')})`;
@@ -11020,8 +11247,8 @@
11020
11247
  this.left = left;
11021
11248
  this.expr = expr;
11022
11249
  }
11023
- eval(context) {
11024
- const evalResult = this.expr.eval(context);
11250
+ eval(context, input) {
11251
+ const evalResult = this.expr.eval(context, input);
11025
11252
  if (evalResult.length !== 1) {
11026
11253
  return [];
11027
11254
  }
@@ -11029,7 +11256,7 @@
11029
11256
  if (typeof index !== 'number') {
11030
11257
  throw new Error(`Invalid indexer expression: should return integer}`);
11031
11258
  }
11032
- const leftResult = this.left.eval(context);
11259
+ const leftResult = this.left.eval(context, input);
11033
11260
  if (!(index in leftResult)) {
11034
11261
  return [];
11035
11262
  }
@@ -11173,10 +11400,12 @@
11173
11400
  * Evaluates a FHIRPath expression against a resource or other object.
11174
11401
  * @param expression The FHIRPath expression to parse.
11175
11402
  * @param input The resource or object to evaluate the expression against.
11403
+ * @param variables A map of variables for eval input.
11176
11404
  * @returns The result of the FHIRPath expression against the resource or object.
11177
11405
  */
11178
- function evalFhirPathTyped(expression, input) {
11179
- return parseFhirPath(expression).eval(input);
11406
+ function evalFhirPathTyped(expression, input, variables) {
11407
+ const variableInput = variables ? variables : {};
11408
+ return parseFhirPath(expression).eval({ variables: variableInput }, input);
11180
11409
  }
11181
11410
 
11182
11411
  const MAPPING_LANGUAGE_OPERATORS$1 = [...FHIRPATH_OPERATORS, '->', '<<', '>>'];
@@ -11831,7 +12060,7 @@
11831
12060
  /**
11832
12061
  * Formats a search definition object into a query string.
11833
12062
  * Note: The return value does not include the resource type.
11834
- * @param {!SearchRequest} definition The search definition.
12063
+ * @param definition The search definition.
11835
12064
  * @returns Formatted URL.
11836
12065
  */
11837
12066
  function formatSearchQuery(definition) {
@@ -12219,7 +12448,7 @@
12219
12448
  * Returns a formatted string representing the date in ISO-8601 format.
12220
12449
  * @param hl7Date Date string.
12221
12450
  * @param options Optional configuration Object
12222
- * @returns
12451
+ * @returns The date in ISO-8601 format.
12223
12452
  */
12224
12453
  function parseHl7Date(hl7Date, options) {
12225
12454
  if (!hl7Date) {
@@ -12308,7 +12537,6 @@
12308
12537
  * const medplum = new MedplumClient();
12309
12538
  * await medplum.requestSchema('Patient');
12310
12539
  * ```
12311
- *
12312
12540
  * @param resourceType The candidate resource type string.
12313
12541
  * @returns True if the resource type is a valid FHIR resource type.
12314
12542
  */
@@ -12348,9 +12576,7 @@
12348
12576
  * const medplum = new MedplumClient();
12349
12577
  * await medplum.requestSchema('Patient');
12350
12578
  * ```
12351
- *
12352
12579
  * @param resourceType The candidate resource type string.
12353
- * @returns True if the resource type is a valid FHIR resource type.
12354
12580
  */
12355
12581
  function validateResourceType(resourceType) {
12356
12582
  if (!resourceType) {
@@ -12390,9 +12616,7 @@
12390
12616
  * const medplum = new MedplumClient();
12391
12617
  * await medplum.requestSchema('Patient');
12392
12618
  * ```
12393
- *
12394
- * @param resourceType The candidate resource type string.
12395
- * @returns True if the resource type is a valid FHIR resource type.
12619
+ * @param resource The candidate resource.
12396
12620
  */
12397
12621
  function validateResource(resource) {
12398
12622
  new FhirSchemaValidator(resource).validate();
@@ -12555,10 +12779,10 @@
12555
12779
  * 2) a JSON property with _ prepended to the name of the element, which, if present, contains the value's id and/or extensions
12556
12780
  *
12557
12781
  * See: https://hl7.org/fhir/json.html#primitive
12558
- *
12559
12782
  * @param path The path to the property
12560
- * @param key
12561
- * @param typedValue
12783
+ * @param key The key in the current typed value.
12784
+ * @param typedValue The current typed value.
12785
+ * @returns True if the primitive element is valid.
12562
12786
  */
12563
12787
  checkPrimitiveElement(path, key, typedValue) {
12564
12788
  // Primitive element starts with underscore
@@ -12611,7 +12835,6 @@
12611
12835
  * Recursively checks for null values in an object.
12612
12836
  *
12613
12837
  * Note that "null" is a special value in JSON that is not allowed in FHIR.
12614
- *
12615
12838
  * @param value Input value of any type.
12616
12839
  * @param path Path string to the value for OperationOutcome.
12617
12840
  * @param issues Output list of issues.
@@ -12675,7 +12898,6 @@
12675
12898
  * 1) The "date" type includes "date", "datetime", and "period".
12676
12899
  * 2) The "token" type includes enums and booleans.
12677
12900
  * 3) Arrays/multiple values are not reflected at all.
12678
- *
12679
12901
  * @param resourceType The root resource type.
12680
12902
  * @param searchParam The search parameter.
12681
12903
  * @returns The search parameter type details.
@@ -12683,18 +12905,18 @@
12683
12905
  function getSearchParameterDetails(resourceType, searchParam) {
12684
12906
  let result = globalSchema.types[resourceType]?.searchParamsDetails?.[searchParam.code];
12685
12907
  if (!result) {
12686
- result = buildSearchParamterDetails(resourceType, searchParam);
12908
+ result = buildSearchParameterDetails(resourceType, searchParam);
12687
12909
  }
12688
12910
  return result;
12689
12911
  }
12690
- function setSearchParamterDetails(resourceType, code, details) {
12912
+ function setSearchParameterDetails(resourceType, code, details) {
12691
12913
  const typeSchema = globalSchema.types[resourceType];
12692
12914
  if (!typeSchema.searchParamsDetails) {
12693
12915
  typeSchema.searchParamsDetails = {};
12694
12916
  }
12695
12917
  typeSchema.searchParamsDetails[code] = details;
12696
12918
  }
12697
- function buildSearchParamterDetails(resourceType, searchParam) {
12919
+ function buildSearchParameterDetails(resourceType, searchParam) {
12698
12920
  const code = searchParam.code;
12699
12921
  const columnName = convertCodeToColumnName(code);
12700
12922
  const expression = getExpressionForResourceType(resourceType, searchParam.expression)?.split('.');
@@ -12736,7 +12958,7 @@
12736
12958
  }
12737
12959
  const type = getSearchParameterType(searchParam, propertyType);
12738
12960
  const result = { columnName, type, elementDefinition, array };
12739
- setSearchParamterDetails(resourceType, code, result);
12961
+ setSearchParameterDetails(resourceType, code, result);
12740
12962
  return result;
12741
12963
  }
12742
12964
  function isBackboneElement(propertyType) {
@@ -12835,6 +13057,7 @@
12835
13057
  /**
12836
13058
  * Determines if the resource matches the search filter.
12837
13059
  * @param resource The resource that was created or updated.
13060
+ * @param searchRequest The search request.
12838
13061
  * @param filter One of the filters of a subscription criteria.
12839
13062
  * @returns True if the resource satisfies the search filter.
12840
13063
  */
@@ -13051,8 +13274,10 @@
13051
13274
  exports.createReference = createReference;
13052
13275
  exports.createStructureIssue = createStructureIssue;
13053
13276
  exports.created = created;
13277
+ exports.decodeBase64 = decodeBase64;
13054
13278
  exports.deepClone = deepClone;
13055
13279
  exports.deepEquals = deepEquals$1;
13280
+ exports.encodeBase64 = encodeBase64;
13056
13281
  exports.evalFhirPath = evalFhirPath;
13057
13282
  exports.evalFhirPathTyped = evalFhirPathTyped;
13058
13283
  exports.fhirPathArrayEquals = fhirPathArrayEquals;
@@ -13131,6 +13356,7 @@
13131
13356
  exports.normalizeOperationOutcome = normalizeOperationOutcome;
13132
13357
  exports.notFound = notFound;
13133
13358
  exports.notModified = notModified;
13359
+ exports.operationOutcomeIssueToString = operationOutcomeIssueToString;
13134
13360
  exports.operationOutcomeToString = operationOutcomeToString;
13135
13361
  exports.parseFhirPath = parseFhirPath;
13136
13362
  exports.parseFilterParameter = parseFilterParameter;