/** * Google Docs operation enum + esquema del formulario — una sola copia para la * api, el Dashboard y el broker. * * ── Lo que quita ── * La lista de cinco estaba escrita a mano **siete veces**: dos en la entidad * (enum de Mongoose y unión de tipos), dos en el DTO (enum de Swagger y `@IsIn`), * y tres en el dashboard (`lib/api.ts`, el array `OPERATIONS` de la página y el * `OP_LABELS` del lienzo). El `operation` del DTO era además un `string` pelado: * sólo lo sujetaba el `@IsIn` en tiempo de ejecución. * * ── Lo fácil de Docs ── * Como Mongo, **no hay capa de renombrado**: el `name` de cada param es la prop * de la entidad tal cual, y el `apiUpdate` de la página es un passthrough. El * ejecutor lee `entity.documentId`, `entity.contentTemplate`… con esos mismos * nombres. * * ── El orden de pantalla, y por qué cambió ── * Hoy es el mismo que en Sheets, Drive, Telegram, Mongo y Postgres — primero * qué hacer, luego sobre qué: * * ── selector de operación ── * DocumentPicker + pegar ID (o el título, si es createDoc) * Content / Search+Replace / Rows+Columns * * Estuvo al revés, con el desplegable EN MEDIO y el razonamiento «qué documento * → qué hacer → con qué», y este comentario decía que un refactor no debía * tocarlo. Se cambió a propósito el 2026-08-12 (dashboard#128) por dos motivos: * la operación es la que decide QUÉ CAMPOS aparecen —`createDoc` ni siquiera * pide documento, pide título—, y ser el único nodo con otro orden es una * sorpresa por nodo. * * Los `slot` siguen haciendo falta: separan la identidad del documento de los * campos de la operación, aunque ahora las dos vayan debajo del selector. Un * bucle único ordenaría por el array de params y no por ese criterio. * * ── Qué exige el motor (y por qué está escrito aquí) ── * Este esquema declaraba CERO obligatorios en las cinco operaciones, y el * ejecutor —`api/src/nodes/docs-actions/docs-actions.service.ts`— rechaza cinco * cosas. Esa distancia no se veía como un error de validación sino como un * nodo que no guía: sin ningún obligatorio no hay nada que esperar, ningún paso * desbloquea al siguiente, y el guiado que el panel SÍ monta no se nota. * * Los cinco 400 del ejecutor, uno por línea, que son los cinco `required` de * este fichero: * * :323 readDoc documentId 'Document ID is required' * :440 appendText documentId 'Document ID is required' * :447 appendText contentTemplate 'Content template is required' * :498 replaceText documentId 'Document ID is required' * :505 replaceText searchText 'Search text is required' * :560 insertTable documentId 'Document ID is required' * * Y los cuatro que NO se marcan, con el defecto que los salva: `documentTitle` * cae en `entity.name`, `contentTemplate` de `createDoc` en un documento vacío, * `tableRows`/`tableCols` en `|| 3`, y `replaceWith` vacío es un BORRADO, no un * hueco. Cada uno lo explica en su sitio. */ export declare const DOCS_OPERATIONS: readonly ["readDoc", "createDoc", "appendText", "replaceText", "insertTable"]; export type DocsOperation = (typeof DOCS_OPERATIONS)[number]; /** Type guard — útil al validar entrada que no controlas (DTOs, tool calls). */ export declare function isDocsOperation(value: unknown): value is DocsOperation; export type DocsParamType = /** * El `DocumentPicker` en vivo (lista los Docs de la credencial) **y** debajo * un `TemplateInput` para pegar un ID o una plantilla. Son dos controles para * un solo campo, como el `driveFile` de Drive. */ 'docPicker' /** `TemplateInput`: una línea con autocompletado de `{{payload.*}}`. */ | 'template' /** `TemplateEditor` con `language="html"`. Ya no lo usa ningún param de * Docs (ver `markdownTemplate`); se conserva por si vuelve a hacer falta. */ | 'htmlTemplate' /** * `MarkdownField`: una caja de texto con pestañas Write / Preview y la * leyenda de la sintaxis (`# Título`, `**negrita**`, `- lista`, `[enlace]`). * * [2026-09-12] El `Content` de Docs era `htmlTemplate` —un editor de HTML * con Beautify— y la api lo metía en el documento con `insertText`, TAL CUAL: * un `