@choiceapps/communityservices-sdk 0.1.0
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/AGENTS.md +43 -0
- package/API.md +86 -0
- package/CHANGELOG.md +12 -0
- package/LICENSE +201 -0
- package/NOTICE +11 -0
- package/README.md +100 -0
- package/SSVF.md +131 -0
- package/browser/attachment-conflict.mjs +6 -0
- package/browser/case-plans-ui.mjs +23 -0
- package/browser/case-plans.d.mts +20 -0
- package/browser/case-plans.mjs +89 -0
- package/browser/client-creation.d.mts +16 -0
- package/browser/client-creation.mjs +60 -0
- package/browser/client-profile-ui.mjs +59 -0
- package/browser/client-profile.d.mts +24 -0
- package/browser/client-profile.mjs +94 -0
- package/browser/client-workflows.mjs +135 -0
- package/browser/connection.d.mts +4 -0
- package/browser/connection.mjs +41 -0
- package/browser/current-living-situation.d.mts +44 -0
- package/browser/current-living-situation.mjs +161 -0
- package/browser/date-of-birth-ui.mjs +68 -0
- package/browser/date-of-birth.d.mts +28 -0
- package/browser/date-of-birth.mjs +112 -0
- package/browser/enrollment-workflow.d.mts +174 -0
- package/browser/enrollment-workflow.mjs +518 -0
- package/browser/exit-details.mjs +21 -0
- package/browser/file-store.mjs +32 -0
- package/browser/gwt-mapped.mjs +46 -0
- package/browser/household-exit.d.mts +34 -0
- package/browser/household-exit.mjs +102 -0
- package/browser/households-ui.mjs +20 -0
- package/browser/households.d.mts +22 -0
- package/browser/households.mjs +115 -0
- package/browser/index.d.mts +78 -0
- package/browser/index.mjs +46 -0
- package/browser/member-entry-date.d.mts +30 -0
- package/browser/member-entry-date.mjs +71 -0
- package/browser/need-recording.d.mts +37 -0
- package/browser/need-recording.mjs +68 -0
- package/browser/need-ui.mjs +138 -0
- package/browser/page-lock.mjs +11 -0
- package/browser/password-recovery.mjs +49 -0
- package/browser/playwright-session.mjs +196 -0
- package/browser/program-discovery.d.mts +22 -0
- package/browser/program-discovery.mjs +80 -0
- package/browser/recovery-diagnostics.mjs +9 -0
- package/browser/service-recording.d.mts +45 -0
- package/browser/service-recording.mjs +148 -0
- package/browser/service-ui.mjs +160 -0
- package/browser/session-authentication.mjs +40 -0
- package/browser/shelter-inventory.d.mts +103 -0
- package/browser/shelter-inventory.mjs +273 -0
- package/browser/shelter-ui.mjs +382 -0
- package/browser/shelters.d.mts +139 -0
- package/browser/shelters.mjs +425 -0
- package/browser/ssvf-rules.d.mts +21 -0
- package/browser/ssvf-rules.mjs +145 -0
- package/browser/ui-login.mjs +135 -0
- package/dist/cjs/bulk.d.ts +33 -0
- package/dist/cjs/bulk.d.ts.map +1 -0
- package/dist/cjs/bulk.js +42 -0
- package/dist/cjs/bulk.js.map +1 -0
- package/dist/cjs/control.d.ts +35 -0
- package/dist/cjs/control.d.ts.map +1 -0
- package/dist/cjs/control.js +141 -0
- package/dist/cjs/control.js.map +1 -0
- package/dist/cjs/effective-date.d.ts +3 -0
- package/dist/cjs/effective-date.d.ts.map +1 -0
- package/dist/cjs/effective-date.js +27 -0
- package/dist/cjs/effective-date.js.map +1 -0
- package/dist/cjs/encoding.d.ts +32 -0
- package/dist/cjs/encoding.d.ts.map +1 -0
- package/dist/cjs/encoding.js +121 -0
- package/dist/cjs/encoding.js.map +1 -0
- package/dist/cjs/enrollment-verifications.d.ts +39 -0
- package/dist/cjs/enrollment-verifications.d.ts.map +1 -0
- package/dist/cjs/enrollment-verifications.js +96 -0
- package/dist/cjs/enrollment-verifications.js.map +1 -0
- package/dist/cjs/errors.d.ts +33 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +45 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/generated/v2-models.d.ts +1482 -0
- package/dist/cjs/generated/v2-models.d.ts.map +1 -0
- package/dist/cjs/generated/v2-models.js +3 -0
- package/dist/cjs/generated/v2-models.js.map +1 -0
- package/dist/cjs/generated/v2.d.ts +1149 -0
- package/dist/cjs/generated/v2.d.ts.map +1 -0
- package/dist/cjs/generated/v2.js +252 -0
- package/dist/cjs/generated/v2.js.map +1 -0
- package/dist/cjs/generated/v3-models.d.ts +1420 -0
- package/dist/cjs/generated/v3-models.d.ts.map +1 -0
- package/dist/cjs/generated/v3-models.js +3 -0
- package/dist/cjs/generated/v3-models.js.map +1 -0
- package/dist/cjs/generated/v3.d.ts +1149 -0
- package/dist/cjs/generated/v3.d.ts.map +1 -0
- package/dist/cjs/generated/v3.js +252 -0
- package/dist/cjs/generated/v3.js.map +1 -0
- package/dist/cjs/gwt-enrollments.d.ts +131 -0
- package/dist/cjs/gwt-enrollments.d.ts.map +1 -0
- package/dist/cjs/gwt-enrollments.js +280 -0
- package/dist/cjs/gwt-enrollments.js.map +1 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/metadata.d.ts +100 -0
- package/dist/cjs/metadata.d.ts.map +1 -0
- package/dist/cjs/metadata.js +165 -0
- package/dist/cjs/metadata.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/program-discovery.d.ts +28 -0
- package/dist/cjs/program-discovery.d.ts.map +1 -0
- package/dist/cjs/program-discovery.js +58 -0
- package/dist/cjs/program-discovery.js.map +1 -0
- package/dist/cjs/race.d.ts +4 -0
- package/dist/cjs/race.d.ts.map +1 -0
- package/dist/cjs/race.js +40 -0
- package/dist/cjs/race.js.map +1 -0
- package/dist/cjs/runtime.d.ts +108 -0
- package/dist/cjs/runtime.d.ts.map +1 -0
- package/dist/cjs/runtime.js +38 -0
- package/dist/cjs/runtime.js.map +1 -0
- package/dist/cjs/subassessments.d.ts +29 -0
- package/dist/cjs/subassessments.d.ts.map +1 -0
- package/dist/cjs/subassessments.js +107 -0
- package/dist/cjs/subassessments.js.map +1 -0
- package/dist/cjs/testing.d.ts +45 -0
- package/dist/cjs/testing.d.ts.map +1 -0
- package/dist/cjs/testing.js +66 -0
- package/dist/cjs/testing.js.map +1 -0
- package/dist/cjs/transport.d.ts +19 -0
- package/dist/cjs/transport.d.ts.map +1 -0
- package/dist/cjs/transport.js +373 -0
- package/dist/cjs/transport.js.map +1 -0
- package/dist/cjs/v2.d.ts +13 -0
- package/dist/cjs/v2.d.ts.map +1 -0
- package/dist/cjs/v2.js +29 -0
- package/dist/cjs/v2.js.map +1 -0
- package/dist/cjs/v3.d.ts +13 -0
- package/dist/cjs/v3.d.ts.map +1 -0
- package/dist/cjs/v3.js +29 -0
- package/dist/cjs/v3.js.map +1 -0
- package/dist/cjs/validation.d.ts +33 -0
- package/dist/cjs/validation.d.ts.map +1 -0
- package/dist/cjs/validation.js +77 -0
- package/dist/cjs/validation.js.map +1 -0
- package/dist/cjs/verification.d.ts +82 -0
- package/dist/cjs/verification.d.ts.map +1 -0
- package/dist/cjs/verification.js +122 -0
- package/dist/cjs/verification.js.map +1 -0
- package/dist/esm/bulk.d.ts +33 -0
- package/dist/esm/bulk.d.ts.map +1 -0
- package/dist/esm/bulk.js +39 -0
- package/dist/esm/bulk.js.map +1 -0
- package/dist/esm/control.d.ts +35 -0
- package/dist/esm/control.d.ts.map +1 -0
- package/dist/esm/control.js +132 -0
- package/dist/esm/control.js.map +1 -0
- package/dist/esm/effective-date.d.ts +3 -0
- package/dist/esm/effective-date.d.ts.map +1 -0
- package/dist/esm/effective-date.js +24 -0
- package/dist/esm/effective-date.js.map +1 -0
- package/dist/esm/encoding.d.ts +32 -0
- package/dist/esm/encoding.d.ts.map +1 -0
- package/dist/esm/encoding.js +117 -0
- package/dist/esm/encoding.js.map +1 -0
- package/dist/esm/enrollment-verifications.d.ts +39 -0
- package/dist/esm/enrollment-verifications.d.ts.map +1 -0
- package/dist/esm/enrollment-verifications.js +93 -0
- package/dist/esm/enrollment-verifications.js.map +1 -0
- package/dist/esm/errors.d.ts +33 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +33 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/generated/v2-models.d.ts +1482 -0
- package/dist/esm/generated/v2-models.d.ts.map +1 -0
- package/dist/esm/generated/v2-models.js +2 -0
- package/dist/esm/generated/v2-models.js.map +1 -0
- package/dist/esm/generated/v2.d.ts +1149 -0
- package/dist/esm/generated/v2.d.ts.map +1 -0
- package/dist/esm/generated/v2.js +247 -0
- package/dist/esm/generated/v2.js.map +1 -0
- package/dist/esm/generated/v3-models.d.ts +1420 -0
- package/dist/esm/generated/v3-models.d.ts.map +1 -0
- package/dist/esm/generated/v3-models.js +2 -0
- package/dist/esm/generated/v3-models.js.map +1 -0
- package/dist/esm/generated/v3.d.ts +1149 -0
- package/dist/esm/generated/v3.d.ts.map +1 -0
- package/dist/esm/generated/v3.js +247 -0
- package/dist/esm/generated/v3.js.map +1 -0
- package/dist/esm/gwt-enrollments.d.ts +131 -0
- package/dist/esm/gwt-enrollments.d.ts.map +1 -0
- package/dist/esm/gwt-enrollments.js +274 -0
- package/dist/esm/gwt-enrollments.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/metadata.d.ts +100 -0
- package/dist/esm/metadata.d.ts.map +1 -0
- package/dist/esm/metadata.js +157 -0
- package/dist/esm/metadata.js.map +1 -0
- package/dist/esm/program-discovery.d.ts +28 -0
- package/dist/esm/program-discovery.d.ts.map +1 -0
- package/dist/esm/program-discovery.js +55 -0
- package/dist/esm/program-discovery.js.map +1 -0
- package/dist/esm/race.d.ts +4 -0
- package/dist/esm/race.d.ts.map +1 -0
- package/dist/esm/race.js +37 -0
- package/dist/esm/race.js.map +1 -0
- package/dist/esm/runtime.d.ts +108 -0
- package/dist/esm/runtime.d.ts.map +1 -0
- package/dist/esm/runtime.js +33 -0
- package/dist/esm/runtime.js.map +1 -0
- package/dist/esm/subassessments.d.ts +29 -0
- package/dist/esm/subassessments.d.ts.map +1 -0
- package/dist/esm/subassessments.js +103 -0
- package/dist/esm/subassessments.js.map +1 -0
- package/dist/esm/testing.d.ts +45 -0
- package/dist/esm/testing.d.ts.map +1 -0
- package/dist/esm/testing.js +60 -0
- package/dist/esm/testing.js.map +1 -0
- package/dist/esm/transport.d.ts +19 -0
- package/dist/esm/transport.d.ts.map +1 -0
- package/dist/esm/transport.js +369 -0
- package/dist/esm/transport.js.map +1 -0
- package/dist/esm/v2.d.ts +13 -0
- package/dist/esm/v2.d.ts.map +1 -0
- package/dist/esm/v2.js +13 -0
- package/dist/esm/v2.js.map +1 -0
- package/dist/esm/v3.d.ts +13 -0
- package/dist/esm/v3.d.ts.map +1 -0
- package/dist/esm/v3.js +13 -0
- package/dist/esm/v3.js.map +1 -0
- package/dist/esm/validation.d.ts +33 -0
- package/dist/esm/validation.d.ts.map +1 -0
- package/dist/esm/validation.js +72 -0
- package/dist/esm/validation.js.map +1 -0
- package/dist/esm/verification.d.ts +82 -0
- package/dist/esm/verification.d.ts.map +1 -0
- package/dist/esm/verification.js +117 -0
- package/dist/esm/verification.js.map +1 -0
- package/docs/README.md +56 -0
- package/docs/assessments.md +103 -0
- package/docs/browser-session.md +129 -0
- package/docs/capabilities.md +75 -0
- package/docs/configuration.md +81 -0
- package/docs/current-living-situation.md +56 -0
- package/docs/dates-and-answers.md +40 -0
- package/docs/development.md +81 -0
- package/docs/durable-records.md +156 -0
- package/docs/enrollments.md +217 -0
- package/docs/files-and-notes.md +39 -0
- package/docs/getting-started.md +56 -0
- package/docs/independent-needs.md +77 -0
- package/docs/integration-methods.md +60 -0
- package/docs/profiles.md +68 -0
- package/docs/reference.md +64 -0
- package/docs/rest-client.md +97 -0
- package/docs/services.md +66 -0
- package/docs/shelter-inventory.md +64 -0
- package/docs/shelters.md +75 -0
- package/docs/troubleshooting.md +61 -0
- package/docs/using-the-sdk.md +203 -0
- package/docs/vendor-issues/README.md +46 -0
- package/docs/vendor-issues/api-coverage.md +27 -0
- package/docs/vendor-issues/attachment-authentication.md +40 -0
- package/docs/vendor-issues/date-semantics.md +51 -0
- package/docs/vendor-issues/empty-service-list-404.md +51 -0
- package/docs/vendor-issues/enrollment-complete-target-error.md +178 -0
- package/docs/vendor-issues/enrollment-effective-date-column.md +112 -0
- package/docs/vendor-issues/household-head-validation.md +26 -0
- package/docs/vendor-issues/write-contracts.md +51 -0
- package/examples/README.md +41 -0
- package/examples/current-living-situation.mts +27 -0
- package/examples/durable-records.mts +78 -0
- package/examples/enrollment-workflow.mts +46 -0
- package/examples/gwt-enrollment-session.ts +17 -0
- package/examples/gwt-file-store.mjs +2 -0
- package/examples/household-enrollment-workflow.mts +43 -0
- package/examples/household-exit-workflow.mts +35 -0
- package/examples/household-lifecycle-workflow.mts +34 -0
- package/examples/independent-needs.mts +30 -0
- package/examples/program-discovery.ts +19 -0
- package/examples/quickstart.mjs +13 -0
- package/examples/shelter-inventory.mts +30 -0
- package/examples/shelters.mts +33 -0
- package/examples/usage.ts +23 -0
- package/examples/verification-snapshot.ts +9 -0
- package/llms.txt +26 -0
- package/package.json +103 -0
- package/specs/provenance.json +17 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { WellSkyError, toItems } from "./runtime.js";
|
|
2
|
+
import { decodeResponse, isRecord, matches } from "./validation.js";
|
|
3
|
+
import { AuthError, TenantMismatchError, ThrottledError, UpstreamError, ValidationError } from "./errors.js";
|
|
4
|
+
import { emit, identity, requestControl, sharedAuthentication, tokenMintQueue } from "./control.js";
|
|
5
|
+
import { correctMobileEffectiveDate } from "./effective-date.js";
|
|
6
|
+
const retryStatuses = new Set([408, 429, 500, 502, 503, 504]);
|
|
7
|
+
function positiveInteger(value, name, minimum = 1) {
|
|
8
|
+
if (!Number.isSafeInteger(value) || value < minimum)
|
|
9
|
+
throw new TypeError(`${name} must be an integer >= ${minimum}`);
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function expiry(token) {
|
|
13
|
+
try {
|
|
14
|
+
const part = token.split(".")[1];
|
|
15
|
+
if (!part)
|
|
16
|
+
return 0;
|
|
17
|
+
const base64 = part.replaceAll("-", "+").replaceAll("_", "/");
|
|
18
|
+
const parsed = JSON.parse(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "=")));
|
|
19
|
+
return isRecord(parsed) && typeof parsed.exp === "number" && Number.isFinite(parsed.exp) ? parsed.exp * 1000 : 0;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function retryAfter(headers) {
|
|
26
|
+
const raw = headers.get("retry-after");
|
|
27
|
+
if (!raw)
|
|
28
|
+
return undefined;
|
|
29
|
+
const seconds = Number(raw);
|
|
30
|
+
const delay = Number.isFinite(seconds) ? seconds * 1000 : Date.parse(raw) - Date.now();
|
|
31
|
+
return Number.isFinite(delay) ? Math.max(0, delay) : undefined;
|
|
32
|
+
}
|
|
33
|
+
function abortError(signal, operation) {
|
|
34
|
+
return new WellSkyError(signal.reason instanceof DOMException && signal.reason.name === "TimeoutError" ? "timeout" : "aborted", operation);
|
|
35
|
+
}
|
|
36
|
+
/** A caller can cancel its wait without cancelling authentication shared by other callers. */
|
|
37
|
+
function withSignal(promise, signal, operation) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const abort = () => reject(abortError(signal, operation));
|
|
40
|
+
if (signal.aborted)
|
|
41
|
+
abort();
|
|
42
|
+
else
|
|
43
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
44
|
+
promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function delay(ms, signal, operation) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
if (signal.aborted) {
|
|
50
|
+
reject(abortError(signal, operation));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const abort = () => { clearTimeout(timer); reject(abortError(signal, operation)); };
|
|
54
|
+
const timer = setTimeout(() => { signal.removeEventListener("abort", abort); resolve(); }, ms);
|
|
55
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export class Transport {
|
|
59
|
+
#baseUrl;
|
|
60
|
+
#tenant;
|
|
61
|
+
#version;
|
|
62
|
+
#auth;
|
|
63
|
+
#fetch;
|
|
64
|
+
#schemas;
|
|
65
|
+
#timeout;
|
|
66
|
+
#retries;
|
|
67
|
+
#retryBase;
|
|
68
|
+
#retryMax;
|
|
69
|
+
#shared;
|
|
70
|
+
#control;
|
|
71
|
+
#observers;
|
|
72
|
+
#mobileDateCorrection;
|
|
73
|
+
constructor(options, version, schemas) {
|
|
74
|
+
if (typeof window !== "undefined" || !("process" in globalThis))
|
|
75
|
+
throw new TypeError("WellSky SDK requires a server-side Node.js runtime");
|
|
76
|
+
if (!options.tenant.trim() || /[\r\n]/.test(options.tenant))
|
|
77
|
+
throw new TypeError("tenant is required and must be a valid header value");
|
|
78
|
+
const url = new URL(options.baseUrl ?? "https://csclientapi.wellsky.com/client-api-prod");
|
|
79
|
+
if (!['https:', 'http:'].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
80
|
+
throw new TypeError("baseUrl must be an HTTP(S) URL without credentials, query, or fragment");
|
|
81
|
+
if (url.protocol === 'http:' && !['localhost', '127.0.0.1', '[::1]'].includes(url.hostname))
|
|
82
|
+
throw new TypeError("Use HTTPS except for loopback testing");
|
|
83
|
+
if (options.auth.kind === "credentials" && (!options.auth.username.trim() || !options.auth.password))
|
|
84
|
+
throw new TypeError("username and password are required");
|
|
85
|
+
if (options.auth.kind === "token" && (!options.auth.token.trim() || /\s/.test(options.auth.token)))
|
|
86
|
+
throw new TypeError("token must be a non-empty bearer token");
|
|
87
|
+
this.#baseUrl = url.toString().replace(/\/$/, "");
|
|
88
|
+
this.#tenant = options.tenant;
|
|
89
|
+
this.#version = version;
|
|
90
|
+
this.#auth = { ...options.auth };
|
|
91
|
+
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
92
|
+
this.#schemas = schemas;
|
|
93
|
+
const correction = options.mobileAssessmentDateCorrectionMinutes;
|
|
94
|
+
if (correction !== undefined && (!Number.isSafeInteger(correction) || Math.abs(correction) > 840))
|
|
95
|
+
throw new ValidationError("client configuration", ["mobileAssessmentDateCorrectionMinutes"]);
|
|
96
|
+
this.#mobileDateCorrection = correction;
|
|
97
|
+
this.#timeout = positiveInteger(options.timeoutMs ?? 30_000, "timeoutMs");
|
|
98
|
+
this.#retries = positiveInteger(options.maxReadRetries ?? 2, "maxReadRetries", 0);
|
|
99
|
+
this.#retryBase = positiveInteger(options.retryBaseDelayMs ?? 250, "retryBaseDelayMs", 0);
|
|
100
|
+
this.#retryMax = positiveInteger(options.maxRetryDelayMs ?? 30_000, "maxRetryDelayMs", 0);
|
|
101
|
+
const scope = JSON.stringify([this.#baseUrl, this.#tenant, identity(this.#fetch)]);
|
|
102
|
+
this.#control = requestControl(scope, options);
|
|
103
|
+
this.#shared = sharedAuthentication(scope, this.#auth);
|
|
104
|
+
this.#observers = { ...(options.hooks ? { hooks: { ...options.hooks } } : {}), ...(options.logger ? { logger: options.logger } : {}) };
|
|
105
|
+
if (this.#auth.kind === "token")
|
|
106
|
+
this.#checkTokenTenant(this.#auth.token);
|
|
107
|
+
}
|
|
108
|
+
get tenant() { return this.#tenant; }
|
|
109
|
+
get baseUrl() { return this.#baseUrl; }
|
|
110
|
+
health() { return this.#control.health(); }
|
|
111
|
+
#checkTenant(value, operation) {
|
|
112
|
+
if (!isRecord(value))
|
|
113
|
+
return;
|
|
114
|
+
for (const key of ["tenant", "tenantCode", "tenant_code", "x-tenant"]) {
|
|
115
|
+
if (value[key] !== undefined && value[key] !== null && value[key] !== this.#tenant)
|
|
116
|
+
throw new TenantMismatchError(operation);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
#checkTokenTenant(token) {
|
|
120
|
+
let payload;
|
|
121
|
+
try {
|
|
122
|
+
const segment = token.split(".")[1];
|
|
123
|
+
if (!segment)
|
|
124
|
+
return;
|
|
125
|
+
const base64 = segment.replaceAll("-", "+").replaceAll("_", "/");
|
|
126
|
+
payload = JSON.parse(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "=")));
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
this.#checkTenant(payload, "authentication token");
|
|
132
|
+
}
|
|
133
|
+
async #send(url, init, operation, correlationId, retryCount) {
|
|
134
|
+
this.#control.check(operation);
|
|
135
|
+
const release = await this.#control.semaphore.acquire(init.signal, operation);
|
|
136
|
+
const started = Date.now();
|
|
137
|
+
const base = { operation, correlationId, retryCount };
|
|
138
|
+
try {
|
|
139
|
+
this.#control.check(operation);
|
|
140
|
+
const headers = new Headers(init.headers);
|
|
141
|
+
headers.set("x-correlation-id", correlationId);
|
|
142
|
+
emit(this.#observers, { ...base, type: "request" });
|
|
143
|
+
const response = await this.#fetch(url, { ...init, headers });
|
|
144
|
+
const event = { ...base, type: "response", status: response.status, durationMs: Date.now() - started };
|
|
145
|
+
emit(this.#observers, event);
|
|
146
|
+
if (response.status === 429)
|
|
147
|
+
emit(this.#observers, { ...event, type: "throttle", retryAfterMs: retryAfter(response.headers) ?? this.#retryBase });
|
|
148
|
+
const until = this.#control.failed(response.status);
|
|
149
|
+
if (until !== undefined)
|
|
150
|
+
emit(this.#observers, { ...base, type: "cooldown", until: new Date(until).toISOString() });
|
|
151
|
+
if (response.headers.has("x-tenant") && response.headers.get("x-tenant") !== this.#tenant) {
|
|
152
|
+
await response.body?.cancel();
|
|
153
|
+
throw new TenantMismatchError(operation);
|
|
154
|
+
}
|
|
155
|
+
// Hold the concurrency slot through body consumption, not merely until headers arrive.
|
|
156
|
+
const body = await response.arrayBuffer();
|
|
157
|
+
return new Response(response.status === 204 || response.status === 205 || response.status === 304 ? null : body, { status: response.status, statusText: response.statusText, headers: response.headers });
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
release();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
#headers(token) {
|
|
164
|
+
const headers = new Headers({ Accept: "application/json", "x-tenant": this.#tenant, "x-version": this.#version });
|
|
165
|
+
if (token)
|
|
166
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
167
|
+
return headers;
|
|
168
|
+
}
|
|
169
|
+
async #read(response, operation, allowText = false) {
|
|
170
|
+
if (!response.ok) {
|
|
171
|
+
// Discard upstream error content; it may contain client data or credentials.
|
|
172
|
+
await response.body?.cancel();
|
|
173
|
+
const requestId = response.headers.get("x-request-id") ?? response.headers.get("request-id") ?? undefined;
|
|
174
|
+
const wait = retryAfter(response.headers);
|
|
175
|
+
if (response.status === 429)
|
|
176
|
+
throw new ThrottledError(operation, wait ?? this.#retryBase, response.status, requestId);
|
|
177
|
+
if (response.status === 401 || response.status === 403)
|
|
178
|
+
throw new AuthError(operation, response.status);
|
|
179
|
+
throw new UpstreamError(operation, response.status, requestId, wait);
|
|
180
|
+
}
|
|
181
|
+
const text = await response.text();
|
|
182
|
+
if (!text.trim())
|
|
183
|
+
return null;
|
|
184
|
+
let value;
|
|
185
|
+
try {
|
|
186
|
+
value = JSON.parse(text);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
if (allowText)
|
|
190
|
+
return text;
|
|
191
|
+
throw new WellSkyError("protocol", operation);
|
|
192
|
+
}
|
|
193
|
+
this.#checkTenant(value, operation);
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
async #mint(forceRefresh, shared) {
|
|
197
|
+
const operation = "POST /authentication/SetAuthKey";
|
|
198
|
+
const controller = new AbortController();
|
|
199
|
+
const timer = setTimeout(() => controller.abort(new DOMException("Deadline exceeded", "TimeoutError")), this.#timeout);
|
|
200
|
+
const signal = controller.signal;
|
|
201
|
+
let release;
|
|
202
|
+
try {
|
|
203
|
+
release = await tokenMintQueue.acquire(signal, operation);
|
|
204
|
+
this.#control.check(operation);
|
|
205
|
+
const correlationId = crypto.randomUUID();
|
|
206
|
+
this.#control.tokenMintCount++;
|
|
207
|
+
emit(this.#observers, { type: "tokenMint", operation, correlationId, retryCount: 0 });
|
|
208
|
+
let token;
|
|
209
|
+
if (this.#auth.kind === "provider")
|
|
210
|
+
token = await withSignal(Promise.resolve().then(() => this.#auth.kind === "provider" ? this.#auth.getToken({ forceRefresh, signal }) : ""), signal, operation);
|
|
211
|
+
else if (this.#auth.kind === "credentials") {
|
|
212
|
+
const headers = this.#headers();
|
|
213
|
+
headers.set("Content-Type", "application/json");
|
|
214
|
+
const response = await this.#send(`${this.#baseUrl}/authentication/SetAuthKey`, {
|
|
215
|
+
method: "POST", headers, body: JSON.stringify({ username: this.#auth.username, password: this.#auth.password }), signal, redirect: "error", cache: "no-store",
|
|
216
|
+
}, operation, correlationId, 0);
|
|
217
|
+
const result = await this.#read(response, operation);
|
|
218
|
+
token = isRecord(result) ? result.token : undefined;
|
|
219
|
+
}
|
|
220
|
+
if (typeof token !== "string" || !token || /\s/.test(token))
|
|
221
|
+
throw new WellSkyError("protocol", operation);
|
|
222
|
+
this.#checkTokenTenant(token);
|
|
223
|
+
const expiresAt = expiry(token);
|
|
224
|
+
if (expiresAt !== 0 && expiresAt <= Date.now())
|
|
225
|
+
throw new WellSkyError("protocol", operation);
|
|
226
|
+
shared.cached = { token, expiresAt };
|
|
227
|
+
return token;
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
if (signal.aborted)
|
|
231
|
+
throw abortError(signal, operation);
|
|
232
|
+
if (error instanceof WellSkyError)
|
|
233
|
+
throw error;
|
|
234
|
+
throw new WellSkyError("network", operation);
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
release?.();
|
|
238
|
+
clearTimeout(timer);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
async #token(rejectedToken) {
|
|
242
|
+
if (this.#auth.kind === "none")
|
|
243
|
+
return Promise.resolve(undefined);
|
|
244
|
+
if (this.#auth.kind === "token")
|
|
245
|
+
return Promise.resolve(this.#auth.token);
|
|
246
|
+
const shared = await this.#shared;
|
|
247
|
+
// An older request's late 401 must not evict a newer token.
|
|
248
|
+
if (rejectedToken && shared.cached?.token !== rejectedToken && shared.cached)
|
|
249
|
+
return shared.cached.token;
|
|
250
|
+
if (shared.inFlight)
|
|
251
|
+
return shared.inFlight;
|
|
252
|
+
if (!rejectedToken && shared.cached && shared.cached.expiresAt > Date.now() + 120_000)
|
|
253
|
+
return shared.cached.token;
|
|
254
|
+
shared.cached = undefined;
|
|
255
|
+
shared.inFlight = this.#mint(Boolean(rejectedToken), shared).finally(() => { shared.inFlight = undefined; });
|
|
256
|
+
return shared.inFlight;
|
|
257
|
+
}
|
|
258
|
+
async execute(definition, args) {
|
|
259
|
+
const operation = `${definition.method} ${definition.path}`;
|
|
260
|
+
const correlationId = args.correlationId ?? crypto.randomUUID();
|
|
261
|
+
if (!/^[A-Za-z0-9_.:-]{1,128}$/.test(correlationId))
|
|
262
|
+
throw new ValidationError(operation, ["correlationId"]);
|
|
263
|
+
const timeout = positiveInteger(args.timeoutMs ?? this.#timeout, "timeoutMs");
|
|
264
|
+
const controller = new AbortController();
|
|
265
|
+
const timer = setTimeout(() => controller.abort(new DOMException("Deadline exceeded", "TimeoutError")), timeout);
|
|
266
|
+
const signal = args.signal ? AbortSignal.any([args.signal, controller.signal]) : controller.signal;
|
|
267
|
+
try {
|
|
268
|
+
if (signal.aborted)
|
|
269
|
+
throw abortError(signal, operation);
|
|
270
|
+
this.#control.check(operation);
|
|
271
|
+
if (!matches(args.path ?? {}, definition.pathSchema, this.#schemas, "request") || !matches(args.query ?? {}, definition.querySchema, this.#schemas, "request") || (definition.bodySchema && !matches(args.body, definition.bodySchema, this.#schemas, "request")))
|
|
272
|
+
throw new ValidationError(operation);
|
|
273
|
+
// Check file bytes before multipart construction or credential authentication.
|
|
274
|
+
if (definition.multipart && isRecord(args.body) && args.body.fileData instanceof Blob && args.body.fileData.size > 10_000_000)
|
|
275
|
+
throw new ValidationError(operation, ["fileData"]);
|
|
276
|
+
const pathValues = new Map(Object.entries(args.path ?? {}));
|
|
277
|
+
const path = definition.path.replace(/\{([^}]+)\}/g, (_, name) => {
|
|
278
|
+
const value = String(pathValues.get(name));
|
|
279
|
+
if (value === "." || value === "..")
|
|
280
|
+
throw new WellSkyError("validation", operation);
|
|
281
|
+
return encodeURIComponent(value);
|
|
282
|
+
});
|
|
283
|
+
const url = new URL(this.#baseUrl + path);
|
|
284
|
+
for (const [name, value] of Object.entries(args.query ?? {})) {
|
|
285
|
+
if (value !== undefined && value !== null) {
|
|
286
|
+
const encoded = this.#mobileDateCorrection !== undefined && name === "dateEffective" && operation === "POST /assessmentsmobile/AddAssessmentAnswer/{clientId}/{assessmentCode}"
|
|
287
|
+
? correctMobileEffectiveDate(value, this.#mobileDateCorrection, operation) : String(value);
|
|
288
|
+
url.searchParams.set(name, encoded);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
let body;
|
|
292
|
+
if (definition.multipart && isRecord(args.body)) {
|
|
293
|
+
body = new FormData();
|
|
294
|
+
for (const [name, value] of Object.entries(args.body)) {
|
|
295
|
+
if (value !== undefined && value !== null)
|
|
296
|
+
body.append(name, value instanceof Blob ? value : String(value));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
else if (args.body !== undefined)
|
|
300
|
+
body = JSON.stringify(args.body);
|
|
301
|
+
let token = definition.authenticated ? await withSignal(this.#token(), signal, operation) : undefined;
|
|
302
|
+
let refreshed = false;
|
|
303
|
+
let attempts = 0;
|
|
304
|
+
while (true) {
|
|
305
|
+
try {
|
|
306
|
+
const headers = this.#headers(token);
|
|
307
|
+
if (typeof body === "string")
|
|
308
|
+
headers.set("Content-Type", "application/json");
|
|
309
|
+
const response = await this.#send(url, { method: definition.method, headers, ...(body === undefined ? {} : { body }), signal, redirect: "error", cache: "no-store" }, operation, correlationId, attempts);
|
|
310
|
+
// Reads can refresh once. Writes are never automatically sent twice, even after a 401.
|
|
311
|
+
if (response.status === 401 && definition.method === "GET" && definition.authenticated && !refreshed && (this.#auth.kind === "credentials" || this.#auth.kind === "provider")) {
|
|
312
|
+
await response.body?.cancel();
|
|
313
|
+
refreshed = true;
|
|
314
|
+
token = await withSignal(this.#token(token), signal, operation);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
const result = await this.#read(response, operation, definition.responseSchema === undefined);
|
|
318
|
+
return decodeResponse(result, definition.responseSchema, this.#schemas, operation);
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
if (signal.aborted)
|
|
322
|
+
throw abortError(signal, operation);
|
|
323
|
+
const failure = error instanceof WellSkyError ? error : new WellSkyError("network", operation);
|
|
324
|
+
const retryable = failure.kind === "network" || ((failure.kind === "http" || failure.kind === "throttled") && retryStatuses.has(failure.status ?? 0));
|
|
325
|
+
if (definition.method !== "GET" || failure.operation !== operation || !retryable || attempts >= this.#retries)
|
|
326
|
+
throw failure;
|
|
327
|
+
const wait = failure.retryAfterMs ?? Math.min(this.#retryMax, this.#retryBase * 2 ** attempts * (1 + Math.random() * 0.2));
|
|
328
|
+
// Never retry earlier than Retry-After. Return the error if the delay exceeds our bound.
|
|
329
|
+
if (wait > this.#retryMax)
|
|
330
|
+
throw failure;
|
|
331
|
+
attempts++;
|
|
332
|
+
await delay(wait, signal, operation);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
if (signal.aborted) {
|
|
338
|
+
const error = abortError(signal, operation);
|
|
339
|
+
error.correlationId = correlationId;
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
if (error instanceof WellSkyError)
|
|
343
|
+
error.correlationId = correlationId;
|
|
344
|
+
if (error instanceof WellSkyError || error instanceof TypeError)
|
|
345
|
+
throw error;
|
|
346
|
+
throw new WellSkyError("network", operation);
|
|
347
|
+
}
|
|
348
|
+
finally {
|
|
349
|
+
clearTimeout(timer);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
async *paginate(definition, args) {
|
|
353
|
+
const operation = `${definition.method} ${definition.path}`;
|
|
354
|
+
const query = Object.fromEntries(Object.entries(args.query ?? {}));
|
|
355
|
+
const start = positiveInteger(typeof query.startPage === "number" ? query.startPage : 1, "startPage");
|
|
356
|
+
positiveInteger(typeof query.perPage === "number" ? query.perPage : 30, "perPage");
|
|
357
|
+
const maxPages = positiveInteger(args.maxPages ?? 10_000, "maxPages");
|
|
358
|
+
for (let page = 0; page < maxPages; page++) {
|
|
359
|
+
const response = await this.execute(definition, { ...args, query: { perPage: 30, ...query, startPage: start + page } });
|
|
360
|
+
const items = toItems(response);
|
|
361
|
+
if (!items.length)
|
|
362
|
+
return;
|
|
363
|
+
yield* items;
|
|
364
|
+
// Continue through short pages: some tenants cap perPage below the requested size.
|
|
365
|
+
}
|
|
366
|
+
throw new WellSkyError("pagination", operation);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { WellSkyError, toItems } from \"./runtime.js\";\nimport type { ApiResponse, Authentication, ClientOptions, PaginationOptions, RequestOptions } from \"./runtime.js\";\nimport { decodeResponse, isRecord, matches } from \"./validation.js\";\nimport type { OperationDefinition, SchemaRegistry } from \"./validation.js\";\nimport { AuthError, TenantMismatchError, ThrottledError, UpstreamError, ValidationError } from \"./errors.js\";\nimport { emit, identity, requestControl, sharedAuthentication, tokenMintQueue } from \"./control.js\";\nimport type { RequestControl, SharedAuthentication } from \"./control.js\";\nimport type { ClientEvent, ClientHealth } from \"./runtime.js\";\nimport { correctMobileEffectiveDate } from \"./effective-date.js\";\n\ninterface Arguments extends RequestOptions {\n path?: object;\n query?: object;\n body?: unknown;\n}\nconst retryStatuses = new Set([408, 429, 500, 502, 503, 504]);\n\nfunction positiveInteger(value: number, name: string, minimum = 1): number {\n if (!Number.isSafeInteger(value) || value < minimum) throw new TypeError(`${name} must be an integer >= ${minimum}`);\n return value;\n}\n\nfunction expiry(token: string): number {\n try {\n const part = token.split(\".\")[1];\n if (!part) return 0;\n const base64 = part.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n const parsed: unknown = JSON.parse(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, \"=\")));\n return isRecord(parsed) && typeof parsed.exp === \"number\" && Number.isFinite(parsed.exp) ? parsed.exp * 1000 : 0;\n } catch { return 0; }\n}\n\nfunction retryAfter(headers: Headers): number | undefined {\n const raw = headers.get(\"retry-after\");\n if (!raw) return undefined;\n const seconds = Number(raw);\n const delay = Number.isFinite(seconds) ? seconds * 1000 : Date.parse(raw) - Date.now();\n return Number.isFinite(delay) ? Math.max(0, delay) : undefined;\n}\n\nfunction abortError(signal: AbortSignal, operation: string): WellSkyError {\n return new WellSkyError(signal.reason instanceof DOMException && signal.reason.name === \"TimeoutError\" ? \"timeout\" : \"aborted\", operation);\n}\n\n/** A caller can cancel its wait without cancelling authentication shared by other callers. */\nfunction withSignal<T>(promise: Promise<T>, signal: AbortSignal, operation: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const abort = () => reject(abortError(signal, operation));\n if (signal.aborted) abort();\n else signal.addEventListener(\"abort\", abort, { once: true });\n promise.then(resolve, reject).finally(() => signal.removeEventListener(\"abort\", abort));\n });\n}\n\nfunction delay(ms: number, signal: AbortSignal, operation: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal.aborted) { reject(abortError(signal, operation)); return; }\n const abort = () => { clearTimeout(timer); reject(abortError(signal, operation)); };\n const timer = setTimeout(() => { signal.removeEventListener(\"abort\", abort); resolve(); }, ms);\n signal.addEventListener(\"abort\", abort, { once: true });\n });\n}\n\nexport class Transport {\n readonly #baseUrl: string;\n readonly #tenant: string;\n readonly #version: string;\n readonly #auth: Authentication;\n readonly #fetch: typeof globalThis.fetch;\n readonly #schemas: SchemaRegistry;\n readonly #timeout: number;\n readonly #retries: number;\n readonly #retryBase: number;\n readonly #retryMax: number;\n readonly #shared: Promise<SharedAuthentication>;\n readonly #control: RequestControl;\n readonly #observers: Pick<ClientOptions, \"hooks\" | \"logger\">;\n readonly #mobileDateCorrection: number | undefined;\n\n constructor(options: ClientOptions, version: string, schemas: SchemaRegistry) {\n if (typeof window !== \"undefined\" || !(\"process\" in globalThis)) throw new TypeError(\"WellSky SDK requires a server-side Node.js runtime\");\n if (!options.tenant.trim() || /[\\r\\n]/.test(options.tenant)) throw new TypeError(\"tenant is required and must be a valid header value\");\n const url = new URL(options.baseUrl ?? \"https://csclientapi.wellsky.com/client-api-prod\");\n if (!['https:', 'http:'].includes(url.protocol) || url.username || url.password || url.search || url.hash) throw new TypeError(\"baseUrl must be an HTTP(S) URL without credentials, query, or fragment\");\n if (url.protocol === 'http:' && !['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)) throw new TypeError(\"Use HTTPS except for loopback testing\");\n if (options.auth.kind === \"credentials\" && (!options.auth.username.trim() || !options.auth.password)) throw new TypeError(\"username and password are required\");\n if (options.auth.kind === \"token\" && (!options.auth.token.trim() || /\\s/.test(options.auth.token))) throw new TypeError(\"token must be a non-empty bearer token\");\n this.#baseUrl = url.toString().replace(/\\/$/, \"\");\n this.#tenant = options.tenant;\n this.#version = version;\n this.#auth = { ...options.auth };\n this.#fetch = options.fetch ?? globalThis.fetch;\n this.#schemas = schemas;\n const correction = options.mobileAssessmentDateCorrectionMinutes;\n if (correction !== undefined && (!Number.isSafeInteger(correction) || Math.abs(correction) > 840)) throw new ValidationError(\"client configuration\", [\"mobileAssessmentDateCorrectionMinutes\"]);\n this.#mobileDateCorrection = correction;\n this.#timeout = positiveInteger(options.timeoutMs ?? 30_000, \"timeoutMs\");\n this.#retries = positiveInteger(options.maxReadRetries ?? 2, \"maxReadRetries\", 0);\n this.#retryBase = positiveInteger(options.retryBaseDelayMs ?? 250, \"retryBaseDelayMs\", 0);\n this.#retryMax = positiveInteger(options.maxRetryDelayMs ?? 30_000, \"maxRetryDelayMs\", 0);\n const scope = JSON.stringify([this.#baseUrl, this.#tenant, identity(this.#fetch)]);\n this.#control = requestControl(scope, options);\n this.#shared = sharedAuthentication(scope, this.#auth);\n this.#observers = { ...(options.hooks ? { hooks: { ...options.hooks } } : {}), ...(options.logger ? { logger: options.logger } : {}) };\n if (this.#auth.kind === \"token\") this.#checkTokenTenant(this.#auth.token);\n }\n\n get tenant(): string { return this.#tenant; }\n get baseUrl(): string { return this.#baseUrl; }\n health(): ClientHealth { return this.#control.health(); }\n\n #checkTenant(value: unknown, operation: string): void {\n if (!isRecord(value)) return;\n for (const key of [\"tenant\", \"tenantCode\", \"tenant_code\", \"x-tenant\"]) {\n if (value[key] !== undefined && value[key] !== null && value[key] !== this.#tenant) throw new TenantMismatchError(operation);\n }\n }\n #checkTokenTenant(token: string): void {\n let payload: unknown;\n try {\n const segment = token.split(\".\")[1];\n if (!segment) return;\n const base64 = segment.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n payload = JSON.parse(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, \"=\")));\n } catch { return; }\n this.#checkTenant(payload, \"authentication token\");\n }\n\n async #send(url: string | URL, init: RequestInit & { signal: AbortSignal }, operation: string, correlationId: string, retryCount: number): Promise<Response> {\n this.#control.check(operation);\n const release = await this.#control.semaphore.acquire(init.signal, operation);\n const started = Date.now();\n const base = { operation, correlationId, retryCount };\n try {\n this.#control.check(operation);\n const headers = new Headers(init.headers);\n headers.set(\"x-correlation-id\", correlationId);\n emit(this.#observers, { ...base, type: \"request\" });\n const response = await this.#fetch(url, { ...init, headers });\n const event: ClientEvent = { ...base, type: \"response\", status: response.status, durationMs: Date.now() - started };\n emit(this.#observers, event);\n if (response.status === 429) emit(this.#observers, { ...event, type: \"throttle\", retryAfterMs: retryAfter(response.headers) ?? this.#retryBase });\n const until = this.#control.failed(response.status);\n if (until !== undefined) emit(this.#observers, { ...base, type: \"cooldown\", until: new Date(until).toISOString() });\n if (response.headers.has(\"x-tenant\") && response.headers.get(\"x-tenant\") !== this.#tenant) {\n await response.body?.cancel(); throw new TenantMismatchError(operation);\n }\n // Hold the concurrency slot through body consumption, not merely until headers arrive.\n const body = await response.arrayBuffer();\n return new Response(response.status === 204 || response.status === 205 || response.status === 304 ? null : body, { status: response.status, statusText: response.statusText, headers: response.headers });\n } finally { release(); }\n }\n\n #headers(token?: string): Headers {\n const headers = new Headers({ Accept: \"application/json\", \"x-tenant\": this.#tenant, \"x-version\": this.#version });\n if (token) headers.set(\"Authorization\", `Bearer ${token}`);\n return headers;\n }\n\n async #read(response: Response, operation: string, allowText = false): Promise<unknown> {\n if (!response.ok) {\n // Discard upstream error content; it may contain client data or credentials.\n await response.body?.cancel();\n const requestId = response.headers.get(\"x-request-id\") ?? response.headers.get(\"request-id\") ?? undefined;\n const wait = retryAfter(response.headers);\n if (response.status === 429) throw new ThrottledError(operation, wait ?? this.#retryBase, response.status, requestId);\n if (response.status === 401 || response.status === 403) throw new AuthError(operation, response.status);\n throw new UpstreamError(operation, response.status, requestId, wait);\n }\n const text = await response.text();\n if (!text.trim()) return null;\n let value: unknown;\n try { value = JSON.parse(text); }\n catch {\n if (allowText) return text;\n throw new WellSkyError(\"protocol\", operation);\n }\n this.#checkTenant(value, operation);\n return value;\n }\n\n async #mint(forceRefresh: boolean, shared: SharedAuthentication): Promise<string> {\n const operation = \"POST /authentication/SetAuthKey\";\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(new DOMException(\"Deadline exceeded\", \"TimeoutError\")), this.#timeout);\n const signal = controller.signal;\n let release: (() => void) | undefined;\n try {\n release = await tokenMintQueue.acquire(signal, operation);\n this.#control.check(operation);\n const correlationId = crypto.randomUUID();\n this.#control.tokenMintCount++;\n emit(this.#observers, { type: \"tokenMint\", operation, correlationId, retryCount: 0 });\n let token: unknown;\n if (this.#auth.kind === \"provider\") token = await withSignal(Promise.resolve().then(() => this.#auth.kind === \"provider\" ? this.#auth.getToken({ forceRefresh, signal }) : \"\"), signal, operation);\n else if (this.#auth.kind === \"credentials\") {\n const headers = this.#headers();\n headers.set(\"Content-Type\", \"application/json\");\n const response = await this.#send(`${this.#baseUrl}/authentication/SetAuthKey`, {\n method: \"POST\", headers, body: JSON.stringify({ username: this.#auth.username, password: this.#auth.password }), signal, redirect: \"error\", cache: \"no-store\",\n }, operation, correlationId, 0);\n const result = await this.#read(response, operation);\n token = isRecord(result) ? result.token : undefined;\n }\n if (typeof token !== \"string\" || !token || /\\s/.test(token)) throw new WellSkyError(\"protocol\", operation);\n this.#checkTokenTenant(token);\n const expiresAt = expiry(token);\n if (expiresAt !== 0 && expiresAt <= Date.now()) throw new WellSkyError(\"protocol\", operation);\n shared.cached = { token, expiresAt };\n return token;\n } catch (error) {\n if (signal.aborted) throw abortError(signal, operation);\n if (error instanceof WellSkyError) throw error;\n throw new WellSkyError(\"network\", operation);\n } finally { release?.(); clearTimeout(timer); }\n }\n\n async #token(rejectedToken?: string): Promise<string | undefined> {\n if (this.#auth.kind === \"none\") return Promise.resolve(undefined);\n if (this.#auth.kind === \"token\") return Promise.resolve(this.#auth.token);\n const shared = await this.#shared;\n // An older request's late 401 must not evict a newer token.\n if (rejectedToken && shared.cached?.token !== rejectedToken && shared.cached) return shared.cached.token;\n if (shared.inFlight) return shared.inFlight;\n if (!rejectedToken && shared.cached && shared.cached.expiresAt > Date.now() + 120_000) return shared.cached.token;\n shared.cached = undefined;\n shared.inFlight = this.#mint(Boolean(rejectedToken), shared).finally(() => { shared.inFlight = undefined; });\n return shared.inFlight;\n }\n\n async execute<T>(definition: OperationDefinition, args: Arguments): Promise<T> {\n const operation = `${definition.method} ${definition.path}`;\n const correlationId = args.correlationId ?? crypto.randomUUID();\n if (!/^[A-Za-z0-9_.:-]{1,128}$/.test(correlationId)) throw new ValidationError(operation, [\"correlationId\"]);\n const timeout = positiveInteger(args.timeoutMs ?? this.#timeout, \"timeoutMs\");\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(new DOMException(\"Deadline exceeded\", \"TimeoutError\")), timeout);\n const signal = args.signal ? AbortSignal.any([args.signal, controller.signal]) : controller.signal;\n try {\n if (signal.aborted) throw abortError(signal, operation);\n this.#control.check(operation);\n if (!matches(args.path ?? {}, definition.pathSchema, this.#schemas, \"request\") || !matches(args.query ?? {}, definition.querySchema, this.#schemas, \"request\") || (definition.bodySchema && !matches(args.body, definition.bodySchema, this.#schemas, \"request\"))) throw new ValidationError(operation);\n // Check file bytes before multipart construction or credential authentication.\n if (definition.multipart && isRecord(args.body) && args.body.fileData instanceof Blob && args.body.fileData.size > 10_000_000) throw new ValidationError(operation, [\"fileData\"]);\n const pathValues = new Map(Object.entries(args.path ?? {}));\n const path = definition.path.replace(/\\{([^}]+)\\}/g, (_, name: string) => {\n const value = String(pathValues.get(name));\n if (value === \".\" || value === \"..\") throw new WellSkyError(\"validation\", operation);\n return encodeURIComponent(value);\n });\n const url = new URL(this.#baseUrl + path);\n for (const [name, value] of Object.entries(args.query ?? {})) {\n if (value !== undefined && value !== null) {\n const encoded = this.#mobileDateCorrection !== undefined && name === \"dateEffective\" && operation === \"POST /assessmentsmobile/AddAssessmentAnswer/{clientId}/{assessmentCode}\"\n ? correctMobileEffectiveDate(value, this.#mobileDateCorrection, operation) : String(value);\n url.searchParams.set(name, encoded);\n }\n }\n let body: string | FormData | undefined;\n if (definition.multipart && isRecord(args.body)) {\n body = new FormData();\n for (const [name, value] of Object.entries(args.body)) {\n if (value !== undefined && value !== null) body.append(name, value instanceof Blob ? value : String(value));\n }\n } else if (args.body !== undefined) body = JSON.stringify(args.body);\n let token = definition.authenticated ? await withSignal(this.#token(), signal, operation) : undefined;\n let refreshed = false;\n let attempts = 0;\n while (true) {\n try {\n const headers = this.#headers(token);\n if (typeof body === \"string\") headers.set(\"Content-Type\", \"application/json\");\n const response = await this.#send(url, { method: definition.method, headers, ...(body === undefined ? {} : { body }), signal, redirect: \"error\", cache: \"no-store\" }, operation, correlationId, attempts);\n // Reads can refresh once. Writes are never automatically sent twice, even after a 401.\n if (response.status === 401 && definition.method === \"GET\" && definition.authenticated && !refreshed && (this.#auth.kind === \"credentials\" || this.#auth.kind === \"provider\")) {\n await response.body?.cancel();\n refreshed = true;\n token = await withSignal(this.#token(token), signal, operation);\n continue;\n }\n const result = await this.#read(response, operation, definition.responseSchema === undefined);\n return decodeResponse<T>(result, definition.responseSchema, this.#schemas, operation);\n } catch (error) {\n if (signal.aborted) throw abortError(signal, operation);\n const failure = error instanceof WellSkyError ? error : new WellSkyError(\"network\", operation);\n const retryable = failure.kind === \"network\" || ((failure.kind === \"http\" || failure.kind === \"throttled\") && retryStatuses.has(failure.status ?? 0));\n if (definition.method !== \"GET\" || failure.operation !== operation || !retryable || attempts >= this.#retries) throw failure;\n const wait = failure.retryAfterMs ?? Math.min(this.#retryMax, this.#retryBase * 2 ** attempts * (1 + Math.random() * 0.2));\n // Never retry earlier than Retry-After. Return the error if the delay exceeds our bound.\n if (wait > this.#retryMax) throw failure;\n attempts++;\n await delay(wait, signal, operation);\n }\n }\n } catch (error) {\n if (signal.aborted) { const error = abortError(signal, operation); error.correlationId = correlationId; throw error; }\n if (error instanceof WellSkyError) error.correlationId = correlationId;\n if (error instanceof WellSkyError || error instanceof TypeError) throw error;\n throw new WellSkyError(\"network\", operation);\n } finally { clearTimeout(timer); }\n }\n\n async *paginate<T>(definition: OperationDefinition, args: Arguments & PaginationOptions): AsyncGenerator<T> {\n const operation = `${definition.method} ${definition.path}`;\n const query = Object.fromEntries(Object.entries(args.query ?? {}));\n const start = positiveInteger(typeof query.startPage === \"number\" ? query.startPage : 1, \"startPage\");\n positiveInteger(typeof query.perPage === \"number\" ? query.perPage : 30, \"perPage\");\n const maxPages = positiveInteger(args.maxPages ?? 10_000, \"maxPages\");\n for (let page = 0; page < maxPages; page++) {\n const response = await this.execute<ApiResponse<T>>(definition, { ...args, query: { perPage: 30, ...query, startPage: start + page } });\n const items = toItems(response);\n if (!items.length) return;\n yield* items;\n // Continue through short pages: some tenants cap perPage below the requested size.\n }\n throw new WellSkyError(\"pagination\", operation);\n }\n}\n"]}
|
package/dist/esm/v2.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./generated/v2.js";
|
|
2
|
+
export * from "./generated/v2-models.js";
|
|
3
|
+
export * from "./runtime.js";
|
|
4
|
+
export * from "./metadata.js";
|
|
5
|
+
export * from "./errors.js";
|
|
6
|
+
export * from "./encoding.js";
|
|
7
|
+
export * from "./verification.js";
|
|
8
|
+
export * from "./bulk.js";
|
|
9
|
+
export * from "./subassessments.js";
|
|
10
|
+
export * from "./enrollment-verifications.js";
|
|
11
|
+
export * from "./gwt-enrollments.js";
|
|
12
|
+
export * from "./program-discovery.js";
|
|
13
|
+
//# sourceMappingURL=v2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2.d.ts","sourceRoot":"","sources":["../../src/v2.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAE9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC"}
|
package/dist/esm/v2.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./generated/v2.js";
|
|
2
|
+
export * from "./generated/v2-models.js";
|
|
3
|
+
export * from "./runtime.js";
|
|
4
|
+
export * from "./metadata.js";
|
|
5
|
+
export * from "./errors.js";
|
|
6
|
+
export * from "./encoding.js";
|
|
7
|
+
export * from "./verification.js";
|
|
8
|
+
export * from "./bulk.js";
|
|
9
|
+
export * from "./subassessments.js";
|
|
10
|
+
export * from "./enrollment-verifications.js";
|
|
11
|
+
export * from "./gwt-enrollments.js";
|
|
12
|
+
export * from "./program-discovery.js";
|
|
13
|
+
//# sourceMappingURL=v2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2.js","sourceRoot":"","sources":["../../src/v2.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAE9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC","sourcesContent":["export * from \"./generated/v2.js\";\nexport * from \"./generated/v2-models.js\";\nexport * from \"./runtime.js\";\nexport * from \"./metadata.js\";\nexport * from \"./errors.js\";\nexport * from \"./encoding.js\";\nexport * from \"./verification.js\";\nexport * from \"./bulk.js\";\nexport * from \"./subassessments.js\";\nexport * from \"./enrollment-verifications.js\";\n\nexport * from \"./gwt-enrollments.js\";\nexport * from \"./program-discovery.js\";\n"]}
|
package/dist/esm/v3.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./generated/v3.js";
|
|
2
|
+
export * from "./generated/v3-models.js";
|
|
3
|
+
export * from "./runtime.js";
|
|
4
|
+
export * from "./metadata.js";
|
|
5
|
+
export * from "./errors.js";
|
|
6
|
+
export * from "./encoding.js";
|
|
7
|
+
export * from "./verification.js";
|
|
8
|
+
export * from "./bulk.js";
|
|
9
|
+
export * from "./subassessments.js";
|
|
10
|
+
export * from "./enrollment-verifications.js";
|
|
11
|
+
export * from "./gwt-enrollments.js";
|
|
12
|
+
export * from "./program-discovery.js";
|
|
13
|
+
//# sourceMappingURL=v3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3.d.ts","sourceRoot":"","sources":["../../src/v3.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAE9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC"}
|
package/dist/esm/v3.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./generated/v3.js";
|
|
2
|
+
export * from "./generated/v3-models.js";
|
|
3
|
+
export * from "./runtime.js";
|
|
4
|
+
export * from "./metadata.js";
|
|
5
|
+
export * from "./errors.js";
|
|
6
|
+
export * from "./encoding.js";
|
|
7
|
+
export * from "./verification.js";
|
|
8
|
+
export * from "./bulk.js";
|
|
9
|
+
export * from "./subassessments.js";
|
|
10
|
+
export * from "./enrollment-verifications.js";
|
|
11
|
+
export * from "./gwt-enrollments.js";
|
|
12
|
+
export * from "./program-discovery.js";
|
|
13
|
+
//# sourceMappingURL=v3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3.js","sourceRoot":"","sources":["../../src/v3.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAE9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC","sourcesContent":["export * from \"./generated/v3.js\";\nexport * from \"./generated/v3-models.js\";\nexport * from \"./runtime.js\";\nexport * from \"./metadata.js\";\nexport * from \"./errors.js\";\nexport * from \"./encoding.js\";\nexport * from \"./verification.js\";\nexport * from \"./bulk.js\";\nexport * from \"./subassessments.js\";\nexport * from \"./enrollment-verifications.js\";\n\nexport * from \"./gwt-enrollments.js\";\nexport * from \"./program-discovery.js\";\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface Schema {
|
|
2
|
+
$ref?: string;
|
|
3
|
+
type?: string;
|
|
4
|
+
format?: string;
|
|
5
|
+
nullable?: boolean;
|
|
6
|
+
properties?: Record<string, Schema>;
|
|
7
|
+
required?: string[];
|
|
8
|
+
items?: Schema;
|
|
9
|
+
additionalProperties?: boolean | Schema;
|
|
10
|
+
minLength?: number;
|
|
11
|
+
maxLength?: number;
|
|
12
|
+
pattern?: string;
|
|
13
|
+
default?: unknown;
|
|
14
|
+
enum?: unknown[];
|
|
15
|
+
}
|
|
16
|
+
export type SchemaRegistry = Record<string, Schema>;
|
|
17
|
+
export type Method = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
|
18
|
+
export interface OperationDefinition {
|
|
19
|
+
method: Method;
|
|
20
|
+
path: string;
|
|
21
|
+
authenticated: boolean;
|
|
22
|
+
pathSchema: Schema;
|
|
23
|
+
querySchema: Schema;
|
|
24
|
+
bodySchema?: Schema;
|
|
25
|
+
responseSchema?: Schema;
|
|
26
|
+
multipart: boolean;
|
|
27
|
+
pageable: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
30
|
+
/** Validates the structural subset used by the pinned specifications. */
|
|
31
|
+
export declare function matches(value: unknown, schema: Schema, registry: SchemaRegistry, mode: "request" | "response", depth?: number): boolean;
|
|
32
|
+
export declare function decodeResponse<T>(value: unknown, schema: Schema | undefined, registry: SchemaRegistry, operation: string): T;
|
|
33
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/validation.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;CAClB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACpD,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AACtF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,EAAE,KAAK,SAAI,GAAG,OAAO,CAiClI;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC,CAgB5H"}
|