@health-samurai/aidbox-client 0.0.0-alpha.3 → 0.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -253,12 +253,74 @@ Both methods can throw the `RequestError` class if the error happened before the
253
253
 
254
254
  ## Authentication Providers
255
255
 
256
- Authentication is managed via the `AuthProvider` interface.
256
+ Authentication is managed via the `AuthProvider` interface. The client ships with three built-in providers:
257
257
 
258
- Currently, the client only provides a `BrowserAuthProvider` class.
259
- It is suitable for usage in browsers, but other environments may require a different method.
258
+ | Provider | Environment | Auth Method |
259
+ |----------|-------------|-------------|
260
+ | `BrowserAuthProvider` | Browser | Cookie-based sessions |
261
+ | `BasicAuthProvider` | Any | HTTP Basic Auth |
262
+ | `SmartBackendServicesAuthProvider` | Server-side | OAuth 2.0 client_credentials with JWT bearer |
260
263
 
261
- Thus, an application can describe its own Auth Provider by implementing a class that implements `AuthProvider`:
264
+ ### BrowserAuthProvider
265
+
266
+ For browser applications. Uses cookie-based sessions and redirects to the login page on 401.
267
+
268
+ ```typescript
269
+ import { AidboxClient, BrowserAuthProvider } from "@health-samurai/aidbox-client";
270
+
271
+ const baseUrl = "https://fhir-server.address";
272
+ const client = new AidboxClient(baseUrl, new BrowserAuthProvider(baseUrl));
273
+ ```
274
+
275
+ ### BasicAuthProvider
276
+
277
+ For server-side applications using HTTP Basic Auth.
278
+
279
+ ```typescript
280
+ import { AidboxClient, BasicAuthProvider } from "@health-samurai/aidbox-client";
281
+
282
+ const baseUrl = "https://fhir-server.address";
283
+ const client = new AidboxClient(
284
+ baseUrl,
285
+ new BasicAuthProvider(baseUrl, "username", "password"),
286
+ );
287
+ ```
288
+
289
+ ### SmartBackendServicesAuthProvider
290
+
291
+ For server-to-server authentication using [SMART Backend Services](https://www.hl7.org/fhir/smart-app-launch/backend-services.html) (OAuth 2.0 client_credentials grant with JWT bearer assertion).
292
+
293
+ Features:
294
+ - Token caching with proactive refresh before expiry
295
+ - Thundering herd prevention — concurrent requests share a single token fetch
296
+ - Automatic retry on 401 with fresh token
297
+ - OAuth2 discovery from `.well-known/smart-configuration`
298
+
299
+ ```typescript
300
+ import { AidboxClient, SmartBackendServicesAuthProvider } from "@health-samurai/aidbox-client";
301
+
302
+ // Generate or import your private key using Web Crypto API
303
+ const privateKey = await crypto.subtle.generateKey(
304
+ { name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-384" },
305
+ true,
306
+ ["sign", "verify"]
307
+ ).then(kp => kp.privateKey);
308
+
309
+ const auth = new SmartBackendServicesAuthProvider({
310
+ baseUrl: "https://fhir-server.address",
311
+ clientId: "my-service",
312
+ privateKey: privateKey, // CryptoKey from Web Crypto API
313
+ keyId: "key-001", // Must match kid in JWKS
314
+ scope: "system/*.read",
315
+ // tokenExpirationBuffer: 30, // Optional: seconds before expiry to refresh (default: 30)
316
+ });
317
+
318
+ const client = new AidboxClient("https://fhir-server.address", auth);
319
+ ```
320
+
321
+ ### Custom Auth Provider
322
+
323
+ For other authentication methods, implement the `AuthProvider` interface:
262
324
 
263
325
  ```typescript
264
326
  import type { AuthProvider } from "@health-samurai/aidbox-client";
@@ -267,30 +329,31 @@ export class CustomAuthProvider implements AuthProvider {
267
329
  public baseUrl: string;
268
330
 
269
331
  constructor(baseUrl: string) {
270
- this.baseUrl = baseUrl;
332
+ this.baseUrl = baseUrl;
271
333
  }
272
334
 
273
335
  public async establishSession() {
274
- /* code to establish a session */
336
+ /* code to establish a session */
275
337
  }
276
338
 
277
339
  public async revokeSession() {
278
- /* code to revoke the session */
340
+ /* code to revoke the session */
279
341
  }
280
342
 
343
+ /**
344
+ * A wrapper around the `fetch` function, that does all the
345
+ * necessary preparations and argument patching required for the
346
+ * request to go through.
347
+ *
348
+ * Optionally, security checks can be implemented, like verifying
349
+ * that the request indeed goes to the `baseUrl`, and not
350
+ * somewhere else.
351
+ */
281
352
  public async fetch(
282
- input: RequestInfo | URL,
283
- init?: RequestInit,
353
+ input: RequestInfo | URL,
354
+ init?: RequestInit,
284
355
  ): Promise<Response> {
285
- /**
286
- * A wrapper around the `fetch` function, that does all the
287
- * necessary preparations and argument patching required for the
288
- * request to go through.
289
- *
290
- * Optionally, security checks can be implemented, like verifying
291
- * that the request indeed goes to the `baseUrl`, and not
292
- * somewhere else.
293
- */
356
+ /* ... */
294
357
  }
295
358
  }
296
359
  ```
@@ -20,4 +20,13 @@ export declare class BrowserAuthProvider implements AuthProvider {
20
20
  */
21
21
  fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
22
22
  }
23
+ export declare class BasicAuthProvider implements AuthProvider {
24
+ #private;
25
+ /** @ignore */
26
+ baseUrl: string;
27
+ constructor(baseUrl: string, username: string, password: string);
28
+ establishSession(): Promise<void>;
29
+ revokeSession(): Promise<void>;
30
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
31
+ }
23
32
  //# sourceMappingURL=auth-providers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-providers.d.ts","sourceRoot":"","sources":["../../src/auth-providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,qBAAa,mBAAoB,YAAW,YAAY;;IACvD,cAAc;IACP,OAAO,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM;IAgB3B;;OAEG;IACU,gBAAgB;IAQ7B;;OAEG;IACU,aAAa;IAW1B;;;;;OAKG;IACU,KAAK,CACjB,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,QAAQ,CAAC;CAsBpB"}
1
+ {"version":3,"file":"auth-providers.d.ts","sourceRoot":"","sources":["../../src/auth-providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C,qBAAa,mBAAoB,YAAW,YAAY;;IACvD,cAAc;IACP,OAAO,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM;IAgB3B;;OAEG;IACU,gBAAgB;IAQ7B;;OAEG;IACU,aAAa;IAW1B;;;;;OAKG;IACU,KAAK,CACjB,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,QAAQ,CAAC;CAepB;AAED,qBAAa,iBAAkB,YAAW,YAAY;;IACrD,cAAc;IACP,OAAO,EAAE,MAAM,CAAC;gBAGX,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IASlD,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B,KAAK,CACjB,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,QAAQ,CAAC;CAcpB"}
@@ -1,3 +1,11 @@
1
+ function _array_like_to_array(arr, len) {
2
+ if (len == null || len > arr.length) len = arr.length;
3
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4
+ return arr2;
5
+ }
6
+ function _array_without_holes(arr) {
7
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
8
+ }
1
9
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
10
  try {
3
11
  var info = gen[key](arg);
@@ -32,11 +40,46 @@ function _check_private_redeclaration(obj, privateCollection) {
32
40
  throw new TypeError("Cannot initialize the same private elements twice on an object");
33
41
  }
34
42
  }
43
+ function _class_apply_descriptor_get(receiver, descriptor) {
44
+ if (descriptor.get) {
45
+ return descriptor.get.call(receiver);
46
+ }
47
+ return descriptor.value;
48
+ }
49
+ function _class_apply_descriptor_set(receiver, descriptor, value) {
50
+ if (descriptor.set) {
51
+ descriptor.set.call(receiver, value);
52
+ } else {
53
+ if (!descriptor.writable) {
54
+ throw new TypeError("attempted to set read only private field");
55
+ }
56
+ descriptor.value = value;
57
+ }
58
+ }
35
59
  function _class_call_check(instance, Constructor) {
36
60
  if (!(instance instanceof Constructor)) {
37
61
  throw new TypeError("Cannot call a class as a function");
38
62
  }
39
63
  }
64
+ function _class_extract_field_descriptor(receiver, privateMap, action) {
65
+ if (!privateMap.has(receiver)) {
66
+ throw new TypeError("attempted to " + action + " private field on non-instance");
67
+ }
68
+ return privateMap.get(receiver);
69
+ }
70
+ function _class_private_field_get(receiver, privateMap) {
71
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
72
+ return _class_apply_descriptor_get(receiver, descriptor);
73
+ }
74
+ function _class_private_field_init(obj, privateMap, value) {
75
+ _check_private_redeclaration(obj, privateMap);
76
+ privateMap.set(obj, value);
77
+ }
78
+ function _class_private_field_set(receiver, privateMap, value) {
79
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
80
+ _class_apply_descriptor_set(receiver, descriptor, value);
81
+ return value;
82
+ }
40
83
  function _class_private_method_get(receiver, privateSet, fn) {
41
84
  if (!privateSet.has(receiver)) {
42
85
  throw new TypeError("attempted to get private field on non-instance");
@@ -81,6 +124,23 @@ function _instanceof(left, right) {
81
124
  return left instanceof right;
82
125
  }
83
126
  }
127
+ function _iterable_to_array(iter) {
128
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
129
+ }
130
+ function _non_iterable_spread() {
131
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
132
+ }
133
+ function _to_consumable_array(arr) {
134
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
135
+ }
136
+ function _unsupported_iterable_to_array(o, minLen) {
137
+ if (!o) return;
138
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
139
+ var n = Object.prototype.toString.call(o).slice(8, -1);
140
+ if (n === "Object" && o.constructor) n = o.constructor.name;
141
+ if (n === "Map" || n === "Set") return Array.from(n);
142
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
143
+ }
84
144
  function _ts_generator(thisArg, body) {
85
145
  var f, y, t, _ = {
86
146
  label: 0,
@@ -172,6 +232,7 @@ function _ts_generator(thisArg, body) {
172
232
  };
173
233
  }
174
234
  }
235
+ import { mergeHeaders, validateBaseUrl } from "./utils";
175
236
  var _checkSession = /*#__PURE__*/ new WeakSet();
176
237
  export var BrowserAuthProvider = /*#__PURE__*/ function() {
177
238
  "use strict";
@@ -249,18 +310,16 @@ export var BrowserAuthProvider = /*#__PURE__*/ function() {
249
310
  * Accepts the same arguments as `fetch`.
250
311
  */ function fetch1(input, init) {
251
312
  return _async_to_generator(function() {
252
- var url, i, response;
313
+ var requestInit, response;
253
314
  return _ts_generator(this, function(_state) {
254
315
  switch(_state.label){
255
316
  case 0:
256
- if (_instanceof(input, Request)) url = input.url;
257
- else url = input.toString();
258
- if (!url.startsWith(this.baseUrl)) throw Error("url of the request must start with baseUrl");
259
- i = init !== null && init !== void 0 ? init : {};
260
- i.credentials = "include";
317
+ validateBaseUrl(input, this.baseUrl);
318
+ requestInit = init !== null && init !== void 0 ? init : {};
319
+ requestInit.credentials = "include";
261
320
  return [
262
321
  4,
263
- fetch(input, i)
322
+ fetch(input, requestInit)
264
323
  ];
265
324
  case 1:
266
325
  response = _state.sent();
@@ -291,8 +350,7 @@ export var BrowserAuthProvider = /*#__PURE__*/ function() {
291
350
  }
292
351
  ]);
293
352
  return BrowserAuthProvider;
294
- } // TODO: backend auth provider
295
- ();
353
+ }();
296
354
  function checkSession() {
297
355
  return _async_to_generator(function() {
298
356
  var response;
@@ -320,3 +378,72 @@ function checkSession() {
320
378
  });
321
379
  }).call(this);
322
380
  }
381
+ var _authHeader = /*#__PURE__*/ new WeakMap();
382
+ export var BasicAuthProvider = /*#__PURE__*/ function() {
383
+ "use strict";
384
+ function BasicAuthProvider(baseUrl, username, password) {
385
+ var _String;
386
+ _class_call_check(this, BasicAuthProvider);
387
+ /** @ignore */ _define_property(this, "baseUrl", void 0);
388
+ _class_private_field_init(this, _authHeader, {
389
+ writable: true,
390
+ value: void 0
391
+ });
392
+ this.baseUrl = baseUrl;
393
+ // Create Base64-encoded credentials for Basic Auth header (RFC 7617: UTF-8 encoded)
394
+ var credentials = "".concat(username, ":").concat(password);
395
+ var utf8Bytes = new TextEncoder().encode(credentials);
396
+ var base64 = btoa((_String = String).fromCharCode.apply(_String, _to_consumable_array(utf8Bytes)));
397
+ _class_private_field_set(this, _authHeader, "Basic ".concat(base64));
398
+ }
399
+ _create_class(BasicAuthProvider, [
400
+ {
401
+ key: "establishSession",
402
+ value: function establishSession() {
403
+ return _async_to_generator(function() {
404
+ return _ts_generator(this, function(_state) {
405
+ return [
406
+ 2
407
+ ];
408
+ });
409
+ // No-op for basic auth - credentials are sent with each request
410
+ })();
411
+ }
412
+ },
413
+ {
414
+ key: "revokeSession",
415
+ value: function revokeSession() {
416
+ return _async_to_generator(function() {
417
+ return _ts_generator(this, function(_state) {
418
+ return [
419
+ 2
420
+ ];
421
+ });
422
+ // No-op for basic auth - stateless authentication
423
+ })();
424
+ }
425
+ },
426
+ {
427
+ key: "fetch",
428
+ value: function fetch1(input, init) {
429
+ return _async_to_generator(function() {
430
+ var requestInit, baseHeaders, initHeaders, headers;
431
+ return _ts_generator(this, function(_state) {
432
+ validateBaseUrl(input, this.baseUrl);
433
+ requestInit = init !== null && init !== void 0 ? init : {};
434
+ baseHeaders = _instanceof(input, Request) ? input.headers : undefined;
435
+ initHeaders = requestInit.headers ? new Headers(requestInit.headers) : undefined;
436
+ headers = mergeHeaders(baseHeaders, initHeaders);
437
+ headers.set("Authorization", _class_private_field_get(this, _authHeader));
438
+ requestInit.headers = headers;
439
+ return [
440
+ 2,
441
+ fetch(input, requestInit)
442
+ ];
443
+ });
444
+ }).call(this);
445
+ }
446
+ }
447
+ ]);
448
+ return BasicAuthProvider;
449
+ }();
@@ -4,6 +4,7 @@ export type * from "./fhir-types/hl7-fhir-r4-core";
4
4
  export * from "./fhir-types/hl7-fhir-r4-core";
5
5
  export type * from "./result";
6
6
  export * from "./result";
7
+ export * from "./smart-backend-services";
7
8
  export type * from "./types";
8
9
  export * from "./types";
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,mBAAmB,+BAA+B,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,mBAAmB,UAAU,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,mBAAmB,SAAS,CAAC;AAC7B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,mBAAmB,+BAA+B,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,mBAAmB,UAAU,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,0BAA0B,CAAC;AACzC,mBAAmB,SAAS,CAAC;AAC7B,cAAc,SAAS,CAAC"}
package/dist/src/index.js CHANGED
@@ -2,4 +2,5 @@ export * from "./auth-providers";
2
2
  export * from "./client";
3
3
  export * from "./fhir-types/hl7-fhir-r4-core";
4
4
  export * from "./result";
5
+ export * from "./smart-backend-services";
5
6
  export * from "./types";
@@ -0,0 +1,44 @@
1
+ import type { AuthProvider } from "./types";
2
+ export type SmartBackendServicesConfig = {
3
+ /** FHIR server base URL */
4
+ baseUrl: string;
5
+ /** OAuth 2.0 client ID */
6
+ clientId: string;
7
+ /** Private key for signing JWTs (CryptoKey from Web Crypto API) */
8
+ privateKey: CryptoKey;
9
+ /** Key ID (kid) - must match the kid in JWKS registered on the server */
10
+ keyId: string;
11
+ /** OAuth 2.0 scopes (e.g., "system/*.read") */
12
+ scope: string;
13
+ /** Token expiration buffer in seconds (refresh token this many seconds before expiry, default: 30) */
14
+ tokenExpirationBuffer?: number;
15
+ /** Allow insecure HTTP requests (for testing only, default: false) */
16
+ allowInsecureRequests?: boolean;
17
+ };
18
+ /**
19
+ * SMART Backend Services authentication provider.
20
+ *
21
+ * Implements OAuth 2.0 client_credentials grant with JWT bearer assertion
22
+ * for server-to-server authentication per SMART Backend Services spec.
23
+ *
24
+ * @see https://hl7.org/fhir/smart-app-launch/backend-services.html
25
+ */
26
+ export declare class SmartBackendServicesAuthProvider implements AuthProvider {
27
+ #private;
28
+ baseUrl: string;
29
+ constructor(config: SmartBackendServicesConfig);
30
+ /**
31
+ * Establish session - for Backend Services this means getting a token.
32
+ */
33
+ establishSession(): Promise<void>;
34
+ /**
35
+ * Revoke session - clear cached token.
36
+ */
37
+ revokeSession(): Promise<void>;
38
+ /**
39
+ * Fetch wrapper that adds Bearer token authorization.
40
+ * Automatically obtains token on first request and retries once on 401.
41
+ */
42
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
43
+ }
44
+ //# sourceMappingURL=smart-backend-services.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-backend-services.d.ts","sourceRoot":"","sources":["../../src/smart-backend-services.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C,MAAM,MAAM,0BAA0B,GAAG;IACxC,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,UAAU,EAAE,SAAS,CAAC;IACtB,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,sGAAsG;IACtG,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sEAAsE;IACtE,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAiBF;;;;;;;GAOG;AACH,qBAAa,gCAAiC,YAAW,YAAY;;IAC7D,OAAO,EAAE,MAAM,CAAC;gBAMX,MAAM,EAAE,0BAA0B;IAsJ9C;;OAEG;IACU,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9C;;OAEG;IACU,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3C;;;OAGG;IACU,KAAK,CACjB,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,QAAQ,CAAC;CAwCpB"}
@@ -0,0 +1,685 @@
1
+ function _array_like_to_array(arr, len) {
2
+ if (len == null || len > arr.length) len = arr.length;
3
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4
+ return arr2;
5
+ }
6
+ function _array_with_holes(arr) {
7
+ if (Array.isArray(arr)) return arr;
8
+ }
9
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
10
+ try {
11
+ var info = gen[key](arg);
12
+ var value = info.value;
13
+ } catch (error) {
14
+ reject(error);
15
+ return;
16
+ }
17
+ if (info.done) {
18
+ resolve(value);
19
+ } else {
20
+ Promise.resolve(value).then(_next, _throw);
21
+ }
22
+ }
23
+ function _async_to_generator(fn) {
24
+ return function() {
25
+ var self = this, args = arguments;
26
+ return new Promise(function(resolve, reject) {
27
+ var gen = fn.apply(self, args);
28
+ function _next(value) {
29
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
30
+ }
31
+ function _throw(err) {
32
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
33
+ }
34
+ _next(undefined);
35
+ });
36
+ };
37
+ }
38
+ function _check_private_redeclaration(obj, privateCollection) {
39
+ if (privateCollection.has(obj)) {
40
+ throw new TypeError("Cannot initialize the same private elements twice on an object");
41
+ }
42
+ }
43
+ function _class_apply_descriptor_get(receiver, descriptor) {
44
+ if (descriptor.get) {
45
+ return descriptor.get.call(receiver);
46
+ }
47
+ return descriptor.value;
48
+ }
49
+ function _class_apply_descriptor_set(receiver, descriptor, value) {
50
+ if (descriptor.set) {
51
+ descriptor.set.call(receiver, value);
52
+ } else {
53
+ if (!descriptor.writable) {
54
+ throw new TypeError("attempted to set read only private field");
55
+ }
56
+ descriptor.value = value;
57
+ }
58
+ }
59
+ function _class_call_check(instance, Constructor) {
60
+ if (!(instance instanceof Constructor)) {
61
+ throw new TypeError("Cannot call a class as a function");
62
+ }
63
+ }
64
+ function _class_extract_field_descriptor(receiver, privateMap, action) {
65
+ if (!privateMap.has(receiver)) {
66
+ throw new TypeError("attempted to " + action + " private field on non-instance");
67
+ }
68
+ return privateMap.get(receiver);
69
+ }
70
+ function _class_private_field_get(receiver, privateMap) {
71
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
72
+ return _class_apply_descriptor_get(receiver, descriptor);
73
+ }
74
+ function _class_private_field_init(obj, privateMap, value) {
75
+ _check_private_redeclaration(obj, privateMap);
76
+ privateMap.set(obj, value);
77
+ }
78
+ function _class_private_field_set(receiver, privateMap, value) {
79
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
80
+ _class_apply_descriptor_set(receiver, descriptor, value);
81
+ return value;
82
+ }
83
+ function _class_private_method_get(receiver, privateSet, fn) {
84
+ if (!privateSet.has(receiver)) {
85
+ throw new TypeError("attempted to get private field on non-instance");
86
+ }
87
+ return fn;
88
+ }
89
+ function _class_private_method_init(obj, privateSet) {
90
+ _check_private_redeclaration(obj, privateSet);
91
+ privateSet.add(obj);
92
+ }
93
+ function _defineProperties(target, props) {
94
+ for(var i = 0; i < props.length; i++){
95
+ var descriptor = props[i];
96
+ descriptor.enumerable = descriptor.enumerable || false;
97
+ descriptor.configurable = true;
98
+ if ("value" in descriptor) descriptor.writable = true;
99
+ Object.defineProperty(target, descriptor.key, descriptor);
100
+ }
101
+ }
102
+ function _create_class(Constructor, protoProps, staticProps) {
103
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
104
+ if (staticProps) _defineProperties(Constructor, staticProps);
105
+ return Constructor;
106
+ }
107
+ function _define_property(obj, key, value) {
108
+ if (key in obj) {
109
+ Object.defineProperty(obj, key, {
110
+ value: value,
111
+ enumerable: true,
112
+ configurable: true,
113
+ writable: true
114
+ });
115
+ } else {
116
+ obj[key] = value;
117
+ }
118
+ return obj;
119
+ }
120
+ function _instanceof(left, right) {
121
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
122
+ return !!right[Symbol.hasInstance](left);
123
+ } else {
124
+ return left instanceof right;
125
+ }
126
+ }
127
+ function _iterable_to_array_limit(arr, i) {
128
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
129
+ if (_i == null) return;
130
+ var _arr = [];
131
+ var _n = true;
132
+ var _d = false;
133
+ var _s, _e;
134
+ try {
135
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
136
+ _arr.push(_s.value);
137
+ if (i && _arr.length === i) break;
138
+ }
139
+ } catch (err) {
140
+ _d = true;
141
+ _e = err;
142
+ } finally{
143
+ try {
144
+ if (!_n && _i["return"] != null) _i["return"]();
145
+ } finally{
146
+ if (_d) throw _e;
147
+ }
148
+ }
149
+ return _arr;
150
+ }
151
+ function _non_iterable_rest() {
152
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
153
+ }
154
+ function _object_without_properties(source, excluded) {
155
+ if (source == null) return {};
156
+ var target = _object_without_properties_loose(source, excluded);
157
+ var key, i;
158
+ if (Object.getOwnPropertySymbols) {
159
+ var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
160
+ for(i = 0; i < sourceSymbolKeys.length; i++){
161
+ key = sourceSymbolKeys[i];
162
+ if (excluded.indexOf(key) >= 0) continue;
163
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
164
+ target[key] = source[key];
165
+ }
166
+ }
167
+ return target;
168
+ }
169
+ function _object_without_properties_loose(source, excluded) {
170
+ if (source == null) return {};
171
+ var target = {};
172
+ var sourceKeys = Object.keys(source);
173
+ var key, i;
174
+ for(i = 0; i < sourceKeys.length; i++){
175
+ key = sourceKeys[i];
176
+ if (excluded.indexOf(key) >= 0) continue;
177
+ target[key] = source[key];
178
+ }
179
+ return target;
180
+ }
181
+ function _sliced_to_array(arr, i) {
182
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
183
+ }
184
+ function _unsupported_iterable_to_array(o, minLen) {
185
+ if (!o) return;
186
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
187
+ var n = Object.prototype.toString.call(o).slice(8, -1);
188
+ if (n === "Object" && o.constructor) n = o.constructor.name;
189
+ if (n === "Map" || n === "Set") return Array.from(n);
190
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
191
+ }
192
+ function _ts_generator(thisArg, body) {
193
+ var f, y, t, _ = {
194
+ label: 0,
195
+ sent: function() {
196
+ if (t[0] & 1) throw t[1];
197
+ return t[1];
198
+ },
199
+ trys: [],
200
+ ops: []
201
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
202
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
203
+ return this;
204
+ }), g;
205
+ function verb(n) {
206
+ return function(v) {
207
+ return step([
208
+ n,
209
+ v
210
+ ]);
211
+ };
212
+ }
213
+ function step(op) {
214
+ if (f) throw new TypeError("Generator is already executing.");
215
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
216
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
217
+ if (y = 0, t) op = [
218
+ op[0] & 2,
219
+ t.value
220
+ ];
221
+ switch(op[0]){
222
+ case 0:
223
+ case 1:
224
+ t = op;
225
+ break;
226
+ case 4:
227
+ _.label++;
228
+ return {
229
+ value: op[1],
230
+ done: false
231
+ };
232
+ case 5:
233
+ _.label++;
234
+ y = op[1];
235
+ op = [
236
+ 0
237
+ ];
238
+ continue;
239
+ case 7:
240
+ op = _.ops.pop();
241
+ _.trys.pop();
242
+ continue;
243
+ default:
244
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
245
+ _ = 0;
246
+ continue;
247
+ }
248
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
249
+ _.label = op[1];
250
+ break;
251
+ }
252
+ if (op[0] === 6 && _.label < t[1]) {
253
+ _.label = t[1];
254
+ t = op;
255
+ break;
256
+ }
257
+ if (t && _.label < t[2]) {
258
+ _.label = t[2];
259
+ _.ops.push(op);
260
+ break;
261
+ }
262
+ if (t[2]) _.ops.pop();
263
+ _.trys.pop();
264
+ continue;
265
+ }
266
+ op = body.call(thisArg, _);
267
+ } catch (e) {
268
+ op = [
269
+ 6,
270
+ e
271
+ ];
272
+ y = 0;
273
+ } finally{
274
+ f = t = 0;
275
+ }
276
+ if (op[0] & 5) throw op[1];
277
+ return {
278
+ value: op[0] ? op[1] : void 0,
279
+ done: true
280
+ };
281
+ }
282
+ }
283
+ import * as oauth from "oauth4webapi";
284
+ import { mergeHeaders, validateBaseUrl } from "./utils";
285
+ var _config = /*#__PURE__*/ new WeakMap(), _cachedToken = /*#__PURE__*/ new WeakMap(), _pendingTokenRequest = /*#__PURE__*/ new WeakMap(), _discoverAuthServer = /*#__PURE__*/ new WeakSet(), _requestToken = /*#__PURE__*/ new WeakSet(), _sanitizeTokenResponse = /*#__PURE__*/ new WeakSet(), /**
286
+ * Get valid cached token if not expired, or null if needs refresh.
287
+ */ _getValidCachedToken = /*#__PURE__*/ new WeakSet(), _getAccessToken = /*#__PURE__*/ new WeakSet(), _fetchAndCacheToken = /*#__PURE__*/ new WeakSet();
288
+ /**
289
+ * SMART Backend Services authentication provider.
290
+ *
291
+ * Implements OAuth 2.0 client_credentials grant with JWT bearer assertion
292
+ * for server-to-server authentication per SMART Backend Services spec.
293
+ *
294
+ * @see https://hl7.org/fhir/smart-app-launch/backend-services.html
295
+ */ export var SmartBackendServicesAuthProvider = /*#__PURE__*/ function() {
296
+ "use strict";
297
+ function SmartBackendServicesAuthProvider(config) {
298
+ _class_call_check(this, SmartBackendServicesAuthProvider);
299
+ _class_private_method_init(this, _discoverAuthServer);
300
+ /**
301
+ * Request access token from token endpoint using client_credentials grant.
302
+ */ _class_private_method_init(this, _requestToken);
303
+ /**
304
+ * Fixes "refresh_token" = null which does not work with oauth4webapi
305
+ * Fixed in Aidbox 2601, but kept for backwards compatibility.
306
+ */ _class_private_method_init(this, _sanitizeTokenResponse);
307
+ _class_private_method_init(this, _getValidCachedToken);
308
+ /**
309
+ * Get a valid access token, refreshing if necessary.
310
+ * Deduplicates concurrent requests to prevent thundering herd.
311
+ */ _class_private_method_init(this, _getAccessToken);
312
+ /**
313
+ * Fetch token from server and cache it.
314
+ */ _class_private_method_init(this, _fetchAndCacheToken);
315
+ _define_property(this, "baseUrl", void 0);
316
+ _class_private_field_init(this, _config, {
317
+ writable: true,
318
+ value: void 0
319
+ });
320
+ _class_private_field_init(this, _cachedToken, {
321
+ writable: true,
322
+ value: null
323
+ });
324
+ _class_private_field_init(this, _pendingTokenRequest, {
325
+ writable: true,
326
+ value: null
327
+ });
328
+ this.baseUrl = config.baseUrl;
329
+ var _config_tokenExpirationBuffer, _config_allowInsecureRequests;
330
+ _class_private_field_set(this, _config, {
331
+ baseUrl: config.baseUrl,
332
+ clientId: config.clientId,
333
+ privateKey: config.privateKey,
334
+ keyId: config.keyId,
335
+ scope: config.scope,
336
+ tokenExpirationBuffer: (_config_tokenExpirationBuffer = config.tokenExpirationBuffer) !== null && _config_tokenExpirationBuffer !== void 0 ? _config_tokenExpirationBuffer : 30,
337
+ allowInsecureRequests: (_config_allowInsecureRequests = config.allowInsecureRequests) !== null && _config_allowInsecureRequests !== void 0 ? _config_allowInsecureRequests : false
338
+ });
339
+ }
340
+ _create_class(SmartBackendServicesAuthProvider, [
341
+ {
342
+ key: "establishSession",
343
+ value: /**
344
+ * Establish session - for Backend Services this means getting a token.
345
+ */ function establishSession() {
346
+ return _async_to_generator(function() {
347
+ return _ts_generator(this, function(_state) {
348
+ switch(_state.label){
349
+ case 0:
350
+ return [
351
+ 4,
352
+ _class_private_method_get(this, _getAccessToken, getAccessToken).call(this)
353
+ ];
354
+ case 1:
355
+ _state.sent();
356
+ return [
357
+ 2
358
+ ];
359
+ }
360
+ });
361
+ }).call(this);
362
+ }
363
+ },
364
+ {
365
+ key: "revokeSession",
366
+ value: /**
367
+ * Revoke session - clear cached token.
368
+ */ function revokeSession() {
369
+ return _async_to_generator(function() {
370
+ var pending, e;
371
+ return _ts_generator(this, function(_state) {
372
+ switch(_state.label){
373
+ case 0:
374
+ // Wait for any pending token request to settle before clearing
375
+ pending = _class_private_field_get(this, _pendingTokenRequest);
376
+ if (!pending) return [
377
+ 3,
378
+ 4
379
+ ];
380
+ _state.label = 1;
381
+ case 1:
382
+ _state.trys.push([
383
+ 1,
384
+ 3,
385
+ ,
386
+ 4
387
+ ]);
388
+ return [
389
+ 4,
390
+ pending
391
+ ];
392
+ case 2:
393
+ _state.sent();
394
+ return [
395
+ 3,
396
+ 4
397
+ ];
398
+ case 3:
399
+ e = _state.sent();
400
+ return [
401
+ 3,
402
+ 4
403
+ ];
404
+ case 4:
405
+ _class_private_field_set(this, _cachedToken, null);
406
+ return [
407
+ 2
408
+ ];
409
+ }
410
+ });
411
+ }).call(this);
412
+ }
413
+ },
414
+ {
415
+ key: "fetch",
416
+ value: /**
417
+ * Fetch wrapper that adds Bearer token authorization.
418
+ * Automatically obtains token on first request and retries once on 401.
419
+ */ function fetch1(input, init) {
420
+ return _async_to_generator(function() {
421
+ var accessToken, requestInit, baseHeaders, initHeaders, mergedHeaders, clonedInput, retryBody, _requestInit_body_tee, stream1, stream2, response, newToken;
422
+ return _ts_generator(this, function(_state) {
423
+ switch(_state.label){
424
+ case 0:
425
+ validateBaseUrl(input, this.baseUrl);
426
+ return [
427
+ 4,
428
+ _class_private_method_get(this, _getAccessToken, getAccessToken).call(this)
429
+ ];
430
+ case 1:
431
+ accessToken = _state.sent();
432
+ requestInit = init !== null && init !== void 0 ? init : {};
433
+ baseHeaders = _instanceof(input, Request) ? input.headers : undefined;
434
+ initHeaders = requestInit.headers ? new Headers(requestInit.headers) : undefined;
435
+ mergedHeaders = mergeHeaders(baseHeaders, initHeaders);
436
+ mergedHeaders.set("Authorization", "Bearer ".concat(accessToken));
437
+ requestInit.headers = mergedHeaders;
438
+ // Clone input/body to preserve for potential retry
439
+ clonedInput = _instanceof(input, Request) ? input.clone() : input;
440
+ retryBody = requestInit.body;
441
+ // If body is a ReadableStream, tee it for potential retry
442
+ if (_instanceof(requestInit.body, ReadableStream)) {
443
+ _requestInit_body_tee = _sliced_to_array(requestInit.body.tee(), 2), stream1 = _requestInit_body_tee[0], stream2 = _requestInit_body_tee[1];
444
+ requestInit.body = stream1;
445
+ retryBody = stream2;
446
+ }
447
+ return [
448
+ 4,
449
+ fetch(clonedInput, requestInit)
450
+ ];
451
+ case 2:
452
+ response = _state.sent();
453
+ if (!(response.status === 401)) return [
454
+ 3,
455
+ 5
456
+ ];
457
+ _class_private_field_set(this, _cachedToken, null);
458
+ return [
459
+ 4,
460
+ _class_private_method_get(this, _getAccessToken, getAccessToken).call(this)
461
+ ];
462
+ case 3:
463
+ newToken = _state.sent();
464
+ mergedHeaders.set("Authorization", "Bearer ".concat(newToken));
465
+ if (retryBody !== undefined) {
466
+ requestInit.body = retryBody;
467
+ }
468
+ return [
469
+ 4,
470
+ fetch(input, requestInit)
471
+ ];
472
+ case 4:
473
+ response = _state.sent();
474
+ _state.label = 5;
475
+ case 5:
476
+ return [
477
+ 2,
478
+ response
479
+ ];
480
+ }
481
+ });
482
+ }).call(this);
483
+ }
484
+ }
485
+ ]);
486
+ return SmartBackendServicesAuthProvider;
487
+ }();
488
+ function discoverAuthServer() {
489
+ return _async_to_generator(function() {
490
+ var url, response, metadata;
491
+ return _ts_generator(this, function(_state) {
492
+ switch(_state.label){
493
+ case 0:
494
+ url = new URL(_class_private_field_get(this, _config).baseUrl);
495
+ return [
496
+ 4,
497
+ oauth.discoveryRequest(url, _define_property({
498
+ algorithm: "oauth2"
499
+ }, oauth.allowInsecureRequests, _class_private_field_get(this, _config).allowInsecureRequests))
500
+ ];
501
+ case 1:
502
+ response = _state.sent();
503
+ return [
504
+ 4,
505
+ oauth.processDiscoveryResponse(url, response)
506
+ ];
507
+ case 2:
508
+ metadata = _state.sent();
509
+ if (!metadata.token_endpoint) {
510
+ throw new Error("Discovery response missing token_endpoint");
511
+ }
512
+ return [
513
+ 2,
514
+ metadata
515
+ ];
516
+ }
517
+ });
518
+ }).call(this);
519
+ }
520
+ function requestToken() {
521
+ return _async_to_generator(function() {
522
+ var as, client, privateKey, clientAuth, params, response, sanitizedResponse;
523
+ return _ts_generator(this, function(_state) {
524
+ switch(_state.label){
525
+ case 0:
526
+ return [
527
+ 4,
528
+ _class_private_method_get(this, _discoverAuthServer, discoverAuthServer).call(this)
529
+ ];
530
+ case 1:
531
+ as = _state.sent();
532
+ client = {
533
+ client_id: _class_private_field_get(this, _config).clientId
534
+ };
535
+ privateKey = {
536
+ key: _class_private_field_get(this, _config).privateKey,
537
+ kid: _class_private_field_get(this, _config).keyId
538
+ };
539
+ // Aidbox requires typ: "JWT" in the client assertion JWT header.
540
+ // oauth.modifyAssertion is a Symbol that allows customizing the JWT before signing.
541
+ clientAuth = oauth.PrivateKeyJwt(privateKey, _define_property({}, oauth.modifyAssertion, function(header) {
542
+ header.typ = "JWT";
543
+ }));
544
+ // Request parameters
545
+ params = new URLSearchParams();
546
+ params.set("scope", _class_private_field_get(this, _config).scope);
547
+ return [
548
+ 4,
549
+ oauth.clientCredentialsGrantRequest(as, client, clientAuth, params, _define_property({}, oauth.allowInsecureRequests, _class_private_field_get(this, _config).allowInsecureRequests))
550
+ ];
551
+ case 2:
552
+ response = _state.sent();
553
+ return [
554
+ 4,
555
+ _class_private_method_get(this, _sanitizeTokenResponse, sanitizeTokenResponse).call(this, response)
556
+ ];
557
+ case 3:
558
+ sanitizedResponse = _state.sent();
559
+ return [
560
+ 2,
561
+ oauth.processClientCredentialsResponse(as, client, sanitizedResponse)
562
+ ];
563
+ }
564
+ });
565
+ }).call(this);
566
+ }
567
+ function sanitizeTokenResponse(response) {
568
+ return _async_to_generator(function() {
569
+ var cloned, body, _, sanitized;
570
+ return _ts_generator(this, function(_state) {
571
+ switch(_state.label){
572
+ case 0:
573
+ cloned = response.clone();
574
+ return [
575
+ 4,
576
+ cloned.json()
577
+ ];
578
+ case 1:
579
+ body = _state.sent();
580
+ if (!("refresh_token" in body) || body.refresh_token !== null) {
581
+ return [
582
+ 2,
583
+ response
584
+ ];
585
+ }
586
+ _ = body.refresh_token, sanitized = _object_without_properties(body, [
587
+ "refresh_token"
588
+ ]);
589
+ return [
590
+ 2,
591
+ new Response(JSON.stringify(sanitized), {
592
+ status: response.status,
593
+ statusText: response.statusText,
594
+ headers: response.headers
595
+ })
596
+ ];
597
+ }
598
+ });
599
+ })();
600
+ }
601
+ function getValidCachedToken() {
602
+ if (!_class_private_field_get(this, _cachedToken)) return null;
603
+ var bufferMs = _class_private_field_get(this, _config).tokenExpirationBuffer * 1000;
604
+ if (_class_private_field_get(this, _cachedToken).expiresAt > Date.now() + bufferMs) {
605
+ return _class_private_field_get(this, _cachedToken).accessToken;
606
+ }
607
+ return null;
608
+ }
609
+ function getAccessToken() {
610
+ return _async_to_generator(function() {
611
+ var validToken;
612
+ return _ts_generator(this, function(_state) {
613
+ switch(_state.label){
614
+ case 0:
615
+ validToken = _class_private_method_get(this, _getValidCachedToken, getValidCachedToken).call(this);
616
+ if (validToken) {
617
+ return [
618
+ 2,
619
+ validToken
620
+ ];
621
+ }
622
+ // If a token request is already in progress, wait for it
623
+ if (_class_private_field_get(this, _pendingTokenRequest)) {
624
+ return [
625
+ 2,
626
+ _class_private_field_get(this, _pendingTokenRequest)
627
+ ];
628
+ }
629
+ // Request new token, storing the promise to deduplicate concurrent calls
630
+ _class_private_field_set(this, _pendingTokenRequest, _class_private_method_get(this, _fetchAndCacheToken, fetchAndCacheToken).call(this));
631
+ _state.label = 1;
632
+ case 1:
633
+ _state.trys.push([
634
+ 1,
635
+ ,
636
+ 3,
637
+ 4
638
+ ]);
639
+ return [
640
+ 4,
641
+ _class_private_field_get(this, _pendingTokenRequest)
642
+ ];
643
+ case 2:
644
+ return [
645
+ 2,
646
+ _state.sent()
647
+ ];
648
+ case 3:
649
+ _class_private_field_set(this, _pendingTokenRequest, null);
650
+ return [
651
+ 7
652
+ ];
653
+ case 4:
654
+ return [
655
+ 2
656
+ ];
657
+ }
658
+ });
659
+ }).call(this);
660
+ }
661
+ function fetchAndCacheToken() {
662
+ return _async_to_generator(function() {
663
+ var tokenResponse, now, _tokenResponse_expires_in;
664
+ return _ts_generator(this, function(_state) {
665
+ switch(_state.label){
666
+ case 0:
667
+ return [
668
+ 4,
669
+ _class_private_method_get(this, _requestToken, requestToken).call(this)
670
+ ];
671
+ case 1:
672
+ tokenResponse = _state.sent();
673
+ now = Date.now();
674
+ _class_private_field_set(this, _cachedToken, {
675
+ accessToken: tokenResponse.access_token,
676
+ expiresAt: now + ((_tokenResponse_expires_in = tokenResponse.expires_in) !== null && _tokenResponse_expires_in !== void 0 ? _tokenResponse_expires_in : 300) * 1000
677
+ });
678
+ return [
679
+ 2,
680
+ _class_private_field_get(this, _cachedToken).accessToken
681
+ ];
682
+ }
683
+ });
684
+ }).call(this);
685
+ }
@@ -1,3 +1,13 @@
1
1
  import type { ResponseWithMeta } from "./types";
2
+ /**
3
+ * Validate that fetch input URL starts with baseUrl.
4
+ * Throws if the URL doesn't match baseUrl.
5
+ */
6
+ export declare function validateBaseUrl(input: RequestInfo | URL, baseUrl: string): void;
7
+ /**
8
+ * Merge two Headers objects.
9
+ * Headers from `override` take precedence over `base`.
10
+ */
11
+ export declare function mergeHeaders(base?: Headers, override?: Headers): Headers;
2
12
  export declare const coerceBody: <T>(meta: ResponseWithMeta) => Promise<T>;
3
13
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAYhD,eAAO,MAAM,UAAU,GAAU,CAAC,EAAE,MAAM,gBAAgB,KAAG,OAAO,CAAC,CAAC,CA2BrE,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGhD;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,OAAO,EAAE,MAAM,GACb,IAAI,CAMN;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAYxE;AAWD,eAAO,MAAM,UAAU,GAAU,CAAC,EAAE,MAAM,gBAAgB,KAAG,OAAO,CAAC,CAAC,CA2BrE,CAAC"}
package/dist/src/utils.js CHANGED
@@ -127,6 +127,28 @@ function _ts_generator(thisArg, body) {
127
127
  }
128
128
  import YAML from "yaml";
129
129
  import { ErrorResponse } from "./types";
130
+ /**
131
+ * Validate that fetch input URL starts with baseUrl.
132
+ * Throws if the URL doesn't match baseUrl.
133
+ */ export function validateBaseUrl(input, baseUrl) {
134
+ var url = _instanceof(input, Request) ? input.url : input.toString();
135
+ if (!url.startsWith(baseUrl)) {
136
+ throw new Error("URL of the request must start with baseUrl");
137
+ }
138
+ }
139
+ /**
140
+ * Merge two Headers objects.
141
+ * Headers from `override` take precedence over `base`.
142
+ */ export function mergeHeaders(base, override) {
143
+ var merged = new Headers();
144
+ base === null || base === void 0 ? void 0 : base.forEach(function(value, key) {
145
+ merged.set(key, value);
146
+ });
147
+ override === null || override === void 0 ? void 0 : override.forEach(function(value, key) {
148
+ merged.set(key, value);
149
+ });
150
+ return merged;
151
+ }
130
152
  var normalizeContentType = function(contentType) {
131
153
  var semicolon = contentType.indexOf(";");
132
154
  if (semicolon !== -1) {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=auth-providers.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-providers.test.d.ts","sourceRoot":"","sources":["../../test/auth-providers.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=basic-auth.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"basic-auth.test.d.ts","sourceRoot":"","sources":["../../test/basic-auth.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=smart-backend-services.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-backend-services.test.d.ts","sourceRoot":"","sources":["../../test/smart-backend-services.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../test/utils.test.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@health-samurai/aidbox-client",
3
- "version": "0.0.0-alpha.3",
3
+ "version": "0.0.0-alpha.4",
4
4
  "description": "A client library for communicating with Aidbox",
5
5
  "author": "Health Samurai",
6
6
  "type": "module",
@@ -14,6 +14,7 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@types/json-patch": "^0.0.33",
17
+ "oauth4webapi": "^3.8.3",
17
18
  "yaml": "^2.8.1"
18
19
  },
19
20
  "publishConfig": {