@wenathlan/extension 1.1.52 → 1.1.53

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/index.js CHANGED
@@ -335,6 +335,14 @@ function teardowncdpsession(input) {
335
335
 
336
336
  // workflow.ts
337
337
  var workflowkinds = ["composeworkflow", "savetemplate", "runworkflow", "dryrun", "delay", "waitelement", "compute", "extractvars"];
338
+ function nestedparamof(value) {
339
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
340
+ const candidate = value;
341
+ if (typeof candidate.name !== "string" || !/^[a-z][a-z0-9]*$/.test(candidate.name)) return void 0;
342
+ if (!variablekinds.includes(candidate.kind)) return void 0;
343
+ if (candidate.default !== void 0 && !["string", "number", "boolean"].includes(typeof candidate.default) && !Array.isArray(candidate.default)) return void 0;
344
+ return { name: candidate.name, kind: candidate.kind, ...candidate.default !== void 0 ? { default: candidate.default } : {} };
345
+ }
338
346
  function workflowstepof(value) {
339
347
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
340
348
  const candidate = value;
@@ -344,6 +352,7 @@ function workflowstepof(value) {
344
352
  if (candidate.target !== void 0 && (typeof candidate.target !== "string" || !candidate.target)) return void 0;
345
353
  if (candidate.value !== void 0 && typeof candidate.value !== "string") return void 0;
346
354
  if (candidate.options !== void 0 && typeof candidate.options !== "string") return void 0;
355
+ if (candidate.breakpoint !== void 0 && typeof candidate.breakpoint !== "boolean") return void 0;
347
356
  const bindings = Array.isArray(candidate.bindings) ? candidate.bindings.flatMap((binding) => bindingof(binding) !== void 0 ? [bindingof(binding)] : []) : void 0;
348
357
  if (candidate.bindings !== void 0 && bindings === void 0) return void 0;
349
358
  if (Array.isArray(candidate.bindings) && bindings !== void 0 && bindings.length !== candidate.bindings.length) return void 0;
@@ -351,14 +360,20 @@ function workflowstepof(value) {
351
360
  if (candidate.expression !== void 0 && expression === void 0) return void 0;
352
361
  const extract = candidate.extract === void 0 ? void 0 : regexruleof(candidate.extract);
353
362
  if (candidate.extract !== void 0 && extract === void 0) return void 0;
354
- return { id: candidate.id, kind: candidate.kind, label: candidate.label, ...candidate.target !== void 0 ? { target: candidate.target } : {}, ...candidate.value !== void 0 ? { value: candidate.value } : {}, ...candidate.options !== void 0 ? { options: candidate.options } : {}, ...bindings !== void 0 && bindings.length > 0 ? { bindings } : {}, ...expression !== void 0 ? { expression } : {}, ...extract !== void 0 ? { extract } : {} };
363
+ const params = Array.isArray(candidate.params) ? candidate.params.flatMap((param) => nestedparamof(param) !== void 0 ? [nestedparamof(param)] : []) : void 0;
364
+ if (candidate.params !== void 0 && params === void 0) return void 0;
365
+ if (Array.isArray(candidate.params) && params !== void 0 && params.length !== candidate.params.length) return void 0;
366
+ return { id: candidate.id, kind: candidate.kind, label: candidate.label, ...candidate.target !== void 0 ? { target: candidate.target } : {}, ...candidate.value !== void 0 ? { value: candidate.value } : {}, ...candidate.options !== void 0 ? { options: candidate.options } : {}, ...bindings !== void 0 && bindings.length > 0 ? { bindings } : {}, ...expression !== void 0 ? { expression } : {}, ...extract !== void 0 ? { extract } : {}, ...candidate.breakpoint === true ? { breakpoint: true } : {}, ...params !== void 0 && params.length > 0 ? { params } : {} };
355
367
  }
356
368
  function blockinvocationof(value) {
357
369
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
358
370
  const candidate = value;
359
371
  if (typeof candidate.block !== "string" || !candidate.block.trim()) return void 0;
360
372
  if (typeof candidate.label !== "string" || !candidate.label.trim()) return void 0;
361
- return { block: candidate.block, label: candidate.label };
373
+ const params = Array.isArray(candidate.params) ? candidate.params.flatMap((param) => nestedparamof(param) !== void 0 ? [nestedparamof(param)] : []) : void 0;
374
+ if (candidate.params !== void 0 && params === void 0) return void 0;
375
+ if (Array.isArray(candidate.params) && params !== void 0 && params.length !== candidate.params.length) return void 0;
376
+ return { block: candidate.block, label: candidate.label, ...params !== void 0 && params.length > 0 ? { params } : {} };
362
377
  }
363
378
  function workflowblockof(value) {
364
379
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
@@ -437,10 +452,15 @@ function regexruleof(value) {
437
452
  function expandblocks(steps, blocks) {
438
453
  const byname = new Map(blocks.map((block) => [block.name, block]));
439
454
  const expanded = [];
440
- const visit = (entries, path, inside) => {
455
+ const visit = (entries, path, inside, params) => {
456
+ let stamped = params === void 0;
441
457
  for (const entry of entries) {
442
458
  if ("kind" in entry && "label" in entry && !("block" in entry)) {
443
- expanded.push(inside === void 0 ? entry : { ...entry, block: inside });
459
+ const marked = inside === void 0 ? entry : { ...entry, block: inside };
460
+ if (!stamped && params !== void 0) {
461
+ expanded.push({ ...marked, params });
462
+ stamped = true;
463
+ } else expanded.push(marked);
444
464
  continue;
445
465
  }
446
466
  const invocation = blockinvocationof(entry);
@@ -448,7 +468,7 @@ function expandblocks(steps, blocks) {
448
468
  if (path.includes(invocation.block)) throw new Error(`The block ${invocation.block} recurs inside itself and cannot expand.`);
449
469
  const block = byname.get(invocation.block);
450
470
  if (!block) throw new Error(`The block ${invocation.block} is not defined in the workflow.`);
451
- visit(block.steps, [...path, invocation.block], invocation.block);
471
+ visit(block.steps, [...path, invocation.block], invocation.block, invocation.params ?? params);
452
472
  }
453
473
  };
454
474
  visit(steps, [], void 0);
@@ -816,6 +836,17 @@ async function runworkflow(input) {
816
836
  if (step.block !== void 0 && step.block !== activeblock) {
817
837
  scopes = pushscope(scopes, step.block, scopes[scopes.length - 1].name);
818
838
  activeblock = step.block;
839
+ if (step.params) {
840
+ try {
841
+ for (const param of step.params) {
842
+ if (param.default === void 0) continue;
843
+ scopes = setvariable(scopes, param.name, param.kind, coercevariable(param.default, param.kind), input.now);
844
+ }
845
+ } catch (error) {
846
+ const reason = error instanceof Error ? error.message : String(error);
847
+ return { run: { ...run, state: "failed", endedat: Date.now(), failreason: `The nested parameter of block ${step.block} failed: ${reason}` }, scopes, log, outputs };
848
+ }
849
+ }
819
850
  } else if (step.block === void 0 && activeblock !== void 0) {
820
851
  while (scopes.length > 1) scopes = popscope(scopes);
821
852
  activeblock = void 0;
@@ -848,6 +879,27 @@ function dryrunworkflow(input) {
848
879
  }
849
880
  return { run: { ...run, state: "done", cursor: input.record.steps.length, endedat: input.now }, scopes, log };
850
881
  }
882
+ function watchdogpass(input) {
883
+ const verdicts = [];
884
+ for (const run of input.runs) {
885
+ if (run.state !== "running") continue;
886
+ const lastcompletedat = input.lastcompletedat[run.id] ?? run.startedat;
887
+ const live = input.liveexecutors.includes(run.id);
888
+ const silence = input.now - lastcompletedat;
889
+ if (!live && input.config.zombiewindow !== void 0 && silence >= input.config.zombiewindow) {
890
+ verdicts.push({ runid: run.id, verdict: "zombie", action: "reap", reason: `The run ${run.id} lost its executor ${silence} ms ago and reaps as a zombie of a browser shutdown at its last checkpoint ${run.cursor}.`, ...lastcompletedat !== run.startedat ? { lastcompletedat } : {} });
891
+ continue;
892
+ }
893
+ if (!live) continue;
894
+ if (silence >= input.config.stallthreshold) {
895
+ const action = input.config.action;
896
+ verdicts.push({ runid: run.id, verdict: "stalled", action, reason: `The run ${run.id} completed no step for ${silence} ms past the reviewed threshold and the watchdog recovers it with ${action} at cursor ${run.cursor}.`, ...lastcompletedat !== run.startedat ? { lastcompletedat } : {} });
897
+ continue;
898
+ }
899
+ verdicts.push({ runid: run.id, verdict: "healthy", action: "none", reason: `The run ${run.id} completed its last step ${silence} ms ago and stays healthy.`, ...lastcompletedat !== run.startedat ? { lastcompletedat } : {} });
900
+ }
901
+ return verdicts;
902
+ }
851
903
 
852
904
  // controlflow.ts
853
905
  var controlflowkinds = ["condition", "branch", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"];
@@ -4434,6 +4486,107 @@ var sessionmemory = class {
4434
4486
  async listmanualruns() {
4435
4487
  return await this.adapter.get("manualruns") ?? [];
4436
4488
  }
4489
+ /** Stores one workflow version record with its change note; saving the same version again replaces its note while older versions survive for the timeline. */
4490
+ async addworkflowversion(version) {
4491
+ const versions = (await this.listworkflowversions()).filter((entry) => !(entry.workflowid === version.workflowid && entry.version === version.version));
4492
+ await this.adapter.set("workflowversions", [version, ...versions]);
4493
+ }
4494
+ /** Returns every stored workflow version record, newest first, optionally filtered to one workflow. */
4495
+ async listworkflowversions(workflowid) {
4496
+ const versions = await this.adapter.get("workflowversions") ?? [];
4497
+ return workflowid === void 0 ? versions : versions.filter((entry) => entry.workflowid === workflowid);
4498
+ }
4499
+ /** Stores one version diff result for the history view. */
4500
+ async addversiondiff(diff) {
4501
+ const diffs = (await this.listversiondiffs()).filter((entry) => !(entry.workflowid === diff.workflowid && entry.from === diff.from && entry.to === diff.to));
4502
+ await this.adapter.set("versiondiffs", [diff, ...diffs]);
4503
+ }
4504
+ /** Returns every stored version diff result, newest first, optionally filtered to one workflow. */
4505
+ async listversiondiffs(workflowid) {
4506
+ const diffs = await this.adapter.get("versiondiffs") ?? [];
4507
+ return workflowid === void 0 ? diffs : diffs.filter((entry) => entry.workflowid === workflowid);
4508
+ }
4509
+ /** Records one run history entry — the outcome, duration and trigger cause of one execution — under the user configured retention window with no code ceiling. */
4510
+ async addrunhistory(entry) {
4511
+ const entries = await this.gethistory();
4512
+ const combined = [entry, ...entries];
4513
+ const retention = (await this.getsettings())?.runhistoryretention;
4514
+ await this.adapter.set("runhistory", retention === void 0 ? combined : combined.slice(0, retention));
4515
+ }
4516
+ /** Returns the stored run history, newest first, filtered by workflow, outcome and time floor; the filters stay user choices. */
4517
+ async gethistory(filter) {
4518
+ const entries = await this.adapter.get("runhistory") ?? [];
4519
+ let filtered = entries;
4520
+ if (filter?.workflowid !== void 0) filtered = filtered.filter((entry) => entry.workflowid === filter.workflowid);
4521
+ if (filter?.outcome !== void 0) filtered = filtered.filter((entry) => entry.outcome === filter.outcome);
4522
+ if (filter?.since !== void 0) filtered = filtered.filter((entry) => entry.endedat >= filter.since);
4523
+ if (filter?.limit !== void 0) filtered = filtered.slice(0, filter.limit);
4524
+ return filtered;
4525
+ }
4526
+ /** Stores the editor layout of one workflow so the canvas reopens exactly as left. */
4527
+ async seteditorlayout(workflowid, layout) {
4528
+ return this.adapter.set(`editorlayout${workflowid}`, layout);
4529
+ }
4530
+ /** Returns the stored editor layout of one workflow. */
4531
+ async geteditorlayout(workflowid) {
4532
+ return await this.adapter.get(`editorlayout${workflowid}`) ?? void 0;
4533
+ }
4534
+ /** Stores the breakpoint step ids of one workflow. */
4535
+ async setworkflowbreakpoints(workflowid, stepids) {
4536
+ return this.adapter.set(`workflowbreakpoints${workflowid}`, stepids);
4537
+ }
4538
+ /** Returns the stored breakpoint step ids of one workflow, oldest first. */
4539
+ async getworkflowbreakpoints(workflowid) {
4540
+ return await this.adapter.get(`workflowbreakpoints${workflowid}`) ?? [];
4541
+ }
4542
+ /** Stores one per site policy override; re-adding the same id replaces its deltas. */
4543
+ async addsiteoverride(override) {
4544
+ const overrides = (await this.listsiteoverrides()).filter((entry) => entry.id !== override.id);
4545
+ await this.adapter.set("siteoverrides", [override, ...overrides]);
4546
+ }
4547
+ /** Returns every stored per site override, newest first, optionally filtered to one workflow. */
4548
+ async listsiteoverrides(workflowid) {
4549
+ const overrides = await this.adapter.get("siteoverrides") ?? [];
4550
+ return workflowid === void 0 ? overrides : overrides.filter((entry) => entry.workflowid === workflowid);
4551
+ }
4552
+ /** Removes one per site override when the user deletes it. */
4553
+ async removesiteoverride(id) {
4554
+ await this.adapter.set("siteoverrides", (await this.listsiteoverrides()).filter((entry) => entry.id !== id));
4555
+ }
4556
+ /** Stores one watchdog event with its recovery outcome; the event history keeps the audit trail of every scan. */
4557
+ async addwatchdogevent(event) {
4558
+ const events = (await this.listwatchdogevents()).filter((entry) => entry.id !== event.id);
4559
+ await this.adapter.set("watchdogevents", [event, ...events]);
4560
+ }
4561
+ /** Returns every stored watchdog event, newest first. */
4562
+ async listwatchdogevents() {
4563
+ return await this.adapter.get("watchdogevents") ?? [];
4564
+ }
4565
+ /** Stores one pending workflow import held for review; approving it later stores the record as runnable. */
4566
+ async addworkflowimport(entry) {
4567
+ const imports = (await this.listworkflowimports()).filter((candidate) => candidate.id !== entry.id);
4568
+ await this.adapter.set("workflowimports", [entry, ...imports]);
4569
+ }
4570
+ /** Returns every pending workflow import, newest first. */
4571
+ async listworkflowimports() {
4572
+ return await this.adapter.get("workflowimports") ?? [];
4573
+ }
4574
+ /** Removes one pending import when the user approves or rejects it. */
4575
+ async removeworkflowimport(id) {
4576
+ await this.adapter.set("workflowimports", (await this.listworkflowimports()).filter((entry) => entry.id !== id));
4577
+ }
4578
+ /** Stores the per workflow background run flags so a workflow keeps running with the panel closed. */
4579
+ async setbackgroundruns(flags) {
4580
+ return this.adapter.set("backgroundruns", flags);
4581
+ }
4582
+ /** Returns the per workflow background run flags. */
4583
+ async getbackgroundruns() {
4584
+ return await this.adapter.get("backgroundruns") ?? {};
4585
+ }
4586
+ /** Removes one stored workflow record version; a rejected import or rollback disappears from the library while every other version survives. */
4587
+ async removeworkflowversion(id, version) {
4588
+ await this.adapter.set("workflowrecords", (await this.getworkflowrecordversions()).filter((entry) => !(entry.id === id && entry.version === version)));
4589
+ }
4437
4590
  };
4438
4591
  function mediakindof(record2) {
4439
4592
  if ("pages" in record2) return "pdf";
@@ -5365,195 +5518,6 @@ function ruleoriginsgranted(rule, workfloworigins) {
5365
5518
  return ruleorigins(rule).every((origin) => granted.has(origin));
5366
5519
  }
5367
5520
 
5368
- // runtimeline.ts
5369
- var timelinekinds = ["watchconsole", "watcherrors", "watchtasks"];
5370
- var loglevels = ["error", "warn", "info", "log", "debug", "trace"];
5371
- var timelinesources = ["console", "error", "rejection", "resource", "longtask", "network", "cdp"];
5372
- function levelrank(level) {
5373
- return loglevels.indexOf(level);
5374
- }
5375
- function redactconsoletext(text2, patterns) {
5376
- let redacted = text2;
5377
- for (const pattern of patterns) {
5378
- if (!pattern) continue;
5379
- while (redacted.includes(pattern)) redacted = redacted.replace(pattern, "[redacted]");
5380
- }
5381
- return redacted;
5382
- }
5383
- function argkind(value) {
5384
- if (value === null) return "null";
5385
- if (Array.isArray(value)) return "array";
5386
- if (value instanceof Error) return "error";
5387
- switch (typeof value) {
5388
- case "string":
5389
- return "string";
5390
- case "number":
5391
- return "number";
5392
- case "boolean":
5393
- return "boolean";
5394
- case "bigint":
5395
- return "bigint";
5396
- case "symbol":
5397
- return "symbol";
5398
- case "function":
5399
- return "function";
5400
- case "undefined":
5401
- return "undefined";
5402
- default:
5403
- return "object";
5404
- }
5405
- }
5406
- function serializearg(value, depth) {
5407
- const render = (item, remaining) => {
5408
- if (item instanceof Error) return `${item.name}: ${item.message}`;
5409
- if (typeof item === "string") return item;
5410
- if (typeof item === "function") return `[function ${item.name || "anonymous"}]`;
5411
- if (typeof item === "bigint") return `${item}n`;
5412
- if (typeof item === "symbol") return item.toString();
5413
- if (item === null || item === void 0 || typeof item !== "object") return String(item);
5414
- if (remaining <= 0) {
5415
- const tag = Array.isArray(item) ? "Array" : item.constructor?.name ?? "Object";
5416
- return `[${tag}]`;
5417
- }
5418
- if (Array.isArray(item)) return `[${item.map((entry) => render(entry, remaining - 1)).join(", ")}]`;
5419
- const record2 = item;
5420
- return `{${Object.keys(record2).map((key) => `${key}: ${render(record2[key], remaining - 1)}`).join(", ")}}`;
5421
- };
5422
- return render(value, Math.max(0, depth));
5423
- }
5424
- function consolecapture(input) {
5425
- const parts = input.args.map((arg) => serializearg(arg, input.depth));
5426
- return { level: input.level, text: redactconsoletext(parts.join(" "), input.redact), argkinds: input.args.map((arg) => argkind(arg)), repeat: 1 };
5427
- }
5428
- function stackframes(stacktext) {
5429
- const frames = [];
5430
- for (const row of stacktext.split("\n")) {
5431
- const trimmed = row.trim();
5432
- if (!trimmed.startsWith("at ")) continue;
5433
- const body = trimmed.slice(3).trim();
5434
- const location = body.match(/\(([^()]*:\d+:\d+)\)$/) ?? body.match(/^(.*:\d+:\d+)$/);
5435
- const located = location?.[1];
5436
- if (!located) continue;
5437
- const segments = located.split(":");
5438
- const column = Number.parseInt(segments.pop() ?? "", 10);
5439
- const lineno = Number.parseInt(segments.pop() ?? "", 10);
5440
- const url = segments.join(":");
5441
- if (!Number.isFinite(lineno) || lineno < 0) continue;
5442
- const name = body.endsWith(`(${located})`) ? body.slice(0, body.length - located.length - 2).trim() : "";
5443
- frames.push({ ...name ? { functionname: name } : {}, url, line: lineno, ...Number.isFinite(column) ? { column } : {} });
5444
- }
5445
- return frames;
5446
- }
5447
- function errorcapture(input) {
5448
- return { message: redactconsoletext(input.message, input.redact), frames: input.stacktext !== void 0 ? stackframes(input.stacktext) : [], sourceurl: input.sourceurl, line: input.line };
5449
- }
5450
- function rejectioncapture(input) {
5451
- return { reason: redactconsoletext(input.reason, input.redact), frames: input.stacktext !== void 0 ? stackframes(input.stacktext) : [] };
5452
- }
5453
- function longtaskcapture(input) {
5454
- return input.entries.filter((entry) => entry.duration >= input.threshold).map((entry) => ({ duration: Math.round(entry.duration), starttime: Math.round(entry.starttime), attributions: [...entry.attributions] }));
5455
- }
5456
- function attachtimeline(input) {
5457
- return { runid: input.runid, origin: input.origin, stepids: [...input.stepids], attachedat: input.now, entries: [] };
5458
- }
5459
- function filterentries(entries, levelset) {
5460
- return entries.filter((entry) => {
5461
- const floor = levelset.floors?.[entry.stepid] ?? levelset.floors?.["*"];
5462
- if (floor !== void 0 && levelrank(entry.level) > levelrank(floor)) return false;
5463
- if (levelset.sources !== void 0 && levelset.sources.length > 0 && !levelset.sources.includes(entry.source)) return false;
5464
- return true;
5465
- });
5466
- }
5467
- function spamdetect(entries, rule) {
5468
- const collapsed = [];
5469
- const counts = /* @__PURE__ */ new Map();
5470
- for (const entry of entries) {
5471
- if (rule.pattern !== "" && !entry.message.includes(rule.pattern)) {
5472
- collapsed.push({ ...entry, repeat: 1 });
5473
- continue;
5474
- }
5475
- const key = `${entry.level}|${entry.source}|${entry.message}`;
5476
- const previous = collapsed[collapsed.length - 1];
5477
- if (previous && previous.repeat !== void 0 && `${previous.level}|${previous.source}|${previous.message}` === key && entry.time - previous.time <= rule.windowsize) {
5478
- previous.repeat += 1;
5479
- continue;
5480
- }
5481
- collapsed.push({ ...entry, repeat: 1 });
5482
- }
5483
- for (const entry of collapsed) {
5484
- if (entry.repeat > 1) counts.set(`${entry.level}|${entry.source}|${entry.message}`, entry.repeat);
5485
- }
5486
- const flagged = [...counts.entries()].filter(([, count]) => count > rule.collapse).map(([key, count]) => ({ message: key.split("|").slice(2).join("|"), count }));
5487
- return { entries: collapsed, flagged };
5488
- }
5489
- function rotatelogs(entries, rule) {
5490
- if (entries.length <= rule.maxentries) return { kept: [...entries], overflow: [] };
5491
- const kept = entries.slice(entries.length - rule.maxentries);
5492
- const overflow = entries.slice(0, entries.length - rule.maxentries);
5493
- return { kept, overflow };
5494
- }
5495
- function timelinecounts(entries) {
5496
- const counts = {};
5497
- for (const level of loglevels) counts[level] = 0;
5498
- for (const entry of entries) counts[entry.level] = (counts[entry.level] ?? 0) + 1;
5499
- return counts;
5500
- }
5501
- function blockingduration(tasks, stepid, window) {
5502
- const inside = tasks.filter((task) => task.starttime >= window.startedat && task.starttime <= window.endedat);
5503
- return { stepid, blocking: inside.reduce((total, task) => total + task.duration, 0), tasks: inside.length };
5504
- }
5505
- function netfailureentryof(input) {
5506
- const exchange = input.exchange;
5507
- if (exchange.errorclass === void 0 && exchange.status < 400) return null;
5508
- return { id: input.id, runid: exchange.runid, stepid: exchange.stepid, url: exchange.url, status: exchange.status, errorclass: exchange.errorclass ?? "httperror", correlationid: exchange.correlationid, at: input.at };
5509
- }
5510
- function watcherdetached(input) {
5511
- for (const navigation of input.navigations) {
5512
- if (navigation >= input.startedat && navigation <= input.startedat + input.lifetime) return { detached: true, at: navigation };
5513
- }
5514
- return { detached: false };
5515
- }
5516
- function consolediff(input) {
5517
- const base = input.baselines;
5518
- const target = input.targetlines;
5519
- const basemap = /* @__PURE__ */ new Map();
5520
- for (const line of base) basemap.set(line, (basemap.get(line) ?? 0) + 1);
5521
- const targetmap = /* @__PURE__ */ new Map();
5522
- for (const line of target) targetmap.set(line, (targetmap.get(line) ?? 0) + 1);
5523
- const lines = [];
5524
- const added = [];
5525
- const removed = [];
5526
- const repeated = [];
5527
- for (const [line, count] of targetmap) {
5528
- const basecount = basemap.get(line) ?? 0;
5529
- if (basecount === 0) {
5530
- for (let index = 0; index < count; index += 1) {
5531
- lines.push({ kind: "added", text: line });
5532
- added.push(line);
5533
- }
5534
- continue;
5535
- }
5536
- const share = Math.min(basecount, count);
5537
- for (let index = 0; index < share; index += 1) {
5538
- lines.push({ kind: "repeated", text: line, count: share });
5539
- repeated.push(line);
5540
- }
5541
- for (let index = share; index < count; index += 1) {
5542
- lines.push({ kind: "added", text: line });
5543
- added.push(line);
5544
- }
5545
- }
5546
- for (const [line, count] of basemap) {
5547
- const targetcount = targetmap.get(line) ?? 0;
5548
- const missing = Math.max(0, count - targetcount);
5549
- for (let index = 0; index < missing; index += 1) {
5550
- lines.push({ kind: "removed", text: line });
5551
- removed.push(line);
5552
- }
5553
- }
5554
- return { base: input.baseid, target: input.targetid, lines, added: added.length, removed: removed.length, repeated: repeated.length, at: input.now };
5555
- }
5556
-
5557
5521
  // socketbus.ts
5558
5522
  var socketkinds = ["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"];
5559
5523
  function channelorigin(url) {
@@ -5774,52 +5738,241 @@ function polldecision(input) {
5774
5738
  return { continue: true, reason: "The long poll loop continues.", ...value !== void 0 ? { cursor: value } : {}, next: { ...next, wait: input.cursor.interval } };
5775
5739
  }
5776
5740
 
5777
- // policy.ts
5778
- var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract", "batchdownload", "pausedownload", "resumedownload", "interceptmime", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "cleanupartifacts", "recordscreen", "captureaudio", "downloadimages", "callrest", "callgraphql", "sendmessage", "blockrequest", "mockresponse", "rewriteheaders", "setcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles", "attachcdp", "detachcdp", "cdpcmd", "overridescript", "heapshot", "profilecpu", "capturesourcemaps", "emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "restoresession", "exportsessions", "importsessions", "runworkflow", "visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"]);
5779
- var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction", "capturebodies", "setbreakpoint", "stepcode", "watchexpr", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"]);
5780
- var readactions = /* @__PURE__ */ new Set(["observe", "inspect", "extract", "wait", "waitfor", "waittext", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "readlinks", "readimages", "readmeta", "readforms", "readstorage", "highlight", "tablist", "windowlist", "tabsnapshot", "mapclicks", "verifyvisible", "verifyenabled", "resolvexpath", "a11ytree", "readvisible", "readertree", "detectlists", "detecttables", "readjson", "watchmutate", "waitquiet", "watchbanner", "detectinfinitescroll", "detectvirtual", "detectlazy", "readscrollpos", "readlang", "readoutline", "countpages", "listshadow", "listframes", "classifypage", "fingerprintsection", "diffsnapshots", "readselection", "watchfocus", "detectsticky", "detectscrolllock", "readopengraph", "detectlanguage", "deriveselector", "waitload", "waiturl", "spawait", "detecthttp", "readredirects", "readfinalurl", "trailaudit", "navintent", "checksafe", "querytabs", "watchtab", "findclones", "searchtabs", "listaudio", "snapshotsession", "savelayout", "attachmeta", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "readerrors", "skiphoneypot", "detectlogin", "detecttemplate", "handoffcaptcha", "scrapetable", "importcsv", "looprows", "transformvalues", "deduperows", "mergepages", "stamplerows", "previewgrid", "logprovenance", "verifydownload", "exportnetlog", "namecaptures", "shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet", "capturepdf", "captureframe", "readmedia", "readassets", "probestream", "timelapse", "shotcanvas", "convertimage", "makethumbs", "fetchurl", "parsejson", "parsehtml", "opensocket", "waitmessage", "watchrequests", "readheaders", "mapapi", "subscribesse", "longpoll", "extractapi", "readcookies", "watchconsole", "watcherrors", "watchtasks", "watchcdp", "measureflow", "trackmemory", "watchshifts", "traceload", "annotatetrace", "replaytrace", "blackboxscripts", "persiststate", "capturesession", "namedsessions", "diffsessions", "searchsessions", "composeworkflow", "savetemplate", "dryrun", "delay", "waitelement", "compute", "extractvars", "condition", "branch"]);
5781
- var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
5782
- var watchactions = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "watchtab"]);
5783
- var targetactions = /* @__PURE__ */ new Set(["inspect", "focus", "click", "type", "scroll", "select", "hover", "clickdeep", "rightclick", "doubleclick", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "highlight", "setattribute", "removeattribute", "waitfor", "shiftclick", "typetime", "appendtext", "setvalue", "typeedit", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "expanddetails", "verifyvisible", "verifyenabled", "pierceshadow", "deriveselector", "fingerprintsection", "submitform", "retryform", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcode", "consentpassword", "scrapetable", "paginateextract", "shotelement", "captureframe", "shotcanvas"]);
5784
- var valueactions = /* @__PURE__ */ new Set(["presskey", "drag", "drop", "upload", "readattribute", "removeattribute", "waittext", "evaluate", "zoomset", "tabactivate", "tabclose", "tabreload", "windowclose", "windowresize", "tabcreate", "windowcreate", "downloadfile", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "chooseradio", "setslider", "setdate", "setcolor", "followlink", "setfragment", "handleauth", "navintent", "openclipboard", "checksafe", "reopentab", "spanav", "duplicatetab", "pintab", "mutetab", "movetab", "movetabwindow", "searchtabs", "badgetab", "attachmeta", "focuswindow", "maximizewindow", "minimizewindow", "restorewindow", "incognitowindow", "asksubmit", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcode", "consentpassword", "pausedownload", "resumedownload", "verifydownload", "writeclipboard", "quarantinedownload", "scanvirus"]);
5785
- var tabscommandactions = /* @__PURE__ */ new Set(["querytabs", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "watchtab", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "savelayout", "restorelayout", "findclones", "searchtabs", "badgetab", "attachmeta", "listaudio", "reopenrun", "snapshotsession"]);
5786
- var formactions = /* @__PURE__ */ new Set(["fillform", "filllabel", "fillplaceholder", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "submitform", "readerrors", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "handoffcaptcha", "fillcard", "fillcode", "consentpassword", "skiphoneypot", "detectlogin", "detecttemplate"]);
5787
- var datasetactions = /* @__PURE__ */ new Set(["scrapetable", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "importcsv", "looprows", "transformvalues", "deduperows", "paginateextract", "mergepages", "stamplerows", "previewgrid", "streamdisk", "resumeextract", "logprovenance"]);
5788
- var exportactions = /* @__PURE__ */ new Set(["exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk"]);
5789
- var filesactions = /* @__PURE__ */ new Set(["batchdownload", "pausedownload", "resumedownload", "verifydownload", "interceptmime", "exportnetlog", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "namecaptures", "cleanupartifacts"]);
5790
- var captureactions = /* @__PURE__ */ new Set(["shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet"]);
5791
- var mediaactions = /* @__PURE__ */ new Set(["capturepdf", "recordscreen", "captureaudio", "captureframe", "downloadimages", "shotcanvas", "probestream", "readmedia", "readassets", "timelapse", "convertimage", "makethumbs"]);
5792
- var httpactions = /* @__PURE__ */ new Set(["fetchurl", "parsejson", "parsehtml", "callrest", "callgraphql"]);
5793
- var socketactions = /* @__PURE__ */ new Set(["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"]);
5794
- var netwatchactions = /* @__PURE__ */ new Set(["watchrequests", "readheaders", "capturebodies", "mapapi", "extractapi"]);
5795
- var controlactions = /* @__PURE__ */ new Set(["blockrequest", "mockresponse", "rewriteheaders", "setcookies", "readcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles"]);
5796
- var debugactions = /* @__PURE__ */ new Set(["watchconsole", "watcherrors", "watchtasks"]);
5797
- var cdpactions = /* @__PURE__ */ new Set(["attachcdp", "detachcdp", "cdpcmd", "watchcdp", "setbreakpoint", "stepcode", "watchexpr", "overridescript"]);
5798
- var profileractions = /* @__PURE__ */ new Set(["measureflow", "heapshot", "trackmemory", "profilecpu", "watchshifts", "traceload", "annotatetrace", "replaytrace", "capturesourcemaps"]);
5799
- var emulationactions = /* @__PURE__ */ new Set(["emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "blackboxscripts"]);
5800
- var sessionactions = /* @__PURE__ */ new Set(["persiststate", "capturesession", "restoresession", "namedsessions", "diffsessions", "searchsessions", "exportsessions", "importsessions"]);
5801
- var workflowactions = /* @__PURE__ */ new Set(["composeworkflow", "savetemplate", "runworkflow", "dryrun", "delay", "waitelement", "compute", "extractvars", "condition", "branch", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"]);
5802
- var triggeractions = /* @__PURE__ */ new Set(["visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"]);
5803
- var credentialheaders = /* @__PURE__ */ new Set(["authorization", "proxy-authorization", "cookie", "cookie2", "set-cookie", "api-key", "x-api-key", "x-auth-token", "x-session-token", "proxy-authorization"]);
5804
- var fieldkinds = ["text", "email", "phone", "date", "number", "select", "check", "radio", "file", "password", "card", "code"];
5805
- var layoutmutationactions = /* @__PURE__ */ new Set(["grouptabs", "colorgroup", "collapsegroup", "savelayout", "restorelayout"]);
5806
- var groupcolors = ["grey", "blue", "red", "yellow", "green", "pink", "purple", "cyan", "orange"];
5807
- function normalizeendpoint(value) {
5808
- const endpoint = new URL(value.trim());
5809
- if (endpoint.protocol !== "https:") throw new Error("Devthink accepts HTTPS endpoints only.");
5810
- if (endpoint.username || endpoint.password) throw new Error("Endpoint credentials are not allowed in the URL.");
5811
- return { endpoint: endpoint.toString(), origin: endpoint.origin, configuredat: Date.now() };
5812
- }
5813
- function hostpattern(origin) {
5814
- const parsed = new URL(origin);
5815
- if (parsed.protocol !== "https:") throw new Error("Only HTTPS origins can be granted.");
5816
- return `${parsed.origin}/*`;
5817
- }
5818
- function issessionkind(kind) {
5819
- return sessionactions.has(kind);
5741
+ // runtimeline.ts
5742
+ var timelinekinds = ["watchconsole", "watcherrors", "watchtasks"];
5743
+ var loglevels = ["error", "warn", "info", "log", "debug", "trace"];
5744
+ var timelinesources = ["console", "error", "rejection", "resource", "longtask", "network", "cdp"];
5745
+ function levelrank(level) {
5746
+ return loglevels.indexOf(level);
5820
5747
  }
5821
- function isworkflowkind(kind) {
5822
- return workflowactions.has(kind);
5748
+ function redactconsoletext(text2, patterns) {
5749
+ let redacted = text2;
5750
+ for (const pattern of patterns) {
5751
+ if (!pattern) continue;
5752
+ while (redacted.includes(pattern)) redacted = redacted.replace(pattern, "[redacted]");
5753
+ }
5754
+ return redacted;
5755
+ }
5756
+ function argkind(value) {
5757
+ if (value === null) return "null";
5758
+ if (Array.isArray(value)) return "array";
5759
+ if (value instanceof Error) return "error";
5760
+ switch (typeof value) {
5761
+ case "string":
5762
+ return "string";
5763
+ case "number":
5764
+ return "number";
5765
+ case "boolean":
5766
+ return "boolean";
5767
+ case "bigint":
5768
+ return "bigint";
5769
+ case "symbol":
5770
+ return "symbol";
5771
+ case "function":
5772
+ return "function";
5773
+ case "undefined":
5774
+ return "undefined";
5775
+ default:
5776
+ return "object";
5777
+ }
5778
+ }
5779
+ function serializearg(value, depth) {
5780
+ const render = (item, remaining) => {
5781
+ if (item instanceof Error) return `${item.name}: ${item.message}`;
5782
+ if (typeof item === "string") return item;
5783
+ if (typeof item === "function") return `[function ${item.name || "anonymous"}]`;
5784
+ if (typeof item === "bigint") return `${item}n`;
5785
+ if (typeof item === "symbol") return item.toString();
5786
+ if (item === null || item === void 0 || typeof item !== "object") return String(item);
5787
+ if (remaining <= 0) {
5788
+ const tag = Array.isArray(item) ? "Array" : item.constructor?.name ?? "Object";
5789
+ return `[${tag}]`;
5790
+ }
5791
+ if (Array.isArray(item)) return `[${item.map((entry) => render(entry, remaining - 1)).join(", ")}]`;
5792
+ const record2 = item;
5793
+ return `{${Object.keys(record2).map((key) => `${key}: ${render(record2[key], remaining - 1)}`).join(", ")}}`;
5794
+ };
5795
+ return render(value, Math.max(0, depth));
5796
+ }
5797
+ function consolecapture(input) {
5798
+ const parts = input.args.map((arg) => serializearg(arg, input.depth));
5799
+ return { level: input.level, text: redactconsoletext(parts.join(" "), input.redact), argkinds: input.args.map((arg) => argkind(arg)), repeat: 1 };
5800
+ }
5801
+ function stackframes(stacktext) {
5802
+ const frames = [];
5803
+ for (const row of stacktext.split("\n")) {
5804
+ const trimmed = row.trim();
5805
+ if (!trimmed.startsWith("at ")) continue;
5806
+ const body = trimmed.slice(3).trim();
5807
+ const location = body.match(/\(([^()]*:\d+:\d+)\)$/) ?? body.match(/^(.*:\d+:\d+)$/);
5808
+ const located = location?.[1];
5809
+ if (!located) continue;
5810
+ const segments = located.split(":");
5811
+ const column = Number.parseInt(segments.pop() ?? "", 10);
5812
+ const lineno = Number.parseInt(segments.pop() ?? "", 10);
5813
+ const url = segments.join(":");
5814
+ if (!Number.isFinite(lineno) || lineno < 0) continue;
5815
+ const name = body.endsWith(`(${located})`) ? body.slice(0, body.length - located.length - 2).trim() : "";
5816
+ frames.push({ ...name ? { functionname: name } : {}, url, line: lineno, ...Number.isFinite(column) ? { column } : {} });
5817
+ }
5818
+ return frames;
5819
+ }
5820
+ function errorcapture(input) {
5821
+ return { message: redactconsoletext(input.message, input.redact), frames: input.stacktext !== void 0 ? stackframes(input.stacktext) : [], sourceurl: input.sourceurl, line: input.line };
5822
+ }
5823
+ function rejectioncapture(input) {
5824
+ return { reason: redactconsoletext(input.reason, input.redact), frames: input.stacktext !== void 0 ? stackframes(input.stacktext) : [] };
5825
+ }
5826
+ function longtaskcapture(input) {
5827
+ return input.entries.filter((entry) => entry.duration >= input.threshold).map((entry) => ({ duration: Math.round(entry.duration), starttime: Math.round(entry.starttime), attributions: [...entry.attributions] }));
5828
+ }
5829
+ function attachtimeline(input) {
5830
+ return { runid: input.runid, origin: input.origin, stepids: [...input.stepids], attachedat: input.now, entries: [] };
5831
+ }
5832
+ function filterentries(entries, levelset) {
5833
+ return entries.filter((entry) => {
5834
+ const floor = levelset.floors?.[entry.stepid] ?? levelset.floors?.["*"];
5835
+ if (floor !== void 0 && levelrank(entry.level) > levelrank(floor)) return false;
5836
+ if (levelset.sources !== void 0 && levelset.sources.length > 0 && !levelset.sources.includes(entry.source)) return false;
5837
+ return true;
5838
+ });
5839
+ }
5840
+ function spamdetect(entries, rule) {
5841
+ const collapsed = [];
5842
+ const counts = /* @__PURE__ */ new Map();
5843
+ for (const entry of entries) {
5844
+ if (rule.pattern !== "" && !entry.message.includes(rule.pattern)) {
5845
+ collapsed.push({ ...entry, repeat: 1 });
5846
+ continue;
5847
+ }
5848
+ const key = `${entry.level}|${entry.source}|${entry.message}`;
5849
+ const previous = collapsed[collapsed.length - 1];
5850
+ if (previous && previous.repeat !== void 0 && `${previous.level}|${previous.source}|${previous.message}` === key && entry.time - previous.time <= rule.windowsize) {
5851
+ previous.repeat += 1;
5852
+ continue;
5853
+ }
5854
+ collapsed.push({ ...entry, repeat: 1 });
5855
+ }
5856
+ for (const entry of collapsed) {
5857
+ if (entry.repeat > 1) counts.set(`${entry.level}|${entry.source}|${entry.message}`, entry.repeat);
5858
+ }
5859
+ const flagged = [...counts.entries()].filter(([, count]) => count > rule.collapse).map(([key, count]) => ({ message: key.split("|").slice(2).join("|"), count }));
5860
+ return { entries: collapsed, flagged };
5861
+ }
5862
+ function rotatelogs(entries, rule) {
5863
+ if (entries.length <= rule.maxentries) return { kept: [...entries], overflow: [] };
5864
+ const kept = entries.slice(entries.length - rule.maxentries);
5865
+ const overflow = entries.slice(0, entries.length - rule.maxentries);
5866
+ return { kept, overflow };
5867
+ }
5868
+ function timelinecounts(entries) {
5869
+ const counts = {};
5870
+ for (const level of loglevels) counts[level] = 0;
5871
+ for (const entry of entries) counts[entry.level] = (counts[entry.level] ?? 0) + 1;
5872
+ return counts;
5873
+ }
5874
+ function blockingduration(tasks, stepid, window) {
5875
+ const inside = tasks.filter((task) => task.starttime >= window.startedat && task.starttime <= window.endedat);
5876
+ return { stepid, blocking: inside.reduce((total, task) => total + task.duration, 0), tasks: inside.length };
5877
+ }
5878
+ function netfailureentryof(input) {
5879
+ const exchange = input.exchange;
5880
+ if (exchange.errorclass === void 0 && exchange.status < 400) return null;
5881
+ return { id: input.id, runid: exchange.runid, stepid: exchange.stepid, url: exchange.url, status: exchange.status, errorclass: exchange.errorclass ?? "httperror", correlationid: exchange.correlationid, at: input.at };
5882
+ }
5883
+ function watcherdetached(input) {
5884
+ for (const navigation of input.navigations) {
5885
+ if (navigation >= input.startedat && navigation <= input.startedat + input.lifetime) return { detached: true, at: navigation };
5886
+ }
5887
+ return { detached: false };
5888
+ }
5889
+ function consolediff(input) {
5890
+ const base = input.baselines;
5891
+ const target = input.targetlines;
5892
+ const basemap = /* @__PURE__ */ new Map();
5893
+ for (const line of base) basemap.set(line, (basemap.get(line) ?? 0) + 1);
5894
+ const targetmap = /* @__PURE__ */ new Map();
5895
+ for (const line of target) targetmap.set(line, (targetmap.get(line) ?? 0) + 1);
5896
+ const lines = [];
5897
+ const added = [];
5898
+ const removed = [];
5899
+ const repeated = [];
5900
+ for (const [line, count] of targetmap) {
5901
+ const basecount = basemap.get(line) ?? 0;
5902
+ if (basecount === 0) {
5903
+ for (let index = 0; index < count; index += 1) {
5904
+ lines.push({ kind: "added", text: line });
5905
+ added.push(line);
5906
+ }
5907
+ continue;
5908
+ }
5909
+ const share = Math.min(basecount, count);
5910
+ for (let index = 0; index < share; index += 1) {
5911
+ lines.push({ kind: "repeated", text: line, count: share });
5912
+ repeated.push(line);
5913
+ }
5914
+ for (let index = share; index < count; index += 1) {
5915
+ lines.push({ kind: "added", text: line });
5916
+ added.push(line);
5917
+ }
5918
+ }
5919
+ for (const [line, count] of basemap) {
5920
+ const targetcount = targetmap.get(line) ?? 0;
5921
+ const missing = Math.max(0, count - targetcount);
5922
+ for (let index = 0; index < missing; index += 1) {
5923
+ lines.push({ kind: "removed", text: line });
5924
+ removed.push(line);
5925
+ }
5926
+ }
5927
+ return { base: input.baseid, target: input.targetid, lines, added: added.length, removed: removed.length, repeated: repeated.length, at: input.now };
5928
+ }
5929
+
5930
+ // policy.ts
5931
+ var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract", "batchdownload", "pausedownload", "resumedownload", "interceptmime", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "cleanupartifacts", "recordscreen", "captureaudio", "downloadimages", "callrest", "callgraphql", "sendmessage", "blockrequest", "mockresponse", "rewriteheaders", "setcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles", "attachcdp", "detachcdp", "cdpcmd", "overridescript", "heapshot", "profilecpu", "capturesourcemaps", "emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "restoresession", "exportsessions", "importsessions", "runworkflow", "visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"]);
5932
+ var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction", "capturebodies", "setbreakpoint", "stepcode", "watchexpr", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"]);
5933
+ var readactions = /* @__PURE__ */ new Set(["observe", "inspect", "extract", "wait", "waitfor", "waittext", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "readlinks", "readimages", "readmeta", "readforms", "readstorage", "highlight", "tablist", "windowlist", "tabsnapshot", "mapclicks", "verifyvisible", "verifyenabled", "resolvexpath", "a11ytree", "readvisible", "readertree", "detectlists", "detecttables", "readjson", "watchmutate", "waitquiet", "watchbanner", "detectinfinitescroll", "detectvirtual", "detectlazy", "readscrollpos", "readlang", "readoutline", "countpages", "listshadow", "listframes", "classifypage", "fingerprintsection", "diffsnapshots", "readselection", "watchfocus", "detectsticky", "detectscrolllock", "readopengraph", "detectlanguage", "deriveselector", "waitload", "waiturl", "spawait", "detecthttp", "readredirects", "readfinalurl", "trailaudit", "navintent", "checksafe", "querytabs", "watchtab", "findclones", "searchtabs", "listaudio", "snapshotsession", "savelayout", "attachmeta", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "readerrors", "skiphoneypot", "detectlogin", "detecttemplate", "handoffcaptcha", "scrapetable", "importcsv", "looprows", "transformvalues", "deduperows", "mergepages", "stamplerows", "previewgrid", "logprovenance", "verifydownload", "exportnetlog", "namecaptures", "shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet", "capturepdf", "captureframe", "readmedia", "readassets", "probestream", "timelapse", "shotcanvas", "convertimage", "makethumbs", "fetchurl", "parsejson", "parsehtml", "opensocket", "waitmessage", "watchrequests", "readheaders", "mapapi", "subscribesse", "longpoll", "extractapi", "readcookies", "watchconsole", "watcherrors", "watchtasks", "watchcdp", "measureflow", "trackmemory", "watchshifts", "traceload", "annotatetrace", "replaytrace", "blackboxscripts", "persiststate", "capturesession", "namedsessions", "diffsessions", "searchsessions", "composeworkflow", "savetemplate", "dryrun", "delay", "waitelement", "compute", "extractvars", "condition", "branch"]);
5934
+ var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
5935
+ var watchactions = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "watchtab"]);
5936
+ var targetactions = /* @__PURE__ */ new Set(["inspect", "focus", "click", "type", "scroll", "select", "hover", "clickdeep", "rightclick", "doubleclick", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "highlight", "setattribute", "removeattribute", "waitfor", "shiftclick", "typetime", "appendtext", "setvalue", "typeedit", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "expanddetails", "verifyvisible", "verifyenabled", "pierceshadow", "deriveselector", "fingerprintsection", "submitform", "retryform", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcode", "consentpassword", "scrapetable", "paginateextract", "shotelement", "captureframe", "shotcanvas"]);
5937
+ var valueactions = /* @__PURE__ */ new Set(["presskey", "drag", "drop", "upload", "readattribute", "removeattribute", "waittext", "evaluate", "zoomset", "tabactivate", "tabclose", "tabreload", "windowclose", "windowresize", "tabcreate", "windowcreate", "downloadfile", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "chooseradio", "setslider", "setdate", "setcolor", "followlink", "setfragment", "handleauth", "navintent", "openclipboard", "checksafe", "reopentab", "spanav", "duplicatetab", "pintab", "mutetab", "movetab", "movetabwindow", "searchtabs", "badgetab", "attachmeta", "focuswindow", "maximizewindow", "minimizewindow", "restorewindow", "incognitowindow", "asksubmit", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcode", "consentpassword", "pausedownload", "resumedownload", "verifydownload", "writeclipboard", "quarantinedownload", "scanvirus"]);
5938
+ var tabscommandactions = /* @__PURE__ */ new Set(["querytabs", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "watchtab", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "savelayout", "restorelayout", "findclones", "searchtabs", "badgetab", "attachmeta", "listaudio", "reopenrun", "snapshotsession"]);
5939
+ var formactions = /* @__PURE__ */ new Set(["fillform", "filllabel", "fillplaceholder", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "submitform", "readerrors", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "handoffcaptcha", "fillcard", "fillcode", "consentpassword", "skiphoneypot", "detectlogin", "detecttemplate"]);
5940
+ var datasetactions = /* @__PURE__ */ new Set(["scrapetable", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "importcsv", "looprows", "transformvalues", "deduperows", "paginateextract", "mergepages", "stamplerows", "previewgrid", "streamdisk", "resumeextract", "logprovenance"]);
5941
+ var exportactions = /* @__PURE__ */ new Set(["exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk"]);
5942
+ var filesactions = /* @__PURE__ */ new Set(["batchdownload", "pausedownload", "resumedownload", "verifydownload", "interceptmime", "exportnetlog", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "namecaptures", "cleanupartifacts"]);
5943
+ var captureactions = /* @__PURE__ */ new Set(["shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet"]);
5944
+ var mediaactions = /* @__PURE__ */ new Set(["capturepdf", "recordscreen", "captureaudio", "captureframe", "downloadimages", "shotcanvas", "probestream", "readmedia", "readassets", "timelapse", "convertimage", "makethumbs"]);
5945
+ var httpactions = /* @__PURE__ */ new Set(["fetchurl", "parsejson", "parsehtml", "callrest", "callgraphql"]);
5946
+ var socketactions = /* @__PURE__ */ new Set(["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"]);
5947
+ var netwatchactions = /* @__PURE__ */ new Set(["watchrequests", "readheaders", "capturebodies", "mapapi", "extractapi"]);
5948
+ var controlactions = /* @__PURE__ */ new Set(["blockrequest", "mockresponse", "rewriteheaders", "setcookies", "readcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles"]);
5949
+ var debugactions = /* @__PURE__ */ new Set(["watchconsole", "watcherrors", "watchtasks"]);
5950
+ var cdpactions = /* @__PURE__ */ new Set(["attachcdp", "detachcdp", "cdpcmd", "watchcdp", "setbreakpoint", "stepcode", "watchexpr", "overridescript"]);
5951
+ var profileractions = /* @__PURE__ */ new Set(["measureflow", "heapshot", "trackmemory", "profilecpu", "watchshifts", "traceload", "annotatetrace", "replaytrace", "capturesourcemaps"]);
5952
+ var emulationactions = /* @__PURE__ */ new Set(["emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "blackboxscripts"]);
5953
+ var sessionactions = /* @__PURE__ */ new Set(["persiststate", "capturesession", "restoresession", "namedsessions", "diffsessions", "searchsessions", "exportsessions", "importsessions"]);
5954
+ var workflowactions = /* @__PURE__ */ new Set(["composeworkflow", "savetemplate", "runworkflow", "dryrun", "delay", "waitelement", "compute", "extractvars", "condition", "branch", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"]);
5955
+ var triggeractions = /* @__PURE__ */ new Set(["visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"]);
5956
+ var credentialheaders = /* @__PURE__ */ new Set(["authorization", "proxy-authorization", "cookie", "cookie2", "set-cookie", "api-key", "x-api-key", "x-auth-token", "x-session-token", "proxy-authorization"]);
5957
+ var fieldkinds = ["text", "email", "phone", "date", "number", "select", "check", "radio", "file", "password", "card", "code"];
5958
+ var layoutmutationactions = /* @__PURE__ */ new Set(["grouptabs", "colorgroup", "collapsegroup", "savelayout", "restorelayout"]);
5959
+ var groupcolors = ["grey", "blue", "red", "yellow", "green", "pink", "purple", "cyan", "orange"];
5960
+ function normalizeendpoint(value) {
5961
+ const endpoint = new URL(value.trim());
5962
+ if (endpoint.protocol !== "https:") throw new Error("Devthink accepts HTTPS endpoints only.");
5963
+ if (endpoint.username || endpoint.password) throw new Error("Endpoint credentials are not allowed in the URL.");
5964
+ return { endpoint: endpoint.toString(), origin: endpoint.origin, configuredat: Date.now() };
5965
+ }
5966
+ function hostpattern(origin) {
5967
+ const parsed = new URL(origin);
5968
+ if (parsed.protocol !== "https:") throw new Error("Only HTTPS origins can be granted.");
5969
+ return `${parsed.origin}/*`;
5970
+ }
5971
+ function issessionkind(kind) {
5972
+ return sessionactions.has(kind);
5973
+ }
5974
+ function isworkflowkind(kind) {
5975
+ return workflowactions.has(kind);
5823
5976
  }
5824
5977
  function istriggeraction(kind) {
5825
5978
  return triggeractions.has(kind);
@@ -8450,9 +8603,137 @@ function canexecute(input) {
8450
8603
  }
8451
8604
  return validatestep(input.step, input.origin);
8452
8605
  }
8606
+ function reviewedkinds() {
8607
+ return [...allowedactions].sort();
8608
+ }
8609
+ function editorsavegate(input) {
8610
+ const gate = sessiongate({ session: input.session, tabid: input.session?.tabid ?? 0, origin: input.session?.origin ?? "https://example.com", now: input.now, action: "save the workflow editor canvas" });
8611
+ if (!gate.allowed) return gate;
8612
+ if (!input.plan || input.plan.state !== "approved") return { allowed: false, reason: "Editor saves need the approved plan review before a new workflow version composes." };
8613
+ const model = input.model;
8614
+ if (typeof model.name !== "string" || !model.name.trim()) return { allowed: false, reason: "The workflow name of the canvas must be a non-empty string." };
8615
+ if (typeof model.version !== "number" || !Number.isInteger(model.version) || model.version < 1) return { allowed: false, reason: "The workflow version of the canvas must be a positive integer." };
8616
+ if (!Array.isArray(model.origins) || model.origins.length === 0) return { allowed: false, reason: "The canvas needs at least one granted HTTPS origin." };
8617
+ const ids = /* @__PURE__ */ new Set();
8618
+ for (const node of model.nodes) {
8619
+ if (node.step === void 0 === (node.invocation === void 0)) return { allowed: false, reason: "Every canvas node must be exactly one workflow step or one block invocation." };
8620
+ const id = node.id ?? (node.step !== void 0 ? node.step.id : node.invocation.block);
8621
+ if (!id || ids.has(id)) return { allowed: false, reason: `The canvas node id ${id || "(empty)"} must be unique.` };
8622
+ ids.add(id);
8623
+ }
8624
+ const reachable = /* @__PURE__ */ new Set();
8625
+ for (const node of model.nodes) {
8626
+ if (node.step !== void 0) {
8627
+ reachable.add(node.step.id);
8628
+ continue;
8629
+ }
8630
+ const walk = (entries) => {
8631
+ for (const entry of entries) {
8632
+ if (typeof entry.id === "string" && typeof entry.kind === "string") {
8633
+ reachable.add(entry.id);
8634
+ continue;
8635
+ }
8636
+ if (typeof entry.block === "string") {
8637
+ const nested = model.blocks.find((candidate) => candidate.name === entry.block);
8638
+ if (nested) walk(nested.steps);
8639
+ }
8640
+ }
8641
+ };
8642
+ const block = model.blocks.find((candidate) => candidate.name === node.invocation.block);
8643
+ if (!block) return { allowed: false, reason: `The block ${node.invocation.block} of the canvas has no definition.` };
8644
+ walk(block.steps);
8645
+ }
8646
+ let order = 0;
8647
+ const positionof = /* @__PURE__ */ new Map();
8648
+ for (const node of model.nodes) {
8649
+ if (node.step !== void 0) {
8650
+ positionof.set(node.step.id, order);
8651
+ order += 1;
8652
+ continue;
8653
+ }
8654
+ const walk = (entries) => {
8655
+ for (const entry of entries) {
8656
+ if (typeof entry.id === "string" && typeof entry.kind === "string") {
8657
+ positionof.set(entry.id, order);
8658
+ order += 1;
8659
+ continue;
8660
+ }
8661
+ if (typeof entry.block === "string") {
8662
+ const nested = model.blocks.find((candidate) => candidate.name === entry.block);
8663
+ if (nested) walk(nested.steps);
8664
+ }
8665
+ }
8666
+ };
8667
+ walk(model.blocks.find((candidate) => candidate.name === node.invocation.block).steps);
8668
+ }
8669
+ for (const edge of model.edges) {
8670
+ if (!reachable.has(edge.from)) return { allowed: false, reason: `The canvas edge of ${edge.variable} references the unknown source step ${edge.from}.` };
8671
+ if (!reachable.has(edge.to)) return { allowed: false, reason: `The canvas edge of ${edge.variable} references the unknown target step ${edge.to}.` };
8672
+ if ((positionof.get(edge.from) ?? -1) >= (positionof.get(edge.to) ?? -1)) return { allowed: false, reason: `The canvas edge of ${edge.variable} runs backwards and would form a cycle.` };
8673
+ }
8674
+ return { allowed: true };
8675
+ }
8676
+ function runreviewgranted(record2) {
8677
+ if (record2.reviewstate === "pending") return { allowed: false, reason: "The workflow stays unreviewed: the import or rollback review must approve its expanded step list before any run." };
8678
+ return { allowed: true };
8679
+ }
8680
+ var overrideknobs = ["loopbound", "stepms", "runms", "waitms", "delaybase"];
8681
+ function validatesiteoverride(override) {
8682
+ if (typeof override.pattern !== "string" || !override.pattern.startsWith("https://") || !/[a-z0-9.-]+/i.test(override.pattern.slice(8))) return { allowed: false, reason: "The override pattern must be an https origin or a `*` subdomain glob of one." };
8683
+ if (!override.pattern.includes("*")) {
8684
+ try {
8685
+ if (new URL(override.pattern).origin !== override.pattern) return { allowed: false, reason: "The override pattern must be a bare https origin or a `*` subdomain glob, never a path." };
8686
+ } catch {
8687
+ return { allowed: false, reason: "The override pattern must parse as an https origin or a `*` subdomain glob of one." };
8688
+ }
8689
+ }
8690
+ for (const [knob, delta] of Object.entries(override.deltas)) {
8691
+ if (!overrideknobs.includes(knob)) return { allowed: false, reason: `The override knob ${knob} is not one of the reviewed knobs: ${overrideknobs.join(", ")}.` };
8692
+ if (typeof delta !== "number" || !Number.isFinite(delta) || delta <= 0) return { allowed: false, reason: `The override delta of ${knob} must be a positive user value with no code ceiling.` };
8693
+ }
8694
+ return { allowed: true };
8695
+ }
8696
+ function exportcontentreview(file) {
8697
+ const secretkeys = /(secret|token|apikey|api_key|password|authorization|credential)/i;
8698
+ const scan = (label, options) => {
8699
+ if (options === void 0) return void 0;
8700
+ let payload;
8701
+ try {
8702
+ payload = JSON.parse(options);
8703
+ } catch {
8704
+ return void 0;
8705
+ }
8706
+ const walk = (value, path) => {
8707
+ if (!value || typeof value !== "object") return void 0;
8708
+ for (const [key, entry] of Object.entries(value)) {
8709
+ if (secretkeys.test(key)) return { allowed: false, reason: `The export of ${label} carries the secret field ${path}${key} and secrets never leave the browser.` };
8710
+ const nested = walk(entry, `${path}${key}.`);
8711
+ if (nested !== void 0) return nested;
8712
+ }
8713
+ return void 0;
8714
+ };
8715
+ return walk(payload, "");
8716
+ };
8717
+ for (const step of file.workflow.steps) {
8718
+ const refusal = scan(`the step ${step.id}`, step.options);
8719
+ if (refusal !== void 0) return refusal;
8720
+ }
8721
+ for (const template of file.templates) {
8722
+ const refusal = scan(`the template ${template.name}`, template.step.options);
8723
+ if (refusal !== void 0) return refusal;
8724
+ }
8725
+ return { allowed: true };
8726
+ }
8727
+ function watchdogconfigvalid(config) {
8728
+ if (typeof config.enabled !== "boolean") return { allowed: false, reason: "The watchdog enabled flag must be a boolean." };
8729
+ if (typeof config.stallthreshold !== "number" || !Number.isFinite(config.stallthreshold) || config.stallthreshold <= 0) return { allowed: false, reason: "The watchdog stall threshold must be a positive number of milliseconds with no code ceiling." };
8730
+ if (!["retry", "pause", "cancel"].includes(config.action)) return { allowed: false, reason: "The watchdog recovery action must be retry, pause or cancel." };
8731
+ if (config.zombiewindow !== void 0 && (typeof config.zombiewindow !== "number" || !Number.isFinite(config.zombiewindow) || config.zombiewindow <= 0)) return { allowed: false, reason: "The watchdog zombie window, when configured, must be a positive number of milliseconds with no code ceiling." };
8732
+ return { allowed: true };
8733
+ }
8453
8734
 
8454
8735
  // version.ts
8455
- var packageversion = "1.1.52";
8736
+ var packageversion = "1.1.53";
8456
8737
 
8457
8738
  // types.ts
8458
8739
  var protocolversion = packageversion;
@@ -9049,8 +9330,744 @@ function triggerfired(input) {
9049
9330
  function manualrunpreview(input) {
9050
9331
  return { version: protocolversion, manualrun: input.preview, ...input.workflowname !== void 0 ? { workflowname: input.workflowname } : {} };
9051
9332
  }
9333
+ var workflowfileversion = 1;
9334
+ function editorstate(input) {
9335
+ const editor = { versions: input.versions, diffs: input.diffs ?? [], history: input.history, breakpoints: input.breakpoints ?? [], overrides: input.overrides, imports: input.imports, backgroundruns: input.backgroundruns ?? {}, watchdog: { ...input.watchdog.config !== void 0 ? { config: input.watchdog.config } : {}, events: input.watchdog.events } };
9336
+ return { version: protocolversion, editor, ...input.model !== void 0 ? { model: input.model } : {} };
9337
+ }
9338
+ function runhistoryquery(value) {
9339
+ if (value === void 0 || value === null) return {};
9340
+ const candidate = record(value);
9341
+ const query = {};
9342
+ if (candidate.workflowid !== void 0) {
9343
+ if (typeof candidate.workflowid !== "string" || !candidate.workflowid.trim()) throw new Error("The run history workflow filter must be a non-empty string.");
9344
+ query.workflowid = candidate.workflowid;
9345
+ }
9346
+ if (candidate.outcome !== void 0) {
9347
+ if (typeof candidate.outcome !== "string" || !candidate.outcome.trim()) throw new Error("The run history outcome filter must be a non-empty string.");
9348
+ query.outcome = candidate.outcome;
9349
+ }
9350
+ if (candidate.since !== void 0) {
9351
+ if (typeof candidate.since !== "number" || !Number.isFinite(candidate.since)) throw new Error("The run history time floor must be a finite timestamp.");
9352
+ query.since = candidate.since;
9353
+ }
9354
+ if (candidate.limit !== void 0) {
9355
+ if (typeof candidate.limit !== "number" || !Number.isInteger(candidate.limit) || candidate.limit < 1) throw new Error("The run history entry count must be a positive integer with no code ceiling.");
9356
+ query.limit = candidate.limit;
9357
+ }
9358
+ return query;
9359
+ }
9360
+ function runhistoryreport(input) {
9361
+ return { version: protocolversion, entries: input.entries, query: input.query ?? {} };
9362
+ }
9363
+
9364
+ // workfloweditor.ts
9365
+ var palettecategories = ["actions", "controlflow", "waits", "variables", "triggers"];
9366
+ var palettenodes = [
9367
+ { kind: "click", label: "Click an element", category: "actions", description: "Clicks the reviewed selector target." },
9368
+ { kind: "type", label: "Type text", category: "actions", description: "Types the reviewed text into the target field." },
9369
+ { kind: "navigate", label: "Navigate", category: "actions", description: "Navigates the tab to the reviewed url." },
9370
+ { kind: "readtext", label: "Read text", category: "actions", description: "Reads the text of the target element." },
9371
+ { kind: "scrapetable", label: "Scrape a table", category: "actions", description: "Extracts the reviewed table into a dataset." },
9372
+ { kind: "fillform", label: "Fill a form", category: "actions", description: "Fills the reviewed form fields from a saved profile." },
9373
+ { kind: "querytabs", label: "Query tabs", category: "actions", description: "Lists the tabs matching the reviewed query." },
9374
+ { kind: "fetchurl", label: "Fetch a url", category: "actions", description: "Fetches the reviewed endpoint behind the call consent." },
9375
+ { kind: "condition", label: "Condition", category: "controlflow", description: "Evaluates one reviewed boolean expression with no page side effect." },
9376
+ { kind: "branch", label: "Branch", category: "controlflow", description: "Chooses one reviewed path by page state with a mandatory else path." },
9377
+ { kind: "loop", label: "Loop a list", category: "controlflow", description: "Iterates a list variable binding the item and index per pass." },
9378
+ { kind: "repeatuntil", label: "Repeat until", category: "controlflow", description: "Reruns the body until the convergence expression holds." },
9379
+ { kind: "whileloop", label: "While loop", category: "controlflow", description: "Loops while the condition holds inside the reviewed bound." },
9380
+ { kind: "foreach", label: "For each element", category: "controlflow", description: "Iterates the elements of the reviewed selector." },
9381
+ { kind: "parallel", label: "Parallel branches", category: "controlflow", description: "Runs branches concurrently and joins them under the reviewed strategy." },
9382
+ { kind: "trycatch", label: "Try catch", category: "controlflow", description: "Wraps fragile steps with a catch handler, retries and timeouts." },
9383
+ { kind: "delay", label: "Delay", category: "waits", description: "Sleeps the reviewed base inside the jitter window." },
9384
+ { kind: "waitelement", label: "Wait for element", category: "waits", description: "Polls the reviewed selector until appearance or timeout." },
9385
+ { kind: "wait", label: "Wait", category: "waits", description: "Waits the reviewed duration." },
9386
+ { kind: "waitfor", label: "Wait for target", category: "waits", description: "Waits until the reviewed target exists." },
9387
+ { kind: "waittext", label: "Wait for text", category: "waits", description: "Waits until the reviewed text appears." },
9388
+ { kind: "waitquiet", label: "Wait for quiet", category: "waits", description: "Waits until the page stops mutating." },
9389
+ { kind: "waitload", label: "Wait for load", category: "waits", description: "Waits until the navigation settles." },
9390
+ { kind: "compute", label: "Compute", category: "variables", description: "Evaluates one reviewed expression into the result variable." },
9391
+ { kind: "extractvars", label: "Extract variables", category: "variables", description: "Applies the reviewed regex and stores the named captures." },
9392
+ { kind: "savetemplate", label: "Save template", category: "variables", description: "Shares the reviewed step as a reusable template." },
9393
+ { kind: "visitrule", label: "Visit rule", category: "triggers", description: "Fires on navigations to the reviewed origins." },
9394
+ { kind: "urlrule", label: "Url rule", category: "triggers", description: "Fires when the url matches the reviewed glob pattern." },
9395
+ { kind: "cronrule", label: "Cron rule", category: "triggers", description: "Fires on the reviewed five field cron schedule." },
9396
+ { kind: "intervalrule", label: "Interval rule", category: "triggers", description: "Fires every reviewed period with the jitter spread." },
9397
+ { kind: "webhookrule", label: "Webhook rule", category: "triggers", description: "Fires on a secret verified webhook delivery." },
9398
+ { kind: "eventrule", label: "Event rule", category: "triggers", description: "Fires on the observed page events of the catalog." }
9399
+ ];
9400
+ var optionschemas = {
9401
+ delay: [{ name: "base", kind: "number", required: true }, { name: "jitter", kind: "number" }],
9402
+ waitelement: [{ name: "timeout", kind: "number" }, { name: "poll", kind: "number" }],
9403
+ compute: [{ name: "expression", kind: "string", required: true }],
9404
+ extractvars: [{ name: "rule", kind: "string", required: true }],
9405
+ composeworkflow: [{ name: "name", kind: "string", required: true }, { name: "version", kind: "number" }],
9406
+ runworkflow: [{ name: "workflowid", kind: "string", required: true }, { name: "reviewed", kind: "boolean", required: true }, { name: "variables", kind: "string" }, { name: "background", kind: "boolean" }],
9407
+ dryrun: [{ name: "workflowid", kind: "string", required: true }],
9408
+ loop: [{ name: "loop", kind: "string", required: true }],
9409
+ repeatuntil: [{ name: "repeatuntil", kind: "string", required: true }],
9410
+ whileloop: [{ name: "whileloop", kind: "string", required: true }],
9411
+ foreach: [{ name: "foreach", kind: "string", required: true }],
9412
+ parallel: [{ name: "parallel", kind: "string", required: true }],
9413
+ trycatch: [{ name: "trycatch", kind: "string", required: true }]
9414
+ };
9415
+ function stepcategory(kind) {
9416
+ if (triggerkinds.includes(kind)) return "triggers";
9417
+ if (controlflowkinds.includes(kind)) return "controlflow";
9418
+ if (kind.startsWith("wait") || kind === "spawait" || kind === "delay") return "waits";
9419
+ if (kind === "compute" || kind === "extractvars" || kind === "savetemplate") return "variables";
9420
+ return "actions";
9421
+ }
9422
+ function buildsteplibrary(kinds) {
9423
+ return [...new Set(kinds)].sort().map((kind) => ({ kind, category: stepcategory(kind), optionschema: optionschemas[kind] ?? [] }));
9424
+ }
9425
+ var noderowheight = 96;
9426
+ var blockcolumnwidth = 280;
9427
+ var canvasoriginx = 40;
9428
+ function snapshotof(model) {
9429
+ const { undo, redo, dirty, ...rest } = model;
9430
+ void undo;
9431
+ void redo;
9432
+ void dirty;
9433
+ return { ...rest, dirty: true };
9434
+ }
9435
+ function withundo(model, next) {
9436
+ const undo = [...model.undo ?? [], snapshotof(model)];
9437
+ const { redo, ...rest } = next;
9438
+ void redo;
9439
+ return { ...rest, dirty: true, undo };
9440
+ }
9441
+ function nodeidof(node) {
9442
+ return node.id ?? (node.step !== void 0 ? node.step.id : node.invocation !== void 0 ? node.invocation.block : "");
9443
+ }
9444
+ function layoutsizeof(nodes) {
9445
+ const width = Math.max(640, ...nodes.map((node) => node.x + blockcolumnwidth)) + 40;
9446
+ const height = Math.max(480, ...nodes.map((node) => node.y + noderowheight)) + 40;
9447
+ return { width, height };
9448
+ }
9449
+ function loadworkflow(record2, layout) {
9450
+ const blocks = record2.blocks.map((block) => ({ ...block, steps: block.steps.map((entry) => ({ ...entry })) }));
9451
+ const blockcolumn = (blockname) => {
9452
+ const index2 = blocks.findIndex((block) => block.name === blockname);
9453
+ return index2 < 0 ? canvasoriginx : canvasoriginx + (index2 + 1) * blockcolumnwidth;
9454
+ };
9455
+ const invocationcount = /* @__PURE__ */ new Map();
9456
+ const nodes = [];
9457
+ const edges = [];
9458
+ let index = 0;
9459
+ while (index < record2.steps.length) {
9460
+ const step = record2.steps[index];
9461
+ for (const binding of step.bindings ?? []) edges.push({ from: binding.stepid, to: step.id, variable: binding.variable, kind: binding.kind, ...binding.path !== void 0 ? { path: binding.path } : {} });
9462
+ if (step.block === void 0) {
9463
+ const { bindings, block, params: params2, ...rest } = step;
9464
+ void bindings;
9465
+ void block;
9466
+ void params2;
9467
+ nodes.push({ step: { ...rest }, x: canvasoriginx, y: 60 + nodes.length * noderowheight });
9468
+ index += 1;
9469
+ continue;
9470
+ }
9471
+ const blockname = step.block;
9472
+ let end = index;
9473
+ while (end < record2.steps.length && record2.steps[end].block === blockname) end += 1;
9474
+ const region = record2.steps.slice(index, end);
9475
+ const count = (invocationcount.get(blockname) ?? 0) + 1;
9476
+ invocationcount.set(blockname, count);
9477
+ const params = region.flatMap((entry) => entry.params ?? []);
9478
+ nodes.push({ id: count === 1 ? blockname : `${blockname}${count}`, invocation: { block: blockname, label: blockname, ...params.length > 0 ? { params: params.map((param) => ({ ...param })) } : {} }, x: blockcolumn(blockname), y: 60 + nodes.length * noderowheight });
9479
+ index = end;
9480
+ }
9481
+ const size = layouttypeof(nodes, layout);
9482
+ const model = { workflowid: record2.id, name: record2.name, version: record2.version, origins: [...record2.origins], nodes, edges, blocks, layout: size, minimap: emptyminimap(), dirty: false };
9483
+ return { ...model, minimap: renderminimap(model).minimap };
9484
+ }
9485
+ function layouttypeof(nodes, layout) {
9486
+ const size = layoutsizeof(nodes);
9487
+ if (!layout) return { width: size.width, height: size.height, viewportx: 0, viewporty: 0, zoom: 1 };
9488
+ return { width: Math.max(size.width, layout.width), height: Math.max(size.height, layout.height), viewportx: layout.viewportx, viewporty: layout.viewporty, zoom: layout.zoom };
9489
+ }
9490
+ function emptyminimap() {
9491
+ return { width: 160, height: 100, scale: 0, zoom: 1, viewport: { x: 0, y: 0, width: 0, height: 0 } };
9492
+ }
9493
+ function saveworkflow(model, input) {
9494
+ if (typeof model.name !== "string" || !model.name.trim()) throw new Error("The workflow name must be a non-empty string.");
9495
+ if (typeof model.version !== "number" || !Number.isInteger(model.version) || model.version < 1) throw new Error("The workflow version must be a positive integer.");
9496
+ if (!Array.isArray(model.origins) || model.origins.length === 0) throw new Error("A workflow needs at least one granted HTTPS origin.");
9497
+ const ids = /* @__PURE__ */ new Set();
9498
+ for (const node of model.nodes) {
9499
+ if (node.step === void 0 === (node.invocation === void 0)) throw new Error("Every canvas node must be exactly one workflow step or one block invocation.");
9500
+ const id = nodeidof(node);
9501
+ if (!id || ids.has(id)) throw new Error(`The canvas node id ${id || "(empty)"} must be unique.`);
9502
+ ids.add(id);
9503
+ }
9504
+ const positionof = /* @__PURE__ */ new Map();
9505
+ let position = 0;
9506
+ for (const node of model.nodes) {
9507
+ if (node.step !== void 0) {
9508
+ positionof.set(node.step.id, position);
9509
+ position += 1;
9510
+ continue;
9511
+ }
9512
+ const block = model.blocks.find((entry) => entry.name === node.invocation?.block);
9513
+ if (!block) throw new Error(`The block ${node.invocation?.block ?? ""} of the canvas has no definition.`);
9514
+ const walk = (entries2) => {
9515
+ for (const entry of entries2) {
9516
+ if ("kind" in entry && "label" in entry && !("block" in entry)) {
9517
+ positionof.set(entry.id, position);
9518
+ position += 1;
9519
+ continue;
9520
+ }
9521
+ const nested = model.blocks.find((candidate) => candidate.name === entry.block);
9522
+ if (!nested) throw new Error(`The block ${entry.block} of the canvas has no definition.`);
9523
+ walk(nested.steps);
9524
+ }
9525
+ };
9526
+ walk(block.steps);
9527
+ }
9528
+ for (const edge of model.edges) {
9529
+ if (!positionof.has(edge.from)) throw new Error(`The edge of ${edge.variable} references the unknown source step ${edge.from}.`);
9530
+ if (!positionof.has(edge.to)) throw new Error(`The edge of ${edge.variable} references the unknown target step ${edge.to}.`);
9531
+ if (positionof.get(edge.from) >= positionof.get(edge.to)) throw new Error(`The edge of ${edge.variable} runs backwards from ${edge.from} into ${edge.to} and would form a cycle.`);
9532
+ }
9533
+ const bindingsof = (stepid) => model.edges.filter((edge) => edge.to === stepid).map((edge) => ({ variable: edge.variable, kind: edge.kind, stepid: edge.from, ...edge.path !== void 0 ? { path: edge.path } : {} }));
9534
+ const entries = [];
9535
+ const attached = /* @__PURE__ */ new Map();
9536
+ for (const node of model.nodes) {
9537
+ if (node.invocation !== void 0) {
9538
+ entries.push({ ...node.invocation });
9539
+ continue;
9540
+ }
9541
+ const step = node.step;
9542
+ const bindings = bindingsof(step.id);
9543
+ const { block, params, ...rest } = { ...step, ...bindings.length > 0 ? { bindings } : {} };
9544
+ void params;
9545
+ const carried = rest;
9546
+ if (block !== void 0) {
9547
+ if (!model.blocks.some((candidate) => candidate.name === block)) throw new Error(`The step ${step.id} attaches to the unknown block ${block}.`);
9548
+ const list = attached.get(block) ?? [];
9549
+ list.push(carried);
9550
+ attached.set(block, list);
9551
+ continue;
9552
+ }
9553
+ entries.push(carried);
9554
+ }
9555
+ const blocks = model.blocks.map((block) => {
9556
+ const snapped = attached.get(block.name) ?? [];
9557
+ const snappedids = new Set(snapped.map((step) => step.id));
9558
+ const carried = [];
9559
+ for (const entry of block.steps) {
9560
+ if ("kind" in entry && "label" in entry && !("block" in entry) && snappedids.has(entry.id)) continue;
9561
+ carried.push(entry);
9562
+ }
9563
+ const steps = [...carried, ...snapped];
9564
+ const withbindings = [];
9565
+ for (const entry of steps) {
9566
+ if (!("kind" in entry && "label" in entry && !("block" in entry))) {
9567
+ withbindings.push(entry);
9568
+ continue;
9569
+ }
9570
+ const bindings = bindingsof(entry.id);
9571
+ const { block: inner, params, ...rest } = { ...entry, ...bindings.length > 0 ? { bindings } : {} };
9572
+ void inner;
9573
+ void params;
9574
+ withbindings.push(rest);
9575
+ }
9576
+ return { ...block, steps: withbindings };
9577
+ });
9578
+ const composed = composeworkflow({ id: model.workflowid, name: model.name, version: model.version, origins: [...model.origins], steps: entries, blocks: blocks.map((block) => ({ ...block })), now: input.now, ...input.kindallowed !== void 0 ? { kindallowed: input.kindallowed } : {}, ...input.riskof !== void 0 ? { riskof: input.riskof } : {} });
9579
+ const checked = validateworkflow(composed, input.kindallowed !== void 0 ? { kindallowed: input.kindallowed } : {});
9580
+ if (!checked.allowed) throw new Error(checked.reason ?? "The canvas model failed the workflow grammar.");
9581
+ return composed;
9582
+ }
9583
+ function snapnode(model, nodeid, x, y, grid = 20) {
9584
+ if (!Number.isFinite(grid) || grid <= 0) throw new Error("The snap grid must be a positive number.");
9585
+ const index = model.nodes.findIndex((node2) => nodeidof(node2) === nodeid);
9586
+ if (index < 0) throw new Error(`No canvas node matches ${nodeid}.`);
9587
+ const node = model.nodes[index];
9588
+ if (node.step === void 0) throw new Error("A block invocation node attaches through its own definition, not through snapping.");
9589
+ const snappedx = Math.round(x / grid) * grid;
9590
+ const snappedy = Math.round(y / grid) * grid;
9591
+ let attached;
9592
+ for (const [blockindex, block] of model.blocks.entries()) {
9593
+ const columnx = canvasoriginx + (blockindex + 1) * blockcolumnwidth;
9594
+ if (Math.abs(snappedx - columnx) <= blockcolumnwidth / 2) attached = block.name;
9595
+ }
9596
+ const { block: priorblock, ...rest } = node.step;
9597
+ void priorblock;
9598
+ const step = { ...rest, ...attached !== void 0 ? { block: attached } : {} };
9599
+ const nodes = model.nodes.map((candidate, position) => position === index ? { step, x: snappedx, y: snappedy } : candidate);
9600
+ const size = layouttypeof(nodes, model.layout);
9601
+ const next = { ...model, nodes, layout: size };
9602
+ return withundo(model, { ...next, minimap: renderminimap(next).minimap });
9603
+ }
9604
+ function reordersteps(model, nodeid, index) {
9605
+ const current = model.nodes.findIndex((node) => nodeidof(node) === nodeid);
9606
+ if (current < 0) throw new Error(`No canvas node matches ${nodeid}.`);
9607
+ if (!Number.isInteger(index) || index < 0 || index > model.nodes.length - 1) throw new Error("The reorder index must address an existing position of the canvas list.");
9608
+ const nodes = [...model.nodes];
9609
+ const [moved] = nodes.splice(current, 1);
9610
+ if (!moved) throw new Error("The reordered canvas node vanished.");
9611
+ nodes.splice(index, 0, moved);
9612
+ const next = { ...model, nodes };
9613
+ return withundo(model, { ...next, minimap: renderminimap(next).minimap });
9614
+ }
9615
+ function groupselect(model, nodeids, blockname) {
9616
+ if (!/^[a-z][a-z0-9]*$/.test(blockname)) throw new Error("The block name must be a unique lowercase word.");
9617
+ if (model.blocks.some((block) => block.name === blockname)) throw new Error(`The block name ${blockname} already exists on the canvas.`);
9618
+ const selected = nodeids.map((id) => {
9619
+ const node = model.nodes.find((candidate) => nodeidof(candidate) === id);
9620
+ if (!node || node.step === void 0) throw new Error(`The grouping selection must address step nodes; ${id} is not one.`);
9621
+ return node;
9622
+ });
9623
+ if (selected.length === 0) throw new Error("The grouping selection needs at least one step node.");
9624
+ const steps = selected.map((node) => node.step);
9625
+ const blocks = [...model.blocks, { name: blockname, label: blockname, steps: steps.map((step) => ({ ...step })) }];
9626
+ const firstindex = model.nodes.findIndex((node) => nodeidof(node) === nodeids[0]);
9627
+ const invocationnode = { id: blockname, invocation: { block: blockname, label: blockname }, x: selected[0].x, y: selected[0].y };
9628
+ const nodes = [];
9629
+ model.nodes.forEach((node, index) => {
9630
+ if (nodeids.includes(nodeidof(node))) {
9631
+ if (index === firstindex) nodes.push(invocationnode);
9632
+ return;
9633
+ }
9634
+ nodes.push(node);
9635
+ });
9636
+ const next = { ...model, nodes, blocks };
9637
+ return withundo(model, { ...next, minimap: renderminimap(next).minimap });
9638
+ }
9639
+ function expandtemplate(model, template, params = [], index) {
9640
+ const parsed = steptemplateof(template);
9641
+ if (!parsed) throw new Error("The template does not carry one reviewed workflow step.");
9642
+ let id = parsed.step.id;
9643
+ let suffix = 2;
9644
+ const taken = new Set(model.nodes.map((node) => nodeidof(node)));
9645
+ while (taken.has(id)) {
9646
+ id = `${parsed.step.id}${suffix}`;
9647
+ suffix += 1;
9648
+ }
9649
+ const step = { ...parsed.step, id, ...params.length > 0 ? { params: params.map((param) => ({ ...param })) } : {} };
9650
+ const position = index !== void 0 && Number.isInteger(index) && index >= 0 && index <= model.nodes.length ? index : model.nodes.length;
9651
+ const nodes = [...model.nodes.slice(0, position), { step, x: canvasoriginx, y: 60 + position * noderowheight }, ...model.nodes.slice(position)];
9652
+ const next = { ...model, nodes };
9653
+ return withundo(model, { ...next, minimap: renderminimap(next).minimap });
9654
+ }
9655
+ function addnode(model, step, index) {
9656
+ const normalized = workflowstepof(step);
9657
+ if (!normalized) throw new Error("The canvas insertion needs one reviewed workflow step.");
9658
+ let id = normalized.id;
9659
+ let suffix = 2;
9660
+ const taken = new Set(model.nodes.map((node) => nodeidof(node)));
9661
+ while (taken.has(id)) {
9662
+ id = `${normalized.id}${suffix}`;
9663
+ suffix += 1;
9664
+ }
9665
+ const position = index !== void 0 && Number.isInteger(index) && index >= 0 && index <= model.nodes.length ? index : model.nodes.length;
9666
+ const nodes = [...model.nodes.slice(0, position), { step: { ...normalized, id }, x: canvasoriginx, y: 60 + position * noderowheight }, ...model.nodes.slice(position)];
9667
+ const next = { ...model, nodes };
9668
+ return withundo(model, { ...next, minimap: renderminimap(next).minimap });
9669
+ }
9670
+ function editstep(model, step) {
9671
+ const normalized = workflowstepof(step);
9672
+ if (!normalized) throw new Error("The step inspector edit needs one reviewed workflow step.");
9673
+ const index = model.nodes.findIndex((node2) => node2.step?.id === normalized.id);
9674
+ if (index < 0) throw new Error(`No canvas step matches ${normalized.id}.`);
9675
+ const node = model.nodes[index];
9676
+ const nodes = model.nodes.map((candidate, position) => position === index ? { step: { ...normalized, ...node.step?.block !== void 0 ? { block: node.step.block } : {}, ...node.step?.breakpoint === true ? { breakpoint: true } : {} }, x: node.x, y: node.y } : candidate);
9677
+ const next = { ...model, nodes };
9678
+ return withundo(model, { ...next, minimap: renderminimap(next).minimap });
9679
+ }
9680
+ function renderminimap(model, width = 160, height = 100) {
9681
+ if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) throw new Error("The mini map size must be positive.");
9682
+ const canvaswidth = Math.max(1, model.layout.width);
9683
+ const canvasheight = Math.max(1, model.layout.height);
9684
+ const scale = Math.min(width / canvaswidth, height / canvasheight);
9685
+ const zoom = model.layout.zoom > 0 ? model.layout.zoom : 1;
9686
+ const visiblewidth = canvaswidth / zoom;
9687
+ const visibleheight = canvasheight / zoom;
9688
+ const viewport = {
9689
+ x: Math.max(0, Math.min(model.layout.viewportx, canvaswidth)) * scale,
9690
+ y: Math.max(0, Math.min(model.layout.viewporty, canvasheight)) * scale,
9691
+ width: visiblewidth * scale,
9692
+ height: visibleheight * scale
9693
+ };
9694
+ const nodes = model.nodes.map((node) => ({ id: nodeidof(node), x: node.x * scale, y: node.y * scale }));
9695
+ return { minimap: { width, height, scale, zoom, viewport }, nodes };
9696
+ }
9697
+ function minimapfocus(model, x, y, width = 160, height = 100) {
9698
+ const projection = renderminimap(model, width, height);
9699
+ if (projection.minimap.scale <= 0) return model;
9700
+ const canvasx = x / projection.minimap.scale;
9701
+ const canvasy = y / projection.minimap.scale;
9702
+ const zoom = model.layout.zoom > 0 ? model.layout.zoom : 1;
9703
+ const visiblewidth = model.layout.width / zoom;
9704
+ const visibleheight = model.layout.height / zoom;
9705
+ const viewportx = Math.max(0, Math.min(canvasx - visiblewidth / 2, Math.max(0, model.layout.width - visiblewidth)));
9706
+ const viewporty = Math.max(0, Math.min(canvasy - visibleheight / 2, Math.max(0, model.layout.height - visibleheight)));
9707
+ const next = { ...model, layout: { ...model.layout, viewportx, viewporty } };
9708
+ return { ...next, minimap: renderminimap(next).minimap };
9709
+ }
9710
+ function zoomcanvas(model, zoom) {
9711
+ if (!Number.isFinite(zoom) || zoom <= 0) throw new Error("The canvas zoom must be a positive number with no code ceiling.");
9712
+ const next = { ...model, layout: { ...model.layout, zoom } };
9713
+ const labelscale = zoom < 1 ? 1 / zoom : 1;
9714
+ return { model: { ...next, minimap: renderminimap(next).minimap }, labelscale };
9715
+ }
9716
+ function searchsteps(model, query) {
9717
+ const needle = query.trim().toLowerCase();
9718
+ if (!needle) return [];
9719
+ const results = [];
9720
+ for (const node of model.nodes) {
9721
+ if (node.step === void 0) continue;
9722
+ const matched = [];
9723
+ if (node.step.label.toLowerCase().includes(needle)) matched.push("label");
9724
+ if (node.step.kind.toLowerCase().includes(needle)) matched.push("kind");
9725
+ const variables = [
9726
+ ...model.edges.filter((edge) => edge.to === node.step?.id || edge.from === node.step?.id).map((edge) => edge.variable),
9727
+ ...node.step.expression !== void 0 ? [node.step.expression.result] : [],
9728
+ ...node.step.extract !== void 0 ? node.step.extract.groups : []
9729
+ ];
9730
+ if (variables.some((name) => name.toLowerCase().includes(needle))) matched.push("variable");
9731
+ if (matched.length > 0) results.push({ id: node.step.id, label: node.step.label, kind: node.step.kind, matched });
9732
+ }
9733
+ return results;
9734
+ }
9735
+ function markbreakpoint(model, stepid) {
9736
+ const toggle = (step) => {
9737
+ const { breakpoint, ...rest } = step;
9738
+ void breakpoint;
9739
+ return breakpoint === true ? rest : { ...rest, breakpoint: true };
9740
+ };
9741
+ const index = model.nodes.findIndex((node) => node.step?.id === stepid);
9742
+ if (index >= 0) {
9743
+ const node = model.nodes[index];
9744
+ const step = node.step;
9745
+ const nodes = model.nodes.map((candidate, position) => position === index ? { step: toggle(step), x: candidate.x, y: candidate.y } : candidate);
9746
+ const next2 = { ...model, nodes };
9747
+ return withundo(model, { ...next2, minimap: renderminimap(next2).minimap });
9748
+ }
9749
+ const blocks = model.blocks.map((block) => {
9750
+ const stepindex = block.steps.findIndex((entry) => "kind" in entry && "label" in entry && !("block" in entry) && entry.id === stepid);
9751
+ if (stepindex < 0) return block;
9752
+ const steps = block.steps.map((entry, position) => position === stepindex ? toggle(entry) : entry);
9753
+ return { ...block, steps };
9754
+ });
9755
+ if (blocks.every((block, position) => block === model.blocks[position])) throw new Error(`No canvas step matches ${stepid}.`);
9756
+ const next = { ...model, blocks };
9757
+ return withundo(model, next);
9758
+ }
9759
+ function runtobreakpoint(input) {
9760
+ const cursor = input.cursor !== void 0 && Number.isInteger(input.cursor) && input.cursor >= 0 ? input.cursor : 0;
9761
+ const marked = new Set(input.breakpoints);
9762
+ for (let index = cursor; index < input.record.steps.length; index += 1) {
9763
+ const step = input.record.steps[index];
9764
+ if (step.breakpoint === true || marked.has(step.id)) {
9765
+ return { until: index, pausat: step.id, remaining: input.record.steps.length - index };
9766
+ }
9767
+ }
9768
+ return { until: input.record.steps.length, pausat: void 0, remaining: 0 };
9769
+ }
9770
+ function diffversions(from, to, now) {
9771
+ const fromsteps = new Map(from.steps.map((step) => [step.id, step]));
9772
+ const tosteps = new Map(to.steps.map((step) => [step.id, step]));
9773
+ const added = [];
9774
+ const removed = [];
9775
+ const changed = [];
9776
+ for (const step of to.steps) {
9777
+ const prior = fromsteps.get(step.id);
9778
+ if (!prior) {
9779
+ added.push({ stepid: step.id, kind: step.kind, label: step.label });
9780
+ continue;
9781
+ }
9782
+ const changes = [];
9783
+ if (prior.label !== step.label) changes.push("label");
9784
+ if (prior.kind !== step.kind) changes.push("kind");
9785
+ if (prior.target !== step.target) changes.push("target");
9786
+ if (prior.value !== step.value) changes.push("value");
9787
+ if (prior.options !== step.options) changes.push("options");
9788
+ if (JSON.stringify(prior.expression) !== JSON.stringify(step.expression)) changes.push("expression");
9789
+ if (JSON.stringify(prior.extract) !== JSON.stringify(step.extract)) changes.push("extract");
9790
+ if (JSON.stringify(prior.bindings) !== JSON.stringify(step.bindings)) changes.push("bindings");
9791
+ if (changes.length > 0) changed.push({ stepid: step.id, kind: step.kind, label: step.label, changes });
9792
+ }
9793
+ for (const step of from.steps) {
9794
+ if (!tosteps.has(step.id)) removed.push({ stepid: step.id, kind: step.kind, label: step.label });
9795
+ }
9796
+ return { workflowid: to.id, from: from.version, to: to.version, added, removed, changed, at: now };
9797
+ }
9798
+ function exportworkflow(record2, format, note, now) {
9799
+ const file = { format: workflowfileversion, exportedat: now ?? Date.now(), workflow: record2, ...note !== void 0 && note.trim() !== "" ? { note } : {}, templates: [] };
9800
+ return { format, contents: serializefile(file, format), file };
9801
+ }
9802
+ function shareworkflow(record2, templates, format, note, now) {
9803
+ const file = { format: workflowfileversion, exportedat: now ?? Date.now(), workflow: record2, ...note !== void 0 && note.trim() !== "" ? { note } : {}, templates: templates.map((template) => ({ ...template })) };
9804
+ return { format, contents: serializefile(file, format), file };
9805
+ }
9806
+ function importworkflow(input) {
9807
+ const format = input.format ?? (input.contents.trimStart().startsWith("{") ? "json" : "yaml");
9808
+ const parsed = parsefile(input.contents, format);
9809
+ if (parsed.format !== workflowfileversion) throw new Error(`The workflow file format ${String(parsed.format)} is not the reviewed format ${workflowfileversion}.`);
9810
+ const candidate = parsed.workflow;
9811
+ if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) throw new Error("The workflow file carries no workflow record.");
9812
+ const fields = candidate;
9813
+ const stepsvalue = fields.steps;
9814
+ if (!Array.isArray(stepsvalue) || stepsvalue.length === 0) throw new Error("An imported workflow needs at least one step.");
9815
+ const steps = [];
9816
+ for (const entry of stepsvalue) {
9817
+ const step = workflowstepof(entry);
9818
+ if (step) {
9819
+ steps.push(step);
9820
+ continue;
9821
+ }
9822
+ throw new Error("Every imported workflow entry must be a reviewed step.");
9823
+ }
9824
+ const composed = composeworkflow({
9825
+ id: typeof fields.id === "string" && fields.id.trim() !== "" ? fields.id : crypto.randomUUID(),
9826
+ name: typeof fields.name === "string" ? fields.name : "",
9827
+ version: typeof fields.version === "number" ? fields.version : 1,
9828
+ origins: Array.isArray(fields.origins) ? fields.origins.filter((origin) => typeof origin === "string") : [],
9829
+ steps,
9830
+ now: input.now ?? Date.now(),
9831
+ ...input.kindallowed !== void 0 ? { kindallowed: input.kindallowed } : {},
9832
+ ...input.riskof !== void 0 ? { riskof: input.riskof } : {}
9833
+ });
9834
+ const templatesvalue = parsed.templates;
9835
+ if (templatesvalue !== void 0 && !Array.isArray(templatesvalue)) throw new Error("The packed templates of the workflow file must be a list.");
9836
+ const templates = [];
9837
+ for (const entry of templatesvalue ?? []) {
9838
+ const template = steptemplateof(entry);
9839
+ if (!template) throw new Error("A packed template of the workflow file does not carry one reviewed step.");
9840
+ templates.push(template);
9841
+ }
9842
+ const record2 = { ...composed, reviewstate: "pending" };
9843
+ return { record: record2, templates, file: { ...parsed, workflow: record2 } };
9844
+ }
9845
+ function bindparam(model, blockname, param) {
9846
+ if (!/^[a-z][a-z0-9]*$/.test(param.name)) throw new Error("The nested parameter name must be a lowercase word.");
9847
+ const index = model.nodes.findIndex((node2) => node2.invocation?.block === blockname);
9848
+ if (index < 0) throw new Error(`No block invocation of ${blockname} sits on the canvas.`);
9849
+ const node = model.nodes[index];
9850
+ const invocation = node.invocation;
9851
+ const params = [...(invocation.params ?? []).filter((existing) => existing.name !== param.name), { ...param }];
9852
+ const nodes = model.nodes.map((candidate, position) => position === index ? { invocation: { ...invocation, params }, x: candidate.x, y: candidate.y } : candidate);
9853
+ const next = { ...model, nodes };
9854
+ return withundo(model, { ...next, minimap: renderminimap(next).minimap });
9855
+ }
9856
+ function originmatches(pattern, origin) {
9857
+ if (pattern === origin) return true;
9858
+ const glob = pattern.replace(/\./g, "\\.").replace(/\*/g, "[^.]+");
9859
+ if (!glob.startsWith("https://")) return false;
9860
+ return new RegExp(`^${glob}$`).test(origin);
9861
+ }
9862
+ function applyoverride(record2, override) {
9863
+ const matching = record2.origins.filter((origin) => originmatches(override.pattern, origin));
9864
+ if (matching.length === 0) throw new Error(`The override pattern ${override.pattern} matches none of the workflow origins ${record2.origins.join(", ")}.`);
9865
+ const knobs = /* @__PURE__ */ new Set(["loopbound", "stepms", "runms", "waitms", "delaybase"]);
9866
+ for (const knob of Object.keys(override.deltas)) {
9867
+ if (!knobs.has(knob)) throw new Error(`The override knob ${knob} is not one of the reviewed knobs: ${[...knobs].join(", ")}.`);
9868
+ if (typeof override.deltas[knob] !== "number" || !Number.isFinite(override.deltas[knob]) || override.deltas[knob] <= 0) throw new Error(`The override delta of ${knob} must be a positive number with no code ceiling.`);
9869
+ }
9870
+ const apply = (step) => {
9871
+ if (Object.keys(override.deltas).length === 0) return step;
9872
+ let payload = {};
9873
+ try {
9874
+ payload = step.options !== void 0 ? JSON.parse(step.options) : {};
9875
+ } catch {
9876
+ payload = {};
9877
+ }
9878
+ const bodyof = (key) => payload[key] !== void 0 && typeof payload[key] === "object" && !Array.isArray(payload[key]) ? payload[key] : {};
9879
+ if (override.deltas.loopbound !== void 0 && ["loop", "repeatuntil", "whileloop"].includes(step.kind)) {
9880
+ const body = bodyof(step.kind);
9881
+ body.bound = override.deltas.loopbound;
9882
+ payload[step.kind] = body;
9883
+ }
9884
+ if ((override.deltas.stepms !== void 0 || override.deltas.runms !== void 0) && step.kind === "trycatch") {
9885
+ const body = bodyof("trycatch");
9886
+ const timeout = body.timeout !== void 0 && typeof body.timeout === "object" && !Array.isArray(body.timeout) ? body.timeout : {};
9887
+ if (override.deltas.stepms !== void 0) timeout.stepms = override.deltas.stepms;
9888
+ if (override.deltas.runms !== void 0) timeout.runms = override.deltas.runms;
9889
+ body.timeout = timeout;
9890
+ payload.trycatch = body;
9891
+ }
9892
+ if (override.deltas.waitms !== void 0 && step.kind === "waitelement") {
9893
+ payload.timeout = override.deltas.waitms;
9894
+ }
9895
+ if (override.deltas.delaybase !== void 0 && step.kind === "delay") {
9896
+ payload.base = override.deltas.delaybase;
9897
+ }
9898
+ const changed = Object.keys(payload).length > 0;
9899
+ return changed ? { ...step, options: JSON.stringify(payload) } : step;
9900
+ };
9901
+ return { ...record2, steps: record2.steps.map(apply) };
9902
+ }
9903
+ function addedge(model, edge) {
9904
+ const from = model.nodes.findIndex((node) => nodeidof(node) === edge.from);
9905
+ const to = model.nodes.findIndex((node) => nodeidof(node) === edge.to);
9906
+ if (from < 0) throw new Error(`The canvas edge references the unknown source step ${edge.from}.`);
9907
+ if (to < 0) throw new Error(`The canvas edge references the unknown target step ${edge.to}.`);
9908
+ if (from >= to) throw new Error(`The canvas edge of ${edge.variable} would run backwards from ${edge.from} into ${edge.to} and form a cycle.`);
9909
+ if (!/^[a-z][a-z0-9]*$/.test(edge.variable)) throw new Error("The bound variable name must be a lowercase word.");
9910
+ const edges = [...model.edges.filter((candidate) => !(candidate.from === edge.from && candidate.to === edge.to && candidate.variable === edge.variable)), { ...edge, ...edge.path !== void 0 ? { path: edge.path } : {} }];
9911
+ const next = { ...model, edges };
9912
+ return withundo(model, next);
9913
+ }
9914
+ function removeedge(model, from, to, variable) {
9915
+ const edges = model.edges.filter((candidate) => !(candidate.from === from && candidate.to === to && candidate.variable === variable));
9916
+ if (edges.length === model.edges.length) throw new Error(`No canvas edge of ${variable} links ${from} into ${to}.`);
9917
+ const next = { ...model, edges };
9918
+ return withundo(model, next);
9919
+ }
9920
+ function removenode(model, nodeid) {
9921
+ const index = model.nodes.findIndex((node) => nodeidof(node) === nodeid);
9922
+ if (index < 0) throw new Error(`No canvas node matches ${nodeid}.`);
9923
+ const nodes = model.nodes.filter((_, position) => position !== index);
9924
+ const edges = model.edges.filter((edge) => edge.from !== nodeid && edge.to !== nodeid);
9925
+ const next = { ...model, nodes, edges };
9926
+ return withundo(model, { ...next, minimap: renderminimap(next).minimap });
9927
+ }
9928
+ function undoedit(model) {
9929
+ const undo = model.undo ?? [];
9930
+ if (undo.length === 0) return model;
9931
+ const previous = undo[undo.length - 1];
9932
+ const current = snapshotof(model);
9933
+ return { ...previous, undo: undo.slice(0, -1), redo: [...model.redo ?? [], current] };
9934
+ }
9935
+ function redoedit(model) {
9936
+ const redo = model.redo ?? [];
9937
+ if (redo.length === 0) return model;
9938
+ const next = redo[redo.length - 1];
9939
+ const current = snapshotof(model);
9940
+ return { ...next, redo: redo.slice(0, -1), undo: [...model.undo ?? [], current] };
9941
+ }
9942
+ function serializefile(file, format) {
9943
+ if (format === "json") return JSON.stringify(file, null, 2);
9944
+ return yamlvalue(file, 0).join("\n") + "\n";
9945
+ }
9946
+ function parsefile(contents, format) {
9947
+ if (format === "json") {
9948
+ const parsed = JSON.parse(contents);
9949
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("The workflow file is not a json object.");
9950
+ return parsed;
9951
+ }
9952
+ const lines = contents.split(/\r?\n/).map((line) => line.replace(/\t/g, " ")).filter((line) => line.trim() !== "" && !line.trim().startsWith("#"));
9953
+ if (lines.length === 0) throw new Error("The yaml workflow file is empty.");
9954
+ const { value, next } = yamlblock(lines, 0, indentof(lines[0]));
9955
+ if (next < lines.length) throw new Error("The yaml workflow file carries content outside the documented subset.");
9956
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("The yaml workflow file is not a mapping.");
9957
+ return value;
9958
+ }
9959
+ function indentof(line) {
9960
+ const match = /^ */.exec(line);
9961
+ return match ? match[0].length : 0;
9962
+ }
9963
+ function yamlscalar(value) {
9964
+ if (value === null || value === void 0) return "null";
9965
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
9966
+ return JSON.stringify(String(value));
9967
+ }
9968
+ function yamlvalue(value, indent) {
9969
+ const pad = " ".repeat(indent);
9970
+ if (value === null || value === void 0 || typeof value !== "object") return [`${pad}${yamlscalar(value)}`];
9971
+ if (Array.isArray(value)) {
9972
+ if (value.length === 0) return [`${pad}[]`];
9973
+ const lines2 = [];
9974
+ for (const item of value) {
9975
+ if (item !== null && typeof item === "object") {
9976
+ lines2.push(`${pad}-`);
9977
+ lines2.push(...yamlvalue(item, indent + 2));
9978
+ } else {
9979
+ lines2.push(`${pad}- ${yamlscalar(item)}`);
9980
+ }
9981
+ }
9982
+ return lines2;
9983
+ }
9984
+ const entries = Object.entries(value);
9985
+ if (entries.length === 0) return [`${pad}{}`];
9986
+ const lines = [];
9987
+ for (const [key, entry] of entries) {
9988
+ if (entry !== null && typeof entry === "object") {
9989
+ if (Array.isArray(entry) && entry.length === 0) {
9990
+ lines.push(`${pad}${key}: []`);
9991
+ continue;
9992
+ }
9993
+ if (!Array.isArray(entry) && Object.keys(entry).length === 0) {
9994
+ lines.push(`${pad}${key}: {}`);
9995
+ continue;
9996
+ }
9997
+ lines.push(`${pad}${key}:`);
9998
+ lines.push(...yamlvalue(entry, indent + 2));
9999
+ } else {
10000
+ lines.push(`${pad}${key}: ${yamlscalar(entry)}`);
10001
+ }
10002
+ }
10003
+ return lines;
10004
+ }
10005
+ function yamlblock(lines, start, indent) {
10006
+ const first = lines[start];
10007
+ if (/^\s*-\s/.test(first) || /^\s*-$/.test(first)) {
10008
+ const items = [];
10009
+ let index2 = start;
10010
+ while (index2 < lines.length) {
10011
+ const line = lines[index2];
10012
+ if (indentof(line) !== indent || !/^\s*-\s?/.test(line)) break;
10013
+ const rest = line.slice(indent + 1).trim();
10014
+ if (rest !== "") {
10015
+ items.push(yamlscalarvalue(rest));
10016
+ index2 += 1;
10017
+ continue;
10018
+ }
10019
+ const nested = yamlblock(lines, index2 + 1, indent + 2);
10020
+ items.push(nested.value);
10021
+ index2 = nested.next;
10022
+ }
10023
+ return { value: items, next: index2 };
10024
+ }
10025
+ const mapping = {};
10026
+ let index = start;
10027
+ while (index < lines.length) {
10028
+ const line = lines[index];
10029
+ if (indentof(line) !== indent) break;
10030
+ const match = /^([A-Za-z][A-Za-z0-9]*):(?:\s(.*))?$/.exec(line.slice(indent));
10031
+ if (!match) break;
10032
+ const key = match[1];
10033
+ const rest = match[2];
10034
+ if (rest !== void 0 && rest !== "") {
10035
+ if (rest === "[]") {
10036
+ mapping[key] = [];
10037
+ index += 1;
10038
+ continue;
10039
+ }
10040
+ if (rest === "{}") {
10041
+ mapping[key] = {};
10042
+ index += 1;
10043
+ continue;
10044
+ }
10045
+ mapping[key] = yamlscalarvalue(rest);
10046
+ index += 1;
10047
+ continue;
10048
+ }
10049
+ const nested = yamlblock(lines, index + 1, indent + 2);
10050
+ mapping[key] = nested.value;
10051
+ index = nested.next;
10052
+ }
10053
+ if (index === start) throw new Error("The yaml workflow file left the documented subset.");
10054
+ return { value: mapping, next: index };
10055
+ }
10056
+ function yamlscalarvalue(text2) {
10057
+ if (text2.startsWith('"')) {
10058
+ const parsed = JSON.parse(text2);
10059
+ return typeof parsed === "string" ? parsed : text2;
10060
+ }
10061
+ if (text2 === "true") return true;
10062
+ if (text2 === "false") return false;
10063
+ if (text2 === "null") return null;
10064
+ if (/^-?\d+(?:\.\d+)?$/.test(text2)) return Number(text2);
10065
+ return text2;
10066
+ }
9052
10067
  export {
9053
10068
  activelayers,
10069
+ addedge,
10070
+ addnode,
9054
10071
  agentgrammarvalid,
9055
10072
  agentpresetof,
9056
10073
  allowlistcovers,
@@ -9063,6 +10080,7 @@ export {
9063
10080
  applycooldown,
9064
10081
  applyheaderules,
9065
10082
  applylayer,
10083
+ applyoverride,
9066
10084
  applyretry,
9067
10085
  applyruntimeout,
9068
10086
  applytimeout,
@@ -9077,6 +10095,7 @@ export {
9077
10095
  authreport,
9078
10096
  autointervalof,
9079
10097
  backoffdelay,
10098
+ bindparam,
9080
10099
  bindvariables,
9081
10100
  blackboxedurls,
9082
10101
  blackboxmatches,
@@ -9096,6 +10115,7 @@ export {
9096
10115
  buildname,
9097
10116
  buildpdf,
9098
10117
  buildsheet,
10118
+ buildsteplibrary,
9099
10119
  buildstitchplan,
9100
10120
  callgraphql,
9101
10121
  callrest,
@@ -9168,10 +10188,14 @@ export {
9168
10188
  diffresponse,
9169
10189
  diffreviewgrade,
9170
10190
  diffsessionrecords,
10191
+ diffversions,
9171
10192
  downloadreport,
9172
10193
  drainqueue,
9173
10194
  dryrunprojection,
9174
10195
  dryrunworkflow,
10196
+ editorsavegate,
10197
+ editorstate,
10198
+ editstep,
9175
10199
  emugate,
9176
10200
  emulationkinds,
9177
10201
  emulationreport,
@@ -9186,11 +10210,14 @@ export {
9186
10210
  eventrulematches,
9187
10211
  exchangesreport,
9188
10212
  expandblocks,
10213
+ expandtemplate,
9189
10214
  expirelayers,
9190
10215
  expireprofilerecords,
9191
10216
  expiresessions,
10217
+ exportcontentreview,
9192
10218
  exportpresetlibrary,
9193
10219
  exportsessionfile,
10220
+ exportworkflow,
9194
10221
  expressioneval,
9195
10222
  expressionof,
9196
10223
  expressionoperators,
@@ -9214,6 +10241,7 @@ export {
9214
10241
  generatedvalueallowed,
9215
10242
  graphqlopenvelope,
9216
10243
  graphqlrequestof,
10244
+ groupselect,
9217
10245
  growsampleof,
9218
10246
  growthtrend,
9219
10247
  headerfilterof,
@@ -9230,6 +10258,7 @@ export {
9230
10258
  imagenames,
9231
10259
  importpresetlibrary,
9232
10260
  importsessionfile,
10261
+ importworkflow,
9233
10262
  iscdpkind,
9234
10263
  iscontrolflowkind,
9235
10264
  iscontrolkind,
@@ -9252,6 +10281,7 @@ export {
9252
10281
  layoutreport,
9253
10282
  levelrank,
9254
10283
  listdue,
10284
+ loadworkflow,
9255
10285
  locationconsentcovers,
9256
10286
  locationconsentgate,
9257
10287
  locationpresetof,
@@ -9263,6 +10293,7 @@ export {
9263
10293
  manualrunpreview,
9264
10294
  mapresponse,
9265
10295
  mapurlof,
10296
+ markbreakpoint,
9266
10297
  matchmessage,
9267
10298
  matchurl,
9268
10299
  matchurlpattern,
@@ -9272,6 +10303,7 @@ export {
9272
10303
  mediareport,
9273
10304
  messagefilterof,
9274
10305
  methoddomain,
10306
+ minimapfocus,
9275
10307
  mockfor,
9276
10308
  mockspecof,
9277
10309
  multipartchunks,
@@ -9302,6 +10334,8 @@ export {
9302
10334
  overridematches,
9303
10335
  pairexchange,
9304
10336
  pairstates,
10337
+ palettecategories,
10338
+ palettenodes,
9305
10339
  parallelof,
9306
10340
  parsehtmlbody,
9307
10341
  parseproposal,
@@ -9356,10 +10390,15 @@ export {
9356
10390
  recordwatchvalue,
9357
10391
  redactconsoletext,
9358
10392
  redactedcookies,
10393
+ redoedit,
9359
10394
  regexextract,
9360
10395
  regexruleof,
9361
10396
  regionsteps,
9362
10397
  rejectioncapture,
10398
+ removeedge,
10399
+ removenode,
10400
+ renderminimap,
10401
+ reordersteps,
9363
10402
  repeatuntilof,
9364
10403
  replaytrace,
9365
10404
  replayurl,
@@ -9377,6 +10416,7 @@ export {
9377
10416
  revertlayer,
9378
10417
  revertplanof,
9379
10418
  revertrule,
10419
+ reviewedkinds,
9380
10420
  revocationruleof,
9381
10421
  rewritesourcelocation,
9382
10422
  rotatelogs,
@@ -9386,15 +10426,20 @@ export {
9386
10426
  runcatch,
9387
10427
  runcontrolstep,
9388
10428
  runforeach,
10429
+ runhistoryquery,
10430
+ runhistoryreport,
9389
10431
  runloop,
9390
10432
  runparallel,
9391
10433
  runrepeatuntil,
10434
+ runreviewgranted,
9392
10435
  runstep,
10436
+ runtobreakpoint,
9393
10437
  runtry,
9394
10438
  runurllist,
9395
10439
  runwhile,
9396
10440
  runworkflow,
9397
10441
  safetyresponse,
10442
+ saveworkflow,
9398
10443
  scaledrect,
9399
10444
  schedulecron,
9400
10445
  scheduleinterval,
@@ -9402,6 +10447,7 @@ export {
9402
10447
  searchfields,
9403
10448
  searchqueryof,
9404
10449
  searchsessionrecords,
10450
+ searchsteps,
9405
10451
  seededrandom,
9406
10452
  selectorresponse,
9407
10453
  sendcdpcommand,
@@ -9419,8 +10465,10 @@ export {
9419
10465
  sessionrestoregate,
9420
10466
  sessiontabof,
9421
10467
  setvariable,
10468
+ shareworkflow,
9422
10469
  shiftentryof,
9423
10470
  signalsreport,
10471
+ snapnode,
9424
10472
  snapshotplanof,
9425
10473
  snapshotretentionwindow,
9426
10474
  snapshotsections,
@@ -9476,6 +10524,7 @@ export {
9476
10524
  triggerpayloadof,
9477
10525
  triggersummary,
9478
10526
  tryof,
10527
+ undoedit,
9479
10528
  unwrapgraphql,
9480
10529
  updaterule,
9481
10530
  urlencodeform,
@@ -9484,6 +10533,7 @@ export {
9484
10533
  validatefieldmatch,
9485
10534
  validateformrecord,
9486
10535
  validateregexrule,
10536
+ validatesiteoverride,
9487
10537
  validatestep,
9488
10538
  validatetargetref,
9489
10539
  validatevaluegen,
@@ -9492,6 +10542,8 @@ export {
9492
10542
  visitmatch,
9493
10543
  waitelementplan,
9494
10544
  watchcdpevents,
10545
+ watchdogconfigvalid,
10546
+ watchdogpass,
9495
10547
  watcherdetached,
9496
10548
  watchexpressionof,
9497
10549
  watchgate,
@@ -9499,10 +10551,12 @@ export {
9499
10551
  whileof,
9500
10552
  wizardreport,
9501
10553
  workflowblockof,
10554
+ workflowfileversion,
9502
10555
  workflowgate,
9503
10556
  workflowkinds,
9504
10557
  workflowoutcome,
9505
10558
  workflowreport,
9506
- workflowstepof
10559
+ workflowstepof,
10560
+ zoomcanvas
9507
10561
  };
9508
10562
  //# sourceMappingURL=index.js.map