@synergenius/flow-weaver 0.21.21 → 0.21.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/generate-in-place.js +4 -10
- package/dist/api/generate.js +5 -20
- package/dist/api/inline-runtime.d.ts +0 -8
- package/dist/api/inline-runtime.js +13 -109
- package/dist/cli/flow-weaver.mjs +55 -161
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/dist/generator/code-utils.d.ts +1 -0
- package/dist/generator/code-utils.js +17 -14
- package/dist/generator/scope-function-generator.js +15 -5
- package/dist/generator/unified.js +18 -15
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Function body (between markers)
|
|
9
9
|
*/
|
|
10
10
|
import { bodyGenerator } from '../body-generator.js';
|
|
11
|
-
import { generateInlineRuntime
|
|
11
|
+
import { generateInlineRuntime } from './inline-runtime.js';
|
|
12
12
|
import { isExecutePort, isSuccessPort, isFailurePort, isControlFlowPort } from '../constants.js';
|
|
13
13
|
import { generateJSDocPortTag, assignPortOrders, generateNodeInstanceTag, } from '../annotation-generator.js';
|
|
14
14
|
import { shouldWorkflowBeAsync } from '../generator/async-detection.js';
|
|
@@ -112,9 +112,11 @@ export function generateInPlace(sourceCode, ast, options = {}) {
|
|
|
112
112
|
}
|
|
113
113
|
// Step 5: Detect async from node composition + source signature
|
|
114
114
|
// If any node is async, force async (even if source isn't marked async)
|
|
115
|
+
// In dev mode (!production), always force async so the debugger can pause execution
|
|
116
|
+
// at breakpoints (sendStatusChangedEvent must be awaited).
|
|
115
117
|
const nodesRequireAsync = shouldWorkflowBeAsync(ast, ast.nodeTypes);
|
|
116
118
|
const sourceIsAsync = detectFunctionIsAsync(result, ast.functionName);
|
|
117
|
-
const forceAsync = nodesRequireAsync;
|
|
119
|
+
const forceAsync = nodesRequireAsync || !production;
|
|
118
120
|
const isAsync = forceAsync || sourceIsAsync;
|
|
119
121
|
// Add async keyword to source if nodes or debug hooks require it
|
|
120
122
|
const asyncSigResult = ensureAsyncKeyword(result, ast.functionName, forceAsync);
|
|
@@ -158,19 +160,11 @@ function generateRuntimeSection(functionName, production, moduleFormat = 'esm',
|
|
|
158
160
|
lines.push(`import type { TDebugger } from '${externalRuntimePath}';`);
|
|
159
161
|
// Declare __flowWeaverDebugger__ so body code can reference it
|
|
160
162
|
lines.push('declare const __flowWeaverDebugger__: TDebugger | undefined;');
|
|
161
|
-
// Include inline debug client (createFlowWeaverDebugClient is not exported from runtime)
|
|
162
|
-
lines.push('');
|
|
163
|
-
lines.push(generateInlineDebugClient(moduleFormat));
|
|
164
163
|
}
|
|
165
164
|
}
|
|
166
165
|
else {
|
|
167
166
|
// Inline runtime: embed all types and classes directly
|
|
168
167
|
lines.push(generateInlineRuntime(production));
|
|
169
|
-
// Add debug client (dev mode only)
|
|
170
|
-
if (!production) {
|
|
171
|
-
lines.push('');
|
|
172
|
-
lines.push(generateInlineDebugClient(moduleFormat));
|
|
173
|
-
}
|
|
174
168
|
}
|
|
175
169
|
return lines.join('\n');
|
|
176
170
|
}
|
package/dist/api/generate.js
CHANGED
|
@@ -3,7 +3,7 @@ import { extractExitPorts, extractStartPorts, hasBranching } from '../ast/workfl
|
|
|
3
3
|
import { isExecutePort } from '../constants.js';
|
|
4
4
|
import { mapToTypeScript } from '../type-mappings.js';
|
|
5
5
|
import { SourceMapGenerator } from 'source-map';
|
|
6
|
-
import { generateInlineRuntime,
|
|
6
|
+
import { generateInlineRuntime, stripTypeScript } from './inline-runtime.js';
|
|
7
7
|
import { validateWorkflowAsync } from '../generator/async-detection.js';
|
|
8
8
|
import { extractTypeDeclarationsFromFile } from './extract-types.js';
|
|
9
9
|
import * as path from 'node:path';
|
|
@@ -100,13 +100,6 @@ export function generateCode(ast, options) {
|
|
|
100
100
|
? `const { TDebugger } = require('${externalRuntimePath}');`
|
|
101
101
|
: `import type { TDebugger } from '${externalRuntimePath}';`);
|
|
102
102
|
addLine();
|
|
103
|
-
// Include inline debug client (createFlowWeaverDebugClient is not exported from runtime)
|
|
104
|
-
const inlineDebugClient = generateInlineDebugClient(moduleFormat);
|
|
105
|
-
const debugClientLines = inlineDebugClient.split('\n');
|
|
106
|
-
debugClientLines.forEach((line) => {
|
|
107
|
-
lines.push(line);
|
|
108
|
-
addLine();
|
|
109
|
-
});
|
|
110
103
|
}
|
|
111
104
|
lines.push('');
|
|
112
105
|
addLine();
|
|
@@ -121,15 +114,6 @@ export function generateCode(ast, options) {
|
|
|
121
114
|
});
|
|
122
115
|
lines.push('');
|
|
123
116
|
addLine();
|
|
124
|
-
// Include inline debug client (dev mode only)
|
|
125
|
-
if (!production) {
|
|
126
|
-
const inlineDebugClient = generateInlineDebugClient(moduleFormat);
|
|
127
|
-
const debugClientLines = inlineDebugClient.split('\n');
|
|
128
|
-
debugClientLines.forEach((line) => {
|
|
129
|
-
lines.push(line);
|
|
130
|
-
addLine();
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
117
|
}
|
|
134
118
|
// Extract and include type declarations from source file (interfaces, type aliases)
|
|
135
119
|
if (ast.sourceFile) {
|
|
@@ -374,7 +358,8 @@ export function generateCode(ast, options) {
|
|
|
374
358
|
}
|
|
375
359
|
}
|
|
376
360
|
// Generate conditional async keyword and export keyword based on module format
|
|
377
|
-
|
|
361
|
+
// In dev mode, always async so the debugger can pause at breakpoints
|
|
362
|
+
const asyncKeyword = (shouldBeAsync || !production) ? 'async ' : '';
|
|
378
363
|
const exportKeyword = generateFunctionExportKeyword(moduleFormat);
|
|
379
364
|
lines.push(`${exportKeyword}${asyncKeyword}function ${ast.functionName}(`);
|
|
380
365
|
addLine();
|
|
@@ -488,8 +473,8 @@ function generateWorkflowFunction(workflow, production, allWorkflows, generatedW
|
|
|
488
473
|
// Generate function signature
|
|
489
474
|
const startPorts = extractStartPorts(workflow);
|
|
490
475
|
const exitPorts = extractExitPorts(workflow);
|
|
491
|
-
const
|
|
492
|
-
lines.push(`${
|
|
476
|
+
const asyncKeyword2 = (shouldBeAsync || !production) ? 'async ' : '';
|
|
477
|
+
lines.push(`${asyncKeyword2}function ${workflow.functionName}(`);
|
|
493
478
|
// STEP Port Architecture: execute is first parameter
|
|
494
479
|
lines.push(` execute: boolean = true,`);
|
|
495
480
|
// Collect param names and types for destructuring
|
|
@@ -18,14 +18,6 @@ export declare function stripTypeScript(code: string): string;
|
|
|
18
18
|
*/
|
|
19
19
|
export declare function generateInlineRuntime(production: boolean, exportClasses?: boolean, outputFormat?: TOutputFormat): string;
|
|
20
20
|
import type { TModuleFormat } from '../ast/types.js';
|
|
21
|
-
/**
|
|
22
|
-
* Generates inline WebSocket debug client for auto-detection from env var
|
|
23
|
-
* Only included in development mode builds
|
|
24
|
-
*
|
|
25
|
-
* @param moduleFormat - The module format to use for imports ('esm' or 'cjs')
|
|
26
|
-
* @param outputFormat - Output format: 'typescript' (default) or 'javascript' (strips types)
|
|
27
|
-
*/
|
|
28
|
-
export declare function generateInlineDebugClient(moduleFormat?: TModuleFormat, outputFormat?: TOutputFormat): string;
|
|
29
21
|
/**
|
|
30
22
|
* Generates a standalone runtime module file for multi-workflow bundles.
|
|
31
23
|
* This exports all runtime types and classes so individual workflow files can import them.
|
|
@@ -303,12 +303,13 @@ export function generateInlineRuntime(production, exportClasses = false, outputF
|
|
|
303
303
|
lines.push(' }');
|
|
304
304
|
lines.push('');
|
|
305
305
|
// createScope
|
|
306
|
-
lines.push(' createScope(_parentNodeName: string, _parentIndex: number, _scopeName: string, cleanScope: boolean = false): GeneratedExecutionContext {');
|
|
306
|
+
lines.push(' createScope(_parentNodeName: string, _parentIndex: number, _scopeName: string, cleanScope: boolean = false, isAsyncOverride?: boolean): GeneratedExecutionContext {');
|
|
307
|
+
lines.push(' const effectiveIsAsync = isAsyncOverride !== undefined ? isAsyncOverride : this.isAsync;');
|
|
307
308
|
if (production) {
|
|
308
|
-
lines.push(' const scopedContext = new GeneratedExecutionContext(
|
|
309
|
+
lines.push(' const scopedContext = new GeneratedExecutionContext(effectiveIsAsync, this.abortSignal);');
|
|
309
310
|
}
|
|
310
311
|
else {
|
|
311
|
-
lines.push(' const scopedContext = new GeneratedExecutionContext(
|
|
312
|
+
lines.push(' const scopedContext = new GeneratedExecutionContext(effectiveIsAsync, this.flowWeaverDebugger, this.abortSignal);');
|
|
312
313
|
}
|
|
313
314
|
lines.push(' // For per-port function scopes (cleanScope=true), start with empty variables');
|
|
314
315
|
lines.push(' // For node-level scopes (cleanScope=false), inherit parent variables');
|
|
@@ -388,12 +389,12 @@ export function generateInlineRuntime(production, exportClasses = false, outputF
|
|
|
388
389
|
lines.push(' }');
|
|
389
390
|
lines.push(' }');
|
|
390
391
|
lines.push('');
|
|
391
|
-
lines.push(' private sendVariableSetEvent(args: {');
|
|
392
|
+
lines.push(' private async sendVariableSetEvent(args: {');
|
|
392
393
|
lines.push(' identifier: TVariableIdentification;');
|
|
393
394
|
lines.push(' value: unknown;');
|
|
394
|
-
lines.push(' }): void {');
|
|
395
|
+
lines.push(' }): Promise<void> {');
|
|
395
396
|
lines.push(' if (this.flowWeaverDebugger) {');
|
|
396
|
-
lines.push(' this.flowWeaverDebugger.sendEvent({');
|
|
397
|
+
lines.push(' await this.flowWeaverDebugger.sendEvent({');
|
|
397
398
|
lines.push(' type: "VARIABLE_SET",');
|
|
398
399
|
lines.push(' ...args,');
|
|
399
400
|
lines.push(' innerFlowInvocation: this.flowWeaverDebugger.innerFlowInvocation,');
|
|
@@ -401,16 +402,16 @@ export function generateInlineRuntime(production, exportClasses = false, outputF
|
|
|
401
402
|
lines.push(' }');
|
|
402
403
|
lines.push(' }');
|
|
403
404
|
lines.push('');
|
|
404
|
-
lines.push(' sendLogErrorEvent(args: {');
|
|
405
|
+
lines.push(' async sendLogErrorEvent(args: {');
|
|
405
406
|
lines.push(' nodeTypeName: string;');
|
|
406
407
|
lines.push(' id: string;');
|
|
407
408
|
lines.push(' scope?: string;');
|
|
408
409
|
lines.push(' side?: "start" | "exit";');
|
|
409
410
|
lines.push(' executionIndex: number;');
|
|
410
411
|
lines.push(' error: string;');
|
|
411
|
-
lines.push(' }): void {');
|
|
412
|
+
lines.push(' }): Promise<void> {');
|
|
412
413
|
lines.push(' if (this.flowWeaverDebugger) {');
|
|
413
|
-
lines.push(' this.flowWeaverDebugger.sendEvent({');
|
|
414
|
+
lines.push(' await this.flowWeaverDebugger.sendEvent({');
|
|
414
415
|
lines.push(' type: "LOG_ERROR",');
|
|
415
416
|
lines.push(' ...args,');
|
|
416
417
|
lines.push(' innerFlowInvocation: this.flowWeaverDebugger.innerFlowInvocation,');
|
|
@@ -418,13 +419,13 @@ export function generateInlineRuntime(production, exportClasses = false, outputF
|
|
|
418
419
|
lines.push(' }');
|
|
419
420
|
lines.push(' }');
|
|
420
421
|
lines.push('');
|
|
421
|
-
lines.push(' sendWorkflowCompletedEvent(args: {');
|
|
422
|
+
lines.push(' async sendWorkflowCompletedEvent(args: {');
|
|
422
423
|
lines.push(' executionIndex: number;');
|
|
423
424
|
lines.push(' status: "SUCCEEDED" | "FAILED" | "CANCELLED";');
|
|
424
425
|
lines.push(' result?: unknown;');
|
|
425
|
-
lines.push(' }): void {');
|
|
426
|
+
lines.push(' }): Promise<void> {');
|
|
426
427
|
lines.push(' if (this.flowWeaverDebugger) {');
|
|
427
|
-
lines.push(' this.flowWeaverDebugger.sendEvent({');
|
|
428
|
+
lines.push(' await this.flowWeaverDebugger.sendEvent({');
|
|
428
429
|
lines.push(' type: "WORKFLOW_COMPLETED",');
|
|
429
430
|
lines.push(' ...args,');
|
|
430
431
|
lines.push(' innerFlowInvocation: this.flowWeaverDebugger.innerFlowInvocation,');
|
|
@@ -490,92 +491,6 @@ export function generateInlineRuntime(production, exportClasses = false, outputF
|
|
|
490
491
|
}
|
|
491
492
|
return output;
|
|
492
493
|
}
|
|
493
|
-
/**
|
|
494
|
-
* Generates inline WebSocket debug client for auto-detection from env var
|
|
495
|
-
* Only included in development mode builds
|
|
496
|
-
*
|
|
497
|
-
* @param moduleFormat - The module format to use for imports ('esm' or 'cjs')
|
|
498
|
-
* @param outputFormat - Output format: 'typescript' (default) or 'javascript' (strips types)
|
|
499
|
-
*/
|
|
500
|
-
export function generateInlineDebugClient(moduleFormat = 'esm', outputFormat = 'typescript') {
|
|
501
|
-
const lines = [];
|
|
502
|
-
lines.push('// ============================================================================');
|
|
503
|
-
lines.push('// Inline Debug Client (auto-created from FLOW_WEAVER_DEBUG env var)');
|
|
504
|
-
lines.push('// ============================================================================');
|
|
505
|
-
lines.push('');
|
|
506
|
-
lines.push('/* eslint-disable @typescript-eslint/no-explicit-any, no-console */');
|
|
507
|
-
lines.push('function createFlowWeaverDebugClient(url: string, workflowExportName: string): any {');
|
|
508
|
-
lines.push(' let ws: any = null;');
|
|
509
|
-
lines.push(' let connected = false;');
|
|
510
|
-
lines.push(' let queue: string[] = [];');
|
|
511
|
-
lines.push(' const sessionId = Math.random().toString(36).substring(2, 15);');
|
|
512
|
-
lines.push('');
|
|
513
|
-
lines.push(' const connect = async () => {');
|
|
514
|
-
lines.push(' try {');
|
|
515
|
-
lines.push(" // Node.js environment - dynamically load 'ws' package");
|
|
516
|
-
// Generate format-appropriate import for 'ws' package
|
|
517
|
-
if (moduleFormat === 'cjs') {
|
|
518
|
-
// CommonJS: use require() directly
|
|
519
|
-
lines.push(" const wsModule = require('ws');");
|
|
520
|
-
}
|
|
521
|
-
else {
|
|
522
|
-
// ESM: use dynamic import
|
|
523
|
-
lines.push(" const wsModule = await import('ws');");
|
|
524
|
-
}
|
|
525
|
-
lines.push(' const WS: any = wsModule.default || wsModule;');
|
|
526
|
-
lines.push(' ws = new WS(url);');
|
|
527
|
-
lines.push('');
|
|
528
|
-
lines.push(" ws.on('open', () => {");
|
|
529
|
-
lines.push(' connected = true;');
|
|
530
|
-
lines.push(' // Send connect message');
|
|
531
|
-
lines.push(' ws.send(JSON.stringify({');
|
|
532
|
-
lines.push(" type: 'connect',");
|
|
533
|
-
lines.push(' sessionId,');
|
|
534
|
-
lines.push(' workflowExportName,');
|
|
535
|
-
lines.push(' clientInfo: {');
|
|
536
|
-
lines.push(' platform: process.platform,');
|
|
537
|
-
lines.push(' nodeVersion: process.version,');
|
|
538
|
-
lines.push(' pid: process.pid');
|
|
539
|
-
lines.push(' }');
|
|
540
|
-
lines.push(' }));');
|
|
541
|
-
lines.push('');
|
|
542
|
-
lines.push(' // Flush queued events');
|
|
543
|
-
lines.push(' while (queue.length > 0) {');
|
|
544
|
-
lines.push(' const msg = queue.shift();');
|
|
545
|
-
lines.push(' if (ws.readyState === 1) ws.send(msg);');
|
|
546
|
-
lines.push(' }');
|
|
547
|
-
lines.push(' });');
|
|
548
|
-
lines.push('');
|
|
549
|
-
lines.push(" ws.on('error', () => { connected = false; });");
|
|
550
|
-
lines.push(" ws.on('close', () => { connected = false; });");
|
|
551
|
-
lines.push(' } catch (err: unknown) {');
|
|
552
|
-
lines.push(" // Silently fail if 'ws' package not available");
|
|
553
|
-
lines.push(" console.warn('[Flow Weaver] Debug client failed to connect:', err instanceof Error ? err.message : String(err));");
|
|
554
|
-
lines.push(' }');
|
|
555
|
-
lines.push(' };');
|
|
556
|
-
lines.push('');
|
|
557
|
-
lines.push(' return {');
|
|
558
|
-
lines.push(' sendEvent: (event: unknown) => {');
|
|
559
|
-
lines.push(" const message = JSON.stringify({ type: 'event', sessionId, event });");
|
|
560
|
-
lines.push(' if (!ws) connect().catch(() => {});');
|
|
561
|
-
lines.push(' if (connected && ws.readyState === 1) {');
|
|
562
|
-
lines.push(' ws.send(message);');
|
|
563
|
-
lines.push(' } else {');
|
|
564
|
-
lines.push(' queue.push(message);');
|
|
565
|
-
lines.push(' }');
|
|
566
|
-
lines.push(' },');
|
|
567
|
-
lines.push(' innerFlowInvocation: false,');
|
|
568
|
-
lines.push(' sessionId');
|
|
569
|
-
lines.push(' };');
|
|
570
|
-
lines.push('}');
|
|
571
|
-
lines.push('/* eslint-enable @typescript-eslint/no-explicit-any, no-console */');
|
|
572
|
-
lines.push('');
|
|
573
|
-
const output = lines.join('\n');
|
|
574
|
-
if (outputFormat === 'javascript') {
|
|
575
|
-
return stripTypeScript(output);
|
|
576
|
-
}
|
|
577
|
-
return output;
|
|
578
|
-
}
|
|
579
494
|
/**
|
|
580
495
|
* Generates a standalone runtime module file for multi-workflow bundles.
|
|
581
496
|
* This exports all runtime types and classes so individual workflow files can import them.
|
|
@@ -595,14 +510,6 @@ export function generateStandaloneRuntimeModule(production, moduleFormat = 'esm'
|
|
|
595
510
|
const inlineRuntime = generateInlineRuntime(production, true);
|
|
596
511
|
lines.push(inlineRuntime);
|
|
597
512
|
lines.push('');
|
|
598
|
-
// Include debug client in development mode
|
|
599
|
-
if (!production) {
|
|
600
|
-
const debugClient = generateInlineDebugClient(moduleFormat);
|
|
601
|
-
// Add export to the createFlowWeaverDebugClient function
|
|
602
|
-
const exportedDebugClient = debugClient.replace('function createFlowWeaverDebugClient', 'export function createFlowWeaverDebugClient');
|
|
603
|
-
lines.push(exportedDebugClient);
|
|
604
|
-
lines.push('');
|
|
605
|
-
}
|
|
606
513
|
if (moduleFormat === 'cjs') {
|
|
607
514
|
// CommonJS exports
|
|
608
515
|
lines.push('// ============================================================================');
|
|
@@ -610,9 +517,6 @@ export function generateStandaloneRuntimeModule(production, moduleFormat = 'esm'
|
|
|
610
517
|
lines.push('// ============================================================================');
|
|
611
518
|
lines.push('');
|
|
612
519
|
const exports = ['GeneratedExecutionContext', 'CancellationError'];
|
|
613
|
-
if (!production) {
|
|
614
|
-
exports.push('createFlowWeaverDebugClient', 'TDebugger');
|
|
615
|
-
}
|
|
616
520
|
lines.push(`module.exports = { ${exports.join(', ')} };`);
|
|
617
521
|
}
|
|
618
522
|
// For ESM, exports are added via 'export' keyword in the generated code
|
package/dist/cli/flow-weaver.mjs
CHANGED
|
@@ -9671,7 +9671,7 @@ var VERSION;
|
|
|
9671
9671
|
var init_generated_version = __esm({
|
|
9672
9672
|
"src/generated-version.ts"() {
|
|
9673
9673
|
"use strict";
|
|
9674
|
-
VERSION = "0.21.
|
|
9674
|
+
VERSION = "0.21.22";
|
|
9675
9675
|
}
|
|
9676
9676
|
});
|
|
9677
9677
|
|
|
@@ -10261,8 +10261,9 @@ function generateScopeFunctionClosure(scopeName, parentNodeId, parentNodeType, w
|
|
|
10261
10261
|
lines.push(``);
|
|
10262
10262
|
const safeParentId = toValidIdentifier(parentNodeId);
|
|
10263
10263
|
lines.push(` // Create scoped context for child nodes`);
|
|
10264
|
+
const isAsyncOverrideArg = isAsync2 ? "" : ", false";
|
|
10264
10265
|
lines.push(
|
|
10265
|
-
` const scopedCtx = ctx.createScope('${parentNodeId}', ${safeParentId}Idx!, '${scopeName}', true);`
|
|
10266
|
+
` const scopedCtx = ctx.createScope('${parentNodeId}', ${safeParentId}Idx!, '${scopeName}', true${isAsyncOverrideArg});`
|
|
10266
10267
|
);
|
|
10267
10268
|
lines.push(``);
|
|
10268
10269
|
if (scopedOutputPorts.length > 0) {
|
|
@@ -10329,7 +10330,7 @@ function generateScopeFunctionClosure(scopeName, parentNodeId, parentNodeType, w
|
|
|
10329
10330
|
lines.push(` // Execute: ${child.id} (${child.nodeType})`);
|
|
10330
10331
|
lines.push(` scopedCtx.checkAborted('${child.id}');`);
|
|
10331
10332
|
lines.push(` const ${safeChildId}Idx = scopedCtx.addExecution('${child.id}');`);
|
|
10332
|
-
lines.push(` if (typeof globalThis !== 'undefined') (globalThis as
|
|
10333
|
+
lines.push(` if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${child.id}';`);
|
|
10333
10334
|
lines.push(` ${awaitPrefix}scopedCtx.sendStatusChangedEvent({`);
|
|
10334
10335
|
lines.push(` nodeTypeName: '${child.nodeType}',`);
|
|
10335
10336
|
lines.push(` id: '${child.id}',`);
|
|
@@ -10373,7 +10374,8 @@ function generateScopeFunctionClosure(scopeName, parentNodeId, parentNodeType, w
|
|
|
10373
10374
|
skipPorts: preHandledPorts,
|
|
10374
10375
|
emitInputEvents: true,
|
|
10375
10376
|
setCall: childSetCall,
|
|
10376
|
-
nodeTypeName: child.nodeType
|
|
10377
|
+
nodeTypeName: child.nodeType,
|
|
10378
|
+
production
|
|
10377
10379
|
});
|
|
10378
10380
|
argLines.forEach((line) => lines.push(line));
|
|
10379
10381
|
if (childNodeType.expression) {
|
|
@@ -10441,7 +10443,7 @@ function generateScopeFunctionClosure(scopeName, parentNodeId, parentNodeType, w
|
|
|
10441
10443
|
lines.push(``);
|
|
10442
10444
|
lines.push(` // Extract return values from child outputs`);
|
|
10443
10445
|
const returnObj = [];
|
|
10444
|
-
const getCallAfterMerge = isAsync2 ? "await
|
|
10446
|
+
const getCallAfterMerge = isAsync2 ? "await scopedCtx.getVariable" : "scopedCtx.getVariable";
|
|
10445
10447
|
lines.push(` const scopeExitIdx = ctx.addExecution('${parentNodeId}_scope_exit');`);
|
|
10446
10448
|
scopedInputPorts.forEach((portName) => {
|
|
10447
10449
|
const connection = workflow.connections.find((conn) => {
|
|
@@ -10460,7 +10462,7 @@ function generateScopeFunctionClosure(scopeName, parentNodeId, parentNodeType, w
|
|
|
10460
10462
|
const defaultValue = portName === "success" ? "true" : portName === "failure" ? "false" : "undefined";
|
|
10461
10463
|
if (isStepPort2) {
|
|
10462
10464
|
lines.push(
|
|
10463
|
-
` const ${varName} =
|
|
10465
|
+
` const ${varName} = scopedCtx.hasVariable(${varAddr}) ? ${getCallAfterMerge}(${varAddr}) as ${portType} : ${defaultValue};`
|
|
10464
10466
|
);
|
|
10465
10467
|
} else {
|
|
10466
10468
|
lines.push(` const ${varName} = ${getCallAfterMerge}(${varAddr}) as ${portType};`);
|
|
@@ -10550,7 +10552,8 @@ function buildNodeArgumentsWithContext(opts) {
|
|
|
10550
10552
|
emitInputEvents = false,
|
|
10551
10553
|
setCall = "await ctx.setVariable",
|
|
10552
10554
|
nodeTypeName,
|
|
10553
|
-
bundleMode = false
|
|
10555
|
+
bundleMode = false,
|
|
10556
|
+
production = false
|
|
10554
10557
|
} = opts;
|
|
10555
10558
|
const safeId = toValidIdentifier(id);
|
|
10556
10559
|
const inputConnections = workflow.connections.filter((conn) => conn.to.node === id);
|
|
@@ -10648,13 +10651,14 @@ function buildNodeArgumentsWithContext(opts) {
|
|
|
10648
10651
|
const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
|
|
10649
10652
|
const needsGuard = portConfig.optional && !isConstSource;
|
|
10650
10653
|
if (portConfig.dataType === "FUNCTION") {
|
|
10654
|
+
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 });`);
|
|
10651
10655
|
const rawVarName = `${varName}_raw`;
|
|
10652
10656
|
if (needsGuard) {
|
|
10653
10657
|
lines.push(
|
|
10654
10658
|
`${indent}const ${rawVarName} = ${sourceIdx} !== undefined ? ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) : undefined;`
|
|
10655
10659
|
);
|
|
10656
10660
|
lines.push(
|
|
10657
|
-
`${indent}const ${varName}_resolved = ${rawVarName} !== undefined ?
|
|
10661
|
+
`${indent}const ${varName}_resolved = ${rawVarName} !== undefined ? __resolveFunction(${rawVarName}) : undefined;`
|
|
10658
10662
|
);
|
|
10659
10663
|
lines.push(
|
|
10660
10664
|
`${indent}const ${varName} = ${varName}_resolved?.fn as ${portType};`
|
|
@@ -10664,7 +10668,7 @@ function buildNodeArgumentsWithContext(opts) {
|
|
|
10664
10668
|
`${indent}const ${rawVarName} = ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx}${nonNullAssert} });`
|
|
10665
10669
|
);
|
|
10666
10670
|
lines.push(
|
|
10667
|
-
`${indent}const ${varName}_resolved =
|
|
10671
|
+
`${indent}const ${varName}_resolved = __resolveFunction(${rawVarName});`
|
|
10668
10672
|
);
|
|
10669
10673
|
lines.push(
|
|
10670
10674
|
`${indent}const ${varName} = ${varName}_resolved.fn as ${portType};`
|
|
@@ -10721,10 +10725,11 @@ function buildNodeArgumentsWithContext(opts) {
|
|
|
10721
10725
|
const ternary = attempts.join(" ?? ");
|
|
10722
10726
|
const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
|
|
10723
10727
|
if (portConfig.dataType === "FUNCTION") {
|
|
10728
|
+
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 });`);
|
|
10724
10729
|
const rawVarName = `${varName}_raw`;
|
|
10725
10730
|
lines.push(`${indent}const ${rawVarName} = ${ternary};`);
|
|
10726
10731
|
lines.push(
|
|
10727
|
-
`${indent}const ${varName}_resolved = ${rawVarName} !== undefined ?
|
|
10732
|
+
`${indent}const ${varName}_resolved = ${rawVarName} !== undefined ? __resolveFunction(${rawVarName}) : undefined;`
|
|
10728
10733
|
);
|
|
10729
10734
|
lines.push(
|
|
10730
10735
|
`${indent}const ${varName} = ${varName}_resolved?.fn as ${portType};`
|
|
@@ -10758,7 +10763,7 @@ function buildNodeArgumentsWithContext(opts) {
|
|
|
10758
10763
|
} else {
|
|
10759
10764
|
const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
|
|
10760
10765
|
lines.push(
|
|
10761
|
-
`${indent}let ${varName}
|
|
10766
|
+
`${indent}let ${varName}: ${portType} = undefined as unknown as ${portType}; // Required port '${portName}' has no connection`
|
|
10762
10767
|
);
|
|
10763
10768
|
args.push(varName);
|
|
10764
10769
|
emitSetEvent();
|
|
@@ -10783,7 +10788,7 @@ function buildNodeArgumentsWithContext(opts) {
|
|
|
10783
10788
|
);
|
|
10784
10789
|
return childNodeType?.isAsync === true;
|
|
10785
10790
|
});
|
|
10786
|
-
const scopeIsAsync =
|
|
10791
|
+
const scopeIsAsync = node.isAsync || hasAsyncChild;
|
|
10787
10792
|
const scopeFunctionCode = generateScopeFunctionClosure(
|
|
10788
10793
|
scopeName,
|
|
10789
10794
|
id,
|
|
@@ -10791,8 +10796,7 @@ function buildNodeArgumentsWithContext(opts) {
|
|
|
10791
10796
|
workflow,
|
|
10792
10797
|
childInstances,
|
|
10793
10798
|
scopeIsAsync,
|
|
10794
|
-
|
|
10795
|
-
// production mode
|
|
10799
|
+
production
|
|
10796
10800
|
);
|
|
10797
10801
|
lines.push(`${indent}const ${scopeFunctionVar} = ${scopeFunctionCode};`);
|
|
10798
10802
|
args.push(scopeFunctionVar);
|
|
@@ -10843,15 +10847,7 @@ function getPullExecutionConfig(instance, nodeType) {
|
|
|
10843
10847
|
function generateControlFlowWithExecutionContext(workflow, nodeTypes, isAsync2, production = false, bundleMode = false) {
|
|
10844
10848
|
const lines = [];
|
|
10845
10849
|
if (!production) {
|
|
10846
|
-
lines.push(`
|
|
10847
|
-
lines.push(` const __effectiveDebugger__ = (`);
|
|
10848
|
-
lines.push(` typeof __flowWeaverDebugger__ !== 'undefined' ? __flowWeaverDebugger__ :`);
|
|
10849
|
-
lines.push(` typeof process !== 'undefined' && process.env.FLOW_WEAVER_DEBUG`);
|
|
10850
|
-
lines.push(
|
|
10851
|
-
` ? createFlowWeaverDebugClient(process.env.FLOW_WEAVER_DEBUG, '${workflow.functionName}')`
|
|
10852
|
-
);
|
|
10853
|
-
lines.push(` : undefined`);
|
|
10854
|
-
lines.push(` );`);
|
|
10850
|
+
lines.push(` const __effectiveDebugger__ = typeof __flowWeaverDebugger__ !== 'undefined' ? __flowWeaverDebugger__ : undefined;`);
|
|
10855
10851
|
lines.push("");
|
|
10856
10852
|
}
|
|
10857
10853
|
lines.push(` // Recursion depth protection`);
|
|
@@ -10862,6 +10858,9 @@ function generateControlFlowWithExecutionContext(workflow, nodeTypes, isAsync2,
|
|
|
10862
10858
|
);
|
|
10863
10859
|
lines.push(` }`);
|
|
10864
10860
|
lines.push("");
|
|
10861
|
+
if (!production) {
|
|
10862
|
+
isAsync2 = true;
|
|
10863
|
+
}
|
|
10865
10864
|
const asyncArg = isAsync2 ? "true" : "false";
|
|
10866
10865
|
if (production) {
|
|
10867
10866
|
lines.push(` const ctx = new GeneratedExecutionContext(${asyncArg}, __abortSignal__);`);
|
|
@@ -10874,8 +10873,8 @@ function generateControlFlowWithExecutionContext(workflow, nodeTypes, isAsync2,
|
|
|
10874
10873
|
if (!production) {
|
|
10875
10874
|
lines.push(` // Debug controller for step-through debugging and checkpoint/resume`);
|
|
10876
10875
|
lines.push(` const __ctrl__: TDebugController = (`);
|
|
10877
|
-
lines.push(` typeof globalThis !== 'undefined' && (globalThis as
|
|
10878
|
-
lines.push(` ? (globalThis as
|
|
10876
|
+
lines.push(` typeof globalThis !== 'undefined' && (globalThis as unknown as { __fw_debug_controller__?: TDebugController }).__fw_debug_controller__`);
|
|
10877
|
+
lines.push(` ? (globalThis as unknown as { __fw_debug_controller__?: TDebugController }).__fw_debug_controller__`);
|
|
10879
10878
|
lines.push(` : { beforeNode: () => true, afterNode: () => {} }`);
|
|
10880
10879
|
lines.push(` );`);
|
|
10881
10880
|
lines.push("");
|
|
@@ -11751,7 +11750,7 @@ function generateBranchingNodeCode(instance, branchNode, workflow, allNodeTypes,
|
|
|
11751
11750
|
}
|
|
11752
11751
|
lines.push(`${indent}${ctxVar}.checkAborted('${instanceId}');`);
|
|
11753
11752
|
lines.push(`${indent}${safeId}Idx = ${ctxVar}.addExecution('${instanceId}');`);
|
|
11754
|
-
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as
|
|
11753
|
+
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${instanceId}';`);
|
|
11755
11754
|
lines.push(`${indent}${awaitPrefix}${ctxVar}.sendStatusChangedEvent({`);
|
|
11756
11755
|
lines.push(`${indent} nodeTypeName: '${functionName}',`);
|
|
11757
11756
|
lines.push(`${indent} id: '${instanceId}',`);
|
|
@@ -11781,7 +11780,8 @@ function generateBranchingNodeCode(instance, branchNode, workflow, allNodeTypes,
|
|
|
11781
11780
|
emitInputEvents: true,
|
|
11782
11781
|
setCall,
|
|
11783
11782
|
nodeTypeName: functionName,
|
|
11784
|
-
bundleMode
|
|
11783
|
+
bundleMode,
|
|
11784
|
+
production
|
|
11785
11785
|
});
|
|
11786
11786
|
const awaitKeyword = branchNode.isAsync ? "await " : "";
|
|
11787
11787
|
if (branchNode.expression) {
|
|
@@ -12129,7 +12129,7 @@ function generateBranchingNodeCode(instance, branchNode, workflow, allNodeTypes,
|
|
|
12129
12129
|
}
|
|
12130
12130
|
generatedNodes.add(instanceId);
|
|
12131
12131
|
}
|
|
12132
|
-
function generatePullNodeWithContext(instance, nodeType, workflow, lines, indent, isAsync2, ctxVar = "ctx", bundleMode = false) {
|
|
12132
|
+
function generatePullNodeWithContext(instance, nodeType, workflow, lines, indent, isAsync2, ctxVar = "ctx", bundleMode = false, production = false) {
|
|
12133
12133
|
const instanceId = instance.id;
|
|
12134
12134
|
const safeId = toValidIdentifier(instanceId);
|
|
12135
12135
|
const functionName = nodeType.functionName;
|
|
@@ -12144,7 +12144,7 @@ function generatePullNodeWithContext(instance, nodeType, workflow, lines, indent
|
|
|
12144
12144
|
lines.push(`${indent} }`);
|
|
12145
12145
|
lines.push(`${indent} ${ctxVar}.checkAborted('${instanceId}');`);
|
|
12146
12146
|
lines.push(`${indent} ${safeId}Idx = ${ctxVar}.addExecution('${instanceId}');`);
|
|
12147
|
-
lines.push(`${indent} if (typeof globalThis !== 'undefined') (globalThis as
|
|
12147
|
+
lines.push(`${indent} if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${instanceId}';`);
|
|
12148
12148
|
lines.push(`${indent} ${awaitPrefix}${ctxVar}.sendStatusChangedEvent({`);
|
|
12149
12149
|
lines.push(`${indent} nodeTypeName: '${functionName}',`);
|
|
12150
12150
|
lines.push(`${indent} id: '${instanceId}',`);
|
|
@@ -12165,7 +12165,8 @@ function generatePullNodeWithContext(instance, nodeType, workflow, lines, indent
|
|
|
12165
12165
|
emitInputEvents: true,
|
|
12166
12166
|
setCall,
|
|
12167
12167
|
nodeTypeName: functionName,
|
|
12168
|
-
bundleMode
|
|
12168
|
+
bundleMode,
|
|
12169
|
+
production
|
|
12169
12170
|
});
|
|
12170
12171
|
const resultVar = `${safeId}Result`;
|
|
12171
12172
|
if (nodeType.variant === "MAP_ITERATOR") {
|
|
@@ -12247,7 +12248,7 @@ function generateNodeCallWithContext(instance, nodeType, workflow, _availableVar
|
|
|
12247
12248
|
const fullInstance = workflow.instances.find((i) => i.id === instanceId);
|
|
12248
12249
|
const pullConfig = fullInstance ? getPullExecutionConfig(fullInstance, nodeType) : { enabled: false, triggerPort: "execute" };
|
|
12249
12250
|
if (pullConfig.enabled) {
|
|
12250
|
-
generatePullNodeWithContext(instance, nodeType, workflow, lines, indent, isAsync2, ctxVar, bundleMode);
|
|
12251
|
+
generatePullNodeWithContext(instance, nodeType, workflow, lines, indent, isAsync2, ctxVar, bundleMode, production);
|
|
12251
12252
|
return;
|
|
12252
12253
|
}
|
|
12253
12254
|
const stepInputs = Object.entries(nodeType.inputs).filter(([portName, portConfig]) => {
|
|
@@ -12373,7 +12374,7 @@ function generateNodeCallWithContext(instance, nodeType, workflow, _availableVar
|
|
|
12373
12374
|
const awaitPrefix = isAsync2 ? "await " : "";
|
|
12374
12375
|
lines.push(`${indent}${ctxVar}.checkAborted('${instanceId}');`);
|
|
12375
12376
|
lines.push(`${indent}${varDecl}${safeId}Idx = ${ctxVar}.addExecution('${instanceId}');`);
|
|
12376
|
-
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as
|
|
12377
|
+
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${instanceId}';`);
|
|
12377
12378
|
lines.push(`${indent}${awaitPrefix}${ctxVar}.sendStatusChangedEvent({`);
|
|
12378
12379
|
lines.push(`${indent} nodeTypeName: '${functionName}',`);
|
|
12379
12380
|
lines.push(`${indent} id: '${instanceId}',`);
|
|
@@ -12395,7 +12396,8 @@ function generateNodeCallWithContext(instance, nodeType, workflow, _availableVar
|
|
|
12395
12396
|
emitInputEvents: true,
|
|
12396
12397
|
setCall,
|
|
12397
12398
|
nodeTypeName: functionName,
|
|
12398
|
-
bundleMode
|
|
12399
|
+
bundleMode,
|
|
12400
|
+
production
|
|
12399
12401
|
});
|
|
12400
12402
|
const resultVar = `${safeId}Result`;
|
|
12401
12403
|
const awaitKeyword = nodeType.isAsync ? "await " : "";
|
|
@@ -17227,15 +17229,18 @@ function generateInlineRuntime(production, exportClasses = false, outputFormat =
|
|
|
17227
17229
|
lines.push(" }");
|
|
17228
17230
|
lines.push("");
|
|
17229
17231
|
lines.push(
|
|
17230
|
-
" createScope(_parentNodeName: string, _parentIndex: number, _scopeName: string, cleanScope: boolean = false): GeneratedExecutionContext {"
|
|
17232
|
+
" createScope(_parentNodeName: string, _parentIndex: number, _scopeName: string, cleanScope: boolean = false, isAsyncOverride?: boolean): GeneratedExecutionContext {"
|
|
17233
|
+
);
|
|
17234
|
+
lines.push(
|
|
17235
|
+
" const effectiveIsAsync = isAsyncOverride !== undefined ? isAsyncOverride : this.isAsync;"
|
|
17231
17236
|
);
|
|
17232
17237
|
if (production) {
|
|
17233
17238
|
lines.push(
|
|
17234
|
-
" const scopedContext = new GeneratedExecutionContext(
|
|
17239
|
+
" const scopedContext = new GeneratedExecutionContext(effectiveIsAsync, this.abortSignal);"
|
|
17235
17240
|
);
|
|
17236
17241
|
} else {
|
|
17237
17242
|
lines.push(
|
|
17238
|
-
" const scopedContext = new GeneratedExecutionContext(
|
|
17243
|
+
" const scopedContext = new GeneratedExecutionContext(effectiveIsAsync, this.flowWeaverDebugger, this.abortSignal);"
|
|
17239
17244
|
);
|
|
17240
17245
|
}
|
|
17241
17246
|
lines.push(" // For per-port function scopes (cleanScope=true), start with empty variables");
|
|
@@ -17314,12 +17319,12 @@ function generateInlineRuntime(production, exportClasses = false, outputFormat =
|
|
|
17314
17319
|
lines.push(" }");
|
|
17315
17320
|
lines.push(" }");
|
|
17316
17321
|
lines.push("");
|
|
17317
|
-
lines.push(" private sendVariableSetEvent(args: {");
|
|
17322
|
+
lines.push(" private async sendVariableSetEvent(args: {");
|
|
17318
17323
|
lines.push(" identifier: TVariableIdentification;");
|
|
17319
17324
|
lines.push(" value: unknown;");
|
|
17320
|
-
lines.push(" }): void {");
|
|
17325
|
+
lines.push(" }): Promise<void> {");
|
|
17321
17326
|
lines.push(" if (this.flowWeaverDebugger) {");
|
|
17322
|
-
lines.push(" this.flowWeaverDebugger.sendEvent({");
|
|
17327
|
+
lines.push(" await this.flowWeaverDebugger.sendEvent({");
|
|
17323
17328
|
lines.push(' type: "VARIABLE_SET",');
|
|
17324
17329
|
lines.push(" ...args,");
|
|
17325
17330
|
lines.push(" innerFlowInvocation: this.flowWeaverDebugger.innerFlowInvocation,");
|
|
@@ -17327,16 +17332,16 @@ function generateInlineRuntime(production, exportClasses = false, outputFormat =
|
|
|
17327
17332
|
lines.push(" }");
|
|
17328
17333
|
lines.push(" }");
|
|
17329
17334
|
lines.push("");
|
|
17330
|
-
lines.push(" sendLogErrorEvent(args: {");
|
|
17335
|
+
lines.push(" async sendLogErrorEvent(args: {");
|
|
17331
17336
|
lines.push(" nodeTypeName: string;");
|
|
17332
17337
|
lines.push(" id: string;");
|
|
17333
17338
|
lines.push(" scope?: string;");
|
|
17334
17339
|
lines.push(' side?: "start" | "exit";');
|
|
17335
17340
|
lines.push(" executionIndex: number;");
|
|
17336
17341
|
lines.push(" error: string;");
|
|
17337
|
-
lines.push(" }): void {");
|
|
17342
|
+
lines.push(" }): Promise<void> {");
|
|
17338
17343
|
lines.push(" if (this.flowWeaverDebugger) {");
|
|
17339
|
-
lines.push(" this.flowWeaverDebugger.sendEvent({");
|
|
17344
|
+
lines.push(" await this.flowWeaverDebugger.sendEvent({");
|
|
17340
17345
|
lines.push(' type: "LOG_ERROR",');
|
|
17341
17346
|
lines.push(" ...args,");
|
|
17342
17347
|
lines.push(" innerFlowInvocation: this.flowWeaverDebugger.innerFlowInvocation,");
|
|
@@ -17344,13 +17349,13 @@ function generateInlineRuntime(production, exportClasses = false, outputFormat =
|
|
|
17344
17349
|
lines.push(" }");
|
|
17345
17350
|
lines.push(" }");
|
|
17346
17351
|
lines.push("");
|
|
17347
|
-
lines.push(" sendWorkflowCompletedEvent(args: {");
|
|
17352
|
+
lines.push(" async sendWorkflowCompletedEvent(args: {");
|
|
17348
17353
|
lines.push(" executionIndex: number;");
|
|
17349
17354
|
lines.push(' status: "SUCCEEDED" | "FAILED" | "CANCELLED";');
|
|
17350
17355
|
lines.push(" result?: unknown;");
|
|
17351
|
-
lines.push(" }): void {");
|
|
17356
|
+
lines.push(" }): Promise<void> {");
|
|
17352
17357
|
lines.push(" if (this.flowWeaverDebugger) {");
|
|
17353
|
-
lines.push(" this.flowWeaverDebugger.sendEvent({");
|
|
17358
|
+
lines.push(" await this.flowWeaverDebugger.sendEvent({");
|
|
17354
17359
|
lines.push(' type: "WORKFLOW_COMPLETED",');
|
|
17355
17360
|
lines.push(" ...args,");
|
|
17356
17361
|
lines.push(" innerFlowInvocation: this.flowWeaverDebugger.innerFlowInvocation,");
|
|
@@ -17413,85 +17418,6 @@ function generateInlineRuntime(production, exportClasses = false, outputFormat =
|
|
|
17413
17418
|
}
|
|
17414
17419
|
return output;
|
|
17415
17420
|
}
|
|
17416
|
-
function generateInlineDebugClient(moduleFormat = "esm", outputFormat = "typescript") {
|
|
17417
|
-
const lines = [];
|
|
17418
|
-
lines.push("// ============================================================================");
|
|
17419
|
-
lines.push("// Inline Debug Client (auto-created from FLOW_WEAVER_DEBUG env var)");
|
|
17420
|
-
lines.push("// ============================================================================");
|
|
17421
|
-
lines.push("");
|
|
17422
|
-
lines.push("/* eslint-disable @typescript-eslint/no-explicit-any, no-console */");
|
|
17423
|
-
lines.push(
|
|
17424
|
-
"function createFlowWeaverDebugClient(url: string, workflowExportName: string): any {"
|
|
17425
|
-
);
|
|
17426
|
-
lines.push(" let ws: any = null;");
|
|
17427
|
-
lines.push(" let connected = false;");
|
|
17428
|
-
lines.push(" let queue: string[] = [];");
|
|
17429
|
-
lines.push(" const sessionId = Math.random().toString(36).substring(2, 15);");
|
|
17430
|
-
lines.push("");
|
|
17431
|
-
lines.push(" const connect = async () => {");
|
|
17432
|
-
lines.push(" try {");
|
|
17433
|
-
lines.push(" // Node.js environment - dynamically load 'ws' package");
|
|
17434
|
-
if (moduleFormat === "cjs") {
|
|
17435
|
-
lines.push(" const wsModule = require('ws');");
|
|
17436
|
-
} else {
|
|
17437
|
-
lines.push(" const wsModule = await import('ws');");
|
|
17438
|
-
}
|
|
17439
|
-
lines.push(" const WS: any = wsModule.default || wsModule;");
|
|
17440
|
-
lines.push(" ws = new WS(url);");
|
|
17441
|
-
lines.push("");
|
|
17442
|
-
lines.push(" ws.on('open', () => {");
|
|
17443
|
-
lines.push(" connected = true;");
|
|
17444
|
-
lines.push(" // Send connect message");
|
|
17445
|
-
lines.push(" ws.send(JSON.stringify({");
|
|
17446
|
-
lines.push(" type: 'connect',");
|
|
17447
|
-
lines.push(" sessionId,");
|
|
17448
|
-
lines.push(" workflowExportName,");
|
|
17449
|
-
lines.push(" clientInfo: {");
|
|
17450
|
-
lines.push(" platform: process.platform,");
|
|
17451
|
-
lines.push(" nodeVersion: process.version,");
|
|
17452
|
-
lines.push(" pid: process.pid");
|
|
17453
|
-
lines.push(" }");
|
|
17454
|
-
lines.push(" }));");
|
|
17455
|
-
lines.push("");
|
|
17456
|
-
lines.push(" // Flush queued events");
|
|
17457
|
-
lines.push(" while (queue.length > 0) {");
|
|
17458
|
-
lines.push(" const msg = queue.shift();");
|
|
17459
|
-
lines.push(" if (ws.readyState === 1) ws.send(msg);");
|
|
17460
|
-
lines.push(" }");
|
|
17461
|
-
lines.push(" });");
|
|
17462
|
-
lines.push("");
|
|
17463
|
-
lines.push(" ws.on('error', () => { connected = false; });");
|
|
17464
|
-
lines.push(" ws.on('close', () => { connected = false; });");
|
|
17465
|
-
lines.push(" } catch (err: unknown) {");
|
|
17466
|
-
lines.push(" // Silently fail if 'ws' package not available");
|
|
17467
|
-
lines.push(
|
|
17468
|
-
" console.warn('[Flow Weaver] Debug client failed to connect:', err instanceof Error ? err.message : String(err));"
|
|
17469
|
-
);
|
|
17470
|
-
lines.push(" }");
|
|
17471
|
-
lines.push(" };");
|
|
17472
|
-
lines.push("");
|
|
17473
|
-
lines.push(" return {");
|
|
17474
|
-
lines.push(" sendEvent: (event: unknown) => {");
|
|
17475
|
-
lines.push(" const message = JSON.stringify({ type: 'event', sessionId, event });");
|
|
17476
|
-
lines.push(" if (!ws) connect().catch(() => {});");
|
|
17477
|
-
lines.push(" if (connected && ws.readyState === 1) {");
|
|
17478
|
-
lines.push(" ws.send(message);");
|
|
17479
|
-
lines.push(" } else {");
|
|
17480
|
-
lines.push(" queue.push(message);");
|
|
17481
|
-
lines.push(" }");
|
|
17482
|
-
lines.push(" },");
|
|
17483
|
-
lines.push(" innerFlowInvocation: false,");
|
|
17484
|
-
lines.push(" sessionId");
|
|
17485
|
-
lines.push(" };");
|
|
17486
|
-
lines.push("}");
|
|
17487
|
-
lines.push("/* eslint-enable @typescript-eslint/no-explicit-any, no-console */");
|
|
17488
|
-
lines.push("");
|
|
17489
|
-
const output = lines.join("\n");
|
|
17490
|
-
if (outputFormat === "javascript") {
|
|
17491
|
-
return stripTypeScript(output);
|
|
17492
|
-
}
|
|
17493
|
-
return output;
|
|
17494
|
-
}
|
|
17495
17421
|
function generateStandaloneRuntimeModule(production, moduleFormat = "esm") {
|
|
17496
17422
|
const lines = [];
|
|
17497
17423
|
lines.push("// ============================================================================");
|
|
@@ -17502,24 +17428,12 @@ function generateStandaloneRuntimeModule(production, moduleFormat = "esm") {
|
|
|
17502
17428
|
const inlineRuntime = generateInlineRuntime(production, true);
|
|
17503
17429
|
lines.push(inlineRuntime);
|
|
17504
17430
|
lines.push("");
|
|
17505
|
-
if (!production) {
|
|
17506
|
-
const debugClient = generateInlineDebugClient(moduleFormat);
|
|
17507
|
-
const exportedDebugClient = debugClient.replace(
|
|
17508
|
-
"function createFlowWeaverDebugClient",
|
|
17509
|
-
"export function createFlowWeaverDebugClient"
|
|
17510
|
-
);
|
|
17511
|
-
lines.push(exportedDebugClient);
|
|
17512
|
-
lines.push("");
|
|
17513
|
-
}
|
|
17514
17431
|
if (moduleFormat === "cjs") {
|
|
17515
17432
|
lines.push("// ============================================================================");
|
|
17516
17433
|
lines.push("// Exports");
|
|
17517
17434
|
lines.push("// ============================================================================");
|
|
17518
17435
|
lines.push("");
|
|
17519
17436
|
const exports2 = ["GeneratedExecutionContext", "CancellationError"];
|
|
17520
|
-
if (!production) {
|
|
17521
|
-
exports2.push("createFlowWeaverDebugClient", "TDebugger");
|
|
17522
|
-
}
|
|
17523
17437
|
lines.push(`module.exports = { ${exports2.join(", ")} };`);
|
|
17524
17438
|
}
|
|
17525
17439
|
lines.push("");
|
|
@@ -17708,12 +17622,6 @@ function generateCode(ast, options) {
|
|
|
17708
17622
|
moduleFormat === "cjs" ? `const { TDebugger } = require('${externalRuntimePath}');` : `import type { TDebugger } from '${externalRuntimePath}';`
|
|
17709
17623
|
);
|
|
17710
17624
|
addLine();
|
|
17711
|
-
const inlineDebugClient = generateInlineDebugClient(moduleFormat);
|
|
17712
|
-
const debugClientLines = inlineDebugClient.split("\n");
|
|
17713
|
-
debugClientLines.forEach((line) => {
|
|
17714
|
-
lines.push(line);
|
|
17715
|
-
addLine();
|
|
17716
|
-
});
|
|
17717
17625
|
}
|
|
17718
17626
|
lines.push("");
|
|
17719
17627
|
addLine();
|
|
@@ -17726,14 +17634,6 @@ function generateCode(ast, options) {
|
|
|
17726
17634
|
});
|
|
17727
17635
|
lines.push("");
|
|
17728
17636
|
addLine();
|
|
17729
|
-
if (!production) {
|
|
17730
|
-
const inlineDebugClient = generateInlineDebugClient(moduleFormat);
|
|
17731
|
-
const debugClientLines = inlineDebugClient.split("\n");
|
|
17732
|
-
debugClientLines.forEach((line) => {
|
|
17733
|
-
lines.push(line);
|
|
17734
|
-
addLine();
|
|
17735
|
-
});
|
|
17736
|
-
}
|
|
17737
17637
|
}
|
|
17738
17638
|
if (ast.sourceFile) {
|
|
17739
17639
|
const extractedTypes = extractTypeDeclarationsFromFile(ast.sourceFile);
|
|
@@ -17943,7 +17843,7 @@ function generateCode(ast, options) {
|
|
|
17943
17843
|
} catch {
|
|
17944
17844
|
}
|
|
17945
17845
|
}
|
|
17946
|
-
const asyncKeyword = shouldBeAsync ? "async " : "";
|
|
17846
|
+
const asyncKeyword = shouldBeAsync || !production ? "async " : "";
|
|
17947
17847
|
const exportKeyword = generateFunctionExportKeyword(moduleFormat);
|
|
17948
17848
|
lines.push(`${exportKeyword}${asyncKeyword}function ${ast.functionName}(`);
|
|
17949
17849
|
addLine();
|
|
@@ -18040,8 +17940,8 @@ function generateWorkflowFunction(workflow, production, allWorkflows, generatedW
|
|
|
18040
17940
|
);
|
|
18041
17941
|
const startPorts = extractStartPorts(workflow);
|
|
18042
17942
|
const exitPorts = extractExitPorts(workflow);
|
|
18043
|
-
const
|
|
18044
|
-
lines.push(`${
|
|
17943
|
+
const asyncKeyword2 = shouldBeAsync || !production ? "async " : "";
|
|
17944
|
+
lines.push(`${asyncKeyword2}function ${workflow.functionName}(`);
|
|
18045
17945
|
lines.push(` execute: boolean = true,`);
|
|
18046
17946
|
const paramEntries = [];
|
|
18047
17947
|
Object.entries(startPorts).forEach(([portName, portDef]) => {
|
|
@@ -19055,7 +18955,7 @@ function generateInPlace(sourceCode, ast, options = {}) {
|
|
|
19055
18955
|
}
|
|
19056
18956
|
const nodesRequireAsync = shouldWorkflowBeAsync(ast, ast.nodeTypes);
|
|
19057
18957
|
const sourceIsAsync = detectFunctionIsAsync(result, ast.functionName);
|
|
19058
|
-
const forceAsync = nodesRequireAsync;
|
|
18958
|
+
const forceAsync = nodesRequireAsync || !production;
|
|
19059
18959
|
const isAsync2 = forceAsync || sourceIsAsync;
|
|
19060
18960
|
const asyncSigResult = ensureAsyncKeyword(result, ast.functionName, forceAsync);
|
|
19061
18961
|
if (asyncSigResult.changed) {
|
|
@@ -19089,15 +18989,9 @@ function generateRuntimeSection(functionName, production, moduleFormat = "esm",
|
|
|
19089
18989
|
if (!production) {
|
|
19090
18990
|
lines.push(`import type { TDebugger } from '${externalRuntimePath}';`);
|
|
19091
18991
|
lines.push("declare const __flowWeaverDebugger__: TDebugger | undefined;");
|
|
19092
|
-
lines.push("");
|
|
19093
|
-
lines.push(generateInlineDebugClient(moduleFormat));
|
|
19094
18992
|
}
|
|
19095
18993
|
} else {
|
|
19096
18994
|
lines.push(generateInlineRuntime(production));
|
|
19097
|
-
if (!production) {
|
|
19098
|
-
lines.push("");
|
|
19099
|
-
lines.push(generateInlineDebugClient(moduleFormat));
|
|
19100
|
-
}
|
|
19101
18995
|
}
|
|
19102
18996
|
return lines.join("\n");
|
|
19103
18997
|
}
|
|
@@ -93281,7 +93175,7 @@ function displayInstalledPackage(pkg) {
|
|
|
93281
93175
|
// src/cli/index.ts
|
|
93282
93176
|
init_logger();
|
|
93283
93177
|
init_error_utils();
|
|
93284
|
-
var version2 = true ? "0.21.
|
|
93178
|
+
var version2 = true ? "0.21.22" : "0.0.0-dev";
|
|
93285
93179
|
var program2 = new Command();
|
|
93286
93180
|
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", () => {
|
|
93287
93181
|
logger.banner(version2);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.21.
|
|
1
|
+
export declare const VERSION = "0.21.22";
|
|
2
2
|
//# sourceMappingURL=generated-version.d.ts.map
|
|
@@ -147,7 +147,7 @@ export function buildMergeExpression(sources, strategy) {
|
|
|
147
147
|
* @returns Array of argument expressions to pass to the node function
|
|
148
148
|
*/
|
|
149
149
|
export function buildNodeArgumentsWithContext(opts) {
|
|
150
|
-
const { node, workflow, id, lines, indent = ' ', getCall = 'await ctx.getVariable', isAsync = true, instanceParent, skipPorts, emitInputEvents = false, setCall = 'await ctx.setVariable', nodeTypeName, bundleMode = false, } = opts;
|
|
150
|
+
const { node, workflow, id, lines, indent = ' ', getCall = 'await ctx.getVariable', isAsync = true, instanceParent, skipPorts, emitInputEvents = false, setCall = 'await ctx.setVariable', nodeTypeName, bundleMode = false, production = false, } = opts;
|
|
151
151
|
const safeId = toValidIdentifier(id);
|
|
152
152
|
const inputConnections = workflow.connections.filter((conn) => conn.to.node === id);
|
|
153
153
|
const args = [];
|
|
@@ -260,15 +260,18 @@ export function buildNodeArgumentsWithContext(opts) {
|
|
|
260
260
|
const needsGuard = portConfig.optional && !isConstSource;
|
|
261
261
|
// For FUNCTION type ports, add resolution step to handle registry IDs
|
|
262
262
|
if (portConfig.dataType === 'FUNCTION') {
|
|
263
|
+
// Emit inline resolveFunction stub if not already declared in scope
|
|
264
|
+
// This avoids a ReferenceError in self-contained generated code
|
|
265
|
+
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 });`);
|
|
263
266
|
const rawVarName = `${varName}_raw`;
|
|
264
267
|
if (needsGuard) {
|
|
265
268
|
lines.push(`${indent}const ${rawVarName} = ${sourceIdx} !== undefined ? ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx} }) : undefined;`);
|
|
266
|
-
lines.push(`${indent}const ${varName}_resolved = ${rawVarName} !== undefined ?
|
|
269
|
+
lines.push(`${indent}const ${varName}_resolved = ${rawVarName} !== undefined ? __resolveFunction(${rawVarName}) : undefined;`);
|
|
267
270
|
lines.push(`${indent}const ${varName} = ${varName}_resolved?.fn as ${portType};`);
|
|
268
271
|
}
|
|
269
272
|
else {
|
|
270
273
|
lines.push(`${indent}const ${rawVarName} = ${getCall}({ id: '${sourceNode}', portName: '${sourcePort}', executionIndex: ${sourceIdx}${nonNullAssert} });`);
|
|
271
|
-
lines.push(`${indent}const ${varName}_resolved =
|
|
274
|
+
lines.push(`${indent}const ${varName}_resolved = __resolveFunction(${rawVarName});`);
|
|
272
275
|
lines.push(`${indent}const ${varName} = ${varName}_resolved.fn as ${portType};`);
|
|
273
276
|
}
|
|
274
277
|
}
|
|
@@ -326,9 +329,10 @@ export function buildNodeArgumentsWithContext(opts) {
|
|
|
326
329
|
const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
|
|
327
330
|
// For FUNCTION type ports, add resolution step to handle registry IDs
|
|
328
331
|
if (portConfig.dataType === 'FUNCTION') {
|
|
332
|
+
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 });`);
|
|
329
333
|
const rawVarName = `${varName}_raw`;
|
|
330
334
|
lines.push(`${indent}const ${rawVarName} = ${ternary};`);
|
|
331
|
-
lines.push(`${indent}const ${varName}_resolved = ${rawVarName} !== undefined ?
|
|
335
|
+
lines.push(`${indent}const ${varName}_resolved = ${rawVarName} !== undefined ? __resolveFunction(${rawVarName}) : undefined;`);
|
|
332
336
|
lines.push(`${indent}const ${varName} = ${varName}_resolved?.fn as ${portType};`);
|
|
333
337
|
}
|
|
334
338
|
else {
|
|
@@ -365,7 +369,7 @@ export function buildNodeArgumentsWithContext(opts) {
|
|
|
365
369
|
else {
|
|
366
370
|
// Required port has no connection, expression, or default - use typed undefined fallback
|
|
367
371
|
const portType = mapToTypeScript(portConfig.dataType, portConfig.tsType);
|
|
368
|
-
lines.push(`${indent}let ${varName}
|
|
372
|
+
lines.push(`${indent}let ${varName}: ${portType} = undefined as unknown as ${portType}; // Required port '${portName}' has no connection`);
|
|
369
373
|
args.push(varName);
|
|
370
374
|
emitSetEvent();
|
|
371
375
|
}
|
|
@@ -392,18 +396,17 @@ export function buildNodeArgumentsWithContext(opts) {
|
|
|
392
396
|
return inst.parent.id === id && inst.parent.scope === scopeName;
|
|
393
397
|
});
|
|
394
398
|
// Generate scope function closure
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
//
|
|
398
|
-
//
|
|
399
|
-
//
|
|
399
|
+
// Scope function async/sync must match what the PARENT NODE expects from its callback.
|
|
400
|
+
// A sync parent node (e.g., forEach) calls the callback synchronously — if the scope
|
|
401
|
+
// function is async it returns a Promise, causing `.field` accesses to yield `undefined`.
|
|
402
|
+
// Only make the scope function async if the parent node itself is async or a child is async.
|
|
403
|
+
// Do NOT inherit the workflow-level isAsync flag (which is true in dev mode for debugging).
|
|
400
404
|
const hasAsyncChild = childInstances.some((child) => {
|
|
401
405
|
const childNodeType = workflow.nodeTypes?.find((nt) => nt.name === child.nodeType || nt.functionName === child.nodeType);
|
|
402
406
|
return childNodeType?.isAsync === true;
|
|
403
407
|
});
|
|
404
|
-
const scopeIsAsync =
|
|
405
|
-
const scopeFunctionCode = generateScopeFunctionClosure(scopeName, id, node, workflow, childInstances, scopeIsAsync,
|
|
406
|
-
);
|
|
408
|
+
const scopeIsAsync = node.isAsync || hasAsyncChild;
|
|
409
|
+
const scopeFunctionCode = generateScopeFunctionClosure(scopeName, id, node, workflow, childInstances, scopeIsAsync, production);
|
|
407
410
|
lines.push(`${indent}const ${scopeFunctionVar} = ${scopeFunctionCode};`);
|
|
408
411
|
args.push(scopeFunctionVar);
|
|
409
412
|
});
|
|
@@ -416,7 +419,7 @@ export function generateNodeWithExecutionContext(node, workflow, lines, isAsync,
|
|
|
416
419
|
const getCall = isAsync ? 'await ctx.getVariable' : 'ctx.getVariable';
|
|
417
420
|
const setCall = isAsync ? 'await ctx.setVariable' : 'ctx.setVariable';
|
|
418
421
|
lines.push(`${indent}const ${safeNodeName}Idx = ctx.addExecution('${nodeName}');`);
|
|
419
|
-
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as
|
|
422
|
+
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${nodeName}';`);
|
|
420
423
|
lines.push(`${indent}${awaitPrefix}ctx.sendStatusChangedEvent({`);
|
|
421
424
|
lines.push(`${indent} nodeTypeName: '${nodeName}',`);
|
|
422
425
|
lines.push(`${indent} id: '${nodeName}',`);
|
|
@@ -79,6 +79,10 @@ import { mapToTypeScript } from '../type-mappings.js';
|
|
|
79
79
|
*/
|
|
80
80
|
export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNodeType, workflow, childInstances, isAsync, production) {
|
|
81
81
|
const lines = [];
|
|
82
|
+
// NOTE: Scope function async/sync is determined by the caller (buildNodeArgumentsWithContext)
|
|
83
|
+
// based on whether the parent node or its children are async. We do NOT force async in dev
|
|
84
|
+
// mode here because the parent node function calls this callback synchronously — if we
|
|
85
|
+
// return a Promise from an async closure, the parent gets Promise objects instead of values.
|
|
82
86
|
// Extract scoped ports for this scope
|
|
83
87
|
const scopedOutputPorts = []; // Parameters to the scope function
|
|
84
88
|
const scopedInputPorts = []; // Return values from the scope function
|
|
@@ -112,9 +116,11 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
112
116
|
lines.push(``);
|
|
113
117
|
// Create scoped execution context for isolation
|
|
114
118
|
// Pass cleanScope=true for per-port function scopes (each call gets fresh variables)
|
|
119
|
+
// When the scope function is sync, override isAsync to false so context ops return values directly
|
|
115
120
|
const safeParentId = toValidIdentifier(parentNodeId);
|
|
116
121
|
lines.push(` // Create scoped context for child nodes`);
|
|
117
|
-
|
|
122
|
+
const isAsyncOverrideArg = isAsync ? '' : ', false';
|
|
123
|
+
lines.push(` const scopedCtx = ctx.createScope('${parentNodeId}', ${safeParentId}Idx!, '${scopeName}', true${isAsyncOverrideArg});`);
|
|
118
124
|
lines.push(``);
|
|
119
125
|
// Set scope parameter values in execution context
|
|
120
126
|
// These become available to child nodes as outputs from the parent node
|
|
@@ -185,7 +191,7 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
185
191
|
lines.push(` // Execute: ${child.id} (${child.nodeType})`);
|
|
186
192
|
lines.push(` scopedCtx.checkAborted('${child.id}');`);
|
|
187
193
|
lines.push(` const ${safeChildId}Idx = scopedCtx.addExecution('${child.id}');`);
|
|
188
|
-
lines.push(` if (typeof globalThis !== 'undefined') (globalThis as
|
|
194
|
+
lines.push(` if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${child.id}';`);
|
|
189
195
|
lines.push(` ${awaitPrefix}scopedCtx.sendStatusChangedEvent({`);
|
|
190
196
|
lines.push(` nodeTypeName: '${child.nodeType}',`);
|
|
191
197
|
lines.push(` id: '${child.id}',`);
|
|
@@ -232,6 +238,7 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
232
238
|
emitInputEvents: true,
|
|
233
239
|
setCall: childSetCall,
|
|
234
240
|
nodeTypeName: child.nodeType,
|
|
241
|
+
production,
|
|
235
242
|
});
|
|
236
243
|
// Add argument building lines
|
|
237
244
|
argLines.forEach((line) => lines.push(line));
|
|
@@ -304,8 +311,11 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
304
311
|
// These are the outputs of child nodes that become the scope function's return value
|
|
305
312
|
lines.push(` // Extract return values from child outputs`);
|
|
306
313
|
const returnObj = [];
|
|
307
|
-
//
|
|
308
|
-
|
|
314
|
+
// Read return values from scopedCtx (not ctx) because:
|
|
315
|
+
// 1. scopedCtx still has all variables after mergeScope (merge copies, doesn't move)
|
|
316
|
+
// 2. scopedCtx.isAsync matches the scope function's sync/async nature, so getVariable
|
|
317
|
+
// returns values directly (not Promises) when the scope function is sync
|
|
318
|
+
const getCallAfterMerge = isAsync ? 'await scopedCtx.getVariable' : 'scopedCtx.getVariable';
|
|
309
319
|
// Create per-iteration execution index for scoped exit ports (so each iteration shows separately in UI)
|
|
310
320
|
// Use ctx (parent context) not scopedCtx so indices accumulate across iterations
|
|
311
321
|
lines.push(` const scopeExitIdx = ctx.addExecution('${parentNodeId}_scope_exit');`);
|
|
@@ -330,7 +340,7 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
330
340
|
const isStepPort = portName === 'success' || portName === 'failure';
|
|
331
341
|
const defaultValue = portName === 'success' ? 'true' : portName === 'failure' ? 'false' : 'undefined';
|
|
332
342
|
if (isStepPort) {
|
|
333
|
-
lines.push(` const ${varName} =
|
|
343
|
+
lines.push(` const ${varName} = scopedCtx.hasVariable(${varAddr}) ? ${getCallAfterMerge}(${varAddr}) as ${portType} : ${defaultValue};`);
|
|
334
344
|
}
|
|
335
345
|
else {
|
|
336
346
|
lines.push(` const ${varName} = ${getCallAfterMerge}(${varAddr}) as ${portType};`);
|
|
@@ -80,15 +80,9 @@ function getPullExecutionConfig(instance, nodeType) {
|
|
|
80
80
|
*/
|
|
81
81
|
export function generateControlFlowWithExecutionContext(workflow, nodeTypes, isAsync, production = false, bundleMode = false) {
|
|
82
82
|
const lines = [];
|
|
83
|
-
// In development mode,
|
|
83
|
+
// In development mode, use the injected debugger if available
|
|
84
84
|
if (!production) {
|
|
85
|
-
lines.push(`
|
|
86
|
-
lines.push(` const __effectiveDebugger__ = (`);
|
|
87
|
-
lines.push(` typeof __flowWeaverDebugger__ !== 'undefined' ? __flowWeaverDebugger__ :`);
|
|
88
|
-
lines.push(` typeof process !== 'undefined' && process.env.FLOW_WEAVER_DEBUG`);
|
|
89
|
-
lines.push(` ? createFlowWeaverDebugClient(process.env.FLOW_WEAVER_DEBUG, '${workflow.functionName}')`);
|
|
90
|
-
lines.push(` : undefined`);
|
|
91
|
-
lines.push(` );`);
|
|
85
|
+
lines.push(` const __effectiveDebugger__ = typeof __flowWeaverDebugger__ !== 'undefined' ? __flowWeaverDebugger__ : undefined;`);
|
|
92
86
|
lines.push('');
|
|
93
87
|
}
|
|
94
88
|
// Recursion depth protection: prevent infinite recursion in workflows
|
|
@@ -101,6 +95,12 @@ export function generateControlFlowWithExecutionContext(workflow, nodeTypes, isA
|
|
|
101
95
|
// In development mode, pass the effective debugger (from parameter or environment)
|
|
102
96
|
// In production mode, omit the debugger parameter
|
|
103
97
|
// Always pass abort signal for cancellation support
|
|
98
|
+
// In dev mode, always treat as async so the debugger can pause execution
|
|
99
|
+
// at breakpoints (sendStatusChangedEvent must be awaited for this to work).
|
|
100
|
+
// Production mode respects the original isAsync to avoid overhead.
|
|
101
|
+
if (!production) {
|
|
102
|
+
isAsync = true; // eslint-disable-line no-param-reassign
|
|
103
|
+
}
|
|
104
104
|
const asyncArg = isAsync ? 'true' : 'false';
|
|
105
105
|
if (production) {
|
|
106
106
|
lines.push(` const ctx = new GeneratedExecutionContext(${asyncArg}, __abortSignal__);`);
|
|
@@ -115,8 +115,8 @@ export function generateControlFlowWithExecutionContext(workflow, nodeTypes, isA
|
|
|
115
115
|
if (!production) {
|
|
116
116
|
lines.push(` // Debug controller for step-through debugging and checkpoint/resume`);
|
|
117
117
|
lines.push(` const __ctrl__: TDebugController = (`);
|
|
118
|
-
lines.push(` typeof globalThis !== 'undefined' && (globalThis as
|
|
119
|
-
lines.push(` ? (globalThis as
|
|
118
|
+
lines.push(` typeof globalThis !== 'undefined' && (globalThis as unknown as { __fw_debug_controller__?: TDebugController }).__fw_debug_controller__`);
|
|
119
|
+
lines.push(` ? (globalThis as unknown as { __fw_debug_controller__?: TDebugController }).__fw_debug_controller__`);
|
|
120
120
|
lines.push(` : { beforeNode: () => true, afterNode: () => {} }`);
|
|
121
121
|
lines.push(` );`);
|
|
122
122
|
lines.push('');
|
|
@@ -958,7 +958,7 @@ bundleMode = false, preDeclaredSuccessFlags = new Set(), forceTrackSuccess = fal
|
|
|
958
958
|
}
|
|
959
959
|
lines.push(`${indent}${ctxVar}.checkAborted('${instanceId}');`);
|
|
960
960
|
lines.push(`${indent}${safeId}Idx = ${ctxVar}.addExecution('${instanceId}');`);
|
|
961
|
-
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as
|
|
961
|
+
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${instanceId}';`);
|
|
962
962
|
lines.push(`${indent}${awaitPrefix}${ctxVar}.sendStatusChangedEvent({`);
|
|
963
963
|
lines.push(`${indent} nodeTypeName: '${functionName}',`);
|
|
964
964
|
lines.push(`${indent} id: '${instanceId}',`);
|
|
@@ -991,6 +991,7 @@ bundleMode = false, preDeclaredSuccessFlags = new Set(), forceTrackSuccess = fal
|
|
|
991
991
|
setCall,
|
|
992
992
|
nodeTypeName: functionName,
|
|
993
993
|
bundleMode,
|
|
994
|
+
production,
|
|
994
995
|
});
|
|
995
996
|
const awaitKeyword = branchNode.isAsync ? 'await ' : '';
|
|
996
997
|
if (branchNode.expression) {
|
|
@@ -1262,7 +1263,7 @@ bundleMode = false, preDeclaredSuccessFlags = new Set(), forceTrackSuccess = fal
|
|
|
1262
1263
|
generatedNodes.add(instanceId);
|
|
1263
1264
|
}
|
|
1264
1265
|
function generatePullNodeWithContext(instance, nodeType, workflow, lines, indent, isAsync, ctxVar = 'ctx', // Context variable name (for scoped contexts)
|
|
1265
|
-
bundleMode = false) {
|
|
1266
|
+
bundleMode = false, production = false) {
|
|
1266
1267
|
const instanceId = instance.id;
|
|
1267
1268
|
const safeId = toValidIdentifier(instanceId);
|
|
1268
1269
|
const functionName = nodeType.functionName;
|
|
@@ -1283,7 +1284,7 @@ bundleMode = false) {
|
|
|
1283
1284
|
lines.push(`${indent} }`);
|
|
1284
1285
|
lines.push(`${indent} ${ctxVar}.checkAborted('${instanceId}');`);
|
|
1285
1286
|
lines.push(`${indent} ${safeId}Idx = ${ctxVar}.addExecution('${instanceId}');`);
|
|
1286
|
-
lines.push(`${indent} if (typeof globalThis !== 'undefined') (globalThis as
|
|
1287
|
+
lines.push(`${indent} if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${instanceId}';`);
|
|
1287
1288
|
lines.push(`${indent} ${awaitPrefix}${ctxVar}.sendStatusChangedEvent({`);
|
|
1288
1289
|
lines.push(`${indent} nodeTypeName: '${functionName}',`);
|
|
1289
1290
|
lines.push(`${indent} id: '${instanceId}',`);
|
|
@@ -1306,6 +1307,7 @@ bundleMode = false) {
|
|
|
1306
1307
|
setCall,
|
|
1307
1308
|
nodeTypeName: functionName,
|
|
1308
1309
|
bundleMode,
|
|
1310
|
+
production,
|
|
1309
1311
|
});
|
|
1310
1312
|
const resultVar = `${safeId}Result`;
|
|
1311
1313
|
// Check if this is a workflow call (IMPORTED_WORKFLOW or WORKFLOW variant)
|
|
@@ -1407,7 +1409,7 @@ production = false // When false, emit debug controller hooks (beforeNode/afterN
|
|
|
1407
1409
|
: { enabled: false, triggerPort: 'execute' };
|
|
1408
1410
|
// If this is a pull execution node, wrap it in a lazy function
|
|
1409
1411
|
if (pullConfig.enabled) {
|
|
1410
|
-
generatePullNodeWithContext(instance, nodeType, workflow, lines, indent, isAsync, ctxVar, bundleMode);
|
|
1412
|
+
generatePullNodeWithContext(instance, nodeType, workflow, lines, indent, isAsync, ctxVar, bundleMode, production);
|
|
1411
1413
|
return;
|
|
1412
1414
|
}
|
|
1413
1415
|
const stepInputs = Object.entries(nodeType.inputs).filter(([portName, portConfig]) => {
|
|
@@ -1556,7 +1558,7 @@ production = false // When false, emit debug controller hooks (beforeNode/afterN
|
|
|
1556
1558
|
const awaitPrefix = isAsync ? 'await ' : '';
|
|
1557
1559
|
lines.push(`${indent}${ctxVar}.checkAborted('${instanceId}');`);
|
|
1558
1560
|
lines.push(`${indent}${varDecl}${safeId}Idx = ${ctxVar}.addExecution('${instanceId}');`);
|
|
1559
|
-
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as
|
|
1561
|
+
lines.push(`${indent}if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${instanceId}';`);
|
|
1560
1562
|
lines.push(`${indent}${awaitPrefix}${ctxVar}.sendStatusChangedEvent({`);
|
|
1561
1563
|
lines.push(`${indent} nodeTypeName: '${functionName}',`);
|
|
1562
1564
|
lines.push(`${indent} id: '${instanceId}',`);
|
|
@@ -1579,6 +1581,7 @@ production = false // When false, emit debug controller hooks (beforeNode/afterN
|
|
|
1579
1581
|
setCall,
|
|
1580
1582
|
nodeTypeName: functionName,
|
|
1581
1583
|
bundleMode,
|
|
1584
|
+
production,
|
|
1582
1585
|
});
|
|
1583
1586
|
const resultVar = `${safeId}Result`;
|
|
1584
1587
|
const awaitKeyword = nodeType.isAsync ? 'await ' : '';
|
package/package.json
CHANGED