@hostwebhook/node-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/code-runner.d.ts +20 -0
  2. package/dist/code-runner.js +138 -0
  3. package/dist/contratos.d.ts +121 -0
  4. package/dist/contratos.js +24 -0
  5. package/dist/dto/output-node.dto.d.ts +19 -0
  6. package/dist/dto/output-node.dto.js +96 -0
  7. package/dist/ensure-meta.d.ts +22 -0
  8. package/dist/ensure-meta.js +35 -0
  9. package/dist/execute-with-iteration.d.ts +18 -0
  10. package/dist/execute-with-iteration.js +66 -0
  11. package/dist/filter-utils.d.ts +22 -0
  12. package/dist/filter-utils.js +178 -0
  13. package/dist/handler-helpers.d.ts +21 -0
  14. package/dist/handler-helpers.js +53 -0
  15. package/dist/index.d.ts +51 -0
  16. package/dist/index.js +73 -0
  17. package/dist/log-metadata.d.ts +191 -0
  18. package/dist/log-metadata.js +375 -0
  19. package/dist/node-dispatch.registry.d.ts +32 -0
  20. package/dist/node-dispatch.registry.js +45 -0
  21. package/dist/node-executors.d.ts +299 -0
  22. package/dist/node-executors.js +555 -0
  23. package/dist/node-lifecycle.d.ts +399 -0
  24. package/dist/node-lifecycle.js +782 -0
  25. package/dist/normalize-nodes.d.ts +18 -0
  26. package/dist/normalize-nodes.js +22 -0
  27. package/dist/output-node-ref.schema.d.ts +82 -0
  28. package/dist/output-node-ref.schema.js +90 -0
  29. package/dist/output-webhook-scope.d.ts +36 -0
  30. package/dist/output-webhook-scope.js +42 -0
  31. package/dist/payload-preview.d.ts +10 -0
  32. package/dist/payload-preview.js +39 -0
  33. package/dist/pipeline.constants.d.ts +29 -0
  34. package/dist/pipeline.constants.js +51 -0
  35. package/dist/pre-request-pool.d.ts +58 -0
  36. package/dist/pre-request-pool.js +308 -0
  37. package/dist/pre-request-runner-source.d.ts +28 -0
  38. package/dist/pre-request-runner-source.js +411 -0
  39. package/dist/regex-de-inquilino.d.ts +15 -0
  40. package/dist/regex-de-inquilino.js +98 -0
  41. package/dist/request-context.d.ts +18 -0
  42. package/dist/request-context.js +34 -0
  43. package/dist/retry-transient.d.ts +54 -0
  44. package/dist/retry-transient.js +67 -0
  45. package/dist/retry-utils.d.ts +17 -0
  46. package/dist/retry-utils.js +23 -0
  47. package/dist/schema-validator-utils.d.ts +9 -0
  48. package/dist/schema-validator-utils.js +140 -0
  49. package/dist/ssrf-guard.d.ts +202 -0
  50. package/dist/ssrf-guard.js +917 -0
  51. package/dist/swallow.d.ts +52 -0
  52. package/dist/swallow.js +55 -0
  53. package/dist/template-render.d.ts +33 -0
  54. package/dist/template-render.js +43 -0
  55. package/dist/try-parse.d.ts +41 -0
  56. package/dist/try-parse.js +69 -0
  57. package/dist/workspace-payloads.d.ts +66 -0
  58. package/dist/workspace-payloads.js +496 -0
  59. package/package.json +35 -0
@@ -0,0 +1,399 @@
1
+ /**
2
+ * Unified Node Lifecycle — single dispatch function for all 3 execution paths.
3
+ *
4
+ * Each node type registers a NodeHandler. dispatchSingleNode() runs the
5
+ * standard lifecycle: fetch → validate → filter → execute → save → delivery → telemetry → downstream.
6
+ * Only the execute step is node-specific.
7
+ */
8
+ import { Types } from 'mongoose';
9
+ import type { PasoEjecutado, RunStepStatus } from './contratos';
10
+ import { type NodeExecutionResult, type NodeExecutorServices, type ExecutorContext } from './node-executors';
11
+ import type { EmisorDeTelemetria as TelemetryService, LogSource } from './contratos';
12
+ /**
13
+ * ⚠️ Extiende `ContextoDelHistorial` a propósito, y no lo repite: son el mismo
14
+ * `orgId`, el mismo `event` y el mismo `webhook`, y dos declaraciones paralelas
15
+ * se separan en cuanto una crezca. Así el compilador garantiza que todo
16
+ * contexto del pipeline sirve para anotar un paso.
17
+ */
18
+ export interface NodeLifecycleContext extends ContextoDelHistorial {
19
+ mode: 'prod' | 'pipeline-run' | 'test';
20
+ orgId: string;
21
+ event: {
22
+ id: string;
23
+ headers: Record<string, unknown>;
24
+ sourceIp?: string;
25
+ eventType?: string;
26
+ correlationId?: string;
27
+ createdAt?: Date;
28
+ };
29
+ webhook: {
30
+ id: string;
31
+ name: string;
32
+ };
33
+ depth: number;
34
+ services: NodeExecutorServices;
35
+ executorContext: ExecutorContext;
36
+ /** Telemetry service (prod + pipeline-run) */
37
+ telemetry?: TelemetryService;
38
+ /**
39
+ * El historial de corridas. CONVIVE con la telemetría: durante un
40
+ * tiempo cada paso se escribe en los dos sitios, que es lo que permite
41
+ * comprobar que el historial no pierde nada antes de retirar el otro.
42
+ *
43
+ * Opcional por lo mismo que `telemetry`: los modos que no lo traen
44
+ * —tests, ejecuciones sueltas— siguen funcionando sin él.
45
+ */
46
+ historial?: {
47
+ registrarPaso(paso: PasoEjecutado): void;
48
+ };
49
+ /** WebSocket gateway for emitting real-time node payload updates */
50
+ gateway?: {
51
+ emitPipelineStep(orgId: string, step: object): void;
52
+ emitNodePayload(orgId: string, data: {
53
+ nodeType: string;
54
+ nodeId: string;
55
+ lastPayload: unknown;
56
+ }): void;
57
+ resolveSyncWaiter(eventId: string, result: {
58
+ status: number;
59
+ body: Record<string, unknown>;
60
+ }): void;
61
+ };
62
+ /** Delivery model for creating delivery records (prod only) */
63
+ deliveryModel?: any;
64
+ /** Dispatch downstream outputs — provided by the caller (event-pipeline or pipeline-run) */
65
+ dispatchOutputNodes?: (outputs: Array<{
66
+ nodeType: string;
67
+ nodeId: Types.ObjectId;
68
+ }>, payload: Record<string, unknown>, event: any, webhook: any, ctx: any, depth: number) => Promise<void>;
69
+ /** Raw event/webhook documents for downstream dispatch */
70
+ rawEvent?: any;
71
+ rawWebhook?: any;
72
+ rawCtx?: any;
73
+ /** Event model for creating child events (webhook outputs) */
74
+ eventModel?: any;
75
+ /** Callback for child events created for webhook outputs */
76
+ onEventCreated?: (childEvent: any, outEp: any, ctx: any) => Promise<void>;
77
+ /** Webhook model for looking up webhook outputs */
78
+ webhookModel?: any;
79
+ /** Handle loop iteration (loop-back signal) — provided by event-pipeline */
80
+ handleLoopIteration?: (event: any, webhook: any, loopNode: any, payload: any, ctx: any, depth: number) => Promise<void>;
81
+ /** Loop state ID — when set, nodes write checkpoints for crash recovery */
82
+ loopStateId?: string;
83
+ /** Called when a node fails inside a loop — triggers skip/retry/stop policy */
84
+ onLoopIterationError?: (loopStateId: string, error: string, retriedTransient: boolean) => Promise<void>;
85
+ /** Loop checkpoint writer — saves lastCompletedNode for crash recovery */
86
+ updateLoopCheckpoint?: (stateId: string, node: {
87
+ nodeType: string;
88
+ nodeId: string;
89
+ outputPayload: Record<string, unknown>;
90
+ }) => Promise<void>;
91
+ /** Raw MongoDB connection for direct queries */
92
+ connection?: any;
93
+ /** In-memory workspace payload overrides — used by loops to inject current iteration payload */
94
+ wsPayloadOverrides?: Record<string, Record<string, unknown>>;
95
+ /**
96
+ * Cross-workspace dispatch hook — called after a node's local downstream
97
+ * dispatch completes. The implementation queries FlowLinks where source
98
+ * matches and invokes each target trigger in another workspace. Optional;
99
+ * paths that don't wire it (test mode, replay) silently skip flow links.
100
+ */
101
+ dispatchFlowLinksFor?: (sourceNodeType: string, sourceNodeId: string, payload: Record<string, unknown>, callStack?: string[]) => Promise<void>;
102
+ }
103
+ export interface DeliveryData {
104
+ eventId: string;
105
+ webhookId: string;
106
+ statusCode: number;
107
+ success: boolean;
108
+ error?: string;
109
+ targetUrl: string;
110
+ /** Dynamic action ID field (e.g. httpActionId, emailActionId) */
111
+ [key: string]: unknown;
112
+ }
113
+ export interface NodeHandler {
114
+ /** Node type key */
115
+ nodeType: string;
116
+ /**
117
+ * Qué versión del tipo atiende este handler.
118
+ *
119
+ * Sin declarar —el caso de los 43 tipos hoy— significa "la única que
120
+ * hay". Se declara el día que un proveedor deprecia sus endpoints y hay
121
+ * que servir dos versiones a la vez; entonces cada una registra el suyo
122
+ * y el despacho las separa por la clave. Ver `docs/ADR-0002`.
123
+ */
124
+ version?: number;
125
+ /** Telemetry source label */
126
+ telemetrySource: LogSource;
127
+ /**
128
+ * Fetch the entity from DB via the node's service.
129
+ */
130
+ fetchEntity(id: string, orgId: string): Promise<any>;
131
+ /**
132
+ * Save lastPayload via the node's service.
133
+ */
134
+ /** El resultado se ignora aquí. Se tipa `unknown` y no `void` porque
135
+ * `BaseNodeService.saveLastPayload` devuelve el `organizationId` para
136
+ * quien quiera avisar por socket, y `Promise<X>` no es asignable a
137
+ * `Promise<void>` — cada servicio que lo pasa como callback fallaría. */
138
+ saveLastPayload(id: string, payload: Record<string, unknown>): Promise<unknown>;
139
+ /**
140
+ * Execute the node. Returns NodeExecutionResult.
141
+ */
142
+ execute(entity: any, payload: Record<string, unknown>, ctx: NodeLifecycleContext): Promise<NodeExecutionResult>;
143
+ /**
144
+ * Pre-execution filter check.
145
+ * Return a reason string to block, or null to proceed.
146
+ * Default: check entity.filters via evaluateFilters (if the node has filters).
147
+ */
148
+ preFilter?(entity: any, payload: Record<string, unknown>): string | null;
149
+ /**
150
+ * Extract the output payload from the execution result.
151
+ * Return null to block downstream dispatch (e.g. code node returns null).
152
+ * Default: result.outputPayload ?? inputPayload
153
+ */
154
+ getOutputPayload?(entity: any, result: NodeExecutionResult, inputPayload: Record<string, unknown>): Record<string, unknown> | null;
155
+ /**
156
+ * Build the lastPayload to save (with _meta diagnostics).
157
+ * Default: wrap in { _meta: { iterable: false, count: 1 }, ...outputPayload }
158
+ */
159
+ buildLastPayload?(entity: any, result: NodeExecutionResult, outputPayload: Record<string, unknown>): Record<string, unknown>;
160
+ /**
161
+ * Build delivery record data (action nodes only).
162
+ * Return null to skip delivery creation.
163
+ */
164
+ buildDeliveryRecord?(entity: any, result: NodeExecutionResult, success: boolean, ctx: NodeLifecycleContext): DeliveryData | null;
165
+ /**
166
+ * Get node-specific telemetry metadata.
167
+ */
168
+ getTelemetryMetadata?(entity: any, result: NodeExecutionResult): Record<string, unknown>;
169
+ /**
170
+ * Override telemetry emission entirely. If provided, the lifecycle skips its generic emit.
171
+ * Use this for nodes with custom telemetry (e.g. filter emits 'warn' when blocked, not 'error').
172
+ * May return a Promise — the lifecycle awaits it. Async variants matter for handlers that
173
+ * call `telemetry.emitAndWait` themselves for SIGTERM-safe recovery.
174
+ */
175
+ emitTelemetry?(entity: any, result: NodeExecutionResult, success: boolean, outputPayload: Record<string, unknown> | null, ctx: NodeLifecycleContext,
176
+ /** Lo que ENTRÓ al nodo. Va también aquí para que un emisor propio pueda
177
+ * guardar los mismos dos campos que el unificado: sin esto, el único
178
+ * handler que se emite aparte se quedaba sin la entrada. */
179
+ inputPayload?: Record<string, unknown>): void | Promise<void>;
180
+ /**
181
+ * When true, the lifecycle awaits the success telemetry write before
182
+ * returning from `dispatchSingleNode`. Use for nodes whose re-execution
183
+ * is costly or non-idempotent — primarily LLM-calling nodes (AI Node)
184
+ * where a SIGTERM between handler completion and a fire-and-forget
185
+ * telemetry write would make `hasRecentSuccess` return false on
186
+ * recovery, triggering a re-run and double-charging the provider.
187
+ * Default false (fire-and-forget — the right choice for cheap idempotent ops).
188
+ */
189
+ awaitTelemetry?: boolean;
190
+ /**
191
+ * Return a sync result to resolve the ingress sync waiter.
192
+ * Called after execution — return non-null to resolve immediately (e.g. schema validator invalid).
193
+ * Return null to let delivery resolve the sync waiter later.
194
+ */
195
+ getSyncResult?(entity: any, result: NodeExecutionResult, outputPayload: Record<string, unknown> | null, ctx: NodeLifecycleContext): {
196
+ status: number;
197
+ body: Record<string, unknown>;
198
+ } | null;
199
+ /**
200
+ * Whether to propagate to downstream on success.
201
+ * Default: true
202
+ */
203
+ propagateDownstream?: boolean;
204
+ /**
205
+ * Which payload to propagate downstream: the execution result or the original input.
206
+ * Default: 'result' (use output payload)
207
+ */
208
+ downstreamPayload?: 'result' | 'original';
209
+ /**
210
+ * Override which nodes to dispatch downstream.
211
+ * If not defined, uses getAllOutputs(entity) which reads outputNodes + elseOutputNodes + branches etc.
212
+ * Use this for nodes with conditional routing (e.g. conditional dispatches only the matched branch).
213
+ */
214
+ getOutputNodes?(entity: any, result: NodeExecutionResult): Array<{
215
+ nodeType: string;
216
+ nodeId: string;
217
+ }>;
218
+ }
219
+ export declare function registerNodeHandler(handler: NodeHandler): void;
220
+ /**
221
+ * El handler de un tipo, opcionalmente el de una versión concreta.
222
+ *
223
+ * Sin `version` devuelve el de la versión vigente, que es exactamente lo
224
+ * que hacía antes de que existieran las versiones. Con una versión que
225
+ * nadie registró cae al vigente en vez de devolver nada: un nodo apuntando
226
+ * a una versión que ya se retiró debe seguir corriendo, no dejar de
227
+ * dispararse en silencio.
228
+ */
229
+ export declare function getNodeHandler(nodeType: string, version?: number): NodeHandler | undefined;
230
+ /**
231
+ * Telemetry log source for a node type.
232
+ *
233
+ * This used to be a 33-entry `NODE_TYPE_TO_SOURCE` map maintained by hand in
234
+ * pipeline-run.service.ts — a fourth place to remember when adding a node,
235
+ * and one that had already grown duplicate aliases (`approval` /
236
+ * `approvalNode`, `delay` / `delayNode`, `merge` / `mergeNode`,
237
+ * `conditional` / `conditionalNode`) because nobody could tell which key the
238
+ * callers passed. Every handler already declares `telemetrySource`, so the
239
+ * map was a copy of information the registry owned.
240
+ *
241
+ * Types with no handler declare their source next to the reason they have no
242
+ * handler, in HANDLERLESS_NODE_TYPES. Anything else — the non-node sources
243
+ * the pipeline logs under, like 'delivery', 'replay' and 'chain' — passes
244
+ * through as-is, which is what the old map's `?? nodeType` fallback did.
245
+ */
246
+ export declare function getTelemetrySource(nodeType: string): LogSource;
247
+ export interface DispatchResult {
248
+ executed: boolean;
249
+ result?: NodeExecutionResult;
250
+ /**
251
+ * El mensaje del fallo cuando el nodo REVENTÓ.
252
+ *
253
+ * ⚠️ `executed: false` no quiere decir «no llegó a correr». `ejecutarNodo`
254
+ * lo devuelve por seis caminos y tres de ellos son fallos: no se pudo traer
255
+ * la entidad, el handler lanzó (o se le acabó el tiempo), o falló dentro de
256
+ * un loop. Los otros tres sí son «no corrió»: no hay handler, el nodo está
257
+ * inactivo, lo descartó el pre-filtro.
258
+ *
259
+ * Sin este campo los seis se leen igual desde fuera, y el historial no
260
+ * puede distinguir un nodo que explotó de uno que nadie llamó — que era
261
+ * exactamente el bug: un nodo caído se guardaba como `skipped`.
262
+ *
263
+ * Vacío = no hubo fallo. Nadie más que el historial lo mira, así que
264
+ * añadirlo no cambia a ningún llamador.
265
+ */
266
+ error?: string;
267
+ }
268
+ /**
269
+ * Lo poco del contexto que hace falta para anotar un paso.
270
+ *
271
+ * Es un subconjunto de `NodeLifecycleContext` a propósito. Quien ejecuta un
272
+ * nodo fuera del pipeline —el Chat Trigger, un tool del nodo AI, uno de MCP—
273
+ * no tiene un contexto de ciclo de vida, y obligarle a fabricar uno a base de
274
+ * `{} as never` para poder anotar es cómo se acaba con `services` vacíos
275
+ * paseándose por sitios donde alguien va a leerlos.
276
+ *
277
+ * `NodeLifecycleContext` lo satisface tal cual, así que el pipeline no cambia.
278
+ */
279
+ export interface ContextoDelHistorial {
280
+ orgId: string;
281
+ event: {
282
+ id: string;
283
+ correlationId?: string;
284
+ };
285
+ /** El ORIGEN de la corrida: el trigger, el chat, el servidor MCP. */
286
+ webhook: {
287
+ id: string;
288
+ name: string;
289
+ };
290
+ historial?: {
291
+ registrarPaso(paso: PasoEjecutado): void;
292
+ };
293
+ /**
294
+ * Cómo se disparó la corrida. Ausente = producción. Ver `Run.modo`.
295
+ *
296
+ * No sale de `NodeLifecycleContext.mode`, que también vale
297
+ * `'pipeline-run'`, porque son dos cosas distintas: aquél dice cómo se
298
+ * ejecuta un nodo —y los tools del agente y los de MCP lo ponen en
299
+ * `'pipeline-run'` estando en producción—, éste dice de dónde salió la
300
+ * corrida. Confundirlos marcaría como prueba todo lo que hace un agente.
301
+ */
302
+ modoDeCorrida?: 'pipeline';
303
+ }
304
+ /**
305
+ * Lo que hay que saber de un paso para poder anotarlo.
306
+ *
307
+ * `nodeName` y `workspaceId` van sueltos y se rellenan DURANTE la ejecución,
308
+ * no antes: viven en la entidad, y la entidad la carga quien corre el paso.
309
+ * Ver `FichaDelNodo`, que es la mitad que `ejecutarNodo` rellena.
310
+ */
311
+ export interface FichaDelPaso {
312
+ nodeType: string;
313
+ nodeId: string;
314
+ nodeName?: string;
315
+ workspaceId?: string;
316
+ entrada: unknown;
317
+ }
318
+ /** Cómo acabó un paso, visto desde fuera de quien lo ejecutó. */
319
+ export interface VeredictoDelPaso {
320
+ status: RunStepStatus;
321
+ salida?: unknown;
322
+ error?: string;
323
+ }
324
+ /**
325
+ * Saca del resultado la frase que explica el fallo.
326
+ *
327
+ * Los handlers devuelven el cuerpo como texto, y casi siempre es un JSON con
328
+ * `error` dentro — una frase ya escrita para leerse. Enseñar el JSON crudo en
329
+ * la línea de tiempo es enseñar llaves y comillas donde cabía la explicación.
330
+ * Si no es JSON, o no trae `error`, se enseña el cuerpo recortado; y si no hay
331
+ * cuerpo, el código HTTP, que al menos dice algo.
332
+ */
333
+ export declare function mensajeDeFallo(result?: NodeExecutionResult): string;
334
+ /**
335
+ * Cómo le fue al paso, a partir de lo que devolvió el despacho.
336
+ *
337
+ * ⚠️ El veredicto sale del `statusCode`, NO de si el nodo llegó a correr. Eso
338
+ * era el bug: `anotar(r.executed ? 'success' : 'skipped')` daba `success` a
339
+ * todo nodo que corriera, devolviese lo que devolviese. Un Email Action que
340
+ * lleva cinco días contestando 500 tenía cinco corridas en verde, con el
341
+ * `{"statusCode":500}` guardado dentro de su propio payload. La telemetría de
342
+ * este mismo fichero ya lo miraba bien (`result.statusCode < 400`): eran dos
343
+ * criterios distintos sobre el mismo resultado.
344
+ *
345
+ * Los tres estados, y por qué son tres y no dos:
346
+ *
347
+ * - `failed` — corrió y salió mal, o reventó. Es lo que cuenta `failures` y
348
+ * lo que hace que la corrida entera sea `failed` o `partial`.
349
+ * - `skipped` — no llegó a correr: inactivo, filtrado, sin handler. Un paso
350
+ * que no existe y uno que se saltó no se leen igual.
351
+ * - `success` — corrió y salió bien.
352
+ */
353
+ export declare function veredictoDelDespacho(r: DispatchResult): VeredictoDelPaso;
354
+ /**
355
+ * El veredicto de un nodo que SÍ corrió, sacado de lo que devolvió.
356
+ *
357
+ * Aparte de `veredictoDelDespacho` porque las rutas que no pasan por el
358
+ * pipeline —el Chat Trigger, los tools del nodo AI, los de MCP— no tienen un
359
+ * `DispatchResult`: tienen el `NodeExecutionResult` a secas. El criterio de
360
+ * qué es un fallo tiene que ser UNO, o vuelven a ser dos.
361
+ *
362
+ * Sin `statusCode` numérico se da por bueno a propósito: un handler que no lo
363
+ * declara no está diciendo que falló, y pintar de rojo lo que no se sabe es
364
+ * peor que dejarlo verde — el rojo se mira.
365
+ */
366
+ export declare function veredictoDeResultado(result?: NodeExecutionResult): VeredictoDelPaso;
367
+ /**
368
+ * Corre algo y lo deja escrito en el historial como un paso.
369
+ *
370
+ * Es una envoltura, y no un puñado de llamadas repartidas por dentro, a
371
+ * propósito: `ejecutarNodo` tiene seis salidas —no hay handler, no se pudo
372
+ * traer la entidad, está inactiva, la filtró el pre-filtro, reventó, salió
373
+ * bien— y anotar el paso en cada una es la clase de lista que se olvida en la
374
+ * séptima. Desde fuera se ven todas a la vez, con su duración de verdad.
375
+ *
376
+ * Vive fuera de `dispatchSingleNode` porque el pipeline de producción NO es la
377
+ * única forma de ejecutar un nodo. El Chat Trigger, los tools del nodo AI, los
378
+ * de MCP, Run Pipeline y Run Test llegan al nodo por su cuenta, y sin una
379
+ * función a la que llamar cada uno tendría que copiar este bloque — que es
380
+ * como se llega a seis copias que se desincronizan.
381
+ *
382
+ * `ficha` se lee DESPUÉS de correr, no antes: `correr` puede rellenarle el
383
+ * `nodeName` y el `workspaceId` en cuanto cargue la entidad. Son opcionales en
384
+ * `PasoEjecutado`, así que olvidarlos no rompe nada y sólo se nota en pantalla
385
+ * —sin `nodeName` la línea de tiempo enseña el tipo dos veces; sin
386
+ * `workspaceId` la corrida sale sin foto y diciendo que es anterior al sellado
387
+ * de versiones—.
388
+ *
389
+ * Nunca estorba: si no hay `historial` en el contexto —tests, modos que no lo
390
+ * montan— esto es una llamada directa y ya está.
391
+ */
392
+ export declare function conPasoRegistrado<T>(ctx: ContextoDelHistorial, ficha: FichaDelPaso, correr: () => Promise<T>, veredicto: (r: T) => VeredictoDelPaso): Promise<T>;
393
+ /**
394
+ * Ejecuta un nodo y, de paso, lo deja escrito en el historial.
395
+ *
396
+ * El payload de entrada es un argumento, así que entra gratis. El de salida y
397
+ * el veredicto salen del resultado, en `veredictoDelDespacho`.
398
+ */
399
+ export declare function dispatchSingleNode(nodeType: string, id: string, payload: Record<string, unknown>, ctx: NodeLifecycleContext): Promise<DispatchResult>;