@synergenius/flow-weaver 0.22.4 → 0.22.6

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.
@@ -9886,7 +9886,7 @@ var VERSION;
9886
9886
  var init_generated_version = __esm({
9887
9887
  "src/generated-version.ts"() {
9888
9888
  "use strict";
9889
- VERSION = "0.22.4";
9889
+ VERSION = "0.22.6";
9890
9890
  }
9891
9891
  });
9892
9892
 
@@ -10791,16 +10791,35 @@ function buildNodeArgumentsWithContext(opts) {
10791
10791
  } else if (skipPorts?.has("execute")) {
10792
10792
  args.push(`${safeId}_execute`);
10793
10793
  } else if (executeConnections.length > 0) {
10794
- const conn = executeConnections[0];
10795
- const sourceNode = conn.from.node;
10796
- const sourcePort = conn.from.port;
10797
10794
  const varName = `${safeId}_execute`;
10798
- const sourceIdx = isStartNode(sourceNode) ? "startIdx" : `${toValidIdentifier(sourceNode)}Idx`;
10799
- const isConstSource = isStartNode(sourceNode) || sourceNode === instanceParent;
10800
- const nonNullAssert = isConstSource ? "" : "!";
10801
- lines.push(
10802
- `${indent}const ${varName} = ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx}${nonNullAssert} }) as boolean;`
10803
- );
10795
+ if (executeConnections.length === 1) {
10796
+ const conn = executeConnections[0];
10797
+ const sourceNode = conn.from.node;
10798
+ const sourcePort = conn.from.port;
10799
+ const sourceIdx = isStartNode(sourceNode) ? "startIdx" : `${toValidIdentifier(sourceNode)}Idx`;
10800
+ const isConstSource = isStartNode(sourceNode) || sourceNode === instanceParent;
10801
+ if (isConstSource) {
10802
+ lines.push(
10803
+ `${indent}const ${varName} = ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) as boolean;`
10804
+ );
10805
+ } else {
10806
+ lines.push(
10807
+ `${indent}const ${varName} = ${sourceIdx} !== undefined ? ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) as boolean : false;`
10808
+ );
10809
+ }
10810
+ } else {
10811
+ const parts = executeConnections.map((conn) => {
10812
+ const sourceNode = conn.from.node;
10813
+ const sourcePort = conn.from.port;
10814
+ const sourceIdx = isStartNode(sourceNode) ? "startIdx" : `${toValidIdentifier(sourceNode)}Idx`;
10815
+ const isConstSource = isStartNode(sourceNode) || sourceNode === instanceParent;
10816
+ if (isConstSource) {
10817
+ return `(${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) as boolean)`;
10818
+ }
10819
+ return `(${sourceIdx} !== undefined ? ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) as boolean : false)`;
10820
+ });
10821
+ lines.push(`${indent}const ${varName} = ${parts.join(" || ")};`);
10822
+ }
10804
10823
  if (emitInputEvents) {
10805
10824
  lines.push(
10806
10825
  `${indent}${setCall}({ id: '${id}', portName: 'execute', executionIndex: ${safeId}Idx, nodeTypeName: '${effectiveNodeTypeName}' }, ${varName});`
@@ -10866,7 +10885,10 @@ function buildNodeArgumentsWithContext(opts) {
10866
10885
  const sourceIdx = isStartNode(sourceNode) ? "startIdx" : `${toValidIdentifier(sourceNode)}Idx`;
10867
10886
  const isConstSource = isStartNode(sourceNode) || sourceNode === instanceParent;
10868
10887
  const nonNullAssert = isConstSource ? "" : "!";
10869
- const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
10888
+ const rawPortType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
10889
+ const isPrimitive = /^(string|number|boolean|void|unknown|any|never|null|undefined)(\[\])?$/.test(rawPortType);
10890
+ const paramIndex = args.length;
10891
+ const portType = isPrimitive ? rawPortType : `Parameters<typeof ${node.functionName}>[${paramIndex}]`;
10870
10892
  const needsGuard = portConfig.optional && !isConstSource;
10871
10893
  if (portConfig.dataType === "FUNCTION") {
10872
10894
  lines.push(`${indent}const __resolveFunction = typeof resolveFunction === 'function' ? resolveFunction : (p: unknown) => ({ fn: typeof p === 'function' ? p : () => { throw new Error('Cannot resolve function reference'); }, source: 'direct' as const });`);
@@ -10941,7 +10963,10 @@ function buildNodeArgumentsWithContext(opts) {
10941
10963
  }
10942
10964
  });
10943
10965
  const ternary = attempts.join(" ?? ");
10944
- const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
10966
+ const rawPortType2 = mapToTypeScript(portConfig.dataType, portConfig.tsType);
10967
+ const isPrimitive2 = /^(string|number|boolean|void|unknown|any|never|null|undefined)(\[\])?$/.test(rawPortType2);
10968
+ const paramIndex2 = args.length;
10969
+ const portType = isPrimitive2 ? rawPortType2 : `Parameters<typeof ${node.functionName}>[${paramIndex2}]`;
10945
10970
  if (portConfig.dataType === "FUNCTION") {
10946
10971
  lines.push(`${indent}const __resolveFunction = typeof resolveFunction === 'function' ? resolveFunction : (p: unknown) => ({ fn: typeof p === 'function' ? p : () => { throw new Error('Cannot resolve function reference'); }, source: 'direct' as const });`);
10947
10972
  const rawVarName = `${varName}_raw`;
@@ -10961,7 +10986,10 @@ function buildNodeArgumentsWithContext(opts) {
10961
10986
  } else if (portConfig.expression) {
10962
10987
  const expression = portConfig.expression;
10963
10988
  const isFunction2 = expression.includes("=>") || expression.trim().startsWith("function");
10964
- const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
10989
+ const rawPortType3 = mapToTypeScript(portConfig.dataType, portConfig.tsType);
10990
+ const isPrimitive3 = /^(string|number|boolean|void|unknown|any|never|null|undefined)(\[\])?$/.test(rawPortType3);
10991
+ const paramIndex3 = args.length;
10992
+ const portType = isPrimitive3 ? rawPortType3 : `Parameters<typeof ${node.functionName}>[${paramIndex3}]`;
10965
10993
  if (isFunction2) {
10966
10994
  lines.push(`${indent}const ${varName} = ${isAsync2 ? "await " : ""}(${expression})(ctx) as ${portType};`);
10967
10995
  } else {
@@ -10979,7 +11007,10 @@ function buildNodeArgumentsWithContext(opts) {
10979
11007
  args.push(varName);
10980
11008
  emitSetEvent();
10981
11009
  } else {
10982
- const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
11010
+ const rawPortType4 = mapToTypeScript(portConfig.dataType, portConfig.tsType);
11011
+ const isPrimitive4 = /^(string|number|boolean|void|unknown|any|never|null|undefined)(\[\])?$/.test(rawPortType4);
11012
+ const paramIndex4 = args.length;
11013
+ const portType = isPrimitive4 ? rawPortType4 : `Parameters<typeof ${node.functionName}>[${paramIndex4}]`;
10983
11014
  lines.push(
10984
11015
  `${indent}let ${varName}: ${portType} = undefined as unknown as ${portType}; // Required port '${portName}' has no connection`
10985
11016
  );
@@ -11094,7 +11125,7 @@ function generateControlFlowWithExecutionContext(workflow, nodeTypes, isAsync2,
11094
11125
  lines.push(` typeof globalThis !== 'undefined' && (globalThis as unknown as { __fw_debug_controller__?: TDebugController }).__fw_debug_controller__`);
11095
11126
  lines.push(` ? (globalThis as unknown as { __fw_debug_controller__?: TDebugController }).__fw_debug_controller__`);
11096
11127
  lines.push(` : { beforeNode: () => true, afterNode: () => {} }`);
11097
- lines.push(` );`);
11128
+ lines.push(` )!;`);
11098
11129
  lines.push("");
11099
11130
  }
11100
11131
  lines.push(` const startIdx = ctx.addExecution('${RESERVED_NODE_NAMES.START}');`);
@@ -94908,7 +94939,7 @@ var {
94908
94939
  // src/cli/index.ts
94909
94940
  init_logger();
94910
94941
  init_error_utils();
94911
- var version2 = true ? "0.22.4" : "0.0.0-dev";
94942
+ var version2 = true ? "0.22.6" : "0.0.0-dev";
94912
94943
  var program2 = new Command();
94913
94944
  program2.name("fw").description("Flow Weaver Annotations - Compile and validate workflow files").option("-v, --version", "Output the current version").option("--no-color", "Disable colors").option("--color", "Force colors").on("option:version", () => {
94914
94945
  logger.banner(version2);
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.22.4";
1
+ export declare const VERSION = "0.22.6";
2
2
  //# sourceMappingURL=generated-version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by scripts/generate-version.ts — do not edit manually
2
- export const VERSION = '0.22.4';
2
+ export const VERSION = '0.22.6';
3
3
  //# sourceMappingURL=generated-version.js.map
@@ -172,16 +172,36 @@ export function buildNodeArgumentsWithContext(opts) {
172
172
  args.push(`${safeId}_execute`);
173
173
  }
174
174
  else if (executeConnections.length > 0) {
175
- // Execute port has a connection - use it
176
- const conn = executeConnections[0];
177
- const sourceNode = conn.from.node;
178
- const sourcePort = conn.from.port;
175
+ // Execute port has connections - use them
179
176
  const varName = `${safeId}_execute`;
180
- // startIdx is const so no ! needed; parent scope node is also const; other node indices are let so need !
181
- const sourceIdx = isStartNode(sourceNode) ? 'startIdx' : `${toValidIdentifier(sourceNode)}Idx`;
182
- const isConstSource = isStartNode(sourceNode) || sourceNode === instanceParent;
183
- const nonNullAssert = isConstSource ? '' : '!';
184
- lines.push(`${indent}const ${varName} = ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx}${nonNullAssert} }) as boolean;`);
177
+ if (executeConnections.length === 1) {
178
+ const conn = executeConnections[0];
179
+ const sourceNode = conn.from.node;
180
+ const sourcePort = conn.from.port;
181
+ const sourceIdx = isStartNode(sourceNode) ? 'startIdx' : `${toValidIdentifier(sourceNode)}Idx`;
182
+ const isConstSource = isStartNode(sourceNode) || sourceNode === instanceParent;
183
+ if (isConstSource) {
184
+ lines.push(`${indent}const ${varName} = ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) as boolean;`);
185
+ }
186
+ else {
187
+ // Non-const source may be undefined (CANCELLED branch) — guard with false default
188
+ lines.push(`${indent}const ${varName} = ${sourceIdx} !== undefined ? ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) as boolean : false;`);
189
+ }
190
+ }
191
+ else {
192
+ // Multiple execute connections — coalesce with ||, each guarded
193
+ const parts = executeConnections.map((conn) => {
194
+ const sourceNode = conn.from.node;
195
+ const sourcePort = conn.from.port;
196
+ const sourceIdx = isStartNode(sourceNode) ? 'startIdx' : `${toValidIdentifier(sourceNode)}Idx`;
197
+ const isConstSource = isStartNode(sourceNode) || sourceNode === instanceParent;
198
+ if (isConstSource) {
199
+ return `(${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) as boolean)`;
200
+ }
201
+ return `(${sourceIdx} !== undefined ? ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) as boolean : false)`;
202
+ });
203
+ lines.push(`${indent}const ${varName} = ${parts.join(' || ')};`);
204
+ }
185
205
  // Emit VARIABLE_SET for execute input port
186
206
  if (emitInputEvents) {
187
207
  lines.push(`${indent}${setCall}({ id: '${id}', portName: 'execute', executionIndex: ${safeId}Idx, nodeTypeName: '${effectiveNodeTypeName}' }, ${varName});`);
@@ -254,7 +274,13 @@ export function buildNodeArgumentsWithContext(opts) {
254
274
  const sourceIdx = isStartNode(sourceNode) ? 'startIdx' : `${toValidIdentifier(sourceNode)}Idx`;
255
275
  const isConstSource = isStartNode(sourceNode) || sourceNode === instanceParent;
256
276
  const nonNullAssert = isConstSource ? '' : '!';
257
- const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
277
+ const rawPortType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
278
+ // Use Parameters<typeof fn>[N] for non-primitive types to avoid bare
279
+ // type names from external modules that aren't in scope. The function
280
+ // IS always imported and in scope, so this is always safe.
281
+ const isPrimitive = /^(string|number|boolean|void|unknown|any|never|null|undefined)(\[\])?$/.test(rawPortType);
282
+ const paramIndex = args.length; // Current position in the function's parameter list
283
+ const portType = isPrimitive ? rawPortType : `Parameters<typeof ${node.functionName}>[${paramIndex}]`;
258
284
  // For optional ports on non-const sources, guard against undefined execution index.
259
285
  // This is critical for DISJUNCTION nodes where the source may not have executed.
260
286
  const needsGuard = portConfig.optional && !isConstSource;
@@ -326,7 +352,10 @@ export function buildNodeArgumentsWithContext(opts) {
326
352
  }
327
353
  });
328
354
  const ternary = attempts.join(' ?? ');
329
- const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
355
+ const rawPortType2 = mapToTypeScript(portConfig.dataType, portConfig.tsType);
356
+ const isPrimitive2 = /^(string|number|boolean|void|unknown|any|never|null|undefined)(\[\])?$/.test(rawPortType2);
357
+ const paramIndex2 = args.length;
358
+ const portType = isPrimitive2 ? rawPortType2 : `Parameters<typeof ${node.functionName}>[${paramIndex2}]`;
330
359
  // For FUNCTION type ports, add resolution step to handle registry IDs
331
360
  if (portConfig.dataType === 'FUNCTION') {
332
361
  lines.push(`${indent}const __resolveFunction = typeof resolveFunction === 'function' ? resolveFunction : (p: unknown) => ({ fn: typeof p === 'function' ? p : () => { throw new Error('Cannot resolve function reference'); }, source: 'direct' as const });`);
@@ -345,7 +374,10 @@ export function buildNodeArgumentsWithContext(opts) {
345
374
  else if (portConfig.expression) {
346
375
  const expression = portConfig.expression;
347
376
  const isFunction = expression.includes('=>') || expression.trim().startsWith('function');
348
- const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
377
+ const rawPortType3 = mapToTypeScript(portConfig.dataType, portConfig.tsType);
378
+ const isPrimitive3 = /^(string|number|boolean|void|unknown|any|never|null|undefined)(\[\])?$/.test(rawPortType3);
379
+ const paramIndex3 = args.length;
380
+ const portType = isPrimitive3 ? rawPortType3 : `Parameters<typeof ${node.functionName}>[${paramIndex3}]`;
349
381
  if (isFunction) {
350
382
  lines.push(`${indent}const ${varName} = ${isAsync ? 'await ' : ''}(${expression})(ctx) as ${portType};`);
351
383
  }
@@ -368,7 +400,10 @@ export function buildNodeArgumentsWithContext(opts) {
368
400
  }
369
401
  else {
370
402
  // Required port has no connection, expression, or default - use typed undefined fallback
371
- const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
403
+ const rawPortType4 = mapToTypeScript(portConfig.dataType, portConfig.tsType);
404
+ const isPrimitive4 = /^(string|number|boolean|void|unknown|any|never|null|undefined)(\[\])?$/.test(rawPortType4);
405
+ const paramIndex4 = args.length;
406
+ const portType = isPrimitive4 ? rawPortType4 : `Parameters<typeof ${node.functionName}>[${paramIndex4}]`;
372
407
  lines.push(`${indent}let ${varName}: ${portType} = undefined as unknown as ${portType}; // Required port '${portName}' has no connection`);
373
408
  args.push(varName);
374
409
  emitSetEvent();
@@ -118,7 +118,7 @@ export function generateControlFlowWithExecutionContext(workflow, nodeTypes, isA
118
118
  lines.push(` typeof globalThis !== 'undefined' && (globalThis as unknown as { __fw_debug_controller__?: TDebugController }).__fw_debug_controller__`);
119
119
  lines.push(` ? (globalThis as unknown as { __fw_debug_controller__?: TDebugController }).__fw_debug_controller__`);
120
120
  lines.push(` : { beforeNode: () => true, afterNode: () => {} }`);
121
- lines.push(` );`);
121
+ lines.push(` )!;`);
122
122
  lines.push('');
123
123
  }
124
124
  lines.push(` const startIdx = ctx.addExecution('${RESERVED_NODE_NAMES.START}');`);
@@ -814,7 +814,9 @@ isAsync = false) {
814
814
  if (!instance)
815
815
  return;
816
816
  const safeId = toValidIdentifier(instanceId);
817
- // Add execution index for this skipped node so the event has a valid reference
817
+ // Use const (block-scoped) intentionally the outer `let ${safeId}Idx`
818
+ // stays undefined, which signals to downstream guards that this node was
819
+ // CANCELLED and its data ports should not be read.
818
820
  lines.push(`${indent}const ${safeId}Idx = ${ctxVar}.addExecution('${instanceId}');`);
819
821
  // Set STEP port variables so downstream nodes reading onSuccess/onFailure
820
822
  // from this cancelled node don't crash with "Variable not found".
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synergenius/flow-weaver",
3
- "version": "0.22.4",
3
+ "version": "0.22.6",
4
4
  "description": "Deterministic workflow compiler for AI agents. Compiles to standalone TypeScript, no runtime dependencies.",
5
5
  "private": false,
6
6
  "type": "module",