@supcoflow/chat 1.0.0 → 2.1.0

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 (78) hide show
  1. package/LICENSES/orca.txt +25 -0
  2. package/README.md +125 -47
  3. package/dist/apariencia.d.ts +16 -0
  4. package/dist/apariencia.d.ts.map +1 -0
  5. package/dist/cliente.d.ts +25 -0
  6. package/dist/cliente.d.ts.map +1 -0
  7. package/dist/componentes/Adjuntos.d.ts +11 -0
  8. package/dist/componentes/Adjuntos.d.ts.map +1 -0
  9. package/dist/componentes/Burbuja.d.ts +6 -0
  10. package/dist/componentes/Burbuja.d.ts.map +1 -0
  11. package/dist/componentes/Compositor.d.ts +19 -0
  12. package/dist/componentes/Compositor.d.ts.map +1 -0
  13. package/dist/componentes/Markdown.d.ts +4 -0
  14. package/dist/componentes/Markdown.d.ts.map +1 -0
  15. package/dist/componentes/Mensajes.d.ts +8 -0
  16. package/dist/componentes/Mensajes.d.ts.map +1 -0
  17. package/dist/componentes/Panel.d.ts +11 -0
  18. package/dist/componentes/Panel.d.ts.map +1 -0
  19. package/dist/componentes/PreguntaHitl.d.ts +8 -0
  20. package/dist/componentes/PreguntaHitl.d.ts.map +1 -0
  21. package/dist/componentes/Widget.d.ts +21 -0
  22. package/dist/componentes/Widget.d.ts.map +1 -0
  23. package/dist/contexto.d.ts +10 -0
  24. package/dist/contexto.d.ts.map +1 -0
  25. package/dist/estado-del-widget.d.ts +18 -37
  26. package/dist/estado-del-widget.d.ts.map +1 -1
  27. package/dist/estado.d.ts +40 -0
  28. package/dist/estado.d.ts.map +1 -0
  29. package/dist/evidencia/adjuntos.d.ts +45 -0
  30. package/dist/evidencia/adjuntos.d.ts.map +1 -0
  31. package/dist/evidencia/captura.d.ts +56 -0
  32. package/dist/evidencia/captura.d.ts.map +1 -0
  33. package/dist/evidencia/elemento.d.ts +46 -0
  34. package/dist/evidencia/elemento.d.ts.map +1 -0
  35. package/dist/evidencia/extraer-elemento.d.ts +11 -0
  36. package/dist/evidencia/extraer-elemento.d.ts.map +1 -0
  37. package/dist/evidencia/resumen-de-evidencia.d.ts +11 -0
  38. package/dist/evidencia/resumen-de-evidencia.d.ts.map +1 -0
  39. package/dist/evidencia/selector-de-elementos.d.ts +11 -0
  40. package/dist/evidencia/selector-de-elementos.d.ts.map +1 -0
  41. package/dist/evidencia/subida.d.ts +17 -0
  42. package/dist/evidencia/subida.d.ts.map +1 -0
  43. package/dist/iife.d.ts +2 -0
  44. package/dist/iife.d.ts.map +1 -0
  45. package/dist/index.d.ts +4 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +91 -2
  48. package/dist/index.js.map +7 -1
  49. package/dist/markdown.d.ts +31 -0
  50. package/dist/markdown.d.ts.map +1 -0
  51. package/dist/montar.d.ts +9 -0
  52. package/dist/montar.d.ts.map +1 -0
  53. package/dist/opciones.d.ts +80 -0
  54. package/dist/opciones.d.ts.map +1 -0
  55. package/dist/protocolo.d.ts +61 -0
  56. package/dist/protocolo.d.ts.map +1 -0
  57. package/dist/react.d.ts +11 -0
  58. package/dist/react.d.ts.map +1 -0
  59. package/dist/sesion-guardada.d.ts +5 -0
  60. package/dist/sesion-guardada.d.ts.map +1 -0
  61. package/dist/tema.d.ts +3 -0
  62. package/dist/tema.d.ts.map +1 -0
  63. package/dist/textos.d.ts +32 -0
  64. package/dist/textos.d.ts.map +1 -0
  65. package/dist/widget.iife.js +91 -0
  66. package/dist/widget.iife.js.map +7 -0
  67. package/package.json +14 -33
  68. package/CHANGELOG.md +0 -24
  69. package/dist/ChatDeIntake.d.ts +0 -11
  70. package/dist/ChatDeIntake.d.ts.map +0 -1
  71. package/dist/ChatDeIntake.js +0 -56
  72. package/dist/ChatDeIntake.js.map +0 -1
  73. package/dist/estado-del-widget.js +0 -46
  74. package/dist/estado-del-widget.js.map +0 -1
  75. package/dist/partes-visibles.d.ts +0 -16
  76. package/dist/partes-visibles.d.ts.map +0 -1
  77. package/dist/partes-visibles.js +0 -14
  78. package/dist/partes-visibles.js.map +0 -1
@@ -0,0 +1,25 @@
1
+ Orca — github.com/stablyai/orca
2
+ Código trasladado a TypeScript en packages/widget/src/evidencia/extraer-elemento.ts y
3
+ selector-de-elementos.ts (src/main/browser/grab-guest-*.ts del original).
4
+
5
+ MIT License
6
+
7
+ Copyright (c) 2026 Lovecast Inc.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
package/README.md CHANGED
@@ -1,72 +1,150 @@
1
1
  # @supcoflow/chat
2
2
 
3
- El chat de intake de Supcoflow, como componente de React. Se monta en el sitio de un cliente y
4
- conversa con un agente que orienta sobre el producto y, cuando hay un bug de verdad, abre un
5
- reporte en Supcoflow.
6
-
7
- ## Requisitos
8
-
9
- - **React 19** (`peerDependencies: react >=19`).
10
- - **Node 24 o mayor** en el entorno donde se instala y se hace el build: el transporte es
11
- [`eve`](https://eve.dev), que lo exige. Con Node 22 o 23, `npm install` avisa por `engines`.
12
- - Un bundler (Next, Vite, webpack): el paquete emite ESM con imports relativos sin extensión.
13
- - Un proyecto de Supcoflow con **el chat activado**. La sección `sdk` del proyecto en la consola
14
- tiene el checklist de lo que falta.
3
+ El chat de intake de Supcoflow, embebible en cualquier sitio. Conversa con un asistente que
4
+ orienta sobre el producto y, cuando hay un bug de verdad, abre un reporte en Supcoflow.
15
5
 
16
6
  ## Instalación
17
7
 
8
+ ### Con npm (React, Vue, Svelte, vanilla)
9
+
18
10
  ```bash
19
11
  npm i @supcoflow/chat
20
12
  ```
21
13
 
22
- Trae `eve` como dependencia (hoy son ~47 MB instalados por un widget de 20 KB — está anotado
23
- como deuda y se va a separar en un paquete cliente liviano). `ai` entra solo como peer de `eve`.
24
- No hace falta `transpilePackages` en `next.config`.
25
-
26
- ## Uso
14
+ En React:
27
15
 
28
16
  ```tsx
29
17
  import { ChatDeIntake } from "@supcoflow/chat";
30
18
 
31
- <ChatDeIntake
32
- tenantId="tnt_xxx"
33
- projectId="proj_xxx"
34
- backendUrl="https://chat.supcoflow.dev"
35
- />
19
+ <ChatDeIntake tenantId="tnt_xxx" projectId="proj_xxx" />
36
20
  ```
37
21
 
38
- Los tres identificadores **son públicos** — modelo DSN. La contención no es un secreto: es la
39
- lista de orígenes admitidos del proyecto más el tope de mensajes (ventana rodante de 24 h), los
40
- dos del lado del motor. Poner el `tenantId` en el HTML de un sitio público es el uso previsto.
22
+ Sin React:
41
23
 
42
- El prop `contexto` se acepta por compatibilidad de tipos pero **hoy no viaja al reporte**. Si
43
- necesitás mandar URL o versión con el reporte, usá la API de ingesta desde tu servidor (la
44
- sección `sdk` de la consola tiene el snippet).
24
+ ```ts
25
+ import { montarChat } from "@supcoflow/chat";
45
26
 
46
- ## Si tu sitio tiene CSP
27
+ const chat = montarChat(document.body, { tenantId: "tnt_xxx", projectId: "proj_xxx" });
28
+ // chat.desmontar() cuando haga falta
29
+ ```
47
30
 
48
- Agregá el backend a `connect-src`, o el navegador bloquea el pedido y el widget no se dibuja
49
- nunca — es la causa más común de «lo instalé y no aparece»:
31
+ ### Con una línea de `<script>` (WordPress, Webflow, HTML plano)
50
32
 
33
+ ```html
34
+ <script src="https://chat.supcoflow.dev/widget.js" data-tenant="tnt_xxx" data-project="proj_xxx" defer></script>
51
35
  ```
52
- connect-src 'self' https://chat.supcoflow.dev;
36
+
37
+ Opciones por atributo: `data-backend`, `data-posicion` (`derecha`|`izquierda`), `data-titulo`,
38
+ `data-acento` (color), `data-version-app`, `data-contexto-automatico="false"`, `data-usuario-id`,
39
+ `data-usuario-rol`. También queda `window.SupcoflowChat.montar(opciones)` / `.desmontar()`.
40
+
41
+ Los identificadores **son públicos** (modelo DSN). La contención es la lista de Origins admitidos
42
+ del proyecto más el tope de mensajes, los dos del lado de Supcoflow.
43
+
44
+ ## Opciones
45
+
46
+ | opción | default | qué |
47
+ |---|---|---|
48
+ | `backendUrl` | `https://chat.supcoflow.dev` | el backend del chat |
49
+ | `modo` | `"burbuja"` | `"burbuja"` (botón flotante + panel) o `"inline"` (el panel donde lo montes) |
50
+ | `posicion` | `"derecha"` | lado de la burbuja |
51
+ | `titulo` | `"Ayuda"` | cabecera del panel |
52
+ | `tema` | neutro | `{ acento, fondo, texto, textoSuave, radio, fuente }`, cualquier subconjunto |
53
+ | `contexto` | `{}` | `{ versionApp }` — viaja con el primer mensaje |
54
+ | `contextoAutomatico` | `true` | manda la URL (sin query) y el navegador. Errores de consola: nunca |
55
+ | `onDiagnostico` | — | `({ visible, status, motivo }) => void`, ver abajo |
56
+ | `usuario` | — | `{ id, rol, atributos }` — quién es el usuario según tu app, para el diagnóstico. Ver abajo |
57
+ | `previewToken` | — | **interna**: la usa la consola de Supcoflow para el preview; en tu sitio no hace nada útil |
58
+
59
+ ## Quién es el usuario
60
+
61
+ ```tsx
62
+ <ChatDeIntake tenantId="tnt_xxx" projectId="proj_xxx" usuario={{ id: "u_123", rol: "admin", atributos: { plan: "pro" } }} />
53
63
  ```
54
64
 
55
- ## Lo que hace cuando algo falla: nada visible
65
+ Todo opcional. `id` (hasta 100 caracteres), `rol` (60) y hasta 8 `atributos` (claves de 40, valores de
66
+ 200) viajan con el primer mensaje al asistente y, si se abre un reporte, al reporte: el rol es el
67
+ dato de diagnóstico más barato que hay (la mitad de los «no me aparece el botón» son permisos). Es
68
+ **declarado, no verificado**: no da permisos a nada, es contexto. Lo que se pasa de largo se
69
+ recorta; lo que no sea `id`, `rol` o `atributos` se descarta.
70
+
71
+ No hay `nombre` en esta versión: llega con la pantalla de inicio, que es lo único que lo va a usar,
72
+ y **nunca va a viajar** al asistente ni al reporte.
73
+
74
+ ## La marca desde la consola
75
+
76
+ El logo, el título y los colores del chat se editan desde `/proyectos/<slug>/sdk` en Supcoflow y el
77
+ widget los aplica solo, antes del primer dibujo. Lo que pases por código (`titulo`, `tema`) gana
78
+ sobre lo guardado en la consola, campo a campo.
79
+
80
+ ## Qué pasa cuando algo falla
81
+
82
+ **Al cargar**, si el chat del proyecto está apagado, el tope del día se agotó, el origen del
83
+ sitio no está admitido o el backend no contesta, el widget **no se dibuja**: quien está del otro
84
+ lado es un usuario final del producto, y no tiene nada que hacer con «el proyecto tiene el tope
85
+ agotado». Para saber por qué no aparece, pasá `onDiagnostico` o mirá la consola en `localhost`:
86
+
87
+ | `status` | `motivo` | qué hacer |
88
+ |---|---|---|
89
+ | 403 | `chat_deshabilitado` | activar el chat en `/proyectos/<slug>/sdk` |
90
+ | 403 | `origen_no_admitido` | agregar el origen del sitio en esa misma pantalla |
91
+ | 404 | `proyecto_desconocido` | revisar `tenantId` / `projectId` |
92
+ | 429 | `tope_de_mensajes` | esperar: el tope vuelve a abrir solo |
93
+ | 502 | `motor_inalcanzable` | es del lado de Supcoflow |
94
+ | 0 | `sin_respuesta` | red, CSP o `backendUrl` mal escrita |
95
+
96
+ **A mitad de conversación**, un error se muestra debajo del último mensaje con un botón de
97
+ reintentar, y lo que el usuario escribió se conserva. `onDiagnostico` lo recibe también, con el
98
+ código del error en `motivo`.
99
+
100
+ ## Lo que el widget hace y no hace
101
+
102
+ - La conversación sobrevive a una recarga **de la misma pestaña**.
103
+ - El asistente escribe con formato (negrita, listas, código, links) y pide la confirmación del
104
+ reporte con botones.
105
+ - El navegador habla sólo con el backend del chat, en un formato propio y chico; el motor de
106
+ agentes queda del lado del servidor.
107
+ - No le da seguimiento del reporte al que reportó. Es a propósito.
108
+ - No recolecta errores de consola ni nada que no esté en la tabla de opciones.
109
+ - Señalar, capturar y adjuntar son acciones del usuario: el widget no captura nada solo.
110
+
111
+ ## Señalar y adjuntar
112
+
113
+ El usuario final puede **señalar el elemento** de tu página que le falla, **capturar la pantalla**
114
+ y **adjuntar una imagen**. Eso viaja al reporte (y al agente que lo arregla), nunca al modelo del
115
+ chat, que sólo recibe una descripción corta («señaló el botón Guardar del formulario»).
116
+
117
+ Qué se recolecta al señalar, y qué no:
118
+
119
+ - Sí: la etiqueta, un selector CSS, la ruta en el DOM, el texto visible, los atributos `id class
120
+ name type role href src alt title placeholder for action method` y `aria-*`, dieciséis
121
+ propiedades de estilo, el texto de los elementos vecinos, y el HTML del elemento acotado a 4 KB.
122
+ - No: **el valor de ningún `input`, `textarea` o `select`**, ningún `<script>`, ninguna query ni
123
+ hash de URL; y cualquier atributo o clase con pinta de secreto (`access_token`, `csrf`,
124
+ `password`…) se reemplaza por `[redacted]`.
125
+
126
+ La captura la toma el usuario con el diálogo del navegador (`getDisplayMedia`) y la ve como
127
+ miniatura antes de que suba; puede quitarla. Algunos navegadores y iOS no soportan
128
+ `getDisplayMedia`: ahí sólo queda «Adjuntar imagen», que funciona en todos lados. Las imágenes se re-codifican
129
+ (WebP o PNG, hasta 1,5 MB) y no conservan metadatos del archivo original. Hasta **4 adjuntos por
130
+ conversación**.
131
+
132
+ Quien señala ve un resaltado sobre tu página: es un overlay nuestro, a pantalla completa, que se
133
+ desmonta al elegir o al apretar Esc. El código del selector es de [Orca](https://github.com/stablyai/orca)
134
+ (MIT), trasladado a TypeScript; la licencia va en `LICENSES/orca.txt`.
135
+
136
+ ## Si tu sitio tiene CSP
137
+
138
+ `connect-src` tiene que admitir el `backendUrl` (por defecto `https://chat.supcoflow.dev`). El
139
+ widget no carga fuentes ni scripts de terceros. Las miniaturas de las capturas son `data:` URLs
140
+ generadas en el navegador: si tu `img-src` no admite `data:`, no se ven las miniaturas (la subida
141
+ funciona igual).
142
+
143
+ ## Tamaño y requisitos
56
144
 
57
- El widget **se oculta** —no muestra un error— si el chat está apagado, si el tope se agotó, si el
58
- origen del sitio no está admitido o si el backend no contesta. Es deliberado: quien está del otro
59
- lado es un usuario final del producto del cliente. Para diagnosticar, mirá el status de
60
- `GET {backendUrl}/api/chat/estado?tenant_id=…&project_id=…` **desde el sitio** (el origen
61
- importa): 403 (chat apagado u origen no admitido), 429 (tope agotado), 404 (proyecto
62
- desconocido), 502 (backend sin poder hablar con el motor). O usá «probar la instalación» en la
63
- sección `sdk` de la consola. Ojo con `www.tu-sitio.com` contra `tu-sitio.com`: la comparación es
64
- por origen exacto, y son dos entradas de la lista.
145
+ Un solo archivo por salida, sin dependencias que instalar. React es opcional (sólo para
146
+ `ChatDeIntake`). Sin webfonts. Funciona en navegadores con ES2022 y Shadow DOM.
65
147
 
66
- ## Lo que este paquete NO hace
148
+ ## Licencias
67
149
 
68
- - No persiste la conversación fuera de la sesión del navegador.
69
- - No le da seguimiento del reporte al que reportó. Es a propósito — el único lugar donde un
70
- reporte se ve es la consola del operador.
71
- - No trae estilos configurables todavía: el panel usa estilos en línea y hereda la tipografía del
72
- sitio.
150
+ MIT. Ver `LICENSES/` por el código de terceros incluido.
@@ -0,0 +1,16 @@
1
+ import { type OpcionesDelChat, type TemaDelChat } from "./opciones";
2
+ /** La marca tal cual la manda el backend (`GET /api/chat/estado`, snake_case). Todo opcional: un
3
+ * backend viejo no la manda y el widget usa sus defaults — nunca se adivina, como con `motivo`. */
4
+ export interface MarcaDelMotor {
5
+ logo_url?: string | null;
6
+ titulo?: string | null;
7
+ saludo?: string | null;
8
+ tema?: Partial<TemaDelChat> | null;
9
+ }
10
+ export interface Apariencia {
11
+ titulo: string;
12
+ logoUrl: string | null;
13
+ tema: TemaDelChat;
14
+ }
15
+ export declare function resolverApariencia(o: Pick<OpcionesDelChat, "titulo" | "tema">, marca: unknown): Apariencia;
16
+ //# sourceMappingURL=apariencia.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apariencia.d.ts","sourceRoot":"","sources":["../src/apariencia.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAWtF;mGACmG;AACnG,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,WAAW,CAAC;CACnB;AAoBD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,UAAU,CAQ1G"}
@@ -0,0 +1,25 @@
1
+ import type { OpcionesResueltas } from "./opciones";
2
+ import type { EventoDelWidget } from "./protocolo";
3
+ export type Respuesta = {
4
+ requestId: string;
5
+ optionId?: string;
6
+ text?: string;
7
+ };
8
+ export interface ClienteDelChat {
9
+ abrir(mensaje: string, contexto: Record<string, string> | undefined): AsyncIterable<EventoDelWidget>;
10
+ /** `contexto` en un mensaje de seguimiento (Revisión 2 punto 5): el resumen acumulado de la
11
+ * evidencia va en CADA turno, porque clientContext de Eve es por turno. */
12
+ seguir(id: string, indice: number, cuerpo: {
13
+ mensaje: string;
14
+ contexto?: Record<string, string>;
15
+ } | {
16
+ respuesta: Respuesta;
17
+ }): AsyncIterable<EventoDelWidget>;
18
+ recuperar(id: string, desde: number): AsyncIterable<EventoDelWidget>;
19
+ }
20
+ /** Una línea que no es un evento v1 es `null`: el lector la salta y sigue. Un `t` desconocido
21
+ * SÍ pasa — es la regla de compatibilidad: el reducer lo ignora. */
22
+ export declare function parsearLinea(linea: string): EventoDelWidget | null;
23
+ export declare function leerNdjson(cuerpo: ReadableStream<Uint8Array>): AsyncGenerator<EventoDelWidget>;
24
+ export declare function crearCliente(o: OpcionesResueltas, fetchFn?: typeof fetch): ClienteDelChat;
25
+ //# sourceMappingURL=cliente.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliente.d.ts","sourceRoot":"","sources":["../src/cliente.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAOnD,MAAM,MAAM,SAAS,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;IACrG;+EAC2E;IAC3E,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG;QAAE,SAAS,EAAE,SAAS,CAAA;KAAE,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;IAC9J,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;CACtE;AAED;oEACoE;AACpE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CASlE;AAED,wBAAuB,UAAU,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,cAAc,CAAC,eAAe,CAAC,CAqBrG;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,iBAAiB,EAAE,OAAO,GAAE,OAAO,KAA6B,GAAG,cAAc,CAyChH"}
@@ -0,0 +1,11 @@
1
+ import type { Adjunto } from "../evidencia/adjuntos";
2
+ export declare function Adjuntos(props: {
3
+ adjuntos: Adjunto[];
4
+ ocupado: boolean;
5
+ aviso: string | null;
6
+ /** Se ofrece sólo si el ÚLTIMO adjunto es un elemento y el navegador sabe capturar (§3.2). */
7
+ onCapturarElemento: (() => void) | null;
8
+ onQuitar: (clave: number) => void;
9
+ onReintentar: (clave: number) => void;
10
+ }): import("preact").JSX.Element | null;
11
+ //# sourceMappingURL=Adjuntos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Adjuntos.d.ts","sourceRoot":"","sources":["../../src/componentes/Adjuntos.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAqBrD,wBAAgB,QAAQ,CAAC,KAAK,EAAE;IAC9B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,8FAA8F;IAC9F,kBAAkB,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,uCAsBA"}
@@ -0,0 +1,6 @@
1
+ export declare function Burbuja(props: {
2
+ posicion: "derecha" | "izquierda";
3
+ abierto: boolean;
4
+ onClick: () => void;
5
+ }): import("preact").JSX.Element;
6
+ //# sourceMappingURL=Burbuja.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Burbuja.d.ts","sourceRoot":"","sources":["../../src/componentes/Burbuja.tsx"],"names":[],"mappings":"AAEA,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAAE,QAAQ,EAAE,SAAS,GAAG,WAAW,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,gCAgB1G"}
@@ -0,0 +1,19 @@
1
+ export interface Herramientas {
2
+ onSenalar: () => void;
3
+ onCapturarPantalla: () => void;
4
+ onAdjuntarImagen: (archivo: File) => void;
5
+ /** §3.2: sin getDisplayMedia (Safari, iOS, http) el ítem de capturar NO se dibuja; adjuntar imagen siempre. */
6
+ puedeCapturar: boolean;
7
+ /** Falso con la cola llena (4): los botones se deshabilitan y el aviso lo dice la barra. */
8
+ puedeAdjuntar: boolean;
9
+ }
10
+ export declare function Compositor(props: {
11
+ valor: string;
12
+ onCambio: (v: string) => void;
13
+ onEnviar: () => void;
14
+ deshabilitado: boolean;
15
+ enfocarAlMontar: boolean;
16
+ /** `null` en preview (§2 del diseño de la marca): ni botones ni input de archivo — la subida está apagada, no deshabilitada. */
17
+ herramientas: Herramientas | null;
18
+ }): import("preact").JSX.Element;
19
+ //# sourceMappingURL=Compositor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Compositor.d.ts","sourceRoot":"","sources":["../../src/componentes/Compositor.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,gBAAgB,EAAE,CAAC,OAAO,EAAE,IAAI,KAAK,IAAI,CAAC;IAC1C,+GAA+G;IAC/G,aAAa,EAAE,OAAO,CAAC;IACvB,4FAA4F;IAC5F,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,gIAAgI;IAChI,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;CACnC,gCAoEA"}
@@ -0,0 +1,4 @@
1
+ export declare function Markdown({ texto }: {
2
+ texto: string;
3
+ }): import("preact").JSX.Element;
4
+ //# sourceMappingURL=Markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../src/componentes/Markdown.tsx"],"names":[],"mappings":"AA+BA,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,gCAEpD"}
@@ -0,0 +1,8 @@
1
+ import type { Respuesta } from "../cliente";
2
+ import { type EstadoDelChat } from "../estado";
3
+ export declare function Mensajes(props: {
4
+ estado: EstadoDelChat;
5
+ onReintentar: () => void;
6
+ onResponder: (r: Respuesta) => void;
7
+ }): import("preact").JSX.Element;
8
+ //# sourceMappingURL=Mensajes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Mensajes.d.ts","sourceRoot":"","sources":["../../src/componentes/Mensajes.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAKjE,wBAAgB,QAAQ,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,YAAY,EAAE,MAAM,IAAI,CAAC;IAAC,WAAW,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAA;CAAE,gCA+BvH"}
@@ -0,0 +1,11 @@
1
+ import type { ComponentChildren } from "preact";
2
+ export declare function Panel(props: {
3
+ titulo: string;
4
+ logoUrl: string | null;
5
+ enPreview: boolean;
6
+ modo: "burbuja" | "inline";
7
+ posicion: "derecha" | "izquierda";
8
+ onMinimizar: () => void;
9
+ children: ComponentChildren;
10
+ }): import("preact").JSX.Element;
11
+ //# sourceMappingURL=Panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Panel.d.ts","sourceRoot":"","sources":["../../src/componentes/Panel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAGhD,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,QAAQ,EAAE,SAAS,GAAG,WAAW,CAAC;IAClC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,EAAE,iBAAiB,CAAC;CAC7B,gCAyBA"}
@@ -0,0 +1,8 @@
1
+ import type { Respuesta } from "../cliente";
2
+ import type { PreguntaPendiente } from "../estado";
3
+ export declare function PreguntaHitl(props: {
4
+ pregunta: PreguntaPendiente;
5
+ ocupado: boolean;
6
+ onResponder: (r: Respuesta) => void;
7
+ }): import("preact").JSX.Element;
8
+ //# sourceMappingURL=PreguntaHitl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PreguntaHitl.d.ts","sourceRoot":"","sources":["../../src/componentes/PreguntaHitl.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAKnD,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAAE,QAAQ,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAA;CAAE,gCAqCzH"}
@@ -0,0 +1,21 @@
1
+ import type { ClienteDelChat } from "../cliente";
2
+ import { type ErrorVisible } from "../estado";
3
+ import type { OpcionesResueltas } from "../opciones";
4
+ import type { CursorDeSesion } from "../protocolo";
5
+ export default function Widget(props: {
6
+ cliente: ClienteDelChat;
7
+ opciones: OpcionesResueltas;
8
+ /** De la marca del motor (§3.3); `null` = sin logo. */
9
+ logoUrl: string | null;
10
+ /** §2/§5.3 del diseño de la marca: rótulo en la cabecera y la evidencia apagada — en el preview no
11
+ * hay `chat_conversaciones` que la reciba, y una captura de pantalla del modal no tiene que
12
+ * confundirse con el chat real. */
13
+ enPreview: boolean;
14
+ cursorInicial: CursorDeSesion | null;
15
+ alCambiarCursor: (c: CursorDeSesion | null) => void;
16
+ alError: (e: ErrorVisible) => void;
17
+ abiertoAlInicio: boolean;
18
+ /** El host de nuestro shadow root: el selector no lo puede elegir (señalar el chat no es un bug del sitio). */
19
+ hostDelWidget: Element | null;
20
+ }): import("preact").JSX.Element | null;
21
+ //# sourceMappingURL=Widget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Widget.d.ts","sourceRoot":"","sources":["../../src/componentes/Widget.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAqG,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAQjJ,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,cAAc,CAAC;AAQpE,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE;IACpC,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,uDAAuD;IACvD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;uCAEmC;IACnC,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,cAAc,GAAG,IAAI,CAAC;IACrC,eAAe,EAAE,CAAC,CAAC,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC;IACpD,OAAO,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;IACnC,eAAe,EAAE,OAAO,CAAC;IACzB,+GAA+G;IAC/G,aAAa,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B,uCAyOA"}
@@ -0,0 +1,10 @@
1
+ import type { OpcionesResueltas } from "./opciones";
2
+ export declare function resumenDeContexto(o: OpcionesResueltas, ventana: {
3
+ location?: {
4
+ href: string;
5
+ };
6
+ navigator?: {
7
+ userAgent: string;
8
+ };
9
+ }): Record<string, string> | undefined;
10
+ //# sourceMappingURL=contexto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contexto.d.ts","sourceRoot":"","sources":["../src/contexto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAapD,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,iBAAiB,EACpB,OAAO,EAAE;IAAE,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,SAAS,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC1E,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAuBpC"}
@@ -1,46 +1,27 @@
1
+ import type { Diagnostico } from "./opciones";
1
2
  export type Visibilidad = "visible" | "oculto";
2
- /** `crypto.randomUUID` no existe en un contexto no-seguro (un sitio embebido por HTTP
3
- * plano, no HTTPS) sin este chequeo, el `useMemo` del widget lanza en el render y
4
- * tira abajo el host entero, justo lo opuesto a la promesa de "se oculta" del §8. El
5
- * fallback no necesita ser criptográfico: es un id de canal anónimo, no un secreto.
6
- *
7
- * `ChatDeIntake` dejó de llamar esta función: sobre `useEveAgent` el rol de identificar la
8
- * conversación lo cumple el `sessionId` que pone el backend. Queda EXPORTADA sin llamador
9
- * dentro de este paquete —no se borra especulativamente— porque `POST /api/chat`, el camino
10
- * viejo, sigue vivo hasta el corte, y es la ruta que necesita el concepto de "id de canal" del
11
- * lado del cliente. */
12
- export declare function generarCanalId(): string;
13
- /** Una barra final en `backendUrl` ("https://x.com/", la forma más natural de
14
- * escribirlo) deja `//` duplicado en las URLs armadas más abajo: el motor responde con
15
- * un 308 sin headers de CORS y el navegador lo bloquea sin explicar que el problema es
16
- * la barra. Mismo patrón que `motor.ts` usa para su propia base URL. */
3
+ /** Una barra final en `backendUrl` ("https://x.com/", la forma más natural de escribirlo) deja
4
+ * `//` duplicado en las URLs armadas: el motor responde con un 308 sin headers de CORS y el
5
+ * navegador lo bloquea sin explicar que el problema es la barra. */
17
6
  export declare function normalizarBackendUrl(backendUrl: string): string;
18
- /** §8 del diseño: sin backend, sin tope, o ante cualquier duda, el widget NO se dibuja.
19
- * Ocultarse es lo honesto: no hay nada que decirle al usuario final sobre el estado interno
20
- * del proyecto de otra empresa. */
7
+ /** §2.4 del diseño: sin backend, sin tope, o ante cualquier duda, el widget NO se dibuja al
8
+ * montar. Ocultarse es lo honesto: no hay nada que decirle al usuario final sobre el estado
9
+ * interno del proyecto de otra empresa. */
21
10
  export declare function decidirVisibilidad(h: {
22
11
  respuesta: {
23
12
  ok: boolean;
24
13
  } | null;
25
14
  huboError: boolean;
26
15
  }): Visibilidad;
27
- export type EstadoDelChat = "submitted" | "streaming" | "ready" | "error" | "resuming";
28
- interface ParteMinima {
29
- type: string;
30
- text?: string;
31
- }
32
- interface MensajeMinimo {
33
- role: string;
34
- parts: readonly ParteMinima[];
35
- }
36
- /** Entre Enviar y el primer token del stream pasan 4-8 s en el peor caso (medido en la pasada
37
- * visual del demo) — el backend responde perfecto, pero un silencio así se lee como "se rompió
38
- * el botón", no como "está pensando". Mostramos un indicador mientras el pedido está en vuelo
39
- * ("submitted") y mientras ya empezó a transmitir pero todavía no llegó texto del asistente
40
- * ("streaming" sin parts de texto no vacíos en el último mensaje). */
41
- export declare function mostrarIndicadorDeEscritura(h: {
42
- status: EstadoDelChat;
43
- ultimoMensaje: MensajeMinimo | undefined;
44
- }): boolean;
45
- export {};
16
+ /** §2.5 del diseño: lo que el widget le cuenta al desarrollador. `decidirVisibilidad` sigue
17
+ * decidiendo si se dibuja; esto sólo agrega el porqué. `motivo` viene del motor vía
18
+ * `/api/chat/estado`; un backend viejo no lo manda y acá queda `null` — nunca se adivina. */
19
+ export declare function diagnosticoDesdeRespuesta(h: {
20
+ status: number;
21
+ cuerpo: {
22
+ ok?: boolean;
23
+ motivo?: string | null;
24
+ } | null;
25
+ huboError: boolean;
26
+ }): Diagnostico;
46
27
  //# sourceMappingURL=estado-del-widget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"estado-del-widget.d.ts","sourceRoot":"","sources":["../src/estado-del-widget.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/C;;;;;;;;;uBASuB;AACvB,wBAAgB,cAAc,IAAI,MAAM,CAKvC;AAED;;;wEAGwE;AACxE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;mCAEmC;AACnC,wBAAgB,kBAAkB,CAAC,CAAC,EAAE;IACpC,SAAS,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;CACpB,GAAG,WAAW,CAGd;AAMD,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC;AAEvF,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IAGb,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;CAC/B;AAED;;;;sEAIsE;AACtE,wBAAgB,2BAA2B,CAAC,CAAC,EAAE;IAC7C,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,aAAa,GAAG,SAAS,CAAC;CAC1C,GAAG,OAAO,CAOV"}
1
+ {"version":3,"file":"estado-del-widget.d.ts","sourceRoot":"","sources":["../src/estado-del-widget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/C;;oEAEoE;AACpE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;2CAE2C;AAC3C,wBAAgB,kBAAkB,CAAC,CAAC,EAAE;IAAE,SAAS,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG,WAAW,CAG5G;AAED;;6FAE6F;AAC7F,wBAAgB,yBAAyB,CAAC,CAAC,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE;QAAE,EAAE,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IACxD,SAAS,EAAE,OAAO,CAAC;CACpB,GAAG,WAAW,CAId"}
@@ -0,0 +1,40 @@
1
+ import type { CursorDeSesion, EventoDelWidget, OpcionDePregunta } from "./protocolo";
2
+ export interface Mensaje {
3
+ clave: number;
4
+ rol: "usuario" | "asistente";
5
+ texto: string;
6
+ /** asistente: todavía llegan deltas. usuario: mandado y todavía no confirmado por `usuario`. */
7
+ abierto: boolean;
8
+ }
9
+ export interface PreguntaPendiente {
10
+ requestId: string;
11
+ opciones: OpcionDePregunta[];
12
+ libre: boolean;
13
+ }
14
+ export interface ErrorVisible {
15
+ codigo: string;
16
+ mensaje: string;
17
+ terminal: boolean;
18
+ }
19
+ export interface EstadoDelChat {
20
+ mensajes: Mensaje[];
21
+ pregunta: PreguntaPendiente | null;
22
+ ocupado: boolean;
23
+ error: ErrorVisible | null;
24
+ /** `null` = el próximo mensaje abre una sesión nueva. */
25
+ cursor: CursorDeSesion | null;
26
+ siguienteClave: number;
27
+ }
28
+ export declare function estadoInicial(cursor: CursorDeSesion | null): EstadoDelChat;
29
+ /** Optimista: lo que el usuario escribió se ve ya, y `usuario` lo confirma después (§2.4: nunca
30
+ * se pierde lo escrito). */
31
+ export declare function alEnviar(e: EstadoDelChat, texto: string): EstadoDelChat;
32
+ export declare function alResponder(e: EstadoDelChat): EstadoDelChat;
33
+ export declare function alReintentar(e: EstadoDelChat): EstadoDelChat;
34
+ /** El cuerpo HTTP terminó, con borde o sin él: nada más va a llegar por este stream. */
35
+ export declare function alTerminarStream(e: EstadoDelChat): EstadoDelChat;
36
+ export declare function reducir(e: EstadoDelChat, ev: EventoDelWidget): EstadoDelChat;
37
+ /** Entre Enviar y el primer token pasan 4-8 s en el peor caso (medido en la 1.x): sin indicador
38
+ * se lee como "se rompió el botón". Se apaga con el primer texto del asistente. */
39
+ export declare function mostrarIndicador(e: EstadoDelChat): boolean;
40
+ //# sourceMappingURL=estado.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estado.d.ts","sourceRoot":"","sources":["../src/estado.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMrF,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,SAAS,GAAG,WAAW,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,gGAAgG;IAChG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,yDAAyD;IACzD,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,aAAa,CAE1E;AA0BD;4BAC4B;AAC5B,wBAAgB,QAAQ,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAEvE;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,aAAa,GAAG,aAAa,CAE3D;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,aAAa,CAE5D;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,aAAa,GAAG,aAAa,CAEhE;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,eAAe,GAAG,aAAa,CAsC5E;AAED;mFACmF;AACnF,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAI1D"}
@@ -0,0 +1,45 @@
1
+ import type { ImagenLista } from "./captura";
2
+ import type { ElementoSeleccionado } from "./elemento";
3
+ /** El motor cuenta 5 evidencias por sesión, de cualquier tipo, y el `contexto` que reenvía `abrir`
4
+ * ocupa una (Revisión 2 punto 4). Cuatro acá, antes que un quinto que siempre rebota con 429. */
5
+ export declare const MAX_ADJUNTOS = 4;
6
+ export type EstadoDeSubida = "pendiente" | "subiendo" | "listo" | "fallo";
7
+ interface AdjuntoBase {
8
+ clave: number;
9
+ estado: EstadoDeSubida;
10
+ evidenciaId: string | null;
11
+ motivo: string | null;
12
+ /** Con `fallo`: si vale la pena ofrecer «reintentar» (red, motor caído) o no (tope, rechazo). */
13
+ reintentable: boolean;
14
+ }
15
+ export type Adjunto = (AdjuntoBase & {
16
+ tipo: "elemento";
17
+ elemento: ElementoSeleccionado;
18
+ etiqueta: string;
19
+ }) | (AdjuntoBase & {
20
+ tipo: "captura";
21
+ imagen: ImagenLista;
22
+ });
23
+ export interface EstadoDeAdjuntos {
24
+ adjuntos: Adjunto[];
25
+ siguienteClave: number;
26
+ }
27
+ export declare function sinAdjuntos(): EstadoDeAdjuntos;
28
+ export declare function puedeAgregar(e: EstadoDeAdjuntos): boolean;
29
+ /** «button «Guardar»»: lo que el chip muestra. El nombre accesible antes que el texto, y corto. */
30
+ export declare function etiquetaDelElemento(el: ElementoSeleccionado): string;
31
+ export declare function agregarElemento(e: EstadoDeAdjuntos, elemento: ElementoSeleccionado): EstadoDeAdjuntos;
32
+ export declare function agregarCaptura(e: EstadoDeAdjuntos, imagen: ImagenLista): EstadoDeAdjuntos;
33
+ export declare function quitar(e: EstadoDeAdjuntos, clave: number): EstadoDeAdjuntos;
34
+ export declare function marcar(e: EstadoDeAdjuntos, clave: number, cambio: {
35
+ estado: EstadoDeSubida;
36
+ evidenciaId?: string;
37
+ motivo?: string;
38
+ reintentable?: boolean;
39
+ }): EstadoDeAdjuntos;
40
+ export declare function pendientes(e: EstadoDeAdjuntos): Adjunto[];
41
+ export declare function ultimoElemento(e: EstadoDeAdjuntos): Extract<Adjunto, {
42
+ tipo: "elemento";
43
+ }> | null;
44
+ export {};
45
+ //# sourceMappingURL=adjuntos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adjuntos.d.ts","sourceRoot":"","sources":["../../src/evidencia/adjuntos.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAOvD;iGACiG;AACjG,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC;AAE1E,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iGAAiG;IACjG,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,OAAO,GACf,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,oBAAoB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GACtF,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,WAAW,IAAI,gBAAgB,CAE9C;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAEzD;AAcD,mGAAmG;AACnG,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,oBAAoB,GAAG,MAAM,CAIpE;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,gBAAgB,EAAE,QAAQ,EAAE,oBAAoB,GAAG,gBAAgB,CAErG;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,EAAE,WAAW,GAAG,gBAAgB,CAEzF;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAG3E;AAED,wBAAgB,MAAM,CACpB,CAAC,EAAE,gBAAgB,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GAChG,gBAAgB,CAelB;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,gBAAgB,GAAG,OAAO,EAAE,CAEzD;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,GAAG,IAAI,CAMjG"}