@ovok/core 0.4.49-dev.495 → 0.4.49-dev.496

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.
Files changed (235) hide show
  1. package/dist/client/observation/measurement-fields.d.ts +1 -1
  2. package/dist/client/observation/methods/observationsToMeasurements.d.ts +1 -1
  3. package/dist/client/observation/methods/observationsToMeasurements.js +59 -59
  4. package/dist/client/observation/services/base-observation-service.d.ts +1 -1
  5. package/dist/client/observation/services/blood-oxygen.d.ts +1 -1
  6. package/dist/client/observation/services/blood-oxygen.js +7 -7
  7. package/dist/client/observation/services/blood-pressure.d.ts +1 -1
  8. package/dist/client/observation/services/blood-pressure.js +16 -16
  9. package/dist/client/observation/services/component-observation-services.d.ts +1 -1
  10. package/dist/client/observation/services/component-observation-services.js +3 -3
  11. package/dist/client/observation/services/creator.d.ts +1 -1
  12. package/dist/client/observation/services/creator.js +10 -10
  13. package/dist/client/observation/services/ecg-observation-fragments.d.ts +1 -1
  14. package/dist/client/observation/services/ecg.d.ts +1 -1
  15. package/dist/client/observation/services/ecg.js +10 -10
  16. package/dist/client/observation/services/lipid-panel.d.ts +1 -1
  17. package/dist/client/observation/services/lipid-panel.js +13 -13
  18. package/dist/client/observation/services/single-value-services.d.ts +1 -1
  19. package/dist/client/observation/services/single-value-services.js +19 -19
  20. package/dist/client/observation/services/step-count.d.ts +1 -1
  21. package/dist/client/observation/services/step-count.js +5 -5
  22. package/dist/client/observation/services/uric-acid-service.d.ts +1 -1
  23. package/dist/client/observation/services/uric-acid-service.js +7 -7
  24. package/dist/client/offline/offline-measurement-queue.d.ts +1 -2
  25. package/dist/client/wearables/types.d.ts +5 -0
  26. package/dist/conformance/capability-requirements.js +1 -1
  27. package/dist/next/auth/access-token.d.ts +9 -0
  28. package/dist/next/auth/access-token.js +18 -0
  29. package/dist/next/auth/client-credentials.d.ts +16 -0
  30. package/dist/next/auth/client-credentials.js +40 -0
  31. package/dist/next/auth/credentials.d.ts +5 -0
  32. package/dist/next/auth/credentials.js +7 -0
  33. package/dist/next/auth/session-store.d.ts +12 -0
  34. package/dist/next/auth/session-store.js +33 -0
  35. package/dist/next/auth/session.d.ts +28 -0
  36. package/dist/next/auth/session.js +27 -0
  37. package/dist/next/auth/token-endpoint.d.ts +12 -0
  38. package/dist/next/auth/token-endpoint.js +28 -0
  39. package/dist/next/auth/user-session.d.ts +27 -0
  40. package/dist/next/auth/user-session.js +82 -0
  41. package/dist/next/config/ovok-config.d.ts +42 -0
  42. package/dist/next/config/ovok-config.js +2 -0
  43. package/dist/next/config/settings.d.ts +6 -0
  44. package/dist/next/config/settings.js +74 -0
  45. package/dist/next/errors/error-from-response.d.ts +2 -0
  46. package/dist/next/errors/error-from-response.js +35 -0
  47. package/dist/next/errors/ovok-errors.d.ts +42 -0
  48. package/dist/next/errors/ovok-errors.js +74 -0
  49. package/dist/next/http/http-client.d.ts +35 -0
  50. package/dist/next/http/http-client.js +113 -0
  51. package/dist/next/http/retry-after.d.ts +1 -0
  52. package/dist/next/http/retry-after.js +16 -0
  53. package/dist/next/http/retry-policy.d.ts +13 -0
  54. package/dist/next/http/retry-policy.js +27 -0
  55. package/dist/next/http/transmit.d.ts +14 -0
  56. package/dist/next/http/transmit.js +57 -0
  57. package/dist/next/http/url.d.ts +6 -0
  58. package/dist/next/http/url.js +22 -0
  59. package/dist/next/index.d.ts +69 -0
  60. package/dist/next/index.js +33 -0
  61. package/dist/next/ovok.d.ts +52 -0
  62. package/dist/next/ovok.js +74 -0
  63. package/dist/next/paging/bundle-page.d.ts +4 -0
  64. package/dist/next/paging/bundle-page.js +25 -0
  65. package/dist/next/paging/cursor-pages.d.ts +7 -0
  66. package/dist/next/paging/cursor-pages.js +14 -0
  67. package/dist/next/paging/numbered-pages.d.ts +15 -0
  68. package/dist/next/paging/numbered-pages.js +20 -0
  69. package/dist/next/paging/page.d.ts +12 -0
  70. package/dist/next/paging/page.js +17 -0
  71. package/dist/next/resources/accounts/accounts-resource.d.ts +8 -0
  72. package/dist/next/resources/accounts/accounts-resource.js +13 -0
  73. package/dist/next/resources/ai/ai-chat-resource.d.ts +8 -0
  74. package/dist/next/resources/ai/ai-chat-resource.js +12 -0
  75. package/dist/next/resources/ai/ai-resource.d.ts +16 -0
  76. package/dist/next/resources/ai/ai-resource.js +19 -0
  77. package/dist/next/resources/ai/chat-messages-resource.d.ts +9 -0
  78. package/dist/next/resources/ai/chat-messages-resource.js +18 -0
  79. package/dist/next/resources/ai/chat-sessions-resource.d.ts +14 -0
  80. package/dist/next/resources/ai/chat-sessions-resource.js +23 -0
  81. package/dist/next/resources/auth/auth-sessions-resource.d.ts +13 -0
  82. package/dist/next/resources/auth/auth-sessions-resource.js +25 -0
  83. package/dist/next/resources/auth/registration.d.ts +35 -0
  84. package/dist/next/resources/auth/registration.js +24 -0
  85. package/dist/next/resources/auth/social-login.d.ts +8 -0
  86. package/dist/next/resources/auth/social-login.js +7 -0
  87. package/dist/next/resources/auth-resource.d.ts +63 -0
  88. package/dist/next/resources/auth-resource.js +119 -0
  89. package/dist/next/resources/bots/bots-resource.d.ts +10 -0
  90. package/dist/next/resources/bots/bots-resource.js +15 -0
  91. package/dist/next/resources/cms/cms-delivery.d.ts +22 -0
  92. package/dist/next/resources/cms/cms-delivery.js +36 -0
  93. package/dist/next/resources/cms/cms-documents-resource.d.ts +11 -0
  94. package/dist/next/resources/cms/cms-documents-resource.js +17 -0
  95. package/dist/next/resources/cms/cms-resource.d.ts +17 -0
  96. package/dist/next/resources/cms/cms-resource.js +38 -0
  97. package/dist/next/resources/cms/payload-pages.d.ts +6 -0
  98. package/dist/next/resources/cms/payload-pages.js +15 -0
  99. package/dist/next/resources/cms/release-notes-resource.d.ts +10 -0
  100. package/dist/next/resources/cms/release-notes-resource.js +15 -0
  101. package/dist/next/resources/cms/translation-tree.d.ts +3 -0
  102. package/dist/next/resources/cms/translation-tree.js +45 -0
  103. package/dist/next/resources/consent/consent-resource.d.ts +23 -0
  104. package/dist/next/resources/consent/consent-resource.js +43 -0
  105. package/dist/next/resources/content/content-resource.d.ts +19 -0
  106. package/dist/next/resources/content/content-resource.js +41 -0
  107. package/dist/next/resources/documents/documents-resource.d.ts +26 -0
  108. package/dist/next/resources/documents/documents-resource.js +41 -0
  109. package/dist/next/resources/email/email-resource.d.ts +6 -0
  110. package/dist/next/resources/email/email-resource.js +10 -0
  111. package/dist/next/resources/email/email-templates-resource.d.ts +8 -0
  112. package/dist/next/resources/email/email-templates-resource.js +13 -0
  113. package/dist/next/resources/fhir-resource.d.ts +28 -0
  114. package/dist/next/resources/fhir-resource.js +64 -0
  115. package/dist/next/resources/health-resource.d.ts +17 -0
  116. package/dist/next/resources/health-resource.js +14 -0
  117. package/dist/next/resources/invites/invite-flow-resource.d.ts +12 -0
  118. package/dist/next/resources/invites/invite-flow-resource.js +19 -0
  119. package/dist/next/resources/invites/invites-resource.d.ts +17 -0
  120. package/dist/next/resources/invites/invites-resource.js +14 -0
  121. package/dist/next/resources/localization/i18next-resource.d.ts +10 -0
  122. package/dist/next/resources/localization/i18next-resource.js +18 -0
  123. package/dist/next/resources/localization/locales-resource.d.ts +9 -0
  124. package/dist/next/resources/localization/locales-resource.js +16 -0
  125. package/dist/next/resources/localization/localizations-resource.d.ts +17 -0
  126. package/dist/next/resources/localization/localizations-resource.js +27 -0
  127. package/dist/next/resources/measurements/measurements-resource.d.ts +42 -0
  128. package/dist/next/resources/measurements/measurements-resource.js +77 -0
  129. package/dist/next/resources/measurements/observation-builder.d.ts +5 -0
  130. package/dist/next/resources/measurements/observation-builder.js +57 -0
  131. package/dist/next/resources/measurements/save-error.d.ts +5 -0
  132. package/dist/next/resources/measurements/save-error.js +18 -0
  133. package/dist/next/resources/measurements/signed-in-account.d.ts +11 -0
  134. package/dist/next/resources/measurements/signed-in-account.js +26 -0
  135. package/dist/next/resources/patient/fhir-records.d.ts +19 -0
  136. package/dist/next/resources/patient/fhir-records.js +33 -0
  137. package/dist/next/resources/patient/patient-resource.d.ts +21 -0
  138. package/dist/next/resources/patient/patient-resource.js +38 -0
  139. package/dist/next/resources/projects/project-features-resource.d.ts +9 -0
  140. package/dist/next/resources/projects/project-features-resource.js +17 -0
  141. package/dist/next/resources/projects/project-members-resource.d.ts +19 -0
  142. package/dist/next/resources/projects/project-members-resource.js +25 -0
  143. package/dist/next/resources/projects/project-settings-resource.d.ts +10 -0
  144. package/dist/next/resources/projects/project-settings-resource.js +21 -0
  145. package/dist/next/resources/projects/projects-resource.d.ts +20 -0
  146. package/dist/next/resources/projects/projects-resource.js +21 -0
  147. package/dist/next/resources/questionnaires/questionnaires-resource.d.ts +18 -0
  148. package/dist/next/resources/questionnaires/questionnaires-resource.js +36 -0
  149. package/dist/next/resources/sharing/sharing-invites-resource.d.ts +9 -0
  150. package/dist/next/resources/sharing/sharing-invites-resource.js +17 -0
  151. package/dist/next/resources/sharing/sharing-resource.d.ts +10 -0
  152. package/dist/next/resources/sharing/sharing-resource.js +14 -0
  153. package/dist/next/resources/sharing/sharing-settings-resource.d.ts +9 -0
  154. package/dist/next/resources/sharing/sharing-settings-resource.js +16 -0
  155. package/dist/next/resources/sharing/sharing-shares-resource.d.ts +9 -0
  156. package/dist/next/resources/sharing/sharing-shares-resource.js +27 -0
  157. package/dist/next/resources/signals/signals-gateway-resource.d.ts +14 -0
  158. package/dist/next/resources/signals/signals-gateway-resource.js +44 -0
  159. package/dist/next/resources/signals/signals-resource.d.ts +13 -0
  160. package/dist/next/resources/signals/signals-resource.js +19 -0
  161. package/dist/next/resources/signals/undeliverable-resource.d.ts +26 -0
  162. package/dist/next/resources/signals/undeliverable-resource.js +18 -0
  163. package/dist/next/resources/slim/live-reads.d.ts +12 -0
  164. package/dist/next/resources/slim/live-reads.js +76 -0
  165. package/dist/next/resources/slim/slim-alarms-resource.d.ts +13 -0
  166. package/dist/next/resources/slim/slim-alarms-resource.js +25 -0
  167. package/dist/next/resources/slim/slim-change-history-resource.d.ts +9 -0
  168. package/dist/next/resources/slim/slim-change-history-resource.js +19 -0
  169. package/dist/next/resources/slim/slim-child-projects-resource.d.ts +17 -0
  170. package/dist/next/resources/slim/slim-child-projects-resource.js +22 -0
  171. package/dist/next/resources/slim/slim-devices-resource.d.ts +28 -0
  172. package/dist/next/resources/slim/slim-devices-resource.js +80 -0
  173. package/dist/next/resources/slim/slim-exports-resource.d.ts +8 -0
  174. package/dist/next/resources/slim/slim-exports-resource.js +14 -0
  175. package/dist/next/resources/slim/slim-locations-resource.d.ts +14 -0
  176. package/dist/next/resources/slim/slim-locations-resource.js +30 -0
  177. package/dist/next/resources/slim/slim-medical-notifications-resource.d.ts +18 -0
  178. package/dist/next/resources/slim/slim-medical-notifications-resource.js +46 -0
  179. package/dist/next/resources/slim/slim-notification-notes-resource.d.ts +12 -0
  180. package/dist/next/resources/slim/slim-notification-notes-resource.js +34 -0
  181. package/dist/next/resources/slim/slim-notifications-resource.d.ts +19 -0
  182. package/dist/next/resources/slim/slim-notifications-resource.js +26 -0
  183. package/dist/next/resources/slim/slim-organizations-resource.d.ts +11 -0
  184. package/dist/next/resources/slim/slim-organizations-resource.js +25 -0
  185. package/dist/next/resources/slim/slim-out-of-bed-resource.d.ts +13 -0
  186. package/dist/next/resources/slim/slim-out-of-bed-resource.js +20 -0
  187. package/dist/next/resources/slim/slim-paths.d.ts +6 -0
  188. package/dist/next/resources/slim/slim-paths.js +9 -0
  189. package/dist/next/resources/slim/slim-patient-thresholds-resource.d.ts +10 -0
  190. package/dist/next/resources/slim/slim-patient-thresholds-resource.js +20 -0
  191. package/dist/next/resources/slim/slim-patients-resource.d.ts +20 -0
  192. package/dist/next/resources/slim/slim-patients-resource.js +39 -0
  193. package/dist/next/resources/slim/slim-policies-resource.d.ts +12 -0
  194. package/dist/next/resources/slim/slim-policies-resource.js +29 -0
  195. package/dist/next/resources/slim/slim-practitioners-resource.d.ts +8 -0
  196. package/dist/next/resources/slim/slim-practitioners-resource.js +14 -0
  197. package/dist/next/resources/slim/slim-projects-resource.d.ts +16 -0
  198. package/dist/next/resources/slim/slim-projects-resource.js +35 -0
  199. package/dist/next/resources/slim/slim-queries.d.ts +34 -0
  200. package/dist/next/resources/slim/slim-queries.js +2 -0
  201. package/dist/next/resources/slim/slim-resource.d.ts +38 -0
  202. package/dist/next/resources/slim/slim-resource.js +44 -0
  203. package/dist/next/resources/slim/slim-sleep-resource.d.ts +9 -0
  204. package/dist/next/resources/slim/slim-sleep-resource.js +15 -0
  205. package/dist/next/resources/slim/slim-thresholds-resource.d.ts +11 -0
  206. package/dist/next/resources/slim/slim-thresholds-resource.js +18 -0
  207. package/dist/next/resources/slim/slim-trends-resource.d.ts +11 -0
  208. package/dist/next/resources/slim/slim-trends-resource.js +19 -0
  209. package/dist/next/resources/slim/slim-users-resource.d.ts +11 -0
  210. package/dist/next/resources/slim/slim-users-resource.js +15 -0
  211. package/dist/next/resources/slim/slim-zones-resource.d.ts +12 -0
  212. package/dist/next/resources/slim/slim-zones-resource.js +24 -0
  213. package/dist/next/resources/video-calls/video-call-access-resource.d.ts +11 -0
  214. package/dist/next/resources/video-calls/video-call-access-resource.js +19 -0
  215. package/dist/next/resources/video-calls/video-call-appointments-resource.d.ts +10 -0
  216. package/dist/next/resources/video-calls/video-call-appointments-resource.js +21 -0
  217. package/dist/next/resources/video-calls/video-call-emails-resource.d.ts +10 -0
  218. package/dist/next/resources/video-calls/video-call-emails-resource.js +19 -0
  219. package/dist/next/resources/video-calls/video-calls-resource.d.ts +14 -0
  220. package/dist/next/resources/video-calls/video-calls-resource.js +20 -0
  221. package/dist/next/resources/wearables/wearable-connections-resource.d.ts +12 -0
  222. package/dist/next/resources/wearables/wearable-connections-resource.js +25 -0
  223. package/dist/next/resources/wearables/wearable-providers-resource.d.ts +12 -0
  224. package/dist/next/resources/wearables/wearable-providers-resource.js +27 -0
  225. package/dist/next/resources/wearables/wearables-resource.d.ts +8 -0
  226. package/dist/next/resources/wearables/wearables-resource.js +14 -0
  227. package/dist/next/storage/ovok-storage.d.ts +11 -0
  228. package/dist/next/storage/ovok-storage.js +19 -0
  229. package/dist/types/MeasurementTypes.d.ts +5 -0
  230. package/dist/types/MeasurementTypes.js +21 -0
  231. package/dist/types/index.d.ts +1 -5
  232. package/dist/types/index.js +1 -5
  233. package/next/index.d.ts +1 -0
  234. package/next/index.js +3 -0
  235. package/package.json +3 -2
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UserSession = void 0;
4
+ const ovok_errors_1 = require("../errors/ovok-errors");
5
+ const session_1 = require("./session");
6
+ const REJECTED_REFRESH_STATUSES = new Set([400, 401, 403]);
7
+ class UserSession {
8
+ constructor(store, endpoint, settings, now = Date.now) {
9
+ this.store = store;
10
+ this.endpoint = endpoint;
11
+ this.settings = settings;
12
+ this.now = now;
13
+ this.loaded = null;
14
+ this.pendingRefresh = null;
15
+ }
16
+ current() {
17
+ var _a;
18
+ (_a = this.loaded) !== null && _a !== void 0 ? _a : (this.loaded = this.store.load());
19
+ return this.loaded;
20
+ }
21
+ async begin(tokens) {
22
+ const session = (0, session_1.sessionFromLogin)(tokens, this.now());
23
+ await this.save(session);
24
+ return session;
25
+ }
26
+ async end() {
27
+ this.loaded = Promise.resolve(null);
28
+ await this.store.clear();
29
+ }
30
+ async accessToken() {
31
+ var _a, _b;
32
+ const session = await this.current();
33
+ const refreshable = session !== null && session.refreshToken !== null;
34
+ if (refreshable && (0, session_1.isSessionStaleAt)(session, this.now())) {
35
+ await this.refresh();
36
+ }
37
+ return (_b = (_a = (await this.current())) === null || _a === void 0 ? void 0 : _a.accessToken) !== null && _b !== void 0 ? _b : null;
38
+ }
39
+ refresh() {
40
+ var _a;
41
+ (_a = this.pendingRefresh) !== null && _a !== void 0 ? _a : (this.pendingRefresh = this.exchangeRefreshToken().finally(() => {
42
+ this.pendingRefresh = null;
43
+ }));
44
+ return this.pendingRefresh;
45
+ }
46
+ async exchangeRefreshToken() {
47
+ var _a;
48
+ const session = await this.current();
49
+ const refreshToken = (_a = session === null || session === void 0 ? void 0 : session.refreshToken) !== null && _a !== void 0 ? _a : null;
50
+ if (session === null || refreshToken === null) {
51
+ return false;
52
+ }
53
+ try {
54
+ const response = await this.endpoint.request(this.refreshForm(refreshToken));
55
+ await this.save((0, session_1.sessionAfterRefresh)(session, response, this.now()));
56
+ return true;
57
+ }
58
+ catch (error) {
59
+ return this.signOutIfRejected(error);
60
+ }
61
+ }
62
+ /** Only a refused refresh token signs the user out; an outage keeps the session for a later retry. */
63
+ async signOutIfRejected(error) {
64
+ const status = error instanceof ovok_errors_1.OvokError ? error.status : null;
65
+ const rejected = status !== null && REJECTED_REFRESH_STATUSES.has(status);
66
+ if (rejected) {
67
+ await this.end();
68
+ this.settings.onUnauthenticated({ type: "refresh-rejected", status });
69
+ return false;
70
+ }
71
+ throw error;
72
+ }
73
+ refreshForm(refreshToken) {
74
+ const client = this.settings.clientId ? { client_id: this.settings.clientId } : {};
75
+ return { grant_type: "refresh_token", refresh_token: refreshToken, ...client };
76
+ }
77
+ async save(session) {
78
+ this.loaded = Promise.resolve(session);
79
+ await this.store.save(session);
80
+ }
81
+ }
82
+ exports.UserSession = UserSession;
@@ -0,0 +1,42 @@
1
+ import { OvokStorage } from "../storage/ovok-storage";
2
+ export type OvokFetch = (url: string, init: RequestInit) => Promise<Response>;
3
+ export type OvokUnauthenticatedReason = {
4
+ type: "refresh-rejected";
5
+ status: number;
6
+ };
7
+ type OvokBaseConfig = {
8
+ baseUrl: string;
9
+ tenantCode: string;
10
+ fhirPath?: string;
11
+ storage?: OvokStorage;
12
+ fetch?: OvokFetch;
13
+ timeoutMs?: number;
14
+ maxNetworkRetries?: number;
15
+ onUnauthenticated?: (reason: OvokUnauthenticatedReason) => void;
16
+ };
17
+ type OvokUserClientConfig = {
18
+ clientId?: string;
19
+ clientSecret?: undefined;
20
+ };
21
+ type OvokMachineClientConfig = {
22
+ clientId: string;
23
+ clientSecret: string;
24
+ };
25
+ export type OvokConfig = OvokBaseConfig & (OvokUserClientConfig | OvokMachineClientConfig);
26
+ export type MachineClient = {
27
+ clientId: string;
28
+ clientSecret: string;
29
+ };
30
+ export type OvokSettings = {
31
+ baseUrl: string;
32
+ tenantCode: string;
33
+ fhirPath: string;
34
+ storage: OvokStorage;
35
+ fetch: OvokFetch;
36
+ timeoutMs: number;
37
+ maxNetworkRetries: number;
38
+ clientId: string | null;
39
+ machineClient: MachineClient | null;
40
+ onUnauthenticated: (reason: OvokUnauthenticatedReason) => void;
41
+ };
42
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import { OvokConfig, OvokSettings } from "./ovok-config";
2
+ export type RuntimeEnvironment = {
3
+ hasDocument: boolean;
4
+ };
5
+ export declare const currentEnvironment: () => RuntimeEnvironment;
6
+ export declare function readSettings(config: OvokConfig, environment: RuntimeEnvironment): OvokSettings;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.currentEnvironment = void 0;
4
+ exports.readSettings = readSettings;
5
+ const ovok_errors_1 = require("../errors/ovok-errors");
6
+ const ovok_storage_1 = require("../storage/ovok-storage");
7
+ const DEFAULT_FHIR_PATH = "fhir";
8
+ const DEFAULT_TIMEOUT_MS = 30000;
9
+ const DEFAULT_MAX_NETWORK_RETRIES = 2;
10
+ const ABSOLUTE_HTTP_URL = /^https?:\/\/[^/\s]+/i;
11
+ const currentEnvironment = () => ({ hasDocument: typeof document !== "undefined" });
12
+ exports.currentEnvironment = currentEnvironment;
13
+ function readSettings(config, environment) {
14
+ var _a, _b, _c, _d, _e, _f, _g;
15
+ const machineClient = readMachineClient(config, environment);
16
+ return {
17
+ baseUrl: readBaseUrl(config.baseUrl),
18
+ tenantCode: requireText(config.tenantCode, "tenantCode"),
19
+ fhirPath: trimSlashes((_a = config.fhirPath) !== null && _a !== void 0 ? _a : DEFAULT_FHIR_PATH),
20
+ storage: (_b = config.storage) !== null && _b !== void 0 ? _b : new ovok_storage_1.MemoryStorage(),
21
+ fetch: (_c = config.fetch) !== null && _c !== void 0 ? _c : globalFetch(),
22
+ timeoutMs: requirePositive((_d = config.timeoutMs) !== null && _d !== void 0 ? _d : DEFAULT_TIMEOUT_MS, "timeoutMs"),
23
+ maxNetworkRetries: requireCount((_e = config.maxNetworkRetries) !== null && _e !== void 0 ? _e : DEFAULT_MAX_NETWORK_RETRIES, "maxNetworkRetries"),
24
+ clientId: (_f = config.clientId) !== null && _f !== void 0 ? _f : null,
25
+ machineClient,
26
+ onUnauthenticated: (_g = config.onUnauthenticated) !== null && _g !== void 0 ? _g : (() => undefined),
27
+ };
28
+ }
29
+ const configError = (message) => new ovok_errors_1.OvokConfigError((0, ovok_errors_1.detailsFor)(message));
30
+ const readBaseUrl = (baseUrl) => {
31
+ if (!ABSOLUTE_HTTP_URL.test(baseUrl)) {
32
+ throw configError("baseUrl must be an absolute http(s) URL.");
33
+ }
34
+ return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
35
+ };
36
+ const readMachineClient = (config, environment) => {
37
+ if (config.clientSecret === undefined) {
38
+ return null;
39
+ }
40
+ if (environment.hasDocument) {
41
+ throw configError("clientSecret is for servers only: a secret shipped to a browser is public.");
42
+ }
43
+ return {
44
+ clientId: requireText(config.clientId, "clientId"),
45
+ clientSecret: requireText(config.clientSecret, "clientSecret"),
46
+ };
47
+ };
48
+ const requireText = (value, name) => {
49
+ var _a;
50
+ const text = (_a = value === null || value === void 0 ? void 0 : value.trim()) !== null && _a !== void 0 ? _a : "";
51
+ if (text === "") {
52
+ throw configError(`${name} is required.`);
53
+ }
54
+ return text;
55
+ };
56
+ const requirePositive = (value, name) => {
57
+ if (!Number.isFinite(value) || value <= 0) {
58
+ throw configError(`${name} must be a positive number.`);
59
+ }
60
+ return value;
61
+ };
62
+ const requireCount = (value, name) => {
63
+ if (!Number.isInteger(value) || value < 0) {
64
+ throw configError(`${name} must be a whole number of at least 0.`);
65
+ }
66
+ return value;
67
+ };
68
+ const trimSlashes = (path) => path.replace(/^\/+|\/+$/g, "");
69
+ const globalFetch = () => {
70
+ if (typeof globalThis.fetch !== "function") {
71
+ throw configError("No global fetch is available: pass config.fetch.");
72
+ }
73
+ return (url, init) => globalThis.fetch(url, init);
74
+ };
@@ -0,0 +1,2 @@
1
+ import { OvokError } from "./ovok-errors";
2
+ export declare function errorFromResponse(response: Response): Promise<OvokError>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.errorFromResponse = errorFromResponse;
4
+ const ovok_error_1 = require("../../client/errors/ovok-error");
5
+ const retry_after_1 = require("../http/retry-after");
6
+ const ovok_errors_1 = require("./ovok-errors");
7
+ async function errorFromResponse(response) {
8
+ var _a, _b, _c, _d, _e, _f, _g, _h;
9
+ const fallback = Object.assign(new Error(`Ovok API answered ${response.status}`), {
10
+ status: response.status,
11
+ body: parseBody(await response.text()),
12
+ });
13
+ const details = (0, ovok_error_1.readOvokError)(fallback);
14
+ return (0, ovok_errors_1.errorForStatus)({
15
+ status: response.status,
16
+ code: (_a = details.code) !== null && _a !== void 0 ? _a : null,
17
+ type: (_b = details.type) !== null && _b !== void 0 ? _b : null,
18
+ message: details.message,
19
+ traceId: (_d = (_c = response.headers.get("x-trace-id")) !== null && _c !== void 0 ? _c : details.traceId) !== null && _d !== void 0 ? _d : null,
20
+ requestId: (_f = (_e = response.headers.get("x-request-id")) !== null && _e !== void 0 ? _e : details.requestId) !== null && _f !== void 0 ? _f : null,
21
+ retryAfterMs: (_h = (_g = (0, retry_after_1.retryAfterMs)(response.headers.get("retry-after"))) !== null && _g !== void 0 ? _g : details.retryAfterMs) !== null && _h !== void 0 ? _h : null,
22
+ fieldErrors: details.fieldErrors,
23
+ });
24
+ }
25
+ const parseBody = (text) => {
26
+ if (text === "") {
27
+ return undefined;
28
+ }
29
+ try {
30
+ return JSON.parse(text);
31
+ }
32
+ catch (_a) {
33
+ return { message: text };
34
+ }
35
+ };
@@ -0,0 +1,42 @@
1
+ import { ValidationError } from "../../types/ValidationError";
2
+ export type OvokErrorDetails = {
3
+ status: number | null;
4
+ code: string | null;
5
+ type: string | null;
6
+ message: string;
7
+ traceId: string | null;
8
+ requestId: string | null;
9
+ retryAfterMs: number | null;
10
+ fieldErrors: ValidationError[];
11
+ };
12
+ export declare class OvokError extends Error {
13
+ readonly status: number | null;
14
+ readonly code: string | null;
15
+ readonly type: string | null;
16
+ readonly traceId: string | null;
17
+ readonly requestId: string | null;
18
+ readonly retryAfterMs: number | null;
19
+ readonly fieldErrors: ValidationError[];
20
+ readonly cause: unknown;
21
+ constructor(details: OvokErrorDetails, cause?: unknown);
22
+ }
23
+ export declare class OvokValidationError extends OvokError {
24
+ }
25
+ export declare class OvokAuthenticationError extends OvokError {
26
+ }
27
+ export declare class OvokPermissionError extends OvokError {
28
+ }
29
+ export declare class OvokNotFoundError extends OvokError {
30
+ }
31
+ export declare class OvokConflictError extends OvokError {
32
+ }
33
+ export declare class OvokRateLimitError extends OvokError {
34
+ }
35
+ export declare class OvokServiceError extends OvokError {
36
+ }
37
+ export declare class OvokConnectionError extends OvokError {
38
+ }
39
+ export declare class OvokConfigError extends OvokError {
40
+ }
41
+ export declare function errorForStatus(details: OvokErrorDetails): OvokError;
42
+ export declare const detailsFor: (message: string) => OvokErrorDetails;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detailsFor = exports.OvokConfigError = exports.OvokConnectionError = exports.OvokServiceError = exports.OvokRateLimitError = exports.OvokConflictError = exports.OvokNotFoundError = exports.OvokPermissionError = exports.OvokAuthenticationError = exports.OvokValidationError = exports.OvokError = void 0;
4
+ exports.errorForStatus = errorForStatus;
5
+ class OvokError extends Error {
6
+ constructor(details, cause) {
7
+ super(details.message);
8
+ this.name = new.target.name;
9
+ this.status = details.status;
10
+ this.code = details.code;
11
+ this.type = details.type;
12
+ this.traceId = details.traceId;
13
+ this.requestId = details.requestId;
14
+ this.retryAfterMs = details.retryAfterMs;
15
+ this.fieldErrors = details.fieldErrors;
16
+ Object.defineProperty(this, "cause", { value: cause, enumerable: false });
17
+ }
18
+ }
19
+ exports.OvokError = OvokError;
20
+ class OvokValidationError extends OvokError {
21
+ }
22
+ exports.OvokValidationError = OvokValidationError;
23
+ class OvokAuthenticationError extends OvokError {
24
+ }
25
+ exports.OvokAuthenticationError = OvokAuthenticationError;
26
+ class OvokPermissionError extends OvokError {
27
+ }
28
+ exports.OvokPermissionError = OvokPermissionError;
29
+ class OvokNotFoundError extends OvokError {
30
+ }
31
+ exports.OvokNotFoundError = OvokNotFoundError;
32
+ class OvokConflictError extends OvokError {
33
+ }
34
+ exports.OvokConflictError = OvokConflictError;
35
+ class OvokRateLimitError extends OvokError {
36
+ }
37
+ exports.OvokRateLimitError = OvokRateLimitError;
38
+ class OvokServiceError extends OvokError {
39
+ }
40
+ exports.OvokServiceError = OvokServiceError;
41
+ class OvokConnectionError extends OvokError {
42
+ }
43
+ exports.OvokConnectionError = OvokConnectionError;
44
+ class OvokConfigError extends OvokError {
45
+ }
46
+ exports.OvokConfigError = OvokConfigError;
47
+ const ERROR_CLASS_BY_STATUS = {
48
+ 400: OvokValidationError,
49
+ 401: OvokAuthenticationError,
50
+ 403: OvokPermissionError,
51
+ 404: OvokNotFoundError,
52
+ 409: OvokConflictError,
53
+ 422: OvokValidationError,
54
+ 429: OvokRateLimitError,
55
+ };
56
+ const FIRST_SERVER_ERROR_STATUS = 500;
57
+ function errorForStatus(details) {
58
+ var _a, _b;
59
+ const status = (_a = details.status) !== null && _a !== void 0 ? _a : 0;
60
+ const isServerError = status >= FIRST_SERVER_ERROR_STATUS;
61
+ const errorClass = isServerError ? OvokServiceError : (_b = ERROR_CLASS_BY_STATUS[status]) !== null && _b !== void 0 ? _b : OvokError;
62
+ return new errorClass(details);
63
+ }
64
+ const detailsFor = (message) => ({
65
+ status: null,
66
+ code: null,
67
+ type: null,
68
+ message,
69
+ traceId: null,
70
+ requestId: null,
71
+ retryAfterMs: null,
72
+ fieldErrors: [],
73
+ });
74
+ exports.detailsFor = detailsFor;
@@ -0,0 +1,35 @@
1
+ import { Credentials } from "../auth/credentials";
2
+ import { OvokSettings } from "../config/ovok-config";
3
+ import { RetryPolicy } from "./retry-policy";
4
+ import { RequestOptions } from "./transmit";
5
+ export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
6
+ export type HttpRequest = {
7
+ method: HttpMethod;
8
+ path: string;
9
+ body?: unknown;
10
+ headers?: Record<string, string>;
11
+ idempotent?: boolean;
12
+ };
13
+ export type HttpContext = {
14
+ settings: OvokSettings;
15
+ credentials: Credentials;
16
+ retryPolicy: RetryPolicy;
17
+ };
18
+ export declare class HttpClient {
19
+ private readonly context;
20
+ private readonly basePath;
21
+ constructor(context: HttpContext, basePath?: string);
22
+ under(path: string): HttpClient;
23
+ anonymous(): HttpClient;
24
+ get<T>(path: string, options?: RequestOptions): Promise<T>;
25
+ post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
26
+ put<T>(path: string, body: unknown, options?: RequestOptions): Promise<T>;
27
+ patch<T>(path: string, body: unknown, options?: RequestOptions): Promise<T>;
28
+ delete<T = void>(path: string, options?: RequestOptions): Promise<T>;
29
+ send<T>(request: HttpRequest, options?: RequestOptions): Promise<T>;
30
+ private sendAuthorized;
31
+ private sendWithRetries;
32
+ private attempt;
33
+ private isRetryable;
34
+ private toTransmit;
35
+ }
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpClient = void 0;
4
+ const credentials_1 = require("../auth/credentials");
5
+ const error_from_response_1 = require("../errors/error-from-response");
6
+ const ovok_errors_1 = require("../errors/ovok-errors");
7
+ const retry_after_1 = require("./retry-after");
8
+ const transmit_1 = require("./transmit");
9
+ const url_1 = require("./url");
10
+ const UNAUTHORIZED = 401;
11
+ const JSON_TYPE = "application/json";
12
+ class HttpClient {
13
+ constructor(context, basePath = "") {
14
+ this.context = context;
15
+ this.basePath = basePath;
16
+ }
17
+ under(path) {
18
+ return new HttpClient(this.context, (0, url_1.joinPath)(this.basePath, path));
19
+ }
20
+ anonymous() {
21
+ return new HttpClient({ ...this.context, credentials: credentials_1.noCredentials }, this.basePath);
22
+ }
23
+ get(path, options) {
24
+ return this.send({ method: "GET", path }, options);
25
+ }
26
+ post(path, body, options) {
27
+ return this.send({ method: "POST", path, body }, options);
28
+ }
29
+ put(path, body, options) {
30
+ return this.send({ method: "PUT", path, body }, options);
31
+ }
32
+ patch(path, body, options) {
33
+ return this.send({ method: "PATCH", path, body }, options);
34
+ }
35
+ delete(path, options) {
36
+ return this.send({ method: "DELETE", path }, options);
37
+ }
38
+ async send(request, options = {}) {
39
+ const response = await this.sendAuthorized(request, options);
40
+ if (response.ok) {
41
+ return readJson(response);
42
+ }
43
+ throw await (0, error_from_response_1.errorFromResponse)(response);
44
+ }
45
+ async sendAuthorized(request, options) {
46
+ const response = await this.sendWithRetries(request, options);
47
+ const unauthorized = response.status === UNAUTHORIZED;
48
+ if (unauthorized && (await this.context.credentials.refresh())) {
49
+ return this.sendWithRetries(request, options);
50
+ }
51
+ return response;
52
+ }
53
+ async sendWithRetries(request, options) {
54
+ var _a, _b;
55
+ const { retryPolicy } = this.context;
56
+ for (let attempt = 0;; attempt += 1) {
57
+ const outcome = await this.attempt(request, options);
58
+ const retry = retryPolicy.allows(request, attempt) && this.isRetryable(outcome);
59
+ if (retry) {
60
+ await discard(outcome.response);
61
+ await retryPolicy.pause(attempt, (0, retry_after_1.retryAfterMs)((_b = (_a = outcome.response) === null || _a === void 0 ? void 0 : _a.headers.get("retry-after")) !== null && _b !== void 0 ? _b : null));
62
+ continue;
63
+ }
64
+ return unwrap(outcome);
65
+ }
66
+ }
67
+ async attempt(request, options) {
68
+ try {
69
+ const response = await (0, transmit_1.transmit)(this.context.settings, await this.toTransmit(request), options);
70
+ return { response };
71
+ }
72
+ catch (error) {
73
+ return { error };
74
+ }
75
+ }
76
+ isRetryable(outcome) {
77
+ return outcome.response
78
+ ? this.context.retryPolicy.isRetryableStatus(outcome.response.status)
79
+ : outcome.error instanceof ovok_errors_1.OvokConnectionError;
80
+ }
81
+ async toTransmit(request) {
82
+ const token = await this.context.credentials.accessToken();
83
+ const contentType = request.body === undefined ? {} : { "Content-Type": JSON_TYPE };
84
+ const authorization = token ? { Authorization: `Bearer ${token}` } : {};
85
+ return {
86
+ url: `${this.context.settings.baseUrl}${(0, url_1.joinPath)(this.basePath, request.path)}`,
87
+ method: request.method,
88
+ headers: { Accept: JSON_TYPE, ...contentType, ...request.headers, ...authorization },
89
+ body: encodeBody(request.body),
90
+ };
91
+ }
92
+ }
93
+ exports.HttpClient = HttpClient;
94
+ const unwrap = (outcome) => {
95
+ if (outcome.response) {
96
+ return outcome.response;
97
+ }
98
+ throw outcome.error;
99
+ };
100
+ const discard = async (response) => {
101
+ var _a;
102
+ await ((_a = response === null || response === void 0 ? void 0 : response.body) === null || _a === void 0 ? void 0 : _a.cancel().catch(() => undefined));
103
+ };
104
+ const encodeBody = (body) => {
105
+ if (body === undefined) {
106
+ return undefined;
107
+ }
108
+ return typeof body === "string" ? body : JSON.stringify(body);
109
+ };
110
+ const readJson = async (response) => {
111
+ const text = await response.text();
112
+ return (text === "" ? undefined : JSON.parse(text));
113
+ };
@@ -0,0 +1 @@
1
+ export declare const retryAfterMs: (header: string | null) => number | null;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.retryAfterMs = void 0;
4
+ const MS_PER_SECOND = 1000;
5
+ const retryAfterMs = (header) => {
6
+ if (header === null) {
7
+ return null;
8
+ }
9
+ const seconds = Number(header);
10
+ if (Number.isFinite(seconds)) {
11
+ return seconds * MS_PER_SECOND;
12
+ }
13
+ const date = Date.parse(header);
14
+ return Number.isNaN(date) ? null : Math.max(0, date - Date.now());
15
+ };
16
+ exports.retryAfterMs = retryAfterMs;
@@ -0,0 +1,13 @@
1
+ export type Sleep = (ms: number) => Promise<void>;
2
+ export type RetryableRequest = {
3
+ method: string;
4
+ idempotent?: boolean;
5
+ };
6
+ export declare class RetryPolicy {
7
+ private readonly maxRetries;
8
+ private readonly wait;
9
+ constructor(maxRetries: number, wait?: Sleep);
10
+ allows(request: RetryableRequest, attempt: number): boolean;
11
+ isRetryableStatus(status: number): boolean;
12
+ pause(attempt: number, retryAfterMs: number | null): Promise<void>;
13
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RetryPolicy = void 0;
4
+ const RETRYABLE_STATUSES = new Set([429, 502, 503, 504]);
5
+ const IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE"]);
6
+ const BASE_DELAY_MS = 300;
7
+ const MAX_DELAY_MS = 5000;
8
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
9
+ class RetryPolicy {
10
+ constructor(maxRetries, wait = sleep) {
11
+ this.maxRetries = maxRetries;
12
+ this.wait = wait;
13
+ }
14
+ allows(request, attempt) {
15
+ var _a;
16
+ const repeatable = (_a = request.idempotent) !== null && _a !== void 0 ? _a : IDEMPOTENT_METHODS.has(request.method);
17
+ return repeatable && attempt < this.maxRetries;
18
+ }
19
+ isRetryableStatus(status) {
20
+ return RETRYABLE_STATUSES.has(status);
21
+ }
22
+ pause(attempt, retryAfterMs) {
23
+ const backoffMs = BASE_DELAY_MS * 2 ** attempt;
24
+ return this.wait(Math.min(retryAfterMs !== null && retryAfterMs !== void 0 ? retryAfterMs : backoffMs, MAX_DELAY_MS));
25
+ }
26
+ }
27
+ exports.RetryPolicy = RetryPolicy;
@@ -0,0 +1,14 @@
1
+ import { OvokSettings } from "../config/ovok-config";
2
+ export type RequestOptions = {
3
+ signal?: AbortSignal;
4
+ timeoutMs?: number;
5
+ };
6
+ export type TransmitRequest = {
7
+ url: string;
8
+ method: string;
9
+ headers: Record<string, string>;
10
+ body: string | undefined;
11
+ };
12
+ type TransmitSettings = Pick<OvokSettings, "fetch" | "timeoutMs">;
13
+ export declare function transmit(settings: TransmitSettings, request: TransmitRequest, options?: RequestOptions): Promise<Response>;
14
+ export {};
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transmit = transmit;
4
+ const ovok_errors_1 = require("../errors/ovok-errors");
5
+ async function transmit(settings, request, options = {}) {
6
+ var _a;
7
+ const deadline = new Deadline((_a = options.timeoutMs) !== null && _a !== void 0 ? _a : settings.timeoutMs, options.signal);
8
+ try {
9
+ return await settings.fetch(request.url, {
10
+ method: request.method,
11
+ headers: request.headers,
12
+ body: request.body,
13
+ signal: deadline.signal,
14
+ });
15
+ }
16
+ catch (error) {
17
+ throw deadline.explain(error);
18
+ }
19
+ finally {
20
+ deadline.clear();
21
+ }
22
+ }
23
+ class Deadline {
24
+ constructor(timeoutMs, callerSignal) {
25
+ this.timeoutMs = timeoutMs;
26
+ this.callerSignal = callerSignal;
27
+ this.controller = new AbortController();
28
+ this.followCaller = () => { var _a; return this.controller.abort((_a = this.callerSignal) === null || _a === void 0 ? void 0 : _a.reason); };
29
+ this.expired = false;
30
+ this.timer = setTimeout(() => this.expire(), timeoutMs);
31
+ callerSignal === null || callerSignal === void 0 ? void 0 : callerSignal.addEventListener("abort", this.followCaller, { once: true });
32
+ if (callerSignal === null || callerSignal === void 0 ? void 0 : callerSignal.aborted) {
33
+ this.followCaller();
34
+ }
35
+ }
36
+ get signal() {
37
+ return this.controller.signal;
38
+ }
39
+ /** A caller's own abort passes through untouched; everything else is a connection failure. */
40
+ explain(error) {
41
+ var _a, _b;
42
+ if ((_a = this.callerSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
43
+ return (_b = this.callerSignal.reason) !== null && _b !== void 0 ? _b : error;
44
+ }
45
+ const message = this.expired ? `The request timed out after ${this.timeoutMs} ms.` : "Could not reach the Ovok API.";
46
+ return new ovok_errors_1.OvokConnectionError((0, ovok_errors_1.detailsFor)(message), error);
47
+ }
48
+ clear() {
49
+ var _a;
50
+ clearTimeout(this.timer);
51
+ (_a = this.callerSignal) === null || _a === void 0 ? void 0 : _a.removeEventListener("abort", this.followCaller);
52
+ }
53
+ expire() {
54
+ this.expired = true;
55
+ this.controller.abort();
56
+ }
57
+ }
@@ -0,0 +1,6 @@
1
+ export type QueryValue = string | number | boolean | readonly string[] | undefined;
2
+ export type QueryParams = Record<string, QueryValue>;
3
+ export declare const joinPath: (...parts: string[]) => string;
4
+ export declare const pathSegment: (value: string) => string;
5
+ /** A list value repeats its key, so `date: ["ge1", "le2"]` is FHIR's AND; write "a,b" for OR. */
6
+ export declare function toSearchQuery(params: QueryParams): string;