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.
- package/dist/apps/evo-chat/channel/zod-schemas.d.ts +273 -0
- package/dist/apps/evo-chat/channel/zod-schemas.js +17 -1
- package/dist/apps/evo-chat/channel/zod-schemas.ts +19 -0
- package/dist/apps/evo-chat/thread-message/zod-schemas.d.ts +24 -0
- package/dist/apps/evo-chat/thread-message/zod-schemas.js +2 -0
- package/dist/apps/evo-chat/thread-message/zod-schemas.ts +2 -0
- package/dist/apps/evo-chat/waba-template/zod-schemas.d.ts +6 -0
- package/dist/apps/evo-chat/waba-template/zod-schemas.js +2 -0
- package/dist/apps/evo-chat/waba-template/zod-schemas.ts +2 -0
- package/dist/apps/evo-crm/lead/zod-schemas.d.ts +9 -0
- package/dist/apps/evo-med/calendar/zod-schemas.d.ts +4215 -1256
- package/dist/apps/evo-med/calendar/zod-schemas.js +61 -1
- package/dist/apps/evo-med/calendar/zod-schemas.ts +64 -0
- package/dist/apps/evo-med/insurance/zod-schemas.d.ts +9 -0
- package/dist/apps/evo-med/people/zod-schemas.d.ts +18 -0
- package/dist/apps/evo-notifications/zod-schemas.d.ts +110 -0
- package/dist/apps/evo-notifications/zod-schemas.js +8 -1
- package/dist/apps/evo-notifications/zod-schemas.ts +9 -0
- package/dist/apps/evo-telemedicine/zod-schemas.d.ts +161 -13
- package/dist/apps/evo-telemedicine/zod-schemas.js +93 -2
- package/dist/apps/evo-telemedicine/zod-schemas.ts +96 -0
- 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/types/evo-chat/channel/index.d.ts +19 -0
- package/dist/types/evo-chat/channel/index.ts +24 -0
- package/dist/types/evo-chat/thread-message/index.d.ts +4 -0
- package/dist/types/evo-chat/thread-message/index.ts +4 -0
- package/dist/types/evo-chat/waba-template/index.d.ts +6 -0
- package/dist/types/evo-chat/waba-template/index.js +3 -1
- package/dist/types/evo-chat/waba-template/index.ts +7 -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 +124 -1
- package/dist/types/evo-med/calendar/index.js +60 -1
- package/dist/types/evo-med/calendar/index.ts +167 -1
- package/dist/types/evo-notifications/index.d.ts +11 -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-telemedicine/index.d.ts +421 -6
- package/dist/types/evo-telemedicine/index.js +69 -1
- package/dist/types/evo-telemedicine/index.ts +454 -6
- package/dist/types/shared/index.d.ts +1 -0
- package/dist/types/shared/index.ts +2 -0
- 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
|
-
/**
|
|
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
|
-
|
|
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;
|
|
@@ -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;
|