@wenathlan/extension 1.1.52 → 1.1.54
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 +7 -5
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2106 -596
- package/dist/index.js.map +4 -4
- package/dist/mcpserver.d.ts +167 -0
- package/dist/mcpserver.d.ts.map +1 -0
- package/dist/memory.d.ts +74 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/policy.d.ts +48 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +102 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/toolcatalog.d.ts +31 -0
- package/dist/toolcatalog.d.ts.map +1 -0
- package/dist/types.d.ts +355 -3
- 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 +1773 -20
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +1 -1
- package/extension/dist/pagebridge.js +1 -1
- package/extension/dist/pagebridge.js.map +2 -2
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js +12 -1
- package/extension/dist/popup.js.map +2 -2
- package/extension/dist/sidepanel.html +1 -1
- package/extension/dist/sidepanel.js +1419 -1
- 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,162 @@ 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
|
+
}
|
|
4590
|
+
/** Returns every stored mcp client record, newest first. */
|
|
4591
|
+
async getclients() {
|
|
4592
|
+
return await this.adapter.get("mcpclients") ?? [];
|
|
4593
|
+
}
|
|
4594
|
+
/** Upserts one mcp client record by its id so one clientrecord stays per connected transport. */
|
|
4595
|
+
async setclient(client) {
|
|
4596
|
+
const records = (await this.getclients()).filter((entry) => entry.id !== client.id);
|
|
4597
|
+
await this.adapter.set("mcpclients", [client, ...records]);
|
|
4598
|
+
}
|
|
4599
|
+
/** Returns the connected client records — every client whose disconnect time is absent. */
|
|
4600
|
+
async listclients() {
|
|
4601
|
+
return (await this.getclients()).filter((client) => client.disconnectedat === void 0);
|
|
4602
|
+
}
|
|
4603
|
+
/** Stores the negotiated capability set of one client on its record. */
|
|
4604
|
+
async setclientcapabilities(id, capabilities) {
|
|
4605
|
+
await this.adapter.set("mcpclients", (await this.getclients()).map((client) => client.id === id ? { ...client, capabilities } : client));
|
|
4606
|
+
}
|
|
4607
|
+
/** Drops every stored client record when the server stops. */
|
|
4608
|
+
async clearclients() {
|
|
4609
|
+
await this.adapter.set("mcpclients", []);
|
|
4610
|
+
}
|
|
4611
|
+
/** Records one stdio bridge launch event with its process id; a restart marker distinguishes the relaunch of a dead client process. */
|
|
4612
|
+
async addbridgelaunch(launch) {
|
|
4613
|
+
await this.adapter.set("mcbridgelaunches", [launch, ...await this.adapter.get("mcbridgelaunches") ?? []]);
|
|
4614
|
+
}
|
|
4615
|
+
/** Returns every stdio bridge launch event, newest first. */
|
|
4616
|
+
async listbridgelaunches() {
|
|
4617
|
+
return await this.adapter.get("mcbridgelaunches") ?? [];
|
|
4618
|
+
}
|
|
4619
|
+
/** Returns the user configured mcp server config; an absent record keeps the documented localhost default. */
|
|
4620
|
+
async getmcpconfig() {
|
|
4621
|
+
return this.adapter.get("mcpconfig");
|
|
4622
|
+
}
|
|
4623
|
+
/** Stores the user configured mcp server config: bind address, port, transports, frame size, queue depth and enablement all stay user choices. */
|
|
4624
|
+
async setmcpconfig(config) {
|
|
4625
|
+
return this.adapter.set("mcpconfig", config);
|
|
4626
|
+
}
|
|
4627
|
+
/** Returns the persisted mcp server runtime state. */
|
|
4628
|
+
async getmcpstate() {
|
|
4629
|
+
return this.adapter.get("mcpstate");
|
|
4630
|
+
}
|
|
4631
|
+
/** Stores the mcp server runtime state with the stdio bridge status. */
|
|
4632
|
+
async setmcpstate(state) {
|
|
4633
|
+
return this.adapter.set("mcpstate", state);
|
|
4634
|
+
}
|
|
4635
|
+
/** Records one mcp tool call — the client, the tool, the origin and the outcome without any payload — under the user configured call retention with no code ceiling. */
|
|
4636
|
+
async addtoolcall(record2) {
|
|
4637
|
+
const records = await this.listtoolcalls();
|
|
4638
|
+
const retention = (await this.getmcpconfig())?.callretention;
|
|
4639
|
+
await this.adapter.set("mcptoolcalls", retention === void 0 ? [record2, ...records] : [record2, ...records].slice(0, retention));
|
|
4640
|
+
}
|
|
4641
|
+
/** Returns every stored mcp tool call record, newest first. */
|
|
4642
|
+
async listtoolcalls() {
|
|
4643
|
+
return await this.adapter.get("mcptoolcalls") ?? [];
|
|
4644
|
+
}
|
|
4437
4645
|
};
|
|
4438
4646
|
function mediakindof(record2) {
|
|
4439
4647
|
if ("pages" in record2) return "pdf";
|
|
@@ -4477,313 +4685,333 @@ function randomid() {
|
|
|
4477
4685
|
return crypto.randomUUID();
|
|
4478
4686
|
}
|
|
4479
4687
|
|
|
4480
|
-
//
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4688
|
+
// version.ts
|
|
4689
|
+
var packageversion = "1.1.54";
|
|
4690
|
+
|
|
4691
|
+
// types.ts
|
|
4692
|
+
var protocolversion = packageversion;
|
|
4693
|
+
|
|
4694
|
+
// toolcatalog.ts
|
|
4695
|
+
var toolcatalogversion = 1;
|
|
4696
|
+
var toolnamespaces = ["browser", "workflow", "memory", "system"];
|
|
4697
|
+
var domainkinds = {
|
|
4698
|
+
browser: ["observe", "extract", "readtext", "readtable", "readlinks", "a11ytree", "tablist", "windowlist", "click", "type", "presskey", "navigate", "back", "forward", "reload", "tabcreate", "tabactivate", "tabclose", "windowcreate", "windowclose", "windowresize"],
|
|
4699
|
+
workflow: ["composeworkflow", "runworkflow", "dryrun", "eventrule"],
|
|
4700
|
+
memory: ["listruns", "extractvars", "trailaudit"],
|
|
4701
|
+
system: ["observe", "readmeta"]
|
|
4702
|
+
};
|
|
4703
|
+
function toolschemaof(properties) {
|
|
4704
|
+
return { type: "object", properties, required: Object.entries(properties).filter(([, property]) => property.required === true).map(([name]) => name) };
|
|
4490
4705
|
}
|
|
4491
|
-
function
|
|
4492
|
-
|
|
4493
|
-
url.searchParams.set("response_type", "code");
|
|
4494
|
-
url.searchParams.set("redirect_uri", flow.redirectorigin);
|
|
4495
|
-
url.searchParams.set("scope", flow.scopes.join(" "));
|
|
4496
|
-
url.searchParams.set("state", state);
|
|
4497
|
-
return url.toString();
|
|
4706
|
+
function readtool(name, kind, description, inputs = {}) {
|
|
4707
|
+
return { name, version: toolcatalogversion, description, inputschema: toolschemaof({ target: { type: "string", description: "Reviewed css selector the tool addresses." }, value: { type: "string", description: "Reviewed literal value the tool carries." }, options: { type: "object", description: "Reviewed json options of the wrapped action kind with the empty default.", default: {} }, ...inputs }), kind, risk: "read" };
|
|
4498
4708
|
}
|
|
4499
|
-
function
|
|
4500
|
-
|
|
4501
|
-
try {
|
|
4502
|
-
parsed = new URL(url);
|
|
4503
|
-
} catch {
|
|
4504
|
-
return { error: "The redirect url does not parse for the code capture." };
|
|
4505
|
-
}
|
|
4506
|
-
const granted = redirectorigin.includes("/", redirectorigin.indexOf("://") + 3) ? `${parsed.origin}${parsed.pathname}`.startsWith(redirectorigin) : parsed.origin === redirectorigin;
|
|
4507
|
-
if (!granted) return { error: `The redirect landed on ${parsed.origin} outside the granted redirect origin ${redirectorigin}.` };
|
|
4508
|
-
const returned = parsed.searchParams.get("state");
|
|
4509
|
-
if (returned !== state) return { error: "The redirect state token does not match the reviewed flow." };
|
|
4510
|
-
const error = parsed.searchParams.get("error");
|
|
4511
|
-
if (error) return { error: `The provider refused the flow: ${error}.` };
|
|
4512
|
-
const code = parsed.searchParams.get("code");
|
|
4513
|
-
if (!code) return { error: "The redirect carries no authorization code." };
|
|
4514
|
-
return { code };
|
|
4709
|
+
function gatedtool(name, kind, risk, description, review) {
|
|
4710
|
+
return { name, version: toolcatalogversion, description, inputschema: toolschemaof({ stepid: { type: "string", description: "Id of the approved plan step this tool executes.", required: true } }), kind, risk, consentmeta: { review } };
|
|
4515
4711
|
}
|
|
4516
|
-
function
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4712
|
+
function browserdomain() {
|
|
4713
|
+
return {
|
|
4714
|
+
namespace: "browser",
|
|
4715
|
+
version: toolcatalogversion,
|
|
4716
|
+
tools: [
|
|
4717
|
+
readtool("browser.snapshot", "observe", "Captures the semantic snapshot of the active tab: url, title, text preview, forms and interactive elements. Read only with no side effects; runs under the dryrun risk class once the session is approved."),
|
|
4718
|
+
readtool("browser.extract", "extract", "Extracts the reviewed structured data of the page. Read only with no side effects."),
|
|
4719
|
+
readtool("browser.readtext", "readtext", "Reads the text of the addressed element. Read only with no side effects.", { target: { type: "string", description: "Reviewed css selector of the element to read.", required: true } }),
|
|
4720
|
+
readtool("browser.readtable", "readtable", "Reads the rows of the addressed data table. Read only with no side effects.", { target: { type: "string", description: "Reviewed css selector of the table to read.", required: true } }),
|
|
4721
|
+
readtool("browser.readlinks", "readlinks", "Reads the link inventory of the page. Read only with no side effects."),
|
|
4722
|
+
readtool("browser.a11ytree", "a11ytree", "Reads the accessibility tree of the page. Read only with no side effects."),
|
|
4723
|
+
readtool("browser.tablist", "tablist", "Lists the open tabs. Read only with no side effects."),
|
|
4724
|
+
readtool("browser.windowlist", "windowlist", "Lists the open windows. Read only with no side effects."),
|
|
4725
|
+
gatedtool("browser.click", "click", "sensitive", "Clicks the addressed element. Sensitive: it changes page state, so it executes exactly one approved plan step.", "The click runs only as the approved plan step it names; a paired client can never widen the reviewed target or options."),
|
|
4726
|
+
gatedtool("browser.type", "type", "sensitive", "Types the reviewed text into the addressed element. Sensitive: it changes page state, so it executes exactly one approved plan step.", "The typing runs only as the approved plan step it names; the reviewed target, text and options stay fixed."),
|
|
4727
|
+
gatedtool("browser.presskey", "presskey", "sensitive", "Presses the reviewed key. Sensitive: it changes page state, so it executes exactly one approved plan step.", "The key press runs only as the approved plan step it names."),
|
|
4728
|
+
gatedtool("browser.navigate", "navigate", "sensitive", "Navigates the active tab to the reviewed url. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The navigation runs only as the approved plan step it names and stays inside the session origin grants."),
|
|
4729
|
+
gatedtool("browser.back", "back", "sensitive", "Navigates back in the history of the active tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The history navigation runs only as the approved plan step it names."),
|
|
4730
|
+
gatedtool("browser.forward", "forward", "sensitive", "Navigates forward in the history of the active tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The history navigation runs only as the approved plan step it names."),
|
|
4731
|
+
gatedtool("browser.reload", "reload", "sensitive", "Reloads the active tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The reload runs only as the approved plan step it names."),
|
|
4732
|
+
gatedtool("browser.tabcreate", "tabcreate", "sensitive", "Opens a new tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The tab creation runs only as the approved plan step it names."),
|
|
4733
|
+
gatedtool("browser.tabactivate", "tabactivate", "sensitive", "Activates the reviewed tab. Sensitive: it moves focus, so it executes exactly one approved plan step.", "The tab activation runs only as the approved plan step it names."),
|
|
4734
|
+
gatedtool("browser.tabclose", "tabclose", "sensitive", "Closes the reviewed tab. Sensitive: it destroys browser state, so it executes exactly one approved plan step.", "The tab close runs only as the approved plan step it names."),
|
|
4735
|
+
gatedtool("browser.windowcreate", "windowcreate", "sensitive", "Opens a new window. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The window creation runs only as the approved plan step it names."),
|
|
4736
|
+
gatedtool("browser.windowclose", "windowclose", "sensitive", "Closes the reviewed window. Sensitive: it destroys browser state, so it executes exactly one approved plan step.", "The window close runs only as the approved plan step it names."),
|
|
4737
|
+
gatedtool("browser.windowresize", "windowresize", "sensitive", "Resizes the reviewed window. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The window resize runs only as the approved plan step it names.")
|
|
4738
|
+
]
|
|
4739
|
+
};
|
|
4532
4740
|
}
|
|
4533
|
-
function
|
|
4534
|
-
|
|
4535
|
-
|
|
4741
|
+
function workflowdomain() {
|
|
4742
|
+
return {
|
|
4743
|
+
namespace: "workflow",
|
|
4744
|
+
version: toolcatalogversion,
|
|
4745
|
+
tools: [
|
|
4746
|
+
readtool("workflow.list", "composeworkflow", "Lists the composed workflows with their names, versions, origins and step counts. Read only with no side effects."),
|
|
4747
|
+
readtool("workflow.dryrun", "dryrun", "Runs a composed workflow as a dry run: read steps project their would be outcome and every step with side effects is refused. Read only with no side effects."),
|
|
4748
|
+
gatedtool("workflow.run", "runworkflow", "sensitive", "Runs a composed workflow for real. Sensitive: it executes every step of the workflow, so it executes exactly one approved runworkflow plan step with its explicit run review.", "The workflow run needs the explicit run review: the approved runworkflow plan step with its expanded step list shown before the first step executes."),
|
|
4749
|
+
gatedtool("workflow.triggers", "eventrule", "sensitive", "Lists the armed trigger rules with their schedules, cooldowns and fire counters so a client can inspect what launches runs automatically. Sensitive by its trigger family: automatic launchers stay behind the arm review class.", "The trigger listing runs behind the approved plan review because trigger rules launch runs automatically.")
|
|
4750
|
+
]
|
|
4751
|
+
};
|
|
4536
4752
|
}
|
|
4537
|
-
function
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4753
|
+
function memorydomain() {
|
|
4754
|
+
return {
|
|
4755
|
+
namespace: "memory",
|
|
4756
|
+
version: toolcatalogversion,
|
|
4757
|
+
tools: [
|
|
4758
|
+
readtool("memory.list", "listruns", "Lists the stored workflow run records with their states and step cursors from local memory. Read only with no page access.", { target: { type: "string", description: "Unused by the memory read; kept for schema uniformity." }, value: { type: "string", description: "Unused by the memory read; kept for schema uniformity." }, state: { type: "string", description: "Optional reviewed run state filter of the listing.", default: "" } }),
|
|
4759
|
+
readtool("memory.variables", "extractvars", "Reads the stored variable scopes of a run from local memory. Read only with no page access."),
|
|
4760
|
+
readtool("memory.audit", "trailaudit", "Reads the audit summary of the session trail from local memory. Read only with no page access.")
|
|
4761
|
+
]
|
|
4762
|
+
};
|
|
4543
4763
|
}
|
|
4544
|
-
function
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
if (typeof field.value !== "string") return void 0;
|
|
4555
|
-
fields.push({ name: field.name.trim(), value: field.value });
|
|
4556
|
-
}
|
|
4557
|
-
return { url: options.url.trim(), fields };
|
|
4764
|
+
function systemdomain() {
|
|
4765
|
+
return {
|
|
4766
|
+
namespace: "system",
|
|
4767
|
+
version: toolcatalogversion,
|
|
4768
|
+
tools: [
|
|
4769
|
+
readtool("system.status", "observe", "Reports the mcp server status, the session state and the connected clients. Read only with no side effects."),
|
|
4770
|
+
readtool("system.version", "readmeta", "Reports the protocol version, the catalog version and the extension version. Read only with no side effects."),
|
|
4771
|
+
readtool("system.capabilities", "observe", "Reports the optional browser capabilities the user has granted. Read only with no side effects.")
|
|
4772
|
+
]
|
|
4773
|
+
};
|
|
4558
4774
|
}
|
|
4559
|
-
function
|
|
4560
|
-
return
|
|
4775
|
+
function buildtoolcatalog() {
|
|
4776
|
+
return { version: toolcatalogversion, domains: [browserdomain(), workflowdomain(), memorydomain(), systemdomain()] };
|
|
4561
4777
|
}
|
|
4562
|
-
function
|
|
4563
|
-
|
|
4564
|
-
return bytes.map((byte) => byte >= 65 && byte <= 90 || byte >= 97 && byte <= 122 || byte >= 48 && byte <= 57 || byte === 45 || byte === 95 || byte === 46 || byte === 126 ? String.fromCharCode(byte) : `%${byte.toString(16).toUpperCase().padStart(2, "0")}`).join("");
|
|
4778
|
+
function alltools(catalog) {
|
|
4779
|
+
return catalog.domains.flatMap((domain) => domain.tools);
|
|
4565
4780
|
}
|
|
4566
|
-
function
|
|
4567
|
-
|
|
4568
|
-
const options = value;
|
|
4569
|
-
if (typeof options.url !== "string" || !options.url.trim()) return void 0;
|
|
4570
|
-
if (!Array.isArray(options.files) || options.files.length === 0) return void 0;
|
|
4571
|
-
const fields = [];
|
|
4572
|
-
for (const item of Array.isArray(options.fields) ? options.fields : []) {
|
|
4573
|
-
if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
|
|
4574
|
-
const field = item;
|
|
4575
|
-
if (typeof field.name !== "string" || !field.name.trim()) return void 0;
|
|
4576
|
-
if (typeof field.value !== "string") return void 0;
|
|
4577
|
-
fields.push({ name: field.name.trim(), value: field.value });
|
|
4578
|
-
}
|
|
4579
|
-
const files = [];
|
|
4580
|
-
for (const item of options.files) {
|
|
4581
|
-
if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
|
|
4582
|
-
const file = item;
|
|
4583
|
-
if (typeof file.name !== "string" || !file.name.trim()) return void 0;
|
|
4584
|
-
if (typeof file.filename !== "string" || !file.filename.trim()) return void 0;
|
|
4585
|
-
if (typeof file.mime !== "string" || !file.mime.trim()) return void 0;
|
|
4586
|
-
if (typeof file.content !== "string") return void 0;
|
|
4587
|
-
if (file.reviewed !== true) return void 0;
|
|
4588
|
-
files.push({ name: file.name.trim(), filename: file.filename.trim(), mime: file.mime.trim(), content: file.content, reviewed: true });
|
|
4589
|
-
}
|
|
4590
|
-
const payload = { url: options.url.trim(), fields, files, ...typeof options.boundary === "string" && options.boundary.trim() ? { boundary: options.boundary.trim() } : {} };
|
|
4591
|
-
return payload;
|
|
4781
|
+
function toolname(namespace, base) {
|
|
4782
|
+
return `${namespace}.${base}`;
|
|
4592
4783
|
}
|
|
4593
|
-
function
|
|
4594
|
-
|
|
4784
|
+
function resolvetool(catalog, name) {
|
|
4785
|
+
if (name.includes(".")) return alltools(catalog).find((tool) => tool.name === name);
|
|
4786
|
+
const matches = alltools(catalog).filter((tool) => tool.name.split(".")[1] === name);
|
|
4787
|
+
return matches.length === 1 ? matches[0] : void 0;
|
|
4595
4788
|
}
|
|
4596
|
-
function
|
|
4597
|
-
const
|
|
4598
|
-
|
|
4599
|
-
for (const field of payload.fields) chunks.push(`--${boundary}\r
|
|
4600
|
-
content-disposition: form-data; name="${field.name}"\r
|
|
4601
|
-
\r
|
|
4602
|
-
${field.value}\r
|
|
4603
|
-
`);
|
|
4604
|
-
for (const file of payload.files) chunks.push(`--${boundary}\r
|
|
4605
|
-
content-disposition: form-data; name="${file.name}"; filename="${file.filename}"\r
|
|
4606
|
-
content-type: ${file.mime}\r
|
|
4607
|
-
\r
|
|
4608
|
-
${file.content}\r
|
|
4609
|
-
`);
|
|
4610
|
-
chunks.push(`--${boundary}--\r
|
|
4611
|
-
`);
|
|
4612
|
-
return { chunks, boundary, bytes: chunks.reduce((total, chunk) => total + chunk.length, 0) };
|
|
4789
|
+
function namespaceof(name) {
|
|
4790
|
+
const head = name.split(".")[0];
|
|
4791
|
+
return toolnamespaces.includes(head) ? head : void 0;
|
|
4613
4792
|
}
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
var controlkinds = ["blockrequest", "mockresponse", "rewriteheaders", "setcookies", "readcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles"];
|
|
4617
|
-
function patternorigin(pattern) {
|
|
4618
|
-
const trimmed = pattern.trim();
|
|
4619
|
-
if (!trimmed.startsWith("https://")) return void 0;
|
|
4620
|
-
const rest = trimmed.slice("https://".length);
|
|
4621
|
-
const host = rest.split("/")[0] ?? "";
|
|
4622
|
-
if (!host.trim()) return void 0;
|
|
4623
|
-
return `https://${host.toLowerCase()}`;
|
|
4793
|
+
function toolsbynamespace(catalog) {
|
|
4794
|
+
return catalog.domains.map((domain) => ({ namespace: domain.namespace, version: domain.version, tools: domain.tools }));
|
|
4624
4795
|
}
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4796
|
+
|
|
4797
|
+
// socketbus.ts
|
|
4798
|
+
var socketkinds = ["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"];
|
|
4799
|
+
function channelorigin(url) {
|
|
4629
4800
|
try {
|
|
4630
|
-
parsed = new URL(url);
|
|
4801
|
+
const parsed = new URL(url);
|
|
4802
|
+
const protocol = parsed.protocol === "wss:" ? "https:" : parsed.protocol === "ws:" ? "http:" : parsed.protocol;
|
|
4803
|
+
return `${protocol}//${parsed.host}`;
|
|
4631
4804
|
} catch {
|
|
4632
|
-
return
|
|
4805
|
+
return "";
|
|
4633
4806
|
}
|
|
4634
|
-
if (parsed.origin !== origin) return false;
|
|
4635
|
-
const patternpath = pattern.trim().slice(origin.length);
|
|
4636
|
-
if (patternpath === "" || patternpath === "/") return true;
|
|
4637
|
-
const segments = patternpath.split("/").filter((segment) => segment !== "");
|
|
4638
|
-
if (segments.includes("**")) return true;
|
|
4639
|
-
const pathsegments = parsed.pathname.split("/").filter((segment) => segment !== "");
|
|
4640
|
-
if (segments.length !== pathsegments.length) return false;
|
|
4641
|
-
return segments.every((segment, index) => segment === pathsegments[index] || segment.includes("*") && new RegExp(`^${segment.split("*").map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(".*")}$`).test(pathsegments[index] ?? ""));
|
|
4642
4807
|
}
|
|
4643
|
-
function
|
|
4808
|
+
function channeloptionsof(value) {
|
|
4644
4809
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
4645
|
-
const
|
|
4646
|
-
if (typeof
|
|
4647
|
-
const
|
|
4648
|
-
if (Array.isArray(options.
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
return
|
|
4810
|
+
const entry = value;
|
|
4811
|
+
if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
|
|
4812
|
+
const options = {};
|
|
4813
|
+
if (Array.isArray(entry.protocols)) options.protocols = entry.protocols.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
4814
|
+
if (typeof entry.reconnect === "number" && Number.isFinite(entry.reconnect)) options.reconnect = entry.reconnect;
|
|
4815
|
+
if (typeof entry.backoff === "number" && Number.isFinite(entry.backoff)) options.backoff = entry.backoff;
|
|
4816
|
+
if (typeof entry.backoffceiling === "number" && Number.isFinite(entry.backoffceiling)) options.backoffceiling = entry.backoffceiling;
|
|
4817
|
+
if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime)) options.lifetime = entry.lifetime;
|
|
4818
|
+
return { url: entry.url.trim(), options };
|
|
4654
4819
|
}
|
|
4655
|
-
function
|
|
4656
|
-
return { id: input.id, runid: input.runid, stepid: input.stepid,
|
|
4820
|
+
function newchannel(input) {
|
|
4821
|
+
return { id: input.id, runid: input.runid, stepid: input.stepid, kind: input.kind, url: input.url, origin: channelorigin(input.url), state: "connecting", openedat: input.at, sent: 0, received: 0, reconnects: 0, ...input.protocols !== void 0 && input.protocols.length > 0 ? { protocols: [...input.protocols] } : {} };
|
|
4657
4822
|
}
|
|
4658
|
-
function
|
|
4659
|
-
|
|
4660
|
-
const
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
if (bodyref !== "") spec.bodyref = bodyref;
|
|
4669
|
-
if (options.headers && typeof options.headers === "object" && !Array.isArray(options.headers)) spec.headers = options.headers;
|
|
4670
|
-
if (options.reviewed === true) spec.reviewed = true;
|
|
4671
|
-
return spec;
|
|
4823
|
+
function reconnectwaits(attempts, base, ceiling) {
|
|
4824
|
+
const count = Math.max(0, Math.floor(attempts));
|
|
4825
|
+
const waits = [];
|
|
4826
|
+
let wait = Math.max(0, base);
|
|
4827
|
+
for (let index = 0; index < count; index += 1) {
|
|
4828
|
+
waits.push(wait);
|
|
4829
|
+
const next = wait * 2;
|
|
4830
|
+
wait = ceiling !== void 0 && Number.isFinite(ceiling) && ceiling >= 0 ? Math.min(next, ceiling) : next;
|
|
4831
|
+
}
|
|
4832
|
+
return waits;
|
|
4672
4833
|
}
|
|
4673
|
-
function
|
|
4674
|
-
|
|
4834
|
+
async function openchannel(input) {
|
|
4835
|
+
const sleep = input.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, Math.max(0, milliseconds))));
|
|
4836
|
+
const now = input.now ?? Date.now;
|
|
4837
|
+
const attempts = Math.max(1, Math.floor(input.options.reconnect ?? 0) + 1);
|
|
4838
|
+
const waits = reconnectwaits(attempts - 1, input.options.backoff ?? 0, input.options.backoffceiling);
|
|
4839
|
+
let record2 = { ...input.record, state: "connecting" };
|
|
4840
|
+
let lasterror = "";
|
|
4841
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
4842
|
+
try {
|
|
4843
|
+
const result = await input.connect(record2.url, record2.protocols ?? []);
|
|
4844
|
+
if (result.open) return { ...record2, state: "open", openedat: now() };
|
|
4845
|
+
lasterror = result.error ?? `closed with code ${result.code ?? 0}`;
|
|
4846
|
+
} catch (error) {
|
|
4847
|
+
lasterror = error instanceof Error ? error.message : String(error);
|
|
4848
|
+
}
|
|
4849
|
+
if (attempt < attempts - 1) {
|
|
4850
|
+
const wait = waits[attempt] ?? 0;
|
|
4851
|
+
if (wait > 0) await sleep(wait);
|
|
4852
|
+
record2 = { ...record2, reconnects: record2.reconnects + 1 };
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
return { ...record2, state: "failed", error: lasterror };
|
|
4675
4856
|
}
|
|
4676
|
-
function
|
|
4677
|
-
|
|
4678
|
-
}
|
|
4679
|
-
function headeruleof(value) {
|
|
4680
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
4681
|
-
const options = value;
|
|
4682
|
-
if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
|
|
4683
|
-
if (typeof options.name !== "string" || !options.name.trim()) return void 0;
|
|
4684
|
-
if (options.operation !== "set" && options.operation !== "append" && options.operation !== "remove") return void 0;
|
|
4685
|
-
if (options.operation === "remove" && options.value !== void 0) return void 0;
|
|
4686
|
-
if (options.operation !== "remove" && typeof options.value !== "string") return void 0;
|
|
4687
|
-
const rule = { urlpattern: options.urlpattern.trim(), name: options.name.trim(), operation: options.operation };
|
|
4688
|
-
if (options.operation !== "remove") rule.value = typeof options.value === "string" ? options.value : "";
|
|
4689
|
-
return rule;
|
|
4857
|
+
function closechannel(record2, at, error) {
|
|
4858
|
+
const state = error !== void 0 ? "failed" : "closed";
|
|
4859
|
+
return { ...record2, state, closedat: at, ...error !== void 0 ? { error } : {} };
|
|
4690
4860
|
}
|
|
4691
|
-
function
|
|
4692
|
-
|
|
4861
|
+
function tagmessage(state, channelid, stream, payload, at) {
|
|
4862
|
+
const sequence = (state.sequences[channelid] ?? 0) + 1;
|
|
4863
|
+
const envelope = { channelid, stream, payload, sequence, at };
|
|
4864
|
+
return { state: { sequences: { ...state.sequences, [channelid]: sequence }, queue: state.queue }, envelope };
|
|
4693
4865
|
}
|
|
4694
|
-
function
|
|
4695
|
-
|
|
4696
|
-
const applied = [];
|
|
4697
|
-
for (const rule of rules) {
|
|
4698
|
-
if (rule.revertedat !== void 0) continue;
|
|
4699
|
-
if (!matchurlpattern(rule.urlpattern, url)) continue;
|
|
4700
|
-
const name = rule.name;
|
|
4701
|
-
if (rule.operation === "remove") {
|
|
4702
|
-
delete rewritten[name];
|
|
4703
|
-
applied.push(rule);
|
|
4704
|
-
continue;
|
|
4705
|
-
}
|
|
4706
|
-
const value = rule.value ?? "";
|
|
4707
|
-
if (rule.operation === "set") rewritten[name] = value;
|
|
4708
|
-
else rewritten[name] = rewritten[name] !== void 0 ? `${rewritten[name]}, ${value}` : value;
|
|
4709
|
-
applied.push(rule);
|
|
4710
|
-
}
|
|
4711
|
-
return { headers: rewritten, applied };
|
|
4866
|
+
function publishmessage(state, channelid, stream, payload, at) {
|
|
4867
|
+
return tagmessage(state, channelid, stream, payload, at);
|
|
4712
4868
|
}
|
|
4713
|
-
function
|
|
4714
|
-
|
|
4715
|
-
return { ...
|
|
4869
|
+
function receivemessage(state, channelid, stream, payload, at) {
|
|
4870
|
+
const tagged = tagmessage(state, channelid, stream, payload, at);
|
|
4871
|
+
return { state: { ...tagged.state, queue: [...state.queue, tagged.envelope] }, envelope: tagged.envelope };
|
|
4716
4872
|
}
|
|
4717
|
-
function
|
|
4718
|
-
if (
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
if (typeof options.domain !== "string" || !options.domain.trim()) return void 0;
|
|
4722
|
-
if (typeof options.path !== "string" || !options.path.trim()) return void 0;
|
|
4723
|
-
if (typeof options.value !== "string") return void 0;
|
|
4724
|
-
const record2 = { name: options.name.trim(), domain: options.domain.trim().toLowerCase(), path: options.path.trim(), value: options.value };
|
|
4725
|
-
if (typeof options.expiresat === "number" && Number.isFinite(options.expiresat)) record2.expiresat = options.expiresat;
|
|
4726
|
-
return record2;
|
|
4873
|
+
function pathstep2(current, segment) {
|
|
4874
|
+
if (Array.isArray(current) && /^\d+$/.test(segment)) return current[Number.parseInt(segment, 10)];
|
|
4875
|
+
if (current && typeof current === "object" && !Array.isArray(current)) return current[segment];
|
|
4876
|
+
return void 0;
|
|
4727
4877
|
}
|
|
4728
|
-
function
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4878
|
+
function matchmessage(filter, envelope) {
|
|
4879
|
+
if (!filter) return true;
|
|
4880
|
+
if (filter.stream !== void 0 && filter.stream !== envelope.stream) return false;
|
|
4881
|
+
if (filter.path !== void 0) {
|
|
4732
4882
|
try {
|
|
4733
|
-
|
|
4883
|
+
const parsed = JSON.parse(envelope.payload);
|
|
4884
|
+
let current = parsed;
|
|
4885
|
+
let missing = false;
|
|
4886
|
+
for (const segment of filter.path.split(".")) {
|
|
4887
|
+
const next = pathstep2(current, segment);
|
|
4888
|
+
if (next === void 0) {
|
|
4889
|
+
missing = true;
|
|
4890
|
+
break;
|
|
4891
|
+
}
|
|
4892
|
+
current = next;
|
|
4893
|
+
}
|
|
4894
|
+
if (missing) return false;
|
|
4734
4895
|
} catch {
|
|
4735
4896
|
return false;
|
|
4736
4897
|
}
|
|
4737
|
-
|
|
4738
|
-
|
|
4898
|
+
}
|
|
4899
|
+
return true;
|
|
4739
4900
|
}
|
|
4740
|
-
function
|
|
4741
|
-
|
|
4901
|
+
function collectmessages(state, channelid, filter) {
|
|
4902
|
+
const limit = filter?.limit !== void 0 && Number.isFinite(filter.limit) && filter.limit >= 1 ? Math.floor(filter.limit) : Number.POSITIVE_INFINITY;
|
|
4903
|
+
const matched = [];
|
|
4904
|
+
const queue = [];
|
|
4905
|
+
for (const envelope of state.queue) {
|
|
4906
|
+
if (envelope.channelid === channelid && matched.length < limit && matchmessage(filter, envelope)) matched.push(envelope);
|
|
4907
|
+
else queue.push(envelope);
|
|
4908
|
+
}
|
|
4909
|
+
return { state: { sequences: state.sequences, queue }, matched };
|
|
4742
4910
|
}
|
|
4743
|
-
function
|
|
4744
|
-
|
|
4745
|
-
const
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4911
|
+
function sequenceintegrity(envelopes) {
|
|
4912
|
+
const last = /* @__PURE__ */ new Map();
|
|
4913
|
+
const gaps = [];
|
|
4914
|
+
for (const envelope of envelopes) {
|
|
4915
|
+
const expected = (last.get(envelope.channelid) ?? 0) + 1;
|
|
4916
|
+
if (envelope.sequence !== expected) gaps.push({ channelid: envelope.channelid, expected, found: envelope.sequence });
|
|
4917
|
+
last.set(envelope.channelid, Math.max(envelope.sequence, expected));
|
|
4918
|
+
}
|
|
4919
|
+
return { ok: gaps.length === 0, gaps };
|
|
4751
4920
|
}
|
|
4752
|
-
function
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4921
|
+
function messagefilterof(value) {
|
|
4922
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
4923
|
+
const entry = value;
|
|
4924
|
+
const filter = {};
|
|
4925
|
+
if (typeof entry.stream === "string" && entry.stream.trim()) filter.stream = entry.stream.trim();
|
|
4926
|
+
if (typeof entry.path === "string" && entry.path.trim()) filter.path = entry.path.trim();
|
|
4927
|
+
if (typeof entry.limit === "number" && Number.isFinite(entry.limit) && entry.limit >= 1) filter.limit = Math.floor(entry.limit);
|
|
4928
|
+
return filter;
|
|
4929
|
+
}
|
|
4930
|
+
function parsessetext(text2) {
|
|
4931
|
+
const separator = text2.lastIndexOf("\n\n");
|
|
4932
|
+
const complete = separator === -1 ? "" : text2.slice(0, separator + 2);
|
|
4933
|
+
const rest = separator === -1 ? text2 : text2.slice(separator + 2);
|
|
4934
|
+
const events = [];
|
|
4935
|
+
for (const block of complete.split(/\n\n/)) {
|
|
4936
|
+
const id = [];
|
|
4937
|
+
const names = [];
|
|
4938
|
+
const data = [];
|
|
4939
|
+
let retry;
|
|
4940
|
+
for (const line of block.split("\n")) {
|
|
4941
|
+
if (line === "" || line.startsWith(":")) continue;
|
|
4942
|
+
const colon = line.indexOf(":");
|
|
4943
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
4944
|
+
let value = colon === -1 ? "" : line.slice(colon + 1);
|
|
4945
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
4946
|
+
if (field === "id" && value !== "") id.push(value);
|
|
4947
|
+
if (field === "event" && value !== "") names.push(value);
|
|
4948
|
+
if (field === "data") data.push(value);
|
|
4949
|
+
if (field === "retry" && /^\d+$/.test(value)) retry = Number.parseInt(value, 10);
|
|
4758
4950
|
}
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
const reset = pick("x-ratelimit-reset");
|
|
4764
|
-
if (remaining === void 0 && limit === void 0 && reset === void 0) return void 0;
|
|
4765
|
-
const read = { origin, ...remaining !== void 0 ? { remaining } : {}, ...limit !== void 0 ? { limit } : {}, resetat: now, at: now };
|
|
4766
|
-
if (reset !== void 0) read.resetat = reset > Math.floor(now / 1e3) ? reset * 1e3 : now + reset * 1e3;
|
|
4767
|
-
return read;
|
|
4951
|
+
if (id.length === 0 && names.length === 0 && data.length === 0) continue;
|
|
4952
|
+
events.push({ ...id.length > 0 ? { id: id[id.length - 1] } : {}, ...names.length > 0 ? { event: names[names.length - 1] } : {}, data: data.join("\n"), ...retry !== void 0 ? { retry } : {} });
|
|
4953
|
+
}
|
|
4954
|
+
return { events, rest };
|
|
4768
4955
|
}
|
|
4769
|
-
function
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4956
|
+
function sserequestheaders(record2) {
|
|
4957
|
+
return { accept: "text/event-stream", ...record2.lasteventid !== void 0 && record2.lasteventid !== "" ? { "last-event-id": record2.lasteventid } : {} };
|
|
4958
|
+
}
|
|
4959
|
+
function subscriptionoptionsof(value) {
|
|
4960
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
4961
|
+
const entry = value;
|
|
4962
|
+
if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
|
|
4963
|
+
const cancel = entry.cancel;
|
|
4964
|
+
if (!cancel || typeof cancel !== "object" || Array.isArray(cancel)) return void 0;
|
|
4965
|
+
const cancelrecord = cancel;
|
|
4966
|
+
if (cancelrecord.kind !== "stop" && cancelrecord.kind !== "lifetime") return void 0;
|
|
4967
|
+
if (typeof cancelrecord.value !== "string" && typeof cancelrecord.value !== "number") return void 0;
|
|
4968
|
+
const result = { url: entry.url.trim(), cancel: { kind: cancelrecord.kind, value: cancelrecord.value } };
|
|
4969
|
+
if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime) && entry.lifetime > 0) result.lifetime = entry.lifetime;
|
|
4970
|
+
if (typeof entry.lasteventid === "string" && entry.lasteventid.trim()) result.lasteventid = entry.lasteventid.trim();
|
|
4971
|
+
return result;
|
|
4972
|
+
}
|
|
4973
|
+
function pollcursorof(value) {
|
|
4974
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
4975
|
+
const entry = value;
|
|
4976
|
+
if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
|
|
4977
|
+
if (typeof entry.cursorfield !== "string" || !entry.cursorfield.trim()) return void 0;
|
|
4978
|
+
if (typeof entry.interval !== "number" || !Number.isFinite(entry.interval) || entry.interval <= 0) return void 0;
|
|
4979
|
+
const stop = entry.stop;
|
|
4980
|
+
if (!stop || typeof stop !== "object" || Array.isArray(stop)) return void 0;
|
|
4981
|
+
const stoprecord = stop;
|
|
4982
|
+
if (typeof stoprecord.field !== "string" || !stoprecord.field.trim()) return void 0;
|
|
4983
|
+
if (typeof stoprecord.equals !== "string") return void 0;
|
|
4984
|
+
const cursor = { url: entry.url.trim(), cursorfield: entry.cursorfield.trim(), interval: entry.interval, stop: { field: stoprecord.field.trim(), equals: stoprecord.equals } };
|
|
4985
|
+
if (typeof entry.maxpolls === "number" && Number.isFinite(entry.maxpolls) && entry.maxpolls >= 1) cursor.maxpolls = Math.floor(entry.maxpolls);
|
|
4986
|
+
if (typeof entry.param === "string" && entry.param.trim()) cursor.param = entry.param.trim();
|
|
4987
|
+
return cursor;
|
|
4988
|
+
}
|
|
4989
|
+
function cursorfrom(response, field) {
|
|
4990
|
+
let current = response;
|
|
4991
|
+
for (const segment of field.split(".")) {
|
|
4992
|
+
const next = pathstep2(current, segment);
|
|
4993
|
+
if (next === void 0) return void 0;
|
|
4994
|
+
current = next;
|
|
4781
4995
|
}
|
|
4782
|
-
return void 0;
|
|
4996
|
+
return current === void 0 || current === null ? void 0 : String(current);
|
|
4783
4997
|
}
|
|
4784
|
-
function
|
|
4785
|
-
if (
|
|
4786
|
-
|
|
4998
|
+
function pollurl(cursor, value) {
|
|
4999
|
+
if (cursor.param === void 0 || value === void 0) {
|
|
5000
|
+
return { url: cursor.url, ...value !== void 0 ? { body: JSON.stringify({ [cursor.cursorfield]: value }) } : {} };
|
|
5001
|
+
}
|
|
5002
|
+
const url = new URL(cursor.url);
|
|
5003
|
+
url.searchParams.set(cursor.param, value);
|
|
5004
|
+
return { url: url.toString() };
|
|
5005
|
+
}
|
|
5006
|
+
function polldecision(input) {
|
|
5007
|
+
if (input.cancelled?.() === true) return { continue: false, reason: "The long poll loop was cancelled." };
|
|
5008
|
+
if (input.expiresat !== void 0 && input.now >= input.expiresat) return { continue: false, reason: "The long poll loop stopped at the reviewed plan expiry." };
|
|
5009
|
+
const stopvalue = cursorfrom(input.response, input.cursor.stop.field);
|
|
5010
|
+
if (stopvalue !== void 0 && stopvalue === input.cursor.stop.equals) return { continue: false, reason: `The stop condition matched ${input.cursor.stop.field} ${stopvalue}.` };
|
|
5011
|
+
if (input.cursor.maxpolls !== void 0 && input.polls + 1 >= input.cursor.maxpolls) return { continue: false, reason: `The long poll loop reached the reviewed poll ceiling of ${input.cursor.maxpolls}.` };
|
|
5012
|
+
const value = cursorfrom(input.response, input.cursor.cursorfield);
|
|
5013
|
+
const next = pollurl(input.cursor, value);
|
|
5014
|
+
return { continue: true, reason: "The long poll loop continues.", ...value !== void 0 ? { cursor: value } : {}, next: { ...next, wait: input.cursor.interval } };
|
|
4787
5015
|
}
|
|
4788
5016
|
|
|
4789
5017
|
// netwatch.ts
|
|
@@ -4970,17 +5198,191 @@ function extractvalues(body, paths) {
|
|
|
4970
5198
|
return fields.map((field) => ({ path: field.path, ...field.value !== void 0 ? { value: field.value } : {}, ...field.missing ? { missing: true } : {} }));
|
|
4971
5199
|
}
|
|
4972
5200
|
|
|
4973
|
-
//
|
|
4974
|
-
var
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
5201
|
+
// netcontrol.ts
|
|
5202
|
+
var controlkinds = ["blockrequest", "mockresponse", "rewriteheaders", "setcookies", "readcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles"];
|
|
5203
|
+
function patternorigin(pattern) {
|
|
5204
|
+
const trimmed = pattern.trim();
|
|
5205
|
+
if (!trimmed.startsWith("https://")) return void 0;
|
|
5206
|
+
const rest = trimmed.slice("https://".length);
|
|
5207
|
+
const host = rest.split("/")[0] ?? "";
|
|
5208
|
+
if (!host.trim()) return void 0;
|
|
5209
|
+
return `https://${host.toLowerCase()}`;
|
|
4980
5210
|
}
|
|
4981
|
-
function
|
|
4982
|
-
const
|
|
4983
|
-
|
|
5211
|
+
function matchurlpattern(pattern, url) {
|
|
5212
|
+
const origin = patternorigin(pattern);
|
|
5213
|
+
if (!origin) return false;
|
|
5214
|
+
let parsed;
|
|
5215
|
+
try {
|
|
5216
|
+
parsed = new URL(url);
|
|
5217
|
+
} catch {
|
|
5218
|
+
return false;
|
|
5219
|
+
}
|
|
5220
|
+
if (parsed.origin !== origin) return false;
|
|
5221
|
+
const patternpath = pattern.trim().slice(origin.length);
|
|
5222
|
+
if (patternpath === "" || patternpath === "/") return true;
|
|
5223
|
+
const segments = patternpath.split("/").filter((segment) => segment !== "");
|
|
5224
|
+
if (segments.includes("**")) return true;
|
|
5225
|
+
const pathsegments = parsed.pathname.split("/").filter((segment) => segment !== "");
|
|
5226
|
+
if (segments.length !== pathsegments.length) return false;
|
|
5227
|
+
return segments.every((segment, index) => segment === pathsegments[index] || segment.includes("*") && new RegExp(`^${segment.split("*").map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(".*")}$`).test(pathsegments[index] ?? ""));
|
|
5228
|
+
}
|
|
5229
|
+
function blockruleof(value) {
|
|
5230
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5231
|
+
const options = value;
|
|
5232
|
+
if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
|
|
5233
|
+
const rule = { urlpattern: options.urlpattern.trim() };
|
|
5234
|
+
if (Array.isArray(options.resourcetypes)) {
|
|
5235
|
+
const types = options.resourcetypes.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
5236
|
+
if (types.length === 0) return void 0;
|
|
5237
|
+
rule.resourcetypes = types;
|
|
5238
|
+
}
|
|
5239
|
+
return rule;
|
|
5240
|
+
}
|
|
5241
|
+
function newblockrule(input) {
|
|
5242
|
+
return { id: input.id, runid: input.runid, stepid: input.stepid, urlpattern: input.urlpattern, ...input.resourcetypes !== void 0 ? { resourcetypes: input.resourcetypes } : {}, hits: 0, registeredat: input.at };
|
|
5243
|
+
}
|
|
5244
|
+
function mockspecof(value) {
|
|
5245
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5246
|
+
const options = value;
|
|
5247
|
+
if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
|
|
5248
|
+
if (typeof options.status !== "number" || !Number.isInteger(options.status) || options.status < 100 || options.status > 599) return void 0;
|
|
5249
|
+
const hasbody = typeof options.body === "string";
|
|
5250
|
+
const bodyref = typeof options.bodyref === "string" ? options.bodyref.trim() : "";
|
|
5251
|
+
if (!hasbody && bodyref === "") return void 0;
|
|
5252
|
+
const spec = { urlpattern: options.urlpattern.trim(), status: options.status };
|
|
5253
|
+
if (hasbody) spec.body = options.body;
|
|
5254
|
+
if (bodyref !== "") spec.bodyref = bodyref;
|
|
5255
|
+
if (options.headers && typeof options.headers === "object" && !Array.isArray(options.headers)) spec.headers = options.headers;
|
|
5256
|
+
if (options.reviewed === true) spec.reviewed = true;
|
|
5257
|
+
return spec;
|
|
5258
|
+
}
|
|
5259
|
+
function newmockspec(input) {
|
|
5260
|
+
return { id: input.id, runid: input.runid, stepid: input.stepid, urlpattern: input.urlpattern, status: input.status, ...input.headers !== void 0 ? { headers: input.headers } : {}, ...input.body !== void 0 ? { body: input.body } : {}, ...input.bodyref !== void 0 ? { bodyref: input.bodyref } : {}, reviewed: input.reviewed, hits: 0, registeredat: input.at };
|
|
5261
|
+
}
|
|
5262
|
+
function mockfor(url, specs) {
|
|
5263
|
+
return specs.find((spec) => spec.revertedat === void 0 && matchurlpattern(spec.urlpattern, url));
|
|
5264
|
+
}
|
|
5265
|
+
function headeruleof(value) {
|
|
5266
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5267
|
+
const options = value;
|
|
5268
|
+
if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
|
|
5269
|
+
if (typeof options.name !== "string" || !options.name.trim()) return void 0;
|
|
5270
|
+
if (options.operation !== "set" && options.operation !== "append" && options.operation !== "remove") return void 0;
|
|
5271
|
+
if (options.operation === "remove" && options.value !== void 0) return void 0;
|
|
5272
|
+
if (options.operation !== "remove" && typeof options.value !== "string") return void 0;
|
|
5273
|
+
const rule = { urlpattern: options.urlpattern.trim(), name: options.name.trim(), operation: options.operation };
|
|
5274
|
+
if (options.operation !== "remove") rule.value = typeof options.value === "string" ? options.value : "";
|
|
5275
|
+
return rule;
|
|
5276
|
+
}
|
|
5277
|
+
function newheaderule(input) {
|
|
5278
|
+
return { id: input.id, runid: input.runid, stepid: input.stepid, urlpattern: input.urlpattern, name: input.name, operation: input.operation, ...input.value !== void 0 ? { value: input.value } : {}, hits: 0, registeredat: input.at };
|
|
5279
|
+
}
|
|
5280
|
+
function applyheaderules(url, headers, rules) {
|
|
5281
|
+
const rewritten = { ...headers };
|
|
5282
|
+
const applied = [];
|
|
5283
|
+
for (const rule of rules) {
|
|
5284
|
+
if (rule.revertedat !== void 0) continue;
|
|
5285
|
+
if (!matchurlpattern(rule.urlpattern, url)) continue;
|
|
5286
|
+
const name = rule.name;
|
|
5287
|
+
if (rule.operation === "remove") {
|
|
5288
|
+
delete rewritten[name];
|
|
5289
|
+
applied.push(rule);
|
|
5290
|
+
continue;
|
|
5291
|
+
}
|
|
5292
|
+
const value = rule.value ?? "";
|
|
5293
|
+
if (rule.operation === "set") rewritten[name] = value;
|
|
5294
|
+
else rewritten[name] = rewritten[name] !== void 0 ? `${rewritten[name]}, ${value}` : value;
|
|
5295
|
+
applied.push(rule);
|
|
5296
|
+
}
|
|
5297
|
+
return { headers: rewritten, applied };
|
|
5298
|
+
}
|
|
5299
|
+
function revertrule(rule, at) {
|
|
5300
|
+
if (rule.revertedat !== void 0) return rule;
|
|
5301
|
+
return { ...rule, revertedat: at };
|
|
5302
|
+
}
|
|
5303
|
+
function cookierecordof(value) {
|
|
5304
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5305
|
+
const options = value;
|
|
5306
|
+
if (typeof options.name !== "string" || !options.name.trim()) return void 0;
|
|
5307
|
+
if (typeof options.domain !== "string" || !options.domain.trim()) return void 0;
|
|
5308
|
+
if (typeof options.path !== "string" || !options.path.trim()) return void 0;
|
|
5309
|
+
if (typeof options.value !== "string") return void 0;
|
|
5310
|
+
const record2 = { name: options.name.trim(), domain: options.domain.trim().toLowerCase(), path: options.path.trim(), value: options.value };
|
|
5311
|
+
if (typeof options.expiresat === "number" && Number.isFinite(options.expiresat)) record2.expiresat = options.expiresat;
|
|
5312
|
+
return record2;
|
|
5313
|
+
}
|
|
5314
|
+
function cookiedomaingranted(domain, grants) {
|
|
5315
|
+
const host = domain.trim().toLowerCase().replace(/^\./, "");
|
|
5316
|
+
return grants.some((grant) => {
|
|
5317
|
+
let granthost = "";
|
|
5318
|
+
try {
|
|
5319
|
+
granthost = new URL(grant).hostname.toLowerCase();
|
|
5320
|
+
} catch {
|
|
5321
|
+
return false;
|
|
5322
|
+
}
|
|
5323
|
+
return host === granthost || host.endsWith(`.${granthost}`);
|
|
5324
|
+
});
|
|
5325
|
+
}
|
|
5326
|
+
function redactedcookies(records) {
|
|
5327
|
+
return records.map((record2) => ({ name: record2.name, domain: record2.domain, path: record2.path, ...record2.expiresat !== void 0 ? { expiresat: record2.expiresat } : {} }));
|
|
5328
|
+
}
|
|
5329
|
+
function proxyrouteof(value) {
|
|
5330
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5331
|
+
const options = value;
|
|
5332
|
+
if (options.scheme !== "http" && options.scheme !== "https" && options.scheme !== "socks4" && options.scheme !== "socks5") return void 0;
|
|
5333
|
+
if (typeof options.host !== "string" || !options.host.trim()) return void 0;
|
|
5334
|
+
if (typeof options.port !== "number" || !Number.isInteger(options.port) || options.port < 1 || options.port > 65535) return void 0;
|
|
5335
|
+
if (!Array.isArray(options.bypass) || options.bypass.length === 0 || !options.bypass.every((item) => typeof item === "string" && item.trim().length > 0)) return void 0;
|
|
5336
|
+
return { scheme: options.scheme, host: options.host.trim(), port: options.port, bypass: options.bypass.map((item) => item.trim()) };
|
|
5337
|
+
}
|
|
5338
|
+
function ratelimitreadof(headers, origin, now) {
|
|
5339
|
+
const pick = (name) => {
|
|
5340
|
+
for (const key of Object.keys(headers)) {
|
|
5341
|
+
if (key.toLowerCase() !== name) continue;
|
|
5342
|
+
const value = Number(headers[key]);
|
|
5343
|
+
return Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
5344
|
+
}
|
|
5345
|
+
return void 0;
|
|
5346
|
+
};
|
|
5347
|
+
const remaining = pick("x-ratelimit-remaining");
|
|
5348
|
+
const limit = pick("x-ratelimit-limit");
|
|
5349
|
+
const reset = pick("x-ratelimit-reset");
|
|
5350
|
+
if (remaining === void 0 && limit === void 0 && reset === void 0) return void 0;
|
|
5351
|
+
const read = { origin, ...remaining !== void 0 ? { remaining } : {}, ...limit !== void 0 ? { limit } : {}, resetat: now, at: now };
|
|
5352
|
+
if (reset !== void 0) read.resetat = reset > Math.floor(now / 1e3) ? reset * 1e3 : now + reset * 1e3;
|
|
5353
|
+
return read;
|
|
5354
|
+
}
|
|
5355
|
+
function retryafterof(status, headers) {
|
|
5356
|
+
if (status !== 429 && status !== 503) return void 0;
|
|
5357
|
+
for (const key of Object.keys(headers)) {
|
|
5358
|
+
if (key.toLowerCase() !== "retry-after") continue;
|
|
5359
|
+
const raw = headers[key];
|
|
5360
|
+
if (raw === void 0) continue;
|
|
5361
|
+
const value = raw.trim();
|
|
5362
|
+
const seconds = Number(value);
|
|
5363
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
|
|
5364
|
+
const date = Date.parse(value);
|
|
5365
|
+
if (Number.isFinite(date)) return Math.max(0, date - Date.now());
|
|
5366
|
+
return void 0;
|
|
5367
|
+
}
|
|
5368
|
+
return void 0;
|
|
5369
|
+
}
|
|
5370
|
+
function ratelimitwait(state, now) {
|
|
5371
|
+
if (!state) return 0;
|
|
5372
|
+
return Math.max(0, state.resetat - now);
|
|
5373
|
+
}
|
|
5374
|
+
|
|
5375
|
+
// trigger.ts
|
|
5376
|
+
var triggerkinds = ["visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"];
|
|
5377
|
+
var triggerfamilies = ["visit", "url", "menu", "key", "button", "cron", "interval", "urllist", "webhook", "event"];
|
|
5378
|
+
var triggereventcatalog = ["mutate", "focus", "banner", "console", "error", "navigate"];
|
|
5379
|
+
var defaulttriggercooldown = 1e4;
|
|
5380
|
+
function istriggerkind(kind) {
|
|
5381
|
+
return triggerkinds.includes(kind);
|
|
5382
|
+
}
|
|
5383
|
+
function triggerfamilyof(kind) {
|
|
5384
|
+
const index = triggerkinds.indexOf(kind);
|
|
5385
|
+
return index >= 0 ? triggerfamilies[index] : void 0;
|
|
4984
5386
|
}
|
|
4985
5387
|
function triggerlabel(value) {
|
|
4986
5388
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
@@ -5365,42 +5767,177 @@ function ruleoriginsgranted(rule, workfloworigins) {
|
|
|
5365
5767
|
return ruleorigins(rule).every((origin) => granted.has(origin));
|
|
5366
5768
|
}
|
|
5367
5769
|
|
|
5368
|
-
//
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5770
|
+
// netauth.ts
|
|
5771
|
+
function oauthflowof(value) {
|
|
5772
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5773
|
+
const options = value;
|
|
5774
|
+
if (typeof options.provider !== "string" || !options.provider.trim()) return void 0;
|
|
5775
|
+
if (typeof options.authorizeurl !== "string" || !options.authorizeurl.trim()) return void 0;
|
|
5776
|
+
if (typeof options.tokenurl !== "string" || !options.tokenurl.trim()) return void 0;
|
|
5777
|
+
if (!Array.isArray(options.scopes) || options.scopes.length === 0 || !options.scopes.every((item) => typeof item === "string" && item.trim().length > 0)) return void 0;
|
|
5778
|
+
if (typeof options.redirectorigin !== "string" || !options.redirectorigin.trim()) return void 0;
|
|
5779
|
+
return { provider: options.provider.trim(), authorizeurl: options.authorizeurl.trim(), tokenurl: options.tokenurl.trim(), scopes: options.scopes.map((item) => item.trim()), redirectorigin: options.redirectorigin.trim() };
|
|
5374
5780
|
}
|
|
5375
|
-
function
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5781
|
+
function authorizeurl(flow, state) {
|
|
5782
|
+
const url = new URL(flow.authorizeurl);
|
|
5783
|
+
url.searchParams.set("response_type", "code");
|
|
5784
|
+
url.searchParams.set("redirect_uri", flow.redirectorigin);
|
|
5785
|
+
url.searchParams.set("scope", flow.scopes.join(" "));
|
|
5786
|
+
url.searchParams.set("state", state);
|
|
5787
|
+
return url.toString();
|
|
5788
|
+
}
|
|
5789
|
+
function capturecode(url, redirectorigin, state) {
|
|
5790
|
+
let parsed;
|
|
5791
|
+
try {
|
|
5792
|
+
parsed = new URL(url);
|
|
5793
|
+
} catch {
|
|
5794
|
+
return { error: "The redirect url does not parse for the code capture." };
|
|
5380
5795
|
}
|
|
5381
|
-
|
|
5796
|
+
const granted = redirectorigin.includes("/", redirectorigin.indexOf("://") + 3) ? `${parsed.origin}${parsed.pathname}`.startsWith(redirectorigin) : parsed.origin === redirectorigin;
|
|
5797
|
+
if (!granted) return { error: `The redirect landed on ${parsed.origin} outside the granted redirect origin ${redirectorigin}.` };
|
|
5798
|
+
const returned = parsed.searchParams.get("state");
|
|
5799
|
+
if (returned !== state) return { error: "The redirect state token does not match the reviewed flow." };
|
|
5800
|
+
const error = parsed.searchParams.get("error");
|
|
5801
|
+
if (error) return { error: `The provider refused the flow: ${error}.` };
|
|
5802
|
+
const code = parsed.searchParams.get("code");
|
|
5803
|
+
if (!code) return { error: "The redirect carries no authorization code." };
|
|
5804
|
+
return { code };
|
|
5382
5805
|
}
|
|
5383
|
-
function
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5806
|
+
function parsetokens(body) {
|
|
5807
|
+
let parsed;
|
|
5808
|
+
try {
|
|
5809
|
+
parsed = JSON.parse(body);
|
|
5810
|
+
} catch {
|
|
5811
|
+
return void 0;
|
|
5812
|
+
}
|
|
5813
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
5814
|
+
const record2 = parsed;
|
|
5815
|
+
const tokens = {};
|
|
5816
|
+
if (typeof record2.access_token === "string" && record2.access_token) tokens.accesstoken = record2.access_token;
|
|
5817
|
+
if (typeof record2.refresh_token === "string" && record2.refresh_token) tokens.refreshtoken = record2.refresh_token;
|
|
5818
|
+
if (typeof record2.expires_in === "number" && Number.isFinite(record2.expires_in) && record2.expires_in >= 0) tokens.expiresin = record2.expires_in;
|
|
5819
|
+
if (typeof record2.scope === "string" && record2.scope.trim()) tokens.scopes = record2.scope.trim().split(/\s+/);
|
|
5820
|
+
if (tokens.accesstoken === void 0 && tokens.refreshtoken === void 0) return void 0;
|
|
5821
|
+
return tokens;
|
|
5822
|
+
}
|
|
5823
|
+
function tokenrequest(flow, input) {
|
|
5824
|
+
if (input.refreshtoken !== void 0) return { url: flow.tokenurl, body: urlencodeform([{ name: "grant_type", value: "refresh_token" }, { name: "refresh_token", value: input.refreshtoken }]) };
|
|
5825
|
+
return { url: flow.tokenurl, body: urlencodeform([{ name: "grant_type", value: "authorization_code" }, { name: "code", value: input.code ?? "" }, { name: "redirect_uri", value: flow.redirectorigin }]) };
|
|
5826
|
+
}
|
|
5827
|
+
function revocationruleof(value) {
|
|
5828
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5829
|
+
const options = value;
|
|
5830
|
+
if (!Array.isArray(options.tokenids) || options.tokenids.length === 0 || !options.tokenids.every((item) => typeof item === "string" && item.trim().length > 0)) return void 0;
|
|
5831
|
+
if (typeof options.reason !== "string" || !options.reason.trim()) return void 0;
|
|
5832
|
+
return { tokenids: options.tokenids.map((item) => item.trim()), reason: options.reason.trim(), revokedat: Date.now() };
|
|
5833
|
+
}
|
|
5834
|
+
function formpayloadof(value) {
|
|
5835
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5836
|
+
const options = value;
|
|
5837
|
+
if (typeof options.url !== "string" || !options.url.trim()) return void 0;
|
|
5838
|
+
if (!Array.isArray(options.fields) || options.fields.length === 0) return void 0;
|
|
5839
|
+
const fields = [];
|
|
5840
|
+
for (const item of options.fields) {
|
|
5841
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
|
|
5842
|
+
const field = item;
|
|
5843
|
+
if (typeof field.name !== "string" || !field.name.trim()) return void 0;
|
|
5844
|
+
if (typeof field.value !== "string") return void 0;
|
|
5845
|
+
fields.push({ name: field.name.trim(), value: field.value });
|
|
5846
|
+
}
|
|
5847
|
+
return { url: options.url.trim(), fields };
|
|
5848
|
+
}
|
|
5849
|
+
function urlencodeform(fields) {
|
|
5850
|
+
return fields.map((field) => `${formencode(field.name)}=${formencode(field.value)}`).join("&");
|
|
5851
|
+
}
|
|
5852
|
+
function formencode(value) {
|
|
5853
|
+
const bytes = [...new TextEncoder().encode(value)];
|
|
5854
|
+
return bytes.map((byte) => byte >= 65 && byte <= 90 || byte >= 97 && byte <= 122 || byte >= 48 && byte <= 57 || byte === 45 || byte === 95 || byte === 46 || byte === 126 ? String.fromCharCode(byte) : `%${byte.toString(16).toUpperCase().padStart(2, "0")}`).join("");
|
|
5855
|
+
}
|
|
5856
|
+
function multipartpayloadof(value) {
|
|
5857
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5858
|
+
const options = value;
|
|
5859
|
+
if (typeof options.url !== "string" || !options.url.trim()) return void 0;
|
|
5860
|
+
if (!Array.isArray(options.files) || options.files.length === 0) return void 0;
|
|
5861
|
+
const fields = [];
|
|
5862
|
+
for (const item of Array.isArray(options.fields) ? options.fields : []) {
|
|
5863
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
|
|
5864
|
+
const field = item;
|
|
5865
|
+
if (typeof field.name !== "string" || !field.name.trim()) return void 0;
|
|
5866
|
+
if (typeof field.value !== "string") return void 0;
|
|
5867
|
+
fields.push({ name: field.name.trim(), value: field.value });
|
|
5868
|
+
}
|
|
5869
|
+
const files = [];
|
|
5870
|
+
for (const item of options.files) {
|
|
5871
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
|
|
5872
|
+
const file = item;
|
|
5873
|
+
if (typeof file.name !== "string" || !file.name.trim()) return void 0;
|
|
5874
|
+
if (typeof file.filename !== "string" || !file.filename.trim()) return void 0;
|
|
5875
|
+
if (typeof file.mime !== "string" || !file.mime.trim()) return void 0;
|
|
5876
|
+
if (typeof file.content !== "string") return void 0;
|
|
5877
|
+
if (file.reviewed !== true) return void 0;
|
|
5878
|
+
files.push({ name: file.name.trim(), filename: file.filename.trim(), mime: file.mime.trim(), content: file.content, reviewed: true });
|
|
5879
|
+
}
|
|
5880
|
+
const payload = { url: options.url.trim(), fields, files, ...typeof options.boundary === "string" && options.boundary.trim() ? { boundary: options.boundary.trim() } : {} };
|
|
5881
|
+
return payload;
|
|
5882
|
+
}
|
|
5883
|
+
function newboundary() {
|
|
5884
|
+
return `----devthink${Math.random().toString(16).slice(2)}${Date.now().toString(16)}`;
|
|
5885
|
+
}
|
|
5886
|
+
function multipartchunks(payload) {
|
|
5887
|
+
const boundary = payload.boundary ?? newboundary();
|
|
5888
|
+
const chunks = [];
|
|
5889
|
+
for (const field of payload.fields) chunks.push(`--${boundary}\r
|
|
5890
|
+
content-disposition: form-data; name="${field.name}"\r
|
|
5891
|
+
\r
|
|
5892
|
+
${field.value}\r
|
|
5893
|
+
`);
|
|
5894
|
+
for (const file of payload.files) chunks.push(`--${boundary}\r
|
|
5895
|
+
content-disposition: form-data; name="${file.name}"; filename="${file.filename}"\r
|
|
5896
|
+
content-type: ${file.mime}\r
|
|
5897
|
+
\r
|
|
5898
|
+
${file.content}\r
|
|
5899
|
+
`);
|
|
5900
|
+
chunks.push(`--${boundary}--\r
|
|
5901
|
+
`);
|
|
5902
|
+
return { chunks, boundary, bytes: chunks.reduce((total, chunk) => total + chunk.length, 0) };
|
|
5903
|
+
}
|
|
5904
|
+
|
|
5905
|
+
// runtimeline.ts
|
|
5906
|
+
var timelinekinds = ["watchconsole", "watcherrors", "watchtasks"];
|
|
5907
|
+
var loglevels = ["error", "warn", "info", "log", "debug", "trace"];
|
|
5908
|
+
var timelinesources = ["console", "error", "rejection", "resource", "longtask", "network", "cdp"];
|
|
5909
|
+
function levelrank(level) {
|
|
5910
|
+
return loglevels.indexOf(level);
|
|
5911
|
+
}
|
|
5912
|
+
function redactconsoletext(text2, patterns) {
|
|
5913
|
+
let redacted = text2;
|
|
5914
|
+
for (const pattern of patterns) {
|
|
5915
|
+
if (!pattern) continue;
|
|
5916
|
+
while (redacted.includes(pattern)) redacted = redacted.replace(pattern, "[redacted]");
|
|
5917
|
+
}
|
|
5918
|
+
return redacted;
|
|
5919
|
+
}
|
|
5920
|
+
function argkind(value) {
|
|
5921
|
+
if (value === null) return "null";
|
|
5922
|
+
if (Array.isArray(value)) return "array";
|
|
5923
|
+
if (value instanceof Error) return "error";
|
|
5924
|
+
switch (typeof value) {
|
|
5925
|
+
case "string":
|
|
5926
|
+
return "string";
|
|
5927
|
+
case "number":
|
|
5928
|
+
return "number";
|
|
5929
|
+
case "boolean":
|
|
5930
|
+
return "boolean";
|
|
5931
|
+
case "bigint":
|
|
5932
|
+
return "bigint";
|
|
5933
|
+
case "symbol":
|
|
5934
|
+
return "symbol";
|
|
5935
|
+
case "function":
|
|
5936
|
+
return "function";
|
|
5937
|
+
case "undefined":
|
|
5938
|
+
return "undefined";
|
|
5939
|
+
default:
|
|
5940
|
+
return "object";
|
|
5404
5941
|
}
|
|
5405
5942
|
}
|
|
5406
5943
|
function serializearg(value, depth) {
|
|
@@ -5498,286 +6035,66 @@ function timelinecounts(entries) {
|
|
|
5498
6035
|
for (const entry of entries) counts[entry.level] = (counts[entry.level] ?? 0) + 1;
|
|
5499
6036
|
return counts;
|
|
5500
6037
|
}
|
|
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
|
-
// socketbus.ts
|
|
5558
|
-
var socketkinds = ["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"];
|
|
5559
|
-
function channelorigin(url) {
|
|
5560
|
-
try {
|
|
5561
|
-
const parsed = new URL(url);
|
|
5562
|
-
const protocol = parsed.protocol === "wss:" ? "https:" : parsed.protocol === "ws:" ? "http:" : parsed.protocol;
|
|
5563
|
-
return `${protocol}//${parsed.host}`;
|
|
5564
|
-
} catch {
|
|
5565
|
-
return "";
|
|
5566
|
-
}
|
|
5567
|
-
}
|
|
5568
|
-
function channeloptionsof(value) {
|
|
5569
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5570
|
-
const entry = value;
|
|
5571
|
-
if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
|
|
5572
|
-
const options = {};
|
|
5573
|
-
if (Array.isArray(entry.protocols)) options.protocols = entry.protocols.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
5574
|
-
if (typeof entry.reconnect === "number" && Number.isFinite(entry.reconnect)) options.reconnect = entry.reconnect;
|
|
5575
|
-
if (typeof entry.backoff === "number" && Number.isFinite(entry.backoff)) options.backoff = entry.backoff;
|
|
5576
|
-
if (typeof entry.backoffceiling === "number" && Number.isFinite(entry.backoffceiling)) options.backoffceiling = entry.backoffceiling;
|
|
5577
|
-
if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime)) options.lifetime = entry.lifetime;
|
|
5578
|
-
return { url: entry.url.trim(), options };
|
|
5579
|
-
}
|
|
5580
|
-
function newchannel(input) {
|
|
5581
|
-
return { id: input.id, runid: input.runid, stepid: input.stepid, kind: input.kind, url: input.url, origin: channelorigin(input.url), state: "connecting", openedat: input.at, sent: 0, received: 0, reconnects: 0, ...input.protocols !== void 0 && input.protocols.length > 0 ? { protocols: [...input.protocols] } : {} };
|
|
5582
|
-
}
|
|
5583
|
-
function reconnectwaits(attempts, base, ceiling) {
|
|
5584
|
-
const count = Math.max(0, Math.floor(attempts));
|
|
5585
|
-
const waits = [];
|
|
5586
|
-
let wait = Math.max(0, base);
|
|
5587
|
-
for (let index = 0; index < count; index += 1) {
|
|
5588
|
-
waits.push(wait);
|
|
5589
|
-
const next = wait * 2;
|
|
5590
|
-
wait = ceiling !== void 0 && Number.isFinite(ceiling) && ceiling >= 0 ? Math.min(next, ceiling) : next;
|
|
5591
|
-
}
|
|
5592
|
-
return waits;
|
|
5593
|
-
}
|
|
5594
|
-
async function openchannel(input) {
|
|
5595
|
-
const sleep = input.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, Math.max(0, milliseconds))));
|
|
5596
|
-
const now = input.now ?? Date.now;
|
|
5597
|
-
const attempts = Math.max(1, Math.floor(input.options.reconnect ?? 0) + 1);
|
|
5598
|
-
const waits = reconnectwaits(attempts - 1, input.options.backoff ?? 0, input.options.backoffceiling);
|
|
5599
|
-
let record2 = { ...input.record, state: "connecting" };
|
|
5600
|
-
let lasterror = "";
|
|
5601
|
-
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
5602
|
-
try {
|
|
5603
|
-
const result = await input.connect(record2.url, record2.protocols ?? []);
|
|
5604
|
-
if (result.open) return { ...record2, state: "open", openedat: now() };
|
|
5605
|
-
lasterror = result.error ?? `closed with code ${result.code ?? 0}`;
|
|
5606
|
-
} catch (error) {
|
|
5607
|
-
lasterror = error instanceof Error ? error.message : String(error);
|
|
5608
|
-
}
|
|
5609
|
-
if (attempt < attempts - 1) {
|
|
5610
|
-
const wait = waits[attempt] ?? 0;
|
|
5611
|
-
if (wait > 0) await sleep(wait);
|
|
5612
|
-
record2 = { ...record2, reconnects: record2.reconnects + 1 };
|
|
5613
|
-
}
|
|
5614
|
-
}
|
|
5615
|
-
return { ...record2, state: "failed", error: lasterror };
|
|
5616
|
-
}
|
|
5617
|
-
function closechannel(record2, at, error) {
|
|
5618
|
-
const state = error !== void 0 ? "failed" : "closed";
|
|
5619
|
-
return { ...record2, state, closedat: at, ...error !== void 0 ? { error } : {} };
|
|
5620
|
-
}
|
|
5621
|
-
function tagmessage(state, channelid, stream, payload, at) {
|
|
5622
|
-
const sequence = (state.sequences[channelid] ?? 0) + 1;
|
|
5623
|
-
const envelope = { channelid, stream, payload, sequence, at };
|
|
5624
|
-
return { state: { sequences: { ...state.sequences, [channelid]: sequence }, queue: state.queue }, envelope };
|
|
5625
|
-
}
|
|
5626
|
-
function publishmessage(state, channelid, stream, payload, at) {
|
|
5627
|
-
return tagmessage(state, channelid, stream, payload, at);
|
|
5628
|
-
}
|
|
5629
|
-
function receivemessage(state, channelid, stream, payload, at) {
|
|
5630
|
-
const tagged = tagmessage(state, channelid, stream, payload, at);
|
|
5631
|
-
return { state: { ...tagged.state, queue: [...state.queue, tagged.envelope] }, envelope: tagged.envelope };
|
|
5632
|
-
}
|
|
5633
|
-
function pathstep2(current, segment) {
|
|
5634
|
-
if (Array.isArray(current) && /^\d+$/.test(segment)) return current[Number.parseInt(segment, 10)];
|
|
5635
|
-
if (current && typeof current === "object" && !Array.isArray(current)) return current[segment];
|
|
5636
|
-
return void 0;
|
|
5637
|
-
}
|
|
5638
|
-
function matchmessage(filter, envelope) {
|
|
5639
|
-
if (!filter) return true;
|
|
5640
|
-
if (filter.stream !== void 0 && filter.stream !== envelope.stream) return false;
|
|
5641
|
-
if (filter.path !== void 0) {
|
|
5642
|
-
try {
|
|
5643
|
-
const parsed = JSON.parse(envelope.payload);
|
|
5644
|
-
let current = parsed;
|
|
5645
|
-
let missing = false;
|
|
5646
|
-
for (const segment of filter.path.split(".")) {
|
|
5647
|
-
const next = pathstep2(current, segment);
|
|
5648
|
-
if (next === void 0) {
|
|
5649
|
-
missing = true;
|
|
5650
|
-
break;
|
|
5651
|
-
}
|
|
5652
|
-
current = next;
|
|
5653
|
-
}
|
|
5654
|
-
if (missing) return false;
|
|
5655
|
-
} catch {
|
|
5656
|
-
return false;
|
|
5657
|
-
}
|
|
5658
|
-
}
|
|
5659
|
-
return true;
|
|
5660
|
-
}
|
|
5661
|
-
function collectmessages(state, channelid, filter) {
|
|
5662
|
-
const limit = filter?.limit !== void 0 && Number.isFinite(filter.limit) && filter.limit >= 1 ? Math.floor(filter.limit) : Number.POSITIVE_INFINITY;
|
|
5663
|
-
const matched = [];
|
|
5664
|
-
const queue = [];
|
|
5665
|
-
for (const envelope of state.queue) {
|
|
5666
|
-
if (envelope.channelid === channelid && matched.length < limit && matchmessage(filter, envelope)) matched.push(envelope);
|
|
5667
|
-
else queue.push(envelope);
|
|
5668
|
-
}
|
|
5669
|
-
return { state: { sequences: state.sequences, queue }, matched };
|
|
5670
|
-
}
|
|
5671
|
-
function sequenceintegrity(envelopes) {
|
|
5672
|
-
const last = /* @__PURE__ */ new Map();
|
|
5673
|
-
const gaps = [];
|
|
5674
|
-
for (const envelope of envelopes) {
|
|
5675
|
-
const expected = (last.get(envelope.channelid) ?? 0) + 1;
|
|
5676
|
-
if (envelope.sequence !== expected) gaps.push({ channelid: envelope.channelid, expected, found: envelope.sequence });
|
|
5677
|
-
last.set(envelope.channelid, Math.max(envelope.sequence, expected));
|
|
5678
|
-
}
|
|
5679
|
-
return { ok: gaps.length === 0, gaps };
|
|
5680
|
-
}
|
|
5681
|
-
function messagefilterof(value) {
|
|
5682
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
5683
|
-
const entry = value;
|
|
5684
|
-
const filter = {};
|
|
5685
|
-
if (typeof entry.stream === "string" && entry.stream.trim()) filter.stream = entry.stream.trim();
|
|
5686
|
-
if (typeof entry.path === "string" && entry.path.trim()) filter.path = entry.path.trim();
|
|
5687
|
-
if (typeof entry.limit === "number" && Number.isFinite(entry.limit) && entry.limit >= 1) filter.limit = Math.floor(entry.limit);
|
|
5688
|
-
return filter;
|
|
5689
|
-
}
|
|
5690
|
-
function parsessetext(text2) {
|
|
5691
|
-
const separator = text2.lastIndexOf("\n\n");
|
|
5692
|
-
const complete = separator === -1 ? "" : text2.slice(0, separator + 2);
|
|
5693
|
-
const rest = separator === -1 ? text2 : text2.slice(separator + 2);
|
|
5694
|
-
const events = [];
|
|
5695
|
-
for (const block of complete.split(/\n\n/)) {
|
|
5696
|
-
const id = [];
|
|
5697
|
-
const names = [];
|
|
5698
|
-
const data = [];
|
|
5699
|
-
let retry;
|
|
5700
|
-
for (const line of block.split("\n")) {
|
|
5701
|
-
if (line === "" || line.startsWith(":")) continue;
|
|
5702
|
-
const colon = line.indexOf(":");
|
|
5703
|
-
const field = colon === -1 ? line : line.slice(0, colon);
|
|
5704
|
-
let value = colon === -1 ? "" : line.slice(colon + 1);
|
|
5705
|
-
if (value.startsWith(" ")) value = value.slice(1);
|
|
5706
|
-
if (field === "id" && value !== "") id.push(value);
|
|
5707
|
-
if (field === "event" && value !== "") names.push(value);
|
|
5708
|
-
if (field === "data") data.push(value);
|
|
5709
|
-
if (field === "retry" && /^\d+$/.test(value)) retry = Number.parseInt(value, 10);
|
|
5710
|
-
}
|
|
5711
|
-
if (id.length === 0 && names.length === 0 && data.length === 0) continue;
|
|
5712
|
-
events.push({ ...id.length > 0 ? { id: id[id.length - 1] } : {}, ...names.length > 0 ? { event: names[names.length - 1] } : {}, data: data.join("\n"), ...retry !== void 0 ? { retry } : {} });
|
|
5713
|
-
}
|
|
5714
|
-
return { events, rest };
|
|
5715
|
-
}
|
|
5716
|
-
function sserequestheaders(record2) {
|
|
5717
|
-
return { accept: "text/event-stream", ...record2.lasteventid !== void 0 && record2.lasteventid !== "" ? { "last-event-id": record2.lasteventid } : {} };
|
|
5718
|
-
}
|
|
5719
|
-
function subscriptionoptionsof(value) {
|
|
5720
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5721
|
-
const entry = value;
|
|
5722
|
-
if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
|
|
5723
|
-
const cancel = entry.cancel;
|
|
5724
|
-
if (!cancel || typeof cancel !== "object" || Array.isArray(cancel)) return void 0;
|
|
5725
|
-
const cancelrecord = cancel;
|
|
5726
|
-
if (cancelrecord.kind !== "stop" && cancelrecord.kind !== "lifetime") return void 0;
|
|
5727
|
-
if (typeof cancelrecord.value !== "string" && typeof cancelrecord.value !== "number") return void 0;
|
|
5728
|
-
const result = { url: entry.url.trim(), cancel: { kind: cancelrecord.kind, value: cancelrecord.value } };
|
|
5729
|
-
if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime) && entry.lifetime > 0) result.lifetime = entry.lifetime;
|
|
5730
|
-
if (typeof entry.lasteventid === "string" && entry.lasteventid.trim()) result.lasteventid = entry.lasteventid.trim();
|
|
5731
|
-
return result;
|
|
5732
|
-
}
|
|
5733
|
-
function pollcursorof(value) {
|
|
5734
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
5735
|
-
const entry = value;
|
|
5736
|
-
if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
|
|
5737
|
-
if (typeof entry.cursorfield !== "string" || !entry.cursorfield.trim()) return void 0;
|
|
5738
|
-
if (typeof entry.interval !== "number" || !Number.isFinite(entry.interval) || entry.interval <= 0) return void 0;
|
|
5739
|
-
const stop = entry.stop;
|
|
5740
|
-
if (!stop || typeof stop !== "object" || Array.isArray(stop)) return void 0;
|
|
5741
|
-
const stoprecord = stop;
|
|
5742
|
-
if (typeof stoprecord.field !== "string" || !stoprecord.field.trim()) return void 0;
|
|
5743
|
-
if (typeof stoprecord.equals !== "string") return void 0;
|
|
5744
|
-
const cursor = { url: entry.url.trim(), cursorfield: entry.cursorfield.trim(), interval: entry.interval, stop: { field: stoprecord.field.trim(), equals: stoprecord.equals } };
|
|
5745
|
-
if (typeof entry.maxpolls === "number" && Number.isFinite(entry.maxpolls) && entry.maxpolls >= 1) cursor.maxpolls = Math.floor(entry.maxpolls);
|
|
5746
|
-
if (typeof entry.param === "string" && entry.param.trim()) cursor.param = entry.param.trim();
|
|
5747
|
-
return cursor;
|
|
5748
|
-
}
|
|
5749
|
-
function cursorfrom(response, field) {
|
|
5750
|
-
let current = response;
|
|
5751
|
-
for (const segment of field.split(".")) {
|
|
5752
|
-
const next = pathstep2(current, segment);
|
|
5753
|
-
if (next === void 0) return void 0;
|
|
5754
|
-
current = next;
|
|
5755
|
-
}
|
|
5756
|
-
return current === void 0 || current === null ? void 0 : String(current);
|
|
6038
|
+
function blockingduration(tasks, stepid, window) {
|
|
6039
|
+
const inside = tasks.filter((task) => task.starttime >= window.startedat && task.starttime <= window.endedat);
|
|
6040
|
+
return { stepid, blocking: inside.reduce((total, task) => total + task.duration, 0), tasks: inside.length };
|
|
5757
6041
|
}
|
|
5758
|
-
function
|
|
5759
|
-
|
|
5760
|
-
|
|
6042
|
+
function netfailureentryof(input) {
|
|
6043
|
+
const exchange = input.exchange;
|
|
6044
|
+
if (exchange.errorclass === void 0 && exchange.status < 400) return null;
|
|
6045
|
+
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 };
|
|
6046
|
+
}
|
|
6047
|
+
function watcherdetached(input) {
|
|
6048
|
+
for (const navigation of input.navigations) {
|
|
6049
|
+
if (navigation >= input.startedat && navigation <= input.startedat + input.lifetime) return { detached: true, at: navigation };
|
|
5761
6050
|
}
|
|
5762
|
-
|
|
5763
|
-
url.searchParams.set(cursor.param, value);
|
|
5764
|
-
return { url: url.toString() };
|
|
6051
|
+
return { detached: false };
|
|
5765
6052
|
}
|
|
5766
|
-
function
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
const
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
const
|
|
5773
|
-
const
|
|
5774
|
-
|
|
6053
|
+
function consolediff(input) {
|
|
6054
|
+
const base = input.baselines;
|
|
6055
|
+
const target = input.targetlines;
|
|
6056
|
+
const basemap = /* @__PURE__ */ new Map();
|
|
6057
|
+
for (const line of base) basemap.set(line, (basemap.get(line) ?? 0) + 1);
|
|
6058
|
+
const targetmap = /* @__PURE__ */ new Map();
|
|
6059
|
+
for (const line of target) targetmap.set(line, (targetmap.get(line) ?? 0) + 1);
|
|
6060
|
+
const lines = [];
|
|
6061
|
+
const added = [];
|
|
6062
|
+
const removed = [];
|
|
6063
|
+
const repeated = [];
|
|
6064
|
+
for (const [line, count] of targetmap) {
|
|
6065
|
+
const basecount = basemap.get(line) ?? 0;
|
|
6066
|
+
if (basecount === 0) {
|
|
6067
|
+
for (let index = 0; index < count; index += 1) {
|
|
6068
|
+
lines.push({ kind: "added", text: line });
|
|
6069
|
+
added.push(line);
|
|
6070
|
+
}
|
|
6071
|
+
continue;
|
|
6072
|
+
}
|
|
6073
|
+
const share = Math.min(basecount, count);
|
|
6074
|
+
for (let index = 0; index < share; index += 1) {
|
|
6075
|
+
lines.push({ kind: "repeated", text: line, count: share });
|
|
6076
|
+
repeated.push(line);
|
|
6077
|
+
}
|
|
6078
|
+
for (let index = share; index < count; index += 1) {
|
|
6079
|
+
lines.push({ kind: "added", text: line });
|
|
6080
|
+
added.push(line);
|
|
6081
|
+
}
|
|
6082
|
+
}
|
|
6083
|
+
for (const [line, count] of basemap) {
|
|
6084
|
+
const targetcount = targetmap.get(line) ?? 0;
|
|
6085
|
+
const missing = Math.max(0, count - targetcount);
|
|
6086
|
+
for (let index = 0; index < missing; index += 1) {
|
|
6087
|
+
lines.push({ kind: "removed", text: line });
|
|
6088
|
+
removed.push(line);
|
|
6089
|
+
}
|
|
6090
|
+
}
|
|
6091
|
+
return { base: input.baseid, target: input.targetid, lines, added: added.length, removed: removed.length, repeated: repeated.length, at: input.now };
|
|
5775
6092
|
}
|
|
5776
6093
|
|
|
5777
6094
|
// policy.ts
|
|
5778
6095
|
var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract", "batchdownload", "pausedownload", "resumedownload", "interceptmime", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "cleanupartifacts", "recordscreen", "captureaudio", "downloadimages", "callrest", "callgraphql", "sendmessage", "blockrequest", "mockresponse", "rewriteheaders", "setcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles", "attachcdp", "detachcdp", "cdpcmd", "overridescript", "heapshot", "profilecpu", "capturesourcemaps", "emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "restoresession", "exportsessions", "importsessions", "runworkflow", "visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"]);
|
|
5779
6096
|
var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction", "capturebodies", "setbreakpoint", "stepcode", "watchexpr", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"]);
|
|
5780
|
-
var readactions = /* @__PURE__ */ new Set(["observe", "inspect", "extract", "wait", "waitfor", "waittext", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "readlinks", "readimages", "readmeta", "readforms", "readstorage", "highlight", "tablist", "windowlist", "tabsnapshot", "mapclicks", "verifyvisible", "verifyenabled", "resolvexpath", "a11ytree", "readvisible", "readertree", "detectlists", "detecttables", "readjson", "watchmutate", "waitquiet", "watchbanner", "detectinfinitescroll", "detectvirtual", "detectlazy", "readscrollpos", "readlang", "readoutline", "countpages", "listshadow", "listframes", "classifypage", "fingerprintsection", "diffsnapshots", "readselection", "watchfocus", "detectsticky", "detectscrolllock", "readopengraph", "detectlanguage", "deriveselector", "waitload", "waiturl", "spawait", "detecthttp", "readredirects", "readfinalurl", "trailaudit", "navintent", "checksafe", "querytabs", "watchtab", "findclones", "searchtabs", "listaudio", "snapshotsession", "savelayout", "attachmeta", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "readerrors", "skiphoneypot", "detectlogin", "detecttemplate", "handoffcaptcha", "scrapetable", "importcsv", "looprows", "transformvalues", "deduperows", "mergepages", "stamplerows", "previewgrid", "logprovenance", "verifydownload", "exportnetlog", "namecaptures", "shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet", "capturepdf", "captureframe", "readmedia", "readassets", "probestream", "timelapse", "shotcanvas", "convertimage", "makethumbs", "fetchurl", "parsejson", "parsehtml", "opensocket", "waitmessage", "watchrequests", "readheaders", "mapapi", "subscribesse", "longpoll", "extractapi", "readcookies", "watchconsole", "watcherrors", "watchtasks", "watchcdp", "measureflow", "trackmemory", "watchshifts", "traceload", "annotatetrace", "replaytrace", "blackboxscripts", "persiststate", "capturesession", "namedsessions", "diffsessions", "searchsessions", "composeworkflow", "savetemplate", "dryrun", "delay", "waitelement", "compute", "extractvars", "condition", "branch"]);
|
|
6097
|
+
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", "listruns", "condition", "branch"]);
|
|
5781
6098
|
var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
|
|
5782
6099
|
var watchactions = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "watchtab"]);
|
|
5783
6100
|
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"]);
|
|
@@ -8450,12 +8767,375 @@ function canexecute(input) {
|
|
|
8450
8767
|
}
|
|
8451
8768
|
return validatestep(input.step, input.origin);
|
|
8452
8769
|
}
|
|
8770
|
+
function reviewedkinds() {
|
|
8771
|
+
return [...allowedactions].sort();
|
|
8772
|
+
}
|
|
8773
|
+
function editorsavegate(input) {
|
|
8774
|
+
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" });
|
|
8775
|
+
if (!gate.allowed) return gate;
|
|
8776
|
+
if (!input.plan || input.plan.state !== "approved") return { allowed: false, reason: "Editor saves need the approved plan review before a new workflow version composes." };
|
|
8777
|
+
const model = input.model;
|
|
8778
|
+
if (typeof model.name !== "string" || !model.name.trim()) return { allowed: false, reason: "The workflow name of the canvas must be a non-empty string." };
|
|
8779
|
+
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." };
|
|
8780
|
+
if (!Array.isArray(model.origins) || model.origins.length === 0) return { allowed: false, reason: "The canvas needs at least one granted HTTPS origin." };
|
|
8781
|
+
const ids = /* @__PURE__ */ new Set();
|
|
8782
|
+
for (const node of model.nodes) {
|
|
8783
|
+
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." };
|
|
8784
|
+
const id = node.id ?? (node.step !== void 0 ? node.step.id : node.invocation.block);
|
|
8785
|
+
if (!id || ids.has(id)) return { allowed: false, reason: `The canvas node id ${id || "(empty)"} must be unique.` };
|
|
8786
|
+
ids.add(id);
|
|
8787
|
+
}
|
|
8788
|
+
const reachable = /* @__PURE__ */ new Set();
|
|
8789
|
+
for (const node of model.nodes) {
|
|
8790
|
+
if (node.step !== void 0) {
|
|
8791
|
+
reachable.add(node.step.id);
|
|
8792
|
+
continue;
|
|
8793
|
+
}
|
|
8794
|
+
const walk = (entries) => {
|
|
8795
|
+
for (const entry of entries) {
|
|
8796
|
+
if (typeof entry.id === "string" && typeof entry.kind === "string") {
|
|
8797
|
+
reachable.add(entry.id);
|
|
8798
|
+
continue;
|
|
8799
|
+
}
|
|
8800
|
+
if (typeof entry.block === "string") {
|
|
8801
|
+
const nested = model.blocks.find((candidate) => candidate.name === entry.block);
|
|
8802
|
+
if (nested) walk(nested.steps);
|
|
8803
|
+
}
|
|
8804
|
+
}
|
|
8805
|
+
};
|
|
8806
|
+
const block = model.blocks.find((candidate) => candidate.name === node.invocation.block);
|
|
8807
|
+
if (!block) return { allowed: false, reason: `The block ${node.invocation.block} of the canvas has no definition.` };
|
|
8808
|
+
walk(block.steps);
|
|
8809
|
+
}
|
|
8810
|
+
let order = 0;
|
|
8811
|
+
const positionof = /* @__PURE__ */ new Map();
|
|
8812
|
+
for (const node of model.nodes) {
|
|
8813
|
+
if (node.step !== void 0) {
|
|
8814
|
+
positionof.set(node.step.id, order);
|
|
8815
|
+
order += 1;
|
|
8816
|
+
continue;
|
|
8817
|
+
}
|
|
8818
|
+
const walk = (entries) => {
|
|
8819
|
+
for (const entry of entries) {
|
|
8820
|
+
if (typeof entry.id === "string" && typeof entry.kind === "string") {
|
|
8821
|
+
positionof.set(entry.id, order);
|
|
8822
|
+
order += 1;
|
|
8823
|
+
continue;
|
|
8824
|
+
}
|
|
8825
|
+
if (typeof entry.block === "string") {
|
|
8826
|
+
const nested = model.blocks.find((candidate) => candidate.name === entry.block);
|
|
8827
|
+
if (nested) walk(nested.steps);
|
|
8828
|
+
}
|
|
8829
|
+
}
|
|
8830
|
+
};
|
|
8831
|
+
walk(model.blocks.find((candidate) => candidate.name === node.invocation.block).steps);
|
|
8832
|
+
}
|
|
8833
|
+
for (const edge of model.edges) {
|
|
8834
|
+
if (!reachable.has(edge.from)) return { allowed: false, reason: `The canvas edge of ${edge.variable} references the unknown source step ${edge.from}.` };
|
|
8835
|
+
if (!reachable.has(edge.to)) return { allowed: false, reason: `The canvas edge of ${edge.variable} references the unknown target step ${edge.to}.` };
|
|
8836
|
+
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.` };
|
|
8837
|
+
}
|
|
8838
|
+
return { allowed: true };
|
|
8839
|
+
}
|
|
8840
|
+
function runreviewgranted(record2) {
|
|
8841
|
+
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." };
|
|
8842
|
+
return { allowed: true };
|
|
8843
|
+
}
|
|
8844
|
+
var overrideknobs = ["loopbound", "stepms", "runms", "waitms", "delaybase"];
|
|
8845
|
+
function validatesiteoverride(override) {
|
|
8846
|
+
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." };
|
|
8847
|
+
if (!override.pattern.includes("*")) {
|
|
8848
|
+
try {
|
|
8849
|
+
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." };
|
|
8850
|
+
} catch {
|
|
8851
|
+
return { allowed: false, reason: "The override pattern must parse as an https origin or a `*` subdomain glob of one." };
|
|
8852
|
+
}
|
|
8853
|
+
}
|
|
8854
|
+
for (const [knob, delta] of Object.entries(override.deltas)) {
|
|
8855
|
+
if (!overrideknobs.includes(knob)) return { allowed: false, reason: `The override knob ${knob} is not one of the reviewed knobs: ${overrideknobs.join(", ")}.` };
|
|
8856
|
+
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.` };
|
|
8857
|
+
}
|
|
8858
|
+
return { allowed: true };
|
|
8859
|
+
}
|
|
8860
|
+
function exportcontentreview(file) {
|
|
8861
|
+
const secretkeys = /(secret|token|apikey|api_key|password|authorization|credential)/i;
|
|
8862
|
+
const scan = (label, options) => {
|
|
8863
|
+
if (options === void 0) return void 0;
|
|
8864
|
+
let payload;
|
|
8865
|
+
try {
|
|
8866
|
+
payload = JSON.parse(options);
|
|
8867
|
+
} catch {
|
|
8868
|
+
return void 0;
|
|
8869
|
+
}
|
|
8870
|
+
const walk = (value, path) => {
|
|
8871
|
+
if (!value || typeof value !== "object") return void 0;
|
|
8872
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
8873
|
+
if (secretkeys.test(key)) return { allowed: false, reason: `The export of ${label} carries the secret field ${path}${key} and secrets never leave the browser.` };
|
|
8874
|
+
const nested = walk(entry, `${path}${key}.`);
|
|
8875
|
+
if (nested !== void 0) return nested;
|
|
8876
|
+
}
|
|
8877
|
+
return void 0;
|
|
8878
|
+
};
|
|
8879
|
+
return walk(payload, "");
|
|
8880
|
+
};
|
|
8881
|
+
for (const step of file.workflow.steps) {
|
|
8882
|
+
const refusal = scan(`the step ${step.id}`, step.options);
|
|
8883
|
+
if (refusal !== void 0) return refusal;
|
|
8884
|
+
}
|
|
8885
|
+
for (const template of file.templates) {
|
|
8886
|
+
const refusal = scan(`the template ${template.name}`, template.step.options);
|
|
8887
|
+
if (refusal !== void 0) return refusal;
|
|
8888
|
+
}
|
|
8889
|
+
return { allowed: true };
|
|
8890
|
+
}
|
|
8891
|
+
function watchdogconfigvalid(config) {
|
|
8892
|
+
if (typeof config.enabled !== "boolean") return { allowed: false, reason: "The watchdog enabled flag must be a boolean." };
|
|
8893
|
+
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." };
|
|
8894
|
+
if (!["retry", "pause", "cancel"].includes(config.action)) return { allowed: false, reason: "The watchdog recovery action must be retry, pause or cancel." };
|
|
8895
|
+
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." };
|
|
8896
|
+
return { allowed: true };
|
|
8897
|
+
}
|
|
8898
|
+
function validatetoolcatalog(catalog) {
|
|
8899
|
+
if (!Array.isArray(catalog.domains) || catalog.domains.length === 0) return { allowed: false, reason: "The tool catalog needs its tool domains." };
|
|
8900
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8901
|
+
for (const domain of catalog.domains) {
|
|
8902
|
+
if (!toolnamespaces.includes(domain.namespace)) return { allowed: false, reason: `The tool domain ${String(domain.namespace)} is not a reviewed namespace.` };
|
|
8903
|
+
if (!Array.isArray(domain.tools) || domain.tools.length === 0) return { allowed: false, reason: `The ${domain.namespace} domain exposes no tools.` };
|
|
8904
|
+
for (const tool of domain.tools) {
|
|
8905
|
+
if (typeof tool.name !== "string" || !tool.name.startsWith(`${domain.namespace}.`)) return { allowed: false, reason: `The tool ${String(tool.name)} does not carry its ${domain.namespace} namespace prefix.` };
|
|
8906
|
+
if (seen.has(tool.name)) return { allowed: false, reason: `The tool name ${tool.name} is not unique across the catalog.` };
|
|
8907
|
+
seen.add(tool.name);
|
|
8908
|
+
if (!allowedactions.has(tool.kind)) return { allowed: false, reason: `The tool ${tool.name} wraps ${String(tool.kind)} which is outside the reviewed action kind grammar.` };
|
|
8909
|
+
if (!domainkinds[domain.namespace].includes(tool.kind)) return { allowed: false, reason: `The tool ${tool.name} wraps ${String(tool.kind)} which does not belong to the ${domain.namespace} domain.` };
|
|
8910
|
+
if (typeof tool.description !== "string" || tool.description.trim() === "") return { allowed: false, reason: `The tool ${tool.name} needs its plain language description.` };
|
|
8911
|
+
const schema = tool.inputschema;
|
|
8912
|
+
if (!schema || schema.type !== "object" || schema.properties === void 0 || schema.properties === null || typeof schema.properties !== "object" || Array.isArray(schema.properties) || Object.keys(schema.properties).length === 0) return { allowed: false, reason: `The tool ${tool.name} needs its json schema inputs of at least one typed property.` };
|
|
8913
|
+
for (const [name, property] of Object.entries(schema.properties)) {
|
|
8914
|
+
if (!["string", "number", "boolean", "object", "array"].includes(property.type)) return { allowed: false, reason: `The ${tool.name} input ${name} carries an untyped property.` };
|
|
8915
|
+
if (typeof property.description !== "string" || property.description.trim() === "") return { allowed: false, reason: `The ${tool.name} input ${name} needs its plain language description.` };
|
|
8916
|
+
}
|
|
8917
|
+
for (const name of schema.required) {
|
|
8918
|
+
if (!(name in schema.properties)) return { allowed: false, reason: `The tool ${tool.name} marks ${name} required outside its properties.` };
|
|
8919
|
+
}
|
|
8920
|
+
}
|
|
8921
|
+
}
|
|
8922
|
+
return { allowed: true };
|
|
8923
|
+
}
|
|
8924
|
+
function toolriskgrade(tool) {
|
|
8925
|
+
const grade = actionrisk(tool.kind);
|
|
8926
|
+
if (grade !== tool.risk) return { allowed: false, reason: `The tool ${tool.name} declares the ${tool.risk} grade while its kind ${String(tool.kind)} grades ${grade}.` };
|
|
8927
|
+
return { allowed: true };
|
|
8928
|
+
}
|
|
8929
|
+
function toolconsentrequired(tool) {
|
|
8930
|
+
if (tool.risk === "read") return { allowed: true };
|
|
8931
|
+
if (tool.consentmeta === void 0 || typeof tool.consentmeta.review !== "string" || tool.consentmeta.review.trim() === "") return { allowed: false, reason: `The tool ${tool.name} has side effects and needs its consent metadata with the review requirement.` };
|
|
8932
|
+
return { allowed: true };
|
|
8933
|
+
}
|
|
8934
|
+
function serverbindgate(config) {
|
|
8935
|
+
const bind = config.bind !== void 0 && config.bind.trim() !== "" ? config.bind.trim() : "127.0.0.1";
|
|
8936
|
+
const local = bind === "127.0.0.1" || bind === "localhost" || bind === "::1";
|
|
8937
|
+
if (!local && config.remote !== true) return { allowed: false, reason: `The bind ${bind} leaves localhost and grades sensitive: the explicit remote review must approve it first.` };
|
|
8938
|
+
return { allowed: true };
|
|
8939
|
+
}
|
|
8940
|
+
function toolversionfloor(tool, floor) {
|
|
8941
|
+
if (typeof floor === "number" && Number.isFinite(floor) && tool.version < floor) return { allowed: false, reason: `The tool ${tool.name} of version ${tool.version} stays below the negotiated compatibility floor of ${floor}.` };
|
|
8942
|
+
return { allowed: true };
|
|
8943
|
+
}
|
|
8944
|
+
function serverenablementgate(config) {
|
|
8945
|
+
if (config.enabled !== true) return { allowed: false, reason: "The mcp server starts only after the user enables it; the protocol surface stays closed by default." };
|
|
8946
|
+
const bind = serverbindgate(config);
|
|
8947
|
+
if (!bind.allowed) return bind;
|
|
8948
|
+
if (!Array.isArray(config.transports) || config.transports.length === 0) return { allowed: false, reason: "The mcp server needs at least one allowed transport of stdio or http." };
|
|
8949
|
+
if (!config.transports.every((transport) => transport === "stdio" || transport === "http")) return { allowed: false, reason: "The allowed transports of the mcp server are stdio and http." };
|
|
8950
|
+
if (typeof config.port !== "number" || !Number.isFinite(config.port) || config.port <= 0 || config.port > 65535) return { allowed: false, reason: "The http listener port must be a valid port number." };
|
|
8951
|
+
if (config.framesize !== void 0 && (typeof config.framesize !== "number" || !Number.isFinite(config.framesize) || config.framesize <= 0)) return { allowed: false, reason: "The user configured frame size must stay a positive number with no code ceiling." };
|
|
8952
|
+
if (config.queuedepth !== void 0 && (typeof config.queuedepth !== "number" || !Number.isFinite(config.queuedepth) || config.queuedepth <= 0)) return { allowed: false, reason: "The user configured queue depth must stay a positive number with no code ceiling." };
|
|
8953
|
+
return { allowed: true };
|
|
8954
|
+
}
|
|
8955
|
+
function toolnamespacegate(tool) {
|
|
8956
|
+
const namespace = tool.name.split(".")[0];
|
|
8957
|
+
if (!toolnamespaces.includes(namespace)) return { allowed: false, reason: `The tool ${tool.name} carries no reviewed namespace prefix.` };
|
|
8958
|
+
if (!domainkinds[namespace].includes(tool.kind)) return { allowed: false, reason: `The tool ${tool.name} wraps ${String(tool.kind)} which does not belong to the ${namespace} domain.` };
|
|
8959
|
+
return { allowed: true };
|
|
8960
|
+
}
|
|
8961
|
+
function tooldispatchgate(input) {
|
|
8962
|
+
if (input.client.disconnectedat !== void 0) return { allowed: false, reason: "The mcp client is disconnected and its tool calls are refused." };
|
|
8963
|
+
if (!input.client.paired) return { allowed: false, reason: "The mcp client waits for the user pairing approval; unpaired clients never dispatch tools." };
|
|
8964
|
+
if (!input.session || input.session.stoppedat || input.session.pausedat) return { allowed: false, reason: "Tool dispatch needs the live browser session behind the consent gates." };
|
|
8965
|
+
if (input.session.expiresat <= input.now) return { allowed: false, reason: "The browser session has expired and tool dispatch is refused." };
|
|
8966
|
+
if (!input.plan || input.plan.state !== "approved") return { allowed: false, reason: "Tool dispatch needs the approved plan review before any tool runs." };
|
|
8967
|
+
if (!origingranted(input.session, input.origin)) return { allowed: false, reason: `The tool call origin ${input.origin} stays outside the session grants and is refused.` };
|
|
8968
|
+
if (input.tool.risk === "read") return { allowed: true };
|
|
8969
|
+
if (input.stepid === void 0 || input.stepid.trim() === "") return { allowed: false, reason: `The ${input.tool.name} tool has side effects and needs the id of the approved plan step it executes.` };
|
|
8970
|
+
const step = input.plan.steps.find((candidate) => candidate.id === input.stepid);
|
|
8971
|
+
if (step === void 0) return { allowed: false, reason: `The tool call names the step ${input.stepid} which the approved plan does not carry.` };
|
|
8972
|
+
if (step.kind !== input.tool.kind) return { allowed: false, reason: `The tool call names the step ${input.stepid} whose kind ${String(step.kind)} does not match the ${input.tool.name} tool.` };
|
|
8973
|
+
return { allowed: true };
|
|
8974
|
+
}
|
|
8453
8975
|
|
|
8454
|
-
//
|
|
8455
|
-
var
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8976
|
+
// mcpserver.ts
|
|
8977
|
+
var localhostbind = "127.0.0.1";
|
|
8978
|
+
var defaultmcpport = 7436;
|
|
8979
|
+
var rpcerrornumbers = { parse: -32700, method: -32601, params: -32602, internal: -32603, consentrefused: -32001 };
|
|
8980
|
+
function rpcerrorof(code, message, data) {
|
|
8981
|
+
return { code, message, ...data !== void 0 ? { data } : {} };
|
|
8982
|
+
}
|
|
8983
|
+
function rpcerrorcodeof(number) {
|
|
8984
|
+
const entry = Object.entries(rpcerrornumbers).find(([, value]) => value === number);
|
|
8985
|
+
return entry?.[0];
|
|
8986
|
+
}
|
|
8987
|
+
function defaultmcpconfig() {
|
|
8988
|
+
return { port: defaultmcpport, transports: ["stdio", "http"], enabled: false };
|
|
8989
|
+
}
|
|
8990
|
+
function unwraphttppost(value) {
|
|
8991
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
8992
|
+
const candidate = value;
|
|
8993
|
+
if (candidate.transport === "http" && candidate.frame && typeof candidate.frame === "object" && !Array.isArray(candidate.frame)) return candidate.frame;
|
|
8994
|
+
}
|
|
8995
|
+
return value;
|
|
8996
|
+
}
|
|
8997
|
+
function parseframe(raw) {
|
|
8998
|
+
const parsed = unwraphttppost(JSON.parse(raw));
|
|
8999
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("A json rpc frame must be an object.");
|
|
9000
|
+
return parsed;
|
|
9001
|
+
}
|
|
9002
|
+
function parsewire(raw) {
|
|
9003
|
+
return raw.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => parseframe(line));
|
|
9004
|
+
}
|
|
9005
|
+
function serializeframe(frame) {
|
|
9006
|
+
return JSON.stringify(frame);
|
|
9007
|
+
}
|
|
9008
|
+
function wireformat(frame, format) {
|
|
9009
|
+
return format === "newline" ? `${serializeframe(frame)}
|
|
9010
|
+
` : JSON.stringify({ transport: "http", frame });
|
|
9011
|
+
}
|
|
9012
|
+
function validateframe(frame, methods, config) {
|
|
9013
|
+
if (frame.jsonrpc !== "2.0") return rpcerrorof("parse", "The frame must carry the jsonrpc 2.0 tag.");
|
|
9014
|
+
if (frame.id !== void 0 && typeof frame.id !== "number" && typeof frame.id !== "string" && frame.id !== null) return rpcerrorof("parse", "The frame id must be a number, a string or null.");
|
|
9015
|
+
if (frame.method === void 0 || frame.method.trim() === "") return rpcerrorof("method", "The frame carries no method to route.");
|
|
9016
|
+
if (!methods.some((entry) => entry.method === frame.method)) return rpcerrorof("method", `The server routes no method named ${frame.method}.`);
|
|
9017
|
+
if (frame.params !== void 0 && (typeof frame.params !== "object" || Array.isArray(frame.params))) return rpcerrorof("params", "The frame params must be an object.");
|
|
9018
|
+
if (config?.framesize !== void 0 && serializeframe(frame).length > config.framesize) return rpcerrorof("params", `The serialized frame exceeds the user configured frame size of ${config.framesize} characters.`);
|
|
9019
|
+
return void 0;
|
|
9020
|
+
}
|
|
9021
|
+
function respond(input) {
|
|
9022
|
+
return { jsonrpc: "2.0", ...input.id === void 0 ? input.error !== void 0 ? { id: null } : {} : { id: input.id }, ...input.error !== void 0 ? { error: input.error } : { result: input.result } };
|
|
9023
|
+
}
|
|
9024
|
+
function servermethods() {
|
|
9025
|
+
return [
|
|
9026
|
+
{ method: "initialize", handler: "initialize", description: "Completes the mcp handshake and returns the server info." },
|
|
9027
|
+
{ method: "ping", handler: "ping", description: "Answers keepalive frames with pong." },
|
|
9028
|
+
{ method: "tools/list", handler: "listtools", description: "Returns every tool with its version and json schema inputs." },
|
|
9029
|
+
{ method: "negotiate", handler: "negotiate", description: "Exchanges capability sets with the client." },
|
|
9030
|
+
{ method: "tools/call", handler: "dispatch", description: "Invokes one tool behind the consent gates." }
|
|
9031
|
+
];
|
|
9032
|
+
}
|
|
9033
|
+
function servercapabilities(input) {
|
|
9034
|
+
return { protocolversion, name: "devthink", version: protocolversion, toolversion: input.catalog.version, tools: alltools(input.catalog).length, namespaces: toolnamespaces, transports: input.config.transports };
|
|
9035
|
+
}
|
|
9036
|
+
function initialize(input) {
|
|
9037
|
+
void input.params;
|
|
9038
|
+
return { serverinfo: servercapabilities({ config: input.config, catalog: input.catalog }), protocolversion, instructions: "Devthink serves browser tools behind the human review gates: read only tools run once a session is approved while every tool with side effects executes exactly the approved plan step it names. No endpoint, provider or key is hardcoded; the user pairs every client." };
|
|
9039
|
+
}
|
|
9040
|
+
function ping(input) {
|
|
9041
|
+
return { pong: true, at: input.now };
|
|
9042
|
+
}
|
|
9043
|
+
function listtools(catalog) {
|
|
9044
|
+
return { tools: alltools(catalog).map((tool) => ({ name: tool.name, version: tool.version, description: tool.description, inputschema: tool.inputschema, risk: tool.risk, ...tool.consentmeta !== void 0 ? { consentmeta: tool.consentmeta.review } : {} })) };
|
|
9045
|
+
}
|
|
9046
|
+
function negotiate(input) {
|
|
9047
|
+
const client = input.client;
|
|
9048
|
+
if (client?.protocolversion !== void 0 && client.protocolversion !== input.server.protocolversion) return { agreed: false, mismatch: `The client speaks protocol version ${String(client.protocolversion)} while the server offers ${input.server.protocolversion}.` };
|
|
9049
|
+
if (client?.toolversion !== void 0 && client.toolversion > input.server.toolversion) return { agreed: false, mismatch: `The client requires tool version ${String(client.toolversion)} while the server offers ${String(input.server.toolversion)}.` };
|
|
9050
|
+
if (client?.transports !== void 0 && client.transports.some((transport) => !input.server.transports.includes(transport))) return { agreed: false, mismatch: "The client requires a transport the server configuration does not allow." };
|
|
9051
|
+
return { agreed: true, capabilities: input.server };
|
|
9052
|
+
}
|
|
9053
|
+
function connectclient(input) {
|
|
9054
|
+
return { id: input.id ?? `client-${input.now}`, transport: input.transport, paired: false, connectedat: input.now };
|
|
9055
|
+
}
|
|
9056
|
+
function pairclient(clients, id, approved, now) {
|
|
9057
|
+
return clients.map((client) => client.id !== id || client.disconnectedat !== void 0 ? client : approved ? { ...client, paired: true, pairedat: now } : { ...client, paired: false, disconnectedat: now });
|
|
9058
|
+
}
|
|
9059
|
+
function disconnectclient(clients, id, now) {
|
|
9060
|
+
return clients.map((client) => client.id === id && client.disconnectedat === void 0 ? { ...client, disconnectedat: now } : client);
|
|
9061
|
+
}
|
|
9062
|
+
function enqueuerequest(input) {
|
|
9063
|
+
if (input.depth !== void 0 && input.queue.length + 1 > input.depth) return void 0;
|
|
9064
|
+
return [...input.queue, input.frame];
|
|
9065
|
+
}
|
|
9066
|
+
function nextrequest(queue) {
|
|
9067
|
+
return queue.length === 0 ? void 0 : { frame: queue[0], remaining: queue.slice(1) };
|
|
9068
|
+
}
|
|
9069
|
+
async function dispatchtool(input) {
|
|
9070
|
+
const params = input.params;
|
|
9071
|
+
if (!params || typeof params !== "object" || Array.isArray(params)) return { error: rpcerrorof("params", "The tool call needs its params object.") };
|
|
9072
|
+
if (typeof params.name !== "string" || !params.name.trim()) return { error: rpcerrorof("params", "The tool call needs the namespaced name of the tool it invokes.") };
|
|
9073
|
+
const tool = resolvetool(input.catalog, params.name.trim());
|
|
9074
|
+
if (tool === void 0) return { error: rpcerrorof("params", `The catalog holds no unambiguous tool named ${params.name.trim()}.`) };
|
|
9075
|
+
const floor = input.client.capabilities?.toolversion ?? input.catalog.version;
|
|
9076
|
+
if (tool.version < floor) return { error: rpcerrorof("params", `The tool ${tool.name} of version ${tool.version} stays below the negotiated compatibility floor of ${floor}.`) };
|
|
9077
|
+
const stepid = typeof params.stepid === "string" ? params.stepid : void 0;
|
|
9078
|
+
const gate = tooldispatchgate({ client: input.client, tool, session: input.session, plan: input.plan, origin: input.origin, ...stepid !== void 0 ? { stepid } : {}, now: input.now });
|
|
9079
|
+
if (!gate.allowed) return { error: rpcerrorof("consentrefused", gate.reason ?? "The consent gates refused the tool call.") };
|
|
9080
|
+
const step = tool.risk === "read" ? { id: `mcp-${input.client.id}-${input.now}`, kind: tool.kind, summary: tool.description.split(".")[0] ?? tool.description, risk: "read", ...typeof params.target === "string" ? { target: params.target } : {}, ...typeof params.value === "string" ? { value: params.value } : {}, ...params.options !== void 0 && typeof params.options === "object" && !Array.isArray(params.options) ? { options: JSON.stringify(params.options) } : {} } : input.plan?.steps.find((candidate) => candidate.id === stepid);
|
|
9081
|
+
if (step === void 0) return { error: rpcerrorof("consentrefused", "The tool call names a step the approved plan does not carry.") };
|
|
9082
|
+
try {
|
|
9083
|
+
const result = await input.execute(step);
|
|
9084
|
+
return { result, step };
|
|
9085
|
+
} catch (error) {
|
|
9086
|
+
return { error: rpcerrorof("internal", error instanceof Error ? error.message : String(error)) };
|
|
9087
|
+
}
|
|
9088
|
+
}
|
|
9089
|
+
async function handleframe(input) {
|
|
9090
|
+
if (input.raw !== void 0 && input.config.framesize !== void 0 && input.raw.length > input.config.framesize) return respond({ id: null, error: rpcerrorof("params", `The wire frame exceeds the user configured frame size of ${input.config.framesize} characters.`) });
|
|
9091
|
+
let frame;
|
|
9092
|
+
if (input.raw !== void 0) {
|
|
9093
|
+
try {
|
|
9094
|
+
frame = parseframe(input.raw);
|
|
9095
|
+
} catch {
|
|
9096
|
+
return respond({ id: null, error: rpcerrorof("parse", "The wire frame does not parse as json.") });
|
|
9097
|
+
}
|
|
9098
|
+
} else if (input.frame !== void 0) {
|
|
9099
|
+
frame = input.frame;
|
|
9100
|
+
} else {
|
|
9101
|
+
return respond({ id: null, error: rpcerrorof("parse", "The server received no frame to route.") });
|
|
9102
|
+
}
|
|
9103
|
+
const invalid = validateframe(frame, servermethods(), input.config);
|
|
9104
|
+
if (invalid !== void 0) return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, error: invalid });
|
|
9105
|
+
const entry = servermethods().find((candidate) => candidate.method === frame.method);
|
|
9106
|
+
if (entry === void 0) return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, error: rpcerrorof("method", `The server routes no method named ${String(frame.method)}.`) });
|
|
9107
|
+
const params = frame.params;
|
|
9108
|
+
if (entry.handler === "initialize") return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, result: initialize({ ...params !== void 0 ? { params } : {}, config: input.config, catalog: input.catalog }) });
|
|
9109
|
+
if (entry.handler === "ping") return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, result: ping({ now: input.now }) });
|
|
9110
|
+
if (entry.handler === "listtools") return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, result: listtools(input.catalog) });
|
|
9111
|
+
if (entry.handler === "negotiate") {
|
|
9112
|
+
const server = servercapabilities({ config: input.config, catalog: input.catalog });
|
|
9113
|
+
const clientcaps = params?.capabilities && typeof params.capabilities === "object" && !Array.isArray(params.capabilities) ? params.capabilities : void 0;
|
|
9114
|
+
const outcome = negotiate({ ...clientcaps !== void 0 ? { client: clientcaps } : {}, server });
|
|
9115
|
+
return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, ...outcome.agreed ? { result: outcome.capabilities } : { error: rpcerrorof("params", outcome.mismatch ?? "The capability negotiation did not agree.") } });
|
|
9116
|
+
}
|
|
9117
|
+
const dispatched = await dispatchtool({ ...params !== void 0 ? { params } : {}, client: input.client, catalog: input.catalog, ...input.session !== void 0 ? { session: input.session } : {}, ...input.plan !== void 0 ? { plan: input.plan } : {}, origin: input.origin, now: input.now, execute: input.execute });
|
|
9118
|
+
return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, ...dispatched.error !== void 0 ? { error: dispatched.error } : { result: dispatched.result } });
|
|
9119
|
+
}
|
|
9120
|
+
function bindlocalhost(config) {
|
|
9121
|
+
const bind = config.bind !== void 0 && config.bind.trim() !== "" ? config.bind.trim() : localhostbind;
|
|
9122
|
+
return { bind, port: config.port, localhost: bind === localhostbind || bind === "localhost" || bind === "::1" };
|
|
9123
|
+
}
|
|
9124
|
+
function launchbridge(input) {
|
|
9125
|
+
return { id: input.id ?? `bridge-${input.now}`, host: input.host, connected: true, ...input.pid !== void 0 ? { pid: input.pid } : {}, startedat: input.now, restarts: 0, received: 0, sent: 0 };
|
|
9126
|
+
}
|
|
9127
|
+
function relayframe(input) {
|
|
9128
|
+
return { ...input.bridge, connected: true, received: input.bridge.received + (input.direction === "inbound" ? 1 : 0), sent: input.bridge.sent + (input.direction === "outbound" ? 1 : 0), lastframeat: input.now };
|
|
9129
|
+
}
|
|
9130
|
+
function restartbridge(input) {
|
|
9131
|
+
return { ...input.bridge, connected: true, pid: input.pid, restarts: input.bridge.restarts + 1, startedat: input.now };
|
|
9132
|
+
}
|
|
9133
|
+
function framedlog(event, at, fields) {
|
|
9134
|
+
return JSON.stringify({ at, event, ...fields ?? {} });
|
|
9135
|
+
}
|
|
9136
|
+
function toolcallevent(input) {
|
|
9137
|
+
return { id: input.id, clientid: input.clientid, tool: input.tool, origin: input.origin, ok: input.ok, ...input.code !== void 0 ? { code: input.code } : {}, at: input.now };
|
|
9138
|
+
}
|
|
8459
9139
|
|
|
8460
9140
|
// protocol.ts
|
|
8461
9141
|
function record(value) {
|
|
@@ -8852,7 +9532,7 @@ function requestbody(input) {
|
|
|
8852
9532
|
return JSON.stringify({ version: protocolversion, objective: input.objective, session: input.session, observation: input.observation, capabilities: input.capabilities });
|
|
8853
9533
|
}
|
|
8854
9534
|
function outcomeresponse(input) {
|
|
8855
|
-
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, outcome: input.outcome, ...input.resolvedtarget ? { resolvedtarget: input.resolvedtarget } : {}, ...input.capture ? { capture: input.capture } : {}, ...input.media ? { media: input.media } : {}, ...input.transport ? { transport: input.transport } : {}, ...input.network ? { network: input.network } : {}, ...input.control ? { control: input.control } : {}, ...input.timeline ? { timeline: input.timeline } : {}, ...input.cdp ? { cdp: input.cdp } : {}, ...input.profile ? { profile: input.profile } : {}, ...input.emulation ? { emulation: input.emulation } : {}, ...input.session ? { session: input.session } : {}, ...input.workflow ? { workflow: { runid: input.workflow.runid, state: input.workflow.state, ...input.workflow.dryrun === true ? { dryrun: true } : {}, produced: input.workflow.produced, consumed: input.workflow.consumed, ...input.workflow.timeout !== void 0 ? { timeout: input.workflow.timeout } : {}, ...input.workflow.retry !== void 0 ? { retry: input.workflow.retry } : {} } } : {}, ...input.trigger ? { trigger: { ruleid: input.trigger.ruleid, kind: input.trigger.kind, enabled: input.trigger.enabled, ...input.trigger.nextfireat !== void 0 ? { nextfireat: input.trigger.nextfireat } : {} } } : {} });
|
|
9535
|
+
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, outcome: input.outcome, ...input.resolvedtarget ? { resolvedtarget: input.resolvedtarget } : {}, ...input.capture ? { capture: input.capture } : {}, ...input.media ? { media: input.media } : {}, ...input.transport ? { transport: input.transport } : {}, ...input.network ? { network: input.network } : {}, ...input.control ? { control: input.control } : {}, ...input.timeline ? { timeline: input.timeline } : {}, ...input.cdp ? { cdp: input.cdp } : {}, ...input.profile ? { profile: input.profile } : {}, ...input.emulation ? { emulation: input.emulation } : {}, ...input.session ? { session: input.session } : {}, ...input.workflow ? { workflow: { runid: input.workflow.runid, state: input.workflow.state, ...input.workflow.dryrun === true ? { dryrun: true } : {}, produced: input.workflow.produced, consumed: input.workflow.consumed, ...input.workflow.timeout !== void 0 ? { timeout: input.workflow.timeout } : {}, ...input.workflow.retry !== void 0 ? { retry: input.workflow.retry } : {} } } : {}, ...input.trigger ? { trigger: { ruleid: input.trigger.ruleid, kind: input.trigger.kind, enabled: input.trigger.enabled, ...input.trigger.nextfireat !== void 0 ? { nextfireat: input.trigger.nextfireat } : {} } } : {}, ...input.tool ? { tool: { clientid: input.tool.clientid, tool: input.tool.tool, origin: input.tool.origin, ok: input.tool.ok, ...input.tool.code !== void 0 ? { code: input.tool.code } : {} } } : {} });
|
|
8856
9536
|
}
|
|
8857
9537
|
function mapresponse(input) {
|
|
8858
9538
|
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, map: input.map });
|
|
@@ -9049,11 +9729,754 @@ function triggerfired(input) {
|
|
|
9049
9729
|
function manualrunpreview(input) {
|
|
9050
9730
|
return { version: protocolversion, manualrun: input.preview, ...input.workflowname !== void 0 ? { workflowname: input.workflowname } : {} };
|
|
9051
9731
|
}
|
|
9732
|
+
function toolcallframe(input) {
|
|
9733
|
+
return { jsonrpc: "2.0", id: input.id, method: "tools/call", params: { ...input.params ?? {}, name: input.name } };
|
|
9734
|
+
}
|
|
9735
|
+
function toolresultframe(input) {
|
|
9736
|
+
return { jsonrpc: "2.0", id: input.id, ...input.error !== void 0 ? { error: input.error } : { result: input.result } };
|
|
9737
|
+
}
|
|
9738
|
+
var workflowfileversion = 1;
|
|
9739
|
+
function editorstate(input) {
|
|
9740
|
+
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 } };
|
|
9741
|
+
return { version: protocolversion, editor, ...input.model !== void 0 ? { model: input.model } : {} };
|
|
9742
|
+
}
|
|
9743
|
+
function runhistoryquery(value) {
|
|
9744
|
+
if (value === void 0 || value === null) return {};
|
|
9745
|
+
const candidate = record(value);
|
|
9746
|
+
const query = {};
|
|
9747
|
+
if (candidate.workflowid !== void 0) {
|
|
9748
|
+
if (typeof candidate.workflowid !== "string" || !candidate.workflowid.trim()) throw new Error("The run history workflow filter must be a non-empty string.");
|
|
9749
|
+
query.workflowid = candidate.workflowid;
|
|
9750
|
+
}
|
|
9751
|
+
if (candidate.outcome !== void 0) {
|
|
9752
|
+
if (typeof candidate.outcome !== "string" || !candidate.outcome.trim()) throw new Error("The run history outcome filter must be a non-empty string.");
|
|
9753
|
+
query.outcome = candidate.outcome;
|
|
9754
|
+
}
|
|
9755
|
+
if (candidate.since !== void 0) {
|
|
9756
|
+
if (typeof candidate.since !== "number" || !Number.isFinite(candidate.since)) throw new Error("The run history time floor must be a finite timestamp.");
|
|
9757
|
+
query.since = candidate.since;
|
|
9758
|
+
}
|
|
9759
|
+
if (candidate.limit !== void 0) {
|
|
9760
|
+
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.");
|
|
9761
|
+
query.limit = candidate.limit;
|
|
9762
|
+
}
|
|
9763
|
+
return query;
|
|
9764
|
+
}
|
|
9765
|
+
function runhistoryreport(input) {
|
|
9766
|
+
return { version: protocolversion, entries: input.entries, query: input.query ?? {} };
|
|
9767
|
+
}
|
|
9768
|
+
|
|
9769
|
+
// workfloweditor.ts
|
|
9770
|
+
var palettecategories = ["actions", "controlflow", "waits", "variables", "triggers"];
|
|
9771
|
+
var palettenodes = [
|
|
9772
|
+
{ kind: "click", label: "Click an element", category: "actions", description: "Clicks the reviewed selector target." },
|
|
9773
|
+
{ kind: "type", label: "Type text", category: "actions", description: "Types the reviewed text into the target field." },
|
|
9774
|
+
{ kind: "navigate", label: "Navigate", category: "actions", description: "Navigates the tab to the reviewed url." },
|
|
9775
|
+
{ kind: "readtext", label: "Read text", category: "actions", description: "Reads the text of the target element." },
|
|
9776
|
+
{ kind: "scrapetable", label: "Scrape a table", category: "actions", description: "Extracts the reviewed table into a dataset." },
|
|
9777
|
+
{ kind: "fillform", label: "Fill a form", category: "actions", description: "Fills the reviewed form fields from a saved profile." },
|
|
9778
|
+
{ kind: "querytabs", label: "Query tabs", category: "actions", description: "Lists the tabs matching the reviewed query." },
|
|
9779
|
+
{ kind: "fetchurl", label: "Fetch a url", category: "actions", description: "Fetches the reviewed endpoint behind the call consent." },
|
|
9780
|
+
{ kind: "condition", label: "Condition", category: "controlflow", description: "Evaluates one reviewed boolean expression with no page side effect." },
|
|
9781
|
+
{ kind: "branch", label: "Branch", category: "controlflow", description: "Chooses one reviewed path by page state with a mandatory else path." },
|
|
9782
|
+
{ kind: "loop", label: "Loop a list", category: "controlflow", description: "Iterates a list variable binding the item and index per pass." },
|
|
9783
|
+
{ kind: "repeatuntil", label: "Repeat until", category: "controlflow", description: "Reruns the body until the convergence expression holds." },
|
|
9784
|
+
{ kind: "whileloop", label: "While loop", category: "controlflow", description: "Loops while the condition holds inside the reviewed bound." },
|
|
9785
|
+
{ kind: "foreach", label: "For each element", category: "controlflow", description: "Iterates the elements of the reviewed selector." },
|
|
9786
|
+
{ kind: "parallel", label: "Parallel branches", category: "controlflow", description: "Runs branches concurrently and joins them under the reviewed strategy." },
|
|
9787
|
+
{ kind: "trycatch", label: "Try catch", category: "controlflow", description: "Wraps fragile steps with a catch handler, retries and timeouts." },
|
|
9788
|
+
{ kind: "delay", label: "Delay", category: "waits", description: "Sleeps the reviewed base inside the jitter window." },
|
|
9789
|
+
{ kind: "waitelement", label: "Wait for element", category: "waits", description: "Polls the reviewed selector until appearance or timeout." },
|
|
9790
|
+
{ kind: "wait", label: "Wait", category: "waits", description: "Waits the reviewed duration." },
|
|
9791
|
+
{ kind: "waitfor", label: "Wait for target", category: "waits", description: "Waits until the reviewed target exists." },
|
|
9792
|
+
{ kind: "waittext", label: "Wait for text", category: "waits", description: "Waits until the reviewed text appears." },
|
|
9793
|
+
{ kind: "waitquiet", label: "Wait for quiet", category: "waits", description: "Waits until the page stops mutating." },
|
|
9794
|
+
{ kind: "waitload", label: "Wait for load", category: "waits", description: "Waits until the navigation settles." },
|
|
9795
|
+
{ kind: "compute", label: "Compute", category: "variables", description: "Evaluates one reviewed expression into the result variable." },
|
|
9796
|
+
{ kind: "extractvars", label: "Extract variables", category: "variables", description: "Applies the reviewed regex and stores the named captures." },
|
|
9797
|
+
{ kind: "savetemplate", label: "Save template", category: "variables", description: "Shares the reviewed step as a reusable template." },
|
|
9798
|
+
{ kind: "visitrule", label: "Visit rule", category: "triggers", description: "Fires on navigations to the reviewed origins." },
|
|
9799
|
+
{ kind: "urlrule", label: "Url rule", category: "triggers", description: "Fires when the url matches the reviewed glob pattern." },
|
|
9800
|
+
{ kind: "cronrule", label: "Cron rule", category: "triggers", description: "Fires on the reviewed five field cron schedule." },
|
|
9801
|
+
{ kind: "intervalrule", label: "Interval rule", category: "triggers", description: "Fires every reviewed period with the jitter spread." },
|
|
9802
|
+
{ kind: "webhookrule", label: "Webhook rule", category: "triggers", description: "Fires on a secret verified webhook delivery." },
|
|
9803
|
+
{ kind: "eventrule", label: "Event rule", category: "triggers", description: "Fires on the observed page events of the catalog." }
|
|
9804
|
+
];
|
|
9805
|
+
var optionschemas = {
|
|
9806
|
+
delay: [{ name: "base", kind: "number", required: true }, { name: "jitter", kind: "number" }],
|
|
9807
|
+
waitelement: [{ name: "timeout", kind: "number" }, { name: "poll", kind: "number" }],
|
|
9808
|
+
compute: [{ name: "expression", kind: "string", required: true }],
|
|
9809
|
+
extractvars: [{ name: "rule", kind: "string", required: true }],
|
|
9810
|
+
composeworkflow: [{ name: "name", kind: "string", required: true }, { name: "version", kind: "number" }],
|
|
9811
|
+
runworkflow: [{ name: "workflowid", kind: "string", required: true }, { name: "reviewed", kind: "boolean", required: true }, { name: "variables", kind: "string" }, { name: "background", kind: "boolean" }],
|
|
9812
|
+
dryrun: [{ name: "workflowid", kind: "string", required: true }],
|
|
9813
|
+
loop: [{ name: "loop", kind: "string", required: true }],
|
|
9814
|
+
repeatuntil: [{ name: "repeatuntil", kind: "string", required: true }],
|
|
9815
|
+
whileloop: [{ name: "whileloop", kind: "string", required: true }],
|
|
9816
|
+
foreach: [{ name: "foreach", kind: "string", required: true }],
|
|
9817
|
+
parallel: [{ name: "parallel", kind: "string", required: true }],
|
|
9818
|
+
trycatch: [{ name: "trycatch", kind: "string", required: true }]
|
|
9819
|
+
};
|
|
9820
|
+
function stepcategory(kind) {
|
|
9821
|
+
if (triggerkinds.includes(kind)) return "triggers";
|
|
9822
|
+
if (controlflowkinds.includes(kind)) return "controlflow";
|
|
9823
|
+
if (kind.startsWith("wait") || kind === "spawait" || kind === "delay") return "waits";
|
|
9824
|
+
if (kind === "compute" || kind === "extractvars" || kind === "savetemplate") return "variables";
|
|
9825
|
+
return "actions";
|
|
9826
|
+
}
|
|
9827
|
+
function buildsteplibrary(kinds) {
|
|
9828
|
+
return [...new Set(kinds)].sort().map((kind) => ({ kind, category: stepcategory(kind), optionschema: optionschemas[kind] ?? [] }));
|
|
9829
|
+
}
|
|
9830
|
+
var noderowheight = 96;
|
|
9831
|
+
var blockcolumnwidth = 280;
|
|
9832
|
+
var canvasoriginx = 40;
|
|
9833
|
+
function snapshotof(model) {
|
|
9834
|
+
const { undo, redo, dirty, ...rest } = model;
|
|
9835
|
+
void undo;
|
|
9836
|
+
void redo;
|
|
9837
|
+
void dirty;
|
|
9838
|
+
return { ...rest, dirty: true };
|
|
9839
|
+
}
|
|
9840
|
+
function withundo(model, next) {
|
|
9841
|
+
const undo = [...model.undo ?? [], snapshotof(model)];
|
|
9842
|
+
const { redo, ...rest } = next;
|
|
9843
|
+
void redo;
|
|
9844
|
+
return { ...rest, dirty: true, undo };
|
|
9845
|
+
}
|
|
9846
|
+
function nodeidof(node) {
|
|
9847
|
+
return node.id ?? (node.step !== void 0 ? node.step.id : node.invocation !== void 0 ? node.invocation.block : "");
|
|
9848
|
+
}
|
|
9849
|
+
function layoutsizeof(nodes) {
|
|
9850
|
+
const width = Math.max(640, ...nodes.map((node) => node.x + blockcolumnwidth)) + 40;
|
|
9851
|
+
const height = Math.max(480, ...nodes.map((node) => node.y + noderowheight)) + 40;
|
|
9852
|
+
return { width, height };
|
|
9853
|
+
}
|
|
9854
|
+
function loadworkflow(record2, layout) {
|
|
9855
|
+
const blocks = record2.blocks.map((block) => ({ ...block, steps: block.steps.map((entry) => ({ ...entry })) }));
|
|
9856
|
+
const blockcolumn = (blockname) => {
|
|
9857
|
+
const index2 = blocks.findIndex((block) => block.name === blockname);
|
|
9858
|
+
return index2 < 0 ? canvasoriginx : canvasoriginx + (index2 + 1) * blockcolumnwidth;
|
|
9859
|
+
};
|
|
9860
|
+
const invocationcount = /* @__PURE__ */ new Map();
|
|
9861
|
+
const nodes = [];
|
|
9862
|
+
const edges = [];
|
|
9863
|
+
let index = 0;
|
|
9864
|
+
while (index < record2.steps.length) {
|
|
9865
|
+
const step = record2.steps[index];
|
|
9866
|
+
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 } : {} });
|
|
9867
|
+
if (step.block === void 0) {
|
|
9868
|
+
const { bindings, block, params: params2, ...rest } = step;
|
|
9869
|
+
void bindings;
|
|
9870
|
+
void block;
|
|
9871
|
+
void params2;
|
|
9872
|
+
nodes.push({ step: { ...rest }, x: canvasoriginx, y: 60 + nodes.length * noderowheight });
|
|
9873
|
+
index += 1;
|
|
9874
|
+
continue;
|
|
9875
|
+
}
|
|
9876
|
+
const blockname = step.block;
|
|
9877
|
+
let end = index;
|
|
9878
|
+
while (end < record2.steps.length && record2.steps[end].block === blockname) end += 1;
|
|
9879
|
+
const region = record2.steps.slice(index, end);
|
|
9880
|
+
const count = (invocationcount.get(blockname) ?? 0) + 1;
|
|
9881
|
+
invocationcount.set(blockname, count);
|
|
9882
|
+
const params = region.flatMap((entry) => entry.params ?? []);
|
|
9883
|
+
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 });
|
|
9884
|
+
index = end;
|
|
9885
|
+
}
|
|
9886
|
+
const size = layouttypeof(nodes, layout);
|
|
9887
|
+
const model = { workflowid: record2.id, name: record2.name, version: record2.version, origins: [...record2.origins], nodes, edges, blocks, layout: size, minimap: emptyminimap(), dirty: false };
|
|
9888
|
+
return { ...model, minimap: renderminimap(model).minimap };
|
|
9889
|
+
}
|
|
9890
|
+
function layouttypeof(nodes, layout) {
|
|
9891
|
+
const size = layoutsizeof(nodes);
|
|
9892
|
+
if (!layout) return { width: size.width, height: size.height, viewportx: 0, viewporty: 0, zoom: 1 };
|
|
9893
|
+
return { width: Math.max(size.width, layout.width), height: Math.max(size.height, layout.height), viewportx: layout.viewportx, viewporty: layout.viewporty, zoom: layout.zoom };
|
|
9894
|
+
}
|
|
9895
|
+
function emptyminimap() {
|
|
9896
|
+
return { width: 160, height: 100, scale: 0, zoom: 1, viewport: { x: 0, y: 0, width: 0, height: 0 } };
|
|
9897
|
+
}
|
|
9898
|
+
function saveworkflow(model, input) {
|
|
9899
|
+
if (typeof model.name !== "string" || !model.name.trim()) throw new Error("The workflow name must be a non-empty string.");
|
|
9900
|
+
if (typeof model.version !== "number" || !Number.isInteger(model.version) || model.version < 1) throw new Error("The workflow version must be a positive integer.");
|
|
9901
|
+
if (!Array.isArray(model.origins) || model.origins.length === 0) throw new Error("A workflow needs at least one granted HTTPS origin.");
|
|
9902
|
+
const ids = /* @__PURE__ */ new Set();
|
|
9903
|
+
for (const node of model.nodes) {
|
|
9904
|
+
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.");
|
|
9905
|
+
const id = nodeidof(node);
|
|
9906
|
+
if (!id || ids.has(id)) throw new Error(`The canvas node id ${id || "(empty)"} must be unique.`);
|
|
9907
|
+
ids.add(id);
|
|
9908
|
+
}
|
|
9909
|
+
const positionof = /* @__PURE__ */ new Map();
|
|
9910
|
+
let position = 0;
|
|
9911
|
+
for (const node of model.nodes) {
|
|
9912
|
+
if (node.step !== void 0) {
|
|
9913
|
+
positionof.set(node.step.id, position);
|
|
9914
|
+
position += 1;
|
|
9915
|
+
continue;
|
|
9916
|
+
}
|
|
9917
|
+
const block = model.blocks.find((entry) => entry.name === node.invocation?.block);
|
|
9918
|
+
if (!block) throw new Error(`The block ${node.invocation?.block ?? ""} of the canvas has no definition.`);
|
|
9919
|
+
const walk = (entries2) => {
|
|
9920
|
+
for (const entry of entries2) {
|
|
9921
|
+
if ("kind" in entry && "label" in entry && !("block" in entry)) {
|
|
9922
|
+
positionof.set(entry.id, position);
|
|
9923
|
+
position += 1;
|
|
9924
|
+
continue;
|
|
9925
|
+
}
|
|
9926
|
+
const nested = model.blocks.find((candidate) => candidate.name === entry.block);
|
|
9927
|
+
if (!nested) throw new Error(`The block ${entry.block} of the canvas has no definition.`);
|
|
9928
|
+
walk(nested.steps);
|
|
9929
|
+
}
|
|
9930
|
+
};
|
|
9931
|
+
walk(block.steps);
|
|
9932
|
+
}
|
|
9933
|
+
for (const edge of model.edges) {
|
|
9934
|
+
if (!positionof.has(edge.from)) throw new Error(`The edge of ${edge.variable} references the unknown source step ${edge.from}.`);
|
|
9935
|
+
if (!positionof.has(edge.to)) throw new Error(`The edge of ${edge.variable} references the unknown target step ${edge.to}.`);
|
|
9936
|
+
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.`);
|
|
9937
|
+
}
|
|
9938
|
+
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 } : {} }));
|
|
9939
|
+
const entries = [];
|
|
9940
|
+
const attached = /* @__PURE__ */ new Map();
|
|
9941
|
+
for (const node of model.nodes) {
|
|
9942
|
+
if (node.invocation !== void 0) {
|
|
9943
|
+
entries.push({ ...node.invocation });
|
|
9944
|
+
continue;
|
|
9945
|
+
}
|
|
9946
|
+
const step = node.step;
|
|
9947
|
+
const bindings = bindingsof(step.id);
|
|
9948
|
+
const { block, params, ...rest } = { ...step, ...bindings.length > 0 ? { bindings } : {} };
|
|
9949
|
+
void params;
|
|
9950
|
+
const carried = rest;
|
|
9951
|
+
if (block !== void 0) {
|
|
9952
|
+
if (!model.blocks.some((candidate) => candidate.name === block)) throw new Error(`The step ${step.id} attaches to the unknown block ${block}.`);
|
|
9953
|
+
const list = attached.get(block) ?? [];
|
|
9954
|
+
list.push(carried);
|
|
9955
|
+
attached.set(block, list);
|
|
9956
|
+
continue;
|
|
9957
|
+
}
|
|
9958
|
+
entries.push(carried);
|
|
9959
|
+
}
|
|
9960
|
+
const blocks = model.blocks.map((block) => {
|
|
9961
|
+
const snapped = attached.get(block.name) ?? [];
|
|
9962
|
+
const snappedids = new Set(snapped.map((step) => step.id));
|
|
9963
|
+
const carried = [];
|
|
9964
|
+
for (const entry of block.steps) {
|
|
9965
|
+
if ("kind" in entry && "label" in entry && !("block" in entry) && snappedids.has(entry.id)) continue;
|
|
9966
|
+
carried.push(entry);
|
|
9967
|
+
}
|
|
9968
|
+
const steps = [...carried, ...snapped];
|
|
9969
|
+
const withbindings = [];
|
|
9970
|
+
for (const entry of steps) {
|
|
9971
|
+
if (!("kind" in entry && "label" in entry && !("block" in entry))) {
|
|
9972
|
+
withbindings.push(entry);
|
|
9973
|
+
continue;
|
|
9974
|
+
}
|
|
9975
|
+
const bindings = bindingsof(entry.id);
|
|
9976
|
+
const { block: inner, params, ...rest } = { ...entry, ...bindings.length > 0 ? { bindings } : {} };
|
|
9977
|
+
void inner;
|
|
9978
|
+
void params;
|
|
9979
|
+
withbindings.push(rest);
|
|
9980
|
+
}
|
|
9981
|
+
return { ...block, steps: withbindings };
|
|
9982
|
+
});
|
|
9983
|
+
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 } : {} });
|
|
9984
|
+
const checked = validateworkflow(composed, input.kindallowed !== void 0 ? { kindallowed: input.kindallowed } : {});
|
|
9985
|
+
if (!checked.allowed) throw new Error(checked.reason ?? "The canvas model failed the workflow grammar.");
|
|
9986
|
+
return composed;
|
|
9987
|
+
}
|
|
9988
|
+
function snapnode(model, nodeid, x, y, grid = 20) {
|
|
9989
|
+
if (!Number.isFinite(grid) || grid <= 0) throw new Error("The snap grid must be a positive number.");
|
|
9990
|
+
const index = model.nodes.findIndex((node2) => nodeidof(node2) === nodeid);
|
|
9991
|
+
if (index < 0) throw new Error(`No canvas node matches ${nodeid}.`);
|
|
9992
|
+
const node = model.nodes[index];
|
|
9993
|
+
if (node.step === void 0) throw new Error("A block invocation node attaches through its own definition, not through snapping.");
|
|
9994
|
+
const snappedx = Math.round(x / grid) * grid;
|
|
9995
|
+
const snappedy = Math.round(y / grid) * grid;
|
|
9996
|
+
let attached;
|
|
9997
|
+
for (const [blockindex, block] of model.blocks.entries()) {
|
|
9998
|
+
const columnx = canvasoriginx + (blockindex + 1) * blockcolumnwidth;
|
|
9999
|
+
if (Math.abs(snappedx - columnx) <= blockcolumnwidth / 2) attached = block.name;
|
|
10000
|
+
}
|
|
10001
|
+
const { block: priorblock, ...rest } = node.step;
|
|
10002
|
+
void priorblock;
|
|
10003
|
+
const step = { ...rest, ...attached !== void 0 ? { block: attached } : {} };
|
|
10004
|
+
const nodes = model.nodes.map((candidate, position) => position === index ? { step, x: snappedx, y: snappedy } : candidate);
|
|
10005
|
+
const size = layouttypeof(nodes, model.layout);
|
|
10006
|
+
const next = { ...model, nodes, layout: size };
|
|
10007
|
+
return withundo(model, { ...next, minimap: renderminimap(next).minimap });
|
|
10008
|
+
}
|
|
10009
|
+
function reordersteps(model, nodeid, index) {
|
|
10010
|
+
const current = model.nodes.findIndex((node) => nodeidof(node) === nodeid);
|
|
10011
|
+
if (current < 0) throw new Error(`No canvas node matches ${nodeid}.`);
|
|
10012
|
+
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.");
|
|
10013
|
+
const nodes = [...model.nodes];
|
|
10014
|
+
const [moved] = nodes.splice(current, 1);
|
|
10015
|
+
if (!moved) throw new Error("The reordered canvas node vanished.");
|
|
10016
|
+
nodes.splice(index, 0, moved);
|
|
10017
|
+
const next = { ...model, nodes };
|
|
10018
|
+
return withundo(model, { ...next, minimap: renderminimap(next).minimap });
|
|
10019
|
+
}
|
|
10020
|
+
function groupselect(model, nodeids, blockname) {
|
|
10021
|
+
if (!/^[a-z][a-z0-9]*$/.test(blockname)) throw new Error("The block name must be a unique lowercase word.");
|
|
10022
|
+
if (model.blocks.some((block) => block.name === blockname)) throw new Error(`The block name ${blockname} already exists on the canvas.`);
|
|
10023
|
+
const selected = nodeids.map((id) => {
|
|
10024
|
+
const node = model.nodes.find((candidate) => nodeidof(candidate) === id);
|
|
10025
|
+
if (!node || node.step === void 0) throw new Error(`The grouping selection must address step nodes; ${id} is not one.`);
|
|
10026
|
+
return node;
|
|
10027
|
+
});
|
|
10028
|
+
if (selected.length === 0) throw new Error("The grouping selection needs at least one step node.");
|
|
10029
|
+
const steps = selected.map((node) => node.step);
|
|
10030
|
+
const blocks = [...model.blocks, { name: blockname, label: blockname, steps: steps.map((step) => ({ ...step })) }];
|
|
10031
|
+
const firstindex = model.nodes.findIndex((node) => nodeidof(node) === nodeids[0]);
|
|
10032
|
+
const invocationnode = { id: blockname, invocation: { block: blockname, label: blockname }, x: selected[0].x, y: selected[0].y };
|
|
10033
|
+
const nodes = [];
|
|
10034
|
+
model.nodes.forEach((node, index) => {
|
|
10035
|
+
if (nodeids.includes(nodeidof(node))) {
|
|
10036
|
+
if (index === firstindex) nodes.push(invocationnode);
|
|
10037
|
+
return;
|
|
10038
|
+
}
|
|
10039
|
+
nodes.push(node);
|
|
10040
|
+
});
|
|
10041
|
+
const next = { ...model, nodes, blocks };
|
|
10042
|
+
return withundo(model, { ...next, minimap: renderminimap(next).minimap });
|
|
10043
|
+
}
|
|
10044
|
+
function expandtemplate(model, template, params = [], index) {
|
|
10045
|
+
const parsed = steptemplateof(template);
|
|
10046
|
+
if (!parsed) throw new Error("The template does not carry one reviewed workflow step.");
|
|
10047
|
+
let id = parsed.step.id;
|
|
10048
|
+
let suffix = 2;
|
|
10049
|
+
const taken = new Set(model.nodes.map((node) => nodeidof(node)));
|
|
10050
|
+
while (taken.has(id)) {
|
|
10051
|
+
id = `${parsed.step.id}${suffix}`;
|
|
10052
|
+
suffix += 1;
|
|
10053
|
+
}
|
|
10054
|
+
const step = { ...parsed.step, id, ...params.length > 0 ? { params: params.map((param) => ({ ...param })) } : {} };
|
|
10055
|
+
const position = index !== void 0 && Number.isInteger(index) && index >= 0 && index <= model.nodes.length ? index : model.nodes.length;
|
|
10056
|
+
const nodes = [...model.nodes.slice(0, position), { step, x: canvasoriginx, y: 60 + position * noderowheight }, ...model.nodes.slice(position)];
|
|
10057
|
+
const next = { ...model, nodes };
|
|
10058
|
+
return withundo(model, { ...next, minimap: renderminimap(next).minimap });
|
|
10059
|
+
}
|
|
10060
|
+
function addnode(model, step, index) {
|
|
10061
|
+
const normalized = workflowstepof(step);
|
|
10062
|
+
if (!normalized) throw new Error("The canvas insertion needs one reviewed workflow step.");
|
|
10063
|
+
let id = normalized.id;
|
|
10064
|
+
let suffix = 2;
|
|
10065
|
+
const taken = new Set(model.nodes.map((node) => nodeidof(node)));
|
|
10066
|
+
while (taken.has(id)) {
|
|
10067
|
+
id = `${normalized.id}${suffix}`;
|
|
10068
|
+
suffix += 1;
|
|
10069
|
+
}
|
|
10070
|
+
const position = index !== void 0 && Number.isInteger(index) && index >= 0 && index <= model.nodes.length ? index : model.nodes.length;
|
|
10071
|
+
const nodes = [...model.nodes.slice(0, position), { step: { ...normalized, id }, x: canvasoriginx, y: 60 + position * noderowheight }, ...model.nodes.slice(position)];
|
|
10072
|
+
const next = { ...model, nodes };
|
|
10073
|
+
return withundo(model, { ...next, minimap: renderminimap(next).minimap });
|
|
10074
|
+
}
|
|
10075
|
+
function editstep(model, step) {
|
|
10076
|
+
const normalized = workflowstepof(step);
|
|
10077
|
+
if (!normalized) throw new Error("The step inspector edit needs one reviewed workflow step.");
|
|
10078
|
+
const index = model.nodes.findIndex((node2) => node2.step?.id === normalized.id);
|
|
10079
|
+
if (index < 0) throw new Error(`No canvas step matches ${normalized.id}.`);
|
|
10080
|
+
const node = model.nodes[index];
|
|
10081
|
+
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);
|
|
10082
|
+
const next = { ...model, nodes };
|
|
10083
|
+
return withundo(model, { ...next, minimap: renderminimap(next).minimap });
|
|
10084
|
+
}
|
|
10085
|
+
function renderminimap(model, width = 160, height = 100) {
|
|
10086
|
+
if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) throw new Error("The mini map size must be positive.");
|
|
10087
|
+
const canvaswidth = Math.max(1, model.layout.width);
|
|
10088
|
+
const canvasheight = Math.max(1, model.layout.height);
|
|
10089
|
+
const scale = Math.min(width / canvaswidth, height / canvasheight);
|
|
10090
|
+
const zoom = model.layout.zoom > 0 ? model.layout.zoom : 1;
|
|
10091
|
+
const visiblewidth = canvaswidth / zoom;
|
|
10092
|
+
const visibleheight = canvasheight / zoom;
|
|
10093
|
+
const viewport = {
|
|
10094
|
+
x: Math.max(0, Math.min(model.layout.viewportx, canvaswidth)) * scale,
|
|
10095
|
+
y: Math.max(0, Math.min(model.layout.viewporty, canvasheight)) * scale,
|
|
10096
|
+
width: visiblewidth * scale,
|
|
10097
|
+
height: visibleheight * scale
|
|
10098
|
+
};
|
|
10099
|
+
const nodes = model.nodes.map((node) => ({ id: nodeidof(node), x: node.x * scale, y: node.y * scale }));
|
|
10100
|
+
return { minimap: { width, height, scale, zoom, viewport }, nodes };
|
|
10101
|
+
}
|
|
10102
|
+
function minimapfocus(model, x, y, width = 160, height = 100) {
|
|
10103
|
+
const projection = renderminimap(model, width, height);
|
|
10104
|
+
if (projection.minimap.scale <= 0) return model;
|
|
10105
|
+
const canvasx = x / projection.minimap.scale;
|
|
10106
|
+
const canvasy = y / projection.minimap.scale;
|
|
10107
|
+
const zoom = model.layout.zoom > 0 ? model.layout.zoom : 1;
|
|
10108
|
+
const visiblewidth = model.layout.width / zoom;
|
|
10109
|
+
const visibleheight = model.layout.height / zoom;
|
|
10110
|
+
const viewportx = Math.max(0, Math.min(canvasx - visiblewidth / 2, Math.max(0, model.layout.width - visiblewidth)));
|
|
10111
|
+
const viewporty = Math.max(0, Math.min(canvasy - visibleheight / 2, Math.max(0, model.layout.height - visibleheight)));
|
|
10112
|
+
const next = { ...model, layout: { ...model.layout, viewportx, viewporty } };
|
|
10113
|
+
return { ...next, minimap: renderminimap(next).minimap };
|
|
10114
|
+
}
|
|
10115
|
+
function zoomcanvas(model, zoom) {
|
|
10116
|
+
if (!Number.isFinite(zoom) || zoom <= 0) throw new Error("The canvas zoom must be a positive number with no code ceiling.");
|
|
10117
|
+
const next = { ...model, layout: { ...model.layout, zoom } };
|
|
10118
|
+
const labelscale = zoom < 1 ? 1 / zoom : 1;
|
|
10119
|
+
return { model: { ...next, minimap: renderminimap(next).minimap }, labelscale };
|
|
10120
|
+
}
|
|
10121
|
+
function searchsteps(model, query) {
|
|
10122
|
+
const needle = query.trim().toLowerCase();
|
|
10123
|
+
if (!needle) return [];
|
|
10124
|
+
const results = [];
|
|
10125
|
+
for (const node of model.nodes) {
|
|
10126
|
+
if (node.step === void 0) continue;
|
|
10127
|
+
const matched = [];
|
|
10128
|
+
if (node.step.label.toLowerCase().includes(needle)) matched.push("label");
|
|
10129
|
+
if (node.step.kind.toLowerCase().includes(needle)) matched.push("kind");
|
|
10130
|
+
const variables = [
|
|
10131
|
+
...model.edges.filter((edge) => edge.to === node.step?.id || edge.from === node.step?.id).map((edge) => edge.variable),
|
|
10132
|
+
...node.step.expression !== void 0 ? [node.step.expression.result] : [],
|
|
10133
|
+
...node.step.extract !== void 0 ? node.step.extract.groups : []
|
|
10134
|
+
];
|
|
10135
|
+
if (variables.some((name) => name.toLowerCase().includes(needle))) matched.push("variable");
|
|
10136
|
+
if (matched.length > 0) results.push({ id: node.step.id, label: node.step.label, kind: node.step.kind, matched });
|
|
10137
|
+
}
|
|
10138
|
+
return results;
|
|
10139
|
+
}
|
|
10140
|
+
function markbreakpoint(model, stepid) {
|
|
10141
|
+
const toggle = (step) => {
|
|
10142
|
+
const { breakpoint, ...rest } = step;
|
|
10143
|
+
void breakpoint;
|
|
10144
|
+
return breakpoint === true ? rest : { ...rest, breakpoint: true };
|
|
10145
|
+
};
|
|
10146
|
+
const index = model.nodes.findIndex((node) => node.step?.id === stepid);
|
|
10147
|
+
if (index >= 0) {
|
|
10148
|
+
const node = model.nodes[index];
|
|
10149
|
+
const step = node.step;
|
|
10150
|
+
const nodes = model.nodes.map((candidate, position) => position === index ? { step: toggle(step), x: candidate.x, y: candidate.y } : candidate);
|
|
10151
|
+
const next2 = { ...model, nodes };
|
|
10152
|
+
return withundo(model, { ...next2, minimap: renderminimap(next2).minimap });
|
|
10153
|
+
}
|
|
10154
|
+
const blocks = model.blocks.map((block) => {
|
|
10155
|
+
const stepindex = block.steps.findIndex((entry) => "kind" in entry && "label" in entry && !("block" in entry) && entry.id === stepid);
|
|
10156
|
+
if (stepindex < 0) return block;
|
|
10157
|
+
const steps = block.steps.map((entry, position) => position === stepindex ? toggle(entry) : entry);
|
|
10158
|
+
return { ...block, steps };
|
|
10159
|
+
});
|
|
10160
|
+
if (blocks.every((block, position) => block === model.blocks[position])) throw new Error(`No canvas step matches ${stepid}.`);
|
|
10161
|
+
const next = { ...model, blocks };
|
|
10162
|
+
return withundo(model, next);
|
|
10163
|
+
}
|
|
10164
|
+
function runtobreakpoint(input) {
|
|
10165
|
+
const cursor = input.cursor !== void 0 && Number.isInteger(input.cursor) && input.cursor >= 0 ? input.cursor : 0;
|
|
10166
|
+
const marked = new Set(input.breakpoints);
|
|
10167
|
+
for (let index = cursor; index < input.record.steps.length; index += 1) {
|
|
10168
|
+
const step = input.record.steps[index];
|
|
10169
|
+
if (step.breakpoint === true || marked.has(step.id)) {
|
|
10170
|
+
return { until: index, pausat: step.id, remaining: input.record.steps.length - index };
|
|
10171
|
+
}
|
|
10172
|
+
}
|
|
10173
|
+
return { until: input.record.steps.length, pausat: void 0, remaining: 0 };
|
|
10174
|
+
}
|
|
10175
|
+
function diffversions(from, to, now) {
|
|
10176
|
+
const fromsteps = new Map(from.steps.map((step) => [step.id, step]));
|
|
10177
|
+
const tosteps = new Map(to.steps.map((step) => [step.id, step]));
|
|
10178
|
+
const added = [];
|
|
10179
|
+
const removed = [];
|
|
10180
|
+
const changed = [];
|
|
10181
|
+
for (const step of to.steps) {
|
|
10182
|
+
const prior = fromsteps.get(step.id);
|
|
10183
|
+
if (!prior) {
|
|
10184
|
+
added.push({ stepid: step.id, kind: step.kind, label: step.label });
|
|
10185
|
+
continue;
|
|
10186
|
+
}
|
|
10187
|
+
const changes = [];
|
|
10188
|
+
if (prior.label !== step.label) changes.push("label");
|
|
10189
|
+
if (prior.kind !== step.kind) changes.push("kind");
|
|
10190
|
+
if (prior.target !== step.target) changes.push("target");
|
|
10191
|
+
if (prior.value !== step.value) changes.push("value");
|
|
10192
|
+
if (prior.options !== step.options) changes.push("options");
|
|
10193
|
+
if (JSON.stringify(prior.expression) !== JSON.stringify(step.expression)) changes.push("expression");
|
|
10194
|
+
if (JSON.stringify(prior.extract) !== JSON.stringify(step.extract)) changes.push("extract");
|
|
10195
|
+
if (JSON.stringify(prior.bindings) !== JSON.stringify(step.bindings)) changes.push("bindings");
|
|
10196
|
+
if (changes.length > 0) changed.push({ stepid: step.id, kind: step.kind, label: step.label, changes });
|
|
10197
|
+
}
|
|
10198
|
+
for (const step of from.steps) {
|
|
10199
|
+
if (!tosteps.has(step.id)) removed.push({ stepid: step.id, kind: step.kind, label: step.label });
|
|
10200
|
+
}
|
|
10201
|
+
return { workflowid: to.id, from: from.version, to: to.version, added, removed, changed, at: now };
|
|
10202
|
+
}
|
|
10203
|
+
function exportworkflow(record2, format, note, now) {
|
|
10204
|
+
const file = { format: workflowfileversion, exportedat: now ?? Date.now(), workflow: record2, ...note !== void 0 && note.trim() !== "" ? { note } : {}, templates: [] };
|
|
10205
|
+
return { format, contents: serializefile(file, format), file };
|
|
10206
|
+
}
|
|
10207
|
+
function shareworkflow(record2, templates, format, note, now) {
|
|
10208
|
+
const file = { format: workflowfileversion, exportedat: now ?? Date.now(), workflow: record2, ...note !== void 0 && note.trim() !== "" ? { note } : {}, templates: templates.map((template) => ({ ...template })) };
|
|
10209
|
+
return { format, contents: serializefile(file, format), file };
|
|
10210
|
+
}
|
|
10211
|
+
function importworkflow(input) {
|
|
10212
|
+
const format = input.format ?? (input.contents.trimStart().startsWith("{") ? "json" : "yaml");
|
|
10213
|
+
const parsed = parsefile(input.contents, format);
|
|
10214
|
+
if (parsed.format !== workflowfileversion) throw new Error(`The workflow file format ${String(parsed.format)} is not the reviewed format ${workflowfileversion}.`);
|
|
10215
|
+
const candidate = parsed.workflow;
|
|
10216
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) throw new Error("The workflow file carries no workflow record.");
|
|
10217
|
+
const fields = candidate;
|
|
10218
|
+
const stepsvalue = fields.steps;
|
|
10219
|
+
if (!Array.isArray(stepsvalue) || stepsvalue.length === 0) throw new Error("An imported workflow needs at least one step.");
|
|
10220
|
+
const steps = [];
|
|
10221
|
+
for (const entry of stepsvalue) {
|
|
10222
|
+
const step = workflowstepof(entry);
|
|
10223
|
+
if (step) {
|
|
10224
|
+
steps.push(step);
|
|
10225
|
+
continue;
|
|
10226
|
+
}
|
|
10227
|
+
throw new Error("Every imported workflow entry must be a reviewed step.");
|
|
10228
|
+
}
|
|
10229
|
+
const composed = composeworkflow({
|
|
10230
|
+
id: typeof fields.id === "string" && fields.id.trim() !== "" ? fields.id : crypto.randomUUID(),
|
|
10231
|
+
name: typeof fields.name === "string" ? fields.name : "",
|
|
10232
|
+
version: typeof fields.version === "number" ? fields.version : 1,
|
|
10233
|
+
origins: Array.isArray(fields.origins) ? fields.origins.filter((origin) => typeof origin === "string") : [],
|
|
10234
|
+
steps,
|
|
10235
|
+
now: input.now ?? Date.now(),
|
|
10236
|
+
...input.kindallowed !== void 0 ? { kindallowed: input.kindallowed } : {},
|
|
10237
|
+
...input.riskof !== void 0 ? { riskof: input.riskof } : {}
|
|
10238
|
+
});
|
|
10239
|
+
const templatesvalue = parsed.templates;
|
|
10240
|
+
if (templatesvalue !== void 0 && !Array.isArray(templatesvalue)) throw new Error("The packed templates of the workflow file must be a list.");
|
|
10241
|
+
const templates = [];
|
|
10242
|
+
for (const entry of templatesvalue ?? []) {
|
|
10243
|
+
const template = steptemplateof(entry);
|
|
10244
|
+
if (!template) throw new Error("A packed template of the workflow file does not carry one reviewed step.");
|
|
10245
|
+
templates.push(template);
|
|
10246
|
+
}
|
|
10247
|
+
const record2 = { ...composed, reviewstate: "pending" };
|
|
10248
|
+
return { record: record2, templates, file: { ...parsed, workflow: record2 } };
|
|
10249
|
+
}
|
|
10250
|
+
function bindparam(model, blockname, param) {
|
|
10251
|
+
if (!/^[a-z][a-z0-9]*$/.test(param.name)) throw new Error("The nested parameter name must be a lowercase word.");
|
|
10252
|
+
const index = model.nodes.findIndex((node2) => node2.invocation?.block === blockname);
|
|
10253
|
+
if (index < 0) throw new Error(`No block invocation of ${blockname} sits on the canvas.`);
|
|
10254
|
+
const node = model.nodes[index];
|
|
10255
|
+
const invocation = node.invocation;
|
|
10256
|
+
const params = [...(invocation.params ?? []).filter((existing) => existing.name !== param.name), { ...param }];
|
|
10257
|
+
const nodes = model.nodes.map((candidate, position) => position === index ? { invocation: { ...invocation, params }, x: candidate.x, y: candidate.y } : candidate);
|
|
10258
|
+
const next = { ...model, nodes };
|
|
10259
|
+
return withundo(model, { ...next, minimap: renderminimap(next).minimap });
|
|
10260
|
+
}
|
|
10261
|
+
function originmatches(pattern, origin) {
|
|
10262
|
+
if (pattern === origin) return true;
|
|
10263
|
+
const glob = pattern.replace(/\./g, "\\.").replace(/\*/g, "[^.]+");
|
|
10264
|
+
if (!glob.startsWith("https://")) return false;
|
|
10265
|
+
return new RegExp(`^${glob}$`).test(origin);
|
|
10266
|
+
}
|
|
10267
|
+
function applyoverride(record2, override) {
|
|
10268
|
+
const matching = record2.origins.filter((origin) => originmatches(override.pattern, origin));
|
|
10269
|
+
if (matching.length === 0) throw new Error(`The override pattern ${override.pattern} matches none of the workflow origins ${record2.origins.join(", ")}.`);
|
|
10270
|
+
const knobs = /* @__PURE__ */ new Set(["loopbound", "stepms", "runms", "waitms", "delaybase"]);
|
|
10271
|
+
for (const knob of Object.keys(override.deltas)) {
|
|
10272
|
+
if (!knobs.has(knob)) throw new Error(`The override knob ${knob} is not one of the reviewed knobs: ${[...knobs].join(", ")}.`);
|
|
10273
|
+
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.`);
|
|
10274
|
+
}
|
|
10275
|
+
const apply = (step) => {
|
|
10276
|
+
if (Object.keys(override.deltas).length === 0) return step;
|
|
10277
|
+
let payload = {};
|
|
10278
|
+
try {
|
|
10279
|
+
payload = step.options !== void 0 ? JSON.parse(step.options) : {};
|
|
10280
|
+
} catch {
|
|
10281
|
+
payload = {};
|
|
10282
|
+
}
|
|
10283
|
+
const bodyof = (key) => payload[key] !== void 0 && typeof payload[key] === "object" && !Array.isArray(payload[key]) ? payload[key] : {};
|
|
10284
|
+
if (override.deltas.loopbound !== void 0 && ["loop", "repeatuntil", "whileloop"].includes(step.kind)) {
|
|
10285
|
+
const body = bodyof(step.kind);
|
|
10286
|
+
body.bound = override.deltas.loopbound;
|
|
10287
|
+
payload[step.kind] = body;
|
|
10288
|
+
}
|
|
10289
|
+
if ((override.deltas.stepms !== void 0 || override.deltas.runms !== void 0) && step.kind === "trycatch") {
|
|
10290
|
+
const body = bodyof("trycatch");
|
|
10291
|
+
const timeout = body.timeout !== void 0 && typeof body.timeout === "object" && !Array.isArray(body.timeout) ? body.timeout : {};
|
|
10292
|
+
if (override.deltas.stepms !== void 0) timeout.stepms = override.deltas.stepms;
|
|
10293
|
+
if (override.deltas.runms !== void 0) timeout.runms = override.deltas.runms;
|
|
10294
|
+
body.timeout = timeout;
|
|
10295
|
+
payload.trycatch = body;
|
|
10296
|
+
}
|
|
10297
|
+
if (override.deltas.waitms !== void 0 && step.kind === "waitelement") {
|
|
10298
|
+
payload.timeout = override.deltas.waitms;
|
|
10299
|
+
}
|
|
10300
|
+
if (override.deltas.delaybase !== void 0 && step.kind === "delay") {
|
|
10301
|
+
payload.base = override.deltas.delaybase;
|
|
10302
|
+
}
|
|
10303
|
+
const changed = Object.keys(payload).length > 0;
|
|
10304
|
+
return changed ? { ...step, options: JSON.stringify(payload) } : step;
|
|
10305
|
+
};
|
|
10306
|
+
return { ...record2, steps: record2.steps.map(apply) };
|
|
10307
|
+
}
|
|
10308
|
+
function addedge(model, edge) {
|
|
10309
|
+
const from = model.nodes.findIndex((node) => nodeidof(node) === edge.from);
|
|
10310
|
+
const to = model.nodes.findIndex((node) => nodeidof(node) === edge.to);
|
|
10311
|
+
if (from < 0) throw new Error(`The canvas edge references the unknown source step ${edge.from}.`);
|
|
10312
|
+
if (to < 0) throw new Error(`The canvas edge references the unknown target step ${edge.to}.`);
|
|
10313
|
+
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.`);
|
|
10314
|
+
if (!/^[a-z][a-z0-9]*$/.test(edge.variable)) throw new Error("The bound variable name must be a lowercase word.");
|
|
10315
|
+
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 } : {} }];
|
|
10316
|
+
const next = { ...model, edges };
|
|
10317
|
+
return withundo(model, next);
|
|
10318
|
+
}
|
|
10319
|
+
function removeedge(model, from, to, variable) {
|
|
10320
|
+
const edges = model.edges.filter((candidate) => !(candidate.from === from && candidate.to === to && candidate.variable === variable));
|
|
10321
|
+
if (edges.length === model.edges.length) throw new Error(`No canvas edge of ${variable} links ${from} into ${to}.`);
|
|
10322
|
+
const next = { ...model, edges };
|
|
10323
|
+
return withundo(model, next);
|
|
10324
|
+
}
|
|
10325
|
+
function removenode(model, nodeid) {
|
|
10326
|
+
const index = model.nodes.findIndex((node) => nodeidof(node) === nodeid);
|
|
10327
|
+
if (index < 0) throw new Error(`No canvas node matches ${nodeid}.`);
|
|
10328
|
+
const nodes = model.nodes.filter((_, position) => position !== index);
|
|
10329
|
+
const edges = model.edges.filter((edge) => edge.from !== nodeid && edge.to !== nodeid);
|
|
10330
|
+
const next = { ...model, nodes, edges };
|
|
10331
|
+
return withundo(model, { ...next, minimap: renderminimap(next).minimap });
|
|
10332
|
+
}
|
|
10333
|
+
function undoedit(model) {
|
|
10334
|
+
const undo = model.undo ?? [];
|
|
10335
|
+
if (undo.length === 0) return model;
|
|
10336
|
+
const previous = undo[undo.length - 1];
|
|
10337
|
+
const current = snapshotof(model);
|
|
10338
|
+
return { ...previous, undo: undo.slice(0, -1), redo: [...model.redo ?? [], current] };
|
|
10339
|
+
}
|
|
10340
|
+
function redoedit(model) {
|
|
10341
|
+
const redo = model.redo ?? [];
|
|
10342
|
+
if (redo.length === 0) return model;
|
|
10343
|
+
const next = redo[redo.length - 1];
|
|
10344
|
+
const current = snapshotof(model);
|
|
10345
|
+
return { ...next, redo: redo.slice(0, -1), undo: [...model.undo ?? [], current] };
|
|
10346
|
+
}
|
|
10347
|
+
function serializefile(file, format) {
|
|
10348
|
+
if (format === "json") return JSON.stringify(file, null, 2);
|
|
10349
|
+
return yamlvalue(file, 0).join("\n") + "\n";
|
|
10350
|
+
}
|
|
10351
|
+
function parsefile(contents, format) {
|
|
10352
|
+
if (format === "json") {
|
|
10353
|
+
const parsed = JSON.parse(contents);
|
|
10354
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("The workflow file is not a json object.");
|
|
10355
|
+
return parsed;
|
|
10356
|
+
}
|
|
10357
|
+
const lines = contents.split(/\r?\n/).map((line) => line.replace(/\t/g, " ")).filter((line) => line.trim() !== "" && !line.trim().startsWith("#"));
|
|
10358
|
+
if (lines.length === 0) throw new Error("The yaml workflow file is empty.");
|
|
10359
|
+
const { value, next } = yamlblock(lines, 0, indentof(lines[0]));
|
|
10360
|
+
if (next < lines.length) throw new Error("The yaml workflow file carries content outside the documented subset.");
|
|
10361
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("The yaml workflow file is not a mapping.");
|
|
10362
|
+
return value;
|
|
10363
|
+
}
|
|
10364
|
+
function indentof(line) {
|
|
10365
|
+
const match = /^ */.exec(line);
|
|
10366
|
+
return match ? match[0].length : 0;
|
|
10367
|
+
}
|
|
10368
|
+
function yamlscalar(value) {
|
|
10369
|
+
if (value === null || value === void 0) return "null";
|
|
10370
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
10371
|
+
return JSON.stringify(String(value));
|
|
10372
|
+
}
|
|
10373
|
+
function yamlvalue(value, indent) {
|
|
10374
|
+
const pad = " ".repeat(indent);
|
|
10375
|
+
if (value === null || value === void 0 || typeof value !== "object") return [`${pad}${yamlscalar(value)}`];
|
|
10376
|
+
if (Array.isArray(value)) {
|
|
10377
|
+
if (value.length === 0) return [`${pad}[]`];
|
|
10378
|
+
const lines2 = [];
|
|
10379
|
+
for (const item of value) {
|
|
10380
|
+
if (item !== null && typeof item === "object") {
|
|
10381
|
+
lines2.push(`${pad}-`);
|
|
10382
|
+
lines2.push(...yamlvalue(item, indent + 2));
|
|
10383
|
+
} else {
|
|
10384
|
+
lines2.push(`${pad}- ${yamlscalar(item)}`);
|
|
10385
|
+
}
|
|
10386
|
+
}
|
|
10387
|
+
return lines2;
|
|
10388
|
+
}
|
|
10389
|
+
const entries = Object.entries(value);
|
|
10390
|
+
if (entries.length === 0) return [`${pad}{}`];
|
|
10391
|
+
const lines = [];
|
|
10392
|
+
for (const [key, entry] of entries) {
|
|
10393
|
+
if (entry !== null && typeof entry === "object") {
|
|
10394
|
+
if (Array.isArray(entry) && entry.length === 0) {
|
|
10395
|
+
lines.push(`${pad}${key}: []`);
|
|
10396
|
+
continue;
|
|
10397
|
+
}
|
|
10398
|
+
if (!Array.isArray(entry) && Object.keys(entry).length === 0) {
|
|
10399
|
+
lines.push(`${pad}${key}: {}`);
|
|
10400
|
+
continue;
|
|
10401
|
+
}
|
|
10402
|
+
lines.push(`${pad}${key}:`);
|
|
10403
|
+
lines.push(...yamlvalue(entry, indent + 2));
|
|
10404
|
+
} else {
|
|
10405
|
+
lines.push(`${pad}${key}: ${yamlscalar(entry)}`);
|
|
10406
|
+
}
|
|
10407
|
+
}
|
|
10408
|
+
return lines;
|
|
10409
|
+
}
|
|
10410
|
+
function yamlblock(lines, start, indent) {
|
|
10411
|
+
const first = lines[start];
|
|
10412
|
+
if (/^\s*-\s/.test(first) || /^\s*-$/.test(first)) {
|
|
10413
|
+
const items = [];
|
|
10414
|
+
let index2 = start;
|
|
10415
|
+
while (index2 < lines.length) {
|
|
10416
|
+
const line = lines[index2];
|
|
10417
|
+
if (indentof(line) !== indent || !/^\s*-\s?/.test(line)) break;
|
|
10418
|
+
const rest = line.slice(indent + 1).trim();
|
|
10419
|
+
if (rest !== "") {
|
|
10420
|
+
items.push(yamlscalarvalue(rest));
|
|
10421
|
+
index2 += 1;
|
|
10422
|
+
continue;
|
|
10423
|
+
}
|
|
10424
|
+
const nested = yamlblock(lines, index2 + 1, indent + 2);
|
|
10425
|
+
items.push(nested.value);
|
|
10426
|
+
index2 = nested.next;
|
|
10427
|
+
}
|
|
10428
|
+
return { value: items, next: index2 };
|
|
10429
|
+
}
|
|
10430
|
+
const mapping = {};
|
|
10431
|
+
let index = start;
|
|
10432
|
+
while (index < lines.length) {
|
|
10433
|
+
const line = lines[index];
|
|
10434
|
+
if (indentof(line) !== indent) break;
|
|
10435
|
+
const match = /^([A-Za-z][A-Za-z0-9]*):(?:\s(.*))?$/.exec(line.slice(indent));
|
|
10436
|
+
if (!match) break;
|
|
10437
|
+
const key = match[1];
|
|
10438
|
+
const rest = match[2];
|
|
10439
|
+
if (rest !== void 0 && rest !== "") {
|
|
10440
|
+
if (rest === "[]") {
|
|
10441
|
+
mapping[key] = [];
|
|
10442
|
+
index += 1;
|
|
10443
|
+
continue;
|
|
10444
|
+
}
|
|
10445
|
+
if (rest === "{}") {
|
|
10446
|
+
mapping[key] = {};
|
|
10447
|
+
index += 1;
|
|
10448
|
+
continue;
|
|
10449
|
+
}
|
|
10450
|
+
mapping[key] = yamlscalarvalue(rest);
|
|
10451
|
+
index += 1;
|
|
10452
|
+
continue;
|
|
10453
|
+
}
|
|
10454
|
+
const nested = yamlblock(lines, index + 1, indent + 2);
|
|
10455
|
+
mapping[key] = nested.value;
|
|
10456
|
+
index = nested.next;
|
|
10457
|
+
}
|
|
10458
|
+
if (index === start) throw new Error("The yaml workflow file left the documented subset.");
|
|
10459
|
+
return { value: mapping, next: index };
|
|
10460
|
+
}
|
|
10461
|
+
function yamlscalarvalue(text2) {
|
|
10462
|
+
if (text2.startsWith('"')) {
|
|
10463
|
+
const parsed = JSON.parse(text2);
|
|
10464
|
+
return typeof parsed === "string" ? parsed : text2;
|
|
10465
|
+
}
|
|
10466
|
+
if (text2 === "true") return true;
|
|
10467
|
+
if (text2 === "false") return false;
|
|
10468
|
+
if (text2 === "null") return null;
|
|
10469
|
+
if (/^-?\d+(?:\.\d+)?$/.test(text2)) return Number(text2);
|
|
10470
|
+
return text2;
|
|
10471
|
+
}
|
|
9052
10472
|
export {
|
|
9053
10473
|
activelayers,
|
|
10474
|
+
addedge,
|
|
10475
|
+
addnode,
|
|
9054
10476
|
agentgrammarvalid,
|
|
9055
10477
|
agentpresetof,
|
|
9056
10478
|
allowlistcovers,
|
|
10479
|
+
alltools,
|
|
9057
10480
|
annotatetrace,
|
|
9058
10481
|
annotationof,
|
|
9059
10482
|
annotationplanof,
|
|
@@ -9063,6 +10486,7 @@ export {
|
|
|
9063
10486
|
applycooldown,
|
|
9064
10487
|
applyheaderules,
|
|
9065
10488
|
applylayer,
|
|
10489
|
+
applyoverride,
|
|
9066
10490
|
applyretry,
|
|
9067
10491
|
applyruntimeout,
|
|
9068
10492
|
applytimeout,
|
|
@@ -9077,6 +10501,8 @@ export {
|
|
|
9077
10501
|
authreport,
|
|
9078
10502
|
autointervalof,
|
|
9079
10503
|
backoffdelay,
|
|
10504
|
+
bindlocalhost,
|
|
10505
|
+
bindparam,
|
|
9080
10506
|
bindvariables,
|
|
9081
10507
|
blackboxedurls,
|
|
9082
10508
|
blackboxmatches,
|
|
@@ -9096,7 +10522,9 @@ export {
|
|
|
9096
10522
|
buildname,
|
|
9097
10523
|
buildpdf,
|
|
9098
10524
|
buildsheet,
|
|
10525
|
+
buildsteplibrary,
|
|
9099
10526
|
buildstitchplan,
|
|
10527
|
+
buildtoolcatalog,
|
|
9100
10528
|
callgraphql,
|
|
9101
10529
|
callrest,
|
|
9102
10530
|
callsreport,
|
|
@@ -9131,6 +10559,7 @@ export {
|
|
|
9131
10559
|
composeworkflow,
|
|
9132
10560
|
conditionof,
|
|
9133
10561
|
confirmmanualrun,
|
|
10562
|
+
connectclient,
|
|
9134
10563
|
consolecapture,
|
|
9135
10564
|
consoleconsentcovers,
|
|
9136
10565
|
consolediff,
|
|
@@ -9160,6 +10589,8 @@ export {
|
|
|
9160
10589
|
debugwaitbudgetallowed,
|
|
9161
10590
|
dedupeimages,
|
|
9162
10591
|
defaultloopbound,
|
|
10592
|
+
defaultmcpconfig,
|
|
10593
|
+
defaultmcpport,
|
|
9163
10594
|
defaulttriggercooldown,
|
|
9164
10595
|
delayjitter,
|
|
9165
10596
|
actionrisk as deriveactionrisk,
|
|
@@ -9168,16 +10599,24 @@ export {
|
|
|
9168
10599
|
diffresponse,
|
|
9169
10600
|
diffreviewgrade,
|
|
9170
10601
|
diffsessionrecords,
|
|
10602
|
+
diffversions,
|
|
10603
|
+
disconnectclient,
|
|
10604
|
+
dispatchtool,
|
|
10605
|
+
domainkinds,
|
|
9171
10606
|
downloadreport,
|
|
9172
10607
|
drainqueue,
|
|
9173
10608
|
dryrunprojection,
|
|
9174
10609
|
dryrunworkflow,
|
|
10610
|
+
editorsavegate,
|
|
10611
|
+
editorstate,
|
|
10612
|
+
editstep,
|
|
9175
10613
|
emugate,
|
|
9176
10614
|
emulationkinds,
|
|
9177
10615
|
emulationreport,
|
|
9178
10616
|
emulationretentionwindow,
|
|
9179
10617
|
emulationstackallowed,
|
|
9180
10618
|
emulationstateof,
|
|
10619
|
+
enqueuerequest,
|
|
9181
10620
|
errorcapture,
|
|
9182
10621
|
errorreportresponse,
|
|
9183
10622
|
evaluatecondition,
|
|
@@ -9186,11 +10625,14 @@ export {
|
|
|
9186
10625
|
eventrulematches,
|
|
9187
10626
|
exchangesreport,
|
|
9188
10627
|
expandblocks,
|
|
10628
|
+
expandtemplate,
|
|
9189
10629
|
expirelayers,
|
|
9190
10630
|
expireprofilerecords,
|
|
9191
10631
|
expiresessions,
|
|
10632
|
+
exportcontentreview,
|
|
9192
10633
|
exportpresetlibrary,
|
|
9193
10634
|
exportsessionfile,
|
|
10635
|
+
exportworkflow,
|
|
9194
10636
|
expressioneval,
|
|
9195
10637
|
expressionof,
|
|
9196
10638
|
expressionoperators,
|
|
@@ -9210,12 +10652,15 @@ export {
|
|
|
9210
10652
|
foreachof,
|
|
9211
10653
|
formpayloadof,
|
|
9212
10654
|
formreportresponse,
|
|
10655
|
+
framedlog,
|
|
9213
10656
|
frameinterval,
|
|
9214
10657
|
generatedvalueallowed,
|
|
9215
10658
|
graphqlopenvelope,
|
|
9216
10659
|
graphqlrequestof,
|
|
10660
|
+
groupselect,
|
|
9217
10661
|
growsampleof,
|
|
9218
10662
|
growthtrend,
|
|
10663
|
+
handleframe,
|
|
9219
10664
|
headerfilterof,
|
|
9220
10665
|
headeruleof,
|
|
9221
10666
|
heapintervalallowed,
|
|
@@ -9230,6 +10675,8 @@ export {
|
|
|
9230
10675
|
imagenames,
|
|
9231
10676
|
importpresetlibrary,
|
|
9232
10677
|
importsessionfile,
|
|
10678
|
+
importworkflow,
|
|
10679
|
+
initialize,
|
|
9233
10680
|
iscdpkind,
|
|
9234
10681
|
iscontrolflowkind,
|
|
9235
10682
|
iscontrolkind,
|
|
@@ -9248,10 +10695,14 @@ export {
|
|
|
9248
10695
|
jsonpathrulesof,
|
|
9249
10696
|
lapseframes,
|
|
9250
10697
|
lapseplanof,
|
|
10698
|
+
launchbridge,
|
|
9251
10699
|
layernames,
|
|
9252
10700
|
layoutreport,
|
|
9253
10701
|
levelrank,
|
|
9254
10702
|
listdue,
|
|
10703
|
+
listtools,
|
|
10704
|
+
loadworkflow,
|
|
10705
|
+
localhostbind,
|
|
9255
10706
|
locationconsentcovers,
|
|
9256
10707
|
locationconsentgate,
|
|
9257
10708
|
locationpresetof,
|
|
@@ -9263,6 +10714,7 @@ export {
|
|
|
9263
10714
|
manualrunpreview,
|
|
9264
10715
|
mapresponse,
|
|
9265
10716
|
mapurlof,
|
|
10717
|
+
markbreakpoint,
|
|
9266
10718
|
matchmessage,
|
|
9267
10719
|
matchurl,
|
|
9268
10720
|
matchurlpattern,
|
|
@@ -9272,11 +10724,14 @@ export {
|
|
|
9272
10724
|
mediareport,
|
|
9273
10725
|
messagefilterof,
|
|
9274
10726
|
methoddomain,
|
|
10727
|
+
minimapfocus,
|
|
9275
10728
|
mockfor,
|
|
9276
10729
|
mockspecof,
|
|
9277
10730
|
multipartchunks,
|
|
9278
10731
|
multipartpayloadof,
|
|
10732
|
+
namespaceof,
|
|
9279
10733
|
navstateresponse,
|
|
10734
|
+
negotiate,
|
|
9280
10735
|
netfailureentryof,
|
|
9281
10736
|
netlogreport,
|
|
9282
10737
|
netwatchkinds,
|
|
@@ -9291,6 +10746,7 @@ export {
|
|
|
9291
10746
|
newsessiondiff,
|
|
9292
10747
|
newsessionrecord,
|
|
9293
10748
|
newworkflowrun,
|
|
10749
|
+
nextrequest,
|
|
9294
10750
|
normalizeendpoint,
|
|
9295
10751
|
oauthflowof,
|
|
9296
10752
|
observationmodeof,
|
|
@@ -9300,13 +10756,18 @@ export {
|
|
|
9300
10756
|
outcomeresponse,
|
|
9301
10757
|
overrideinputof,
|
|
9302
10758
|
overridematches,
|
|
10759
|
+
pairclient,
|
|
9303
10760
|
pairexchange,
|
|
9304
10761
|
pairstates,
|
|
10762
|
+
palettecategories,
|
|
10763
|
+
palettenodes,
|
|
9305
10764
|
parallelof,
|
|
10765
|
+
parseframe,
|
|
9306
10766
|
parsehtmlbody,
|
|
9307
10767
|
parseproposal,
|
|
9308
10768
|
parsessetext,
|
|
9309
10769
|
parsetokens,
|
|
10770
|
+
parsewire,
|
|
9310
10771
|
parseworkflowproposal,
|
|
9311
10772
|
passwordconsentgranted,
|
|
9312
10773
|
patternorigin,
|
|
@@ -9325,6 +10786,7 @@ export {
|
|
|
9325
10786
|
permissionnamevalid,
|
|
9326
10787
|
permissionstates,
|
|
9327
10788
|
permissionstatevalid,
|
|
10789
|
+
ping,
|
|
9328
10790
|
planallowlist,
|
|
9329
10791
|
pollcursorof,
|
|
9330
10792
|
polldecision,
|
|
@@ -9356,18 +10818,27 @@ export {
|
|
|
9356
10818
|
recordwatchvalue,
|
|
9357
10819
|
redactconsoletext,
|
|
9358
10820
|
redactedcookies,
|
|
10821
|
+
redoedit,
|
|
9359
10822
|
regexextract,
|
|
9360
10823
|
regexruleof,
|
|
9361
10824
|
regionsteps,
|
|
9362
10825
|
rejectioncapture,
|
|
10826
|
+
relayframe,
|
|
10827
|
+
removeedge,
|
|
10828
|
+
removenode,
|
|
10829
|
+
renderminimap,
|
|
10830
|
+
reordersteps,
|
|
9363
10831
|
repeatuntilof,
|
|
9364
10832
|
replaytrace,
|
|
9365
10833
|
replayurl,
|
|
9366
10834
|
requestbody,
|
|
9367
10835
|
resolutionverdict,
|
|
9368
10836
|
resolvedrisk,
|
|
10837
|
+
resolvetool,
|
|
9369
10838
|
resolvevariable,
|
|
9370
10839
|
resourcefacts,
|
|
10840
|
+
respond,
|
|
10841
|
+
restartbridge,
|
|
9371
10842
|
restoreoriginsgranted,
|
|
9372
10843
|
restoreplanof,
|
|
9373
10844
|
restorereviewgranted,
|
|
@@ -9377,24 +10848,33 @@ export {
|
|
|
9377
10848
|
revertlayer,
|
|
9378
10849
|
revertplanof,
|
|
9379
10850
|
revertrule,
|
|
10851
|
+
reviewedkinds,
|
|
9380
10852
|
revocationruleof,
|
|
9381
10853
|
rewritesourcelocation,
|
|
9382
10854
|
rotatelogs,
|
|
9383
10855
|
rotationruleof,
|
|
10856
|
+
rpcerrorcodeof,
|
|
10857
|
+
rpcerrornumbers,
|
|
10858
|
+
rpcerrorof,
|
|
9384
10859
|
ruleorigins,
|
|
9385
10860
|
ruleoriginsgranted,
|
|
9386
10861
|
runcatch,
|
|
9387
10862
|
runcontrolstep,
|
|
9388
10863
|
runforeach,
|
|
10864
|
+
runhistoryquery,
|
|
10865
|
+
runhistoryreport,
|
|
9389
10866
|
runloop,
|
|
9390
10867
|
runparallel,
|
|
9391
10868
|
runrepeatuntil,
|
|
10869
|
+
runreviewgranted,
|
|
9392
10870
|
runstep,
|
|
10871
|
+
runtobreakpoint,
|
|
9393
10872
|
runtry,
|
|
9394
10873
|
runurllist,
|
|
9395
10874
|
runwhile,
|
|
9396
10875
|
runworkflow,
|
|
9397
10876
|
safetyresponse,
|
|
10877
|
+
saveworkflow,
|
|
9398
10878
|
scaledrect,
|
|
9399
10879
|
schedulecron,
|
|
9400
10880
|
scheduleinterval,
|
|
@@ -9402,6 +10882,7 @@ export {
|
|
|
9402
10882
|
searchfields,
|
|
9403
10883
|
searchqueryof,
|
|
9404
10884
|
searchsessionrecords,
|
|
10885
|
+
searchsteps,
|
|
9405
10886
|
seededrandom,
|
|
9406
10887
|
selectorresponse,
|
|
9407
10888
|
sendcdpcommand,
|
|
@@ -9409,6 +10890,11 @@ export {
|
|
|
9409
10890
|
sequenceintegrity,
|
|
9410
10891
|
serializearg,
|
|
9411
10892
|
serializecdpcommand,
|
|
10893
|
+
serializeframe,
|
|
10894
|
+
serverbindgate,
|
|
10895
|
+
servercapabilities,
|
|
10896
|
+
serverenablementgate,
|
|
10897
|
+
servermethods,
|
|
9412
10898
|
sessionfileversion,
|
|
9413
10899
|
sessionfolderof,
|
|
9414
10900
|
sessionfolderunique,
|
|
@@ -9419,8 +10905,10 @@ export {
|
|
|
9419
10905
|
sessionrestoregate,
|
|
9420
10906
|
sessiontabof,
|
|
9421
10907
|
setvariable,
|
|
10908
|
+
shareworkflow,
|
|
9422
10909
|
shiftentryof,
|
|
9423
10910
|
signalsreport,
|
|
10911
|
+
snapnode,
|
|
9424
10912
|
snapshotplanof,
|
|
9425
10913
|
snapshotretentionwindow,
|
|
9426
10914
|
snapshotsections,
|
|
@@ -9459,6 +10947,19 @@ export {
|
|
|
9459
10947
|
timelinesources,
|
|
9460
10948
|
timezonevalid,
|
|
9461
10949
|
tokenrequest,
|
|
10950
|
+
toolcallevent,
|
|
10951
|
+
toolcallframe,
|
|
10952
|
+
toolcatalogversion,
|
|
10953
|
+
toolconsentrequired,
|
|
10954
|
+
tooldispatchgate,
|
|
10955
|
+
toolname,
|
|
10956
|
+
toolnamespacegate,
|
|
10957
|
+
toolnamespaces,
|
|
10958
|
+
toolresultframe,
|
|
10959
|
+
toolriskgrade,
|
|
10960
|
+
toolsbynamespace,
|
|
10961
|
+
toolschemaof,
|
|
10962
|
+
toolversionfloor,
|
|
9462
10963
|
tracecategories,
|
|
9463
10964
|
traceceilingof,
|
|
9464
10965
|
tracestart,
|
|
@@ -9476,6 +10977,7 @@ export {
|
|
|
9476
10977
|
triggerpayloadof,
|
|
9477
10978
|
triggersummary,
|
|
9478
10979
|
tryof,
|
|
10980
|
+
undoedit,
|
|
9479
10981
|
unwrapgraphql,
|
|
9480
10982
|
updaterule,
|
|
9481
10983
|
urlencodeform,
|
|
@@ -9483,26 +10985,34 @@ export {
|
|
|
9483
10985
|
validatecontrolpayload,
|
|
9484
10986
|
validatefieldmatch,
|
|
9485
10987
|
validateformrecord,
|
|
10988
|
+
validateframe,
|
|
9486
10989
|
validateregexrule,
|
|
10990
|
+
validatesiteoverride,
|
|
9487
10991
|
validatestep,
|
|
9488
10992
|
validatetargetref,
|
|
10993
|
+
validatetoolcatalog,
|
|
9489
10994
|
validatevaluegen,
|
|
9490
10995
|
validateworkflow,
|
|
9491
10996
|
verifywebhook,
|
|
9492
10997
|
visitmatch,
|
|
9493
10998
|
waitelementplan,
|
|
9494
10999
|
watchcdpevents,
|
|
11000
|
+
watchdogconfigvalid,
|
|
11001
|
+
watchdogpass,
|
|
9495
11002
|
watcherdetached,
|
|
9496
11003
|
watchexpressionof,
|
|
9497
11004
|
watchgate,
|
|
9498
11005
|
webhooksecretok,
|
|
9499
11006
|
whileof,
|
|
11007
|
+
wireformat,
|
|
9500
11008
|
wizardreport,
|
|
9501
11009
|
workflowblockof,
|
|
11010
|
+
workflowfileversion,
|
|
9502
11011
|
workflowgate,
|
|
9503
11012
|
workflowkinds,
|
|
9504
11013
|
workflowoutcome,
|
|
9505
11014
|
workflowreport,
|
|
9506
|
-
workflowstepof
|
|
11015
|
+
workflowstepof,
|
|
11016
|
+
zoomcanvas
|
|
9507
11017
|
};
|
|
9508
11018
|
//# sourceMappingURL=index.js.map
|