@hostwebhook/node-types 1.76.0 → 1.78.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.
- package/README.md +0 -0
- package/dist/dispatch.js +13 -8
- package/dist/esm/dispatch.js +13 -8
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/respuesta-del-sync.d.ts +353 -0
- package/dist/esm/respuesta-del-sync.js +446 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +12 -1
- package/dist/respuesta-del-sync.d.ts +353 -0
- package/dist/respuesta-del-sync.js +451 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
Binary file
|
package/dist/dispatch.js
CHANGED
|
@@ -39,31 +39,36 @@ exports.NODE_DISPATCH = {
|
|
|
39
39
|
// ── Routing — custom dispatch ──
|
|
40
40
|
router: { service: 'routersService', collection: 'routers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
|
|
41
41
|
// ── Action nodes — fired in onDeliveryResult, excluded from webhook dispatch ──
|
|
42
|
-
emailAction: { service: 'emailActionsService', collection: 'emailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
43
|
-
gmailAction: { service: 'gmailActionsService', collection: 'gmailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
42
|
+
emailAction: { service: 'emailActionsService', collection: 'emailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
43
|
+
gmailAction: { service: 'gmailActionsService', collection: 'gmailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
44
44
|
httpAction: { service: 'httpActionsService', collection: 'httpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
45
45
|
mongoAction: { service: 'mongoActionsService', collection: 'mongoactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
46
46
|
postgresAction: { service: 'postgresActionsService', collection: 'postgresactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
47
|
-
notificationAction: { service: 'notificationActionsService', collection: 'notificationactions', hasFilters: true, outputFields: [], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
47
|
+
notificationAction: { service: 'notificationActionsService', collection: 'notificationactions', hasFilters: true, outputFields: [], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
48
48
|
sheetsAction: { service: 'sheetsActionsService', collection: 'sheetsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
49
49
|
calendarAction: { service: 'calendarActionsService', collection: 'calendaractions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
50
50
|
docsAction: { service: 'docsActionsService', collection: 'docsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
51
51
|
driveAction: { service: 'driveActionsService', collection: 'driveactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
52
52
|
firecrawlAction: { service: 'firecrawlActionsService', collection: 'firecrawlactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
53
|
-
telegramAction: { service: 'telegramActionsService', collection: 'telegramactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
54
|
-
whatsappAction: { service: 'whatsappActionsService', collection: 'whatsappactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
55
|
-
|
|
53
|
+
telegramAction: { service: 'telegramActionsService', collection: 'telegramactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
54
|
+
whatsappAction: { service: 'whatsappActionsService', collection: 'whatsappactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
55
|
+
/* `'result'` y no `'original'` por decisión del dueño: lo que tiene que bajar
|
|
56
|
+
de un Discord es SU acuse —`messageId`, `channelId`, `content`— y no el
|
|
57
|
+
evento que le entró. Ver `discord-actions.service.ts`, donde está el coste
|
|
58
|
+
escrito: un flujo que leyera `{{payload.<campo del evento>}}` después de un
|
|
59
|
+
Discord ahora lee el acuse. */
|
|
60
|
+
discordAction: { service: 'discordActionsService', collection: 'discordactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
56
61
|
mailchimpAction: { service: 'mailchimpActionsService', collection: 'mailchimpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
57
62
|
shopifyAction: { service: 'shopifyActionsService', collection: 'shopifyactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
58
63
|
githubAction: { service: 'githubActionsService', collection: 'githubactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
59
64
|
jiraAction: { service: 'jiraActionsService', collection: 'jiraactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
60
65
|
bucketAction: { service: 'bucketActionsService', collection: 'bucketactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
61
|
-
slackAction: { service: 'slackActionsService', collection: 'slackactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
66
|
+
slackAction: { service: 'slackActionsService', collection: 'slackactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
62
67
|
googleContactsAction: { service: 'googleContactsActionsService', collection: 'googlecontactsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
63
68
|
googleAnalyticsAction: { service: 'googleAnalyticsActionsService', collection: 'googleanalyticsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
64
69
|
notionAction: { service: 'notionActionsService', collection: 'notionactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
65
70
|
rssAction: { service: 'rssActionsService', collection: 'rssactions', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
66
|
-
socialMediaAction: { service: 'socialMediaActionsService', collection: 'socialmediaactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
71
|
+
socialMediaAction: { service: 'socialMediaActionsService', collection: 'socialmediaactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
67
72
|
// ── Sources — start the flow themselves, not dispatched ──
|
|
68
73
|
webhook: { service: 'webhooksService', collection: 'webhooks', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
69
74
|
scheduledWorkflow: { service: 'scheduledWorkflowsService', collection: 'scheduledworkflows', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
package/dist/esm/dispatch.js
CHANGED
|
@@ -33,31 +33,36 @@ export const NODE_DISPATCH = {
|
|
|
33
33
|
// ── Routing — custom dispatch ──
|
|
34
34
|
router: { service: 'routersService', collection: 'routers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
|
|
35
35
|
// ── Action nodes — fired in onDeliveryResult, excluded from webhook dispatch ──
|
|
36
|
-
emailAction: { service: 'emailActionsService', collection: 'emailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
37
|
-
gmailAction: { service: 'gmailActionsService', collection: 'gmailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
36
|
+
emailAction: { service: 'emailActionsService', collection: 'emailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
37
|
+
gmailAction: { service: 'gmailActionsService', collection: 'gmailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
38
38
|
httpAction: { service: 'httpActionsService', collection: 'httpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
39
39
|
mongoAction: { service: 'mongoActionsService', collection: 'mongoactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
40
40
|
postgresAction: { service: 'postgresActionsService', collection: 'postgresactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
41
|
-
notificationAction: { service: 'notificationActionsService', collection: 'notificationactions', hasFilters: true, outputFields: [], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
41
|
+
notificationAction: { service: 'notificationActionsService', collection: 'notificationactions', hasFilters: true, outputFields: [], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
42
42
|
sheetsAction: { service: 'sheetsActionsService', collection: 'sheetsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
43
43
|
calendarAction: { service: 'calendarActionsService', collection: 'calendaractions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
44
44
|
docsAction: { service: 'docsActionsService', collection: 'docsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
45
45
|
driveAction: { service: 'driveActionsService', collection: 'driveactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
46
46
|
firecrawlAction: { service: 'firecrawlActionsService', collection: 'firecrawlactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
47
|
-
telegramAction: { service: 'telegramActionsService', collection: 'telegramactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
48
|
-
whatsappAction: { service: 'whatsappActionsService', collection: 'whatsappactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
49
|
-
|
|
47
|
+
telegramAction: { service: 'telegramActionsService', collection: 'telegramactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
48
|
+
whatsappAction: { service: 'whatsappActionsService', collection: 'whatsappactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
49
|
+
/* `'result'` y no `'original'` por decisión del dueño: lo que tiene que bajar
|
|
50
|
+
de un Discord es SU acuse —`messageId`, `channelId`, `content`— y no el
|
|
51
|
+
evento que le entró. Ver `discord-actions.service.ts`, donde está el coste
|
|
52
|
+
escrito: un flujo que leyera `{{payload.<campo del evento>}}` después de un
|
|
53
|
+
Discord ahora lee el acuse. */
|
|
54
|
+
discordAction: { service: 'discordActionsService', collection: 'discordactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
50
55
|
mailchimpAction: { service: 'mailchimpActionsService', collection: 'mailchimpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
51
56
|
shopifyAction: { service: 'shopifyActionsService', collection: 'shopifyactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
52
57
|
githubAction: { service: 'githubActionsService', collection: 'githubactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
53
58
|
jiraAction: { service: 'jiraActionsService', collection: 'jiraactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
54
59
|
bucketAction: { service: 'bucketActionsService', collection: 'bucketactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
55
|
-
slackAction: { service: 'slackActionsService', collection: 'slackactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
60
|
+
slackAction: { service: 'slackActionsService', collection: 'slackactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
56
61
|
googleContactsAction: { service: 'googleContactsActionsService', collection: 'googlecontactsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
57
62
|
googleAnalyticsAction: { service: 'googleAnalyticsActionsService', collection: 'googleanalyticsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
58
63
|
notionAction: { service: 'notionActionsService', collection: 'notionactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
59
64
|
rssAction: { service: 'rssActionsService', collection: 'rssactions', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
60
|
-
socialMediaAction: { service: 'socialMediaActionsService', collection: 'socialmediaactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: '
|
|
65
|
+
socialMediaAction: { service: 'socialMediaActionsService', collection: 'socialmediaactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
61
66
|
// ── Sources — start the flow themselves, not dispatched ──
|
|
62
67
|
webhook: { service: 'webhooksService', collection: 'webhooks', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
|
63
68
|
scheduledWorkflow: { service: 'scheduledWorkflowsService', collection: 'scheduledworkflows', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -66,3 +66,5 @@ export type { ModeloDeOpenRouter, PrecioDeOpenRouter, RespuestaDeModelosDeOpenRo
|
|
|
66
66
|
export { URL_DE_MODELOS_DE_OPENROUTER, opcionesDeModelosDeOpenRouter, ventanaDeContextoDeOpenRouter, } from './openrouter.js';
|
|
67
67
|
export type { CredentialTypeRegistration, CredentialType } from './credentials.js';
|
|
68
68
|
export { CREDENTIAL_TYPES, CREDENTIAL_TYPE_VALUES, credentialTypeValues, getCredentialType, isCredentialType, } from './credentials.js';
|
|
69
|
+
export type { NodoQueContestaEnSync, ResultadoDelValidador, FalloDeValidacion, VeredictoDelValidador, NivelDeDetalle, ModoDePayload, SobreDeRespuesta, TopeDeNumero, RespuestaDelSync, RespuestaHttp, } from './respuesta-del-sync.js';
|
|
70
|
+
export { NODOS_QUE_CONTESTAN_EN_SYNC, contestaEnSync, RESULTADOS_DEL_VALIDADOR, NIVELES_DE_DETALLE, MODOS_DE_PAYLOAD, SOBRES_DE_RESPUESTA, TOPES_DE_ESTADO, TOPE_DE_ESPERA_DEL_SYNC, RESPUESTA_DEL_SYNC_POR_DEFECTO, armarRespuestaDelSync, } from './respuesta-del-sync.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -51,3 +51,4 @@ export { DOCS_TOOLKIT_SPECS, DOCS_TOOLKIT_BY_TOOL_NAME, DOCS_TOOLKIT_DEFAULTABLE
|
|
|
51
51
|
export { LLM_PROVIDERS, LLM_MODELS, MODEL_CONTEXT_WINDOWS, getModelsFor, getDefaultModel, getModelLabel, } from './llm-models.js';
|
|
52
52
|
export { URL_DE_MODELOS_DE_OPENROUTER, opcionesDeModelosDeOpenRouter, ventanaDeContextoDeOpenRouter, } from './openrouter.js';
|
|
53
53
|
export { CREDENTIAL_TYPES, CREDENTIAL_TYPE_VALUES, credentialTypeValues, getCredentialType, isCredentialType, } from './credentials.js';
|
|
54
|
+
export { NODOS_QUE_CONTESTAN_EN_SYNC, contestaEnSync, RESULTADOS_DEL_VALIDADOR, NIVELES_DE_DETALLE, MODOS_DE_PAYLOAD, SOBRES_DE_RESPUESTA, TOPES_DE_ESTADO, TOPE_DE_ESPERA_DEL_SYNC, RESPUESTA_DEL_SYNC_POR_DEFECTO, armarRespuestaDelSync, } from './respuesta-del-sync.js';
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* La respuesta que recibe quien llama a un webhook en modo `sync`, armada en
|
|
3
|
+
* UN solo sitio.
|
|
4
|
+
*
|
|
5
|
+
* ## Qué problema resuelve
|
|
6
|
+
*
|
|
7
|
+
* El dueño quiere unas pestañas para configurar qué recibe el cliente y una
|
|
8
|
+
* VISTA PREVIA que enseñe los bytes exactos. Una vista previa sólo vale si no
|
|
9
|
+
* puede desincronizarse del servidor: si son dos implementaciones, el día que
|
|
10
|
+
* difieran la pantalla miente con toda la confianza del mundo, y miente sobre
|
|
11
|
+
* lo único que el usuario no puede comprobar desde ahí.
|
|
12
|
+
*
|
|
13
|
+
* Ya hay un caso así en el dashboard —`FORMAT_OPTIONS`, cuatro formatos
|
|
14
|
+
* copiados a mano en `schema-validators/[id]/page.tsx` cuando el paquete
|
|
15
|
+
* publica dieciocho— y ahí se asume porque desincronizarse AVISA: el campo
|
|
16
|
+
* deja de ofrecer un formato que sí existe y alguien lo pide. Aquí no avisaría
|
|
17
|
+
* nada. La previa diría 422 con tres errores, el servidor mandaría otra cosa,
|
|
18
|
+
* y nadie se enteraría hasta que un cliente se quejara.
|
|
19
|
+
*
|
|
20
|
+
* Así que la función de abajo es la ÚNICA que sabe montar estos bytes. La
|
|
21
|
+
* llaman los tres: el handler del validador en hw-nodes, el endpoint de previa
|
|
22
|
+
* de la api, y el dashboard para pintarla.
|
|
23
|
+
*
|
|
24
|
+
* ## Por qué este paquete y no otro — medido el 2026-09-10
|
|
25
|
+
*
|
|
26
|
+
* Los tres candidatos, con los números delante:
|
|
27
|
+
*
|
|
28
|
+
* | | `platform-contracts` | `node-sdk` | **`node-types`** |
|
|
29
|
+
* |---|---|---|---|
|
|
30
|
+
* | lo pinea el dashboard | `^0.2.0` (0.2.0 instalada) | no es dependencia suya | `^1.74.0` (1.74.0 instalada) |
|
|
31
|
+
* | ¿el caret llega a lo nuevo? | **NO** — en `0.x` no cruza el minor: habría que subir a `^0.16` a mano | — | **SÍ** — en `1.x` sí lo cruza; basta refrescar el lock |
|
|
32
|
+
* | dependencias de ejecución | `dependencies: {}` **pero** su barril hace `require('@nestjs/common')` de verdad | mongoose, mongodb, express, re2 (binario nativo) | **ninguna: ni deps ni peers** |
|
|
33
|
+
* | ¿sirve en el navegador? | **NO** hoy | no | **sí** |
|
|
34
|
+
* | ficheros del dashboard que ya lo importan | 6 | 0 | **92** |
|
|
35
|
+
*
|
|
36
|
+
* ⚠️ Lo de `platform-contracts` conviene leerlo dos veces, porque la primera
|
|
37
|
+
* medición decía lo contrario. `dependencies: {}` es cierto, y por eso parecía
|
|
38
|
+
* servible en el navegador. Pero un PEER también se ejecuta: desde 0.3.0 el
|
|
39
|
+
* paquete trae `servicios/credenciales-del-gateway`, que importa
|
|
40
|
+
* `BadRequestException` como VALOR, y eso sale en el `dist` como un
|
|
41
|
+
* `require("@nestjs/common")` al que se llega desde `dist/index.js` —barril de
|
|
42
|
+
* CommonJS, sin mapa `exports` y sin `sideEffects`, o sea que no se sacude—.
|
|
43
|
+
* El dashboard entra por ese barril (`lib/store/hooks.ts` pide `tieneAddon`
|
|
44
|
+
* como valor, no como tipo), así que subirlo metería ~9,5 MB de framework de
|
|
45
|
+
* servidor —@nestjs/common 1,1 MB, rxjs 8,1 MB, reflect-metadata 265 kB— en un
|
|
46
|
+
* Next. Lo que NO es el problema, y también se midió: entre 0.2.0 y 0.15.0
|
|
47
|
+
* `addons.ts` y `operadores.ts` están byte a byte idénticos, así que de los 13
|
|
48
|
+
* minors de salto NO sale ni un breaking para lo que el dashboard usa hoy.
|
|
49
|
+
*
|
|
50
|
+
* Y aquí, además, cae en el sitio correcto por significado: la constante del
|
|
51
|
+
* gate es una lista de `NodeType`, y `NodeType` vive en este fichero de al
|
|
52
|
+
* lado. En cualquier otro paquete sería una lista de cadenas sueltas que nadie
|
|
53
|
+
* comprueba contra el catálogo de nodos.
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* Los tipos de nodo que SABEN contestar en `sync`.
|
|
57
|
+
*
|
|
58
|
+
* Lo lee la api al guardar —para no dejar activar `responseMode: 'sync'` en un
|
|
59
|
+
* flujo que no lleva ninguno— y el dashboard para avisar antes de guardar.
|
|
60
|
+
*
|
|
61
|
+
* 🔥 Es una CONSTANTE y no el literal `'schemaValidator'` repartido por los dos
|
|
62
|
+
* sitios, y la razón no es estética: el día que un segundo nodo implemente
|
|
63
|
+
* `getSyncResult`, con literales el gate sigue compilando, sigue pasando los
|
|
64
|
+
* tests y **se queda mintiendo en silencio** —le dice al usuario que su flujo
|
|
65
|
+
* no puede contestar cuando sí puede—. Un fallo que no rompe nada es el que
|
|
66
|
+
* sobrevive años.
|
|
67
|
+
*
|
|
68
|
+
* ⚠️ Y lo que esta lista NO puede comprobar desde aquí: que sea la misma que
|
|
69
|
+
* la de los handlers que de verdad implementan `getSyncResult`. Esos viven en
|
|
70
|
+
* hw-nodes, que este paquete no ve ni debe ver. El guardián de esa atadura va
|
|
71
|
+
* ALLÍ, que es donde están los handlers — el mismo reparto que ya usa
|
|
72
|
+
* `pasaLoQueRecibe`: la tabla se fija aquí y
|
|
73
|
+
* `el-panel-lee-lo-mismo-que-el-handler.spec.ts` la ata en hw-nodes.
|
|
74
|
+
*
|
|
75
|
+
* ⚠️⚠️ Presencia no es paso. Que el flujo LLEVE un validador no garantiza que
|
|
76
|
+
* el evento pase por él: un conditional o un filter puede rutear alrededor. Por
|
|
77
|
+
* eso el gate es de producto y no de corrección, y por eso `'no-verdict'`
|
|
78
|
+
* existe ahí abajo — sin él, el flujo con el gate puesto se colgaría igual.
|
|
79
|
+
*/
|
|
80
|
+
export declare const NODOS_QUE_CONTESTAN_EN_SYNC: readonly ["schemaValidator"];
|
|
81
|
+
/** Un tipo de nodo de los que saben contestar en `sync`. */
|
|
82
|
+
export type NodoQueContestaEnSync = (typeof NODOS_QUE_CONTESTAN_EN_SYNC)[number];
|
|
83
|
+
/**
|
|
84
|
+
* ¿Este tipo de nodo sabe contestar en `sync`?
|
|
85
|
+
*
|
|
86
|
+
* Acepta `string` y no `NodeType` a propósito: quien pregunta es la api con lo
|
|
87
|
+
* que trae un documento de mongo y el dashboard con lo que hay en el lienzo, y
|
|
88
|
+
* los dos manejan cadenas que todavía no han pasado por ningún tipo.
|
|
89
|
+
*/
|
|
90
|
+
export declare function contestaEnSync(tipo: string): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Los cuatro finales posibles de una espera en `sync`. Son cuatro y no dos, y
|
|
93
|
+
* los dos de en medio son los que hoy faltan:
|
|
94
|
+
*
|
|
95
|
+
* - `valid` — el payload pasó. **Esto es lo que hoy no contesta nadie**: el
|
|
96
|
+
* `getSyncResult` del validador devuelve `null` cuando todo está bien y el
|
|
97
|
+
* paso 8.5 de `node-lifecycle.ts` sólo resuelve `if (syncResult)`. O sea que
|
|
98
|
+
* el camino FELIZ es el que se cuelga 120 s y sale con un 408. Pasar la
|
|
99
|
+
* validación era indistinguible de que no contestara nadie.
|
|
100
|
+
* - `invalid` — el payload no pasó. El único que funciona hoy.
|
|
101
|
+
* - `no-verdict` — la corrida TERMINÓ y ningún validador se pronunció (nadie
|
|
102
|
+
* pasó por él, o el flujo no lleva ninguno). Hay que contestar igual, ahí
|
|
103
|
+
* mismo, en vez de esperar el tope entero.
|
|
104
|
+
* - `timeout` — se acabó la espera de verdad.
|
|
105
|
+
*/
|
|
106
|
+
export declare const RESULTADOS_DEL_VALIDADOR: readonly ["valid", "invalid", "no-verdict", "timeout"];
|
|
107
|
+
export type ResultadoDelValidador = (typeof RESULTADOS_DEL_VALIDADOR)[number];
|
|
108
|
+
/**
|
|
109
|
+
* Un campo que no pasó.
|
|
110
|
+
*
|
|
111
|
+
* `path` y `message` son lo que `validateSchema` produce hoy
|
|
112
|
+
* (`@hostwebhook/node-sdk`, `schema-validator-utils.ts`). `rule` y `expected`
|
|
113
|
+
* son OPCIONALES porque hoy ese validador todavía no los emite: cuando no
|
|
114
|
+
* vienen, el nivel `full` sale exactamente igual que el cuerpo que ya se envía,
|
|
115
|
+
* o sea que nada empeora mientras tanto, y el día que los emita esta función no
|
|
116
|
+
* cambia una línea.
|
|
117
|
+
*/
|
|
118
|
+
export interface FalloDeValidacion {
|
|
119
|
+
/**
|
|
120
|
+
* La ruta del campo dentro del payload: `user.email`, `items[0].sku`.
|
|
121
|
+
*
|
|
122
|
+
* ⚠️ Se llama `path` y no `field` a propósito, aunque el hueco de la
|
|
123
|
+
* plantilla se llame `{{field}}`. `path` es lo que YA sale por el cable en el
|
|
124
|
+
* 422 de hoy, y renombrarlo rompería a todo el que lo esté parseando ahí
|
|
125
|
+
* fuera. El hueco se llama como lo pidió el dueño, que es quien lo escribe en
|
|
126
|
+
* una caja de texto; la clave del JSON se llama como siempre se llamó.
|
|
127
|
+
*/
|
|
128
|
+
path: string;
|
|
129
|
+
/** El texto que produjo el validador: `must be a valid email`. */
|
|
130
|
+
message: string;
|
|
131
|
+
/** Qué regla falló: `format`, `minLength`, `required`, `type`… */
|
|
132
|
+
rule?: string;
|
|
133
|
+
/** Qué esperaba esa regla: `email`, `3`, `string`… */
|
|
134
|
+
expected?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Lo que dictaminó el validador. Es la ENTRADA de la función pura, y va como
|
|
138
|
+
* unión porque los cuatro finales no llevan los mismos datos: un `valid` no
|
|
139
|
+
* tiene errores y un `timeout` tampoco tiene payload que devolver.
|
|
140
|
+
*/
|
|
141
|
+
export type VeredictoDelValidador = {
|
|
142
|
+
outcome: 'valid';
|
|
143
|
+
eventId?: string;
|
|
144
|
+
webhookName?: string;
|
|
145
|
+
nodeName?: string;
|
|
146
|
+
} | {
|
|
147
|
+
outcome: 'invalid';
|
|
148
|
+
errors: FalloDeValidacion[];
|
|
149
|
+
/** Lo que ENTRÓ. Hace falta para `includePayload`. */
|
|
150
|
+
payload?: unknown;
|
|
151
|
+
eventId?: string;
|
|
152
|
+
webhookName?: string;
|
|
153
|
+
nodeName?: string;
|
|
154
|
+
} | {
|
|
155
|
+
outcome: 'no-verdict';
|
|
156
|
+
eventId?: string;
|
|
157
|
+
webhookName?: string;
|
|
158
|
+
nodeName?: string;
|
|
159
|
+
} | {
|
|
160
|
+
outcome: 'timeout';
|
|
161
|
+
eventId?: string;
|
|
162
|
+
webhookName?: string;
|
|
163
|
+
nodeName?: string;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Cuánto se le cuenta al cliente de POR QUÉ falló.
|
|
167
|
+
*
|
|
168
|
+
* Los valores van en inglés aunque el tipo se llame en español, por lo mismo
|
|
169
|
+
* que `FORMATOS_DEL_ESQUEMA`: acaban en un `enum` de mongoose, en un `@IsIn`
|
|
170
|
+
* de un DTO y en un `<select>`, y ninguno de esos tres sitios quiere una
|
|
171
|
+
* cadena en español dentro de un JSON que un cliente puede exportar.
|
|
172
|
+
*
|
|
173
|
+
* - `full` — ruta, regla y esperado. Lo que quiere quien integra con su propio
|
|
174
|
+
* equipo detrás.
|
|
175
|
+
* - `fields-only` — QUÉ campos fallaron, sin el porqué. El término medio para
|
|
176
|
+
* un formulario público: basta para señalar la casilla en rojo y no publica
|
|
177
|
+
* las reglas.
|
|
178
|
+
* - `opaque` — «Invalid payload» y ya. **Ni una ruta de campo sale de aquí.**
|
|
179
|
+
* Un esquema es un mapa de tu modelo de datos; repartirlo por un endpoint
|
|
180
|
+
* público es regalar el trabajo de enumeración a quien lo quiera.
|
|
181
|
+
*/
|
|
182
|
+
export declare const NIVELES_DE_DETALLE: readonly ["full", "fields-only", "opaque"];
|
|
183
|
+
export type NivelDeDetalle = (typeof NIVELES_DE_DETALLE)[number];
|
|
184
|
+
/**
|
|
185
|
+
* Si se le devuelve al cliente lo que mandó, y cuánto.
|
|
186
|
+
*
|
|
187
|
+
* - `none` — no.
|
|
188
|
+
* - `full` — tal cual llegó. No revela nada: es SU payload.
|
|
189
|
+
* - `failed-fields` — sólo los campos que fallaron, **en plano**, con la ruta
|
|
190
|
+
* completa como clave: `{ "user.email": "nope", "items[0].sku": 12 }`.
|
|
191
|
+
* Plano y no reconstruido con su anidamiento por dos razones: reconstruirlo
|
|
192
|
+
* añade una segunda lectura de rutas que puede discrepar de la del
|
|
193
|
+
* validador, y porque quien está depurando quiere la lista de lo que falló
|
|
194
|
+
* junto a lo que mandó, no un recorte del original con la misma forma.
|
|
195
|
+
*/
|
|
196
|
+
export declare const MODOS_DE_PAYLOAD: readonly ["none", "full", "failed-fields"];
|
|
197
|
+
export type ModoDePayload = (typeof MODOS_DE_PAYLOAD)[number];
|
|
198
|
+
/**
|
|
199
|
+
* La forma del sobre.
|
|
200
|
+
*
|
|
201
|
+
* - `hostwebhook` — el nuestro, el que ya sale hoy por el cable.
|
|
202
|
+
* - `problem+json` — RFC 7807, con su `content-type: application/problem+json`.
|
|
203
|
+
* Lo piden los que meten esto detrás de un cliente generado.
|
|
204
|
+
*/
|
|
205
|
+
export declare const SOBRES_DE_RESPUESTA: readonly ["hostwebhook", "problem+json"];
|
|
206
|
+
export type SobreDeRespuesta = (typeof SOBRES_DE_RESPUESTA)[number];
|
|
207
|
+
/** Un tope: el mínimo, el máximo y con qué se rellena si se sale. */
|
|
208
|
+
export interface TopeDeNumero {
|
|
209
|
+
min: number;
|
|
210
|
+
max: number;
|
|
211
|
+
defecto: number;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Los topes de los códigos de estado, exportados para que el dashboard ponga
|
|
215
|
+
* el `min`/`max` de cada caja desde AQUÍ y no a ojo.
|
|
216
|
+
*
|
|
217
|
+
* El del éxito acaba en 299 por lo que pidió el dueño: nada de un 500 en el
|
|
218
|
+
* éxito. Y no es una manía — un 5xx en la respuesta de «tu payload es válido»
|
|
219
|
+
* hace que el cliente reintente, y reintentar un webhook aceptado duplica el
|
|
220
|
+
* evento.
|
|
221
|
+
*
|
|
222
|
+
* El del error se queda en 4xx: la culpa del payload es de quien lo manda, y un
|
|
223
|
+
* 5xx ahí también invita al reintento de lo que nunca va a pasar.
|
|
224
|
+
*
|
|
225
|
+
* El del timeout llega hasta 599 porque ahí sí caben los dos: 408 (lo que sale
|
|
226
|
+
* hoy) y 504, que es lo que muchos proxies esperan.
|
|
227
|
+
*/
|
|
228
|
+
export declare const TOPES_DE_ESTADO: {
|
|
229
|
+
readonly success: {
|
|
230
|
+
readonly min: 200;
|
|
231
|
+
readonly max: 299;
|
|
232
|
+
readonly defecto: 200;
|
|
233
|
+
};
|
|
234
|
+
readonly error: {
|
|
235
|
+
readonly min: 400;
|
|
236
|
+
readonly max: 499;
|
|
237
|
+
readonly defecto: 422;
|
|
238
|
+
};
|
|
239
|
+
readonly timeout: {
|
|
240
|
+
readonly min: 400;
|
|
241
|
+
readonly max: 599;
|
|
242
|
+
readonly defecto: 408;
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Cuánto se puede tener la conexión viva.
|
|
247
|
+
*
|
|
248
|
+
* ⚠️ El `max` es `SYNC_TIMEOUT_SECONDS` de `@hostwebhook/node-sdk`
|
|
249
|
+
* (`topes/plan.constants.ts`), que es el `setTimeout` real del `waitForSync`
|
|
250
|
+
* del gateway. Está copiado y no importado porque este paquete **no tiene ni
|
|
251
|
+
* una dependencia** —es justo lo que lo hace servible en el navegador— y
|
|
252
|
+
* traerse node-sdk arrastraría mongoose, express y un binario nativo.
|
|
253
|
+
*
|
|
254
|
+
* Que la copia no se despiste lo ata un test EN node-sdk, que sí puede ver los
|
|
255
|
+
* dos: `el-tope-de-la-espera-es-uno.test.ts`. Sin esa atadura, configurar 200 s
|
|
256
|
+
* aquí daría una pantalla que promete 200 y un gateway que corta a los 120.
|
|
257
|
+
*/
|
|
258
|
+
export declare const TOPE_DE_ESPERA_DEL_SYNC: {
|
|
259
|
+
readonly min: 1;
|
|
260
|
+
readonly max: 120;
|
|
261
|
+
readonly defecto: 120;
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Cómo se quiere la respuesta del `sync`. Todo opcional: lo que no venga sale
|
|
265
|
+
* de `RESPUESTA_DEL_SYNC_POR_DEFECTO`, y así un webhook que nunca tocó estas
|
|
266
|
+
* pestañas se comporta exactamente como hoy.
|
|
267
|
+
*/
|
|
268
|
+
export interface RespuestaDelSync {
|
|
269
|
+
/** Estado del ÉXITO. 200–299; fuera de rango vuelve a 200. */
|
|
270
|
+
successStatus?: number;
|
|
271
|
+
/** Estado del ERROR de validación. 400–499; fuera de rango vuelve a 422. */
|
|
272
|
+
errorStatus?: number;
|
|
273
|
+
/** Cuánto se cuenta del porqué. */
|
|
274
|
+
detail?: NivelDeDetalle;
|
|
275
|
+
/**
|
|
276
|
+
* Plantilla del mensaje de cada fallo, con huecos `{{field}}`, `{{rule}}` y
|
|
277
|
+
* `{{expected}}`. Sin ella se usa el texto del validador tal cual.
|
|
278
|
+
*/
|
|
279
|
+
messageTemplate?: string;
|
|
280
|
+
/**
|
|
281
|
+
* Plantilla propia para un campo concreto, por su ruta exacta. Gana sobre
|
|
282
|
+
* `messageTemplate`.
|
|
283
|
+
*/
|
|
284
|
+
fieldTemplates?: Record<string, string>;
|
|
285
|
+
/** Si se le devuelve al cliente lo que mandó. */
|
|
286
|
+
includePayload?: ModoDePayload;
|
|
287
|
+
/** La forma del sobre. */
|
|
288
|
+
envelope?: SobreDeRespuesta;
|
|
289
|
+
/**
|
|
290
|
+
* El `type` de RFC 7807: un URI que describe el problema. Sólo se usa con el
|
|
291
|
+
* sobre `problem+json`.
|
|
292
|
+
*
|
|
293
|
+
* Por defecto `about:blank`, que es lo que manda el propio RFC cuando no hay
|
|
294
|
+
* un URI específico. Inventarse una URL de hostwebhook.com que da 404 es peor
|
|
295
|
+
* que no dar ninguna: el 7807 existe para que ese enlace se pueda seguir.
|
|
296
|
+
*/
|
|
297
|
+
problemType?: string;
|
|
298
|
+
/** Segundos de conexión viva. 1–120; fuera de rango vuelve a 120. */
|
|
299
|
+
timeoutSeconds?: number;
|
|
300
|
+
/** Estado del timeout. 400–599; fuera de rango vuelve a 408. */
|
|
301
|
+
timeoutStatus?: number;
|
|
302
|
+
/** Cuerpo del timeout. Sin él, el de hoy: `{ error: 'Pipeline timeout' }`. */
|
|
303
|
+
timeoutBody?: Record<string, unknown>;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Lo que se usa cuando no se configuró nada.
|
|
307
|
+
*
|
|
308
|
+
* Están elegidos para que un webhook que no toque nada se comporte IGUAL que
|
|
309
|
+
* antes de todo esto: 422 al fallar, 120 s de espera, 408 al agotarse, el sobre
|
|
310
|
+
* de siempre y sin devolver el payload. Lo único que cambia respecto a hoy es
|
|
311
|
+
* que el camino feliz ahora contesta en vez de colgarse, que era el bug.
|
|
312
|
+
*
|
|
313
|
+
* `detail: 'full'` por lo mismo: es lo que sale hoy por el cable.
|
|
314
|
+
*/
|
|
315
|
+
export declare const RESPUESTA_DEL_SYNC_POR_DEFECTO: {
|
|
316
|
+
readonly successStatus: 200;
|
|
317
|
+
readonly errorStatus: 422;
|
|
318
|
+
readonly detail: "full";
|
|
319
|
+
readonly includePayload: "none";
|
|
320
|
+
readonly envelope: "hostwebhook";
|
|
321
|
+
readonly problemType: "about:blank";
|
|
322
|
+
readonly timeoutSeconds: 120;
|
|
323
|
+
readonly timeoutStatus: 408;
|
|
324
|
+
};
|
|
325
|
+
/**
|
|
326
|
+
* La respuesta HTTP, entera.
|
|
327
|
+
*
|
|
328
|
+
* Lleva `headers` y no sólo `{status, body}` porque el sobre RFC 7807 SON las
|
|
329
|
+
* cabeceras tanto como el cuerpo: mandar ese JSON con `application/json` no es
|
|
330
|
+
* un 7807, es un JSON que se le parece, y el cliente generado que lo espera no
|
|
331
|
+
* lo reconoce. `{status, body}` sigue siendo un subconjunto de esto, así que
|
|
332
|
+
* el `getSyncResult` de hoy encaja sin tocar nada.
|
|
333
|
+
*/
|
|
334
|
+
export interface RespuestaHttp {
|
|
335
|
+
status: number;
|
|
336
|
+
headers: Record<string, string>;
|
|
337
|
+
/**
|
|
338
|
+
* ⚠️ El orden de inserción de las claves ES el orden en el que salen por el
|
|
339
|
+
* cable: `JSON.stringify` respeta el orden de inserción de las claves de
|
|
340
|
+
* texto. La vista previa enseña esto mismo, así que el orden de abajo está
|
|
341
|
+
* escrito a mano y no por casualidad.
|
|
342
|
+
*/
|
|
343
|
+
body: Record<string, unknown>;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Arma la respuesta que recibe quien llamó en `sync`.
|
|
347
|
+
*
|
|
348
|
+
* PURA: sin nestjs, sin mongoose, sin `Date.now()`, sin nada de servidor. Entra
|
|
349
|
+
* un veredicto y una configuración, sale la respuesta. Por eso puede correr
|
|
350
|
+
* igual en el handler de hw-nodes y en el navegador del dashboard, y por eso la
|
|
351
|
+
* vista previa no puede desincronizarse: es literalmente la misma llamada.
|
|
352
|
+
*/
|
|
353
|
+
export declare function armarRespuestaDelSync(veredicto: VeredictoDelValidador, config?: RespuestaDelSync): RespuestaHttp;
|