@haau3/sdk 0.2.0 → 0.2.2

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/index.mjs CHANGED
@@ -36,14 +36,45 @@ var APIPromise = class extends Promise {
36
36
  };
37
37
  //#endregion
38
38
  //#region src/errors.ts
39
+ /** The fields {@link Haau3Error.toJSON} copies when they are set, in this order. */
40
+ const LOGGED = [
41
+ "status",
42
+ "reason",
43
+ "retryAfter",
44
+ "attempts",
45
+ "durationMs",
46
+ "requestId",
47
+ "correlationId"
48
+ ];
39
49
  /** What every error this package throws has. */
40
50
  var Haau3Error = class extends Error {
41
51
  name = "Haau3Error";
42
52
  /** The `X-Request-Id` the API sent, when it answered. Quote it when you ask for help. */
43
53
  requestId;
54
+ /** The `correlationId` you sent, as the API returned it in `X-Correlation-Id`, when it answered. */
55
+ correlationId;
44
56
  constructor(message, requestId, options) {
45
- super(message, options);
57
+ super(message, options?.cause === void 0 ? void 0 : { cause: options.cause });
46
58
  this.requestId = requestId;
59
+ this.correlationId = options?.correlationId;
60
+ }
61
+ /**
62
+ * The error as a plain object that is safe to log: its name, its message and every field that is
63
+ * set, and never the body the API answered with (`outcome`, `problem`) or the `cause`.
64
+ * `JSON.stringify(error)` and loggers that call `toJSON` print this.
65
+ *
66
+ * ```ts
67
+ * logger.warn({ error: error.toJSON() }, "the plan read failed");
68
+ * ```
69
+ */
70
+ toJSON() {
71
+ const json = {
72
+ name: this.name,
73
+ message: this.message
74
+ };
75
+ const fields = this;
76
+ for (const key of LOGGED) if (fields[key] !== void 0) json[key] = fields[key];
77
+ return json;
47
78
  }
48
79
  };
49
80
  /**
@@ -70,7 +101,7 @@ var AuthError = class extends Haau3Error {
70
101
  /** Milliseconds from the first attempt to the answer. */
71
102
  durationMs;
72
103
  constructor(message, status, requestId, body, timing) {
73
- super(message, requestId);
104
+ super(message, requestId, { correlationId: timing?.correlationId });
74
105
  this.status = status;
75
106
  this.attempts = timing?.attempts ?? 1;
76
107
  this.durationMs = timing?.durationMs;
@@ -90,7 +121,7 @@ var RefusedError = class extends Haau3Error {
90
121
  /** Milliseconds from the first attempt to the answer. */
91
122
  durationMs;
92
123
  constructor(message, status, requestId, body, timing) {
93
- super(message, requestId);
124
+ super(message, requestId, { correlationId: timing?.correlationId });
94
125
  this.status = status;
95
126
  this.attempts = timing?.attempts ?? 1;
96
127
  this.durationMs = timing?.durationMs;
@@ -113,7 +144,10 @@ var NoAnswerError = class extends Haau3Error {
113
144
  /** Milliseconds from the first attempt to the last failure, waits between attempts included. */
114
145
  durationMs;
115
146
  constructor(message, details) {
116
- super(message, details.requestId, details.cause === void 0 ? void 0 : { cause: details.cause });
147
+ super(message, details.requestId, {
148
+ cause: details.cause,
149
+ correlationId: details.correlationId
150
+ });
117
151
  this.reason = details.reason;
118
152
  this.status = details.status;
119
153
  this.retryAfter = details.retryAfter;
@@ -125,9 +159,14 @@ var NoAnswerError = class extends Haau3Error {
125
159
  //#endregion
126
160
  //#region src/version.ts
127
161
  /** This package's version, sent in the `User-Agent` header. A test holds it to package.json. */
128
- const VERSION = "0.2.0";
162
+ const VERSION = "0.2.2";
129
163
  //#endregion
130
164
  //#region src/transport.ts
165
+ /**
166
+ * The form the API takes for your own request id: a UUID in its usual text form, any version, as the
167
+ * spec's `X-Request-Id` parameter declares (`format: uuid`).
168
+ */
169
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
131
170
  const DEFAULT_BASE_URL = "https://api.haau3.com";
132
171
  const DEFAULT_TIMEOUT = 65e3;
133
172
  const DEFAULT_MAX_RETRIES = 1;
@@ -214,6 +253,85 @@ function noAnswerReason(status) {
214
253
  if (status === 504) return "timeout";
215
254
  return "server-error";
216
255
  }
256
+ /** Appends a query to a URL's parameters: a list sends the parameter once per value, `undefined` sends none. */
257
+ function appendQuery(params, query) {
258
+ for (const [name, value] of Object.entries(query ?? {})) {
259
+ if (value === void 0) continue;
260
+ for (const item of Array.isArray(value) ? value : [value]) params.append(name, String(item));
261
+ }
262
+ }
263
+ /**
264
+ * What one answer means: the answer itself, or the error it is. A single call and each entry of a
265
+ * batch are judged alike. `name` says which request it was, in words that carry no value a caller
266
+ * sent: the method and the operation's path with its `{id}` left in.
267
+ */
268
+ function judge(name, status, body, context) {
269
+ const { requestId, attempts, durationMs, expects } = context;
270
+ const timing = {
271
+ attempts,
272
+ durationMs,
273
+ correlationId: context.correlationId
274
+ };
275
+ if (status >= 200 && status < 300) {
276
+ if (body === void 0) return {
277
+ ok: false,
278
+ error: new NoAnswerError(`${name} answered ${status} with ${context.missing}.`, {
279
+ reason: "unreadable",
280
+ status,
281
+ requestId,
282
+ ...timing
283
+ })
284
+ };
285
+ if (expects && !expects.includes(body?.resourceType)) {
286
+ const wanted = expects.map(withArticle).join(" or ");
287
+ return {
288
+ ok: false,
289
+ error: new NoAnswerError(`${name} answered ${describeAnswer(body)} where ${wanted} was expected.`, {
290
+ reason: "unreadable",
291
+ status,
292
+ requestId,
293
+ ...timing
294
+ })
295
+ };
296
+ }
297
+ return {
298
+ ok: true,
299
+ data: body
300
+ };
301
+ }
302
+ const errorBody = readErrorBody(body);
303
+ if ((status === 401 || status === 403) && !context.entry) return {
304
+ ok: false,
305
+ error: new AuthError(`${name} was refused: the API key was not accepted (${status}).`, status, requestId, errorBody, timing)
306
+ };
307
+ if (status === 429 || status >= 500) {
308
+ const reason = noAnswerReason(status);
309
+ return {
310
+ ok: false,
311
+ error: new NoAnswerError(`${name} got no answer (${reason}, ${status}) after ${attempts} attempt${attempts === 1 ? "" : "s"}.`, {
312
+ reason,
313
+ status,
314
+ retryAfter: context.retryAfter,
315
+ requestId,
316
+ body: errorBody,
317
+ ...timing
318
+ })
319
+ };
320
+ }
321
+ if (status >= 400) return {
322
+ ok: false,
323
+ error: new RefusedError(`${name} was refused (${status}).`, status, requestId, errorBody, timing)
324
+ };
325
+ return {
326
+ ok: false,
327
+ error: new NoAnswerError(`${name} answered ${status}, which is not an answer.`, {
328
+ reason: "unreadable",
329
+ status,
330
+ requestId,
331
+ ...timing
332
+ })
333
+ };
334
+ }
217
335
  /** The connection, retries and errors every operation shares. */
218
336
  var Transport = class {
219
337
  #apiKey;
@@ -252,6 +370,7 @@ var Transport = class {
252
370
  headers: sent.response.headers,
253
371
  body: parseBody(sent.text, sent.response.headers.get("content-type")) ?? sent.text,
254
372
  requestId: sent.response.headers.get("x-request-id") ?? void 0,
373
+ correlationId: sent.response.headers.get("x-correlation-id") ?? void 0,
255
374
  attempts: sent.attempts,
256
375
  durationMs: sent.durationMs
257
376
  };
@@ -284,57 +403,26 @@ var Transport = class {
284
403
  const { response, text, attempts, durationMs } = await this.#send(method, url, body, options, label);
285
404
  const status = response.status;
286
405
  const requestId = response.headers.get("x-request-id") ?? void 0;
287
- const parsed = parseBody(text, response.headers.get("content-type"));
288
- const name = `${method} ${label}`;
289
- const timing = {
290
- attempts,
291
- durationMs
292
- };
293
- if (status >= 200 && status < 300) {
294
- if (parsed === void 0) throw new NoAnswerError(`${name} answered ${status} with a body that is not JSON.`, {
295
- reason: "unreadable",
296
- status,
297
- requestId,
298
- ...timing
299
- });
300
- if (expects && !expects.includes(parsed?.resourceType)) {
301
- const wanted = expects.map(withArticle).join(" or ");
302
- throw new NoAnswerError(`${name} answered ${describeAnswer(parsed)} where ${wanted} was expected.`, {
303
- reason: "unreadable",
304
- status,
305
- requestId,
306
- ...timing
307
- });
308
- }
309
- return {
310
- data: parsed,
311
- requestId,
312
- durationMs,
313
- attempts,
314
- status,
315
- headers: response.headers
316
- };
317
- }
318
- const errorBody = readErrorBody(parsed);
319
- if (status === 401 || status === 403) throw new AuthError(`${name} was refused: the API key was not accepted (${status}).`, status, requestId, errorBody, timing);
320
- if (status === 429 || status >= 500) {
321
- const reason = noAnswerReason(status);
322
- throw new NoAnswerError(`${name} got no answer (${reason}, ${status}) after ${attempts} attempt${attempts === 1 ? "" : "s"}.`, {
323
- reason,
324
- status,
325
- retryAfter: retryAfterSeconds(response.headers),
326
- requestId,
327
- body: errorBody,
328
- ...timing
329
- });
330
- }
331
- if (status >= 400) throw new RefusedError(`${name} was refused (${status}).`, status, requestId, errorBody, timing);
332
- throw new NoAnswerError(`${name} answered ${status}, which is not an answer.`, {
333
- reason: "unreadable",
334
- status,
406
+ const correlationId = response.headers.get("x-correlation-id") ?? void 0;
407
+ const verdict = judge(`${method} ${label}`, status, parseBody(text, response.headers.get("content-type")), {
335
408
  requestId,
336
- ...timing
409
+ correlationId,
410
+ attempts,
411
+ durationMs,
412
+ retryAfter: retryAfterSeconds(response.headers),
413
+ expects,
414
+ missing: "a body that is not JSON"
337
415
  });
416
+ if (!verdict.ok) throw verdict.error;
417
+ return {
418
+ data: verdict.data,
419
+ requestId,
420
+ correlationId,
421
+ durationMs,
422
+ attempts,
423
+ status,
424
+ headers: response.headers
425
+ };
338
426
  }
339
427
  /** A URL on this client's base, refusing any other host so the key is never sent to one. */
340
428
  url(pathOrUrl) {
@@ -344,10 +432,7 @@ var Transport = class {
344
432
  const base = new URL(this.baseURL);
345
433
  const url = /^https?:\/\//i.test(pathOrUrl) ? new URL(pathOrUrl) : new URL(base.pathname.replace(/\/$/, "") + (pathOrUrl.startsWith("/") ? pathOrUrl : `/${pathOrUrl}`), base);
346
434
  if (url.origin !== base.origin) throw new Haau3Error(`Refusing to send the API key to ${url.origin}: the client's baseURL is ${base.origin}.`);
347
- for (const [name, value] of Object.entries(query ?? {})) {
348
- if (value === void 0) continue;
349
- for (const item of Array.isArray(value) ? value : [value]) url.searchParams.append(name, String(item));
350
- }
435
+ appendQuery(url.searchParams, query);
351
436
  return url;
352
437
  }
353
438
  async #send(method, url, body, options, label) {
@@ -363,6 +448,10 @@ var Transport = class {
363
448
  headers["content-type"] = fhir ? FHIR_JSON : "application/json";
364
449
  }
365
450
  for (const [name, value] of Object.entries(options.headers ?? {})) headers[name.toLowerCase()] = value;
451
+ if (options.correlationId !== void 0) {
452
+ if (!UUID.test(options.correlationId)) throw new Haau3Error(`${method} ${label} was not sent: correlationId must be a UUID, which is all the API keeps (it drops anything else).`);
453
+ headers["x-request-id"] = options.correlationId;
454
+ }
366
455
  const timeout = options.timeout ?? this.timeout;
367
456
  const maxRetries = options.maxRetries ?? this.maxRetries;
368
457
  const fetchOptions = {
@@ -420,6 +509,499 @@ var Transport = class {
420
509
  }
421
510
  };
422
511
  //#endregion
512
+ //#region src/batch.ts
513
+ /** What the batch needs from each entry it sends, kept off the entry itself. */
514
+ const made = /* @__PURE__ */ new WeakMap();
515
+ /** An entry for one operation. Called by the generated builder. */
516
+ function entry(call) {
517
+ let path = call.path;
518
+ for (const [name, value] of Object.entries(call.pathParams ?? {})) path = path.replace(`{${name}}`, encodeURIComponent(value));
519
+ const search = new URLSearchParams();
520
+ appendQuery(search, call.query);
521
+ const relative = path.slice(12);
522
+ const query = search.toString();
523
+ const url = query ? `${relative}?${query}` : relative;
524
+ const value = Object.freeze({
525
+ method: call.method,
526
+ url
527
+ });
528
+ made.set(value, {
529
+ label: `${call.method} ${call.path}`,
530
+ resource: call.body,
531
+ expects: call.expects
532
+ });
533
+ return value;
534
+ }
535
+ /** The batch Bundle for these entries. Throws for anything the builder did not make. */
536
+ function batchBundle(entries) {
537
+ if (!Array.isArray(entries)) throw new Haau3Error("batch() takes a function that returns a list of entries made by the builder it is given.");
538
+ return {
539
+ resourceType: "Bundle",
540
+ type: "batch",
541
+ entry: entries.map((value, index) => {
542
+ const internal = typeof value === "object" && value !== null ? made.get(value) : void 0;
543
+ if (!internal) throw new Haau3Error(`Entry ${index + 1} of the batch was not made by the builder batch() hands you.`);
544
+ return {
545
+ request: {
546
+ method: value.method,
547
+ url: value.url
548
+ },
549
+ ...internal.resource !== void 0 ? { resource: internal.resource } : {}
550
+ };
551
+ })
552
+ };
553
+ }
554
+ /** A batch entry's status: "200", or "200 OK" with its reason phrase, as FHIR allows. */
555
+ function entryStatus(entry) {
556
+ const match = /^(\d{3})(?:\s|$)/.exec(entry?.response?.status ?? "");
557
+ return match ? Number(match[1]) : void 0;
558
+ }
559
+ /**
560
+ * Reads a batch-response into one result per entry sent. FHIR R4 says a batch-response holds one
561
+ * entry for each entry of the request, in the same order, so each answer is paired with its request
562
+ * by position. An answer that is not a batch-response, or holds another number of entries, cannot be
563
+ * paired at all and is no answer.
564
+ */
565
+ function readBatch(entries, answer, meta) {
566
+ const { requestId, correlationId, attempts, durationMs, status } = meta;
567
+ const timing = {
568
+ attempts,
569
+ durationMs,
570
+ correlationId
571
+ };
572
+ const answered = answer.entry ?? [];
573
+ if (answer.type !== "batch-response") throw new NoAnswerError(`POST /v1/fhir/r4 answered a Bundle that is not a batch-response.`, {
574
+ reason: "unreadable",
575
+ status,
576
+ requestId,
577
+ ...timing
578
+ });
579
+ if (answered.length !== entries.length) throw new NoAnswerError(`POST /v1/fhir/r4 answered ${answered.length} entries for a batch of ${entries.length}.`, {
580
+ reason: "unreadable",
581
+ status,
582
+ requestId,
583
+ ...timing
584
+ });
585
+ return entries.map((value, index) => {
586
+ const internal = made.get(value);
587
+ const name = `${internal.label} (entry ${index + 1} of ${entries.length})`;
588
+ const answeredEntry = answered[index];
589
+ const entryCode = entryStatus(answeredEntry);
590
+ if (entryCode === void 0) return {
591
+ ok: false,
592
+ error: new NoAnswerError(`${name} answered with no status.`, {
593
+ reason: "unreadable",
594
+ requestId,
595
+ ...timing
596
+ })
597
+ };
598
+ const verdict = judge(name, entryCode, answeredEntry?.resource ?? (entryCode >= 400 ? answeredEntry?.response?.outcome : void 0), {
599
+ requestId,
600
+ correlationId,
601
+ attempts,
602
+ durationMs,
603
+ expects: internal.expects,
604
+ missing: "no resource",
605
+ entry: true
606
+ });
607
+ return verdict.ok ? {
608
+ ok: true,
609
+ data: verdict.data,
610
+ status: entryCode
611
+ } : {
612
+ ok: false,
613
+ error: verdict.error
614
+ };
615
+ });
616
+ }
617
+ //#endregion
618
+ //#region src/generated/batch.ts
619
+ /**
620
+ * Every operation a batch can carry, each called as on {@link Haau3} and returning an entry for the
621
+ * batch instead of sending. Everything on the FHIR base but the batch itself and
622
+ * `reconcileMedications`.
623
+ */
624
+ var BatchBuilder = class {
625
+ /**
626
+ * Check providers against a plan's network, as one entry of a batch. Called as `Haau3.checkInsurancePlanNetwork` is.
627
+ *
628
+ * `GET /v1/fhir/r4/InsurancePlan/{id}/$in-network`
629
+ */
630
+ checkInsurancePlanNetwork(id, params) {
631
+ return entry({
632
+ method: "GET",
633
+ path: "/v1/fhir/r4/InsurancePlan/{id}/$in-network",
634
+ pathParams: { id },
635
+ query: params,
636
+ expects: ["Parameters"]
637
+ });
638
+ }
639
+ /**
640
+ * Look up a code, as one entry of a batch. Called as `Haau3.codeSystemLookup` is.
641
+ *
642
+ * `GET /v1/fhir/r4/CodeSystem/$lookup`
643
+ */
644
+ codeSystemLookup(params) {
645
+ return entry({
646
+ method: "GET",
647
+ path: "/v1/fhir/r4/CodeSystem/$lookup",
648
+ query: params,
649
+ expects: ["Parameters"]
650
+ });
651
+ }
652
+ /**
653
+ * Look up a code, as one entry of a batch. Called as `Haau3.codeSystemLookupPost` is.
654
+ *
655
+ * `POST /v1/fhir/r4/CodeSystem/$lookup`
656
+ */
657
+ codeSystemLookupPost(body) {
658
+ return entry({
659
+ method: "POST",
660
+ path: "/v1/fhir/r4/CodeSystem/$lookup",
661
+ body,
662
+ expects: ["Parameters"]
663
+ });
664
+ }
665
+ /**
666
+ * Validate a code in a code system, as one entry of a batch. Called as `Haau3.codeSystemValidateCode` is.
667
+ *
668
+ * `GET /v1/fhir/r4/CodeSystem/$validate-code`
669
+ */
670
+ codeSystemValidateCode(params) {
671
+ return entry({
672
+ method: "GET",
673
+ path: "/v1/fhir/r4/CodeSystem/$validate-code",
674
+ query: params,
675
+ expects: ["Parameters"]
676
+ });
677
+ }
678
+ /**
679
+ * Validate a code in a code system, as one entry of a batch. Called as `Haau3.codeSystemValidateCodePost` is.
680
+ *
681
+ * `POST /v1/fhir/r4/CodeSystem/$validate-code`
682
+ */
683
+ codeSystemValidateCodePost(body) {
684
+ return entry({
685
+ method: "POST",
686
+ path: "/v1/fhir/r4/CodeSystem/$validate-code",
687
+ body,
688
+ expects: ["Parameters"]
689
+ });
690
+ }
691
+ /**
692
+ * Capability statement, as one entry of a batch. Called as `Haau3.fhirMetadata` is.
693
+ *
694
+ * `GET /v1/fhir/r4/metadata`
695
+ */
696
+ fhirMetadata(params) {
697
+ return entry({
698
+ method: "GET",
699
+ path: "/v1/fhir/r4/metadata",
700
+ query: params,
701
+ expects: ["CapabilityStatement", "TerminologyCapabilities"]
702
+ });
703
+ }
704
+ /**
705
+ * List a state's counties, as one entry of a batch. Called as `Haau3.listInsurancePlanCounties` is.
706
+ *
707
+ * `GET /v1/fhir/r4/InsurancePlan/$counties`
708
+ */
709
+ listInsurancePlanCounties(params) {
710
+ return entry({
711
+ method: "GET",
712
+ path: "/v1/fhir/r4/InsurancePlan/$counties",
713
+ query: params,
714
+ expects: ["Parameters"]
715
+ });
716
+ }
717
+ /**
718
+ * Read an Endpoint, as one entry of a batch. Called as `Haau3.readEndpoint` is.
719
+ *
720
+ * `GET /v1/fhir/r4/Endpoint/{id}`
721
+ */
722
+ readEndpoint(id) {
723
+ return entry({
724
+ method: "GET",
725
+ path: "/v1/fhir/r4/Endpoint/{id}",
726
+ pathParams: { id },
727
+ expects: ["Endpoint"]
728
+ });
729
+ }
730
+ /**
731
+ * Read a HealthcareService, as one entry of a batch. Called as `Haau3.readHealthcareService` is.
732
+ *
733
+ * `GET /v1/fhir/r4/HealthcareService/{id}`
734
+ */
735
+ readHealthcareService(id) {
736
+ return entry({
737
+ method: "GET",
738
+ path: "/v1/fhir/r4/HealthcareService/{id}",
739
+ pathParams: { id },
740
+ expects: ["HealthcareService"]
741
+ });
742
+ }
743
+ /**
744
+ * Read a plan, as one entry of a batch. Called as `Haau3.readInsurancePlan` is.
745
+ *
746
+ * `GET /v1/fhir/r4/InsurancePlan/{id}`
747
+ */
748
+ readInsurancePlan(id) {
749
+ return entry({
750
+ method: "GET",
751
+ path: "/v1/fhir/r4/InsurancePlan/{id}",
752
+ pathParams: { id },
753
+ expects: ["InsurancePlan"]
754
+ });
755
+ }
756
+ /**
757
+ * Read a Location, as one entry of a batch. Called as `Haau3.readLocation` is.
758
+ *
759
+ * `GET /v1/fhir/r4/Location/{id}`
760
+ */
761
+ readLocation(id) {
762
+ return entry({
763
+ method: "GET",
764
+ path: "/v1/fhir/r4/Location/{id}",
765
+ pathParams: { id },
766
+ expects: ["Location"]
767
+ });
768
+ }
769
+ /**
770
+ * Read an Organization, as one entry of a batch. Called as `Haau3.readOrganization` is.
771
+ *
772
+ * `GET /v1/fhir/r4/Organization/{id}`
773
+ */
774
+ readOrganization(id) {
775
+ return entry({
776
+ method: "GET",
777
+ path: "/v1/fhir/r4/Organization/{id}",
778
+ pathParams: { id },
779
+ expects: ["Organization"]
780
+ });
781
+ }
782
+ /**
783
+ * Read an OrganizationAffiliation, as one entry of a batch. Called as `Haau3.readOrganizationAffiliation` is.
784
+ *
785
+ * `GET /v1/fhir/r4/OrganizationAffiliation/{id}`
786
+ */
787
+ readOrganizationAffiliation(id) {
788
+ return entry({
789
+ method: "GET",
790
+ path: "/v1/fhir/r4/OrganizationAffiliation/{id}",
791
+ pathParams: { id },
792
+ expects: ["OrganizationAffiliation"]
793
+ });
794
+ }
795
+ /**
796
+ * Read a Practitioner, as one entry of a batch. Called as `Haau3.readPractitioner` is.
797
+ *
798
+ * `GET /v1/fhir/r4/Practitioner/{id}`
799
+ */
800
+ readPractitioner(id) {
801
+ return entry({
802
+ method: "GET",
803
+ path: "/v1/fhir/r4/Practitioner/{id}",
804
+ pathParams: { id },
805
+ expects: ["Practitioner"]
806
+ });
807
+ }
808
+ /**
809
+ * Read a PractitionerRole, as one entry of a batch. Called as `Haau3.readPractitionerRole` is.
810
+ *
811
+ * `GET /v1/fhir/r4/PractitionerRole/{id}`
812
+ */
813
+ readPractitionerRole(id) {
814
+ return entry({
815
+ method: "GET",
816
+ path: "/v1/fhir/r4/PractitionerRole/{id}",
817
+ pathParams: { id },
818
+ expects: ["PractitionerRole"]
819
+ });
820
+ }
821
+ /**
822
+ * Read a questionnaire, as one entry of a batch. Called as `Haau3.readQuestionnaire` is.
823
+ *
824
+ * `GET /v1/fhir/r4/Questionnaire/{id}`
825
+ */
826
+ readQuestionnaire(id) {
827
+ return entry({
828
+ method: "GET",
829
+ path: "/v1/fhir/r4/Questionnaire/{id}",
830
+ pathParams: { id },
831
+ expects: ["Questionnaire"]
832
+ });
833
+ }
834
+ /**
835
+ * Find endpoints, as one entry of a batch. Called as `Haau3.searchEndpoint` is.
836
+ *
837
+ * `GET /v1/fhir/r4/Endpoint`
838
+ */
839
+ searchEndpoint(params) {
840
+ return entry({
841
+ method: "GET",
842
+ path: "/v1/fhir/r4/Endpoint",
843
+ query: params,
844
+ expects: ["Bundle"]
845
+ });
846
+ }
847
+ /**
848
+ * Find healthcare services, as one entry of a batch. Called as `Haau3.searchHealthcareService` is.
849
+ *
850
+ * `GET /v1/fhir/r4/HealthcareService`
851
+ */
852
+ searchHealthcareService(params) {
853
+ return entry({
854
+ method: "GET",
855
+ path: "/v1/fhir/r4/HealthcareService",
856
+ query: params,
857
+ expects: ["Bundle"]
858
+ });
859
+ }
860
+ /**
861
+ * Find a plan, as one entry of a batch. Called as `Haau3.searchInsurancePlan` is.
862
+ *
863
+ * `GET /v1/fhir/r4/InsurancePlan`
864
+ */
865
+ searchInsurancePlan(params) {
866
+ return entry({
867
+ method: "GET",
868
+ path: "/v1/fhir/r4/InsurancePlan",
869
+ query: params,
870
+ expects: ["Bundle"]
871
+ });
872
+ }
873
+ /**
874
+ * Find practice locations, as one entry of a batch. Called as `Haau3.searchLocation` is.
875
+ *
876
+ * `GET /v1/fhir/r4/Location`
877
+ */
878
+ searchLocation(params) {
879
+ return entry({
880
+ method: "GET",
881
+ path: "/v1/fhir/r4/Location",
882
+ query: params,
883
+ expects: ["Bundle"]
884
+ });
885
+ }
886
+ /**
887
+ * Find organizations, payers and networks, as one entry of a batch. Called as `Haau3.searchOrganization` is.
888
+ *
889
+ * `GET /v1/fhir/r4/Organization`
890
+ */
891
+ searchOrganization(params) {
892
+ return entry({
893
+ method: "GET",
894
+ path: "/v1/fhir/r4/Organization",
895
+ query: params,
896
+ expects: ["Bundle"]
897
+ });
898
+ }
899
+ /**
900
+ * Find the organizations in a network, as one entry of a batch. Called as `Haau3.searchOrganizationAffiliation` is.
901
+ *
902
+ * `GET /v1/fhir/r4/OrganizationAffiliation`
903
+ */
904
+ searchOrganizationAffiliation(params) {
905
+ return entry({
906
+ method: "GET",
907
+ path: "/v1/fhir/r4/OrganizationAffiliation",
908
+ query: params,
909
+ expects: ["Bundle"]
910
+ });
911
+ }
912
+ /**
913
+ * Find a practitioner by NPI or name, as one entry of a batch. Called as `Haau3.searchPractitioner` is.
914
+ *
915
+ * `GET /v1/fhir/r4/Practitioner`
916
+ */
917
+ searchPractitioner(params) {
918
+ return entry({
919
+ method: "GET",
920
+ path: "/v1/fhir/r4/Practitioner",
921
+ query: params,
922
+ expects: ["Bundle"]
923
+ });
924
+ }
925
+ /**
926
+ * Find practitioner roles, as one entry of a batch. Called as `Haau3.searchPractitionerRole` is.
927
+ *
928
+ * `GET /v1/fhir/r4/PractitionerRole`
929
+ */
930
+ searchPractitionerRole(params) {
931
+ return entry({
932
+ method: "GET",
933
+ path: "/v1/fhir/r4/PractitionerRole",
934
+ query: params,
935
+ expects: ["Bundle"]
936
+ });
937
+ }
938
+ /**
939
+ * List or find a questionnaire, as one entry of a batch. Called as `Haau3.searchQuestionnaire` is.
940
+ *
941
+ * `GET /v1/fhir/r4/Questionnaire`
942
+ */
943
+ searchQuestionnaire(params) {
944
+ return entry({
945
+ method: "GET",
946
+ path: "/v1/fhir/r4/Questionnaire",
947
+ query: params,
948
+ expects: ["Bundle"]
949
+ });
950
+ }
951
+ /**
952
+ * Expand a value set, as one entry of a batch. Called as `Haau3.valueSetExpand` is.
953
+ *
954
+ * `GET /v1/fhir/r4/ValueSet/$expand`
955
+ */
956
+ valueSetExpand(params) {
957
+ return entry({
958
+ method: "GET",
959
+ path: "/v1/fhir/r4/ValueSet/$expand",
960
+ query: params,
961
+ expects: ["ValueSet"]
962
+ });
963
+ }
964
+ /**
965
+ * Expand a value set, as one entry of a batch. Called as `Haau3.valueSetExpandPost` is.
966
+ *
967
+ * `POST /v1/fhir/r4/ValueSet/$expand`
968
+ */
969
+ valueSetExpandPost(body) {
970
+ return entry({
971
+ method: "POST",
972
+ path: "/v1/fhir/r4/ValueSet/$expand",
973
+ body,
974
+ expects: ["ValueSet"]
975
+ });
976
+ }
977
+ /**
978
+ * Validate a code against a value set, as one entry of a batch. Called as `Haau3.valueSetValidateCode` is.
979
+ *
980
+ * `GET /v1/fhir/r4/ValueSet/$validate-code`
981
+ */
982
+ valueSetValidateCode(params) {
983
+ return entry({
984
+ method: "GET",
985
+ path: "/v1/fhir/r4/ValueSet/$validate-code",
986
+ query: params,
987
+ expects: ["Parameters"]
988
+ });
989
+ }
990
+ /**
991
+ * Validate a code against a value set, as one entry of a batch. Called as `Haau3.valueSetValidateCodePost` is.
992
+ *
993
+ * `POST /v1/fhir/r4/ValueSet/$validate-code`
994
+ */
995
+ valueSetValidateCodePost(body) {
996
+ return entry({
997
+ method: "POST",
998
+ path: "/v1/fhir/r4/ValueSet/$validate-code",
999
+ body,
1000
+ expects: ["Parameters"]
1001
+ });
1002
+ }
1003
+ };
1004
+ //#endregion
423
1005
  //#region src/generated/methods.ts
424
1006
  /** Every operation of the haau3 platform API. {@link Haau3} is the class to construct. */
425
1007
  var Operations = class extends Transport {
@@ -989,6 +1571,8 @@ var Operations = class extends Transport {
989
1571
  };
990
1572
  //#endregion
991
1573
  //#region src/client.ts
1574
+ /** The builder every batch is handed. It holds nothing, so one serves every call. */
1575
+ const builder = new BatchBuilder();
992
1576
  /**
993
1577
  * The haau3 platform API client.
994
1578
  *
@@ -1028,6 +1612,45 @@ var Haau3 = class extends Operations {
1028
1612
  page = await this.answer("GET", url, void 0, options, url.pathname, ["Bundle"]);
1029
1613
  }
1030
1614
  }
1615
+ /**
1616
+ * Several operations of the FHIR base in one request, each with its own answer or error, in the
1617
+ * order given. The function you pass gets a builder with every operation a batch can carry, called
1618
+ * as on this client; what it returns is sent.
1619
+ *
1620
+ * ```ts
1621
+ * const [plan, counties] = await haau3.batch((b) => [
1622
+ * b.readInsurancePlan("H2406-013-000"),
1623
+ * b.listInsurancePlanCounties({ state: "NC" }),
1624
+ * ]);
1625
+ * if (plan.ok) plan.data; // fhir4.InsurancePlan
1626
+ * else plan.error; // RefusedError or NoAnswerError, as the call alone would have thrown
1627
+ * ```
1628
+ *
1629
+ * Each entry is checked as the call alone is, and fails alone: its result is `{ ok: false, error }`
1630
+ * and the others still answer. An entry that fails is not retried. The batch itself is retried,
1631
+ * and throws, as any call does: an {@link AuthError}, a {@link NoAnswerError} when no answer came
1632
+ * back, a {@link RefusedError} when the API refused the whole batch. The API takes up to 100
1633
+ * entries in up to 1 MiB, and gives a batch 60 seconds; a larger batch is refused, so send several.
1634
+ * `reconcileMedications` cannot go in a batch.
1635
+ */
1636
+ batch(build, options = {}) {
1637
+ let entries;
1638
+ let bundle;
1639
+ try {
1640
+ entries = build(builder);
1641
+ bundle = batchBundle(entries);
1642
+ } catch (error) {
1643
+ return new APIPromise(Promise.reject(error));
1644
+ }
1645
+ return new APIPromise(this.#sendBatch(entries, bundle, options));
1646
+ }
1647
+ async #sendBatch(entries, bundle, options) {
1648
+ const { data, ...meta } = await this.respond("POST", this.url("/v1/fhir/r4"), bundle, options, "/v1/fhir/r4", ["Bundle"]);
1649
+ return {
1650
+ ...meta,
1651
+ data: readBatch(entries, data, meta)
1652
+ };
1653
+ }
1031
1654
  };
1032
1655
  //#endregion
1033
1656
  export { APIPromise, AuthError, Haau3, Haau3Error, NoAnswerError, RefusedError, VERSION };