evo360-types 1.3.574 → 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.
@@ -227,6 +227,18 @@ export const AccessGrantKindEnum = {
227
227
  LaunchCode: "launch_code",
228
228
  /** Sessão do browser (cookie `__session`), 15 min, rotativa. */
229
229
  BrowserSession: "browser_session",
230
+ /**
231
+ * feat-160 F7 — `kind` de uma ENTRADA A MAIS no `grant-index`, apontando
232
+ * para o MESMO grant `qr_capability`, para o link do calendário (ICS)
233
+ * resolver o caminho da teleconsulta (T56/P1).
234
+ *
235
+ * ⚠️ NENHUM grant tem este kind: `ITeleconsultationAccessGrant.kind` nunca
236
+ * vale `ics_capability`. O poder de entrar continua amarrado ao
237
+ * `secret_hash` do grant, que é o HMAC do `cap` e não do `ics_cap`. Está no
238
+ * mesmo enum porque é o `kind` do índice e o índice é endereçado pelo mesmo
239
+ * espaço de nomes — não para virar um grant.
240
+ */
241
+ IcsCapability: "ics_capability",
230
242
  } as const;
231
243
  export type AccessGrantKind = (typeof AccessGrantKindEnum)[keyof typeof AccessGrantKindEnum];
232
244
 
@@ -284,6 +296,12 @@ export const TeleconsultationEventTypeEnum = {
284
296
  /** Alteração tardia na agenda com consulta já iniciada — tratamento operacional, não apaga o encontro. */
285
297
  TeleconsultationDiverged: "teleconsultation.diverged",
286
298
  AccessCreated: "access.created",
299
+ /**
300
+ * feat-160 F13/D31 — alguém REVELOU/copiou o link do paciente no painel. Um
301
+ * evento por revelação (é o ato do usuário que fica registrado, não a
302
+ * abertura da tela). Distinto de `access.created`, que é a emissão do grant.
303
+ */
304
+ AccessLinkRevealed: "access.link_revealed",
287
305
  AccessRevoked: "access.revoked",
288
306
  AccessExchanged: "access.exchanged",
289
307
  AccessVerificationFailed: "access.verification_failed",
@@ -408,7 +426,33 @@ export interface ITeleconsultation extends IFireDoc {
408
426
  provider_meeting_id?: string;
409
427
  active_provider_session_id?: string;
410
428
  recording_status: RecordingStatus;
429
+ /**
430
+ * Gravação — campos de OPERAÇÃO escritos por F8 e lidos pelo `GET /session`
431
+ * (feat-160). Nenhum id do provedor entra aqui: o id da gravação no
432
+ * provedor vive em `private/provider.active_provider_recording_id` (T52).
433
+ */
434
+ recording_request_id?: string;
435
+ /** Versão do texto legal `recording` referenciada na solicitação (D21). */
436
+ recording_terms_version?: string;
437
+ recording_requested_at?: Date | null;
438
+ /** `userId` do médico que solicitou. */
439
+ recording_requested_by?: string;
440
+ recording_started_at?: Date | null;
441
+ recording_stopped_at?: Date | null;
442
+ /** Código estável, sem PII, quando `recording_status === 'failed'`. */
443
+ recording_failure_code?: string | null;
444
+ /** Segmento corrente (1..n) — mais de uma sessão física = vários segmentos. */
445
+ recording_segment?: number;
411
446
  transcription_status: TranscriptionStatus;
447
+ /**
448
+ * feat-160 F10 — desmonte do meeting no provedor ainda pendente; o sweep lê e
449
+ * limpa. Escrito FORA do comando transacional de propósito: não é estado
450
+ * clínico e um `version + 1` por housekeeping faria o `expected_version` que
451
+ * o painel acabou de ler virar 409.
452
+ */
453
+ provider_teardown_pending?: boolean;
454
+ /** feat-160 F10 — até quando o metadado sensível sobrevive à retenção. */
455
+ metadata_retention_until?: Date | null;
412
456
  entitlement_snapshot: ITeleconsultationEntitlementSnapshot;
413
457
  /**
414
458
  * Geração no `appointment-index`: incrementa quando o appointment volta a ser
@@ -420,12 +464,69 @@ export interface ITeleconsultation extends IFireDoc {
420
464
  /** Última versão/data do appointment aplicada — descarta evento de reconciliação antigo. */
421
465
  last_reconciled_appointment_version?: number | string | null;
422
466
  last_reconciled_at?: Date | null;
467
+ /**
468
+ * feat-160 F18 — quando a passada de bilhetagem do sweep pode contar esta
469
+ * consulta. Carimbado por `endForAll` (`ended_at + 15 min`): o `ready` das
470
+ * gravações só chega pelo webhook DEPOIS do fim, então contar no `end`
471
+ * classificaria toda consulta gravada como "sem gravação".
472
+ */
473
+ usage_metering_due_at?: Date | null;
474
+ /**
475
+ * Quando o evento de uso foi emitido. Presente = já contada; é o que torna a
476
+ * bilhetagem idempotente no doc (a dedup em BigQuery, por `target.entityId`,
477
+ * é a segunda camada) e a trilha para reconciliar contra o BigQuery — o
478
+ * publish é best-effort e pode se perder.
479
+ */
480
+ usage_metered_at?: Date | null;
423
481
  /** Concorrência otimista: todo comando de estado é transação + `version`. */
424
482
  version: number;
425
483
  created_at: Date;
426
484
  updated_at: Date;
427
485
  }
428
486
 
487
+ /**
488
+ * `.../teleconsultations/{teleconsultationId}/private/provider` (data-model §7;
489
+ * threat model P1/T52).
490
+ *
491
+ * Tudo o que identifica o encontro NO PROVEDOR mora aqui, e só aqui: o subdoc
492
+ * `private/**` é negado a todo mundo nas rules, inclusive super admin, enquanto
493
+ * `teleconsultations/{id}` e `participants/{id}` são legíveis pelo FE com
494
+ * `evo_telemedicine_read`. Um id de provedor na mão do browser é exatamente o
495
+ * que T52 proíbe — e `runTeleconsultationCommand` LANÇA se um patch do doc
496
+ * principal carregar `provider_meeting_id`/`active_provider_session_id`, para
497
+ * que o invariante não dependa de alguém lembrar em cada PR.
498
+ */
499
+ export interface ITeleconsultationPrivateProvider {
500
+ readonly id: string;
501
+ tenant: string;
502
+ teleconsultation_id: string;
503
+ provider: TeleconsultationProvider;
504
+ /** Id do meeting no provider — nunca sai deste doc para o FE nem para o SPA. */
505
+ provider_meeting_id?: string;
506
+ active_provider_session_id?: string;
507
+ /** Sessões físicas já vistas (mais de uma = segmentos do mesmo encontro). */
508
+ provider_session_ids?: string[];
509
+ /** Id do participante no provider, por id LÓGICO (`doctor`/`patient`). */
510
+ provider_participant_ids?: Record<string, string>;
511
+ /**
512
+ * Gravação ativa no provedor. O artefato guarda o mesmo valor em
513
+ * `provider_artifact_id` (é por ele que o webhook casa), mas o `stop` precisa
514
+ * do id sem depender de qual segmento é o corrente.
515
+ */
516
+ active_provider_recording_id?: string | null;
517
+ created_at?: Date | null;
518
+ updated_at?: Date | null;
519
+ }
520
+
521
+ /**
522
+ * Campos que o doc PRINCIPAL da teleconsulta jamais carrega — a asserção do
523
+ * `runTeleconsultationCommand` e do teste de sanidade itera esta lista.
524
+ */
525
+ export const TELECONSULTATION_PROVIDER_ONLY_FIELDS = [
526
+ "provider_meeting_id",
527
+ "active_provider_session_id",
528
+ ] as const;
529
+
429
530
  /** `.../participants/{participantId}` (data-model §2). Id lógico estável; reconexão reutiliza o mesmo participante. */
430
531
  export interface ITeleconsultationParticipant extends IFireDoc {
431
532
  teleconsultation_id: string;
@@ -491,6 +592,11 @@ export interface ITeleconsultationArtifact extends IFireDoc {
491
592
  ended_at?: Date | null;
492
593
  /** Retenção: o sweep deleta o objeto e só então marca `deleted` (auditoria preservada). */
493
594
  expires_at?: Date | null;
595
+ /**
596
+ * feat-160 F10 — quando o CONTEÚDO foi apagado. O doc sobrevive (status
597
+ * `deleted`) porque a auditoria da deleção é preservada (D13).
598
+ */
599
+ deleted_at?: Date | null;
494
600
  error_code?: string;
495
601
  created_at: Date;
496
602
  updated_at: Date;
@@ -582,6 +688,21 @@ export interface ITelemedicineAppointmentIndex extends IFireDoc {
582
688
  active_teleconsultation_id: string | null;
583
689
  generation: number;
584
690
  last_reconciled_appointment_version?: number | string | null;
691
+ /**
692
+ * feat-160 F3 — instante do write do appointment já aplicado. A marca d'água
693
+ * mora AQUI, e não só na teleconsulta, porque o índice sobrevive ao que ela
694
+ * precisa cobrir: um `denied` não cria doc nenhum e um terminal deixa de ser
695
+ * a teleconsulta ativa. Sem isto, um evento antigo redelivered depois de um
696
+ * `denied` seria reavaliado como novo.
697
+ */
698
+ last_reconciled_at?: Date | null;
699
+ /**
700
+ * Última teleconsulta deste appointment, ativa ou não. Gravada quando o
701
+ * índice é liberado (terminal) para o painel continuar mostrando a
702
+ * teleconsulta expirada/encerrada em vez de "não tem teleconsulta". NÃO é
703
+ * fonte de verdade de ativo — isso é `active_teleconsultation_id`.
704
+ */
705
+ last_teleconsultation_id?: string | null;
585
706
  updated_at: Date;
586
707
  }
587
708
 
@@ -638,6 +759,12 @@ export interface ITelemedicineGrantIndex extends IFireGlobalDoc {
638
759
  tenant: string;
639
760
  teleconsultation_id: string;
640
761
  grant_id: string;
762
+ /**
763
+ * Qual segredo esta entrada resolve. Ausente = a capability do `/qr`
764
+ * (comportamento original); `ics_capability` = o segredo derivado do link do
765
+ * calendário, que aponta para o MESMO grant `qr_capability` (F7).
766
+ */
767
+ kind?: AccessGrantKind;
641
768
  /** TTL nativo. */
642
769
  expires_at: Date;
643
770
  }
@@ -822,6 +949,24 @@ export interface IRoomConsentRefDto {
822
949
  terms_version: string;
823
950
  }
824
951
 
952
+ /**
953
+ * Projeção SANITIZADA do estado de gravação no `GET /session` (feat-160 F8).
954
+ * Nunca traz id do provider, path do objeto no GCS nem URL assinada — só o que
955
+ * a UI dos dois papéis precisa.
956
+ */
957
+ export interface IRoomRecordingStateDto {
958
+ /** Mesma origem do `recording_status` do DTO da sessão. */
959
+ status: RecordingStatus;
960
+ /** Início do segmento ativo — única origem do cronômetro; `null` fora de gravação. */
961
+ started_at: string | null;
962
+ /** Idempotência do comando e vínculo do consentimento (T19). */
963
+ recording_request_id?: string;
964
+ /** Versão do texto legal `recording` referenciada na solicitação (D21). */
965
+ terms_version?: string;
966
+ /** Código estável, sem PII, quando `status === 'failed'`. */
967
+ failure_code?: string;
968
+ }
969
+
825
970
  /**
826
971
  * `GET /api/room/v1/session` — estado SANITIZADO: sem tenant id, sem ids do
827
972
  * provider; nome do profissional/clínica só depois da verificação.
@@ -838,13 +983,45 @@ export interface IRoomSessionDto {
838
983
  identity_level: IdentityLevel;
839
984
  /** Paciente precisa passar por `POST /identity/verify` antes do join. */
840
985
  identity_required: boolean;
986
+ /**
987
+ * Quais campos o formulário de identidade deve pedir (spec §8.3): a data de
988
+ * nascimento só é pedida quando EXISTE no cadastro. Para o médico vem sempre
989
+ * `{ birth_date: false }`.
990
+ */
991
+ identity_required_fields: { birth_date: boolean };
992
+ /**
993
+ * Contador do lockout, lido do GRANT raiz — e a ÚNICA fonte dele: o erro do
994
+ * `POST /identity/verify` é neutro e não devolve tentativas nem prazo. Por
995
+ * isso a UI relê a sessão depois de cada falha.
996
+ */
997
+ identity_attempts: { remaining: number; blocked_until: string | null };
841
998
  recording_status: RecordingStatus;
999
+ recording: IRoomRecordingStateDto;
842
1000
  transcription_status: TranscriptionStatus;
843
1001
  /** Textos vigentes que ainda precisam de aceite antes do join. */
844
1002
  required_consents: IRoomConsentRefDto[];
845
1003
  accepted_consents: IRoomConsentRefDto[];
846
1004
  /** Capabilities efetivas para esta sessão (entitlement AND rollout AND papel). */
847
1005
  capabilities: Record<string, boolean>;
1006
+ /** Presença do médico; `null` quando não há participante. Atalho de `participants`. */
1007
+ doctor_presence: ParticipantState | null;
1008
+ /** Presença do paciente. Atalho de `participants`. */
1009
+ patient_presence: ParticipantState | null;
1010
+ /** Os dois papéis, com `state`/`disconnected_at`/`reconnect_count`. */
1011
+ participants: ITeleconsultationParticipantDto[];
1012
+ /**
1013
+ * Pacientes em `state === 'waiting'`, e a ponte OBRIGATÓRIA do `POST /admit`:
1014
+ * o `participant_id` de domínio é o literal `'patient'`, enquanto o
1015
+ * `custom_participant_id` devolvido no `POST /join` é hash opaco que nunca
1016
+ * casaria com ele.
1017
+ */
1018
+ waiting_participants: ITeleconsultationParticipantDto[];
1019
+ /**
1020
+ * Máscara "Maria A. d. S." do titular do agendamento. SÓ na sessão do
1021
+ * MÉDICO — o backend nunca a manda ao paciente (T01), e é por isso que é o
1022
+ * único destes campos legitimamente opcional.
1023
+ */
1024
+ patient_display_masked?: string;
848
1025
  professional_display_name?: string;
849
1026
  clinic_display_name?: string;
850
1027
  /** Expiração do access da sessão (15 min, rotativo via `/session/refresh`). */
@@ -925,6 +1102,13 @@ export interface ITelemedicineLegalTextDto {
925
1102
  content_html: string;
926
1103
  content_hash: string;
927
1104
  effective_at?: string | null;
1105
+ /**
1106
+ * VALORES dos placeholders já resolvidos e filtrados pela allowlist do
1107
+ * próprio doc (`ITelemedicineLegalText.placeholders`, que guarda os NOMES
1108
+ * permitidos). ux-flows §3 exige "usada para {finalidade} e ficará
1109
+ * disponível por {prazo}", e D21 proíbe hardcode disso no bundle.
1110
+ */
1111
+ placeholders?: Record<string, string>;
928
1112
  }
929
1113
 
930
1114
  /** `GET /api/room/v1/legal-texts`. */
@@ -939,17 +1123,64 @@ export interface IIdentityVerifyResponseDto {
939
1123
  identity_level: IdentityLevel;
940
1124
  }
941
1125
 
942
- /** `POST /v1/teleconsultations/:id/access/send`. */
1126
+ /**
1127
+ * `POST /api/room/v1/exchange` e `POST /api/room/v1/session/refresh`.
1128
+ *
1129
+ * O corpo NÃO repete o `sid` (está no cookie `__session`, `HttpOnly`,
1130
+ * `Path=/api`) nem o tenant; traz o papel, que é o que permite ao SPA escolher
1131
+ * a tela sem um `GET /session` extra.
1132
+ */
1133
+ export interface IExchangeResponseDto {
1134
+ ok: true;
1135
+ role: ParticipantRole;
1136
+ session_expires_at: string;
1137
+ }
1138
+
1139
+ /** `POST /api/room/v1/participant-token/refresh` — token novo, MESMO participante lógico. */
1140
+ export interface IParticipantTokenRefreshDto {
1141
+ ok: true;
1142
+ provider_token: string;
1143
+ /** Nome do preset no provider (`hm_doctor`, `hm_patient_waiting`, ...). */
1144
+ preset: string;
1145
+ token_expires_at?: string;
1146
+ }
1147
+
1148
+ /**
1149
+ * `POST /v1/teleconsultations/:id/access/send` (feat-160 F7).
1150
+ *
1151
+ * É RECIBO DE TASK, não confirmação de envio: a rota publica a mesma task fina
1152
+ * que a rotina publicaria (`telemedicine_join_reminder`) e responde antes de
1153
+ * existir grant — o executor é quem resolve template, canal e elegibilidade e
1154
+ * emite a capability, uma por perna do fan-out. Por isso NÃO há `grant_id` nem
1155
+ * `expires_at` aqui: forjá-los era mentir para a recepção sobre um acesso que
1156
+ * ainda não existia.
1157
+ */
943
1158
  export interface IAccessSendResponseDto {
944
1159
  ok: true;
945
- grant_id: string;
1160
+ task_id: string;
1161
+ /** `true` quando a chave de idempotência colapsou num envio já pedido. */
1162
+ reused: boolean;
946
1163
  channel_kind: AccessSendChannelKind;
1164
+ /** Eco do pedido: revogar a capability anterior antes de emitir a nova. */
1165
+ resend: boolean;
1166
+ /** Destinatário mascarado do canal pedido; ausente em `manual`. */
947
1167
  recipient_masked?: string;
1168
+ }
1169
+
1170
+ /**
1171
+ * `POST /v1/teleconsultations/:id/access/link` (feat-160 F13; D31).
1172
+ *
1173
+ * **A `url` é CREDENCIAL** (capability de 128 bits do `/qr`), não um
1174
+ * identificador: não tem lugar em store, log, analytics nem storage do
1175
+ * navegador (T01/T04). Nasce nesta resposta, vai para a área de transferência e
1176
+ * morre com o diálogo. Cada revelação é uma chamada nova, de propósito — o que
1177
+ * fica registrado em `access.link_revealed` é o ato do usuário.
1178
+ */
1179
+ export interface IAccessLinkResultDto {
1180
+ ok: true;
1181
+ url: string;
1182
+ grant_id: string;
948
1183
  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
1184
  }
954
1185
 
955
1186
  // ======================================================
@@ -1002,6 +1233,28 @@ export interface IConsentCommand {
1002
1233
  decision: Extract<ConsentDecision, "accepted" | "declined">;
1003
1234
  }
1004
1235
 
1236
+ /**
1237
+ * `POST /api/room/v1/join` — intenção de mídia do preflight ("Entrar somente
1238
+ * com áudio"). Os dois campos são opcionais porque o backend só os REGISTRA
1239
+ * (escolha de preset e `audio_only_allowed`) e ignora o que não vier.
1240
+ */
1241
+ export interface IJoinCommand {
1242
+ audio?: boolean;
1243
+ video?: boolean;
1244
+ }
1245
+
1246
+ /**
1247
+ * `POST /api/room/v1/leave` — saída TEMPORÁRIA (D10); nunca encerra a consulta.
1248
+ *
1249
+ * `reason` é string aberta e o backend só distingue UM valor: `'temporary'` é
1250
+ * saída explícita (`left`), qualquer outro é tratado como queda de rede
1251
+ * (`disconnected`). Ausente = `'temporary'`. Chega pelo `pagehide` com
1252
+ * `fetch(keepalive)`, então pode vir sem `Content-Type`.
1253
+ */
1254
+ export interface ILeaveCommand {
1255
+ reason?: string;
1256
+ }
1257
+
1005
1258
  /** `POST /api/room/v1/presence`. */
1006
1259
  export interface IPresenceCommand {
1007
1260
  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.578",
4
4
  "description": "HREVO360 Shared Types",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",