@medplum/core 2.0.15 → 2.0.17
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.cjs +96 -48
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.min.cjs +1 -1
- package/dist/esm/client.mjs +43 -25
- package/dist/esm/client.mjs.map +1 -1
- package/dist/esm/format.mjs +24 -15
- package/dist/esm/format.mjs.map +1 -1
- package/dist/esm/index.min.mjs +1 -1
- package/dist/esm/index.mjs +2 -2
- package/dist/esm/outcomes.mjs +15 -1
- package/dist/esm/outcomes.mjs.map +1 -1
- package/dist/esm/search/search.mjs +15 -9
- package/dist/esm/search/search.mjs.map +1 -1
- package/dist/types/client.d.ts +27 -1
- package/dist/types/format.d.ts +3 -1
- package/dist/types/outcomes.d.ts +1 -0
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -322,8 +322,9 @@
|
|
|
322
322
|
return capitalize(builder.join(' ').trim());
|
|
323
323
|
}
|
|
324
324
|
/**
|
|
325
|
-
* Returns a human-readable string for a FHIR Range datatype, taking into account
|
|
325
|
+
* Returns a human-readable string for a FHIR Range datatype, taking into account one-sided ranges
|
|
326
326
|
* @param range A FHIR Range element
|
|
327
|
+
* @param precision Number of decimal places to display in the rendered quantity values
|
|
327
328
|
* @param exclusive If true, one-sided ranges will be rendered with the '>' or '<' bounds rather than '>=' or '<='
|
|
328
329
|
* @returns A human-readable string representation of the Range
|
|
329
330
|
*/
|
|
@@ -331,33 +332,41 @@
|
|
|
331
332
|
if (exclusive && precision === undefined) {
|
|
332
333
|
throw new Error('Precision must be specified for exclusive ranges');
|
|
333
334
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
335
|
+
// Extract high and low range endpoints, explicitly ignoring any comparator
|
|
336
|
+
// since Range uses SimpleQuantity variants (see http://www.hl7.org/fhir/datatypes.html#Range)
|
|
337
|
+
const low = range?.low && { ...range.low, comparator: undefined };
|
|
338
|
+
const high = range?.high && { ...range.high, comparator: undefined };
|
|
339
|
+
if (low?.value === undefined && high?.value === undefined) {
|
|
337
340
|
return '';
|
|
338
341
|
}
|
|
339
|
-
if (
|
|
342
|
+
if (low?.value !== undefined && high?.value === undefined) {
|
|
343
|
+
// Lower bound only
|
|
340
344
|
if (exclusive && precision !== undefined) {
|
|
341
|
-
|
|
342
|
-
return `> ${formatQuantity(
|
|
345
|
+
low.value = preciseDecrement(low.value, precision);
|
|
346
|
+
return `> ${formatQuantity(low, precision)}`;
|
|
343
347
|
}
|
|
344
|
-
return `>= ${formatQuantity(
|
|
348
|
+
return `>= ${formatQuantity(low, precision)}`;
|
|
345
349
|
}
|
|
346
|
-
if (
|
|
350
|
+
else if (low?.value === undefined && high?.value !== undefined) {
|
|
351
|
+
// Upper bound only
|
|
347
352
|
if (exclusive && precision !== undefined) {
|
|
348
|
-
|
|
349
|
-
return `< ${formatQuantity(
|
|
353
|
+
high.value = preciseIncrement(high.value, precision);
|
|
354
|
+
return `< ${formatQuantity(high, precision)}`;
|
|
350
355
|
}
|
|
351
|
-
return `<= ${formatQuantity(
|
|
356
|
+
return `<= ${formatQuantity(high, precision)}`;
|
|
352
357
|
}
|
|
353
|
-
|
|
354
|
-
|
|
358
|
+
else {
|
|
359
|
+
// Double-sided range
|
|
360
|
+
if (low?.unit === high?.unit) {
|
|
361
|
+
delete low?.unit; // Format like "X - Y units" instead of "X units - Y units"
|
|
362
|
+
}
|
|
363
|
+
return `${formatQuantity(low, precision)} - ${formatQuantity(high, precision)}`;
|
|
355
364
|
}
|
|
356
|
-
return `${formatQuantity(low, precision)} - ${formatQuantity(high, precision)}`;
|
|
357
365
|
}
|
|
358
366
|
/**
|
|
359
367
|
* Returns a human-readable string for a FHIR Quantity datatype, taking into account units and comparators
|
|
360
368
|
* @param quantity A FHIR Quantity element
|
|
369
|
+
* @param precision Number of decimal places to display in the rendered quantity values
|
|
361
370
|
* @returns A human-readable string representation of the Quantity
|
|
362
371
|
*/
|
|
363
372
|
function formatQuantity(quantity, precision) {
|
|
@@ -1203,6 +1212,7 @@
|
|
|
1203
1212
|
const UNAUTHORIZED_ID = 'unauthorized';
|
|
1204
1213
|
const FORBIDDEN_ID = 'forbidden';
|
|
1205
1214
|
const TOO_MANY_REQUESTS_ID = 'too-many-requests';
|
|
1215
|
+
const ACCEPTED_ID = 'accepted';
|
|
1206
1216
|
const allOk = {
|
|
1207
1217
|
resourceType: 'OperationOutcome',
|
|
1208
1218
|
id: OK_ID,
|
|
@@ -1307,6 +1317,19 @@
|
|
|
1307
1317
|
},
|
|
1308
1318
|
],
|
|
1309
1319
|
};
|
|
1320
|
+
const accepted = {
|
|
1321
|
+
resourceType: 'OperationOutcome',
|
|
1322
|
+
id: ACCEPTED_ID,
|
|
1323
|
+
issue: [
|
|
1324
|
+
{
|
|
1325
|
+
severity: 'information',
|
|
1326
|
+
code: 'informational',
|
|
1327
|
+
details: {
|
|
1328
|
+
text: 'Accepted',
|
|
1329
|
+
},
|
|
1330
|
+
},
|
|
1331
|
+
],
|
|
1332
|
+
};
|
|
1310
1333
|
function badRequest(details, expression) {
|
|
1311
1334
|
return {
|
|
1312
1335
|
resourceType: 'OperationOutcome',
|
|
@@ -6381,7 +6404,7 @@
|
|
|
6381
6404
|
const globalSchema = baseSchema;
|
|
6382
6405
|
|
|
6383
6406
|
// PKCE auth based on:
|
|
6384
|
-
const MEDPLUM_VERSION = "2.0.
|
|
6407
|
+
const MEDPLUM_VERSION = "2.0.17-5c5ebbda";
|
|
6385
6408
|
const DEFAULT_BASE_URL = 'https://api.medplum.com/';
|
|
6386
6409
|
const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
|
|
6387
6410
|
const DEFAULT_CACHE_TIME = 60000; // 60 seconds
|
|
@@ -6389,6 +6412,35 @@
|
|
|
6389
6412
|
const FHIR_CONTENT_TYPE = 'application/fhir+json';
|
|
6390
6413
|
const PATCH_CONTENT_TYPE = 'application/json-patch+json';
|
|
6391
6414
|
const system = { resourceType: 'Device', id: 'system', deviceName: [{ name: 'System' }] };
|
|
6415
|
+
/**
|
|
6416
|
+
* OAuth 2.0 Grant Type Identifiers
|
|
6417
|
+
* Standard identifiers defined here: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07#name-grant-types
|
|
6418
|
+
* Token exchange extension defined here: https://datatracker.ietf.org/doc/html/rfc8693
|
|
6419
|
+
*/
|
|
6420
|
+
exports.OAuthGrantType = void 0;
|
|
6421
|
+
(function (OAuthGrantType) {
|
|
6422
|
+
OAuthGrantType["ClientCredentials"] = "client_credentials";
|
|
6423
|
+
OAuthGrantType["AuthorizationCode"] = "authorization_code";
|
|
6424
|
+
OAuthGrantType["RefreshToken"] = "refresh_token";
|
|
6425
|
+
OAuthGrantType["TokenExchange"] = "urn:ietf:params:oauth:grant-type:token-exchange";
|
|
6426
|
+
})(exports.OAuthGrantType || (exports.OAuthGrantType = {}));
|
|
6427
|
+
/**
|
|
6428
|
+
* OAuth 2.0 Token Type Identifiers
|
|
6429
|
+
* See: https://datatracker.ietf.org/doc/html/rfc8693#name-token-type-identifiers
|
|
6430
|
+
*/
|
|
6431
|
+
exports.OAuthTokenType = void 0;
|
|
6432
|
+
(function (OAuthTokenType) {
|
|
6433
|
+
/** Indicates that the token is an OAuth 2.0 access token issued by the given authorization server. */
|
|
6434
|
+
OAuthTokenType["AccessToken"] = "urn:ietf:params:oauth:token-type:access_token";
|
|
6435
|
+
/** Indicates that the token is an OAuth 2.0 refresh token issued by the given authorization server. */
|
|
6436
|
+
OAuthTokenType["RefreshToken"] = "urn:ietf:params:oauth:token-type:refresh_token";
|
|
6437
|
+
/** Indicates that the token is an ID Token as defined in Section 2 of [OpenID.Core]. */
|
|
6438
|
+
OAuthTokenType["IdToken"] = "urn:ietf:params:oauth:token-type:id_token";
|
|
6439
|
+
/** Indicates that the token is a base64url-encoded SAML 1.1 [OASIS.saml-core-1.1] assertion. */
|
|
6440
|
+
OAuthTokenType["Saml1Token"] = "urn:ietf:params:oauth:token-type:saml1";
|
|
6441
|
+
/** Indicates that the token is a base64url-encoded SAML 2.0 [OASIS.saml-core-2.0-os] assertion. */
|
|
6442
|
+
OAuthTokenType["Saml2Token"] = "urn:ietf:params:oauth:token-type:saml2";
|
|
6443
|
+
})(exports.OAuthTokenType || (exports.OAuthTokenType = {}));
|
|
6392
6444
|
/**
|
|
6393
6445
|
* The MedplumClient class provides a client for the Medplum FHIR server.
|
|
6394
6446
|
*
|
|
@@ -6458,7 +6510,6 @@
|
|
|
6458
6510
|
this.authorizeUrl = options?.authorizeUrl || this.baseUrl + 'oauth2/authorize';
|
|
6459
6511
|
this.tokenUrl = options?.tokenUrl || this.baseUrl + 'oauth2/token';
|
|
6460
6512
|
this.logoutUrl = options?.logoutUrl || this.baseUrl + 'oauth2/logout';
|
|
6461
|
-
this.exchangeUrl = this.baseUrl + 'auth/exchange';
|
|
6462
6513
|
this.onUnauthenticated = options?.onUnauthenticated;
|
|
6463
6514
|
this.cacheTime = options?.cacheTime ?? DEFAULT_CACHE_TIME;
|
|
6464
6515
|
if (this.cacheTime > 0) {
|
|
@@ -6530,7 +6581,7 @@
|
|
|
6530
6581
|
* @param resourceType The resource type to invalidate.
|
|
6531
6582
|
*/
|
|
6532
6583
|
invalidateSearches(resourceType) {
|
|
6533
|
-
const url =
|
|
6584
|
+
const url = this.fhirBaseUrl + resourceType;
|
|
6534
6585
|
if (this.requestCache) {
|
|
6535
6586
|
for (const key of this.requestCache.keys()) {
|
|
6536
6587
|
if (key.endsWith(url) || key.includes(url + '?')) {
|
|
@@ -6808,22 +6859,12 @@
|
|
|
6808
6859
|
if (!clientId) {
|
|
6809
6860
|
throw new Error('MedplumClient is missing clientId');
|
|
6810
6861
|
}
|
|
6811
|
-
const
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
}),
|
|
6818
|
-
credentials: 'include',
|
|
6819
|
-
});
|
|
6820
|
-
if (!response.ok) {
|
|
6821
|
-
this.clearActiveLogin();
|
|
6822
|
-
throw new Error('Failed to fetch tokens');
|
|
6823
|
-
}
|
|
6824
|
-
const tokens = await response.json();
|
|
6825
|
-
await this.verifyTokens(tokens);
|
|
6826
|
-
return this.getProfile();
|
|
6862
|
+
const formBody = new URLSearchParams();
|
|
6863
|
+
formBody.set('grant_type', exports.OAuthGrantType.TokenExchange);
|
|
6864
|
+
formBody.set('subject_token_type', exports.OAuthTokenType.AccessToken);
|
|
6865
|
+
formBody.set('client_id', clientId);
|
|
6866
|
+
formBody.set('subject_token', token);
|
|
6867
|
+
return this.fetchTokens(formBody);
|
|
6827
6868
|
}
|
|
6828
6869
|
/**
|
|
6829
6870
|
* Builds the external identity provider redirect URI.
|
|
@@ -7655,7 +7696,7 @@
|
|
|
7655
7696
|
* @returns The FHIR batch/transaction response bundle.
|
|
7656
7697
|
*/
|
|
7657
7698
|
executeBatch(bundle) {
|
|
7658
|
-
return this.post(
|
|
7699
|
+
return this.post(this.fhirBaseUrl.slice(0, -1), bundle);
|
|
7659
7700
|
}
|
|
7660
7701
|
/**
|
|
7661
7702
|
* Sends an email using the Medplum Email API.
|
|
@@ -7999,7 +8040,7 @@
|
|
|
7999
8040
|
})),
|
|
8000
8041
|
};
|
|
8001
8042
|
// Execute the batch request
|
|
8002
|
-
const response = (await this.post(
|
|
8043
|
+
const response = (await this.post(this.fhirBaseUrl.slice(0, -1), batch));
|
|
8003
8044
|
// Process the response
|
|
8004
8045
|
for (let i = 0; i < entries.length; i++) {
|
|
8005
8046
|
const entry = entries[i];
|
|
@@ -8127,7 +8168,7 @@
|
|
|
8127
8168
|
*/
|
|
8128
8169
|
processCode(code, loginParams) {
|
|
8129
8170
|
const formBody = new URLSearchParams();
|
|
8130
|
-
formBody.set('grant_type',
|
|
8171
|
+
formBody.set('grant_type', exports.OAuthGrantType.AuthorizationCode);
|
|
8131
8172
|
formBody.set('code', code);
|
|
8132
8173
|
formBody.set('client_id', loginParams?.clientId || this.clientId);
|
|
8133
8174
|
formBody.set('redirect_uri', loginParams?.redirectUri || getWindowOrigin());
|
|
@@ -8149,7 +8190,7 @@
|
|
|
8149
8190
|
}
|
|
8150
8191
|
if (this.refreshToken) {
|
|
8151
8192
|
const formBody = new URLSearchParams();
|
|
8152
|
-
formBody.set('grant_type',
|
|
8193
|
+
formBody.set('grant_type', exports.OAuthGrantType.RefreshToken);
|
|
8153
8194
|
formBody.set('client_id', this.clientId);
|
|
8154
8195
|
formBody.set('refresh_token', this.refreshToken);
|
|
8155
8196
|
this.refreshPromise = this.fetchTokens(formBody);
|
|
@@ -8173,7 +8214,7 @@
|
|
|
8173
8214
|
this.clientId = clientId;
|
|
8174
8215
|
this.clientSecret = clientSecret;
|
|
8175
8216
|
const formBody = new URLSearchParams();
|
|
8176
|
-
formBody.set('grant_type',
|
|
8217
|
+
formBody.set('grant_type', exports.OAuthGrantType.ClientCredentials);
|
|
8177
8218
|
formBody.set('client_id', clientId);
|
|
8178
8219
|
formBody.set('client_secret', clientSecret);
|
|
8179
8220
|
return this.fetchTokens(formBody);
|
|
@@ -12278,7 +12319,18 @@
|
|
|
12278
12319
|
* @returns A parsed SearchRequest.
|
|
12279
12320
|
*/
|
|
12280
12321
|
function parseSearchRequest(resourceType, query) {
|
|
12281
|
-
|
|
12322
|
+
const queryArray = [];
|
|
12323
|
+
for (const [key, value] of Object.entries(query)) {
|
|
12324
|
+
if (Array.isArray(value)) {
|
|
12325
|
+
for (let i = 0; i < value.length; i++) {
|
|
12326
|
+
queryArray.push([key, value[i]]);
|
|
12327
|
+
}
|
|
12328
|
+
}
|
|
12329
|
+
else {
|
|
12330
|
+
queryArray.push([key, value || '']);
|
|
12331
|
+
}
|
|
12332
|
+
}
|
|
12333
|
+
return parseSearchImpl(resourceType, queryArray);
|
|
12282
12334
|
}
|
|
12283
12335
|
/**
|
|
12284
12336
|
* Parses a search URL into a search request.
|
|
@@ -12287,7 +12339,7 @@
|
|
|
12287
12339
|
*/
|
|
12288
12340
|
function parseSearchUrl(url) {
|
|
12289
12341
|
const resourceType = url.pathname.split('/').filter(Boolean).pop();
|
|
12290
|
-
return parseSearchImpl(resourceType,
|
|
12342
|
+
return parseSearchImpl(resourceType, url.searchParams.entries());
|
|
12291
12343
|
}
|
|
12292
12344
|
/**
|
|
12293
12345
|
* Parses a URL string into a SearchRequest.
|
|
@@ -12301,13 +12353,8 @@
|
|
|
12301
12353
|
const searchRequest = {
|
|
12302
12354
|
resourceType,
|
|
12303
12355
|
};
|
|
12304
|
-
for (const [key, value] of
|
|
12305
|
-
|
|
12306
|
-
value.forEach((element) => parseKeyValue(searchRequest, key, element));
|
|
12307
|
-
}
|
|
12308
|
-
else {
|
|
12309
|
-
parseKeyValue(searchRequest, key, value ?? '');
|
|
12310
|
-
}
|
|
12356
|
+
for (const [key, value] of query) {
|
|
12357
|
+
parseKeyValue(searchRequest, key, value);
|
|
12311
12358
|
}
|
|
12312
12359
|
return searchRequest;
|
|
12313
12360
|
}
|
|
@@ -12708,6 +12755,7 @@
|
|
|
12708
12755
|
exports.UnaryOperatorAtom = UnaryOperatorAtom;
|
|
12709
12756
|
exports.UnionAtom = UnionAtom;
|
|
12710
12757
|
exports.XorAtom = XorAtom;
|
|
12758
|
+
exports.accepted = accepted;
|
|
12711
12759
|
exports.allOk = allOk;
|
|
12712
12760
|
exports.arrayBufferToBase64 = arrayBufferToBase64;
|
|
12713
12761
|
exports.arrayBufferToHex = arrayBufferToHex;
|