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