@medplum/core 0.9.27 → 0.9.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -156,6 +156,111 @@
156
156
  function formatFamilyName(name) {
157
157
  return name.family || '';
158
158
  }
159
+ function isValidDate(date) {
160
+ return date instanceof Date && !isNaN(date.getTime());
161
+ }
162
+ function formatDate(date, options) {
163
+ if (!date) {
164
+ return '';
165
+ }
166
+ const d = new Date(date);
167
+ if (!isValidDate(d)) {
168
+ return '';
169
+ }
170
+ return d.toLocaleDateString(undefined, options);
171
+ }
172
+ function formatTime(time, options) {
173
+ if (!time) {
174
+ return '';
175
+ }
176
+ const d = new Date('2000-01-01T' + time + 'Z');
177
+ if (!isValidDate(d)) {
178
+ return '';
179
+ }
180
+ return d.toLocaleTimeString(undefined, options);
181
+ }
182
+ function formatDateTime(dateTime, options) {
183
+ if (!dateTime) {
184
+ return '';
185
+ }
186
+ const d = new Date(dateTime);
187
+ if (!isValidDate(d)) {
188
+ return '';
189
+ }
190
+ return d.toLocaleString(undefined, options);
191
+ }
192
+ function formatPeriod(period) {
193
+ if (!period || (!period.start && !period.end)) {
194
+ return '';
195
+ }
196
+ return formatDateTime(period.start) + ' - ' + formatDateTime(period.end);
197
+ }
198
+ const unitAdverbForm = {
199
+ s: 'every second',
200
+ min: 'every minute',
201
+ h: 'hourly',
202
+ d: 'daily',
203
+ wk: 'weekly',
204
+ mo: 'monthly',
205
+ a: 'annually',
206
+ };
207
+ const singularUnits = {
208
+ s: 'second',
209
+ min: 'minute',
210
+ h: 'hour',
211
+ d: 'day',
212
+ wk: 'week',
213
+ mo: 'month',
214
+ a: 'year',
215
+ };
216
+ const pluralUnits = {
217
+ s: 'seconds',
218
+ min: 'minutes',
219
+ h: 'hours',
220
+ d: 'days',
221
+ wk: 'weeks',
222
+ mo: 'months',
223
+ a: 'years',
224
+ };
225
+ function formatTiming(timing) {
226
+ var _a;
227
+ if (!timing) {
228
+ return '';
229
+ }
230
+ const builder = [];
231
+ if ((_a = timing.repeat) === null || _a === void 0 ? void 0 : _a.periodUnit) {
232
+ const frequency = timing.repeat.frequency || 1;
233
+ const period = timing.repeat.period || 1;
234
+ const periodUnit = timing.repeat.periodUnit;
235
+ if (frequency === 1 && period === 1) {
236
+ builder.push(unitAdverbForm[periodUnit]);
237
+ }
238
+ else {
239
+ if (frequency === 1) {
240
+ builder.push('once');
241
+ }
242
+ else {
243
+ builder.push(frequency + ' times');
244
+ }
245
+ if (period === 1) {
246
+ builder.push('per ' + singularUnits[periodUnit]);
247
+ }
248
+ else {
249
+ builder.push('per ' + period + ' ' + pluralUnits[periodUnit]);
250
+ }
251
+ }
252
+ if (timing.repeat.dayOfWeek) {
253
+ builder.push('on ' + timing.repeat.dayOfWeek.map(capitalize).join(', '));
254
+ }
255
+ if (timing.repeat.timeOfDay) {
256
+ builder.push('at ' + timing.repeat.timeOfDay.map((t) => formatTime(t)).join(', '));
257
+ }
258
+ }
259
+ if (timing.event) {
260
+ builder.push(timing.event.map((d) => formatDateTime(d)).join(', '));
261
+ }
262
+ return capitalize(builder.join(' ').trim());
263
+ }
159
264
 
160
265
  /**
161
266
  * Creates a reference resource.
@@ -6097,7 +6202,7 @@
6097
6202
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
6098
6203
  const DEFAULT_SCOPE = 'launch/patient openid fhirUser offline_access user/*.*';
6099
6204
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
6100
- const DEFAULT_CACHE_TIME = 10000; // 10 seconds
6205
+ const DEFAULT_CACHE_TIME = 60000; // 60 seconds
6101
6206
  const JSON_CONTENT_TYPE = 'application/json';
6102
6207
  const FHIR_CONTENT_TYPE = 'application/fhir+json';
6103
6208
  const PATCH_CONTENT_TYPE = 'application/json-patch+json';
@@ -6999,14 +7104,19 @@
6999
7104
  * @returns The result of the update operation.
7000
7105
  */
7001
7106
  updateResource(resource) {
7002
- if (!resource.resourceType) {
7003
- throw new Error('Missing resourceType');
7004
- }
7005
- if (!resource.id) {
7006
- throw new Error('Missing id');
7007
- }
7008
- this.invalidateSearches(resource.resourceType);
7009
- return this.put(this.fhirUrl(resource.resourceType, resource.id), resource);
7107
+ return __awaiter(this, void 0, void 0, function* () {
7108
+ if (!resource.resourceType) {
7109
+ throw new Error('Missing resourceType');
7110
+ }
7111
+ if (!resource.id) {
7112
+ throw new Error('Missing id');
7113
+ }
7114
+ this.invalidateSearches(resource.resourceType);
7115
+ const result = yield this.put(this.fhirUrl(resource.resourceType, resource.id), resource);
7116
+ // On 304 not modified, result will be undefined
7117
+ // Return the user input instead
7118
+ return result !== null && result !== void 0 ? result : resource;
7119
+ });
7010
7120
  }
7011
7121
  /**
7012
7122
  * Updates a FHIR resource using JSONPatch operations.
@@ -7668,9 +7778,18 @@
7668
7778
  result = input[path];
7669
7779
  }
7670
7780
  else {
7671
- const propertyName = Object.keys(input).find((k) => k.startsWith(path));
7672
- if (propertyName) {
7673
- result = input[propertyName];
7781
+ // Only support property names that would be valid types
7782
+ // Examples:
7783
+ // value + valueString = ok, because "string" is valid
7784
+ // value + valueDecimal = ok, because "decimal" is valid
7785
+ // id + identifiier = not ok, because "entifier" is not a valid type
7786
+ // resource + resourceType = not ok, because "type" is not a valid type
7787
+ for (const propertyType in exports.PropertyType) {
7788
+ const propertyName = path + capitalize(propertyType);
7789
+ if (propertyName in input) {
7790
+ result = input[propertyName];
7791
+ break;
7792
+ }
7674
7793
  }
7675
7794
  }
7676
7795
  if (result === undefined) {
@@ -10277,7 +10396,8 @@
10277
10396
  const GONE_ID = 'gone';
10278
10397
  const NOT_MODIFIED_ID = 'not-modified';
10279
10398
  const NOT_FOUND_ID = 'not-found';
10280
- const ACCESS_DENIED = 'access-denied';
10399
+ const ACCESS_DENIED_ID = 'access-denied';
10400
+ const TOO_MANY_REQUESTS_ID = 'too-many-requests';
10281
10401
  const allOk = {
10282
10402
  resourceType: 'OperationOutcome',
10283
10403
  id: OK_ID,
@@ -10345,17 +10465,30 @@
10345
10465
  };
10346
10466
  const accessDenied = {
10347
10467
  resourceType: 'OperationOutcome',
10348
- id: ACCESS_DENIED,
10468
+ id: ACCESS_DENIED_ID,
10349
10469
  issue: [
10350
10470
  {
10351
10471
  severity: 'error',
10352
- code: 'access-denied',
10472
+ code: 'forbidden',
10353
10473
  details: {
10354
10474
  text: 'Access Denied',
10355
10475
  },
10356
10476
  },
10357
10477
  ],
10358
10478
  };
10479
+ const tooManyRequests = {
10480
+ resourceType: 'OperationOutcome',
10481
+ id: TOO_MANY_REQUESTS_ID,
10482
+ issue: [
10483
+ {
10484
+ severity: 'error',
10485
+ code: 'throttled',
10486
+ details: {
10487
+ text: 'Too Many Requests',
10488
+ },
10489
+ },
10490
+ ],
10491
+ };
10359
10492
  function badRequest(details, expression) {
10360
10493
  return {
10361
10494
  resourceType: 'OperationOutcome',
@@ -10390,7 +10523,7 @@
10390
10523
  else if (outcome.id === NOT_MODIFIED_ID) {
10391
10524
  return 304;
10392
10525
  }
10393
- else if (outcome.id === ACCESS_DENIED) {
10526
+ else if (outcome.id === ACCESS_DENIED_ID) {
10394
10527
  return 403;
10395
10528
  }
10396
10529
  else if (outcome.id === NOT_FOUND_ID) {
@@ -10399,6 +10532,9 @@
10399
10532
  else if (outcome.id === GONE_ID) {
10400
10533
  return 410;
10401
10534
  }
10535
+ else if (outcome.id === TOO_MANY_REQUESTS_ID) {
10536
+ return 429;
10537
+ }
10402
10538
  else {
10403
10539
  return 400;
10404
10540
  }
@@ -10420,6 +10556,28 @@
10420
10556
  this.outcome = outcome;
10421
10557
  }
10422
10558
  }
10559
+ /**
10560
+ * Normalizes an error object into a displayable error string.
10561
+ * @param error The error value which could be a string, Error, OperationOutcome, or other unknown type.
10562
+ * @returns A display string for the error.
10563
+ */
10564
+ function normalizeErrorString(error) {
10565
+ var _a, _b, _c, _d;
10566
+ if (!error) {
10567
+ return 'Unknown error';
10568
+ }
10569
+ if (typeof error === 'string') {
10570
+ return error;
10571
+ }
10572
+ if (error instanceof Error) {
10573
+ return error.message;
10574
+ }
10575
+ if (typeof error === 'object' && 'resourceType' in error) {
10576
+ const outcome = error;
10577
+ return (_d = (_c = (_b = (_a = outcome.issue) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.details) === null || _c === void 0 ? void 0 : _c.text) !== null && _d !== void 0 ? _d : 'Unknown error';
10578
+ }
10579
+ return JSON.stringify(error);
10580
+ }
10423
10581
 
10424
10582
  const DEFAULT_SEARCH_COUNT = 20;
10425
10583
  /**
@@ -10826,10 +10984,15 @@
10826
10984
  exports.findObservationInterval = findObservationInterval;
10827
10985
  exports.findObservationReferenceRange = findObservationReferenceRange;
10828
10986
  exports.formatAddress = formatAddress;
10987
+ exports.formatDate = formatDate;
10988
+ exports.formatDateTime = formatDateTime;
10829
10989
  exports.formatFamilyName = formatFamilyName;
10830
10990
  exports.formatGivenName = formatGivenName;
10831
10991
  exports.formatHumanName = formatHumanName;
10992
+ exports.formatPeriod = formatPeriod;
10832
10993
  exports.formatSearchQuery = formatSearchQuery;
10994
+ exports.formatTime = formatTime;
10995
+ exports.formatTiming = formatTiming;
10833
10996
  exports.getCodeBySystem = getCodeBySystem;
10834
10997
  exports.getDateProperty = getDateProperty;
10835
10998
  exports.getDisplayString = getDisplayString;
@@ -10859,7 +11022,9 @@
10859
11022
  exports.isQuantityEquivalent = isQuantityEquivalent;
10860
11023
  exports.isStringArray = isStringArray;
10861
11024
  exports.isUUID = isUUID;
11025
+ exports.isValidDate = isValidDate;
10862
11026
  exports.matchesRange = matchesRange;
11027
+ exports.normalizeErrorString = normalizeErrorString;
10863
11028
  exports.notFound = notFound;
10864
11029
  exports.notModified = notModified;
10865
11030
  exports.parseFhirPath = parseFhirPath;
@@ -10877,6 +11042,7 @@
10877
11042
  exports.toJsBoolean = toJsBoolean;
10878
11043
  exports.toTypedValue = toTypedValue;
10879
11044
  exports.tokenize = tokenize;
11045
+ exports.tooManyRequests = tooManyRequests;
10880
11046
 
10881
11047
  Object.defineProperty(exports, '__esModule', { value: true });
10882
11048