flowstride 1.0.20-rc.6 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/NATIVE_BROWSER.md +341 -0
  2. package/NATIVE_CI.md +88 -169
  3. package/README.md +46 -214
  4. package/dist/adapters/api/undici.d.ts +8 -0
  5. package/dist/adapters/api/undici.js +11 -0
  6. package/dist/adapters/web/playwright.d.ts +25 -2
  7. package/dist/adapters/web/playwright.js +285 -21
  8. package/dist/ci/config.js +14 -1
  9. package/dist/ci/distribution.d.ts +38 -0
  10. package/dist/ci/distribution.js +134 -0
  11. package/dist/ci/init.d.ts +4 -1
  12. package/dist/ci/init.js +13 -2
  13. package/dist/ci/runtime.js +24 -5
  14. package/dist/cli/commands/run.js +3 -0
  15. package/dist/cli/index.js +24 -5
  16. package/dist/manual/security.d.ts +2 -2
  17. package/dist/native/accessibility.d.ts +3 -0
  18. package/dist/native/accessibility.js +68 -0
  19. package/dist/native/assertions.d.ts +2 -0
  20. package/dist/native/assertions.js +140 -0
  21. package/dist/native/compatibility.d.ts +3 -0
  22. package/dist/native/compatibility.js +16 -0
  23. package/dist/native/components.d.ts +12 -0
  24. package/dist/native/components.js +122 -0
  25. package/dist/native/dashboard.d.ts +7 -0
  26. package/dist/native/dashboard.js +32 -0
  27. package/dist/native/events.d.ts +34 -0
  28. package/dist/native/events.js +281 -0
  29. package/dist/native/evidence.d.ts +3 -0
  30. package/dist/native/evidence.js +31 -0
  31. package/dist/native/functions.d.ts +9 -0
  32. package/dist/native/functions.js +103 -0
  33. package/dist/native/runtime.d.ts +14 -0
  34. package/dist/native/runtime.js +154 -0
  35. package/dist/native/validation.d.ts +107 -0
  36. package/dist/native/validation.js +84 -0
  37. package/dist/parser/lexer.js +15 -4
  38. package/dist/parser/parser.js +1 -1
  39. package/dist/runner/flow_orchestrator.d.ts +4 -0
  40. package/dist/runner/flow_orchestrator.js +22 -5
  41. package/dist/runner/flow_worker.d.ts +7 -0
  42. package/dist/runner/flow_worker.js +141 -37
  43. package/dist/security/redaction.js +3 -1
  44. package/dist/sessions/manager.js +3 -1
  45. package/dist/types/index.d.ts +12 -0
  46. package/dist/utils/replayRequest.d.ts +8 -0
  47. package/dist/utils/replayRequest.js +77 -0
  48. package/package.json +22 -9
  49. package/src/ui/dist/assets/index-DglsL_J2.js +636 -0
  50. package/src/ui/dist/index.html +1 -1
  51. package/src/ui/dist/assets/index-DVwp0K-J.js +0 -462
@@ -0,0 +1,107 @@
1
+ import { z } from 'zod';
2
+ import type { BrowserContextOptions } from 'playwright';
3
+ import type { FlowstrideConfig } from '../types';
4
+ export declare const name: z.ZodString;
5
+ export declare const positive: z.ZodNumber;
6
+ export declare const headers: z.ZodRecord<z.ZodString, z.ZodString>;
7
+ export declare const contextOptions: z.ZodObject<{
8
+ acceptDownloads: z.ZodOptional<z.ZodBoolean>;
9
+ strictSelectors: z.ZodOptional<z.ZodBoolean>;
10
+ clientCertificates: z.ZodOptional<z.ZodArray<z.ZodObject<{
11
+ origin: z.ZodString;
12
+ certPath: z.ZodOptional<z.ZodString>;
13
+ keyPath: z.ZodOptional<z.ZodString>;
14
+ pfxPath: z.ZodOptional<z.ZodString>;
15
+ passphrase: z.ZodOptional<z.ZodString>;
16
+ }, z.core.$strict>>>;
17
+ storageState: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
18
+ cookies: z.ZodArray<z.ZodObject<{
19
+ name: z.ZodString;
20
+ value: z.ZodString;
21
+ domain: z.ZodString;
22
+ path: z.ZodString;
23
+ expires: z.ZodNumber;
24
+ httpOnly: z.ZodBoolean;
25
+ secure: z.ZodBoolean;
26
+ sameSite: z.ZodEnum<{
27
+ Strict: "Strict";
28
+ Lax: "Lax";
29
+ None: "None";
30
+ }>;
31
+ }, z.core.$strict>>;
32
+ origins: z.ZodArray<z.ZodObject<{
33
+ origin: z.ZodString;
34
+ localStorage: z.ZodArray<z.ZodObject<{
35
+ name: z.ZodString;
36
+ value: z.ZodString;
37
+ }, z.core.$strict>>;
38
+ indexedDB: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
39
+ }, z.core.$strict>>;
40
+ }, z.core.$strict>]>>;
41
+ baseURL: z.ZodOptional<z.ZodString>;
42
+ bypassCSP: z.ZodOptional<z.ZodBoolean>;
43
+ colorScheme: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
44
+ light: "light";
45
+ dark: "dark";
46
+ "no-preference": "no-preference";
47
+ }>>>;
48
+ contrast: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
49
+ "no-preference": "no-preference";
50
+ more: "more";
51
+ }>>>;
52
+ deviceScaleFactor: z.ZodOptional<z.ZodNumber>;
53
+ extraHTTPHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
54
+ forcedColors: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
55
+ none: "none";
56
+ active: "active";
57
+ }>>>;
58
+ hasTouch: z.ZodOptional<z.ZodBoolean>;
59
+ httpCredentials: z.ZodOptional<z.ZodObject<{
60
+ username: z.ZodString;
61
+ password: z.ZodString;
62
+ origin: z.ZodOptional<z.ZodString>;
63
+ send: z.ZodOptional<z.ZodEnum<{
64
+ always: "always";
65
+ unauthorized: "unauthorized";
66
+ }>>;
67
+ }, z.core.$strict>>;
68
+ geolocation: z.ZodOptional<z.ZodObject<{
69
+ latitude: z.ZodNumber;
70
+ longitude: z.ZodNumber;
71
+ accuracy: z.ZodOptional<z.ZodNumber>;
72
+ }, z.core.$strict>>;
73
+ ignoreHTTPSErrors: z.ZodOptional<z.ZodBoolean>;
74
+ isMobile: z.ZodOptional<z.ZodBoolean>;
75
+ javaScriptEnabled: z.ZodOptional<z.ZodBoolean>;
76
+ locale: z.ZodOptional<z.ZodString>;
77
+ offline: z.ZodOptional<z.ZodBoolean>;
78
+ permissions: z.ZodOptional<z.ZodArray<z.ZodString>>;
79
+ proxy: z.ZodOptional<z.ZodObject<{
80
+ server: z.ZodString;
81
+ bypass: z.ZodOptional<z.ZodString>;
82
+ username: z.ZodOptional<z.ZodString>;
83
+ password: z.ZodOptional<z.ZodString>;
84
+ }, z.core.$strict>>;
85
+ reducedMotion: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
86
+ reduce: "reduce";
87
+ "no-preference": "no-preference";
88
+ }>>>;
89
+ screen: z.ZodOptional<z.ZodObject<{
90
+ width: z.ZodNumber;
91
+ height: z.ZodNumber;
92
+ }, z.core.$strict>>;
93
+ serviceWorkers: z.ZodOptional<z.ZodEnum<{
94
+ allow: "allow";
95
+ block: "block";
96
+ }>>;
97
+ timezoneId: z.ZodOptional<z.ZodString>;
98
+ userAgent: z.ZodOptional<z.ZodString>;
99
+ viewport: z.ZodOptional<z.ZodNullable<z.ZodObject<{
100
+ width: z.ZodNumber;
101
+ height: z.ZodNumber;
102
+ }, z.core.$strict>>>;
103
+ }, z.core.$strict>;
104
+ export declare function validateContextOptions(value: unknown, browser?: string, root?: string): BrowserContextOptions;
105
+ export declare function evidencePath(config: FlowstrideConfig, file: string): string;
106
+ export declare function readProjectFile(config: FlowstrideConfig, file: string, maxSize?: number): Buffer;
107
+ export declare function poll(read: () => Promise<boolean>, timeout: number, label: string): Promise<void>;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.contextOptions = exports.headers = exports.positive = exports.name = void 0;
7
+ exports.validateContextOptions = validateContextOptions;
8
+ exports.evidencePath = evidencePath;
9
+ exports.readProjectFile = readProjectFile;
10
+ exports.poll = poll;
11
+ const node_fs_1 = __importDefault(require("node:fs"));
12
+ const node_path_1 = __importDefault(require("node:path"));
13
+ const zod_1 = require("zod");
14
+ const projectPaths_1 = require("../utils/projectPaths");
15
+ exports.name = zod_1.z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,79}$/, 'Use a simple name without path separators.');
16
+ exports.positive = zod_1.z.number().int().min(1).max(2147483647);
17
+ exports.headers = zod_1.z.record(zod_1.z.string(), zod_1.z.string());
18
+ const size = zod_1.z.object({ width: exports.positive, height: exports.positive }).strict();
19
+ // File-bearing options are handled explicitly; evidence paths cannot bypass project containment.
20
+ exports.contextOptions = zod_1.z.object({
21
+ acceptDownloads: zod_1.z.boolean().optional(), strictSelectors: zod_1.z.boolean().optional(),
22
+ clientCertificates: zod_1.z.array(zod_1.z.object({ origin: zod_1.z.string().url(), certPath: zod_1.z.string().optional(), keyPath: zod_1.z.string().optional(), pfxPath: zod_1.z.string().optional(), passphrase: zod_1.z.string().optional() }).strict()).optional(),
23
+ storageState: zod_1.z.union([zod_1.z.string(), zod_1.z.object({ cookies: zod_1.z.array(zod_1.z.object({ name: zod_1.z.string(), value: zod_1.z.string(), domain: zod_1.z.string(), path: zod_1.z.string(), expires: zod_1.z.number(), httpOnly: zod_1.z.boolean(), secure: zod_1.z.boolean(), sameSite: zod_1.z.enum(['Strict', 'Lax', 'None']) }).strict()), origins: zod_1.z.array(zod_1.z.object({ origin: zod_1.z.string().url(), localStorage: zod_1.z.array(zod_1.z.object({ name: zod_1.z.string(), value: zod_1.z.string() }).strict()), indexedDB: zod_1.z.array(zod_1.z.unknown()).optional() }).strict()) }).strict()]).optional(),
24
+ baseURL: zod_1.z.string().url().optional(),
25
+ bypassCSP: zod_1.z.boolean().optional(), colorScheme: zod_1.z.enum(['light', 'dark', 'no-preference']).nullable().optional(),
26
+ contrast: zod_1.z.enum(['no-preference', 'more']).nullable().optional(),
27
+ deviceScaleFactor: zod_1.z.number().positive().optional(), extraHTTPHeaders: exports.headers.optional(),
28
+ forcedColors: zod_1.z.enum(['active', 'none']).nullable().optional(), hasTouch: zod_1.z.boolean().optional(),
29
+ httpCredentials: zod_1.z.object({ username: zod_1.z.string(), password: zod_1.z.string(), origin: zod_1.z.string().url().optional(), send: zod_1.z.enum(['always', 'unauthorized']).optional() }).strict().optional(),
30
+ geolocation: zod_1.z.object({ latitude: zod_1.z.number().min(-90).max(90), longitude: zod_1.z.number().min(-180).max(180), accuracy: zod_1.z.number().nonnegative().optional() }).strict().optional(),
31
+ ignoreHTTPSErrors: zod_1.z.boolean().optional(), isMobile: zod_1.z.boolean().optional(), javaScriptEnabled: zod_1.z.boolean().optional(),
32
+ locale: zod_1.z.string().min(1).optional(), offline: zod_1.z.boolean().optional(), permissions: zod_1.z.array(zod_1.z.string()).optional(),
33
+ proxy: zod_1.z.object({ server: zod_1.z.string().min(1), bypass: zod_1.z.string().optional(), username: zod_1.z.string().optional(), password: zod_1.z.string().optional() }).strict().optional(),
34
+ reducedMotion: zod_1.z.enum(['reduce', 'no-preference']).nullable().optional(), screen: size.optional(),
35
+ serviceWorkers: zod_1.z.enum(['allow', 'block']).optional(), timezoneId: zod_1.z.string().optional(),
36
+ userAgent: zod_1.z.string().optional(), viewport: size.nullable().optional(),
37
+ }).strict();
38
+ function validateContextOptions(value, browser = 'chromium', root = process.cwd()) {
39
+ const parsed = exports.contextOptions.parse(value ?? {});
40
+ if (typeof parsed.storageState === 'string')
41
+ parsed.storageState = (0, projectPaths_1.projectPath)(root, parsed.storageState);
42
+ for (const certificate of parsed.clientCertificates || [])
43
+ for (const key of ['certPath', 'keyPath', 'pfxPath'])
44
+ if (certificate[key])
45
+ certificate[key] = (0, projectPaths_1.projectPath)(root, certificate[key]);
46
+ if (browser === 'firefox' && parsed.isMobile)
47
+ throw new Error('Firefox does not support mobile emulation; use viewport and touch options instead.');
48
+ return parsed;
49
+ }
50
+ function evidencePath(config, file) {
51
+ const safe = exports.name.parse(file);
52
+ const root = config.projectRoot || process.cwd();
53
+ const dir = (0, projectPaths_1.projectPath)(root, config.artifactsDir || 'flowstride-artifacts');
54
+ node_fs_1.default.mkdirSync(dir, { recursive: true, mode: 0o700 });
55
+ return (0, projectPaths_1.projectPath)(root, node_path_1.default.join(dir, (0, projectPaths_1.artifactPrefix)(config.testFile) + safe));
56
+ }
57
+ function readProjectFile(config, file, maxSize = 20 * 1024 * 1024) {
58
+ const absolute = (0, projectPaths_1.projectPath)(config.projectRoot || process.cwd(), file);
59
+ if (!node_fs_1.default.statSync(absolute).isFile() || node_fs_1.default.statSync(absolute).size > maxSize)
60
+ throw new Error('Fixture must be a regular project file within the size limit.');
61
+ return node_fs_1.default.readFileSync(absolute);
62
+ }
63
+ async function poll(read, timeout, label) {
64
+ const deadline = Date.now() + exports.positive.parse(timeout);
65
+ let last;
66
+ for (;;) {
67
+ const remaining = deadline - Date.now();
68
+ if (remaining <= 0)
69
+ throw new Error(`Assertion timed out: ${label}`, { cause: last });
70
+ let timer;
71
+ try {
72
+ const ok = await Promise.race([read(), new Promise((_, reject) => { timer = setTimeout(() => reject(new Error('Read timed out')), remaining); })]);
73
+ if (ok)
74
+ return;
75
+ }
76
+ catch (error) {
77
+ last = error;
78
+ }
79
+ finally {
80
+ clearTimeout(timer);
81
+ }
82
+ await new Promise(resolve => setTimeout(resolve, Math.min(50, Math.max(0, deadline - Date.now()))));
83
+ }
84
+ }
@@ -53,11 +53,22 @@ class Lexer {
53
53
  let jsonStr = "";
54
54
  let depth = 0;
55
55
  let startLine = this.line;
56
+ let inString = false, escaped = false;
56
57
  while (this.position < this.input.length) {
57
58
  const c = this.input[this.position];
58
- if (c === "{")
59
+ if (inString) {
60
+ if (escaped)
61
+ escaped = false;
62
+ else if (c === "\\")
63
+ escaped = true;
64
+ else if (c === '"')
65
+ inString = false;
66
+ }
67
+ else if (c === '"')
68
+ inString = true;
69
+ else if (c === "{")
59
70
  depth++;
60
- if (c === "}")
71
+ else if (c === "}")
61
72
  depth--;
62
73
  if (c === "\n")
63
74
  this.line++;
@@ -217,7 +228,7 @@ class Lexer {
217
228
  });
218
229
  continue;
219
230
  }
220
- else if (ident.includes(".") && !lowerIdent.startsWith("flow.")) {
231
+ else if (/^flow\.(browser|assert|network|download|clock|stub|trace|har|a11y|component)\.[a-z]+$/i.test(ident) || (ident.includes(".") && !lowerIdent.startsWith("flow."))) {
221
232
  tokens.push({
222
233
  type: TokenType.ALIAS_COMMAND,
223
234
  value: ident,
@@ -392,7 +403,7 @@ class Lexer {
392
403
  line: this.line,
393
404
  });
394
405
  }
395
- else if (ident.includes(".") && !lowerIdent.startsWith("flow.")) {
406
+ else if (/^flow\.(browser|assert|network|download|clock|stub|trace|har|a11y|component)\.[a-z]+$/i.test(ident) || (ident.includes(".") && !lowerIdent.startsWith("flow."))) {
396
407
  tokens.push({
397
408
  type: TokenType.ALIAS_COMMAND,
398
409
  value: ident,
@@ -242,7 +242,7 @@ class Parser {
242
242
  return {
243
243
  id: `scenario_${this.scenarioCounter}_S${this.stepCounter++}`,
244
244
  blockDescription: this.currentBlockDescription,
245
- action: "plugin",
245
+ action: alias === "flow" ? "native" : "plugin",
246
246
  payload: {
247
247
  pluginAlias: alias,
248
248
  pluginMethod: method,
@@ -4,6 +4,7 @@ export declare class FlowOrchestrator {
4
4
  private worker;
5
5
  private workerCount;
6
6
  private config?;
7
+ static readonly nativeBrowserProtocol = 2;
7
8
  static readonly nativeCIProtocol = 1;
8
9
  readonly nativeEventProtocol = 1;
9
10
  private wss;
@@ -12,6 +13,9 @@ export declare class FlowOrchestrator {
12
13
  private stepStatusRegistry;
13
14
  private pdfGenerator;
14
15
  private disconnectTimer;
16
+ private dashboardBrowser;
17
+ private closing;
18
+ private browserInfoByFile;
15
19
  constructor(worker: FlowWorker, workerCount?: number, config?: FlowstrideConfig | undefined);
16
20
  private forwardToDashboard;
17
21
  private executeTestRun;
@@ -37,8 +37,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.FlowOrchestrator = void 0;
40
+ const dashboard_1 = require("../native/dashboard");
41
+ const evidence_1 = require("../native/evidence");
42
+ const distribution_1 = require("../ci/distribution");
40
43
  const localDashboard_1 = require("../security/localDashboard");
41
- const projectPaths_1 = require("../utils/projectPaths");
42
44
  const fs = __importStar(require("fs"));
43
45
  const path = __importStar(require("path"));
44
46
  const http = __importStar(require("http"));
@@ -50,6 +52,7 @@ class FlowOrchestrator {
50
52
  worker;
51
53
  workerCount;
52
54
  config;
55
+ static nativeBrowserProtocol = 2;
53
56
  static nativeCIProtocol = 1;
54
57
  nativeEventProtocol = 1;
55
58
  wss = null;
@@ -58,6 +61,9 @@ class FlowOrchestrator {
58
61
  stepStatusRegistry = new Map();
59
62
  pdfGenerator;
60
63
  disconnectTimer = null;
64
+ dashboardBrowser = new dashboard_1.DashboardBrowser();
65
+ closing = false;
66
+ browserInfoByFile = new Map();
61
67
  constructor(worker, workerCount = 1, config) {
62
68
  this.worker = worker;
63
69
  this.workerCount = workerCount;
@@ -68,6 +74,10 @@ class FlowOrchestrator {
68
74
  });
69
75
  }
70
76
  forwardToDashboard(type, payload) {
77
+ if (type === 'BROWSER_INFO')
78
+ this.browserInfoByFile.set(payload.fileName, payload);
79
+ if (type === 'SUITE_START')
80
+ this.browserInfoByFile.clear();
71
81
  this.config?.onRunEvent?.({ type, payload });
72
82
  if (this.wss) {
73
83
  this.wss.clients.forEach((client) => {
@@ -78,7 +88,7 @@ class FlowOrchestrator {
78
88
  }
79
89
  async executeTestRun(targetPath) {
80
90
  this.forwardToDashboard("SUITE_START", {});
81
- const filesToProcess = (0, projectPaths_1.discoverFlows)(targetPath);
91
+ const filesToProcess = (0, distribution_1.executionPlan)(targetPath, this.config).files;
82
92
  if (this.config)
83
93
  this.config.flowRoot = fs.statSync(targetPath).isDirectory() ? targetPath : path.dirname(targetPath);
84
94
  this.globalTestScenarios = [];
@@ -115,6 +125,8 @@ class FlowOrchestrator {
115
125
  return;
116
126
  }
117
127
  res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
128
+ if ((0, evidence_1.serveDOMSnapshot)(req, res, this.config))
129
+ return;
118
130
  if (req.url && req.url.startsWith("/videos/")) {
119
131
  let urlObj;
120
132
  try {
@@ -229,6 +241,8 @@ class FlowOrchestrator {
229
241
  });
230
242
  this.wss = new ws_1.WebSocketServer({ server: this.httpServer, verifyClient: (info) => Boolean(info.origin) && (0, localDashboard_1.isLocalDashboardRequest)(info.req.headers.host, info.origin) });
231
243
  this.wss.on("connection", (ws) => {
244
+ for (const payload of this.browserInfoByFile.values())
245
+ ws.send(JSON.stringify({ type: 'BROWSER_INFO', payload }));
232
246
  if (this.disconnectTimer) {
233
247
  clearTimeout(this.disconnectTimer);
234
248
  this.disconnectTimer = null;
@@ -267,7 +281,7 @@ class FlowOrchestrator {
267
281
  }
268
282
  });
269
283
  ws.on("close", () => {
270
- if (this.wss && this.wss.clients.size === 0) {
284
+ if (!this.closing && this.wss && this.wss.clients.size === 0) {
271
285
  this.disconnectTimer = setTimeout(async () => {
272
286
  console.log(chalk_1.default.yellow("\n[Flowstride]: Dashboard disconnected. Shutting down framework..."));
273
287
  this.worker.abort();
@@ -300,8 +314,8 @@ class FlowOrchestrator {
300
314
  !!process.env.GITHUB_ACTIONS ||
301
315
  !!process.env.FLOWSTRIDE_API_KEY;
302
316
  if (!isStrictHeadless) {
303
- const { default: open } = await import("open");
304
- await open(localUrl);
317
+ await this.dashboardBrowser.open(localUrl, this.config?.browser);
318
+ console.log(`[Dashboard]: ${this.config?.browser === 'firefox' || this.config?.browser === 'webkit' ? this.config.browser : 'system default'} dashboard window; test browser reported after launch${this.config?.headless ? ' (headless tests)' : ''}.`);
305
319
  console.log(chalk_1.default.yellow("[Dashboard]: Waiting for UI connection..."));
306
320
  while (this.wss.clients.size === 0)
307
321
  await new Promise((r) => setTimeout(r, 250));
@@ -314,6 +328,7 @@ class FlowOrchestrator {
314
328
  resolve(result);
315
329
  }
316
330
  catch (err) {
331
+ await this.dashboardBrowser.close();
317
332
  reject(err);
318
333
  }
319
334
  });
@@ -327,6 +342,8 @@ class FlowOrchestrator {
327
342
  this.worker.abort();
328
343
  }
329
344
  async close() {
345
+ this.closing = true;
346
+ await this.dashboardBrowser.close();
330
347
  if (this.disconnectTimer)
331
348
  clearTimeout(this.disconnectTimer);
332
349
  this.wss?.clients.forEach(client => client.terminate());
@@ -19,10 +19,16 @@ export declare class FlowWorker extends EventEmitter {
19
19
  private store;
20
20
  private sessions;
21
21
  private pluginManager?;
22
+ static readonly nativeBrowserProtocol = 2;
22
23
  private isSilent;
23
24
  private isAborted;
24
25
  private bailTriggered;
25
26
  private isDebugHalted;
27
+ private native;
28
+ private attempt;
29
+ private maxAttempts;
30
+ private fallbackStream?;
31
+ private interceptedContexts;
26
32
  private currentStepContext;
27
33
  private currentFileName;
28
34
  private activeAudioPath;
@@ -46,6 +52,7 @@ export declare class FlowWorker extends EventEmitter {
46
52
  handleReplayRequest(payload: any): Promise<void>;
47
53
  abort(): void;
48
54
  runBatch(filesToProcess: string[]): Promise<void>;
55
+ private runScenarioWithRetries;
49
56
  private runScenario;
50
57
  private waitForPipeline;
51
58
  private executeStep;