evo360-types 1.3.574 → 1.3.581

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 (47) hide show
  1. package/dist/apps/evo-chat/channel/zod-schemas.d.ts +273 -0
  2. package/dist/apps/evo-chat/channel/zod-schemas.js +17 -1
  3. package/dist/apps/evo-chat/channel/zod-schemas.ts +19 -0
  4. package/dist/apps/evo-chat/thread-message/zod-schemas.d.ts +24 -0
  5. package/dist/apps/evo-chat/thread-message/zod-schemas.js +2 -0
  6. package/dist/apps/evo-chat/thread-message/zod-schemas.ts +2 -0
  7. package/dist/apps/evo-chat/waba-template/zod-schemas.d.ts +6 -0
  8. package/dist/apps/evo-chat/waba-template/zod-schemas.js +2 -0
  9. package/dist/apps/evo-chat/waba-template/zod-schemas.ts +2 -0
  10. package/dist/apps/evo-crm/lead/zod-schemas.d.ts +9 -0
  11. package/dist/apps/evo-med/calendar/zod-schemas.d.ts +4215 -1256
  12. package/dist/apps/evo-med/calendar/zod-schemas.js +61 -1
  13. package/dist/apps/evo-med/calendar/zod-schemas.ts +64 -0
  14. package/dist/apps/evo-med/insurance/zod-schemas.d.ts +9 -0
  15. package/dist/apps/evo-med/people/zod-schemas.d.ts +18 -0
  16. package/dist/apps/evo-notifications/zod-schemas.d.ts +110 -0
  17. package/dist/apps/evo-notifications/zod-schemas.js +8 -1
  18. package/dist/apps/evo-notifications/zod-schemas.ts +9 -0
  19. package/dist/apps/evo-telemedicine/zod-schemas.d.ts +161 -13
  20. package/dist/apps/evo-telemedicine/zod-schemas.js +93 -2
  21. package/dist/apps/evo-telemedicine/zod-schemas.ts +96 -0
  22. package/dist/apps/shared/zod-schemas.d.ts +3 -0
  23. package/dist/apps/shared/zod-schemas.js +2 -0
  24. package/dist/apps/shared/zod-schemas.ts +2 -0
  25. package/dist/types/evo-chat/channel/index.d.ts +19 -0
  26. package/dist/types/evo-chat/channel/index.ts +24 -0
  27. package/dist/types/evo-chat/thread-message/index.d.ts +4 -0
  28. package/dist/types/evo-chat/thread-message/index.ts +4 -0
  29. package/dist/types/evo-chat/waba-template/index.d.ts +6 -0
  30. package/dist/types/evo-chat/waba-template/index.js +3 -1
  31. package/dist/types/evo-chat/waba-template/index.ts +7 -0
  32. package/dist/types/evo-finops/common/contract.d.ts +8 -0
  33. package/dist/types/evo-finops/common/contract.js +7 -0
  34. package/dist/types/evo-finops/common/contract.ts +7 -0
  35. package/dist/types/evo-med/calendar/index.d.ts +124 -1
  36. package/dist/types/evo-med/calendar/index.js +60 -1
  37. package/dist/types/evo-med/calendar/index.ts +167 -1
  38. package/dist/types/evo-notifications/index.d.ts +11 -0
  39. package/dist/types/evo-notifications/index.ts +13 -0
  40. package/dist/types/evo-reports/index.d.ts +27 -0
  41. package/dist/types/evo-reports/index.ts +28 -0
  42. package/dist/types/evo-telemedicine/index.d.ts +421 -6
  43. package/dist/types/evo-telemedicine/index.js +69 -1
  44. package/dist/types/evo-telemedicine/index.ts +454 -6
  45. package/dist/types/shared/index.d.ts +1 -0
  46. package/dist/types/shared/index.ts +2 -0
  47. package/package.json +1 -1
@@ -1,6 +1,9 @@
1
1
  export * from "./fb_collections";
2
2
  import type { IFireDoc, IFireGlobalDoc } from "../shared";
3
3
  import type { ITenantModuleEntitlement } from "../evo-tenant";
4
+ // feat-160 F15/F16 — a política da sala é projeção do `calendar.virtual_care`:
5
+ // o MODO de gravação é o mesmo tipo dos dois lados, de propósito.
6
+ import type { VirtualCareRecordingMode } from "../evo-med/calendar";
4
7
 
5
8
  // ======================================================
6
9
  // evo-telemedicine (feat-160 — Telemedicina integrada)
@@ -227,6 +230,18 @@ export const AccessGrantKindEnum = {
227
230
  LaunchCode: "launch_code",
228
231
  /** Sessão do browser (cookie `__session`), 15 min, rotativa. */
229
232
  BrowserSession: "browser_session",
233
+ /**
234
+ * feat-160 F7 — `kind` de uma ENTRADA A MAIS no `grant-index`, apontando
235
+ * para o MESMO grant `qr_capability`, para o link do calendário (ICS)
236
+ * resolver o caminho da teleconsulta (T56/P1).
237
+ *
238
+ * ⚠️ NENHUM grant tem este kind: `ITeleconsultationAccessGrant.kind` nunca
239
+ * vale `ics_capability`. O poder de entrar continua amarrado ao
240
+ * `secret_hash` do grant, que é o HMAC do `cap` e não do `ics_cap`. Está no
241
+ * mesmo enum porque é o `kind` do índice e o índice é endereçado pelo mesmo
242
+ * espaço de nomes — não para virar um grant.
243
+ */
244
+ IcsCapability: "ics_capability",
230
245
  } as const;
231
246
  export type AccessGrantKind = (typeof AccessGrantKindEnum)[keyof typeof AccessGrantKindEnum];
232
247
 
@@ -284,6 +299,12 @@ export const TeleconsultationEventTypeEnum = {
284
299
  /** Alteração tardia na agenda com consulta já iniciada — tratamento operacional, não apaga o encontro. */
285
300
  TeleconsultationDiverged: "teleconsultation.diverged",
286
301
  AccessCreated: "access.created",
302
+ /**
303
+ * feat-160 F13/D31 — alguém REVELOU/copiou o link do paciente no painel. Um
304
+ * evento por revelação (é o ato do usuário que fica registrado, não a
305
+ * abertura da tela). Distinto de `access.created`, que é a emissão do grant.
306
+ */
307
+ AccessLinkRevealed: "access.link_revealed",
287
308
  AccessRevoked: "access.revoked",
288
309
  AccessExchanged: "access.exchanged",
289
310
  AccessVerificationFailed: "access.verification_failed",
@@ -307,8 +328,22 @@ export const TeleconsultationEventTypeEnum = {
307
328
  RecordingConsentRequested: "recording.consent_requested",
308
329
  RecordingConsentAccepted: "recording.consent_accepted",
309
330
  RecordingConsentDeclined: "recording.consent_declined",
331
+ /**
332
+ * feat-160 F15 — o paciente RECUSOU a gravação automática ANTES de entrar.
333
+ * Não é `recording.consent_declined`: aquela é a recusa de uma solicitação
334
+ * feita em sala (a consulta segue sem gravar); esta IMPEDE a entrada, porque
335
+ * em `auto_*` o aceite é condição do join (D21).
336
+ */
337
+ RecordingConsentDeclinedPreJoin: "recording.consent_declined_pre_join",
310
338
  RecordingConsentWithdrawn: "recording.consent_withdrawn",
311
339
  RecordingStarted: "recording.started",
340
+ /**
341
+ * feat-160 F15 — gravação iniciada pela POLÍTICA da agenda (`auto_audio`/
342
+ * `auto_video`), não por comando do médico. Trilha própria porque
343
+ * `recording.started` sem um `recording.consent_requested` antes pareceria
344
+ * gravação sem solicitação na auditoria.
345
+ */
346
+ RecordingAutoStarted: "recording.auto_started",
312
347
  RecordingStopped: "recording.stopped",
313
348
  RecordingFailed: "recording.failed",
314
349
  TranscriptionQueued: "transcription.queued",
@@ -318,6 +353,15 @@ export const TeleconsultationEventTypeEnum = {
318
353
  ConsultationStarted: "consultation.started",
319
354
  ConsultationReconnecting: "consultation.reconnecting",
320
355
  ConsultationEnded: "consultation.ended",
356
+ /**
357
+ * feat-160 F18 — consulta encerrada e MEDIDA como "não contada" (paciente
358
+ * não atendeu, sem gravação elegível, franquia). Existe porque
359
+ * `usage_metered_at` é carimbado nos DOIS casos: sem este evento a
360
+ * reconciliação "quantas `ended` carimbadas × quantas linhas no BigQuery"
361
+ * acusaria diferença em toda consulta não contada, indistinguível de evento
362
+ * perdido.
363
+ */
364
+ UsageSkipped: "teleconsultation.usage_skipped",
321
365
  ArtifactAccessed: "artifact.accessed",
322
366
  ArtifactDeleted: "artifact.deleted",
323
367
  EntitlementDenied: "entitlement.denied",
@@ -408,7 +452,33 @@ export interface ITeleconsultation extends IFireDoc {
408
452
  provider_meeting_id?: string;
409
453
  active_provider_session_id?: string;
410
454
  recording_status: RecordingStatus;
455
+ /**
456
+ * Gravação — campos de OPERAÇÃO escritos por F8 e lidos pelo `GET /session`
457
+ * (feat-160). Nenhum id do provedor entra aqui: o id da gravação no
458
+ * provedor vive em `private/provider.active_provider_recording_id` (T52).
459
+ */
460
+ recording_request_id?: string;
461
+ /** Versão do texto legal `recording` referenciada na solicitação (D21). */
462
+ recording_terms_version?: string;
463
+ recording_requested_at?: Date | null;
464
+ /** `userId` do médico que solicitou. */
465
+ recording_requested_by?: string;
466
+ recording_started_at?: Date | null;
467
+ recording_stopped_at?: Date | null;
468
+ /** Código estável, sem PII, quando `recording_status === 'failed'`. */
469
+ recording_failure_code?: string | null;
470
+ /** Segmento corrente (1..n) — mais de uma sessão física = vários segmentos. */
471
+ recording_segment?: number;
411
472
  transcription_status: TranscriptionStatus;
473
+ /**
474
+ * feat-160 F10 — desmonte do meeting no provedor ainda pendente; o sweep lê e
475
+ * limpa. Escrito FORA do comando transacional de propósito: não é estado
476
+ * clínico e um `version + 1` por housekeeping faria o `expected_version` que
477
+ * o painel acabou de ler virar 409.
478
+ */
479
+ provider_teardown_pending?: boolean;
480
+ /** feat-160 F10 — até quando o metadado sensível sobrevive à retenção. */
481
+ metadata_retention_until?: Date | null;
412
482
  entitlement_snapshot: ITeleconsultationEntitlementSnapshot;
413
483
  /**
414
484
  * Geração no `appointment-index`: incrementa quando o appointment volta a ser
@@ -420,12 +490,69 @@ export interface ITeleconsultation extends IFireDoc {
420
490
  /** Última versão/data do appointment aplicada — descarta evento de reconciliação antigo. */
421
491
  last_reconciled_appointment_version?: number | string | null;
422
492
  last_reconciled_at?: Date | null;
493
+ /**
494
+ * feat-160 F18 — quando a passada de bilhetagem do sweep pode contar esta
495
+ * consulta. Carimbado por `endForAll` (`ended_at + 15 min`): o `ready` das
496
+ * gravações só chega pelo webhook DEPOIS do fim, então contar no `end`
497
+ * classificaria toda consulta gravada como "sem gravação".
498
+ */
499
+ usage_metering_due_at?: Date | null;
500
+ /**
501
+ * Quando o evento de uso foi emitido. Presente = já contada; é o que torna a
502
+ * bilhetagem idempotente no doc (a dedup em BigQuery, por `target.entityId`,
503
+ * é a segunda camada) e a trilha para reconciliar contra o BigQuery — o
504
+ * publish é best-effort e pode se perder.
505
+ */
506
+ usage_metered_at?: Date | null;
423
507
  /** Concorrência otimista: todo comando de estado é transação + `version`. */
424
508
  version: number;
425
509
  created_at: Date;
426
510
  updated_at: Date;
427
511
  }
428
512
 
513
+ /**
514
+ * `.../teleconsultations/{teleconsultationId}/private/provider` (data-model §7;
515
+ * threat model P1/T52).
516
+ *
517
+ * Tudo o que identifica o encontro NO PROVEDOR mora aqui, e só aqui: o subdoc
518
+ * `private/**` é negado a todo mundo nas rules, inclusive super admin, enquanto
519
+ * `teleconsultations/{id}` e `participants/{id}` são legíveis pelo FE com
520
+ * `evo_telemedicine_read`. Um id de provedor na mão do browser é exatamente o
521
+ * que T52 proíbe — e `runTeleconsultationCommand` LANÇA se um patch do doc
522
+ * principal carregar `provider_meeting_id`/`active_provider_session_id`, para
523
+ * que o invariante não dependa de alguém lembrar em cada PR.
524
+ */
525
+ export interface ITeleconsultationPrivateProvider {
526
+ readonly id: string;
527
+ tenant: string;
528
+ teleconsultation_id: string;
529
+ provider: TeleconsultationProvider;
530
+ /** Id do meeting no provider — nunca sai deste doc para o FE nem para o SPA. */
531
+ provider_meeting_id?: string;
532
+ active_provider_session_id?: string;
533
+ /** Sessões físicas já vistas (mais de uma = segmentos do mesmo encontro). */
534
+ provider_session_ids?: string[];
535
+ /** Id do participante no provider, por id LÓGICO (`doctor`/`patient`). */
536
+ provider_participant_ids?: Record<string, string>;
537
+ /**
538
+ * Gravação ativa no provedor. O artefato guarda o mesmo valor em
539
+ * `provider_artifact_id` (é por ele que o webhook casa), mas o `stop` precisa
540
+ * do id sem depender de qual segmento é o corrente.
541
+ */
542
+ active_provider_recording_id?: string | null;
543
+ created_at?: Date | null;
544
+ updated_at?: Date | null;
545
+ }
546
+
547
+ /**
548
+ * Campos que o doc PRINCIPAL da teleconsulta jamais carrega — a asserção do
549
+ * `runTeleconsultationCommand` e do teste de sanidade itera esta lista.
550
+ */
551
+ export const TELECONSULTATION_PROVIDER_ONLY_FIELDS = [
552
+ "provider_meeting_id",
553
+ "active_provider_session_id",
554
+ ] as const;
555
+
429
556
  /** `.../participants/{participantId}` (data-model §2). Id lógico estável; reconexão reutiliza o mesmo participante. */
430
557
  export interface ITeleconsultationParticipant extends IFireDoc {
431
558
  teleconsultation_id: string;
@@ -491,6 +618,11 @@ export interface ITeleconsultationArtifact extends IFireDoc {
491
618
  ended_at?: Date | null;
492
619
  /** Retenção: o sweep deleta o objeto e só então marca `deleted` (auditoria preservada). */
493
620
  expires_at?: Date | null;
621
+ /**
622
+ * feat-160 F10 — quando o CONTEÚDO foi apagado. O doc sobrevive (status
623
+ * `deleted`) porque a auditoria da deleção é preservada (D13).
624
+ */
625
+ deleted_at?: Date | null;
494
626
  error_code?: string;
495
627
  created_at: Date;
496
628
  updated_at: Date;
@@ -582,6 +714,21 @@ export interface ITelemedicineAppointmentIndex extends IFireDoc {
582
714
  active_teleconsultation_id: string | null;
583
715
  generation: number;
584
716
  last_reconciled_appointment_version?: number | string | null;
717
+ /**
718
+ * feat-160 F3 — instante do write do appointment já aplicado. A marca d'água
719
+ * mora AQUI, e não só na teleconsulta, porque o índice sobrevive ao que ela
720
+ * precisa cobrir: um `denied` não cria doc nenhum e um terminal deixa de ser
721
+ * a teleconsulta ativa. Sem isto, um evento antigo redelivered depois de um
722
+ * `denied` seria reavaliado como novo.
723
+ */
724
+ last_reconciled_at?: Date | null;
725
+ /**
726
+ * Última teleconsulta deste appointment, ativa ou não. Gravada quando o
727
+ * índice é liberado (terminal) para o painel continuar mostrando a
728
+ * teleconsulta expirada/encerrada em vez de "não tem teleconsulta". NÃO é
729
+ * fonte de verdade de ativo — isso é `active_teleconsultation_id`.
730
+ */
731
+ last_teleconsultation_id?: string | null;
585
732
  updated_at: Date;
586
733
  }
587
734
 
@@ -638,6 +785,12 @@ export interface ITelemedicineGrantIndex extends IFireGlobalDoc {
638
785
  tenant: string;
639
786
  teleconsultation_id: string;
640
787
  grant_id: string;
788
+ /**
789
+ * Qual segredo esta entrada resolve. Ausente = a capability do `/qr`
790
+ * (comportamento original); `ics_capability` = o segredo derivado do link do
791
+ * calendário, que aponta para o MESMO grant `qr_capability` (F7).
792
+ */
793
+ kind?: AccessGrantKind;
641
794
  /** TTL nativo. */
642
795
  expires_at: Date;
643
796
  }
@@ -822,6 +975,76 @@ export interface IRoomConsentRefDto {
822
975
  terms_version: string;
823
976
  }
824
977
 
978
+ /**
979
+ * Projeção SANITIZADA do estado de gravação no `GET /session` (feat-160 F8).
980
+ * Nunca traz id do provider, path do objeto no GCS nem URL assinada — só o que
981
+ * a UI dos dois papéis precisa.
982
+ */
983
+ export interface IRoomRecordingStateDto {
984
+ /** Mesma origem do `recording_status` do DTO da sessão. */
985
+ status: RecordingStatus;
986
+ /** Início do segmento ativo — única origem do cronômetro; `null` fora de gravação. */
987
+ started_at: string | null;
988
+ /** Idempotência do comando e vínculo do consentimento (T19). */
989
+ recording_request_id?: string;
990
+ /** Versão do texto legal `recording` referenciada na solicitação (D21). */
991
+ terms_version?: string;
992
+ /** Código estável, sem PII, quando `status === 'failed'`. */
993
+ failure_code?: string;
994
+ /** feat-160 F15 — presente só nos modos `auto_*` (aviso pré-join). */
995
+ auto?: IRoomRecordingAutoDto;
996
+ }
997
+
998
+ /**
999
+ * feat-160 F15 — aviso PRÉ-JOIN da gravação automática (`auto_audio`/
1000
+ * `auto_video`). Presente só nesses modos: é o que o SPA usa para explicar o
1001
+ * que vai ser gravado e por quanto tempo ANTES do aceite.
1002
+ */
1003
+ export interface IRoomRecordingAutoDto {
1004
+ /** `auto_audio` ou `auto_video`; os outros modos não têm este bloco. */
1005
+ mode: VirtualCareRecordingMode;
1006
+ /**
1007
+ * `true` em `auto_audio`. Hoje é INTENÇÃO declarada: o `POST /recordings` do
1008
+ * provedor não expõe flag de áudio-only, então o arquivo sai A/V. O SPA usa o
1009
+ * campo para o texto do aviso; quando o provedor ganhar a flag, só o adapter
1010
+ * muda.
1011
+ */
1012
+ audio_only: boolean;
1013
+ /** Retenção que o texto mostrado ao paciente promete (`{{retention}}`, D32). */
1014
+ retention_days: number;
1015
+ /**
1016
+ * Versão vigente do texto `recording` que o `POST /consents` tem de
1017
+ * referenciar. `null` = não há texto publicado ⇒ sem aceite possível (D21) e
1018
+ * a gravação automática NÃO acontece.
1019
+ */
1020
+ terms_version: string | null;
1021
+ }
1022
+
1023
+ /**
1024
+ * feat-160 F16 — política EFETIVA da agenda nesta sessão (`virtual_care` já
1025
+ * com os defaults aplicados). É projeção de decisão, não de config gravada:
1026
+ * agenda sem o bloco devolve os defaults.
1027
+ */
1028
+ export interface IRoomSessionPolicyDto {
1029
+ recording_mode: VirtualCareRecordingMode;
1030
+ auto_admit: boolean;
1031
+ identity: {
1032
+ require_name: boolean;
1033
+ require_birth_date: boolean;
1034
+ skip: boolean;
1035
+ };
1036
+ /**
1037
+ * Prazo duro da consulta. `end_at`/`warning_at` são `null` quando não há
1038
+ * prazo (consulta não iniciada com `allow_late_end`), e `reason` diz qual
1039
+ * limite venceu — o MESMO `reason` com que o sweep encerra.
1040
+ */
1041
+ deadline: {
1042
+ end_at: string | null;
1043
+ warning_at: string | null;
1044
+ reason: "scheduled_end" | "max_duration" | null;
1045
+ };
1046
+ }
1047
+
825
1048
  /**
826
1049
  * `GET /api/room/v1/session` — estado SANITIZADO: sem tenant id, sem ids do
827
1050
  * provider; nome do profissional/clínica só depois da verificação.
@@ -838,13 +1061,59 @@ export interface IRoomSessionDto {
838
1061
  identity_level: IdentityLevel;
839
1062
  /** Paciente precisa passar por `POST /identity/verify` antes do join. */
840
1063
  identity_required: boolean;
1064
+ /**
1065
+ * Quais campos o formulário de identidade deve pedir (spec §8.3): a data de
1066
+ * nascimento só é pedida quando EXISTE no cadastro. Para o médico vem sempre
1067
+ * `{ birth_date: false }`.
1068
+ */
1069
+ identity_required_fields: {
1070
+ birth_date: boolean;
1071
+ /**
1072
+ * feat-160 F16 — `virtual_care.identity.require_name`: a agenda pode exigir
1073
+ * o nome também. OPCIONAL no contrato porque SPA anterior à F16 não o
1074
+ * conhece e deve seguir pedindo só a data (comportamento de antes).
1075
+ */
1076
+ name?: boolean;
1077
+ };
1078
+ /**
1079
+ * Contador do lockout, lido do GRANT raiz — e a ÚNICA fonte dele: o erro do
1080
+ * `POST /identity/verify` é neutro e não devolve tentativas nem prazo. Por
1081
+ * isso a UI relê a sessão depois de cada falha.
1082
+ */
1083
+ identity_attempts: { remaining: number; blocked_until: string | null };
841
1084
  recording_status: RecordingStatus;
1085
+ recording: IRoomRecordingStateDto;
1086
+ /**
1087
+ * feat-160 F16 — o que a AGENDA decidiu (`calendar.virtual_care` resolvido
1088
+ * com os defaults). OPCIONAL: aditivo, SPA que não o conheça mantém o
1089
+ * comportamento pré-F16.
1090
+ */
1091
+ policy?: IRoomSessionPolicyDto;
842
1092
  transcription_status: TranscriptionStatus;
843
1093
  /** Textos vigentes que ainda precisam de aceite antes do join. */
844
1094
  required_consents: IRoomConsentRefDto[];
845
1095
  accepted_consents: IRoomConsentRefDto[];
846
1096
  /** Capabilities efetivas para esta sessão (entitlement AND rollout AND papel). */
847
1097
  capabilities: Record<string, boolean>;
1098
+ /** Presença do médico; `null` quando não há participante. Atalho de `participants`. */
1099
+ doctor_presence: ParticipantState | null;
1100
+ /** Presença do paciente. Atalho de `participants`. */
1101
+ patient_presence: ParticipantState | null;
1102
+ /** Os dois papéis, com `state`/`disconnected_at`/`reconnect_count`. */
1103
+ participants: ITeleconsultationParticipantDto[];
1104
+ /**
1105
+ * Pacientes em `state === 'waiting'`, e a ponte OBRIGATÓRIA do `POST /admit`:
1106
+ * o `participant_id` de domínio é o literal `'patient'`, enquanto o
1107
+ * `custom_participant_id` devolvido no `POST /join` é hash opaco que nunca
1108
+ * casaria com ele.
1109
+ */
1110
+ waiting_participants: ITeleconsultationParticipantDto[];
1111
+ /**
1112
+ * Máscara "Maria A. d. S." do titular do agendamento. SÓ na sessão do
1113
+ * MÉDICO — o backend nunca a manda ao paciente (T01), e é por isso que é o
1114
+ * único destes campos legitimamente opcional.
1115
+ */
1116
+ patient_display_masked?: string;
848
1117
  professional_display_name?: string;
849
1118
  clinic_display_name?: string;
850
1119
  /** Expiração do access da sessão (15 min, rotativo via `/session/refresh`). */
@@ -890,11 +1159,114 @@ export interface ITeleconsultationArtifactDto {
890
1159
  created_at: string;
891
1160
  }
892
1161
 
1162
+ /**
1163
+ * Modo da URL assinada de um artefato (feat-160 F21; D34).
1164
+ *
1165
+ * `attachment` é o default histórico (F8): o navegador BAIXA o arquivo.
1166
+ * `inline` existe para o `<video>` do painel fazer streaming por `Range` sem
1167
+ * baixar — e a única diferença técnica é NÃO emitir `Content-Disposition`.
1168
+ */
1169
+ export const ArtifactDispositionEnum = {
1170
+ Inline: "inline",
1171
+ Attachment: "attachment",
1172
+ } as const;
1173
+ export type ArtifactDisposition =
1174
+ (typeof ArtifactDispositionEnum)[keyof typeof ArtifactDispositionEnum];
1175
+
1176
+ /**
1177
+ * Teto de validade da URL `inline` (feat-160 F21): 15 min. Playback casa com a
1178
+ * duração de uma consulta; download curto casa com o clique. É TETO, não
1179
+ * default — o use case aplica, e o adapter recusa acima dele.
1180
+ */
1181
+ export const ARTIFACT_INLINE_SIGNED_URL_MAX_SECONDS = 900;
1182
+
893
1183
  /** `POST /v1/teleconsultations/:id/artifacts/:artifactId/signed-url` — URL ≤ 5 min; evento `artifact.accessed`. */
894
1184
  export interface ISignedUrlResponseDto {
895
1185
  ok: true;
896
1186
  url: string;
897
1187
  expires_at: string;
1188
+ /** Modo efetivamente aplicado (`attachment` quando o comando omite). */
1189
+ disposition?: ArtifactDisposition;
1190
+ }
1191
+
1192
+ // ----- Transcrição servida ao painel (feat-160 F21 §9.1 b)
1193
+ //
1194
+ // O texto NUNCA vive em doc do Firestore (threat model): a rota lê o objeto do
1195
+ // bucket e devolve ESTE DTO. Tempos em MILISSEGUNDOS porque o player faz
1196
+ // `seekTo` e o `mm:ss` da bolha vem de arredondamento — dois consumidores do
1197
+ // mesmo número, e um `0.1 + 0.2` no meio é ruído garantido.
1198
+
1199
+ export type TranscriptSpeakerRole = "doctor" | "patient" | "unknown";
1200
+
1201
+ export interface ITranscriptSpeakerDto {
1202
+ /** `opaque_custom_participant_id` que amarra a fala ao papel. */
1203
+ key: string;
1204
+ display_name: string;
1205
+ role: TranscriptSpeakerRole;
1206
+ }
1207
+
1208
+ export interface ITranscriptEntryDto {
1209
+ index: number;
1210
+ speaker_key: string;
1211
+ start_ms: number;
1212
+ end_ms: number;
1213
+ text: string;
1214
+ overlapping?: boolean;
1215
+ }
1216
+
1217
+ /** Corpo da transcrição de UM artefato (`segment`). */
1218
+ export interface ITranscriptDto {
1219
+ artifact_id: string;
1220
+ segment: number;
1221
+ language?: string;
1222
+ generated_at?: string;
1223
+ speakers: ITranscriptSpeakerDto[];
1224
+ entries: ITranscriptEntryDto[];
1225
+ }
1226
+
1227
+ /**
1228
+ * `GET /v1/teleconsultations/:id/artifacts/:artifactId/transcript` — envelope
1229
+ * da rota: `{ ok: true, ...ITranscriptDto }` (o DTO é espalhado, não aninhado).
1230
+ */
1231
+ export interface ITranscriptResponseDto extends ITranscriptDto {
1232
+ ok: true;
1233
+ }
1234
+
1235
+ // ----- Badges da lista de agendamentos (feat-160 F21 §9.1 d)
1236
+
1237
+ /**
1238
+ * Um agendamento que TEM teleconsulta, e o que ela produziu. Id ausente do mapa
1239
+ * = "nunca virou teleconsulta" — é essa diferença que impede a tela de
1240
+ * desenhar três ícones apagados em toda linha comum.
1241
+ */
1242
+ export interface ITeleconsultationBadgeDto {
1243
+ teleconsultation_id: string;
1244
+ status: TeleconsultationStatus;
1245
+ recording_audio: boolean;
1246
+ recording_video: boolean;
1247
+ transcript: boolean;
1248
+ }
1249
+
1250
+ /** `GET /v1/appointments/teleconsultation-badges?ids=a,b,c` (máx. 50 ids). */
1251
+ export interface ITeleconsultationBadgesResponseDto {
1252
+ ok: true;
1253
+ /** Keyed por `appointment_id`. */
1254
+ items: Record<string, ITeleconsultationBadgeDto>;
1255
+ }
1256
+
1257
+ /** Teto de ids por chamada; acima disso a rota responde 400. */
1258
+ export const TELECONSULTATION_BADGES_MAX_IDS = 50;
1259
+
1260
+ /**
1261
+ * Corpo do `POST …/artifacts/:artifactId/signed-url` (feat-160 F21). O zod
1262
+ * espelho é `zArtifactSignedUrlCommandSchema`.
1263
+ */
1264
+ export interface IArtifactSignedUrlCommand {
1265
+ disposition?: ArtifactDisposition;
1266
+ /** 30..900; o teto REAL depende do modo e é aplicado pelo backend. */
1267
+ ttl_seconds?: number;
1268
+ /** Renova a URL de um artefato já acessado (evento `artifact.accessed`). */
1269
+ refresh?: boolean;
898
1270
  }
899
1271
 
900
1272
  export interface ITeleconsultationEventDto {
@@ -925,6 +1297,13 @@ export interface ITelemedicineLegalTextDto {
925
1297
  content_html: string;
926
1298
  content_hash: string;
927
1299
  effective_at?: string | null;
1300
+ /**
1301
+ * VALORES dos placeholders já resolvidos e filtrados pela allowlist do
1302
+ * próprio doc (`ITelemedicineLegalText.placeholders`, que guarda os NOMES
1303
+ * permitidos). ux-flows §3 exige "usada para {finalidade} e ficará
1304
+ * disponível por {prazo}", e D21 proíbe hardcode disso no bundle.
1305
+ */
1306
+ placeholders?: Record<string, string>;
928
1307
  }
929
1308
 
930
1309
  /** `GET /api/room/v1/legal-texts`. */
@@ -939,17 +1318,64 @@ export interface IIdentityVerifyResponseDto {
939
1318
  identity_level: IdentityLevel;
940
1319
  }
941
1320
 
942
- /** `POST /v1/teleconsultations/:id/access/send`. */
1321
+ /**
1322
+ * `POST /api/room/v1/exchange` e `POST /api/room/v1/session/refresh`.
1323
+ *
1324
+ * O corpo NÃO repete o `sid` (está no cookie `__session`, `HttpOnly`,
1325
+ * `Path=/api`) nem o tenant; traz o papel, que é o que permite ao SPA escolher
1326
+ * a tela sem um `GET /session` extra.
1327
+ */
1328
+ export interface IExchangeResponseDto {
1329
+ ok: true;
1330
+ role: ParticipantRole;
1331
+ session_expires_at: string;
1332
+ }
1333
+
1334
+ /** `POST /api/room/v1/participant-token/refresh` — token novo, MESMO participante lógico. */
1335
+ export interface IParticipantTokenRefreshDto {
1336
+ ok: true;
1337
+ provider_token: string;
1338
+ /** Nome do preset no provider (`hm_doctor`, `hm_patient_waiting`, ...). */
1339
+ preset: string;
1340
+ token_expires_at?: string;
1341
+ }
1342
+
1343
+ /**
1344
+ * `POST /v1/teleconsultations/:id/access/send` (feat-160 F7).
1345
+ *
1346
+ * É RECIBO DE TASK, não confirmação de envio: a rota publica a mesma task fina
1347
+ * que a rotina publicaria (`telemedicine_join_reminder`) e responde antes de
1348
+ * existir grant — o executor é quem resolve template, canal e elegibilidade e
1349
+ * emite a capability, uma por perna do fan-out. Por isso NÃO há `grant_id` nem
1350
+ * `expires_at` aqui: forjá-los era mentir para a recepção sobre um acesso que
1351
+ * ainda não existia.
1352
+ */
943
1353
  export interface IAccessSendResponseDto {
944
1354
  ok: true;
945
- grant_id: string;
1355
+ task_id: string;
1356
+ /** `true` quando a chave de idempotência colapsou num envio já pedido. */
1357
+ reused: boolean;
946
1358
  channel_kind: AccessSendChannelKind;
1359
+ /** Eco do pedido: revogar a capability anterior antes de emitir a nova. */
1360
+ resend: boolean;
1361
+ /** Destinatário mascarado do canal pedido; ausente em `manual`. */
947
1362
  recipient_masked?: string;
1363
+ }
1364
+
1365
+ /**
1366
+ * `POST /v1/teleconsultations/:id/access/link` (feat-160 F13; D31).
1367
+ *
1368
+ * **A `url` é CREDENCIAL** (capability de 128 bits do `/qr`), não um
1369
+ * identificador: não tem lugar em store, log, analytics nem storage do
1370
+ * navegador (T01/T04). Nasce nesta resposta, vai para a área de transferência e
1371
+ * morre com o diálogo. Cada revelação é uma chamada nova, de propósito — o que
1372
+ * fica registrado em `access.link_revealed` é o ato do usuário.
1373
+ */
1374
+ export interface IAccessLinkResultDto {
1375
+ ok: true;
1376
+ url: string;
1377
+ grant_id: string;
948
1378
  expires_at: string;
949
- /** Só para `channel_kind = manual` (smoke): URL mascarada, nunca a capability inteira. */
950
- url_masked?: string;
951
- /** Id da task `telemedicine_join.send` criada, quando houver canal. */
952
- task_id?: string;
953
1379
  }
954
1380
 
955
1381
  // ======================================================
@@ -1002,6 +1428,28 @@ export interface IConsentCommand {
1002
1428
  decision: Extract<ConsentDecision, "accepted" | "declined">;
1003
1429
  }
1004
1430
 
1431
+ /**
1432
+ * `POST /api/room/v1/join` — intenção de mídia do preflight ("Entrar somente
1433
+ * com áudio"). Os dois campos são opcionais porque o backend só os REGISTRA
1434
+ * (escolha de preset e `audio_only_allowed`) e ignora o que não vier.
1435
+ */
1436
+ export interface IJoinCommand {
1437
+ audio?: boolean;
1438
+ video?: boolean;
1439
+ }
1440
+
1441
+ /**
1442
+ * `POST /api/room/v1/leave` — saída TEMPORÁRIA (D10); nunca encerra a consulta.
1443
+ *
1444
+ * `reason` é string aberta e o backend só distingue UM valor: `'temporary'` é
1445
+ * saída explícita (`left`), qualquer outro é tratado como queda de rede
1446
+ * (`disconnected`). Ausente = `'temporary'`. Chega pelo `pagehide` com
1447
+ * `fetch(keepalive)`, então pode vir sem `Content-Type`.
1448
+ */
1449
+ export interface ILeaveCommand {
1450
+ reason?: string;
1451
+ }
1452
+
1005
1453
  /** `POST /api/room/v1/presence`. */
1006
1454
  export interface IPresenceCommand {
1007
1455
  state: PresenceState;
@@ -32,6 +32,7 @@ export interface IContact {
32
32
  type?: string | null;
33
33
  instagram?: string | null;
34
34
  instagram_username?: string | null;
35
+ bsuid?: string | null;
35
36
  }
36
37
  export interface IAddress {
37
38
  name?: string;
@@ -43,6 +43,8 @@ export interface IContact {
43
43
  type?: string | null;
44
44
  instagram?: string | null;
45
45
  instagram_username?: string | null;
46
+ // WhatsApp BSUID (Business-Scoped User ID) — contato que a Meta entrega sem telefone
47
+ bsuid?: string | null;
46
48
  }
47
49
  export interface IAddress {
48
50
  name?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evo360-types",
3
- "version": "1.3.574",
3
+ "version": "1.3.581",
4
4
  "description": "HREVO360 Shared Types",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",