@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
package/package.json CHANGED
@@ -1,51 +1,32 @@
1
1
  {
2
2
  "name": "@supcoflow/chat",
3
- "version": "1.0.0",
4
- "description": "El chat de intake de Supcoflow como componente de React: orienta sobre el producto y abre el reporte cuando el problema es un bug.",
3
+ "version": "2.1.0",
4
+ "description": "El chat de intake de Supcoflow, embebible en cualquier sitio: orienta sobre el producto y abre el reporte cuando el problema es un bug.",
5
5
  "license": "MIT",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/supcoflow/sdk.git",
9
- "directory": "packages/widget"
10
- },
6
+ "repository": { "type": "git", "url": "git+https://github.com/supcoflow/sdk.git", "directory": "packages/widget" },
11
7
  "homepage": "https://supcoflow.dev",
12
- "keywords": [
13
- "supcoflow",
14
- "chat",
15
- "intake",
16
- "bug-report",
17
- "react",
18
- "widget"
19
- ],
8
+ "keywords": ["supcoflow", "chat", "intake", "bug-report", "widget", "react", "preact"],
20
9
  "type": "module",
21
10
  "main": "./dist/index.js",
22
11
  "types": "./dist/index.d.ts",
23
12
  "exports": {
24
- ".": {
25
- "types": "./dist/index.d.ts",
26
- "default": "./dist/index.js"
27
- }
13
+ ".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" },
14
+ "./widget.js": "./dist/widget.iife.js"
28
15
  },
29
- "files": [
30
- "dist",
31
- "CHANGELOG.md"
32
- ],
16
+ "files": ["dist", "LICENSES"],
17
+ "sideEffects": false,
33
18
  "scripts": {
34
- "build": "tsc -p tsconfig.build.json",
19
+ "build": "node build.mjs && tsc -p tsconfig.build.json",
35
20
  "prepare": "npm run build"
36
21
  },
37
- "peerDependencies": {
38
- "react": ">=19"
39
- },
40
- "dependencies": {
41
- "eve": "0.47.7"
42
- },
22
+ "peerDependencies": { "react": ">=18" },
23
+ "peerDependenciesMeta": { "react": { "optional": true } },
43
24
  "devDependencies": {
44
25
  "@types/react": "19.2.18",
26
+ "esbuild": "0.28.2",
27
+ "preact": "10.28.3",
45
28
  "typescript": "^5.7.0",
46
29
  "vitest": "^4.0.0"
47
30
  },
48
- "publishConfig": {
49
- "access": "public"
50
- }
31
+ "publishConfig": { "access": "public" }
51
32
  }
package/CHANGELOG.md DELETED
@@ -1,24 +0,0 @@
1
- # Changelog de @supcoflow/chat
2
-
3
- ## 1.0.0 — 2026-09-02
4
-
5
- Para quien instala, no para quien mantiene.
6
-
7
- - **El transporte pasa a Eve** (`useEveAgent`): sesión por conversación y stream NDJSON contra
8
- `{backendUrl}/eve/v1/*`. El uso del componente no cambia: mismas tres props.
9
- - **React ≥19**, igual que antes.
10
- - **Nuevo requisito: Node ≥24** en el entorno de instalación y build, por `eve`.
11
- - **Nueva dependencia: `eve@0.47.7`** (~47 MB instalados) y `ai` como peer que npm instala solo.
12
- Deuda declarada: separar el cliente en un paquete liviano es una rebanada aparte.
13
- - **`contexto` sale del README**: el prop sigue aceptado por compatibilidad de tipos pero no viaja
14
- al reporte. Ya era así en 0.1.0 y el README lo prometía igual.
15
- - **La CSP entra al README** (`connect-src`), y «tope por día» pasa a «ventana rodante de 24 h».
16
- - El backend sigue sirviendo `POST /api/chat` para las instalaciones de 0.1.0 (1.0.0 ya no lo
17
- usa: el transporte pasó a Eve). `GET /api/chat/estado` es distinto: lo sondean las DOS
18
- versiones al montar el widget, y además el motor lo usa para «probar la instalación» — así
19
- que no queda libre para retirar el día que 0.1.0 se dé de baja. Retirar cualquiera de las dos
20
- es una decisión aparte, protegida por un test.
21
-
22
- ## 0.1.0 — 2026-08-19
23
-
24
- Primera publicación: transporte `useChat` de AI SDK, sondeo de estado, sin estilos configurables.
@@ -1,11 +0,0 @@
1
- export interface ContextoDelReporte {
2
- url?: string;
3
- versionApp?: string;
4
- }
5
- export declare function ChatDeIntake(props: {
6
- tenantId: string;
7
- projectId: string;
8
- backendUrl: string;
9
- contexto?: ContextoDelReporte;
10
- }): import("react").JSX.Element | null;
11
- //# sourceMappingURL=ChatDeIntake.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ChatDeIntake.d.ts","sourceRoot":"","sources":["../src/ChatDeIntake.tsx"],"names":[],"mappings":"AAYA,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B,sCAgFA"}
@@ -1,56 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useEveAgent } from "eve/react";
4
- import { useEffect, useMemo, useState } from "react";
5
- import { partesVisibles } from "./partes-visibles";
6
- import { decidirVisibilidad, mostrarIndicadorDeEscritura, normalizarBackendUrl, } from "./estado-del-widget";
7
- export function ChatDeIntake(props) {
8
- const [visibilidad, setVisibilidad] = useState("oculto");
9
- const [entrada, setEntrada] = useState("");
10
- const backendUrl = useMemo(() => normalizarBackendUrl(props.backendUrl), [props.backendUrl]);
11
- useEffect(() => {
12
- let vivo = true;
13
- fetch(`${backendUrl}/api/chat/estado?tenant_id=${encodeURIComponent(props.tenantId)}&project_id=${encodeURIComponent(props.projectId)}`)
14
- .then((r) => r.json())
15
- .then((cuerpo) => { if (vivo)
16
- setVisibilidad(decidirVisibilidad({ respuesta: cuerpo, huboError: false })); })
17
- .catch(() => { if (vivo)
18
- setVisibilidad(decidirVisibilidad({ respuesta: null, huboError: true })); });
19
- return () => { vivo = false; };
20
- }, [backendUrl, props.tenantId, props.projectId]);
21
- // `host`/`headers` son los nombres reales de `UseEveAgentOptions` (verificado contra
22
- // `eve/dist/src/react/use-eve-agent.d.ts`) — no "api"/"body" como en el `DefaultChatTransport`
23
- // viejo. Los dos headers son el borde de auth por proyecto que `agent/channels/eve.ts`
24
- // (tarea 4) exige: sin `x-supcoflow-project` el canal contesta 401 antes de tocar el agente.
25
- // Un mapa estático alcanza: `tenantId`/`projectId` son props fijas del montaje, igual que
26
- // `backendUrl` ya lo era para `canalId` en la versión vieja.
27
- const agent = useEveAgent({
28
- host: backendUrl,
29
- headers: {
30
- "x-supcoflow-tenant": props.tenantId,
31
- "x-supcoflow-project": props.projectId,
32
- },
33
- });
34
- // La misma política que el montaje: un error en medio de la conversación repliega el panel.
35
- useEffect(() => { if (agent.error !== undefined)
36
- setVisibilidad("oculto"); }, [agent.error]);
37
- if (visibilidad === "oculto")
38
- return null;
39
- const mensajes = agent.data.messages;
40
- // Entre Enviar y el primer token del stream pasan 4-8 s en el peor caso (hallazgo de la
41
- // pasada visual: el dueño lo leyó como "se rompió el botón" con la pantalla en silencio).
42
- // El indicador cubre ese hueco sin prometer nada sobre CUÁNTO va a tardar. `agent.status`
43
- // reemplaza al `status` de `useChat` con el mismo vocabulario para "submitted"/"streaming".
44
- const mostrarIndicador = mostrarIndicadorDeEscritura({
45
- status: agent.status,
46
- ultimoMensaje: mensajes[mensajes.length - 1],
47
- });
48
- return (_jsxs("div", { style: { border: "1px solid #ccc", borderRadius: 8, maxWidth: 420, display: "flex", flexDirection: "column", fontFamily: "inherit" }, children: [_jsxs("div", { style: { padding: 12, overflowY: "auto", maxHeight: 420, display: "flex", flexDirection: "column", gap: 8 }, children: [mensajes.map((m) => (_jsx("div", { style: { alignSelf: m.role === "user" ? "flex-end" : "flex-start", whiteSpace: "pre-wrap" }, children: partesVisibles(m.parts).map((p, i) => _jsx("span", { children: p.text }, i)) }, m.id))), mostrarIndicador && (_jsx("div", { style: { alignSelf: "flex-start", whiteSpace: "pre-wrap" }, "aria-live": "polite", children: "\u2026" }))] }), _jsxs("form", { style: { display: "flex", gap: 8, padding: 12, borderTop: "1px solid #ccc" }, onSubmit: (e) => {
49
- e.preventDefault();
50
- if (entrada.trim().length === 0 || agent.status !== "ready")
51
- return;
52
- void agent.send(entrada);
53
- setEntrada("");
54
- }, children: [_jsx("input", { style: { flex: 1 }, value: entrada, onChange: (e) => setEntrada(e.target.value), placeholder: "Pregunt\u00E1 o cont\u00E1 qu\u00E9 pas\u00F3\u2026", "aria-label": "Mensaje" }), _jsx("button", { type: "submit", disabled: agent.status !== "ready", children: "Enviar" })] })] }));
55
- }
56
- //# sourceMappingURL=ChatDeIntake.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ChatDeIntake.js","sourceRoot":"","sources":["../src/ChatDeIntake.tsx"],"names":[],"mappings":"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"}
@@ -1,46 +0,0 @@
1
- /** `crypto.randomUUID` no existe en un contexto no-seguro (un sitio embebido por HTTP
2
- * plano, no HTTPS) — sin este chequeo, el `useMemo` del widget lanza en el render y
3
- * tira abajo el host entero, justo lo opuesto a la promesa de "se oculta" del §8. El
4
- * fallback no necesita ser criptográfico: es un id de canal anónimo, no un secreto.
5
- *
6
- * `ChatDeIntake` dejó de llamar esta función: sobre `useEveAgent` el rol de identificar la
7
- * conversación lo cumple el `sessionId` que pone el backend. Queda EXPORTADA sin llamador
8
- * dentro de este paquete —no se borra especulativamente— porque `POST /api/chat`, el camino
9
- * viejo, sigue vivo hasta el corte, y es la ruta que necesita el concepto de "id de canal" del
10
- * lado del cliente. */
11
- export function generarCanalId() {
12
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
13
- return crypto.randomUUID();
14
- }
15
- return `canal_${Date.now()}_${Math.random().toString(36).slice(2)}`;
16
- }
17
- /** Una barra final en `backendUrl` ("https://x.com/", la forma más natural de
18
- * escribirlo) deja `//` duplicado en las URLs armadas más abajo: el motor responde con
19
- * un 308 sin headers de CORS y el navegador lo bloquea sin explicar que el problema es
20
- * la barra. Mismo patrón que `motor.ts` usa para su propia base URL. */
21
- export function normalizarBackendUrl(backendUrl) {
22
- return backendUrl.replace(/\/$/, "");
23
- }
24
- /** §8 del diseño: sin backend, sin tope, o ante cualquier duda, el widget NO se dibuja.
25
- * Ocultarse es lo honesto: no hay nada que decirle al usuario final sobre el estado interno
26
- * del proyecto de otra empresa. */
27
- export function decidirVisibilidad(h) {
28
- if (h.huboError || h.respuesta === null || !h.respuesta.ok)
29
- return "oculto";
30
- return "visible";
31
- }
32
- /** Entre Enviar y el primer token del stream pasan 4-8 s en el peor caso (medido en la pasada
33
- * visual del demo) — el backend responde perfecto, pero un silencio así se lee como "se rompió
34
- * el botón", no como "está pensando". Mostramos un indicador mientras el pedido está en vuelo
35
- * ("submitted") y mientras ya empezó a transmitir pero todavía no llegó texto del asistente
36
- * ("streaming" sin parts de texto no vacíos en el último mensaje). */
37
- export function mostrarIndicadorDeEscritura(h) {
38
- if (h.status === "submitted")
39
- return true;
40
- if (h.status !== "streaming")
41
- return false;
42
- const yaHayTexto = h.ultimoMensaje?.role === "assistant" &&
43
- h.ultimoMensaje.parts.some((p) => p.type === "text" && (p.text?.length ?? 0) > 0);
44
- return !yaHayTexto;
45
- }
46
- //# sourceMappingURL=estado-del-widget.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"estado-del-widget.js","sourceRoot":"","sources":["../src/estado-del-widget.ts"],"names":[],"mappings":"AAEA;;;;;;;;;uBASuB;AACvB,MAAM,UAAU,cAAc;IAC5B,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QAC7E,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO,SAAS,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACtE,CAAC;AAED;;;wEAGwE;AACxE,MAAM,UAAU,oBAAoB,CAAC,UAAkB;IACrD,OAAO,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC;AAED;;mCAEmC;AACnC,MAAM,UAAU,kBAAkB,CAAC,CAGlC;IACC,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC5E,OAAO,SAAS,CAAC;AACnB,CAAC;AAoBD;;;;sEAIsE;AACtE,MAAM,UAAU,2BAA2B,CAAC,CAG3C;IACC,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IAC3C,MAAM,UAAU,GACd,CAAC,CAAC,aAAa,EAAE,IAAI,KAAK,WAAW;QACrC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACpF,OAAO,CAAC,UAAU,CAAC;AACrB,CAAC"}
@@ -1,16 +0,0 @@
1
- /** El §6 del diseño: en el sitio del CLIENTE se dibuja solo texto. El reasoning streamea por
2
- * defecto en el protocolo de Eve, y el modelo razonando en crudo sobre el producto del
3
- * cliente delante de su usuario final no es una feature.
4
- *
5
- * El predicado de tipo (`p is Extract<P, { type: "text" }>`) es lo que hace que el llamador
6
- * pueda leer `p.text` sin volver a angostar: `EveMessagePart` es una unión con variantes que
7
- * NO tienen `text` (`dynamic-tool`, `file`, `step-start`, `authorization`), así que un filtro
8
- * sin predicado devolvería la unión completa y el acceso a `.text` no compilaría. El filtro en
9
- * sí es exactamente el que pide la tarea — comparar `p.type === "text"` — solo el tipo de
10
- * retorno cambió. */
11
- export declare function partesVisibles<P extends {
12
- type: string;
13
- }>(partes: readonly P[]): Extract<P, {
14
- type: "text";
15
- }>[];
16
- //# sourceMappingURL=partes-visibles.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"partes-visibles.d.ts","sourceRoot":"","sources":["../src/partes-visibles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;qBASqB;AACrB,wBAAgB,cAAc,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACvD,MAAM,EAAE,SAAS,CAAC,EAAE,GACnB,OAAO,CAAC,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,CAEhC"}
@@ -1,14 +0,0 @@
1
- /** El §6 del diseño: en el sitio del CLIENTE se dibuja solo texto. El reasoning streamea por
2
- * defecto en el protocolo de Eve, y el modelo razonando en crudo sobre el producto del
3
- * cliente delante de su usuario final no es una feature.
4
- *
5
- * El predicado de tipo (`p is Extract<P, { type: "text" }>`) es lo que hace que el llamador
6
- * pueda leer `p.text` sin volver a angostar: `EveMessagePart` es una unión con variantes que
7
- * NO tienen `text` (`dynamic-tool`, `file`, `step-start`, `authorization`), así que un filtro
8
- * sin predicado devolvería la unión completa y el acceso a `.text` no compilaría. El filtro en
9
- * sí es exactamente el que pide la tarea — comparar `p.type === "text"` — solo el tipo de
10
- * retorno cambió. */
11
- export function partesVisibles(partes) {
12
- return partes.filter((p) => p.type === "text");
13
- }
14
- //# sourceMappingURL=partes-visibles.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"partes-visibles.js","sourceRoot":"","sources":["../src/partes-visibles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;qBASqB;AACrB,MAAM,UAAU,cAAc,CAC5B,MAAoB;IAEpB,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAqC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;AACpF,CAAC"}