@synergenius/flow-weaver 0.21.20 → 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.
@@ -8,7 +8,7 @@
8
8
  * - Function body (between markers)
9
9
  */
10
10
  import { bodyGenerator } from '../body-generator.js';
11
- import { generateInlineRuntime, generateInlineDebugClient } from './inline-runtime.js';
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
  }
@@ -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, generateInlineDebugClient, stripTypeScript } from './inline-runtime.js';
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
- const asyncKeyword = shouldBeAsync ? 'async ' : '';
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 asyncKeyword = shouldBeAsync ? 'async ' : '';
492
- lines.push(`${asyncKeyword}function ${workflow.functionName}(`);
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.
@@ -100,7 +100,7 @@ export function generateInlineRuntime(production, exportClasses = false, outputF
100
100
  lines.push(' | TWorkflowCompletedEvent;');
101
101
  lines.push('');
102
102
  lines.push(`${exportKeyword}type TDebugger = {`);
103
- lines.push(' sendEvent: (event: TEvent) => void;');
103
+ lines.push(' sendEvent: (event: TEvent) => void | Promise<void>;');
104
104
  lines.push(' innerFlowInvocation: boolean;');
105
105
  lines.push(' sessionId?: string;');
106
106
  lines.push('};');
@@ -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(this.isAsync, this.abortSignal);');
309
+ lines.push(' const scopedContext = new GeneratedExecutionContext(effectiveIsAsync, this.abortSignal);');
309
310
  }
310
311
  else {
311
- lines.push(' const scopedContext = new GeneratedExecutionContext(this.isAsync, this.flowWeaverDebugger, this.abortSignal);');
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');
@@ -371,16 +372,16 @@ export function generateInlineRuntime(production, exportClasses = false, outputF
371
372
  lines.push('');
372
373
  // Debug event methods (only in development mode)
373
374
  if (!production) {
374
- lines.push(' sendStatusChangedEvent(args: {');
375
+ lines.push(' async sendStatusChangedEvent(args: {');
375
376
  lines.push(' nodeTypeName: string;');
376
377
  lines.push(' id: string;');
377
378
  lines.push(' scope?: string;');
378
379
  lines.push(' side?: "start" | "exit";');
379
380
  lines.push(' executionIndex: number;');
380
381
  lines.push(' status: TStatusType;');
381
- lines.push(' }): void {');
382
+ lines.push(' }): Promise<void> {');
382
383
  lines.push(' if (this.flowWeaverDebugger) {');
383
- lines.push(' this.flowWeaverDebugger.sendEvent({');
384
+ lines.push(' await this.flowWeaverDebugger.sendEvent({');
384
385
  lines.push(' type: "STATUS_CHANGED",');
385
386
  lines.push(' ...args,');
386
387
  lines.push(' innerFlowInvocation: this.flowWeaverDebugger.innerFlowInvocation,');
@@ -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