@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/README.md +4 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1295 -241
- package/dist/index.js.map +4 -4
- package/dist/memory.d.ts +48 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/policy.d.ts +24 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +78 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/types.d.ts +192 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/workflow.d.ts +19 -3
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workfloweditor.d.ts +108 -0
- package/dist/workfloweditor.d.ts.map +1 -0
- package/extension/dist/background.js +1241 -18
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +1 -1
- package/extension/dist/pagebridge.js.map +1 -1
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js.map +1 -1
- package/extension/dist/sidepanel.html +1 -1
- package/extension/dist/sidepanel.js +1283 -0
- package/extension/dist/sidepanel.js.map +4 -4
- package/extension/dist/style.css +2 -0
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
5778
|
-
var
|
|
5779
|
-
var
|
|
5780
|
-
var
|
|
5781
|
-
|
|
5782
|
-
|
|
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
|
|
5822
|
-
|
|
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.
|
|
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
|