evo360-types 1.3.570 → 1.3.578
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps/evo-crm/lead/zod-schemas.d.ts +18 -9
- package/dist/apps/evo-csq/zod-schemas.d.ts +12 -12
- package/dist/apps/evo-finops/zod-schemas.d.ts +18 -18
- package/dist/apps/evo-med/calendar/zod-schemas.d.ts +535 -0
- package/dist/apps/evo-med/calendar/zod-schemas.js +52 -1
- package/dist/apps/evo-med/calendar/zod-schemas.ts +55 -0
- package/dist/apps/evo-med/dic/zod-schemas.d.ts +2 -2
- package/dist/apps/evo-med/insurance/zod-schemas.d.ts +9 -0
- package/dist/apps/evo-med/people/zod-schemas.d.ts +63 -45
- package/dist/apps/evo-notifications/quick-reply-action/zod-schemas.d.ts +3 -0
- package/dist/apps/evo-notifications/quick-reply-action/zod-schemas.js +3 -0
- package/dist/apps/evo-notifications/quick-reply-action/zod-schemas.ts +3 -0
- package/dist/apps/evo-notifications/zod-schemas.d.ts +69 -39
- package/dist/apps/evo-task/zod-schemas.d.ts +69 -69
- package/dist/apps/evo-task/zod-schemas.js +8 -0
- package/dist/apps/evo-task/zod-schemas.ts +8 -0
- package/dist/apps/evo-telemedicine/zod-schemas.d.ts +1567 -0
- package/dist/apps/evo-telemedicine/zod-schemas.js +709 -0
- package/dist/apps/evo-telemedicine/zod-schemas.ts +794 -0
- package/dist/apps/evo-tenant/zod-schemas.d.ts +94 -0
- package/dist/apps/evo-tenant/zod-schemas.js +29 -1
- package/dist/apps/evo-tenant/zod-schemas.ts +32 -1
- package/dist/apps/hub-automation/zod-schemas.d.ts +172 -172
- package/dist/apps/shared/zod-schemas.d.ts +3 -0
- package/dist/apps/shared/zod-schemas.js +2 -0
- package/dist/apps/shared/zod-schemas.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.ts +2 -0
- package/dist/types/evo-finops/common/contract.d.ts +8 -0
- package/dist/types/evo-finops/common/contract.js +7 -0
- package/dist/types/evo-finops/common/contract.ts +7 -0
- package/dist/types/evo-med/calendar/index.d.ts +104 -0
- package/dist/types/evo-med/calendar/index.js +66 -1
- package/dist/types/evo-med/calendar/index.ts +146 -0
- package/dist/types/evo-notifications/index.d.ts +13 -0
- package/dist/types/evo-notifications/index.js +6 -0
- package/dist/types/evo-notifications/index.ts +13 -0
- package/dist/types/evo-reports/index.d.ts +27 -0
- package/dist/types/evo-reports/index.ts +28 -0
- package/dist/types/evo-task/index.d.ts +1 -0
- package/dist/types/evo-task/index.js +8 -0
- package/dist/types/evo-task/index.ts +8 -0
- package/dist/types/evo-telemedicine/fb_collections.d.ts +16 -0
- package/dist/types/evo-telemedicine/fb_collections.js +38 -0
- package/dist/types/evo-telemedicine/fb_collections.ts +37 -0
- package/dist/types/evo-telemedicine/index.d.ts +1137 -0
- package/dist/types/evo-telemedicine/index.js +387 -0
- package/dist/types/evo-telemedicine/index.ts +1299 -0
- package/dist/types/evo-tenant/index.d.ts +45 -0
- package/dist/types/evo-tenant/index.js +20 -1
- package/dist/types/evo-tenant/index.ts +65 -0
- package/dist/types/shared/external-links.d.ts +6 -0
- package/dist/types/shared/external-links.js +6 -0
- package/dist/types/shared/external-links.ts +6 -0
- package/dist/types/shared/index.d.ts +1 -0
- package/dist/types/shared/index.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,794 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import {
|
|
3
|
+
zFireDocSchema,
|
|
4
|
+
zFirestoreDateSchema,
|
|
5
|
+
} from "../shared/zod-schemas";
|
|
6
|
+
import { zTenantModuleEntitlementSchema } from "../evo-tenant/zod-schemas";
|
|
7
|
+
|
|
8
|
+
// ======================================================
|
|
9
|
+
// evo-telemedicine (feat-160) — zod schemas
|
|
10
|
+
//
|
|
11
|
+
// Espelhos À MÃO dos enums/interfaces em types/evo-telemedicine/index.ts (o
|
|
12
|
+
// repo não gera um lado a partir do outro). Ao acrescentar um valor no `*Enum`
|
|
13
|
+
// TS, acrescente aqui — e vice-versa. Doc schemas usam `.passthrough()` para
|
|
14
|
+
// tolerar campos aditivos sem republish; command schemas são ESTRITOS (fronteira
|
|
15
|
+
// HTTP) e nunca aceitam `tenant` no body.
|
|
16
|
+
// ======================================================
|
|
17
|
+
|
|
18
|
+
// ----- Enums ----------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
/** Espelha `TeleconsultationStatusEnum`. */
|
|
21
|
+
export const zTeleconsultationStatusSchema = z.enum([
|
|
22
|
+
"scheduled",
|
|
23
|
+
"open",
|
|
24
|
+
"live",
|
|
25
|
+
"reconnecting",
|
|
26
|
+
"ending",
|
|
27
|
+
"ended",
|
|
28
|
+
"cancelled",
|
|
29
|
+
"expired",
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
/** Espelha `WaitingPolicyEnum`. */
|
|
33
|
+
export const zWaitingPolicySchema = z.enum([
|
|
34
|
+
"manual_admit",
|
|
35
|
+
"auto_when_doctor_present",
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
/** Espelha `TeleconsultationModeEnum`. */
|
|
39
|
+
export const zTeleconsultationModeSchema = z.enum([
|
|
40
|
+
"audio_video",
|
|
41
|
+
"audio_only_allowed",
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
/** Espelha `TeleconsultationProviderEnum`. */
|
|
45
|
+
export const zTeleconsultationProviderSchema = z.enum(["realtimekit"]);
|
|
46
|
+
|
|
47
|
+
/** Espelha `ParticipantRoleEnum`. */
|
|
48
|
+
export const zParticipantRoleSchema = z.enum(["doctor", "patient"]);
|
|
49
|
+
|
|
50
|
+
/** Espelha `ParticipantStateEnum`. */
|
|
51
|
+
export const zParticipantStateSchema = z.enum([
|
|
52
|
+
"invited",
|
|
53
|
+
"verified",
|
|
54
|
+
"waiting",
|
|
55
|
+
"connected",
|
|
56
|
+
"disconnected",
|
|
57
|
+
"left",
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
/** Espelha `PresenceStateEnum` (subconjunto reportável pelo cliente). */
|
|
61
|
+
export const zPresenceStateSchema = z.enum([
|
|
62
|
+
"waiting",
|
|
63
|
+
"connected",
|
|
64
|
+
"disconnected",
|
|
65
|
+
"left",
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
/** Espelha `IdentityLevelEnum`. */
|
|
69
|
+
export const zIdentityLevelSchema = z.enum(["none", "weak", "strong"]);
|
|
70
|
+
|
|
71
|
+
/** Espelha `RecordingStatusEnum`. */
|
|
72
|
+
export const zRecordingStatusSchema = z.enum([
|
|
73
|
+
"idle",
|
|
74
|
+
"consent_pending",
|
|
75
|
+
"recording",
|
|
76
|
+
"stopping",
|
|
77
|
+
"failed",
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
/** Espelha `TranscriptionStatusEnum`. */
|
|
81
|
+
export const zTranscriptionStatusSchema = z.enum([
|
|
82
|
+
"not_requested",
|
|
83
|
+
"queued",
|
|
84
|
+
"processing",
|
|
85
|
+
"ready",
|
|
86
|
+
"failed",
|
|
87
|
+
"deleted",
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
/** Espelha `ConsentSubjectEnum`. */
|
|
91
|
+
export const zConsentSubjectSchema = z.enum([
|
|
92
|
+
"terms",
|
|
93
|
+
"privacy",
|
|
94
|
+
"recording",
|
|
95
|
+
"transcription",
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
/** Espelha `ConsentDecisionEnum`. */
|
|
99
|
+
export const zConsentDecisionSchema = z.enum([
|
|
100
|
+
"accepted",
|
|
101
|
+
"declined",
|
|
102
|
+
"withdrawn",
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
/** Espelha `ConsentActorTypeEnum`. */
|
|
106
|
+
export const zConsentActorTypeSchema = z.enum(["patient", "doctor"]);
|
|
107
|
+
|
|
108
|
+
/** Espelha `ArtifactTypeEnum`. */
|
|
109
|
+
export const zArtifactTypeSchema = z.enum([
|
|
110
|
+
"recording_audio_video",
|
|
111
|
+
"recording_audio",
|
|
112
|
+
"transcript",
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
/** Espelha `ArtifactStatusEnum`. */
|
|
116
|
+
export const zArtifactStatusSchema = z.enum([
|
|
117
|
+
"pending",
|
|
118
|
+
"processing",
|
|
119
|
+
"ready",
|
|
120
|
+
"failed",
|
|
121
|
+
"deleting",
|
|
122
|
+
"deleted",
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
/** Espelha `AccessGrantKindEnum`. */
|
|
126
|
+
export const zAccessGrantKindSchema = z.enum([
|
|
127
|
+
"qr_capability",
|
|
128
|
+
"launch_code",
|
|
129
|
+
"browser_session",
|
|
130
|
+
// feat-160 F7: `kind` de uma ENTRADA do `grant-index`, nunca de um grant.
|
|
131
|
+
"ics_capability",
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
/** Espelha `AccessGrantStateEnum`. */
|
|
135
|
+
export const zAccessGrantStateSchema = z.enum([
|
|
136
|
+
"active",
|
|
137
|
+
"consumed",
|
|
138
|
+
"blocked",
|
|
139
|
+
"revoked",
|
|
140
|
+
"expired",
|
|
141
|
+
]);
|
|
142
|
+
|
|
143
|
+
/** Espelha `AccessSendChannelKindEnum`. */
|
|
144
|
+
export const zAccessSendChannelKindSchema = z.enum([
|
|
145
|
+
"whatsapp",
|
|
146
|
+
"email",
|
|
147
|
+
"manual",
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
/** Espelha `EndedByTypeEnum`. */
|
|
151
|
+
export const zEndedByTypeSchema = z.enum(["user", "system"]);
|
|
152
|
+
|
|
153
|
+
/** Espelha `TeleconsultationEventActorTypeEnum`. */
|
|
154
|
+
export const zTeleconsultationEventActorTypeSchema = z.enum([
|
|
155
|
+
"user",
|
|
156
|
+
"patient",
|
|
157
|
+
"system",
|
|
158
|
+
"provider",
|
|
159
|
+
]);
|
|
160
|
+
|
|
161
|
+
/** Espelha `TeleconsultationEventSourceEnum`. */
|
|
162
|
+
export const zTeleconsultationEventSourceSchema = z.enum([
|
|
163
|
+
"api",
|
|
164
|
+
"webhook",
|
|
165
|
+
"appointment_reconciler",
|
|
166
|
+
"retention_job",
|
|
167
|
+
"sweep",
|
|
168
|
+
]);
|
|
169
|
+
|
|
170
|
+
/** Espelha `TeleconsultationEventTypeEnum`. ADITIVO: eventos já gravados dependem desta lista. */
|
|
171
|
+
export const zTeleconsultationEventTypeSchema = z.enum([
|
|
172
|
+
"teleconsultation.created",
|
|
173
|
+
"teleconsultation.rescheduled",
|
|
174
|
+
"teleconsultation.cancelled",
|
|
175
|
+
"teleconsultation.expired",
|
|
176
|
+
"teleconsultation.diverged",
|
|
177
|
+
"access.created",
|
|
178
|
+
"access.link_revealed",
|
|
179
|
+
"access.revoked",
|
|
180
|
+
"access.exchanged",
|
|
181
|
+
"access.verification_failed",
|
|
182
|
+
"access.blocked",
|
|
183
|
+
"host.claimed",
|
|
184
|
+
"host.reassigned",
|
|
185
|
+
"waiting_policy.changed",
|
|
186
|
+
"doctor.prepared",
|
|
187
|
+
"doctor.joined",
|
|
188
|
+
"doctor.disconnected",
|
|
189
|
+
"doctor.rejoined",
|
|
190
|
+
"doctor.left",
|
|
191
|
+
"patient.verified",
|
|
192
|
+
"patient.waiting",
|
|
193
|
+
"patient.admitted",
|
|
194
|
+
"patient.rejected",
|
|
195
|
+
"patient.joined",
|
|
196
|
+
"patient.disconnected",
|
|
197
|
+
"patient.rejoined",
|
|
198
|
+
"patient.left",
|
|
199
|
+
"recording.consent_requested",
|
|
200
|
+
"recording.consent_accepted",
|
|
201
|
+
"recording.consent_declined",
|
|
202
|
+
"recording.consent_withdrawn",
|
|
203
|
+
"recording.started",
|
|
204
|
+
"recording.stopped",
|
|
205
|
+
"recording.failed",
|
|
206
|
+
"transcription.queued",
|
|
207
|
+
"transcription.ready",
|
|
208
|
+
"transcription.failed",
|
|
209
|
+
"transcription.deleted",
|
|
210
|
+
"consultation.started",
|
|
211
|
+
"consultation.reconnecting",
|
|
212
|
+
"consultation.ended",
|
|
213
|
+
"artifact.accessed",
|
|
214
|
+
"artifact.deleted",
|
|
215
|
+
"entitlement.denied",
|
|
216
|
+
"rollout.denied",
|
|
217
|
+
"permission.denied",
|
|
218
|
+
"webhook.observed",
|
|
219
|
+
]);
|
|
220
|
+
|
|
221
|
+
/** Espelha `WebhookEventStatusEnum`. */
|
|
222
|
+
export const zWebhookEventStatusSchema = z.enum([
|
|
223
|
+
"pending",
|
|
224
|
+
"claimed",
|
|
225
|
+
"completed",
|
|
226
|
+
"failed",
|
|
227
|
+
]);
|
|
228
|
+
|
|
229
|
+
/** Espelha `LegalTextStatusEnum`. */
|
|
230
|
+
export const zLegalTextStatusSchema = z.enum(["draft", "published", "retired"]);
|
|
231
|
+
|
|
232
|
+
/** Espelha `TranscriptionProviderEnum`. */
|
|
233
|
+
export const zTranscriptionProviderSchema = z.enum(["none", "realtimekit"]);
|
|
234
|
+
|
|
235
|
+
/** Espelha `EntitlementAuditActionEnum`. */
|
|
236
|
+
export const zEntitlementAuditActionSchema = z.enum(["set", "override", "revoke"]);
|
|
237
|
+
|
|
238
|
+
/** Espelha `TelemedicineErrorCode`. */
|
|
239
|
+
export const zTelemedicineErrorCodeSchema = z.enum([
|
|
240
|
+
"TENANT_MODULE_DISABLED",
|
|
241
|
+
"ROLLOUT_DISABLED",
|
|
242
|
+
"EMERGENCY_KILL",
|
|
243
|
+
"PERMISSION_DENIED",
|
|
244
|
+
"CAPABILITY_DISABLED",
|
|
245
|
+
"NOT_FOUND",
|
|
246
|
+
"ACCESS_WINDOW_CLOSED",
|
|
247
|
+
"HOST_CLAIMED_BY_OTHER",
|
|
248
|
+
"HOST_REQUIRED",
|
|
249
|
+
"CONSENT_REQUIRED",
|
|
250
|
+
"IDENTITY_REQUIRED",
|
|
251
|
+
"IDENTITY_VERIFICATION_FAILED",
|
|
252
|
+
"GRANT_BLOCKED",
|
|
253
|
+
"GRANT_INVALID",
|
|
254
|
+
"SESSION_INVALID",
|
|
255
|
+
"TELECONSULTATION_TERMINAL",
|
|
256
|
+
"INVALID_TRANSITION",
|
|
257
|
+
"VERSION_CONFLICT",
|
|
258
|
+
"WAITING_POLICY_LOCKED",
|
|
259
|
+
"RECORDING_ACTIVE",
|
|
260
|
+
"RECORDING_FAILED",
|
|
261
|
+
"TRANSCRIPTION_GATE_CLOSED",
|
|
262
|
+
"ARTIFACT_NOT_READY",
|
|
263
|
+
"PROVIDER_ERROR",
|
|
264
|
+
"RATE_LIMITED",
|
|
265
|
+
"VALIDATION_ERROR",
|
|
266
|
+
]);
|
|
267
|
+
|
|
268
|
+
// ----- Value objects ----------------------------------------------------------
|
|
269
|
+
|
|
270
|
+
const zDate = zFirestoreDateSchema;
|
|
271
|
+
const zDateNullable = zFirestoreDateSchema.nullable().optional();
|
|
272
|
+
|
|
273
|
+
/** Metadata allowlisted (sem PII/conteúdo médico): só primitivos. */
|
|
274
|
+
export const zTeleconsultationEventMetadataSchema = z.record(
|
|
275
|
+
z.string().min(1).max(60),
|
|
276
|
+
z.union([z.string().max(500), z.number(), z.boolean()])
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
export const zTeleconsultationEndedBySchema = z
|
|
280
|
+
.object({
|
|
281
|
+
type: zEndedByTypeSchema,
|
|
282
|
+
id: z.string().optional(),
|
|
283
|
+
reason: z.string().min(1).max(120),
|
|
284
|
+
})
|
|
285
|
+
.passthrough();
|
|
286
|
+
|
|
287
|
+
export const zTeleconsultationEntitlementSnapshotSchema = z
|
|
288
|
+
.object({
|
|
289
|
+
version: z.number().int().min(0),
|
|
290
|
+
capabilities: z.record(
|
|
291
|
+
z.string(),
|
|
292
|
+
z.union([z.boolean(), z.number(), z.string()])
|
|
293
|
+
),
|
|
294
|
+
})
|
|
295
|
+
.passthrough();
|
|
296
|
+
|
|
297
|
+
export const zTeleconsultationEventActorSchema = z
|
|
298
|
+
.object({
|
|
299
|
+
type: zTeleconsultationEventActorTypeSchema,
|
|
300
|
+
id: z.string().optional(),
|
|
301
|
+
})
|
|
302
|
+
.passthrough();
|
|
303
|
+
|
|
304
|
+
// ----- Documentos (por tenant) -------------------------------------------------
|
|
305
|
+
|
|
306
|
+
/** Espelha `ITeleconsultation`. */
|
|
307
|
+
export const zTeleconsultationSchema = zFireDocSchema
|
|
308
|
+
.extend({
|
|
309
|
+
calendar_id: z.string().min(1),
|
|
310
|
+
appointment_id: z.string().min(1),
|
|
311
|
+
patient_id: z.string().min(1),
|
|
312
|
+
scheduled_professional_id: z.string().optional(),
|
|
313
|
+
claimed_host_user_id: z.string().optional(),
|
|
314
|
+
claimed_host_at: zDateNullable,
|
|
315
|
+
mode: zTeleconsultationModeSchema,
|
|
316
|
+
status: zTeleconsultationStatusSchema,
|
|
317
|
+
waiting_policy: zWaitingPolicySchema,
|
|
318
|
+
scheduled_start_at: zDate,
|
|
319
|
+
scheduled_end_at: zDate,
|
|
320
|
+
doctor_access_from: zDate,
|
|
321
|
+
patient_access_from: zDate,
|
|
322
|
+
unused_expires_at: zDate,
|
|
323
|
+
reconnect_until: zDateNullable,
|
|
324
|
+
started_at: zDateNullable,
|
|
325
|
+
ended_at: zDateNullable,
|
|
326
|
+
ended_by: zTeleconsultationEndedBySchema.nullable().optional(),
|
|
327
|
+
provider: zTeleconsultationProviderSchema,
|
|
328
|
+
provider_meeting_id: z.string().optional(),
|
|
329
|
+
active_provider_session_id: z.string().optional(),
|
|
330
|
+
recording_status: zRecordingStatusSchema,
|
|
331
|
+
recording_request_id: z.string().optional(),
|
|
332
|
+
recording_terms_version: z.string().optional(),
|
|
333
|
+
recording_requested_at: zDateNullable,
|
|
334
|
+
recording_requested_by: z.string().optional(),
|
|
335
|
+
recording_started_at: zDateNullable,
|
|
336
|
+
recording_stopped_at: zDateNullable,
|
|
337
|
+
recording_failure_code: z.string().nullable().optional(),
|
|
338
|
+
recording_segment: z.number().int().min(0).optional(),
|
|
339
|
+
transcription_status: zTranscriptionStatusSchema,
|
|
340
|
+
provider_teardown_pending: z.boolean().optional(),
|
|
341
|
+
metadata_retention_until: zDateNullable,
|
|
342
|
+
entitlement_snapshot: zTeleconsultationEntitlementSnapshotSchema,
|
|
343
|
+
generation: z.number().int().min(0),
|
|
344
|
+
reschedule_count: z.number().int().min(0).optional(),
|
|
345
|
+
last_reconciled_appointment_version: z
|
|
346
|
+
.union([z.number(), z.string()])
|
|
347
|
+
.nullable()
|
|
348
|
+
.optional(),
|
|
349
|
+
last_reconciled_at: zDateNullable,
|
|
350
|
+
usage_metering_due_at: zDateNullable,
|
|
351
|
+
usage_metered_at: zDateNullable,
|
|
352
|
+
version: z.number().int().min(0),
|
|
353
|
+
})
|
|
354
|
+
.passthrough();
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Espelha `ITeleconsultationPrivateProvider` (subdoc `private/provider`).
|
|
358
|
+
*
|
|
359
|
+
* NÃO estende `zFireDocSchema`: o subdoc não é um IFireDoc (não tem `version`
|
|
360
|
+
* de concorrência nem `ref`), e é lido sempre pelo backend com `id` do snap.
|
|
361
|
+
*/
|
|
362
|
+
export const zTeleconsultationPrivateProviderSchema = z
|
|
363
|
+
.object({
|
|
364
|
+
id: z.string(),
|
|
365
|
+
tenant: z.string().min(1),
|
|
366
|
+
teleconsultation_id: z.string().min(1),
|
|
367
|
+
provider: zTeleconsultationProviderSchema,
|
|
368
|
+
provider_meeting_id: z.string().optional(),
|
|
369
|
+
active_provider_session_id: z.string().optional(),
|
|
370
|
+
provider_session_ids: z.array(z.string().min(1)).optional(),
|
|
371
|
+
provider_participant_ids: z.record(z.string(), z.string()).optional(),
|
|
372
|
+
active_provider_recording_id: z.string().nullable().optional(),
|
|
373
|
+
created_at: zDateNullable,
|
|
374
|
+
updated_at: zDateNullable,
|
|
375
|
+
})
|
|
376
|
+
.passthrough();
|
|
377
|
+
|
|
378
|
+
/** Espelha `ITeleconsultationParticipant`. */
|
|
379
|
+
export const zTeleconsultationParticipantSchema = zFireDocSchema
|
|
380
|
+
.extend({
|
|
381
|
+
teleconsultation_id: z.string().min(1),
|
|
382
|
+
role: zParticipantRoleSchema,
|
|
383
|
+
actor_user_id: z.string().optional(),
|
|
384
|
+
patient_id: z.string().optional(),
|
|
385
|
+
provider_participant_id: z.string().optional(),
|
|
386
|
+
opaque_custom_participant_id: z.string().min(1),
|
|
387
|
+
state: zParticipantStateSchema,
|
|
388
|
+
identity_level: zIdentityLevelSchema.optional(),
|
|
389
|
+
admitted_at: zDateNullable,
|
|
390
|
+
connected_at: zDateNullable,
|
|
391
|
+
last_seen_at: zDateNullable,
|
|
392
|
+
disconnected_at: zDateNullable,
|
|
393
|
+
reconnect_count: z.number().int().min(0),
|
|
394
|
+
})
|
|
395
|
+
.passthrough();
|
|
396
|
+
|
|
397
|
+
export const zTeleconsultationConsentEvidenceSchema = z
|
|
398
|
+
.object({
|
|
399
|
+
ui_locale: z.string().min(2).max(10),
|
|
400
|
+
session_id_hash: z.string().min(1),
|
|
401
|
+
})
|
|
402
|
+
.passthrough();
|
|
403
|
+
|
|
404
|
+
/** Espelha `ITeleconsultationConsent`. */
|
|
405
|
+
export const zTeleconsultationConsentSchema = zFireDocSchema
|
|
406
|
+
.extend({
|
|
407
|
+
teleconsultation_id: z.string().min(1),
|
|
408
|
+
subject: zConsentSubjectSchema,
|
|
409
|
+
decision: zConsentDecisionSchema,
|
|
410
|
+
terms_version: z.string().min(1).max(40),
|
|
411
|
+
terms_content_hash: z.string().optional(),
|
|
412
|
+
participant_id: z.string().min(1),
|
|
413
|
+
actor_type: zConsentActorTypeSchema,
|
|
414
|
+
occurred_at: zDate,
|
|
415
|
+
correlation_id: z.string().min(1),
|
|
416
|
+
recording_request_id: z.string().optional(),
|
|
417
|
+
evidence: zTeleconsultationConsentEvidenceSchema,
|
|
418
|
+
})
|
|
419
|
+
.passthrough();
|
|
420
|
+
|
|
421
|
+
/** Espelha `ITeleconsultationArtifact`. */
|
|
422
|
+
export const zTeleconsultationArtifactSchema = zFireDocSchema
|
|
423
|
+
.extend({
|
|
424
|
+
teleconsultation_id: z.string().min(1),
|
|
425
|
+
type: zArtifactTypeSchema,
|
|
426
|
+
segment: z.number().int().min(1),
|
|
427
|
+
status: zArtifactStatusSchema,
|
|
428
|
+
provider_artifact_id: z.string().optional(),
|
|
429
|
+
provider_session_id: z.string().optional(),
|
|
430
|
+
recording_request_id: z.string().optional(),
|
|
431
|
+
storage_bucket: z.string().optional(),
|
|
432
|
+
storage_object: z.string().optional(),
|
|
433
|
+
content_type: z.string().optional(),
|
|
434
|
+
size_bytes: z.number().int().min(0).optional(),
|
|
435
|
+
checksum: z.string().optional(),
|
|
436
|
+
started_at: zDateNullable,
|
|
437
|
+
ended_at: zDateNullable,
|
|
438
|
+
expires_at: zDateNullable,
|
|
439
|
+
deleted_at: zDateNullable,
|
|
440
|
+
error_code: z.string().optional(),
|
|
441
|
+
})
|
|
442
|
+
.passthrough();
|
|
443
|
+
|
|
444
|
+
/** Espelha `ITeleconsultationEvent` (append-only). */
|
|
445
|
+
export const zTeleconsultationEventSchema = zFireDocSchema
|
|
446
|
+
.extend({
|
|
447
|
+
teleconsultation_id: z.string().min(1),
|
|
448
|
+
type: zTeleconsultationEventTypeSchema,
|
|
449
|
+
occurred_at: zDate,
|
|
450
|
+
actor: zTeleconsultationEventActorSchema,
|
|
451
|
+
source: zTeleconsultationEventSourceSchema,
|
|
452
|
+
correlation_id: z.string().min(1),
|
|
453
|
+
causation_id: z.string().optional(),
|
|
454
|
+
idempotency_key: z.string().optional(),
|
|
455
|
+
from_status: z.string().optional(),
|
|
456
|
+
to_status: z.string().optional(),
|
|
457
|
+
metadata: zTeleconsultationEventMetadataSchema.optional(),
|
|
458
|
+
})
|
|
459
|
+
.passthrough();
|
|
460
|
+
|
|
461
|
+
/** Espelha `ITeleconsultationWebhookEvent` (dedup + outbox). */
|
|
462
|
+
export const zTeleconsultationWebhookEventSchema = zFireDocSchema
|
|
463
|
+
.extend({
|
|
464
|
+
teleconsultation_id: z.string().optional(),
|
|
465
|
+
provider: zTeleconsultationProviderSchema,
|
|
466
|
+
provider_event_id: z.string().min(1),
|
|
467
|
+
event_type: z.string().min(1),
|
|
468
|
+
payload_hash: z.string().optional(),
|
|
469
|
+
sanitized_payload: z
|
|
470
|
+
.record(
|
|
471
|
+
z.string(),
|
|
472
|
+
z.union([z.string(), z.number(), z.boolean(), z.null()])
|
|
473
|
+
)
|
|
474
|
+
.optional(),
|
|
475
|
+
status: zWebhookEventStatusSchema,
|
|
476
|
+
received_at: zDate,
|
|
477
|
+
claimed_at: zDateNullable,
|
|
478
|
+
claimed_by: z.string().optional(),
|
|
479
|
+
lease_until: zDateNullable,
|
|
480
|
+
processed_at: zDateNullable,
|
|
481
|
+
attempt: z.number().int().min(0),
|
|
482
|
+
next_attempt_at: zDateNullable,
|
|
483
|
+
result: z.string().optional(),
|
|
484
|
+
error_code: z.string().optional(),
|
|
485
|
+
correlation_id: z.string().min(1),
|
|
486
|
+
expires_at: zDate,
|
|
487
|
+
})
|
|
488
|
+
.passthrough();
|
|
489
|
+
|
|
490
|
+
/** Espelha `ITeleconsultationAccessGrant`. `secret_hash` é HMAC — nunca o segredo. */
|
|
491
|
+
export const zTeleconsultationAccessGrantSchema = zFireDocSchema
|
|
492
|
+
.extend({
|
|
493
|
+
teleconsultation_id: z.string().min(1),
|
|
494
|
+
role: zParticipantRoleSchema,
|
|
495
|
+
kind: zAccessGrantKindSchema,
|
|
496
|
+
secret_hash: z.string().min(1),
|
|
497
|
+
recipient_ref_hash: z.string().optional(),
|
|
498
|
+
actor_user_id: z.string().optional(),
|
|
499
|
+
participant_id: z.string().optional(),
|
|
500
|
+
state: zAccessGrantStateSchema,
|
|
501
|
+
expires_at: zDate,
|
|
502
|
+
consumed_at: zDateNullable,
|
|
503
|
+
revoked_at: zDateNullable,
|
|
504
|
+
revoked_by: z.string().optional(),
|
|
505
|
+
last_used_at: zDateNullable,
|
|
506
|
+
failed_attempts: z.number().int().min(0),
|
|
507
|
+
failed_window_started_at: zDateNullable,
|
|
508
|
+
blocked_until: zDateNullable,
|
|
509
|
+
parent_grant_id: z.string().optional(),
|
|
510
|
+
channel_kind: zAccessSendChannelKindSchema.optional(),
|
|
511
|
+
quick_reply_action_id: z.string().optional(),
|
|
512
|
+
version: z.number().int().min(0),
|
|
513
|
+
})
|
|
514
|
+
.passthrough();
|
|
515
|
+
|
|
516
|
+
/** Espelha `ITelemedicineAppointmentIndex`. */
|
|
517
|
+
export const zTelemedicineAppointmentIndexSchema = zFireDocSchema
|
|
518
|
+
.extend({
|
|
519
|
+
calendar_id: z.string().min(1),
|
|
520
|
+
appointment_id: z.string().min(1),
|
|
521
|
+
active_teleconsultation_id: z.string().nullable(),
|
|
522
|
+
generation: z.number().int().min(0),
|
|
523
|
+
last_reconciled_appointment_version: z
|
|
524
|
+
.union([z.number(), z.string()])
|
|
525
|
+
.nullable()
|
|
526
|
+
.optional(),
|
|
527
|
+
last_reconciled_at: zDateNullable,
|
|
528
|
+
last_teleconsultation_id: z.string().nullable().optional(),
|
|
529
|
+
})
|
|
530
|
+
.passthrough();
|
|
531
|
+
|
|
532
|
+
/** Espelha `ITelemedicineEntitlementAudit`. */
|
|
533
|
+
export const zTelemedicineEntitlementAuditSchema = zFireDocSchema
|
|
534
|
+
.extend({
|
|
535
|
+
module: z.string().min(1).max(40),
|
|
536
|
+
action: zEntitlementAuditActionSchema,
|
|
537
|
+
before: zTenantModuleEntitlementSchema.nullable().optional(),
|
|
538
|
+
after: zTenantModuleEntitlementSchema,
|
|
539
|
+
actor: z
|
|
540
|
+
.object({
|
|
541
|
+
type: z.enum(["user", "system", "script"]),
|
|
542
|
+
id: z.string().optional(),
|
|
543
|
+
})
|
|
544
|
+
.passthrough(),
|
|
545
|
+
reason: z.string().min(1).max(500),
|
|
546
|
+
occurred_at: zDate,
|
|
547
|
+
correlation_id: z.string().optional(),
|
|
548
|
+
})
|
|
549
|
+
.passthrough();
|
|
550
|
+
|
|
551
|
+
// ----- Documentos de plataforma -------------------------------------------------
|
|
552
|
+
|
|
553
|
+
// Docs globais (`IFireGlobalDoc`): sem `tenant`.
|
|
554
|
+
const zGlobalDocSchema = z.object({
|
|
555
|
+
id: z.string(),
|
|
556
|
+
ref: z.any().optional(),
|
|
557
|
+
model_ver: z.number().optional(),
|
|
558
|
+
version: z.number().optional(),
|
|
559
|
+
created_at: zDateNullable,
|
|
560
|
+
updated_at: zDateNullable,
|
|
561
|
+
deleted_at: zDateNullable,
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
/** Espelha `ITelemedicineLegalText` (standalone: `version` aqui é a versão do texto). */
|
|
565
|
+
export const zTelemedicineLegalTextSchema = z
|
|
566
|
+
.object({
|
|
567
|
+
id: z.string(),
|
|
568
|
+
subject: zConsentSubjectSchema,
|
|
569
|
+
locale: z.string().min(2).max(10),
|
|
570
|
+
version: z.string().min(1).max(40),
|
|
571
|
+
title: z.string().min(1).max(200),
|
|
572
|
+
content_html: z.string().min(1),
|
|
573
|
+
content_hash: z.string().min(1),
|
|
574
|
+
published_at: zDateNullable,
|
|
575
|
+
effective_at: zDateNullable,
|
|
576
|
+
status: zLegalTextStatusSchema,
|
|
577
|
+
placeholders: z.array(z.string().min(1).max(60)).optional(),
|
|
578
|
+
created_at: zDateNullable,
|
|
579
|
+
updated_at: zDateNullable,
|
|
580
|
+
})
|
|
581
|
+
.passthrough();
|
|
582
|
+
|
|
583
|
+
/** Espelha `ITelemedicineRollout`. Ausência do doc = deny. */
|
|
584
|
+
export const zTelemedicineRolloutSchema = zGlobalDocSchema
|
|
585
|
+
.extend({
|
|
586
|
+
create_enabled: z.boolean(),
|
|
587
|
+
join_enabled: z.boolean(),
|
|
588
|
+
recording_enabled: z.boolean(),
|
|
589
|
+
transcription_enabled: z.boolean(),
|
|
590
|
+
emergency_kill: z.boolean(),
|
|
591
|
+
updated_at: zDate,
|
|
592
|
+
updated_by: z.string().min(1),
|
|
593
|
+
})
|
|
594
|
+
.passthrough();
|
|
595
|
+
|
|
596
|
+
/** Espelha `ITelemedicineTranscriptionConfig`. */
|
|
597
|
+
export const zTelemedicineTranscriptionConfigSchema = zGlobalDocSchema
|
|
598
|
+
.extend({
|
|
599
|
+
provider: zTranscriptionProviderSchema,
|
|
600
|
+
production_gate_approved: z.boolean(),
|
|
601
|
+
approved_by: z.string().optional(),
|
|
602
|
+
approved_at: zDateNullable,
|
|
603
|
+
})
|
|
604
|
+
.passthrough();
|
|
605
|
+
|
|
606
|
+
/** Espelha `ITelemedicineGrantIndex`. */
|
|
607
|
+
export const zTelemedicineGrantIndexSchema = zGlobalDocSchema
|
|
608
|
+
.extend({
|
|
609
|
+
tenant: z.string().min(1),
|
|
610
|
+
teleconsultation_id: z.string().min(1),
|
|
611
|
+
grant_id: z.string().min(1),
|
|
612
|
+
kind: zAccessGrantKindSchema.optional(),
|
|
613
|
+
expires_at: zDate,
|
|
614
|
+
})
|
|
615
|
+
.passthrough();
|
|
616
|
+
|
|
617
|
+
// ----- Comandos (request bodies — fronteira HTTP, estritos) --------------------
|
|
618
|
+
|
|
619
|
+
const zExpectedVersion = z.number().int().min(0).optional();
|
|
620
|
+
const zReason = z.string().trim().min(1).max(500);
|
|
621
|
+
|
|
622
|
+
/** `PATCH /waiting-policy` — espelha `IWaitingPolicyCommand`. */
|
|
623
|
+
export const zWaitingPolicyCommandSchema = z
|
|
624
|
+
.object({
|
|
625
|
+
waiting_policy: zWaitingPolicySchema,
|
|
626
|
+
expected_version: zExpectedVersion,
|
|
627
|
+
})
|
|
628
|
+
.strict();
|
|
629
|
+
|
|
630
|
+
/** `POST /reassign-host` — espelha `IReassignHostCommand` (motivo obrigatório, D22). */
|
|
631
|
+
export const zReassignHostCommandSchema = z
|
|
632
|
+
.object({
|
|
633
|
+
to_user_id: z.string().trim().min(1).max(128),
|
|
634
|
+
reason: zReason,
|
|
635
|
+
expected_version: zExpectedVersion,
|
|
636
|
+
})
|
|
637
|
+
.strict();
|
|
638
|
+
|
|
639
|
+
/** `POST /access/send` — espelha `IAccessSendCommand`. */
|
|
640
|
+
export const zAccessSendCommandSchema = z
|
|
641
|
+
.object({
|
|
642
|
+
channel_kind: zAccessSendChannelKindSchema,
|
|
643
|
+
resend: z.boolean().optional(),
|
|
644
|
+
})
|
|
645
|
+
.strict();
|
|
646
|
+
|
|
647
|
+
/** `POST /access/revoke` — espelha `IAccessRevokeCommand`. */
|
|
648
|
+
export const zAccessRevokeCommandSchema = z
|
|
649
|
+
.object({
|
|
650
|
+
grant_id: z.string().trim().min(1).max(128).optional(),
|
|
651
|
+
reason: zReason,
|
|
652
|
+
})
|
|
653
|
+
.strict();
|
|
654
|
+
|
|
655
|
+
/** `POST /end` — espelha `IEndCommand`. */
|
|
656
|
+
export const zEndCommandSchema = z
|
|
657
|
+
.object({
|
|
658
|
+
reason: z.string().trim().min(1).max(120).optional(),
|
|
659
|
+
expected_version: zExpectedVersion,
|
|
660
|
+
})
|
|
661
|
+
.strict();
|
|
662
|
+
|
|
663
|
+
/** `POST /api/room/v1/exchange` — espelha `IExchangeCommand` (code base64url de 128 bits = 22 chars). */
|
|
664
|
+
export const zExchangeCommandSchema = z
|
|
665
|
+
.object({
|
|
666
|
+
code: z
|
|
667
|
+
.string()
|
|
668
|
+
.trim()
|
|
669
|
+
.min(16)
|
|
670
|
+
.max(128)
|
|
671
|
+
.regex(/^[A-Za-z0-9_-]+$/, "code must be base64url"),
|
|
672
|
+
})
|
|
673
|
+
.strict();
|
|
674
|
+
|
|
675
|
+
/** `POST /api/room/v1/identity/verify` — espelha `IIdentityVerifyCommand`. */
|
|
676
|
+
export const zIdentityVerifyCommandSchema = z
|
|
677
|
+
.object({
|
|
678
|
+
display_name: z.string().trim().min(2).max(120),
|
|
679
|
+
// Normalizada no cliente para YYYY-MM-DD; o backend normaliza de novo antes
|
|
680
|
+
// da comparação constant-time. Erro de formato NÃO revela qual campo falhou.
|
|
681
|
+
birth_date: z
|
|
682
|
+
.string()
|
|
683
|
+
.trim()
|
|
684
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/, "birth_date must be YYYY-MM-DD")
|
|
685
|
+
.optional(),
|
|
686
|
+
})
|
|
687
|
+
.strict();
|
|
688
|
+
|
|
689
|
+
/** `POST /api/room/v1/consents` — espelha `IConsentCommand` (só `accepted|declined`; retirada é rota de gravação). */
|
|
690
|
+
export const zConsentCommandSchema = z
|
|
691
|
+
.object({
|
|
692
|
+
subject: zConsentSubjectSchema,
|
|
693
|
+
terms_version: z.string().trim().min(1).max(40),
|
|
694
|
+
decision: z.enum(["accepted", "declined"]),
|
|
695
|
+
})
|
|
696
|
+
.strict();
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* `POST /api/room/v1/join` — espelha `IJoinCommand`.
|
|
700
|
+
*
|
|
701
|
+
* `.passthrough()`, não `.strict()`, ao contrário dos outros comandos: o
|
|
702
|
+
* backend hoje LÊ os dois booleanos à mão e ignora o resto, e o corpo é a
|
|
703
|
+
* intenção de mídia do preflight. Trocar por `.strict()` faria um campo novo do
|
|
704
|
+
* SPA derrubar o join inteiro em `400` — alto preço para um corpo que o
|
|
705
|
+
* servidor pode ignorar por completo.
|
|
706
|
+
*/
|
|
707
|
+
export const zJoinCommandSchema = z
|
|
708
|
+
.object({
|
|
709
|
+
audio: z.boolean().optional(),
|
|
710
|
+
video: z.boolean().optional(),
|
|
711
|
+
})
|
|
712
|
+
.passthrough();
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* `POST /api/room/v1/leave` — espelha `ILeaveCommand`.
|
|
716
|
+
*
|
|
717
|
+
* `.passthrough()` pelo mesmo motivo, agravado: este corpo chega pelo
|
|
718
|
+
* `pagehide` com `fetch(keepalive)` e é a ÚLTIMA chance de registrar a saída.
|
|
719
|
+
* Um 400 aqui é uma saída perdida, e o backend já trata corpo ausente
|
|
720
|
+
* (`reason` default `'temporary'`).
|
|
721
|
+
*/
|
|
722
|
+
export const zLeaveCommandSchema = z
|
|
723
|
+
.object({
|
|
724
|
+
reason: z.string().trim().min(1).max(60).optional(),
|
|
725
|
+
})
|
|
726
|
+
.passthrough();
|
|
727
|
+
|
|
728
|
+
/** `POST /api/room/v1/presence` — espelha `IPresenceCommand`. */
|
|
729
|
+
export const zPresenceCommandSchema = z
|
|
730
|
+
.object({
|
|
731
|
+
state: zPresenceStateSchema,
|
|
732
|
+
provider_participant_id: z.string().trim().min(1).max(128).optional(),
|
|
733
|
+
})
|
|
734
|
+
.strict();
|
|
735
|
+
|
|
736
|
+
/** `POST /api/room/v1/admit` — espelha `IAdmitCommand`. */
|
|
737
|
+
export const zAdmitCommandSchema = z
|
|
738
|
+
.object({
|
|
739
|
+
participant_id: z.string().trim().min(1).max(128),
|
|
740
|
+
})
|
|
741
|
+
.strict();
|
|
742
|
+
|
|
743
|
+
/** `POST /api/room/v1/reject` — espelha `IRejectCommand`. */
|
|
744
|
+
export const zRejectCommandSchema = z
|
|
745
|
+
.object({
|
|
746
|
+
participant_id: z.string().trim().min(1).max(128),
|
|
747
|
+
reason: z.string().trim().min(1).max(120).optional(),
|
|
748
|
+
})
|
|
749
|
+
.strict();
|
|
750
|
+
|
|
751
|
+
/** `POST /api/room/v1/recording/request` — espelha `IRecordingRequestCommand`. */
|
|
752
|
+
export const zRecordingRequestCommandSchema = z
|
|
753
|
+
.object({
|
|
754
|
+
recording_request_id: z.string().trim().min(8).max(128),
|
|
755
|
+
})
|
|
756
|
+
.strict();
|
|
757
|
+
|
|
758
|
+
/** `POST /api/room/v1/recording/accept|decline|withdraw` — espelha `IRecordingConsentCommand`. */
|
|
759
|
+
export const zRecordingConsentCommandSchema = z
|
|
760
|
+
.object({
|
|
761
|
+
recording_request_id: z.string().trim().min(8).max(128),
|
|
762
|
+
terms_version: z.string().trim().min(1).max(40),
|
|
763
|
+
})
|
|
764
|
+
.strict();
|
|
765
|
+
|
|
766
|
+
/** `POST /api/room/v1/recording/stop` — espelha `IRecordingStopCommand`. */
|
|
767
|
+
export const zRecordingStopCommandSchema = z
|
|
768
|
+
.object({
|
|
769
|
+
recording_request_id: z.string().trim().min(8).max(128).optional(),
|
|
770
|
+
})
|
|
771
|
+
.strict();
|
|
772
|
+
|
|
773
|
+
/** `POST /api/room/v1/telemetry` — espelha `ITelemetryCommand`; nomes allowlisted no backend. */
|
|
774
|
+
export const zTelemetryCommandSchema = z
|
|
775
|
+
.object({
|
|
776
|
+
events: z
|
|
777
|
+
.array(
|
|
778
|
+
z
|
|
779
|
+
.object({
|
|
780
|
+
name: z.string().trim().min(1).max(60),
|
|
781
|
+
at: z.string().datetime({ offset: true }),
|
|
782
|
+
attrs: z
|
|
783
|
+
.record(
|
|
784
|
+
z.string().min(1).max(40),
|
|
785
|
+
z.union([z.string().max(200), z.number(), z.boolean()])
|
|
786
|
+
)
|
|
787
|
+
.optional(),
|
|
788
|
+
})
|
|
789
|
+
.strict()
|
|
790
|
+
)
|
|
791
|
+
.min(1)
|
|
792
|
+
.max(50),
|
|
793
|
+
})
|
|
794
|
+
.strict();
|