@hostwebhook/node-types 1.75.2 → 1.76.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.
@@ -62,11 +62,29 @@ const eventConfigParams = () => [
62
62
  entera de la regla de ambigüedad ANTES de mandar el payload. `05-06-2026`
63
63
  se rechaza en ejecución (ver `normalizeDate`), y un rechazo que sólo
64
64
  aparece en el log del run llega tarde: aquí se dice al lado del campo.
65
- El de End Date dice además que es el ÚLTIMO DÍA INCLUIDO, porque el `+1`
66
- de la exclusividad de Google lo pone HostWebhook y sin decirlo el usuario
67
- lo escribiría dos veces. */
68
- { name: 'startTemplate', target: 'eventConfig', label: 'Start Date', type: 'template', placeholder: '{{payload.startTime}}', description: 'YYYY-MM-DD for an all-day event, or YYYY-MM-DDTHH:mm:ss for a timed one (interpreted in the Time Zone below). M-D-YYYY and D-M-YYYY work only when one part is above 12 — 05-06-2026 is rejected as ambiguous instead of guessed.', execKey: 'start' },
69
- { name: 'endTemplate', target: 'eventConfig', label: 'End Date', type: 'template', placeholder: '{{payload.endTime}}', description: 'YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss, same rules as Start Date. For all-day events this is the LAST DAY INCLUDED — HostWebhook adds the extra day Google needs, so a trip ending 2026-09-21 goes in as 2026-09-21.', execKey: 'end' },
65
+ 🔴 [2026-09-09] Y ya no dan la clase de formatos. Decían qué formas de
66
+ fecha se aceptan y cuáles se rechazan por ambiguas — un párrafo cada uno,
67
+ debajo de cada campo. Ariel: «quítame esos mensajes».
68
+
69
+ Tenía razón, y lo que los mató fue el propio producto: el campo lleva un
70
+ calendario que ESCRIBE la fecha y la hora, así que la forma ya no la teclea
71
+ nadie. Un texto que explica cómo escribir a mano lo que se elige con un
72
+ clic no es ayuda, es ruido — y encima ocupa el sitio donde se lee lo que sí
73
+ importa.
74
+
75
+ Y no se quedó ninguna suelta: las dos fechas se leen JUNTAS —una es el
76
+ principio y la otra el final de lo mismo—, así que la pantalla las mete en
77
+ un bloque con una regla arriba y otra abajo y pone la nota UNA vez al pie
78
+ (`NOTA_DE_LAS_FECHAS`, en `CalendarActionDetail.tsx` del dashboard). Ariel:
79
+ «crea una sección para el start y end date… y en esa sección agregas el
80
+ mensaje, para no repetir información».
81
+
82
+ ⚠️ Ahí sigue entera la frase del ÚLTIMO DÍA INCLUIDO, que es la única que
83
+ no es de formato y la única que no se puede recortar: el `+1` de la
84
+ exclusividad de `end.date` en Google lo pone HostWebhook, no da error, y
85
+ quien lo sepa y no lo lea lo suma otra vez. */
86
+ { name: 'startTemplate', target: 'eventConfig', label: 'Start Date', type: 'template', placeholder: '{{payload.startTime}}', execKey: 'start' },
87
+ { name: 'endTemplate', target: 'eventConfig', label: 'End Date', type: 'template', placeholder: '{{payload.endTime}}', execKey: 'end' },
70
88
  {
71
89
  name: 'attendeesTemplate',
72
90
  target: 'eventConfig',
@@ -14,3 +14,11 @@ export declare const NODE_DISPATCH: Record<NodeType, NodeDispatchConfig>;
14
14
  export declare function getAllNodeCollections(): string[];
15
15
  /** Find dispatch config by node type */
16
16
  export declare function getNodeDispatchConfig(type: string): NodeDispatchConfig | undefined;
17
+ /**
18
+ * ¿Este tipo de nodo pasa hacia abajo lo que le ENTRA, en vez de lo que produce?
19
+ *
20
+ * Un tipo desconocido contesta `false`, que es el caso de casi todos y el que
21
+ * no cambia nada: quien pregunte por un tipo que no está en la tabla se queda
22
+ * con el comportamiento de siempre en vez de con una ausencia que tratar.
23
+ */
24
+ export declare function pasaLoQueRecibe(type: string): boolean;
package/dist/dispatch.js CHANGED
@@ -13,64 +13,65 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.NODE_DISPATCH = void 0;
14
14
  exports.getAllNodeCollections = getAllNodeCollections;
15
15
  exports.getNodeDispatchConfig = getNodeDispatchConfig;
16
+ exports.pasaLoQueRecibe = pasaLoQueRecibe;
16
17
  exports.NODE_DISPATCH = {
17
18
  // ── Pipeline processing — generic dispatch off webhook ──
18
- filter: { service: 'filterNodesService', collection: 'filternodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic' },
19
- transform: { service: 'transformNodesService', collection: 'transformnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic' },
20
- code: { service: 'codeNodesService', collection: 'codenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
21
- ai: { service: 'aiNodesService', collection: 'ainodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
22
- markdown: { service: 'markdownNodesService', collection: 'markdownnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
23
- fileTransform: { service: 'fileTransformNodesService', collection: 'filetransformnodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
24
- vectorStore: { service: 'vectorStoreNodesService', collection: 'vectorstorenodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
25
- limit: { service: 'limitNodesService', collection: 'limitnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic' },
19
+ filter: { service: 'filterNodesService', collection: 'filternodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic', downstreamPayload: 'result' },
20
+ transform: { service: 'transformNodesService', collection: 'transformnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic', downstreamPayload: 'result' },
21
+ code: { service: 'codeNodesService', collection: 'codenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
22
+ ai: { service: 'aiNodesService', collection: 'ainodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
23
+ markdown: { service: 'markdownNodesService', collection: 'markdownnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
24
+ fileTransform: { service: 'fileTransformNodesService', collection: 'filetransformnodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
25
+ vectorStore: { service: 'vectorStoreNodesService', collection: 'vectorstorenodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
26
+ limit: { service: 'limitNodesService', collection: 'limitnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic', downstreamPayload: 'result' },
26
27
  // ── Pipeline processing — custom dispatch (dedicated switch case) ──
27
- schemaValidator: { service: 'schemaValidatorsService', collection: 'schemavalidators', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
28
- delay: { service: 'delayNodesService', collection: 'delaynodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
29
- rateLimiter: { service: 'rateLimiterNodesService', collection: 'ratelimiternodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
30
- aggregator: { service: 'aggregatorNodesService', collection: 'aggregatornodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
31
- cache: { service: 'cacheNodesService', collection: 'cachenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
28
+ schemaValidator: { service: 'schemaValidatorsService', collection: 'schemavalidators', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
29
+ delay: { service: 'delayNodesService', collection: 'delaynodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
30
+ rateLimiter: { service: 'rateLimiterNodesService', collection: 'ratelimiternodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
31
+ aggregator: { service: 'aggregatorNodesService', collection: 'aggregatornodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
32
+ cache: { service: 'cacheNodesService', collection: 'cachenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
32
33
  // ── Flow control — custom dispatch (branching / merging / loops) ──
33
- split: { service: 'splitNodesService', collection: 'splitnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
34
- conditional: { service: 'conditionalNodesService', collection: 'conditionalnodes', hasFilters: false, outputFields: ['outputNodes', 'elseOutputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
35
- merge: { service: 'mergeNodesService', collection: 'mergenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
36
- approval: { service: 'approvalNodesService', collection: 'approvalnodes', hasFilters: false, outputFields: ['outputNodes', 'rejectionOutputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
37
- loop: { service: 'loopNodesService', collection: 'loopnodes', hasFilters: false, outputFields: ['loopOutputNodes', 'doneOutputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
34
+ split: { service: 'splitNodesService', collection: 'splitnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
35
+ conditional: { service: 'conditionalNodesService', collection: 'conditionalnodes', hasFilters: false, outputFields: ['outputNodes', 'elseOutputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'original' },
36
+ merge: { service: 'mergeNodesService', collection: 'mergenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
37
+ approval: { service: 'approvalNodesService', collection: 'approvalnodes', hasFilters: false, outputFields: ['outputNodes', 'rejectionOutputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
38
+ loop: { service: 'loopNodesService', collection: 'loopnodes', hasFilters: false, outputFields: ['loopOutputNodes', 'doneOutputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
38
39
  // ── Routing — custom dispatch ──
39
- router: { service: 'routersService', collection: 'routers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
40
+ router: { service: 'routersService', collection: 'routers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
40
41
  // ── Action nodes — fired in onDeliveryResult, excluded from webhook dispatch ──
41
- emailAction: { service: 'emailActionsService', collection: 'emailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
42
- gmailAction: { service: 'gmailActionsService', collection: 'gmailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
43
- httpAction: { service: 'httpActionsService', collection: 'httpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
44
- mongoAction: { service: 'mongoActionsService', collection: 'mongoactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
45
- postgresAction: { service: 'postgresActionsService', collection: 'postgresactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
46
- notificationAction: { service: 'notificationActionsService', collection: 'notificationactions', hasFilters: true, outputFields: [], customDispatch: true, pipelineDispatch: 'excluded' },
47
- sheetsAction: { service: 'sheetsActionsService', collection: 'sheetsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
48
- calendarAction: { service: 'calendarActionsService', collection: 'calendaractions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
49
- docsAction: { service: 'docsActionsService', collection: 'docsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
50
- driveAction: { service: 'driveActionsService', collection: 'driveactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
51
- firecrawlAction: { service: 'firecrawlActionsService', collection: 'firecrawlactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
52
- telegramAction: { service: 'telegramActionsService', collection: 'telegramactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
53
- whatsappAction: { service: 'whatsappActionsService', collection: 'whatsappactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
54
- discordAction: { service: 'discordActionsService', collection: 'discordactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
55
- mailchimpAction: { service: 'mailchimpActionsService', collection: 'mailchimpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
56
- shopifyAction: { service: 'shopifyActionsService', collection: 'shopifyactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
57
- githubAction: { service: 'githubActionsService', collection: 'githubactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
58
- jiraAction: { service: 'jiraActionsService', collection: 'jiraactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
59
- bucketAction: { service: 'bucketActionsService', collection: 'bucketactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
60
- slackAction: { service: 'slackActionsService', collection: 'slackactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
61
- googleContactsAction: { service: 'googleContactsActionsService', collection: 'googlecontactsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
62
- googleAnalyticsAction: { service: 'googleAnalyticsActionsService', collection: 'googleanalyticsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
63
- notionAction: { service: 'notionActionsService', collection: 'notionactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
64
- rssAction: { service: 'rssActionsService', collection: 'rssactions', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
65
- socialMediaAction: { service: 'socialMediaActionsService', collection: 'socialmediaactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
42
+ emailAction: { service: 'emailActionsService', collection: 'emailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'original' },
43
+ gmailAction: { service: 'gmailActionsService', collection: 'gmailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'original' },
44
+ httpAction: { service: 'httpActionsService', collection: 'httpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
45
+ mongoAction: { service: 'mongoActionsService', collection: 'mongoactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
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: 'original' },
48
+ sheetsAction: { service: 'sheetsActionsService', collection: 'sheetsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
49
+ calendarAction: { service: 'calendarActionsService', collection: 'calendaractions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
50
+ docsAction: { service: 'docsActionsService', collection: 'docsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
51
+ driveAction: { service: 'driveActionsService', collection: 'driveactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
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: 'original' },
54
+ whatsappAction: { service: 'whatsappActionsService', collection: 'whatsappactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'original' },
55
+ discordAction: { service: 'discordActionsService', collection: 'discordactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'original' },
56
+ mailchimpAction: { service: 'mailchimpActionsService', collection: 'mailchimpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
57
+ shopifyAction: { service: 'shopifyActionsService', collection: 'shopifyactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
58
+ githubAction: { service: 'githubActionsService', collection: 'githubactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
59
+ jiraAction: { service: 'jiraActionsService', collection: 'jiraactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
60
+ 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: 'original' },
62
+ googleContactsAction: { service: 'googleContactsActionsService', collection: 'googlecontactsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
63
+ googleAnalyticsAction: { service: 'googleAnalyticsActionsService', collection: 'googleanalyticsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
64
+ notionAction: { service: 'notionActionsService', collection: 'notionactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
65
+ 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: 'original' },
66
67
  // ── Sources — start the flow themselves, not dispatched ──
67
- webhook: { service: 'webhooksService', collection: 'webhooks', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
68
- scheduledWorkflow: { service: 'scheduledWorkflowsService', collection: 'scheduledworkflows', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
69
- chatTrigger: { service: 'chatTriggersService', collection: 'chattriggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
70
- trigger: { service: 'triggersService', collection: 'triggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
71
- voiceAgent: { service: 'voiceAgentsService', collection: 'voiceagents', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
68
+ webhook: { service: 'webhooksService', collection: 'webhooks', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
69
+ scheduledWorkflow: { service: 'scheduledWorkflowsService', collection: 'scheduledworkflows', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
70
+ chatTrigger: { service: 'chatTriggersService', collection: 'chattriggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
71
+ trigger: { service: 'triggersService', collection: 'triggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
72
+ voiceAgent: { service: 'voiceAgentsService', collection: 'voiceagents', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
72
73
  // ── Annotation — never executed in pipeline ──
73
- stickyNote: { service: 'stickyNotesService', collection: 'stickynotes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
74
+ stickyNote: { service: 'stickyNotesService', collection: 'stickynotes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
74
75
  };
75
76
  /** Get all MongoDB collection names for cascade cleanup */
76
77
  function getAllNodeCollections() {
@@ -80,3 +81,13 @@ function getAllNodeCollections() {
80
81
  function getNodeDispatchConfig(type) {
81
82
  return exports.NODE_DISPATCH[type];
82
83
  }
84
+ /**
85
+ * ¿Este tipo de nodo pasa hacia abajo lo que le ENTRA, en vez de lo que produce?
86
+ *
87
+ * Un tipo desconocido contesta `false`, que es el caso de casi todos y el que
88
+ * no cambia nada: quien pregunte por un tipo que no está en la tabla se queda
89
+ * con el comportamiento de siempre en vez de con una ausencia que tratar.
90
+ */
91
+ function pasaLoQueRecibe(type) {
92
+ return getNodeDispatchConfig(type)?.downstreamPayload === 'original';
93
+ }
@@ -58,11 +58,29 @@ const eventConfigParams = () => [
58
58
  entera de la regla de ambigüedad ANTES de mandar el payload. `05-06-2026`
59
59
  se rechaza en ejecución (ver `normalizeDate`), y un rechazo que sólo
60
60
  aparece en el log del run llega tarde: aquí se dice al lado del campo.
61
- El de End Date dice además que es el ÚLTIMO DÍA INCLUIDO, porque el `+1`
62
- de la exclusividad de Google lo pone HostWebhook y sin decirlo el usuario
63
- lo escribiría dos veces. */
64
- { name: 'startTemplate', target: 'eventConfig', label: 'Start Date', type: 'template', placeholder: '{{payload.startTime}}', description: 'YYYY-MM-DD for an all-day event, or YYYY-MM-DDTHH:mm:ss for a timed one (interpreted in the Time Zone below). M-D-YYYY and D-M-YYYY work only when one part is above 12 — 05-06-2026 is rejected as ambiguous instead of guessed.', execKey: 'start' },
65
- { name: 'endTemplate', target: 'eventConfig', label: 'End Date', type: 'template', placeholder: '{{payload.endTime}}', description: 'YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss, same rules as Start Date. For all-day events this is the LAST DAY INCLUDED — HostWebhook adds the extra day Google needs, so a trip ending 2026-09-21 goes in as 2026-09-21.', execKey: 'end' },
61
+ 🔴 [2026-09-09] Y ya no dan la clase de formatos. Decían qué formas de
62
+ fecha se aceptan y cuáles se rechazan por ambiguas — un párrafo cada uno,
63
+ debajo de cada campo. Ariel: «quítame esos mensajes».
64
+
65
+ Tenía razón, y lo que los mató fue el propio producto: el campo lleva un
66
+ calendario que ESCRIBE la fecha y la hora, así que la forma ya no la teclea
67
+ nadie. Un texto que explica cómo escribir a mano lo que se elige con un
68
+ clic no es ayuda, es ruido — y encima ocupa el sitio donde se lee lo que sí
69
+ importa.
70
+
71
+ Y no se quedó ninguna suelta: las dos fechas se leen JUNTAS —una es el
72
+ principio y la otra el final de lo mismo—, así que la pantalla las mete en
73
+ un bloque con una regla arriba y otra abajo y pone la nota UNA vez al pie
74
+ (`NOTA_DE_LAS_FECHAS`, en `CalendarActionDetail.tsx` del dashboard). Ariel:
75
+ «crea una sección para el start y end date… y en esa sección agregas el
76
+ mensaje, para no repetir información».
77
+
78
+ ⚠️ Ahí sigue entera la frase del ÚLTIMO DÍA INCLUIDO, que es la única que
79
+ no es de formato y la única que no se puede recortar: el `+1` de la
80
+ exclusividad de `end.date` en Google lo pone HostWebhook, no da error, y
81
+ quien lo sepa y no lo lea lo suma otra vez. */
82
+ { name: 'startTemplate', target: 'eventConfig', label: 'Start Date', type: 'template', placeholder: '{{payload.startTime}}', execKey: 'start' },
83
+ { name: 'endTemplate', target: 'eventConfig', label: 'End Date', type: 'template', placeholder: '{{payload.endTime}}', execKey: 'end' },
66
84
  {
67
85
  name: 'attendeesTemplate',
68
86
  target: 'eventConfig',
@@ -14,3 +14,11 @@ export declare const NODE_DISPATCH: Record<NodeType, NodeDispatchConfig>;
14
14
  export declare function getAllNodeCollections(): string[];
15
15
  /** Find dispatch config by node type */
16
16
  export declare function getNodeDispatchConfig(type: string): NodeDispatchConfig | undefined;
17
+ /**
18
+ * ¿Este tipo de nodo pasa hacia abajo lo que le ENTRA, en vez de lo que produce?
19
+ *
20
+ * Un tipo desconocido contesta `false`, que es el caso de casi todos y el que
21
+ * no cambia nada: quien pregunte por un tipo que no está en la tabla se queda
22
+ * con el comportamiento de siempre en vez de con una ausencia que tratar.
23
+ */
24
+ export declare function pasaLoQueRecibe(type: string): boolean;
@@ -10,62 +10,62 @@
10
10
  */
11
11
  export const NODE_DISPATCH = {
12
12
  // ── Pipeline processing — generic dispatch off webhook ──
13
- filter: { service: 'filterNodesService', collection: 'filternodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic' },
14
- transform: { service: 'transformNodesService', collection: 'transformnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic' },
15
- code: { service: 'codeNodesService', collection: 'codenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
16
- ai: { service: 'aiNodesService', collection: 'ainodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
17
- markdown: { service: 'markdownNodesService', collection: 'markdownnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
18
- fileTransform: { service: 'fileTransformNodesService', collection: 'filetransformnodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
19
- vectorStore: { service: 'vectorStoreNodesService', collection: 'vectorstorenodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic' },
20
- limit: { service: 'limitNodesService', collection: 'limitnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic' },
13
+ filter: { service: 'filterNodesService', collection: 'filternodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic', downstreamPayload: 'result' },
14
+ transform: { service: 'transformNodesService', collection: 'transformnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic', downstreamPayload: 'result' },
15
+ code: { service: 'codeNodesService', collection: 'codenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
16
+ ai: { service: 'aiNodesService', collection: 'ainodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
17
+ markdown: { service: 'markdownNodesService', collection: 'markdownnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
18
+ fileTransform: { service: 'fileTransformNodesService', collection: 'filetransformnodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
19
+ vectorStore: { service: 'vectorStoreNodesService', collection: 'vectorstorenodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'generic', downstreamPayload: 'result' },
20
+ limit: { service: 'limitNodesService', collection: 'limitnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: false, pipelineDispatch: 'generic', downstreamPayload: 'result' },
21
21
  // ── Pipeline processing — custom dispatch (dedicated switch case) ──
22
- schemaValidator: { service: 'schemaValidatorsService', collection: 'schemavalidators', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
23
- delay: { service: 'delayNodesService', collection: 'delaynodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
24
- rateLimiter: { service: 'rateLimiterNodesService', collection: 'ratelimiternodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
25
- aggregator: { service: 'aggregatorNodesService', collection: 'aggregatornodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
26
- cache: { service: 'cacheNodesService', collection: 'cachenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
22
+ schemaValidator: { service: 'schemaValidatorsService', collection: 'schemavalidators', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
23
+ delay: { service: 'delayNodesService', collection: 'delaynodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
24
+ rateLimiter: { service: 'rateLimiterNodesService', collection: 'ratelimiternodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
25
+ aggregator: { service: 'aggregatorNodesService', collection: 'aggregatornodes', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
26
+ cache: { service: 'cacheNodesService', collection: 'cachenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
27
27
  // ── Flow control — custom dispatch (branching / merging / loops) ──
28
- split: { service: 'splitNodesService', collection: 'splitnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
29
- conditional: { service: 'conditionalNodesService', collection: 'conditionalnodes', hasFilters: false, outputFields: ['outputNodes', 'elseOutputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
30
- merge: { service: 'mergeNodesService', collection: 'mergenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
31
- approval: { service: 'approvalNodesService', collection: 'approvalnodes', hasFilters: false, outputFields: ['outputNodes', 'rejectionOutputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
32
- loop: { service: 'loopNodesService', collection: 'loopnodes', hasFilters: false, outputFields: ['loopOutputNodes', 'doneOutputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
28
+ split: { service: 'splitNodesService', collection: 'splitnodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
29
+ conditional: { service: 'conditionalNodesService', collection: 'conditionalnodes', hasFilters: false, outputFields: ['outputNodes', 'elseOutputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'original' },
30
+ merge: { service: 'mergeNodesService', collection: 'mergenodes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
31
+ approval: { service: 'approvalNodesService', collection: 'approvalnodes', hasFilters: false, outputFields: ['outputNodes', 'rejectionOutputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
32
+ loop: { service: 'loopNodesService', collection: 'loopnodes', hasFilters: false, outputFields: ['loopOutputNodes', 'doneOutputNodes'], customDispatch: true, pipelineDispatch: 'custom', downstreamPayload: 'result' },
33
33
  // ── Routing — custom dispatch ──
34
- router: { service: 'routersService', collection: 'routers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'custom' },
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' },
37
- gmailAction: { service: 'gmailActionsService', collection: 'gmailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
38
- httpAction: { service: 'httpActionsService', collection: 'httpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
39
- mongoAction: { service: 'mongoActionsService', collection: 'mongoactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
40
- postgresAction: { service: 'postgresActionsService', collection: 'postgresactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
41
- notificationAction: { service: 'notificationActionsService', collection: 'notificationactions', hasFilters: true, outputFields: [], customDispatch: true, pipelineDispatch: 'excluded' },
42
- sheetsAction: { service: 'sheetsActionsService', collection: 'sheetsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
43
- calendarAction: { service: 'calendarActionsService', collection: 'calendaractions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
44
- docsAction: { service: 'docsActionsService', collection: 'docsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
45
- driveAction: { service: 'driveActionsService', collection: 'driveactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
46
- firecrawlAction: { service: 'firecrawlActionsService', collection: 'firecrawlactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
47
- telegramAction: { service: 'telegramActionsService', collection: 'telegramactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
48
- whatsappAction: { service: 'whatsappActionsService', collection: 'whatsappactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
49
- discordAction: { service: 'discordActionsService', collection: 'discordactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
50
- mailchimpAction: { service: 'mailchimpActionsService', collection: 'mailchimpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
51
- shopifyAction: { service: 'shopifyActionsService', collection: 'shopifyactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
52
- githubAction: { service: 'githubActionsService', collection: 'githubactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
53
- jiraAction: { service: 'jiraActionsService', collection: 'jiraactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
54
- bucketAction: { service: 'bucketActionsService', collection: 'bucketactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
55
- slackAction: { service: 'slackActionsService', collection: 'slackactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
56
- googleContactsAction: { service: 'googleContactsActionsService', collection: 'googlecontactsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
57
- googleAnalyticsAction: { service: 'googleAnalyticsActionsService', collection: 'googleanalyticsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
58
- notionAction: { service: 'notionActionsService', collection: 'notionactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
59
- rssAction: { service: 'rssActionsService', collection: 'rssactions', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
60
- socialMediaAction: { service: 'socialMediaActionsService', collection: 'socialmediaactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
36
+ emailAction: { service: 'emailActionsService', collection: 'emailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'original' },
37
+ gmailAction: { service: 'gmailActionsService', collection: 'gmailactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'original' },
38
+ httpAction: { service: 'httpActionsService', collection: 'httpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
39
+ mongoAction: { service: 'mongoActionsService', collection: 'mongoactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
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: 'original' },
42
+ sheetsAction: { service: 'sheetsActionsService', collection: 'sheetsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
43
+ calendarAction: { service: 'calendarActionsService', collection: 'calendaractions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
44
+ docsAction: { service: 'docsActionsService', collection: 'docsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
45
+ driveAction: { service: 'driveActionsService', collection: 'driveactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
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: 'original' },
48
+ whatsappAction: { service: 'whatsappActionsService', collection: 'whatsappactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'original' },
49
+ discordAction: { service: 'discordActionsService', collection: 'discordactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'original' },
50
+ mailchimpAction: { service: 'mailchimpActionsService', collection: 'mailchimpactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
51
+ shopifyAction: { service: 'shopifyActionsService', collection: 'shopifyactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
52
+ githubAction: { service: 'githubActionsService', collection: 'githubactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
53
+ jiraAction: { service: 'jiraActionsService', collection: 'jiraactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
54
+ 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: 'original' },
56
+ googleContactsAction: { service: 'googleContactsActionsService', collection: 'googlecontactsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
57
+ googleAnalyticsAction: { service: 'googleAnalyticsActionsService', collection: 'googleanalyticsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
58
+ notionAction: { service: 'notionActionsService', collection: 'notionactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
59
+ 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: 'original' },
61
61
  // ── Sources — start the flow themselves, not dispatched ──
62
- webhook: { service: 'webhooksService', collection: 'webhooks', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
63
- scheduledWorkflow: { service: 'scheduledWorkflowsService', collection: 'scheduledworkflows', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
64
- chatTrigger: { service: 'chatTriggersService', collection: 'chattriggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
65
- trigger: { service: 'triggersService', collection: 'triggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
66
- voiceAgent: { service: 'voiceAgentsService', collection: 'voiceagents', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
62
+ webhook: { service: 'webhooksService', collection: 'webhooks', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
63
+ scheduledWorkflow: { service: 'scheduledWorkflowsService', collection: 'scheduledworkflows', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
64
+ chatTrigger: { service: 'chatTriggersService', collection: 'chattriggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
65
+ trigger: { service: 'triggersService', collection: 'triggers', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
66
+ voiceAgent: { service: 'voiceAgentsService', collection: 'voiceagents', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
67
67
  // ── Annotation — never executed in pipeline ──
68
- stickyNote: { service: 'stickyNotesService', collection: 'stickynotes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
68
+ stickyNote: { service: 'stickyNotesService', collection: 'stickynotes', hasFilters: false, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded', downstreamPayload: 'result' },
69
69
  };
70
70
  /** Get all MongoDB collection names for cascade cleanup */
71
71
  export function getAllNodeCollections() {
@@ -75,3 +75,13 @@ export function getAllNodeCollections() {
75
75
  export function getNodeDispatchConfig(type) {
76
76
  return NODE_DISPATCH[type];
77
77
  }
78
+ /**
79
+ * ¿Este tipo de nodo pasa hacia abajo lo que le ENTRA, en vez de lo que produce?
80
+ *
81
+ * Un tipo desconocido contesta `false`, que es el caso de casi todos y el que
82
+ * no cambia nada: quien pregunte por un tipo que no está en la tabla se queda
83
+ * con el comportamiento de siempre en vez de con una ausencia que tratar.
84
+ */
85
+ export function pasaLoQueRecibe(type) {
86
+ return getNodeDispatchConfig(type)?.downstreamPayload === 'original';
87
+ }
@@ -1,8 +1,8 @@
1
- export type { NodeType, NodeRole, HandlePosition, NodeConnectionConfig, NodeUIConfig, NodeDispatchConfig, PrefixMapping, PayloadMeta, } from './types.js';
1
+ export type { NodeType, NodeRole, HandlePosition, NodeConnectionConfig, NodeUIConfig, NodeDispatchConfig, DownstreamPayload, PrefixMapping, PayloadMeta, } from './types.js';
2
2
  export { singleMeta, iterableMeta } from './types.js';
3
3
  export { NODE_CONNECTIONS, canReceiveFrom, canReceiveFromNodes, canSendToNodes, isTerminal, isNodeType, ALL_NODE_TYPES, } from './connections.js';
4
4
  export { NODE_UI, PREFIX_TO_TYPE, resolveNodeId, } from './ui.js';
5
- export { NODE_DISPATCH, getAllNodeCollections, getNodeDispatchConfig, } from './dispatch.js';
5
+ export { NODE_DISPATCH, getAllNodeCollections, getNodeDispatchConfig, pasaLoQueRecibe, } from './dispatch.js';
6
6
  export type { NodeRegistryEntry, NodeGroup, NodeVersionSpec, VersionCatalog, } from './registry.js';
7
7
  export { NODE_REGISTRY, getNodeRegistryEntry, NODE_DETAIL_PATHS, NODE_COLORS, NODE_STATE_KEYS, PREFIX_TO_NODE_TYPE, NODE_TYPE_TO_PREFIX, } from './registry.js';
8
8
  export { isVersioned, versionsOf, versionSpec, currentVersion, fieldsLostBetween, fieldsLost, versionCatalogErrors, } from './registry.js';
package/dist/esm/index.js CHANGED
@@ -3,8 +3,10 @@ export { singleMeta, iterableMeta } from './types.js';
3
3
  export { NODE_CONNECTIONS, canReceiveFrom, canReceiveFromNodes, canSendToNodes, isTerminal, isNodeType, ALL_NODE_TYPES, } from './connections.js';
4
4
  // ── UI config (Dashboard only) ──
5
5
  export { NODE_UI, PREFIX_TO_TYPE, resolveNodeId, } from './ui.js';
6
- // ── Dispatch config (API only) ──
7
- export { NODE_DISPATCH, getAllNodeCollections, getNodeDispatchConfig, } from './dispatch.js';
6
+ // ── Dispatch config ──
7
+ /* Ya no es «API only»: `downstreamPayload` lo lee tambien el panel, que sin el
8
+ ensenaba como entrada de un nodo la salida del que pasa de largo. */
9
+ export { NODE_DISPATCH, getAllNodeCollections, getNodeDispatchConfig, pasaLoQueRecibe, } from './dispatch.js';
8
10
  export { NODE_REGISTRY, getNodeRegistryEntry, NODE_DETAIL_PATHS, NODE_COLORS, NODE_STATE_KEYS, PREFIX_TO_NODE_TYPE, NODE_TYPE_TO_PREFIX, } from './registry.js';
9
11
  // ── Node version catalog (ALL repos) ──
10
12
  // See docs/ADR-0002-node-versioning.md in the api repo.
@@ -179,7 +179,34 @@ export interface NodeDispatchConfig {
179
179
  customDispatch: boolean;
180
180
  /** Required. See PipelineDispatchKind for the contract per value. */
181
181
  pipelineDispatch: PipelineDispatchKind;
182
+ /** Required. See DownstreamPayload. */
183
+ downstreamPayload: DownstreamPayload;
182
184
  }
185
+ /**
186
+ * Que pone este nodo en la cinta para el de abajo.
187
+ *
188
+ * `'result'` es lo normal: baja lo que este nodo produjo.
189
+ *
190
+ * `'original'` es el nodo que NO transforma —notifica, o rutea—: baja su
191
+ * ENTRADA intacta, y su propia salida (el acuse del envio, la rama que caso)
192
+ * NO baja con ella. Nueve tipos hoy.
193
+ *
194
+ * ## Por que vive aqui y no solo en el handler
195
+ *
196
+ * Porque no es un detalle del ejecutor: decide QUE CAMPOS existen aguas abajo,
197
+ * y de eso vive tambien el panel. Estaba escrito solo en los handlers de
198
+ * hw-nodes, el dashboard no podia leerlo, y por eso la columna «Input» de un
199
+ * nodo colgado de un Discord ensenaba el acuse del mensaje —`messageId`,
200
+ * `channelId`, `content`— cuando lo que de verdad le llega es lo que entro al
201
+ * Discord. Quien leyo esa columna escribio su plantilla contra campos que en
202
+ * produccion no existen.
203
+ *
204
+ * El nombre y los dos valores son los MISMOS que declara el handler
205
+ * (`NodeHandler.downstreamPayload` del SDK) a proposito: asi la comprobacion de
206
+ * que no derivan es una igualdad y no una traduccion. Vive en hw-nodes, que es
207
+ * donde estan los handlers.
208
+ */
209
+ export type DownstreamPayload = 'original' | 'result';
183
210
  /** Standardized payload metadata — every node output MUST include _meta */
184
211
  export interface PayloadMeta {
185
212
  iterable: boolean;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export type { NodeType, NodeRole, HandlePosition, NodeConnectionConfig, NodeUIConfig, NodeDispatchConfig, PrefixMapping, PayloadMeta, } from './types.js';
1
+ export type { NodeType, NodeRole, HandlePosition, NodeConnectionConfig, NodeUIConfig, NodeDispatchConfig, DownstreamPayload, PrefixMapping, PayloadMeta, } from './types.js';
2
2
  export { singleMeta, iterableMeta } from './types.js';
3
3
  export { NODE_CONNECTIONS, canReceiveFrom, canReceiveFromNodes, canSendToNodes, isTerminal, isNodeType, ALL_NODE_TYPES, } from './connections.js';
4
4
  export { NODE_UI, PREFIX_TO_TYPE, resolveNodeId, } from './ui.js';
5
- export { NODE_DISPATCH, getAllNodeCollections, getNodeDispatchConfig, } from './dispatch.js';
5
+ export { NODE_DISPATCH, getAllNodeCollections, getNodeDispatchConfig, pasaLoQueRecibe, } from './dispatch.js';
6
6
  export type { NodeRegistryEntry, NodeGroup, NodeVersionSpec, VersionCatalog, } from './registry.js';
7
7
  export { NODE_REGISTRY, getNodeRegistryEntry, NODE_DETAIL_PATHS, NODE_COLORS, NODE_STATE_KEYS, PREFIX_TO_NODE_TYPE, NODE_TYPE_TO_PREFIX, } from './registry.js';
8
8
  export { isVersioned, versionsOf, versionSpec, currentVersion, fieldsLostBetween, fieldsLost, versionCatalogErrors, } from './registry.js';
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DRIVE_OPERATION_SPECS = exports.DRIVE_OPERATIONS = exports.GOOGLE_CALENDAR_TOOLKIT_BY_TOOL_NAME = exports.GOOGLE_CALENDAR_TOOLKIT_SPECS = exports.isGoogleCalendarOperation = exports.GOOGLE_CALENDAR_OPERATION_SPECS = exports.GOOGLE_CALENDAR_OPERATIONS = exports.isGmailOperation = exports.resolveGmailSendFields = exports.GMAIL_SEND_LEGACY_FIELDS = exports.NATIVE_EMAIL_TOOLKIT_BY_TOOL_NAME = exports.GMAIL_TOOLKIT_BY_TOOL_NAME = exports.NATIVE_EMAIL_TOOLKIT_SPECS = exports.GMAIL_SEND_AND_WAIT_TOOL_SPEC = exports.GMAIL_ALL_TOOLKIT_SPECS = exports.GMAIL_TOOLKIT_SPECS = exports.GMAIL_TOOLKIT_OPERATIONS = exports.GMAIL_DROPDOWN_OPERATIONS = exports.GMAIL_OPERATION_GROUPS = exports.GMAIL_OPERATION_SPECS = exports.GMAIL_OPERATIONS = exports.versionCatalogErrors = exports.fieldsLost = exports.fieldsLostBetween = exports.currentVersion = exports.versionSpec = exports.versionsOf = exports.isVersioned = exports.NODE_TYPE_TO_PREFIX = exports.PREFIX_TO_NODE_TYPE = exports.NODE_STATE_KEYS = exports.NODE_COLORS = exports.NODE_DETAIL_PATHS = exports.getNodeRegistryEntry = exports.NODE_REGISTRY = exports.getNodeDispatchConfig = exports.getAllNodeCollections = exports.NODE_DISPATCH = exports.resolveNodeId = exports.PREFIX_TO_TYPE = exports.NODE_UI = exports.ALL_NODE_TYPES = exports.isNodeType = exports.isTerminal = exports.canSendToNodes = exports.canReceiveFromNodes = exports.canReceiveFrom = exports.NODE_CONNECTIONS = exports.iterableMeta = exports.singleMeta = void 0;
4
- exports.isBucketOperation = exports.BUCKET_ITERABLE_OPERATIONS = exports.BUCKET_OPERATION_SPECS = exports.BUCKET_OPERATIONS = exports.isJiraOperation = exports.JIRA_ITERABLE_OPERATIONS = exports.JIRA_DROPDOWN_OPERATIONS = exports.JIRA_OPERATION_SPECS = exports.JIRA_OPERATIONS = exports.isGithubOperation = exports.GITHUB_ITERABLE_OPERATIONS = exports.GITHUB_DROPDOWN_OPERATIONS = exports.GITHUB_OPERATION_SPECS = exports.GITHUB_OPERATIONS = exports.scopesQueFaltanEnShopify = exports.isShopifyOperation = exports.SHOPIFY_PRODUCT_STATUSES = exports.SHOPIFY_CANCEL_REASONS = exports.SHOPIFY_SEARCHABLE_RESOURCES = exports.SHOPIFY_TAGGABLE_RESOURCES = exports.SHOPIFY_OPERATION_SCOPES = exports.SHOPIFY_OPERATION_SPECS = exports.SHOPIFY_OPERATIONS = exports.isMailchimpOperation = exports.MAILCHIMP_CONTACT_STATUSES = exports.MAILCHIMP_OPERATION_SPECS = exports.MAILCHIMP_OPERATIONS = exports.herramientasDeDiscordPara = exports.DISCORD_TOOLKIT_BY_TOOL_NAME = exports.DISCORD_TOOLKIT_SPECS = exports.isDiscordOperation = exports.camposDeDiscordNoDisponibles = exports.discordPuedeEjecutar = exports.operacionesDeDiscordPara = exports.DISCORD_CAPACIDADES_POR_CREDENCIAL = exports.DISCORD_OPERATION_SPECS = exports.DISCORD_OPERATIONS = exports.camposNoDisponiblesPara = exports.puedeEjecutar = exports.operacionesPara = exports.isWhatsAppOperation = exports.WHATSAPP_OPERATIONS = exports.TELEGRAM_TOOLKIT_BY_TOOL_NAME = exports.TELEGRAM_TOOLKIT_SPECS = exports.isTelegramOperation = exports.TELEGRAM_OPERATION_SPECS = exports.TELEGRAM_OPERATIONS = exports.DRIVE_TOOLKIT_BY_TOOL_NAME = exports.DRIVE_TOOLKIT_SPECS = exports.isDriveOperation = void 0;
5
- exports.getModelLabel = exports.getDefaultModel = exports.getModelsFor = exports.MODEL_CONTEXT_WINDOWS = exports.LLM_MODELS = exports.LLM_PROVIDERS = exports.DOCS_TOOLKIT_DEFAULTABLE = exports.DOCS_TOOLKIT_BY_TOOL_NAME = exports.DOCS_TOOLKIT_SPECS = exports.isDocsOperation = exports.DOCS_OPERATION_SPECS = exports.DOCS_OPERATIONS = exports.isMongoOperation = exports.MONGO_OPERATION_SPECS = exports.MONGO_OPERATIONS = exports.isPostgresOperation = exports.POSTGRES_OPERATION_SPECS = exports.POSTGRES_MODES = exports.POSTGRES_OPERATIONS = exports.isNotionOperation = exports.NOTION_DROPDOWN_OPERATIONS = exports.NOTION_OPERATION_SPECS = exports.NOTION_OPERATIONS = exports.isGoogleAnalyticsOperation = exports.GOOGLE_ANALYTICS_DROPDOWN_OPERATIONS = exports.GOOGLE_ANALYTICS_OPERATION_SPECS = exports.GOOGLE_ANALYTICS_OPERATIONS = exports.isGoogleContactsOperation = exports.GOOGLE_CONTACTS_DEFAULT_PERSON_FIELDS = exports.GOOGLE_CONTACTS_OPERATION_GROUPS = exports.GOOGLE_CONTACTS_OPERATION_SPECS = exports.GOOGLE_CONTACTS_OPERATIONS_V2 = exports.GOOGLE_CONTACTS_OPERATIONS_V1 = exports.GOOGLE_CONTACTS_OPERATIONS = exports.SHEETS_TOOLKIT_DEFAULTABLE = exports.SHEETS_TOOLKIT_BY_TOOL_NAME = exports.SHEETS_TOOLKIT_SPECS = exports.isSheetsOperation = exports.SHEETS_OPERATION_SPECS = exports.SHEETS_OPERATIONS = exports.herramientasDeSlackPara = exports.SLACK_TOOLKIT_BY_TOOL_NAME = exports.SLACK_TOOLKIT_SPECS = exports.isSlackOperation = exports.camposDeSlackNoDisponibles = exports.slackPuedeEjecutar = exports.operacionesDeSlackPara = exports.SLACK_CAPACIDADES_POR_CREDENCIAL = exports.SLACK_OPERATION_SPECS = exports.SLACK_OPERATIONS = void 0;
6
- exports.isCredentialType = exports.getCredentialType = exports.credentialTypeValues = exports.CREDENTIAL_TYPE_VALUES = exports.CREDENTIAL_TYPES = exports.ventanaDeContextoDeOpenRouter = exports.opcionesDeModelosDeOpenRouter = exports.URL_DE_MODELOS_DE_OPENROUTER = void 0;
3
+ exports.DRIVE_OPERATIONS = exports.GOOGLE_CALENDAR_TOOLKIT_BY_TOOL_NAME = exports.GOOGLE_CALENDAR_TOOLKIT_SPECS = exports.isGoogleCalendarOperation = exports.GOOGLE_CALENDAR_OPERATION_SPECS = exports.GOOGLE_CALENDAR_OPERATIONS = exports.isGmailOperation = exports.resolveGmailSendFields = exports.GMAIL_SEND_LEGACY_FIELDS = exports.NATIVE_EMAIL_TOOLKIT_BY_TOOL_NAME = exports.GMAIL_TOOLKIT_BY_TOOL_NAME = exports.NATIVE_EMAIL_TOOLKIT_SPECS = exports.GMAIL_SEND_AND_WAIT_TOOL_SPEC = exports.GMAIL_ALL_TOOLKIT_SPECS = exports.GMAIL_TOOLKIT_SPECS = exports.GMAIL_TOOLKIT_OPERATIONS = exports.GMAIL_DROPDOWN_OPERATIONS = exports.GMAIL_OPERATION_GROUPS = exports.GMAIL_OPERATION_SPECS = exports.GMAIL_OPERATIONS = exports.versionCatalogErrors = exports.fieldsLost = exports.fieldsLostBetween = exports.currentVersion = exports.versionSpec = exports.versionsOf = exports.isVersioned = exports.NODE_TYPE_TO_PREFIX = exports.PREFIX_TO_NODE_TYPE = exports.NODE_STATE_KEYS = exports.NODE_COLORS = exports.NODE_DETAIL_PATHS = exports.getNodeRegistryEntry = exports.NODE_REGISTRY = exports.pasaLoQueRecibe = exports.getNodeDispatchConfig = exports.getAllNodeCollections = exports.NODE_DISPATCH = exports.resolveNodeId = exports.PREFIX_TO_TYPE = exports.NODE_UI = exports.ALL_NODE_TYPES = exports.isNodeType = exports.isTerminal = exports.canSendToNodes = exports.canReceiveFromNodes = exports.canReceiveFrom = exports.NODE_CONNECTIONS = exports.iterableMeta = exports.singleMeta = void 0;
4
+ exports.BUCKET_ITERABLE_OPERATIONS = exports.BUCKET_OPERATION_SPECS = exports.BUCKET_OPERATIONS = exports.isJiraOperation = exports.JIRA_ITERABLE_OPERATIONS = exports.JIRA_DROPDOWN_OPERATIONS = exports.JIRA_OPERATION_SPECS = exports.JIRA_OPERATIONS = exports.isGithubOperation = exports.GITHUB_ITERABLE_OPERATIONS = exports.GITHUB_DROPDOWN_OPERATIONS = exports.GITHUB_OPERATION_SPECS = exports.GITHUB_OPERATIONS = exports.scopesQueFaltanEnShopify = exports.isShopifyOperation = exports.SHOPIFY_PRODUCT_STATUSES = exports.SHOPIFY_CANCEL_REASONS = exports.SHOPIFY_SEARCHABLE_RESOURCES = exports.SHOPIFY_TAGGABLE_RESOURCES = exports.SHOPIFY_OPERATION_SCOPES = exports.SHOPIFY_OPERATION_SPECS = exports.SHOPIFY_OPERATIONS = exports.isMailchimpOperation = exports.MAILCHIMP_CONTACT_STATUSES = exports.MAILCHIMP_OPERATION_SPECS = exports.MAILCHIMP_OPERATIONS = exports.herramientasDeDiscordPara = exports.DISCORD_TOOLKIT_BY_TOOL_NAME = exports.DISCORD_TOOLKIT_SPECS = exports.isDiscordOperation = exports.camposDeDiscordNoDisponibles = exports.discordPuedeEjecutar = exports.operacionesDeDiscordPara = exports.DISCORD_CAPACIDADES_POR_CREDENCIAL = exports.DISCORD_OPERATION_SPECS = exports.DISCORD_OPERATIONS = exports.camposNoDisponiblesPara = exports.puedeEjecutar = exports.operacionesPara = exports.isWhatsAppOperation = exports.WHATSAPP_OPERATIONS = exports.TELEGRAM_TOOLKIT_BY_TOOL_NAME = exports.TELEGRAM_TOOLKIT_SPECS = exports.isTelegramOperation = exports.TELEGRAM_OPERATION_SPECS = exports.TELEGRAM_OPERATIONS = exports.DRIVE_TOOLKIT_BY_TOOL_NAME = exports.DRIVE_TOOLKIT_SPECS = exports.isDriveOperation = exports.DRIVE_OPERATION_SPECS = void 0;
5
+ exports.getDefaultModel = exports.getModelsFor = exports.MODEL_CONTEXT_WINDOWS = exports.LLM_MODELS = exports.LLM_PROVIDERS = exports.DOCS_TOOLKIT_DEFAULTABLE = exports.DOCS_TOOLKIT_BY_TOOL_NAME = exports.DOCS_TOOLKIT_SPECS = exports.isDocsOperation = exports.DOCS_OPERATION_SPECS = exports.DOCS_OPERATIONS = exports.isMongoOperation = exports.MONGO_OPERATION_SPECS = exports.MONGO_OPERATIONS = exports.isPostgresOperation = exports.POSTGRES_OPERATION_SPECS = exports.POSTGRES_MODES = exports.POSTGRES_OPERATIONS = exports.isNotionOperation = exports.NOTION_DROPDOWN_OPERATIONS = exports.NOTION_OPERATION_SPECS = exports.NOTION_OPERATIONS = exports.isGoogleAnalyticsOperation = exports.GOOGLE_ANALYTICS_DROPDOWN_OPERATIONS = exports.GOOGLE_ANALYTICS_OPERATION_SPECS = exports.GOOGLE_ANALYTICS_OPERATIONS = exports.isGoogleContactsOperation = exports.GOOGLE_CONTACTS_DEFAULT_PERSON_FIELDS = exports.GOOGLE_CONTACTS_OPERATION_GROUPS = exports.GOOGLE_CONTACTS_OPERATION_SPECS = exports.GOOGLE_CONTACTS_OPERATIONS_V2 = exports.GOOGLE_CONTACTS_OPERATIONS_V1 = exports.GOOGLE_CONTACTS_OPERATIONS = exports.SHEETS_TOOLKIT_DEFAULTABLE = exports.SHEETS_TOOLKIT_BY_TOOL_NAME = exports.SHEETS_TOOLKIT_SPECS = exports.isSheetsOperation = exports.SHEETS_OPERATION_SPECS = exports.SHEETS_OPERATIONS = exports.herramientasDeSlackPara = exports.SLACK_TOOLKIT_BY_TOOL_NAME = exports.SLACK_TOOLKIT_SPECS = exports.isSlackOperation = exports.camposDeSlackNoDisponibles = exports.slackPuedeEjecutar = exports.operacionesDeSlackPara = exports.SLACK_CAPACIDADES_POR_CREDENCIAL = exports.SLACK_OPERATION_SPECS = exports.SLACK_OPERATIONS = exports.isBucketOperation = void 0;
6
+ exports.isCredentialType = exports.getCredentialType = exports.credentialTypeValues = exports.CREDENTIAL_TYPE_VALUES = exports.CREDENTIAL_TYPES = exports.ventanaDeContextoDeOpenRouter = exports.opcionesDeModelosDeOpenRouter = exports.URL_DE_MODELOS_DE_OPENROUTER = exports.getModelLabel = void 0;
7
7
  var types_js_1 = require("./types.js");
8
8
  Object.defineProperty(exports, "singleMeta", { enumerable: true, get: function () { return types_js_1.singleMeta; } });
9
9
  Object.defineProperty(exports, "iterableMeta", { enumerable: true, get: function () { return types_js_1.iterableMeta; } });
@@ -21,11 +21,14 @@ var ui_js_1 = require("./ui.js");
21
21
  Object.defineProperty(exports, "NODE_UI", { enumerable: true, get: function () { return ui_js_1.NODE_UI; } });
22
22
  Object.defineProperty(exports, "PREFIX_TO_TYPE", { enumerable: true, get: function () { return ui_js_1.PREFIX_TO_TYPE; } });
23
23
  Object.defineProperty(exports, "resolveNodeId", { enumerable: true, get: function () { return ui_js_1.resolveNodeId; } });
24
- // ── Dispatch config (API only) ──
24
+ // ── Dispatch config ──
25
+ /* Ya no es «API only»: `downstreamPayload` lo lee tambien el panel, que sin el
26
+ ensenaba como entrada de un nodo la salida del que pasa de largo. */
25
27
  var dispatch_js_1 = require("./dispatch.js");
26
28
  Object.defineProperty(exports, "NODE_DISPATCH", { enumerable: true, get: function () { return dispatch_js_1.NODE_DISPATCH; } });
27
29
  Object.defineProperty(exports, "getAllNodeCollections", { enumerable: true, get: function () { return dispatch_js_1.getAllNodeCollections; } });
28
30
  Object.defineProperty(exports, "getNodeDispatchConfig", { enumerable: true, get: function () { return dispatch_js_1.getNodeDispatchConfig; } });
31
+ Object.defineProperty(exports, "pasaLoQueRecibe", { enumerable: true, get: function () { return dispatch_js_1.pasaLoQueRecibe; } });
29
32
  var registry_js_1 = require("./registry.js");
30
33
  Object.defineProperty(exports, "NODE_REGISTRY", { enumerable: true, get: function () { return registry_js_1.NODE_REGISTRY; } });
31
34
  Object.defineProperty(exports, "getNodeRegistryEntry", { enumerable: true, get: function () { return registry_js_1.getNodeRegistryEntry; } });
package/dist/types.d.ts CHANGED
@@ -179,7 +179,34 @@ export interface NodeDispatchConfig {
179
179
  customDispatch: boolean;
180
180
  /** Required. See PipelineDispatchKind for the contract per value. */
181
181
  pipelineDispatch: PipelineDispatchKind;
182
+ /** Required. See DownstreamPayload. */
183
+ downstreamPayload: DownstreamPayload;
182
184
  }
185
+ /**
186
+ * Que pone este nodo en la cinta para el de abajo.
187
+ *
188
+ * `'result'` es lo normal: baja lo que este nodo produjo.
189
+ *
190
+ * `'original'` es el nodo que NO transforma —notifica, o rutea—: baja su
191
+ * ENTRADA intacta, y su propia salida (el acuse del envio, la rama que caso)
192
+ * NO baja con ella. Nueve tipos hoy.
193
+ *
194
+ * ## Por que vive aqui y no solo en el handler
195
+ *
196
+ * Porque no es un detalle del ejecutor: decide QUE CAMPOS existen aguas abajo,
197
+ * y de eso vive tambien el panel. Estaba escrito solo en los handlers de
198
+ * hw-nodes, el dashboard no podia leerlo, y por eso la columna «Input» de un
199
+ * nodo colgado de un Discord ensenaba el acuse del mensaje —`messageId`,
200
+ * `channelId`, `content`— cuando lo que de verdad le llega es lo que entro al
201
+ * Discord. Quien leyo esa columna escribio su plantilla contra campos que en
202
+ * produccion no existen.
203
+ *
204
+ * El nombre y los dos valores son los MISMOS que declara el handler
205
+ * (`NodeHandler.downstreamPayload` del SDK) a proposito: asi la comprobacion de
206
+ * que no derivan es una igualdad y no una traduccion. Vive en hw-nodes, que es
207
+ * donde estan los handlers.
208
+ */
209
+ export type DownstreamPayload = 'original' | 'result';
183
210
  /** Standardized payload metadata — every node output MUST include _meta */
184
211
  export interface PayloadMeta {
185
212
  iterable: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostwebhook/node-types",
3
- "version": "1.75.2",
3
+ "version": "1.76.0",
4
4
  "description": "Shared node type definitions, connection rules, and dispatch config for HostWebhook",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/esm/index.js",