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.
Files changed (58) hide show
  1. package/dist/apps/evo-crm/lead/zod-schemas.d.ts +18 -9
  2. package/dist/apps/evo-csq/zod-schemas.d.ts +12 -12
  3. package/dist/apps/evo-finops/zod-schemas.d.ts +18 -18
  4. package/dist/apps/evo-med/calendar/zod-schemas.d.ts +535 -0
  5. package/dist/apps/evo-med/calendar/zod-schemas.js +52 -1
  6. package/dist/apps/evo-med/calendar/zod-schemas.ts +55 -0
  7. package/dist/apps/evo-med/dic/zod-schemas.d.ts +2 -2
  8. package/dist/apps/evo-med/insurance/zod-schemas.d.ts +9 -0
  9. package/dist/apps/evo-med/people/zod-schemas.d.ts +63 -45
  10. package/dist/apps/evo-notifications/quick-reply-action/zod-schemas.d.ts +3 -0
  11. package/dist/apps/evo-notifications/quick-reply-action/zod-schemas.js +3 -0
  12. package/dist/apps/evo-notifications/quick-reply-action/zod-schemas.ts +3 -0
  13. package/dist/apps/evo-notifications/zod-schemas.d.ts +69 -39
  14. package/dist/apps/evo-task/zod-schemas.d.ts +69 -69
  15. package/dist/apps/evo-task/zod-schemas.js +8 -0
  16. package/dist/apps/evo-task/zod-schemas.ts +8 -0
  17. package/dist/apps/evo-telemedicine/zod-schemas.d.ts +1567 -0
  18. package/dist/apps/evo-telemedicine/zod-schemas.js +709 -0
  19. package/dist/apps/evo-telemedicine/zod-schemas.ts +794 -0
  20. package/dist/apps/evo-tenant/zod-schemas.d.ts +94 -0
  21. package/dist/apps/evo-tenant/zod-schemas.js +29 -1
  22. package/dist/apps/evo-tenant/zod-schemas.ts +32 -1
  23. package/dist/apps/hub-automation/zod-schemas.d.ts +172 -172
  24. package/dist/apps/shared/zod-schemas.d.ts +3 -0
  25. package/dist/apps/shared/zod-schemas.js +2 -0
  26. package/dist/apps/shared/zod-schemas.ts +2 -0
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.js +2 -0
  29. package/dist/index.ts +2 -0
  30. package/dist/types/evo-finops/common/contract.d.ts +8 -0
  31. package/dist/types/evo-finops/common/contract.js +7 -0
  32. package/dist/types/evo-finops/common/contract.ts +7 -0
  33. package/dist/types/evo-med/calendar/index.d.ts +104 -0
  34. package/dist/types/evo-med/calendar/index.js +66 -1
  35. package/dist/types/evo-med/calendar/index.ts +146 -0
  36. package/dist/types/evo-notifications/index.d.ts +13 -0
  37. package/dist/types/evo-notifications/index.js +6 -0
  38. package/dist/types/evo-notifications/index.ts +13 -0
  39. package/dist/types/evo-reports/index.d.ts +27 -0
  40. package/dist/types/evo-reports/index.ts +28 -0
  41. package/dist/types/evo-task/index.d.ts +1 -0
  42. package/dist/types/evo-task/index.js +8 -0
  43. package/dist/types/evo-task/index.ts +8 -0
  44. package/dist/types/evo-telemedicine/fb_collections.d.ts +16 -0
  45. package/dist/types/evo-telemedicine/fb_collections.js +38 -0
  46. package/dist/types/evo-telemedicine/fb_collections.ts +37 -0
  47. package/dist/types/evo-telemedicine/index.d.ts +1137 -0
  48. package/dist/types/evo-telemedicine/index.js +387 -0
  49. package/dist/types/evo-telemedicine/index.ts +1299 -0
  50. package/dist/types/evo-tenant/index.d.ts +45 -0
  51. package/dist/types/evo-tenant/index.js +20 -1
  52. package/dist/types/evo-tenant/index.ts +65 -0
  53. package/dist/types/shared/external-links.d.ts +6 -0
  54. package/dist/types/shared/external-links.js +6 -0
  55. package/dist/types/shared/external-links.ts +6 -0
  56. package/dist/types/shared/index.d.ts +1 -0
  57. package/dist/types/shared/index.ts +2 -0
  58. 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();