@ovok/core 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +221 -4
- package/dist/client/auth/errors.d.ts +3 -0
- package/dist/client/auth/errors.js +11 -0
- package/dist/client/auth/methods/index.d.ts +1 -0
- package/dist/client/auth/methods/index.js +1 -0
- package/dist/client/auth/methods/registerPractitioner.d.ts +4 -0
- package/dist/client/auth/methods/registerPractitioner.js +15 -0
- package/dist/client/auth/types/RegisterPractitionerBody.d.ts +2 -0
- package/dist/client/auth/types/RegisterPractitionerBody.js +2 -0
- package/dist/client/email/index.d.ts +2 -0
- package/dist/client/email/index.js +18 -0
- package/dist/client/email/methods.d.ts +3 -0
- package/dist/client/email/methods.js +6 -0
- package/dist/client/email/types.d.ts +21 -0
- package/dist/client/email/types.js +2 -0
- package/dist/client/errors/ovok-error.d.ts +6 -0
- package/dist/client/errors/ovok-error.js +158 -26
- package/dist/client/errors/rate-limit-error.js +4 -0
- package/dist/client/invites/index.d.ts +3 -0
- package/dist/client/invites/index.js +19 -0
- package/dist/client/invites/methods.d.ts +8 -0
- package/dist/client/invites/methods.js +30 -0
- package/dist/client/invites/parse-accept-invite-link.d.ts +3 -0
- package/dist/client/invites/parse-accept-invite-link.js +23 -0
- package/dist/client/invites/types.d.ts +19 -0
- package/dist/client/invites/types.js +8 -0
- package/dist/client/ovok-client.d.ts +3 -1
- package/dist/client/ovok-client.js +4 -0
- package/dist/client/patient-sharing/methods.d.ts +2 -2
- package/dist/client/patient-sharing/methods.js +7 -1
- package/dist/client/patient-sharing/types.d.ts +30 -3
- package/dist/client/platform/methods.d.ts +2 -1
- package/dist/client/platform/methods.js +4 -0
- package/dist/client/platform/types.d.ts +10 -1
- package/dist/client/platform/types.js +15 -2
- package/dist/client/signals/errors.js +3 -104
- package/dist/client/signals/methods.d.ts +17 -4
- package/dist/client/signals/methods.js +47 -24
- package/dist/client/signals/types.d.ts +74 -1
- package/dist/conformance/api-requirements.js +13 -0
- package/dist/conformance/capability-requirements.js +1 -1
- package/dist/hooks/email-hooks.d.ts +3 -0
- package/dist/hooks/email-hooks.js +46 -0
- package/dist/hooks/index.d.ts +3 -1
- package/dist/hooks/index.js +9 -2
- package/dist/hooks/invites-hooks.d.ts +5 -0
- package/dist/hooks/invites-hooks.js +11 -0
- package/dist/hooks/patient-sharing-hooks.d.ts +2 -2
- package/dist/hooks/platform-hooks.d.ts +5 -1
- package/dist/hooks/platform-hooks.js +3 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/types/ValidationError.d.ts +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.invitePractitioner = invitePractitioner;
|
|
4
|
+
exports.invitePatient = invitePatient;
|
|
5
|
+
exports.acceptPractitionerInvite = acceptPractitionerInvite;
|
|
6
|
+
exports.acceptPatientInvite = acceptPatientInvite;
|
|
7
|
+
exports.acceptInvite = acceptInvite;
|
|
8
|
+
function invitePractitioner(body) {
|
|
9
|
+
return this.post("/v1/invites/practitioner", body);
|
|
10
|
+
}
|
|
11
|
+
function invitePatient(body) {
|
|
12
|
+
return this.post("/v1/invites/patient", body);
|
|
13
|
+
}
|
|
14
|
+
function acceptPractitionerInvite(body) {
|
|
15
|
+
return this.post("/v1/invites/practitioner/accept", body);
|
|
16
|
+
}
|
|
17
|
+
function acceptPatientInvite(body) {
|
|
18
|
+
return this.post("/v1/invites/patient/accept", body);
|
|
19
|
+
}
|
|
20
|
+
function acceptInvite(body) {
|
|
21
|
+
var _a;
|
|
22
|
+
const resourceType = (_a = this.getProfile()) === null || _a === void 0 ? void 0 : _a.resourceType;
|
|
23
|
+
if (resourceType === "Practitioner") {
|
|
24
|
+
return this.acceptPractitionerInvite(body);
|
|
25
|
+
}
|
|
26
|
+
if (resourceType === "Patient") {
|
|
27
|
+
return this.acceptPatientInvite(body);
|
|
28
|
+
}
|
|
29
|
+
throw new Error("Accepting an invite requires a signed-in Patient or Practitioner profile.");
|
|
30
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseAcceptInviteLink = parseAcceptInviteLink;
|
|
4
|
+
/** Reads an invite link without making a request; callers should remove its code from browser history. */
|
|
5
|
+
function parseAcceptInviteLink(url) {
|
|
6
|
+
let parsed;
|
|
7
|
+
try {
|
|
8
|
+
parsed = url instanceof URL ? url : new URL(url, "https://ovok.invalid");
|
|
9
|
+
}
|
|
10
|
+
catch (_a) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const inviteId = parsed.searchParams.get("invite");
|
|
14
|
+
const code = parsed.searchParams.get("code");
|
|
15
|
+
if (!inviteId ||
|
|
16
|
+
!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(inviteId) ||
|
|
17
|
+
!code ||
|
|
18
|
+
code.length < 16 ||
|
|
19
|
+
code.length > 128) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return { inviteId, code };
|
|
23
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PatientSharingPractitionerShare } from "../patient-sharing/types";
|
|
2
|
+
export type InviteBody = {
|
|
3
|
+
email: string;
|
|
4
|
+
firstName: string;
|
|
5
|
+
lastName: string;
|
|
6
|
+
};
|
|
7
|
+
export type InviteSent = {
|
|
8
|
+
status: "sent";
|
|
9
|
+
};
|
|
10
|
+
export type AcceptInviteBody = {
|
|
11
|
+
inviteId: string;
|
|
12
|
+
code: string;
|
|
13
|
+
};
|
|
14
|
+
export type AcceptInviteResult = PatientSharingPractitionerShare;
|
|
15
|
+
export declare const OVOK_INVITE_ERROR_CODES: {
|
|
16
|
+
readonly invitationNotConfigured: "invitation_not_configured";
|
|
17
|
+
readonly appUrlNotConfigured: "app_url_not_configured";
|
|
18
|
+
readonly practitionerWithoutAccessPolicy: "practitioner_without_access_policy";
|
|
19
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OVOK_INVITE_ERROR_CODES = void 0;
|
|
4
|
+
exports.OVOK_INVITE_ERROR_CODES = {
|
|
5
|
+
invitationNotConfigured: "invitation_not_configured",
|
|
6
|
+
appUrlNotConfigured: "app_url_not_configured",
|
|
7
|
+
practitionerWithoutAccessPolicy: "practitioner_without_access_policy",
|
|
8
|
+
};
|
|
@@ -6,7 +6,9 @@ import * as authMethods from "./auth/methods";
|
|
|
6
6
|
import * as botMethods from "./bot/methods";
|
|
7
7
|
import * as carehubMethods from "./carehub/methods";
|
|
8
8
|
import * as aiMethods from "./chat/ai/methods";
|
|
9
|
+
import * as emailMethods from "./email";
|
|
9
10
|
import * as experienceMethods from "./experience/methods";
|
|
11
|
+
import * as inviteMethods from "./invites/methods";
|
|
10
12
|
import * as observationMethods from "./observation/methods";
|
|
11
13
|
import { GenerateObservationBodyParams } from "./observation/types/generate-observation-body/GenerateObservationBodyParams";
|
|
12
14
|
import { OfflineMeasurementFlushOptions, OfflineMeasurementFlushResult, OfflineMeasurementQueueOptions } from "./offline";
|
|
@@ -60,7 +62,7 @@ export declare class OvokClient extends MedplumClient {
|
|
|
60
62
|
*/
|
|
61
63
|
getSubscriptionManager(): SubscriptionManager;
|
|
62
64
|
}
|
|
63
|
-
type Methods = typeof authMethods & typeof observationMethods & typeof questionnaireResponseMethods & typeof aiMethods & typeof aiFhirMethods & typeof botMethods & typeof carehubMethods & typeof platformMethods & typeof experienceMethods & typeof patientMethods & typeof patientSharingMethods & typeof signalsMethods;
|
|
65
|
+
type Methods = typeof authMethods & typeof observationMethods & typeof questionnaireResponseMethods & typeof aiMethods & typeof aiFhirMethods & typeof botMethods & typeof carehubMethods & typeof emailMethods & typeof platformMethods & typeof experienceMethods & typeof inviteMethods & typeof patientMethods & typeof patientSharingMethods & typeof signalsMethods;
|
|
64
66
|
type Omitted<T> = Omit<T, "executeBot">;
|
|
65
67
|
declare module "./ovok-client" {
|
|
66
68
|
interface OvokClient extends Omitted<Methods> {
|
|
@@ -42,8 +42,10 @@ const authMethods = __importStar(require("./auth/methods"));
|
|
|
42
42
|
const botMethods = __importStar(require("./bot/methods"));
|
|
43
43
|
const carehubMethods = __importStar(require("./carehub/methods"));
|
|
44
44
|
const aiMethods = __importStar(require("./chat/ai/methods"));
|
|
45
|
+
const emailMethods = __importStar(require("./email"));
|
|
45
46
|
const rate_limit_error_1 = require("./errors/rate-limit-error");
|
|
46
47
|
const experienceMethods = __importStar(require("./experience/methods"));
|
|
48
|
+
const inviteMethods = __importStar(require("./invites/methods"));
|
|
47
49
|
const observationMethods = __importStar(require("./observation/methods"));
|
|
48
50
|
const observation_bundle_utils_1 = require("./observation/observation-bundle-utils");
|
|
49
51
|
const offline_1 = require("./offline");
|
|
@@ -73,8 +75,10 @@ class OvokClient extends core_1.MedplumClient {
|
|
|
73
75
|
this.bindMethods(aiFhirMethods);
|
|
74
76
|
this.bindMethods(botMethods);
|
|
75
77
|
this.bindMethods(carehubMethods);
|
|
78
|
+
this.bindMethods(emailMethods);
|
|
76
79
|
this.bindMethods(platformMethods);
|
|
77
80
|
this.bindMethods(experienceMethods);
|
|
81
|
+
this.bindMethods(inviteMethods);
|
|
78
82
|
this.bindMethods(patientMethods);
|
|
79
83
|
this.bindMethods(patientSharingMethods);
|
|
80
84
|
this.bindMethods(signalsMethods, (error) => (0, errors_1.mapSignalsError)((0, rate_limit_error_1.mapRateLimitError)(error), { signalsRequest: true }));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { OvokClient } from "../ovok-client";
|
|
2
|
-
import { CreatePatientSharingInvite, PatientSharingInvite, PatientSharingSettings, PatientSharingShare, PatientSharingShares, RedeemPatientSharingInvite } from "./types";
|
|
2
|
+
import { CreatePatientSharingInvite, PatientSharingInvite, PatientSharingSettings, PatientSharingShare, PatientSharingShares, RedeemPatientSharingInvite, PatientSharingSettingsUpdate } from "./types";
|
|
3
3
|
export declare function createPatientSharingInvite(this: OvokClient, body: CreatePatientSharingInvite): Promise<PatientSharingInvite>;
|
|
4
4
|
export declare function redeemPatientSharingInvite(this: OvokClient, body: RedeemPatientSharingInvite): Promise<PatientSharingShare>;
|
|
5
5
|
export declare function listPatientSharing(this: OvokClient): Promise<PatientSharingShares>;
|
|
6
6
|
export declare function revokePatientSharing(this: OvokClient, consentId: string): Promise<void>;
|
|
7
7
|
export declare function getPatientSharingSettings(this: OvokClient): Promise<PatientSharingSettings>;
|
|
8
|
-
export declare function updatePatientSharingSettings(this: OvokClient, settings:
|
|
8
|
+
export declare function updatePatientSharingSettings(this: OvokClient, settings: PatientSharingSettingsUpdate): Promise<PatientSharingSettings>;
|
|
@@ -14,7 +14,13 @@ function redeemPatientSharingInvite(body) {
|
|
|
14
14
|
return this.post("/v1/patient-sharing/invites/redeem", body);
|
|
15
15
|
}
|
|
16
16
|
function listPatientSharing() {
|
|
17
|
-
return this.get("/v1/patient-sharing/shares")
|
|
17
|
+
return this.get("/v1/patient-sharing/shares").then((shares) => {
|
|
18
|
+
var _a;
|
|
19
|
+
return ({
|
|
20
|
+
...shares,
|
|
21
|
+
practitioners: (_a = shares.practitioners) !== null && _a !== void 0 ? _a : [],
|
|
22
|
+
});
|
|
23
|
+
});
|
|
18
24
|
}
|
|
19
25
|
async function revokePatientSharing(consentId) {
|
|
20
26
|
await this.delete(`/v1/patient-sharing/shares/${segment(consentId)}`);
|
|
@@ -5,18 +5,45 @@ export type PatientSharingInvite = {
|
|
|
5
5
|
};
|
|
6
6
|
export type PatientSharingShare = {
|
|
7
7
|
consentId: string;
|
|
8
|
-
|
|
8
|
+
sharer: PatientSharingParty;
|
|
9
|
+
recipient: PatientSharingParty;
|
|
10
|
+
codes: string[];
|
|
11
|
+
startedAt: string | null;
|
|
12
|
+
endsAt: string | null;
|
|
13
|
+
};
|
|
14
|
+
export type PatientSharingParty = {
|
|
15
|
+
patientId: string;
|
|
16
|
+
name: string | null;
|
|
17
|
+
};
|
|
18
|
+
export type PatientSharingPractitionerShare = {
|
|
19
|
+
consentId: string;
|
|
20
|
+
sharer: PatientSharingParty;
|
|
21
|
+
practitioner: {
|
|
22
|
+
practitionerId: string;
|
|
23
|
+
name: string | null;
|
|
24
|
+
};
|
|
25
|
+
startedAt: string | null;
|
|
26
|
+
endsAt: string | null;
|
|
9
27
|
};
|
|
10
28
|
export type PatientSharingShares = {
|
|
11
29
|
outgoing: PatientSharingShare[];
|
|
12
30
|
incoming: PatientSharingShare[];
|
|
31
|
+
practitioners: PatientSharingPractitionerShare[];
|
|
13
32
|
};
|
|
14
33
|
export type CreatePatientSharingInvite = {
|
|
15
34
|
codes: string[];
|
|
16
|
-
endsAt: string;
|
|
35
|
+
endsAt: string | null;
|
|
17
36
|
};
|
|
18
37
|
export type RedeemPatientSharingInvite = {
|
|
19
38
|
inviteId: string;
|
|
20
39
|
code: string;
|
|
21
40
|
};
|
|
22
|
-
export type PatientSharingSettings =
|
|
41
|
+
export type PatientSharingSettings = {
|
|
42
|
+
enabled: boolean;
|
|
43
|
+
accessPolicyId: string | null;
|
|
44
|
+
practitionerSharingEnabled: boolean;
|
|
45
|
+
};
|
|
46
|
+
export type PatientSharingSettingsUpdate = {
|
|
47
|
+
enabled: boolean;
|
|
48
|
+
practitionerSharingEnabled?: boolean | null;
|
|
49
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OvokClient } from "../ovok-client";
|
|
2
|
-
import { OvokAccount, OvokAdministeredProject, OvokCreateProject, OvokCreatedProject, OvokI18nDocument, OvokI18nValue, OvokInviteProjectMember, OvokLocalization, OvokLocalizationQuery, OvokLocalizationUpdate, OvokLocales, OvokPage, OvokPatientObservations, OvokProjectFeature, OvokProjectFeatures, OvokProjectMember, OvokProjectMemberResponse, OvokProjectSettings, OvokProjectSettingKey, OvokRemoveProjectMemberResponse, OvokUpdateProjectMember } from "./types";
|
|
2
|
+
import { OvokAccount, OvokAdministeredProject, OvokCreateProject, OvokCreatedProject, OvokI18nDocument, OvokI18nValue, OvokInviteProjectMember, OvokLocalization, OvokLocalizationQuery, OvokLocalizationUpdate, OvokLocales, OvokPage, OvokPatientObservations, OvokProjectFeature, OvokProjectFeatures, OvokProjectMember, OvokProjectMemberResponse, OvokProjectSettings, OvokProjectSettingKey, OvokProjectTextSettingKey, OvokRemoveProjectMemberResponse, OvokUpdateProjectMember } from "./types";
|
|
3
3
|
export declare function getAccounts(this: OvokClient): Promise<OvokAccount[]>;
|
|
4
4
|
export declare function listAdministeredProjects(this: OvokClient, params?: {
|
|
5
5
|
page?: number;
|
|
@@ -24,6 +24,7 @@ export declare function getProjectFeatures(this: OvokClient): Promise<OvokProjec
|
|
|
24
24
|
export declare function updateProjectFeatures(this: OvokClient, features: OvokProjectFeature[]): Promise<OvokProjectFeatures>;
|
|
25
25
|
export declare function getProjectSettings(this: OvokClient): Promise<OvokProjectSettings>;
|
|
26
26
|
export declare function updateProjectSetting(this: OvokClient, key: OvokProjectSettingKey, enabled: boolean): Promise<OvokProjectSettings>;
|
|
27
|
+
export declare function updateProjectTextSetting(this: OvokClient, key: OvokProjectTextSettingKey, value: string | null): Promise<OvokProjectSettings>;
|
|
27
28
|
export declare function getLocales(this: OvokClient): Promise<OvokLocales>;
|
|
28
29
|
export declare function updateLocales(this: OvokClient, locales: OvokLocales): Promise<OvokLocales>;
|
|
29
30
|
export declare function listLocalizations(this: OvokClient, language: string, params?: OvokLocalizationQuery): Promise<{
|
|
@@ -13,6 +13,7 @@ exports.getProjectFeatures = getProjectFeatures;
|
|
|
13
13
|
exports.updateProjectFeatures = updateProjectFeatures;
|
|
14
14
|
exports.getProjectSettings = getProjectSettings;
|
|
15
15
|
exports.updateProjectSetting = updateProjectSetting;
|
|
16
|
+
exports.updateProjectTextSetting = updateProjectTextSetting;
|
|
16
17
|
exports.getLocales = getLocales;
|
|
17
18
|
exports.updateLocales = updateLocales;
|
|
18
19
|
exports.listLocalizations = listLocalizations;
|
|
@@ -73,6 +74,9 @@ async function getProjectSettings() {
|
|
|
73
74
|
async function updateProjectSetting(key, enabled) {
|
|
74
75
|
return (await this.put(`/v1/project/settings/${segment(key)}`, { enabled }));
|
|
75
76
|
}
|
|
77
|
+
async function updateProjectTextSetting(key, value) {
|
|
78
|
+
return (await this.put(`/v1/project/settings/values/${segment(key)}`, { value }));
|
|
79
|
+
}
|
|
76
80
|
async function getLocales() {
|
|
77
81
|
return this.get("/locales");
|
|
78
82
|
}
|
|
@@ -68,11 +68,20 @@ export type OvokProjectFeatures = {
|
|
|
68
68
|
export type OvokProjectFeaturesUpdate = {
|
|
69
69
|
features: OvokProjectFeature[];
|
|
70
70
|
};
|
|
71
|
-
export declare const OVOK_PROJECT_SETTING_KEYS: readonly ["CONTENT_ENABLED", "MAILING_ENABLED", "PATIENT_INVITATION_ENABLED", "PATIENT_REGISTRATION_ENABLED", "PATIENT_LOGIN_ENABLED", "PRACTITIONER_INVITATION_ENABLED", "PRACTITIONER_REGISTRATION_ENABLED", "PRACTITIONER_LOGIN_ENABLED", "
|
|
71
|
+
export declare const OVOK_PROJECT_SETTING_KEYS: readonly ["CONTENT_ENABLED", "MAILING_ENABLED", "PATIENT_INVITATION_ENABLED", "PATIENT_REGISTRATION_ENABLED", "PATIENT_LOGIN_ENABLED", "PRACTITIONER_INVITATION_ENABLED", "PRACTITIONER_REGISTRATION_ENABLED", "PRACTITIONER_LOGIN_ENABLED", "CLINICIAN_INVITE_ON_BUSINESS_EMAIL"];
|
|
72
72
|
export type OvokProjectSettingKey = (typeof OVOK_PROJECT_SETTING_KEYS)[number];
|
|
73
|
+
export declare const OVOK_PROJECT_TEXT_SETTING_KEYS: readonly ["PATIENT_APP_URL", "PRACTITIONER_APP_URL", "PATIENT_SIGNUP_URL", "CLINICIAN_DASHBOARD_URL", "DEFAULT_PRACTITIONER_ACCESS_POLICY", "CLINICIAN_INVITE_ACCESS_POLICY"];
|
|
74
|
+
export type OvokProjectTextSettingKey = (typeof OVOK_PROJECT_TEXT_SETTING_KEYS)[number];
|
|
75
|
+
export declare const OVOK_PROJECT_TEXT_SETTING_ERROR_CODES: {
|
|
76
|
+
readonly invalidValue: "INVALID_SETTING_VALUE";
|
|
77
|
+
readonly appUrlNotAllowed: "APP_URL_NOT_ALLOWED";
|
|
78
|
+
readonly unknownSetting: "UNKNOWN_SETTING";
|
|
79
|
+
readonly appUrlNotConfigured: "app_url_not_configured";
|
|
80
|
+
};
|
|
73
81
|
export type OvokProjectSettings = {
|
|
74
82
|
projectId: string;
|
|
75
83
|
settings: Record<OvokProjectSettingKey, boolean>;
|
|
84
|
+
values: Record<OvokProjectTextSettingKey, string | null>;
|
|
76
85
|
};
|
|
77
86
|
export type OvokLocales = {
|
|
78
87
|
languages: string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OVOK_PROJECT_SETTING_KEYS = exports.OVOK_PROJECT_FEATURE_VALUES = void 0;
|
|
3
|
+
exports.OVOK_PROJECT_TEXT_SETTING_ERROR_CODES = exports.OVOK_PROJECT_TEXT_SETTING_KEYS = exports.OVOK_PROJECT_SETTING_KEYS = exports.OVOK_PROJECT_FEATURE_VALUES = void 0;
|
|
4
4
|
exports.OVOK_PROJECT_FEATURE_VALUES = [
|
|
5
5
|
"ai",
|
|
6
6
|
"aws-comprehend",
|
|
@@ -23,6 +23,19 @@ exports.OVOK_PROJECT_SETTING_KEYS = [
|
|
|
23
23
|
"PRACTITIONER_INVITATION_ENABLED",
|
|
24
24
|
"PRACTITIONER_REGISTRATION_ENABLED",
|
|
25
25
|
"PRACTITIONER_LOGIN_ENABLED",
|
|
26
|
-
"IOT_ENABLED",
|
|
27
26
|
"CLINICIAN_INVITE_ON_BUSINESS_EMAIL",
|
|
28
27
|
];
|
|
28
|
+
exports.OVOK_PROJECT_TEXT_SETTING_KEYS = [
|
|
29
|
+
"PATIENT_APP_URL",
|
|
30
|
+
"PRACTITIONER_APP_URL",
|
|
31
|
+
"PATIENT_SIGNUP_URL",
|
|
32
|
+
"CLINICIAN_DASHBOARD_URL",
|
|
33
|
+
"DEFAULT_PRACTITIONER_ACCESS_POLICY",
|
|
34
|
+
"CLINICIAN_INVITE_ACCESS_POLICY",
|
|
35
|
+
];
|
|
36
|
+
exports.OVOK_PROJECT_TEXT_SETTING_ERROR_CODES = {
|
|
37
|
+
invalidValue: "INVALID_SETTING_VALUE",
|
|
38
|
+
appUrlNotAllowed: "APP_URL_NOT_ALLOWED",
|
|
39
|
+
unknownSetting: "UNKNOWN_SETTING",
|
|
40
|
+
appUrlNotConfigured: "app_url_not_configured",
|
|
41
|
+
};
|
|
@@ -51,21 +51,14 @@ function mapSignalsError(error, options = {}) {
|
|
|
51
51
|
if (isSignalsError(error)) {
|
|
52
52
|
return error;
|
|
53
53
|
}
|
|
54
|
-
const
|
|
55
|
-
const code = responseCode(payload);
|
|
56
|
-
const parsed = (0, ovok_error_1.parseOvokError)(payload !== null && payload !== void 0 ? payload : error);
|
|
57
|
-
const message = (parsed.message === "[object Object]" || parsed.message === "undefined") &&
|
|
58
|
-
error instanceof Error
|
|
59
|
-
? error.message
|
|
60
|
-
: parsed.message;
|
|
61
|
-
const status = responseStatus(error, payload);
|
|
54
|
+
const { code, fieldErrors, message, status } = (0, ovok_error_1.readOvokError)(error);
|
|
62
55
|
if (code && SIGNALS_ERROR_CODES.has(code)) {
|
|
63
56
|
const knownCode = code;
|
|
64
57
|
const resolvedStatus = status !== null && status !== void 0 ? status : SIGNALS_ERROR_STATUSES[knownCode];
|
|
65
58
|
if (resolvedStatus !== undefined) {
|
|
66
59
|
return new SignalsError(knownCode, resolvedStatus, message, {
|
|
67
60
|
cause: error,
|
|
68
|
-
fieldErrors
|
|
61
|
+
fieldErrors,
|
|
69
62
|
});
|
|
70
63
|
}
|
|
71
64
|
}
|
|
@@ -84,102 +77,8 @@ function mapSignalsError(error, options = {}) {
|
|
|
84
77
|
: "validation_error";
|
|
85
78
|
return new SignalsError(validationCode, status, message, {
|
|
86
79
|
cause: error,
|
|
87
|
-
fieldErrors
|
|
80
|
+
fieldErrors,
|
|
88
81
|
});
|
|
89
82
|
}
|
|
90
83
|
return error;
|
|
91
84
|
}
|
|
92
|
-
function responsePayload(error) {
|
|
93
|
-
var _a, _b;
|
|
94
|
-
const root = asRecord(error);
|
|
95
|
-
const candidates = [
|
|
96
|
-
root === null || root === void 0 ? void 0 : root.body,
|
|
97
|
-
root === null || root === void 0 ? void 0 : root.data,
|
|
98
|
-
(_a = asRecord(root === null || root === void 0 ? void 0 : root.response)) === null || _a === void 0 ? void 0 : _a.data,
|
|
99
|
-
(_b = asRecord(root === null || root === void 0 ? void 0 : root.response)) === null || _b === void 0 ? void 0 : _b.body,
|
|
100
|
-
root === null || root === void 0 ? void 0 : root.outcome,
|
|
101
|
-
];
|
|
102
|
-
for (const candidate of candidates) {
|
|
103
|
-
const parsed = parseJson(candidate);
|
|
104
|
-
if (parsed !== undefined) {
|
|
105
|
-
return parsed;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (error instanceof Error) {
|
|
109
|
-
const parsed = parseJson(error.message);
|
|
110
|
-
if (parsed !== undefined) {
|
|
111
|
-
return parsed;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return error;
|
|
115
|
-
}
|
|
116
|
-
function responseCode(payload) {
|
|
117
|
-
var _a, _b, _c, _d, _e, _f;
|
|
118
|
-
const root = asRecord(payload);
|
|
119
|
-
const error = asRecord(root === null || root === void 0 ? void 0 : root.error);
|
|
120
|
-
const directCode = (_b = (_a = (typeof (root === null || root === void 0 ? void 0 : root.error) === "string" ? root.error : undefined)) !== null && _a !== void 0 ? _a : (typeof (root === null || root === void 0 ? void 0 : root.code) === "string" ? root.code : undefined)) !== null && _b !== void 0 ? _b : (typeof (error === null || error === void 0 ? void 0 : error.code) === "string" ? error.code : undefined);
|
|
121
|
-
if (directCode) {
|
|
122
|
-
return directCode;
|
|
123
|
-
}
|
|
124
|
-
const outcome = (_d = (_c = asRecord(root === null || root === void 0 ? void 0 : root.outcome)) !== null && _c !== void 0 ? _c : root) !== null && _d !== void 0 ? _d : {};
|
|
125
|
-
const issues = Array.isArray(outcome.issue) ? outcome.issue : [];
|
|
126
|
-
for (const issue of issues) {
|
|
127
|
-
const issueRecord = asRecord(issue);
|
|
128
|
-
const details = asRecord(issueRecord === null || issueRecord === void 0 ? void 0 : issueRecord.details);
|
|
129
|
-
const coding = Array.isArray(details === null || details === void 0 ? void 0 : details.coding) ? details.coding : [];
|
|
130
|
-
for (const entry of coding) {
|
|
131
|
-
const entryCode = (_e = asRecord(entry)) === null || _e === void 0 ? void 0 : _e.code;
|
|
132
|
-
if (typeof entryCode === "string" && entryCode.startsWith("signals_")) {
|
|
133
|
-
return entryCode;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
const diagnostic = parseJson(issueRecord === null || issueRecord === void 0 ? void 0 : issueRecord.diagnostics);
|
|
137
|
-
const diagnosticRecord = asRecord(diagnostic);
|
|
138
|
-
const diagnosticCode = (_f = diagnosticRecord === null || diagnosticRecord === void 0 ? void 0 : diagnosticRecord.error) !== null && _f !== void 0 ? _f : diagnosticRecord === null || diagnosticRecord === void 0 ? void 0 : diagnosticRecord.code;
|
|
139
|
-
if (typeof diagnosticCode === "string") {
|
|
140
|
-
return diagnosticCode;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return undefined;
|
|
144
|
-
}
|
|
145
|
-
function responseStatus(error, payload) {
|
|
146
|
-
var _a, _b, _c, _d, _e, _f;
|
|
147
|
-
const root = asRecord(error);
|
|
148
|
-
const response = asRecord(root === null || root === void 0 ? void 0 : root.response);
|
|
149
|
-
const body = asRecord(payload);
|
|
150
|
-
const status = (_d = (_c = (_b = (_a = root === null || root === void 0 ? void 0 : root.status) !== null && _a !== void 0 ? _a : root === null || root === void 0 ? void 0 : root.statusCode) !== null && _b !== void 0 ? _b : response === null || response === void 0 ? void 0 : response.status) !== null && _c !== void 0 ? _c : body === null || body === void 0 ? void 0 : body.status) !== null && _d !== void 0 ? _d : body === null || body === void 0 ? void 0 : body.statusCode;
|
|
151
|
-
if (typeof status === "number") {
|
|
152
|
-
return status;
|
|
153
|
-
}
|
|
154
|
-
const outcome = (_e = asRecord(body === null || body === void 0 ? void 0 : body.outcome)) !== null && _e !== void 0 ? _e : body;
|
|
155
|
-
const issues = Array.isArray(outcome === null || outcome === void 0 ? void 0 : outcome.issue) ? outcome.issue : [];
|
|
156
|
-
for (const issue of issues) {
|
|
157
|
-
const issueCode = (_f = asRecord(issue)) === null || _f === void 0 ? void 0 : _f.code;
|
|
158
|
-
if (issueCode === "conflict") {
|
|
159
|
-
return 409;
|
|
160
|
-
}
|
|
161
|
-
if (issueCode === "forbidden") {
|
|
162
|
-
return 403;
|
|
163
|
-
}
|
|
164
|
-
if (issueCode === "not-found") {
|
|
165
|
-
return 404;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return undefined;
|
|
169
|
-
}
|
|
170
|
-
function parseJson(value) {
|
|
171
|
-
if (typeof value !== "string") {
|
|
172
|
-
return value;
|
|
173
|
-
}
|
|
174
|
-
try {
|
|
175
|
-
return JSON.parse(value);
|
|
176
|
-
}
|
|
177
|
-
catch (_a) {
|
|
178
|
-
return undefined;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
function asRecord(value) {
|
|
182
|
-
return value && typeof value === "object"
|
|
183
|
-
? value
|
|
184
|
-
: undefined;
|
|
185
|
-
}
|
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
import { OvokClient } from "../ovok-client";
|
|
2
|
-
import { EnableSignalsResponse, SetSignalsThresholdBody, SignalsAlert, SignalsAlertsPage, SignalsAlertsQuery, SignalsSettingsPatch, SignalsSettingsResponse, SignalsThreshold, SignalsThresholds } from "./types";
|
|
2
|
+
import { EnableSignalsResponse, SetSignalsThresholdBody, SignalsAlert, SignalsAlertsPage, SignalsAlertsQuery, SignalsRawAlert, SignalsRawAlertsPage, SignalsRawAlertsQuery, SignalsSettingsPatch, SignalsSettingsResponse, SignalsThreshold, SignalsThresholds } from "./types";
|
|
3
3
|
/**
|
|
4
|
-
* Enables Signals for an existing patient. The operation is idempotent;
|
|
5
|
-
* forwarded by the backend, so callers should not submit
|
|
4
|
+
* Enables Signals for an existing patient. The operation is idempotent; retry after 409 or 503.
|
|
5
|
+
* Observations saved through Ovok are forwarded by the backend, so callers should not submit
|
|
6
|
+
* the same readings to Signals separately.
|
|
6
7
|
*/
|
|
7
8
|
export declare function enableSignalsForPatient(this: OvokClient, patientId: string): Promise<EnableSignalsResponse>;
|
|
8
9
|
export declare function getSignalsThresholds(this: OvokClient, patientId: string): Promise<SignalsThresholds>;
|
|
9
10
|
export declare function setSignalsThreshold(this: OvokClient, patientId: string, code: string, body: SetSignalsThresholdBody): Promise<SignalsThreshold>;
|
|
10
11
|
export declare function removeSignalsThreshold(this: OvokClient, patientId: string, code: string, reason: string): Promise<void>;
|
|
11
|
-
export declare function serializeSignalsAlertsQuery(query?: SignalsAlertsQuery): string;
|
|
12
|
+
export declare function serializeSignalsAlertsQuery(query?: SignalsAlertsQuery | SignalsRawAlertsQuery, keys?: readonly string[]): string;
|
|
12
13
|
export declare function listSignalsAlerts(this: OvokClient, query?: SignalsAlertsQuery): Promise<SignalsAlertsPage>;
|
|
13
14
|
export declare function getSignalsAlert(this: OvokClient, episodeId: string): Promise<SignalsAlert>;
|
|
14
15
|
export declare function acknowledgeSignalsAlert(this: OvokClient, episodeId: string): Promise<SignalsAlert>;
|
|
16
|
+
/**
|
|
17
|
+
* The project's individual Signals alerts, not episodes: works whether or not the project's
|
|
18
|
+
* `episodicAlerts` is on. `acknowledged: false` lists what is still open for the practitioner.
|
|
19
|
+
*/
|
|
20
|
+
export declare function listSignalsRawAlerts(this: OvokClient, query?: SignalsRawAlertsQuery): Promise<SignalsRawAlertsPage>;
|
|
21
|
+
export declare function getSignalsRawAlert(this: OvokClient, alertId: string): Promise<SignalsRawAlert>;
|
|
22
|
+
/**
|
|
23
|
+
* Acknowledges one alert: it resolves, and `acknowledgedAt` and `acknowledgedActor` record when
|
|
24
|
+
* and by whom. Idempotent: an acknowledged alert keeps its first acknowledgement. Needs
|
|
25
|
+
* `signals_alerts:update` and update access to the resident.
|
|
26
|
+
*/
|
|
27
|
+
export declare function acknowledgeSignalsRawAlert(this: OvokClient, alertId: string): Promise<SignalsRawAlert>;
|
|
15
28
|
export declare function getSignalsSettings(this: OvokClient): Promise<SignalsSettingsResponse>;
|
|
16
29
|
export declare function updateSignalsSettings(this: OvokClient, patch: SignalsSettingsPatch, reason?: string | null): Promise<SignalsSettingsResponse>;
|
|
@@ -8,12 +8,16 @@ exports.serializeSignalsAlertsQuery = serializeSignalsAlertsQuery;
|
|
|
8
8
|
exports.listSignalsAlerts = listSignalsAlerts;
|
|
9
9
|
exports.getSignalsAlert = getSignalsAlert;
|
|
10
10
|
exports.acknowledgeSignalsAlert = acknowledgeSignalsAlert;
|
|
11
|
+
exports.listSignalsRawAlerts = listSignalsRawAlerts;
|
|
12
|
+
exports.getSignalsRawAlert = getSignalsRawAlert;
|
|
13
|
+
exports.acknowledgeSignalsRawAlert = acknowledgeSignalsRawAlert;
|
|
11
14
|
exports.getSignalsSettings = getSignalsSettings;
|
|
12
15
|
exports.updateSignalsSettings = updateSignalsSettings;
|
|
13
16
|
const segment = (value) => encodeURIComponent(value);
|
|
14
17
|
/**
|
|
15
|
-
* Enables Signals for an existing patient. The operation is idempotent;
|
|
16
|
-
* forwarded by the backend, so callers should not submit
|
|
18
|
+
* Enables Signals for an existing patient. The operation is idempotent; retry after 409 or 503.
|
|
19
|
+
* Observations saved through Ovok are forwarded by the backend, so callers should not submit
|
|
20
|
+
* the same readings to Signals separately.
|
|
17
21
|
*/
|
|
18
22
|
function enableSignalsForPatient(patientId) {
|
|
19
23
|
return this.post(`/fhir/Patient/${segment(patientId)}/$enable-signals`);
|
|
@@ -27,28 +31,28 @@ function setSignalsThreshold(patientId, code, body) {
|
|
|
27
31
|
function removeSignalsThreshold(patientId, code, reason) {
|
|
28
32
|
return this.delete(`/v1/signals/patients/${segment(patientId)}/thresholds/${segment(code)}?reason=${segment(reason)}`);
|
|
29
33
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
34
|
+
// Each route's own filters, in the order they are sent: a key outside the list is never sent, so
|
|
35
|
+
// a wider object passed as an episode query can't turn into a refused request.
|
|
36
|
+
const EPISODE_QUERY_KEYS = ["status", "since", "acknowledged", "codes", "limit", "cursor"];
|
|
37
|
+
const RAW_ALERT_QUERY_KEYS = [
|
|
38
|
+
"status",
|
|
39
|
+
"patientId",
|
|
40
|
+
"since",
|
|
41
|
+
"until",
|
|
42
|
+
"acknowledged",
|
|
43
|
+
"codes",
|
|
44
|
+
"limit",
|
|
45
|
+
"cursor",
|
|
46
|
+
];
|
|
47
|
+
function serializeSignalsAlertsQuery(query = {}, keys = EPISODE_QUERY_KEYS) {
|
|
48
|
+
const values = query;
|
|
49
|
+
return keys
|
|
50
|
+
.filter((key) => values[key] !== undefined)
|
|
51
|
+
.map((key) => {
|
|
52
|
+
const value = values[key];
|
|
53
|
+
const text = Array.isArray(value) ? value.join(",") : String(value);
|
|
54
|
+
return `${segment(key)}=${segment(text)}`;
|
|
55
|
+
})
|
|
52
56
|
.join("&");
|
|
53
57
|
}
|
|
54
58
|
function listSignalsAlerts(query = {}) {
|
|
@@ -61,6 +65,25 @@ function getSignalsAlert(episodeId) {
|
|
|
61
65
|
function acknowledgeSignalsAlert(episodeId) {
|
|
62
66
|
return this.post(`/v1/signals/alerts/${segment(episodeId)}/ack`);
|
|
63
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* The project's individual Signals alerts, not episodes: works whether or not the project's
|
|
70
|
+
* `episodicAlerts` is on. `acknowledged: false` lists what is still open for the practitioner.
|
|
71
|
+
*/
|
|
72
|
+
function listSignalsRawAlerts(query = {}) {
|
|
73
|
+
const serialized = serializeSignalsAlertsQuery(query, RAW_ALERT_QUERY_KEYS);
|
|
74
|
+
return this.get(`/v1/signals/raw-alerts${serialized ? `?${serialized}` : ""}`);
|
|
75
|
+
}
|
|
76
|
+
function getSignalsRawAlert(alertId) {
|
|
77
|
+
return this.get(`/v1/signals/raw-alerts/${segment(alertId)}`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Acknowledges one alert: it resolves, and `acknowledgedAt` and `acknowledgedActor` record when
|
|
81
|
+
* and by whom. Idempotent: an acknowledged alert keeps its first acknowledgement. Needs
|
|
82
|
+
* `signals_alerts:update` and update access to the resident.
|
|
83
|
+
*/
|
|
84
|
+
function acknowledgeSignalsRawAlert(alertId) {
|
|
85
|
+
return this.post(`/v1/signals/raw-alerts/${segment(alertId)}/ack`);
|
|
86
|
+
}
|
|
64
87
|
function getSignalsSettings() {
|
|
65
88
|
return this.get("/v1/signals/settings");
|
|
66
89
|
}
|
|
@@ -39,6 +39,79 @@ export type SignalsAlertsPage = {
|
|
|
39
39
|
items: SignalsAlert[];
|
|
40
40
|
nextCursor: string | null;
|
|
41
41
|
};
|
|
42
|
+
/** Signals' own state of a raw alert: ACTIVE while breaching, RESOLVED once recovered or acknowledged. */
|
|
43
|
+
export type SignalsRawAlertStatus = "ACTIVE" | "RESOLVED";
|
|
44
|
+
/** The person who acknowledged an alert. */
|
|
45
|
+
export type SignalsAcknowledgedActor = {
|
|
46
|
+
/** A FHIR reference, e.g. `Practitioner/<id>`. */
|
|
47
|
+
reference: string;
|
|
48
|
+
display: string | null;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* One individual Signals alert, not an episode: available whether or not the project's
|
|
52
|
+
* `episodicAlerts` is on. `id`, `createdAt` and `resolvedAt` are Signals' own.
|
|
53
|
+
*
|
|
54
|
+
* An alert stays open for the practitioner until it is acknowledged: `acknowledgedAt` is null until
|
|
55
|
+
* then, even when `status` is already RESOLVED because the reading recovered. Acknowledging
|
|
56
|
+
* resolves it, and the next breaching reading opens a new alert.
|
|
57
|
+
*/
|
|
58
|
+
export type SignalsRawAlert = {
|
|
59
|
+
id: string;
|
|
60
|
+
/** The resident's Medplum Patient id. */
|
|
61
|
+
patientId: string;
|
|
62
|
+
signalsPatientId: string;
|
|
63
|
+
/** The LOINC code that breached; null when no reading's code raised it. */
|
|
64
|
+
code: string | null;
|
|
65
|
+
/**
|
|
66
|
+
* TRIGGER is a threshold breach; EMPTY a reading with no value; NOTE a note; INACTIVE a resident
|
|
67
|
+
* who stopped reporting.
|
|
68
|
+
*/
|
|
69
|
+
reason: "TRIGGER" | "EMPTY" | "NOTE" | "INACTIVE";
|
|
70
|
+
/** The latest breaching reading, as a number or as text. */
|
|
71
|
+
valueNumber: number | null;
|
|
72
|
+
valueString: string | null;
|
|
73
|
+
/** The rule's own payload; it names the bound that was crossed. */
|
|
74
|
+
message: string | null;
|
|
75
|
+
observationId: string | null;
|
|
76
|
+
triggerCode: string | null;
|
|
77
|
+
triggerVersion: number | null;
|
|
78
|
+
status: SignalsRawAlertStatus;
|
|
79
|
+
createdAt: string;
|
|
80
|
+
resolvedAt: string | null;
|
|
81
|
+
acknowledgedAt: string | null;
|
|
82
|
+
/** The Signals client that acknowledged it (Ovok's), not a person: use `acknowledgedActor`. */
|
|
83
|
+
acknowledgedBy: string | null;
|
|
84
|
+
acknowledgedActor: SignalsAcknowledgedActor | null;
|
|
85
|
+
[key: string]: unknown;
|
|
86
|
+
};
|
|
87
|
+
export type SignalsRawAlertsQuery = {
|
|
88
|
+
status?: SignalsRawAlertStatus;
|
|
89
|
+
/** `false` for the alerts still open for the practitioner, whatever their `status`. */
|
|
90
|
+
acknowledged?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* One resident's alerts, by Medplum Patient id. 404 when the caller can't read the resident,
|
|
93
|
+
* 409 `signals_patient_not_enrolled` when they aren't in Signals yet.
|
|
94
|
+
*/
|
|
95
|
+
patientId?: string;
|
|
96
|
+
/** LOINC codes, e.g. `["8867-4", "9279-1"]`. Omitted or empty, every alert. */
|
|
97
|
+
codes?: readonly string[];
|
|
98
|
+
/** Alerts created at or after this date-time, with `Z` or an offset. */
|
|
99
|
+
since?: string;
|
|
100
|
+
/** Alerts created before this date-time, with `Z` or an offset. */
|
|
101
|
+
until?: string;
|
|
102
|
+
/** 1 to 50; 50 when omitted. */
|
|
103
|
+
limit?: number;
|
|
104
|
+
/** The previous page's `nextCursor`, passed back unchanged. */
|
|
105
|
+
cursor?: string;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Newest first. A page can be shorter than `limit`, even empty, and still have a next one: alerts
|
|
109
|
+
* of residents the caller can't read are left out. Page until `nextCursor` is null.
|
|
110
|
+
*/
|
|
111
|
+
export type SignalsRawAlertsPage = {
|
|
112
|
+
items: SignalsRawAlert[];
|
|
113
|
+
nextCursor: string | null;
|
|
114
|
+
};
|
|
42
115
|
export type SignalsSettings = {
|
|
43
116
|
episodicAlerts: boolean;
|
|
44
117
|
synchronousMode: boolean;
|
|
@@ -53,7 +126,7 @@ export type SignalsSettingsPatch = Partial<SignalsSettings>;
|
|
|
53
126
|
export type EnableSignalsResponse = {
|
|
54
127
|
patientId: string;
|
|
55
128
|
signalsPatientId: string;
|
|
56
|
-
enabled:
|
|
129
|
+
enabled: true;
|
|
57
130
|
};
|
|
58
131
|
export type SignalsErrorCode = "signals_threshold_not_editable" | "signals_patient_not_enrolled" | "signals_conflict" | "signals_code_not_medical" | "signals_reason_required" | "signals_episodes_disabled" | "signals_bad_request" | "signals_shared_tenant" | "signals_audit_failed" | "signals_write_mismatch" | "signals_unavailable" | "signals_undo_failed" | "signals_mint_failed" | "signals_forbidden" | "signals_not_found" | "validation_error";
|
|
59
132
|
export type SignalsFieldError = ValidationError;
|