@hostwebhook/platform-contracts 0.1.0 → 0.3.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 (66) hide show
  1. package/README.md +64 -4
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +2 -0
  4. package/dist/operadores.d.ts +60 -0
  5. package/dist/operadores.js +123 -0
  6. package/dist/servicios/almacenes-vectoriales.d.ts +105 -0
  7. package/dist/servicios/almacenes-vectoriales.js +26 -0
  8. package/dist/servicios/aprobaciones-pendientes.d.ts +207 -0
  9. package/dist/servicios/aprobaciones-pendientes.js +51 -0
  10. package/dist/servicios/avisos-en-vivo.d.ts +106 -0
  11. package/dist/servicios/avisos-en-vivo.js +60 -0
  12. package/dist/servicios/canal-de-stream.d.ts +78 -0
  13. package/dist/servicios/canal-de-stream.js +5 -0
  14. package/dist/servicios/conversaciones-del-chat.d.ts +139 -0
  15. package/dist/servicios/conversaciones-del-chat.js +51 -0
  16. package/dist/servicios/corridas-programadas.d.ts +29 -0
  17. package/dist/servicios/corridas-programadas.js +5 -0
  18. package/dist/servicios/credencial/permiso-sobre-credencial.d.ts +61 -0
  19. package/dist/servicios/credencial/permiso-sobre-credencial.js +42 -0
  20. package/dist/servicios/credenciales-del-gateway.d.ts +722 -0
  21. package/dist/servicios/credenciales-del-gateway.js +114 -0
  22. package/dist/servicios/cuentas-de-atlassian.d.ts +22 -0
  23. package/dist/servicios/cuentas-de-atlassian.js +5 -0
  24. package/dist/servicios/descarga-de-drive.d.ts +74 -0
  25. package/dist/servicios/descarga-de-drive.js +41 -0
  26. package/dist/servicios/ejecucion-de-ia.d.ts +81 -0
  27. package/dist/servicios/ejecucion-de-ia.js +39 -0
  28. package/dist/servicios/enlaces-de-flujo.d.ts +59 -0
  29. package/dist/servicios/enlaces-de-flujo.js +27 -0
  30. package/dist/servicios/ficheros-del-gateway.d.ts +210 -0
  31. package/dist/servicios/ficheros-del-gateway.js +8 -0
  32. package/dist/servicios/formas-compartidas.d.ts +57 -0
  33. package/dist/servicios/formas-compartidas.js +22 -0
  34. package/dist/servicios/historial-de-corridas.d.ts +75 -0
  35. package/dist/servicios/historial-de-corridas.js +7 -0
  36. package/dist/servicios/index.d.ts +57 -0
  37. package/dist/servicios/index.js +44 -0
  38. package/dist/servicios/limites-del-plan.d.ts +82 -0
  39. package/dist/servicios/limites-del-plan.js +41 -0
  40. package/dist/servicios/motor-de-ejecucion.d.ts +197 -0
  41. package/dist/servicios/motor-de-ejecucion.js +11 -0
  42. package/dist/servicios/plantillas-de-origen.d.ts +25 -0
  43. package/dist/servicios/plantillas-de-origen.js +5 -0
  44. package/dist/servicios/posts-sociales.d.ts +69 -0
  45. package/dist/servicios/posts-sociales.js +23 -0
  46. package/dist/servicios/registro-de-entregas.d.ts +93 -0
  47. package/dist/servicios/registro-de-entregas.js +46 -0
  48. package/dist/servicios/registro-de-eventos.d.ts +135 -0
  49. package/dist/servicios/registro-de-eventos.js +62 -0
  50. package/dist/servicios/restauracion-de-nodos.d.ts +53 -0
  51. package/dist/servicios/restauracion-de-nodos.js +4 -0
  52. package/dist/servicios/salud-del-webhook.d.ts +26 -0
  53. package/dist/servicios/salud-del-webhook.js +6 -0
  54. package/dist/servicios/secretos-de-firma.d.ts +26 -0
  55. package/dist/servicios/secretos-de-firma.js +5 -0
  56. package/dist/servicios/telemetria.d.ts +114 -0
  57. package/dist/servicios/telemetria.js +60 -0
  58. package/dist/servicios/trazas-de-llm.d.ts +79 -0
  59. package/dist/servicios/trazas-de-llm.js +23 -0
  60. package/dist/servicios/tuneles.d.ts +106 -0
  61. package/dist/servicios/tuneles.js +87 -0
  62. package/dist/servicios/workspace/acceso-al-recurso.d.ts +39 -0
  63. package/dist/servicios/workspace/acceso-al-recurso.js +5 -0
  64. package/dist/servicios/zona-horaria-del-usuario.d.ts +40 -0
  65. package/dist/servicios/zona-horaria-del-usuario.js +7 -0
  66. package/package.json +9 -3
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Lo que el nodo de redes le pide al calendario de publicaciones.
3
+ *
4
+ * Costura de la Fase 2, del lote de las pequeñas. `SocialPostsService`
5
+ * arrastra la colección de posts, el planificador por zona horaria y el
6
+ * publicador con sus siete proveedores. El nodo publica y deja constancia.
7
+ *
8
+ * ## Cómo viaja
9
+ *
10
+ * ⚠️ `publicarDesdeNodo` devolvía un documento de Mongoose. Su llamante lee
11
+ * TRES campos —`id`, `status` y `results`— y nada más; se comprobó llamante
12
+ * por llamante. El contrato devuelve esos tres, planos.
13
+ *
14
+ * ⚠️ `publishApproved` devuelve `null` cuando el post sigue esperando su hora,
15
+ * y eso NO es un error: el llamante lo distingue en el log («sigue esperando
16
+ * su hora»). Un contrato que lanzara en vez de devolver `null` convertiría un
17
+ * caso normal en un fallo.
18
+ */
19
+ /** Una fila por (red × cuenta): de aquí sale el `3/7` del parcial. */
20
+ export interface ResultadoDePublicacion {
21
+ platform: string;
22
+ credentialId: string;
23
+ success: boolean;
24
+ url?: string;
25
+ error?: string;
26
+ }
27
+ /** Lo que el nodo lee de un post recién creado. Tres campos. */
28
+ export interface PostCreado {
29
+ id: string;
30
+ status: string;
31
+ results: ResultadoDePublicacion[];
32
+ }
33
+ export interface PostsSociales {
34
+ publicarDesdeNodo(params: {
35
+ orgId: string;
36
+ workspaceId: string;
37
+ ownerUserId: string;
38
+ sourceNodeId?: string;
39
+ entityName?: string;
40
+ platforms: string[];
41
+ credentialIds: Record<string, string[]>;
42
+ text: string;
43
+ media?: Array<Record<string, unknown>>;
44
+ perNetwork?: Record<string, {
45
+ text?: string;
46
+ media?: unknown[];
47
+ }>;
48
+ }): Promise<PostCreado>;
49
+ /** Deja constancia de lo que ya publicó el flujo por su cuenta. */
50
+ recordFlowPost(params: {
51
+ orgId: string;
52
+ workspaceId: string;
53
+ sourceNodeId?: string;
54
+ text?: string;
55
+ media?: Array<Record<string, unknown>>;
56
+ results: Array<{
57
+ platform: string;
58
+ credentialId: string;
59
+ success: boolean;
60
+ url?: string;
61
+ error?: string;
62
+ }>;
63
+ }): Promise<void>;
64
+ /** ⚠️ `null` = aprobado pero aún no le toca. No es un error. */
65
+ publishApproved(postId: string, porQuien?: string): Promise<string | null>;
66
+ rejectApproval(postId: string, porQuien?: string): Promise<void>;
67
+ }
68
+ /** ⚠️ Cadena y no `Symbol`, igual que el resto de tokens de la Fase 2. */
69
+ export declare const POSTS_SOCIALES = "POSTS_SOCIALES";
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ /**
3
+ * Lo que el nodo de redes le pide al calendario de publicaciones.
4
+ *
5
+ * Costura de la Fase 2, del lote de las pequeñas. `SocialPostsService`
6
+ * arrastra la colección de posts, el planificador por zona horaria y el
7
+ * publicador con sus siete proveedores. El nodo publica y deja constancia.
8
+ *
9
+ * ## Cómo viaja
10
+ *
11
+ * ⚠️ `publicarDesdeNodo` devolvía un documento de Mongoose. Su llamante lee
12
+ * TRES campos —`id`, `status` y `results`— y nada más; se comprobó llamante
13
+ * por llamante. El contrato devuelve esos tres, planos.
14
+ *
15
+ * ⚠️ `publishApproved` devuelve `null` cuando el post sigue esperando su hora,
16
+ * y eso NO es un error: el llamante lo distingue en el log («sigue esperando
17
+ * su hora»). Un contrato que lanzara en vez de devolver `null` convertiría un
18
+ * caso normal en un fallo.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.POSTS_SOCIALES = void 0;
22
+ /** ⚠️ Cadena y no `Symbol`, igual que el resto de tokens de la Fase 2. */
23
+ exports.POSTS_SOCIALES = 'POSTS_SOCIALES';
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Lo que el motor apunta y consulta sobre las entregas.
3
+ *
4
+ * ## Por qué esta costura es distinta de las trece anteriores
5
+ *
6
+ * Las otras invertían un SERVICIO. Ésta invierte el acceso directo a una
7
+ * COLECCIÓN: `nodes/` y el motor inyectaban `Model<DeliveryDocument>` y
8
+ * consultaban `deliveries` a mano.
9
+ *
10
+ * Por eso se dejó fuera del lote del #468: cerrarla obliga a decidir de quién
11
+ * es la colección. La respuesta, mirando lo que se hace con ella, es que es
12
+ * del gateway — `deliveries` es lo que el panel enseña como historial de
13
+ * entregas, tiene su propia política de retención en `plans/` y su controlador
14
+ * de reintentos. El motor sólo escribe filas y pregunta si ya escribió una.
15
+ *
16
+ * ## Las tres operaciones, medidas
17
+ *
18
+ * 3 `exists` la comprobación de IDEMPOTENCIA de email, sheets y
19
+ * notificaciones
20
+ * 3 `create` la fila de cada entrega, con la misma forma las tres
21
+ * 2 `deleteMany` las dos cascadas: por webhook y por evento
22
+ *
23
+ * ## ⚠️ Lo que no se puede perder
24
+ *
25
+ * **`soloSiTuvoExito`.** El chequeo de notificaciones añade `success: true` al
26
+ * filtro cuando `triggerOn` NO es `'always'`. Perder esa condición tiene dos
27
+ * caras y las dos son malas: sin ella, una notificación que falló cuenta como
28
+ * entregada y no se reintenta nunca; con ella siempre puesta, una que sí se
29
+ * mandó se manda otra vez en cada reintento del evento.
30
+ *
31
+ * **`refIdIn` en el borrado.** `webhookId` se guarda como cadena en unas filas
32
+ * y como `ObjectId` en otras. Filtrar por una sola forma deja la mitad de las
33
+ * entregas huérfanas — que es justo lo que la cascada existe para evitar. El
34
+ * contrato recibe los ids en crudo y la conversión se queda en el gateway,
35
+ * donde vive el problema.
36
+ *
37
+ * ## Cómo viaja
38
+ *
39
+ * Bien: entran y salen datos planos, y `anotar` es «dispara y olvida» —el SDK
40
+ * ya la llama con `.catch()` colgado, sin esperarla—.
41
+ */
42
+ /** Una fila del historial de entregas. */
43
+ export interface EntregaAnotada {
44
+ eventId: string;
45
+ webhookId?: string;
46
+ emailActionId?: string;
47
+ sheetsActionId?: string;
48
+ notificationActionId?: string;
49
+ targetUrl?: string;
50
+ attempt?: number;
51
+ statusCode?: number;
52
+ responseBody?: string;
53
+ latencyMs?: number;
54
+ success?: boolean;
55
+ error?: string | null;
56
+ }
57
+ export interface RegistroDeEntregas {
58
+ /**
59
+ * ¿Ya se entregó esto para este evento?
60
+ *
61
+ * ⚠️ `soloSiTuvoExito` NO es opcional en el sentido de «da igual»: cambia
62
+ * qué cuenta como entregado. Ver la cabecera.
63
+ */
64
+ yaSeEntrego(filtro: {
65
+ eventId: string;
66
+ emailActionId?: string;
67
+ sheetsActionId?: string;
68
+ notificationActionId?: string;
69
+ soloSiTuvoExito?: boolean;
70
+ }): Promise<boolean>;
71
+ /** ⚠️ No se espera. El SDK la llama con un `.catch()` colgado. */
72
+ anotar(entrega: EntregaAnotada): Promise<void>;
73
+ /**
74
+ * La cascada al borrar webhooks.
75
+ *
76
+ * ⚠️ Recibe los ids en crudo a propósito: la conversión a las dos formas en
77
+ * que se guardan —cadena y `ObjectId`— se queda en el gateway. Ver la
78
+ * cabecera.
79
+ */
80
+ borrarDeWebhooks(webhookIds: ReadonlyArray<string>): Promise<void>;
81
+ /**
82
+ * La otra cascada: al borrar un trigger, sus entregas.
83
+ *
84
+ * ⚠️ Va por `eventId` y NO por `webhookId`, y ésa es toda la razón de que
85
+ * sean dos métodos. Las entregas se indexan por el evento; el llamante tiene
86
+ * que recoger los ids de evento ANTES de borrar los eventos, porque después
87
+ * no queda nada por lo que resolverlos y se quedan huérfanas en silencio.
88
+ * Ver `cascade-trigger-events.ts`, que existe justo por eso.
89
+ */
90
+ borrarDeEventos(eventIds: ReadonlyArray<string>): Promise<void>;
91
+ }
92
+ /** ⚠️ Cadena y no `Symbol`, igual que el resto de tokens de la Fase 2. */
93
+ export declare const REGISTRO_DE_ENTREGAS = "REGISTRO_DE_ENTREGAS";
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /**
3
+ * Lo que el motor apunta y consulta sobre las entregas.
4
+ *
5
+ * ## Por qué esta costura es distinta de las trece anteriores
6
+ *
7
+ * Las otras invertían un SERVICIO. Ésta invierte el acceso directo a una
8
+ * COLECCIÓN: `nodes/` y el motor inyectaban `Model<DeliveryDocument>` y
9
+ * consultaban `deliveries` a mano.
10
+ *
11
+ * Por eso se dejó fuera del lote del #468: cerrarla obliga a decidir de quién
12
+ * es la colección. La respuesta, mirando lo que se hace con ella, es que es
13
+ * del gateway — `deliveries` es lo que el panel enseña como historial de
14
+ * entregas, tiene su propia política de retención en `plans/` y su controlador
15
+ * de reintentos. El motor sólo escribe filas y pregunta si ya escribió una.
16
+ *
17
+ * ## Las tres operaciones, medidas
18
+ *
19
+ * 3 `exists` la comprobación de IDEMPOTENCIA de email, sheets y
20
+ * notificaciones
21
+ * 3 `create` la fila de cada entrega, con la misma forma las tres
22
+ * 2 `deleteMany` las dos cascadas: por webhook y por evento
23
+ *
24
+ * ## ⚠️ Lo que no se puede perder
25
+ *
26
+ * **`soloSiTuvoExito`.** El chequeo de notificaciones añade `success: true` al
27
+ * filtro cuando `triggerOn` NO es `'always'`. Perder esa condición tiene dos
28
+ * caras y las dos son malas: sin ella, una notificación que falló cuenta como
29
+ * entregada y no se reintenta nunca; con ella siempre puesta, una que sí se
30
+ * mandó se manda otra vez en cada reintento del evento.
31
+ *
32
+ * **`refIdIn` en el borrado.** `webhookId` se guarda como cadena en unas filas
33
+ * y como `ObjectId` en otras. Filtrar por una sola forma deja la mitad de las
34
+ * entregas huérfanas — que es justo lo que la cascada existe para evitar. El
35
+ * contrato recibe los ids en crudo y la conversión se queda en el gateway,
36
+ * donde vive el problema.
37
+ *
38
+ * ## Cómo viaja
39
+ *
40
+ * Bien: entran y salen datos planos, y `anotar` es «dispara y olvida» —el SDK
41
+ * ya la llama con `.catch()` colgado, sin esperarla—.
42
+ */
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.REGISTRO_DE_ENTREGAS = void 0;
45
+ /** ⚠️ Cadena y no `Symbol`, igual que el resto de tokens de la Fase 2. */
46
+ exports.REGISTRO_DE_ENTREGAS = 'REGISTRO_DE_ENTREGAS';
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Lo que un nodo apunta y pregunta sobre eventos.
3
+ *
4
+ * ## ⚠️ Esta costura es MUCHO más pequeña de lo que el conteo decía
5
+ *
6
+ * `nodes/` y `common/` tocan el modelo de eventos en seis ficheros y con una
7
+ * superficie grande —`create` ×10, `findById` ×5, `findByIdAndUpdate` ×5,
8
+ * `hydrate`, `aggregate`, incluso `db.db` en crudo—. Con ese número, esto
9
+ * parecía la costura más cara de la fase.
10
+ *
11
+ * Lo es sólo si uno olvida leer el plan. `event-pipeline` y `pipeline-run`
12
+ * **se quedan en el gateway**: este servicio ejecuta nodos, no orquesta
13
+ * corridas. Y `agent-context` también es del gateway. O sea que casi toda esa
14
+ * superficie es del motor consultando SU PROPIA colección de trabajo, y no
15
+ * hay nada que invertir ahí.
16
+ *
17
+ * Lo que de verdad viaja son tres ficheros y tres operaciones:
18
+ *
19
+ * `triggers.service` crea el evento de un empujón externo
20
+ * `scheduled-workflows.processor` crea el de un cron
21
+ * `webhooks.service` cuenta para las estadísticas y borra en
22
+ * cascada
23
+ *
24
+ * ⚠️ Y `common/node-handlers.ts` lo inyectaba sin usarlo NUNCA. Fuera.
25
+ *
26
+ * ## Cómo viaja
27
+ *
28
+ * Bien: entra un objeto plano y sale lo que el llamante lee. De los tres
29
+ * `create`, dos DESCARTAN el resultado y sólo el del cron le lee dos campos.
30
+ */
31
+ /**
32
+ * En qué estado está un evento.
33
+ *
34
+ * ⚠️ Vivía en `events/event.entity.ts`, junto al esquema de Mongoose. Es un
35
+ * enum puro y los nodos lo necesitan, así que se muda aquí y allí queda el
36
+ * reenvío — mismo reparto que `Audited` o `PasoEjecutado`.
37
+ */
38
+ export declare enum EstadoDeEvento {
39
+ PENDING = "pending",
40
+ DELIVERED = "delivered",
41
+ FAILED = "failed",
42
+ RETRYING = "retrying",
43
+ FILTERED = "filtered",
44
+ SCHEMA_INVALID = "schema_invalid",
45
+ AWAITING_APPROVAL = "awaiting_approval",
46
+ DELAYED = "delayed",
47
+ DEDUPLICATED = "deduplicated",
48
+ RATE_LIMITED = "rate_limited",
49
+ IP_BLOCKED = "ip_blocked",
50
+ SIGNATURE_INVALID = "signature_invalid",
51
+ /** Payload contained a `_file` ref that the malware scanner flagged
52
+ * as infected or scan_failed. Distinct from FAILED so dashboards
53
+ * and stats can highlight security blocks separately from
54
+ * delivery errors. */
55
+ MALICIOUS_FILE = "malicious_file"
56
+ }
57
+ /** Un evento que entra al sistema. */
58
+ export interface EventoEntrante {
59
+ /** El nodo fuente que lo produjo: webhook, trigger o programado. */
60
+ webhookId: string;
61
+ payload: unknown;
62
+ rawBody: string;
63
+ headers: Record<string, string>;
64
+ sourceIp: string;
65
+ status: string;
66
+ /** ⚠️ Opcional: el trigger no lo pone y el esquema tiene su valor por
67
+ * defecto. Exigirlo aquí obligaría a inventárselo en el llamante. */
68
+ eventType?: string;
69
+ attemptCount?: number;
70
+ /**
71
+ * La corrida a la que pertenece.
72
+ *
73
+ * ⚠️ Ausente significa «este evento ABRE una corrida», y entonces la abre
74
+ * con su propio id. No es lo mismo que ponerlo a `null`.
75
+ */
76
+ correlationId?: string;
77
+ /**
78
+ * La llave con que se reconoce un empujón repetido del proveedor.
79
+ *
80
+ * ⚠️ Gmail, Drive y compañía reenvían la misma notificación más de una vez.
81
+ * Sin esto, un cambio se despacha dos veces.
82
+ */
83
+ idempotencyKey?: string;
84
+ }
85
+ /** Lo que el llamante lee de un evento recién creado. Dos campos. */
86
+ export interface EventoCreado {
87
+ id: string;
88
+ correlationId?: string;
89
+ }
90
+ export interface RegistroDeEventos {
91
+ /**
92
+ * ⚠️ Devuelve datos planos, no el documento. Se comprobó llamante por
93
+ * llamante: dos de los tres tiran el resultado y el tercero lee `id` y
94
+ * `correlationId` para enhebrar la corrida.
95
+ */
96
+ crear(evento: EventoEntrante): Promise<EventoCreado>;
97
+ /**
98
+ * Cuántos eventos tiene un webhook, para el `successRate` del panel.
99
+ *
100
+ * ⚠️ `soloEntregados` cambia la pregunta, no la afina: sin él es el
101
+ * denominador y con él el numerador. Y las pruebas NO cuentan —`isTest`
102
+ * queda fuera siempre—, porque un webhook que se probó diez veces tendría
103
+ * un porcentaje que no describe su tráfico real.
104
+ */
105
+ contarDeWebhook(webhookId: string, opts?: {
106
+ soloEntregados?: boolean;
107
+ }): Promise<number>;
108
+ /**
109
+ * La cascada al borrar webhooks.
110
+ *
111
+ * ⚠️ Los ids van en crudo: `webhookId` se guarda como cadena en unas filas
112
+ * y como `ObjectId` en otras, y esa conversión se queda en el gateway,
113
+ * donde vive el problema. Mismo reparto que el registro de entregas.
114
+ */
115
+ borrarDeWebhooks(webhookIds: ReadonlyArray<string>): Promise<void>;
116
+ /**
117
+ * ¿Ya se despachó este empujón?
118
+ *
119
+ * ⚠️ Falla ABIERTO y hay que conservarlo: si la consulta revienta devuelve
120
+ * `false` —«no lo he visto»— y el evento se despacha igual. El peor caso es
121
+ * un duplicado aguas abajo; el otro camino es tragarse un cambio real en
122
+ * silencio, que es mucho peor y no deja rastro.
123
+ */
124
+ yaSeDespacho(webhookId: string, idempotencyKey: string): Promise<boolean>;
125
+ /**
126
+ * Los ids de los eventos de un nodo fuente.
127
+ *
128
+ * ⚠️ Se recogen ANTES de borrarlos: las entregas se indexan por `eventId`,
129
+ * y una vez borrados los eventos no queda nada por lo que resolverlas.
130
+ * Ver `cascade-trigger-events.ts`.
131
+ */
132
+ idsDeWebhook(webhookId: string): Promise<string[]>;
133
+ }
134
+ /** ⚠️ Cadena y no `Symbol`, igual que el resto de tokens de la Fase 2. */
135
+ export declare const REGISTRO_DE_EVENTOS = "REGISTRO_DE_EVENTOS";
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * Lo que un nodo apunta y pregunta sobre eventos.
4
+ *
5
+ * ## ⚠️ Esta costura es MUCHO más pequeña de lo que el conteo decía
6
+ *
7
+ * `nodes/` y `common/` tocan el modelo de eventos en seis ficheros y con una
8
+ * superficie grande —`create` ×10, `findById` ×5, `findByIdAndUpdate` ×5,
9
+ * `hydrate`, `aggregate`, incluso `db.db` en crudo—. Con ese número, esto
10
+ * parecía la costura más cara de la fase.
11
+ *
12
+ * Lo es sólo si uno olvida leer el plan. `event-pipeline` y `pipeline-run`
13
+ * **se quedan en el gateway**: este servicio ejecuta nodos, no orquesta
14
+ * corridas. Y `agent-context` también es del gateway. O sea que casi toda esa
15
+ * superficie es del motor consultando SU PROPIA colección de trabajo, y no
16
+ * hay nada que invertir ahí.
17
+ *
18
+ * Lo que de verdad viaja son tres ficheros y tres operaciones:
19
+ *
20
+ * `triggers.service` crea el evento de un empujón externo
21
+ * `scheduled-workflows.processor` crea el de un cron
22
+ * `webhooks.service` cuenta para las estadísticas y borra en
23
+ * cascada
24
+ *
25
+ * ⚠️ Y `common/node-handlers.ts` lo inyectaba sin usarlo NUNCA. Fuera.
26
+ *
27
+ * ## Cómo viaja
28
+ *
29
+ * Bien: entra un objeto plano y sale lo que el llamante lee. De los tres
30
+ * `create`, dos DESCARTAN el resultado y sólo el del cron le lee dos campos.
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.REGISTRO_DE_EVENTOS = exports.EstadoDeEvento = void 0;
34
+ /**
35
+ * En qué estado está un evento.
36
+ *
37
+ * ⚠️ Vivía en `events/event.entity.ts`, junto al esquema de Mongoose. Es un
38
+ * enum puro y los nodos lo necesitan, así que se muda aquí y allí queda el
39
+ * reenvío — mismo reparto que `Audited` o `PasoEjecutado`.
40
+ */
41
+ var EstadoDeEvento;
42
+ (function (EstadoDeEvento) {
43
+ EstadoDeEvento["PENDING"] = "pending";
44
+ EstadoDeEvento["DELIVERED"] = "delivered";
45
+ EstadoDeEvento["FAILED"] = "failed";
46
+ EstadoDeEvento["RETRYING"] = "retrying";
47
+ EstadoDeEvento["FILTERED"] = "filtered";
48
+ EstadoDeEvento["SCHEMA_INVALID"] = "schema_invalid";
49
+ EstadoDeEvento["AWAITING_APPROVAL"] = "awaiting_approval";
50
+ EstadoDeEvento["DELAYED"] = "delayed";
51
+ EstadoDeEvento["DEDUPLICATED"] = "deduplicated";
52
+ EstadoDeEvento["RATE_LIMITED"] = "rate_limited";
53
+ EstadoDeEvento["IP_BLOCKED"] = "ip_blocked";
54
+ EstadoDeEvento["SIGNATURE_INVALID"] = "signature_invalid";
55
+ /** Payload contained a `_file` ref that the malware scanner flagged
56
+ * as infected or scan_failed. Distinct from FAILED so dashboards
57
+ * and stats can highlight security blocks separately from
58
+ * delivery errors. */
59
+ EstadoDeEvento["MALICIOUS_FILE"] = "malicious_file";
60
+ })(EstadoDeEvento || (exports.EstadoDeEvento = EstadoDeEvento = {}));
61
+ /** ⚠️ Cadena y no `Symbol`, igual que el resto de tokens de la Fase 2. */
62
+ exports.REGISTRO_DE_EVENTOS = 'REGISTRO_DE_EVENTOS';
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Restaurar las entidades de nodo de un snapshot del lienzo.
3
+ *
4
+ * ## Por qué esto es un contrato y no una lectura cruda
5
+ *
6
+ * `agent-context` dejó de necesitar las entidades leyendo las colecciones a
7
+ * pelo (api#555). Aquí no vale, y la diferencia es de una palabra: **aquí se
8
+ * escribe**.
9
+ *
10
+ * `model.create` aplica los `default`, el casteo y las validaciones del
11
+ * esquema. Un `insertOne` crudo no aplica ninguno, así que un snapshot viejo
12
+ * restaurado contra un esquema nuevo saldría sin los campos que el esquema
13
+ * habría rellenado — y eso no falla al escribir, falla mucho más tarde, en
14
+ * quien lee. La escritura tiene que ocurrir donde vive el esquema.
15
+ *
16
+ * ## Y por eso la restauración es de los dos lados
17
+ *
18
+ * Un lienzo mezcla nodos de origen —del gateway— con nodos de acción, que se
19
+ * van a hw-nodes. De las cuarenta y nueve claves que un snapshot puede traer, **cinco
20
+ * son del gateway** —los cinco nodos de ORIGEN, que es exactamente la frontera
21
+ * del corte— y **cuarenta y cuatro se van**.
22
+ *
23
+ * Así que los dos lados reciben el snapshot ENTERO y cada uno escribe su
24
+ * parte: el bucle vive en `@hostwebhook/node-sdk` y a cada lado se le pasan sus
25
+ * modelos. Una clave que un lado no posee se salta sin contarla.
26
+ *
27
+ * ⚠️ La caché del lienzo se tira UNA vez, cuando han terminado los dos. Por eso
28
+ * el contrato devuelve los workspaces tocados en vez de invalidar por su
29
+ * cuenta: invalidar antes de que el otro lado haya escrito devuelve el grafo
30
+ * viejo durante 30 s, que es justo el momento en el que nadie se cree que la
31
+ * restauración haya funcionado.
32
+ */
33
+ export interface RestauracionDeNodos {
34
+ /**
35
+ * Las claves del snapshot que este lado sabe escribir.
36
+ *
37
+ * ⚠️ Se pregunta, no se escribe a mano en el gateway: un segundo mapa que se
38
+ * queda viejo es exactamente cómo se perdió `mailchimpAction` del registro de
39
+ * conexiones. El que sabe qué nodos tiene es quien los tiene.
40
+ */
41
+ clavesQueRestaura(): string[];
42
+ restaurar(peticion: {
43
+ /** El `entities` del snapshot, entero — el otro lado ignora lo que no es suyo. */
44
+ entidades: Record<string, unknown[]>;
45
+ orgId: string;
46
+ /** Quien restaura. La identidad del nodo se rederiva de aquí, no del snapshot. */
47
+ userId: string;
48
+ }): Promise<{
49
+ contadores: Record<string, number>;
50
+ workspacesTocados: string[];
51
+ }>;
52
+ }
53
+ export declare const RESTAURACION_DE_NODOS = "RESTAURACION_DE_NODOS";
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RESTAURACION_DE_NODOS = void 0;
4
+ exports.RESTAURACION_DE_NODOS = 'RESTAURACION_DE_NODOS';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Lo que el motor necesita del comprobador de salud del webhook. UN método.
3
+ *
4
+ * ## Por qué
5
+ *
6
+ * `event-pipeline` llama a `HealthCheckerService.startRecovery(webhookId)`
7
+ * cuando un webhook pasa a `down` y tiene la recuperación automática puesta.
8
+ * Es la ÚNICA llamada: medido, `startRecovery` y nada más.
9
+ *
10
+ * El motor viaja a hw-nodes; `webhooks` es uno de los cinco nodos de origen que
11
+ * se quedan en el gateway. Sin esto, el motor arrastra un servicio del gateway
12
+ * entero por un método de cuatro líneas.
13
+ *
14
+ * ## Lo que cruza
15
+ *
16
+ * Un id y nada más. No hay respuesta que esperar: quien llama lo lanza con
17
+ * `void`, porque arrancar la recuperación no puede retrasar el despacho del
18
+ * evento que la disparó.
19
+ */
20
+ export interface SaludDelWebhook {
21
+ /** Marca el webhook como «recuperándose». No devuelve nada. */
22
+ arrancarRecuperacion(webhookId: string): Promise<void>;
23
+ }
24
+ /** ⚠️ Cadena y no `Symbol`: un `Symbol` no sobrevive a una frontera de módulo
25
+ * duplicada. */
26
+ export declare const SALUD_DEL_WEBHOOK = "SALUD_DEL_WEBHOOK";
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SALUD_DEL_WEBHOOK = void 0;
4
+ /** ⚠️ Cadena y no `Symbol`: un `Symbol` no sobrevive a una frontera de módulo
5
+ * duplicada. */
6
+ exports.SALUD_DEL_WEBHOOK = 'SALUD_DEL_WEBHOOK';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Si un secreto de firma es de esta organización. Una pregunta.
3
+ *
4
+ * Costura de la Fase 2, del lote de las pequeñas. `webhooks.service` hacía
5
+ * `connection.model(SigningSecret.name).collection.findOne(...)` — o sea,
6
+ * consultaba una colección de OTRO dominio a través de la conexión, sólo para
7
+ * comprobar que el id que llega en el cuerpo es suyo.
8
+ *
9
+ * ⚠️ Importaba la clase de la entidad para usar su `.name` como cadena. Eso
10
+ * arrastra el fichero de la entidad entero —con sus decoradores de Mongoose—
11
+ * para leerle una palabra.
12
+ *
13
+ * ## Lo que hay que conservar
14
+ *
15
+ * ⚠️ La comprobación existe porque `signingSecretId` llega del CUERPO de la
16
+ * petición y sólo se validaba con `@IsMongoId()`: sin esto, un id de otra
17
+ * organización pasaba el DTO. Devolver `true` cuando no se sabe abriría justo
18
+ * esa puerta, así que quien lo implemente por red tiene que fallar hacia
19
+ * `false` — al revés que la mayoría de fallbacks de esta fase.
20
+ */
21
+ export interface SecretosDeFirma {
22
+ /** ⚠️ Ante la duda, `false`. Ver la cabecera. */
23
+ esDeLaOrganizacion(secretoId: string, orgId: string): Promise<boolean>;
24
+ }
25
+ /** ⚠️ Cadena y no `Symbol`, igual que el resto de tokens de la Fase 2. */
26
+ export declare const SECRETOS_DE_FIRMA = "SECRETOS_DE_FIRMA";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SECRETOS_DE_FIRMA = void 0;
4
+ /** ⚠️ Cadena y no `Symbol`, igual que el resto de tokens de la Fase 2. */
5
+ exports.SECRETOS_DE_FIRMA = 'SECRETOS_DE_FIRMA';
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Lo que un nodo apunta en el registro. Una sola operación.
3
+ *
4
+ * ## Por qué
5
+ *
6
+ * Costura de la Fase 2. Después del #459 quedaban 16 ficheros de `nodes/`
7
+ * importando `TelemetryService`, más tres del motor en `common/` —que viaja
8
+ * con ellos—. Los 19 lo usan para **lo mismo**: `emit`.
9
+ *
10
+ * `TelemetryService` arrastra la colección de logs, su conexión de Mongo
11
+ * propia y el gateway de sockets que empuja la fila al panel en vivo. Nada de
12
+ * eso puede vivir en `hw-nodes`: el registro es del gateway, y lo que el nodo
13
+ * necesita es poder DECIR lo que ha pasado.
14
+ *
15
+ * ## Tres métodos, y medidos
16
+ *
17
+ * En `nodes/` el inventario dio **uno solo** —`emit`— en 15 de los 16
18
+ * ficheros. El que sobraba (`ai-nodes.controller`) no lo llamaba: se lo
19
+ * pasaba al probador, y para eso ya existe la bandera `conTelemetria` desde
20
+ * el #458.
21
+ *
22
+ * ⚠️ Pero el inventario iba apuntado sólo a `nodes/`, y el motor vive en
23
+ * `common/`, que viaja con ellos. Al compilar salieron dos métodos más:
24
+ * `hasRecentSuccess` y `emitAndWait`. Los dos son de la recuperación de
25
+ * caídas, no del registro: sin ellos un nodo caro se re-ejecuta. Lo cazó tsc,
26
+ * no yo — la lección de siempre, con el barrido mal apuntado.
27
+ *
28
+ * ⚠️ Y ahí apareció una regresión MÍA. El #459 le quitó a
29
+ * `code-nodes.controller` el parámetro `telemetry` y su `super()`, pero dejó
30
+ * en pie un `this.telemetry` en la ruta `:id/test` escrita a mano. Desde
31
+ * entonces valía `undefined`, así que un paso de Run Pipeline sobre un Code
32
+ * node **no anotaba nada** — justo el comportamiento que el #459 decía haber
33
+ * conservado. No lo vio tsc porque la clase base del factory está tipada como
34
+ * `=> any`: dentro de una subclase, `this.loquesea` compila.
35
+ *
36
+ * ## Los campos son los que se usan
37
+ *
38
+ * El esquema `TelemetryLog` tiene ~20 campos. Se contaron los que aparecen de
39
+ * verdad en las 67 llamadas de `nodes/` y las 53 de `common/`: son quince.
40
+ * Fuera quedan `timestamp` —lo pone el gateway si falta—, `correlationId` y
41
+ * los dos de voz, que nadie de este lado escribe.
42
+ *
43
+ * ## Cómo viaja
44
+ *
45
+ * Bien: sólo datos planos. `TelemetryLog` es una clase con decoradores pero
46
+ * sin métodos, así que no hay documento vivo que aplanar; aun así el contrato
47
+ * lo declara aparte para no arrastrar `@nestjs/mongoose` a `hw-nodes`.
48
+ *
49
+ * ⚠️ `emit` devuelve `void` y no espera: por dentro hace `create(...).catch()`.
50
+ * Eso es deliberado y hay que conservarlo cuando esto sea una llamada de red —
51
+ * un nodo no puede quedarse esperando a que se escriba una fila de log, y
52
+ * menos aún fallar porque no se pudo escribir.
53
+ */
54
+ /** Nivel de la fila. Los mismos cuatro del esquema. */
55
+ export type NivelDeRegistro = 'info' | 'warn' | 'error' | 'debug';
56
+ /**
57
+ * Una fila del registro.
58
+ *
59
+ * ⚠️ Los quince campos MEDIDOS, ni uno más. Si hace falta otro, se añade
60
+ * aquí: tsc rechaza una clave desconocida en un literal, así que no se puede
61
+ * colar por accidente.
62
+ */
63
+ export interface EntradaDeTelemetria {
64
+ organizationId: string;
65
+ level: NivelDeRegistro;
66
+ /** Cadena abierta, no un enum: un tipo de nodo nuevo funciona solo. */
67
+ source: string;
68
+ message: string;
69
+ /** `pipeline_test` distingue una corrida de una prueba suelta. */
70
+ trigger?: 'event' | 'pipeline_test';
71
+ eventId?: string;
72
+ webhookId?: string;
73
+ webhookName?: string;
74
+ nodeId?: string;
75
+ nodeName?: string;
76
+ scheduledWorkflowId?: string;
77
+ durationMs?: number;
78
+ statusCode?: number;
79
+ success?: boolean;
80
+ metadata?: Record<string, unknown>;
81
+ }
82
+ /** Apuntar en el registro, y preguntarle a la recuperación de caídas. */
83
+ export interface Telemetria {
84
+ /**
85
+ * ⚠️ `void`, y no espera. Ver la nota de arriba: una implementación por red
86
+ * tiene que seguir sin bloquear y sin propagar su propio fallo.
87
+ */
88
+ emit(entrada: EntradaDeTelemetria): void;
89
+ /**
90
+ * Lo mismo, pero espera a que la fila esté escrita.
91
+ *
92
+ * ⚠️ No es un capricho de consistencia: lo usan los handlers que declaran
93
+ * `awaitTelemetry: true`, que son los caros (llamadas a un LLM). Si un
94
+ * SIGTERM cae entre el handler y la escritura, al recuperar
95
+ * `hasRecentSuccess` dice que no y la operación **se repite** — y al
96
+ * usuario se la cobran dos veces. Una implementación por red tiene que
97
+ * seguir esperando de verdad aquí.
98
+ */
99
+ emitAndWait(entrada: EntradaDeTelemetria): Promise<void>;
100
+ /**
101
+ * ¿Ya corrió con éxito este nodo para este evento hace poco?
102
+ *
103
+ * ⚠️ Falla ABIERTO: si la consulta revienta devuelve `false`, o sea «no
104
+ * corrió», y el nodo se re-ejecuta. Es lo correcto —repetir es más seguro
105
+ * que saltarse un paso— pero hay que conservarlo: una implementación por
106
+ * red que devolviera `true` al fallar dejaría pasos sin ejecutar en
107
+ * silencio, que es el fallo que no se ve.
108
+ */
109
+ hasRecentSuccess(eventId: string, nodeId: string, withinMs?: number): Promise<boolean>;
110
+ }
111
+ /**
112
+ * ⚠️ Cadena y no `Symbol`, igual que el resto de tokens de la Fase 2.
113
+ */
114
+ export declare const TELEMETRIA = "TELEMETRIA";