@wenathlan/extension 1.1.49 → 1.1.50
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 +6 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +878 -5
- package/dist/index.js.map +4 -4
- package/dist/memory.d.ts +34 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/policy.d.ts +16 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +68 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/types.d.ts +157 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/workflow.d.ts +148 -0
- package/dist/workflow.d.ts.map +1 -0
- package/extension/dist/background.js +1189 -48
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +1 -1
- package/extension/dist/pagebridge.js +2 -2
- package/extension/dist/pagebridge.js.map +2 -2
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js +46 -2
- package/extension/dist/popup.js.map +2 -2
- package/extension/dist/sidepanel.html +1 -1
- package/extension/dist/sidepanel.js +179 -2
- package/extension/dist/sidepanel.js.map +2 -2
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3070,6 +3070,84 @@ var sessionmemory = class {
|
|
|
3070
3070
|
async setcrashflag(value) {
|
|
3071
3071
|
return this.adapter.set("crashed", value);
|
|
3072
3072
|
}
|
|
3073
|
+
/** Stores one composed workflow record version with its timestamp; re-composing the same version replaces it while older versions survive for the audit trail. */
|
|
3074
|
+
async addworkflowrecord(record2) {
|
|
3075
|
+
const records = await this.getworkflowrecordversions();
|
|
3076
|
+
const remaining = records.filter((entry) => !(entry.id === record2.id && entry.version === record2.version));
|
|
3077
|
+
await this.adapter.set("workflowrecords", [record2, ...remaining]);
|
|
3078
|
+
}
|
|
3079
|
+
/** Returns every stored workflow record version, newest first. */
|
|
3080
|
+
async getworkflowrecordversions() {
|
|
3081
|
+
return await this.adapter.get("workflowrecords") ?? [];
|
|
3082
|
+
}
|
|
3083
|
+
/** Returns the latest stored version of one workflow record. */
|
|
3084
|
+
async getworkflowrecord(id) {
|
|
3085
|
+
return (await this.getworkflowrecordversions()).find((entry) => entry.id === id);
|
|
3086
|
+
}
|
|
3087
|
+
/** Lists the saved workflow records, the latest version of each, newest first. */
|
|
3088
|
+
async listworkflows() {
|
|
3089
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3090
|
+
const latest = [];
|
|
3091
|
+
for (const entry of await this.getworkflowrecordversions()) {
|
|
3092
|
+
if (seen.has(entry.id)) continue;
|
|
3093
|
+
seen.add(entry.id);
|
|
3094
|
+
latest.push(entry);
|
|
3095
|
+
}
|
|
3096
|
+
return latest;
|
|
3097
|
+
}
|
|
3098
|
+
/** Stores one workflow run with its state transition; a run replace keeps the full runlog of the same id. */
|
|
3099
|
+
async setworkflowrun(run) {
|
|
3100
|
+
const runs = await this.listworkflowruns();
|
|
3101
|
+
const remaining = runs.filter((entry) => entry.id !== run.id);
|
|
3102
|
+
await this.adapter.set("workflowruns", [run, ...remaining]);
|
|
3103
|
+
}
|
|
3104
|
+
/** Returns every stored workflow run, newest first. */
|
|
3105
|
+
async listworkflowruns() {
|
|
3106
|
+
return await this.adapter.get("workflowruns") ?? [];
|
|
3107
|
+
}
|
|
3108
|
+
/** Returns one run with its full step outcome list so the panel shows the timeline after and during a run. */
|
|
3109
|
+
async getrun(id) {
|
|
3110
|
+
const run = (await this.listworkflowruns()).find((entry) => entry.id === id);
|
|
3111
|
+
if (!run) return void 0;
|
|
3112
|
+
return { run, log: await this.getrunlog(id) };
|
|
3113
|
+
}
|
|
3114
|
+
/** Records one runlog entry of a run; the runlog retention window is a user setting and an absent window keeps every entry. */
|
|
3115
|
+
async addrunlogentry(runid, entry) {
|
|
3116
|
+
const entries = await this.getrunlog(runid);
|
|
3117
|
+
const combined = [...entries, entry];
|
|
3118
|
+
const retention = (await this.getsettings())?.runlogretention;
|
|
3119
|
+
await this.adapter.set(`runlog${runid}`, retention === void 0 ? combined : combined.slice(-retention));
|
|
3120
|
+
}
|
|
3121
|
+
/** Returns the runlog of one run, oldest first. */
|
|
3122
|
+
async getrunlog(runid) {
|
|
3123
|
+
return await this.adapter.get(`runlog${runid}`) ?? [];
|
|
3124
|
+
}
|
|
3125
|
+
/** Stores the variable values per scope of one run for inspection after the run. */
|
|
3126
|
+
async setrunscopes(runid, scopes) {
|
|
3127
|
+
return this.adapter.set(`runscopes${runid}`, scopes);
|
|
3128
|
+
}
|
|
3129
|
+
/** Returns the variable scopes of one run, oldest first. */
|
|
3130
|
+
async getrunscopes(runid) {
|
|
3131
|
+
return await this.adapter.get(`runscopes${runid}`) ?? [];
|
|
3132
|
+
}
|
|
3133
|
+
/** Records one provenance entry of a run: an expression result or a regex capture with its name, value and time. */
|
|
3134
|
+
async addworkflowprovenance(runid, entry) {
|
|
3135
|
+
const entries = await this.getworkflowprovenance(runid);
|
|
3136
|
+
await this.adapter.set(`workflowprovenance${runid}`, [...entries, entry]);
|
|
3137
|
+
}
|
|
3138
|
+
/** Returns every provenance entry of one run, oldest first. */
|
|
3139
|
+
async getworkflowprovenance(runid) {
|
|
3140
|
+
return await this.adapter.get(`workflowprovenance${runid}`) ?? [];
|
|
3141
|
+
}
|
|
3142
|
+
/** Stores one shareable step template under its unique name. */
|
|
3143
|
+
async addsteptemplate(template) {
|
|
3144
|
+
const templates = (await this.getsteptemplates()).filter((entry) => entry.name !== template.name);
|
|
3145
|
+
await this.adapter.set("steptemplates", [template, ...templates]);
|
|
3146
|
+
}
|
|
3147
|
+
/** Returns every stored step template, newest first. */
|
|
3148
|
+
async getsteptemplates() {
|
|
3149
|
+
return await this.adapter.get("steptemplates") ?? [];
|
|
3150
|
+
}
|
|
3073
3151
|
};
|
|
3074
3152
|
function mediakindof(record2) {
|
|
3075
3153
|
if ("pages" in record2) return "pdf";
|
|
@@ -3606,6 +3684,511 @@ function extractvalues(body, paths) {
|
|
|
3606
3684
|
return fields.map((field) => ({ path: field.path, ...field.value !== void 0 ? { value: field.value } : {}, ...field.missing ? { missing: true } : {} }));
|
|
3607
3685
|
}
|
|
3608
3686
|
|
|
3687
|
+
// workflow.ts
|
|
3688
|
+
var workflowkinds = ["composeworkflow", "savetemplate", "runworkflow", "dryrun", "delay", "waitelement", "compute", "extractvars"];
|
|
3689
|
+
function workflowstepof(value) {
|
|
3690
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3691
|
+
const candidate = value;
|
|
3692
|
+
if (typeof candidate.id !== "string" || !candidate.id.trim()) return void 0;
|
|
3693
|
+
if (typeof candidate.kind !== "string" || !/^[a-z]+$/.test(candidate.kind)) return void 0;
|
|
3694
|
+
if (typeof candidate.label !== "string" || !candidate.label.trim()) return void 0;
|
|
3695
|
+
if (candidate.target !== void 0 && (typeof candidate.target !== "string" || !candidate.target)) return void 0;
|
|
3696
|
+
if (candidate.value !== void 0 && typeof candidate.value !== "string") return void 0;
|
|
3697
|
+
if (candidate.options !== void 0 && typeof candidate.options !== "string") return void 0;
|
|
3698
|
+
const bindings = Array.isArray(candidate.bindings) ? candidate.bindings.flatMap((binding) => bindingof(binding) !== void 0 ? [bindingof(binding)] : []) : void 0;
|
|
3699
|
+
if (candidate.bindings !== void 0 && bindings === void 0) return void 0;
|
|
3700
|
+
if (Array.isArray(candidate.bindings) && bindings !== void 0 && bindings.length !== candidate.bindings.length) return void 0;
|
|
3701
|
+
const expression = candidate.expression === void 0 ? void 0 : expressionof(candidate.expression);
|
|
3702
|
+
if (candidate.expression !== void 0 && expression === void 0) return void 0;
|
|
3703
|
+
const extract = candidate.extract === void 0 ? void 0 : regexruleof(candidate.extract);
|
|
3704
|
+
if (candidate.extract !== void 0 && extract === void 0) return void 0;
|
|
3705
|
+
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 } : {} };
|
|
3706
|
+
}
|
|
3707
|
+
function blockinvocationof(value) {
|
|
3708
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3709
|
+
const candidate = value;
|
|
3710
|
+
if (typeof candidate.block !== "string" || !candidate.block.trim()) return void 0;
|
|
3711
|
+
if (typeof candidate.label !== "string" || !candidate.label.trim()) return void 0;
|
|
3712
|
+
return { block: candidate.block, label: candidate.label };
|
|
3713
|
+
}
|
|
3714
|
+
function workflowblockof(value) {
|
|
3715
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3716
|
+
const candidate = value;
|
|
3717
|
+
if (typeof candidate.name !== "string" || !/^[a-z][a-z0-9]*$/.test(candidate.name)) return void 0;
|
|
3718
|
+
if (typeof candidate.label !== "string" || !candidate.label.trim()) return void 0;
|
|
3719
|
+
if (!Array.isArray(candidate.steps)) return void 0;
|
|
3720
|
+
const steps = [];
|
|
3721
|
+
for (const entry of candidate.steps) {
|
|
3722
|
+
const step = workflowstepof(entry);
|
|
3723
|
+
if (step) {
|
|
3724
|
+
steps.push(step);
|
|
3725
|
+
continue;
|
|
3726
|
+
}
|
|
3727
|
+
const invocation = blockinvocationof(entry);
|
|
3728
|
+
if (invocation) {
|
|
3729
|
+
steps.push(invocation);
|
|
3730
|
+
continue;
|
|
3731
|
+
}
|
|
3732
|
+
return void 0;
|
|
3733
|
+
}
|
|
3734
|
+
return { name: candidate.name, label: candidate.label, steps };
|
|
3735
|
+
}
|
|
3736
|
+
function steptemplateof(value) {
|
|
3737
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3738
|
+
const candidate = value;
|
|
3739
|
+
if (typeof candidate.id !== "string" || !candidate.id.trim()) return void 0;
|
|
3740
|
+
if (typeof candidate.name !== "string" || !candidate.name.trim()) return void 0;
|
|
3741
|
+
if (typeof candidate.origin !== "string" || !candidate.origin.trim()) return void 0;
|
|
3742
|
+
const step = workflowstepof(candidate.step);
|
|
3743
|
+
if (!step) return void 0;
|
|
3744
|
+
if (typeof candidate.sharedat !== "number" || !Number.isFinite(candidate.sharedat)) return void 0;
|
|
3745
|
+
return { id: candidate.id, name: candidate.name, origin: candidate.origin, step, sharedat: candidate.sharedat };
|
|
3746
|
+
}
|
|
3747
|
+
function bindingof(value) {
|
|
3748
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3749
|
+
const candidate = value;
|
|
3750
|
+
if (typeof candidate.variable !== "string" || !/^[a-z][a-z0-9]*$/.test(candidate.variable)) return void 0;
|
|
3751
|
+
if (!variablekinds.includes(candidate.kind)) return void 0;
|
|
3752
|
+
if (typeof candidate.stepid !== "string" || !candidate.stepid.trim()) return void 0;
|
|
3753
|
+
if (candidate.path !== void 0 && (typeof candidate.path !== "string" || !candidate.path.trim())) return void 0;
|
|
3754
|
+
return { variable: candidate.variable, kind: candidate.kind, stepid: candidate.stepid, ...candidate.path !== void 0 ? { path: candidate.path } : {} };
|
|
3755
|
+
}
|
|
3756
|
+
var variablekinds = ["string", "number", "boolean", "list", "element"];
|
|
3757
|
+
var expressionoperators = ["add", "subtract", "multiply", "divide", "modulo", "equal", "notequal", "less", "greater", "lessequal", "greaterequal", "and", "or", "not", "concat", "contains", "length"];
|
|
3758
|
+
function expressionof(value) {
|
|
3759
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3760
|
+
const candidate = value;
|
|
3761
|
+
const left = operandof(candidate.left);
|
|
3762
|
+
if (!left) return void 0;
|
|
3763
|
+
const right = candidate.right === void 0 ? void 0 : operandof(candidate.right);
|
|
3764
|
+
if (candidate.right !== void 0 && right === void 0) return void 0;
|
|
3765
|
+
if (typeof candidate.operator !== "string" || !expressionoperators.includes(candidate.operator)) return void 0;
|
|
3766
|
+
if (typeof candidate.result !== "string" || !/^[a-z][a-z0-9]*$/.test(candidate.result)) return void 0;
|
|
3767
|
+
if (!variablekinds.includes(candidate.resultkind)) return void 0;
|
|
3768
|
+
return { left, ...right !== void 0 ? { right } : {}, operator: candidate.operator, result: candidate.result, resultkind: candidate.resultkind };
|
|
3769
|
+
}
|
|
3770
|
+
function operandof(value) {
|
|
3771
|
+
if (value === void 0) return void 0;
|
|
3772
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return { literal: value };
|
|
3773
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3774
|
+
const candidate = value;
|
|
3775
|
+
if (typeof candidate.ref === "string" && /^[a-z][a-z0-9]*$/.test(candidate.ref)) return { ref: candidate.ref };
|
|
3776
|
+
if (typeof candidate.literal === "string" || typeof candidate.literal === "number" || typeof candidate.literal === "boolean") return { literal: candidate.literal };
|
|
3777
|
+
return void 0;
|
|
3778
|
+
}
|
|
3779
|
+
function regexruleof(value) {
|
|
3780
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3781
|
+
const candidate = value;
|
|
3782
|
+
if (typeof candidate.pattern !== "string" || !candidate.pattern.trim()) return void 0;
|
|
3783
|
+
if (typeof candidate.flags !== "string" || !/^[dgimsuvy]*$/.test(candidate.flags)) return void 0;
|
|
3784
|
+
const groups = Array.isArray(candidate.groups) ? candidate.groups.flatMap((group) => typeof group === "string" && /^[a-z][a-z0-9]*$/.test(group) ? [group] : []) : [];
|
|
3785
|
+
if (candidate.groups !== void 0 && groups.length !== candidate.groups.length) return void 0;
|
|
3786
|
+
return { pattern: candidate.pattern, flags: candidate.flags, groups };
|
|
3787
|
+
}
|
|
3788
|
+
function expandblocks(steps, blocks) {
|
|
3789
|
+
const byname = new Map(blocks.map((block) => [block.name, block]));
|
|
3790
|
+
const expanded = [];
|
|
3791
|
+
const visit = (entries, path, inside) => {
|
|
3792
|
+
for (const entry of entries) {
|
|
3793
|
+
if ("kind" in entry && "label" in entry && !("block" in entry)) {
|
|
3794
|
+
expanded.push(inside === void 0 ? entry : { ...entry, block: inside });
|
|
3795
|
+
continue;
|
|
3796
|
+
}
|
|
3797
|
+
const invocation = blockinvocationof(entry);
|
|
3798
|
+
if (!invocation) throw new Error("The step list entry is neither a reviewed step nor a block invocation.");
|
|
3799
|
+
if (path.includes(invocation.block)) throw new Error(`The block ${invocation.block} recurs inside itself and cannot expand.`);
|
|
3800
|
+
const block = byname.get(invocation.block);
|
|
3801
|
+
if (!block) throw new Error(`The block ${invocation.block} is not defined in the workflow.`);
|
|
3802
|
+
visit(block.steps, [...path, invocation.block], invocation.block);
|
|
3803
|
+
}
|
|
3804
|
+
};
|
|
3805
|
+
visit(steps, [], void 0);
|
|
3806
|
+
if (expanded.length === 0) throw new Error("A workflow needs at least one executable step after block expansion.");
|
|
3807
|
+
return expanded;
|
|
3808
|
+
}
|
|
3809
|
+
function composeworkflow(input) {
|
|
3810
|
+
if (typeof input.name !== "string" || !input.name.trim()) throw new Error("The workflow name must be a non-empty string.");
|
|
3811
|
+
if (typeof input.version !== "number" || !Number.isInteger(input.version) || input.version < 1) throw new Error("The workflow version must be a positive integer.");
|
|
3812
|
+
if (!Array.isArray(input.origins) || input.origins.length === 0) throw new Error("A workflow needs at least one granted HTTPS origin.");
|
|
3813
|
+
const origins = input.origins.map((origin) => {
|
|
3814
|
+
try {
|
|
3815
|
+
return new URL(origin).origin;
|
|
3816
|
+
} catch {
|
|
3817
|
+
throw new Error(`The workflow origin ${origin} is not a valid url.`);
|
|
3818
|
+
}
|
|
3819
|
+
});
|
|
3820
|
+
if (origins.some((origin) => !origin.startsWith("https://"))) throw new Error("Workflow origins must use HTTPS.");
|
|
3821
|
+
const blocks = input.blocks ?? [];
|
|
3822
|
+
if (blocks.some((block, index) => blocks.findIndex((other) => other.name === block.name) !== index)) throw new Error("Workflow block names must stay unique.");
|
|
3823
|
+
for (const entry of input.steps) {
|
|
3824
|
+
if ("kind" in entry && "label" in entry && !("block" in entry)) {
|
|
3825
|
+
if (input.kindallowed && !input.kindallowed(entry.kind)) throw new Error(`The workflow step kind ${entry.kind} is not a reviewed action kind.`);
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
for (const block of blocks) for (const entry of block.steps) {
|
|
3829
|
+
if ("kind" in entry && "label" in entry && !("block" in entry) && input.kindallowed && !input.kindallowed(entry.kind)) throw new Error(`The workflow step kind ${entry.kind} inside block ${block.name} is not a reviewed action kind.`);
|
|
3830
|
+
}
|
|
3831
|
+
const steps = expandblocks(input.steps, blocks);
|
|
3832
|
+
for (const step of steps) {
|
|
3833
|
+
if (input.kindallowed && !input.kindallowed(step.kind)) throw new Error(`The workflow step kind ${step.kind} is not a reviewed action kind.`);
|
|
3834
|
+
if (step.bindings) for (const binding of step.bindings) {
|
|
3835
|
+
if (!steps.some((other) => other.id === binding.stepid)) throw new Error(`The binding of ${binding.variable} references the unknown step ${binding.stepid}.`);
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
const riskof = input.riskof ?? (() => "sensitive");
|
|
3839
|
+
const risk = steps.some((step) => riskof(step.kind) === "sensitive") ? "sensitive" : steps.some((step) => riskof(step.kind) === "interaction") ? "interaction" : "read";
|
|
3840
|
+
const record2 = { id: input.id ?? crypto.randomUUID(), name: input.name, version: input.version, origins: [...new Set(origins)], steps, blocks, risk, createdat: input.now };
|
|
3841
|
+
return deepfreeze(record2);
|
|
3842
|
+
}
|
|
3843
|
+
function deepfreeze(record2) {
|
|
3844
|
+
for (const step of record2.steps) Object.freeze(step);
|
|
3845
|
+
for (const block of record2.blocks) for (const entry of block.steps) if ("kind" in entry && "label" in entry && !("block" in entry)) Object.freeze(entry);
|
|
3846
|
+
Object.freeze(record2.blocks);
|
|
3847
|
+
Object.freeze(record2.steps);
|
|
3848
|
+
return Object.freeze(record2);
|
|
3849
|
+
}
|
|
3850
|
+
function validateworkflow(record2, options) {
|
|
3851
|
+
if (record2.steps.length === 0) return { allowed: false, reason: "A workflow needs at least one reviewed step." };
|
|
3852
|
+
const defined = new Set(options?.inputs ?? []);
|
|
3853
|
+
const byid = new Map(record2.steps.map((step, index) => [step.id, { step, index }]));
|
|
3854
|
+
for (let index = 0; index < record2.steps.length; index += 1) {
|
|
3855
|
+
const step = record2.steps[index];
|
|
3856
|
+
if (options?.kindallowed && !options.kindallowed(step.kind)) return { allowed: false, reason: `The workflow step kind ${step.kind} is not a reviewed action kind.` };
|
|
3857
|
+
if (step.bindings) for (const binding of step.bindings) {
|
|
3858
|
+
const source = byid.get(binding.stepid);
|
|
3859
|
+
if (!source) return { allowed: false, reason: `The binding of ${binding.variable} references the unknown step ${binding.stepid}.` };
|
|
3860
|
+
if (source.index >= index) return { allowed: false, reason: `The binding of ${binding.variable} must link an earlier step than ${step.id}.` };
|
|
3861
|
+
defined.add(binding.variable);
|
|
3862
|
+
}
|
|
3863
|
+
if (step.expression) {
|
|
3864
|
+
for (const operand of [step.expression.left, step.expression.right]) {
|
|
3865
|
+
if (operand?.ref && !defined.has(operand.ref)) return { allowed: false, reason: `The expression of step ${step.id} references the undefined variable ${operand.ref}.` };
|
|
3866
|
+
}
|
|
3867
|
+
defined.add(step.expression.result);
|
|
3868
|
+
}
|
|
3869
|
+
if (step.extract) for (const group of step.extract.groups) defined.add(group);
|
|
3870
|
+
}
|
|
3871
|
+
return { allowed: true };
|
|
3872
|
+
}
|
|
3873
|
+
function pushscope(scopes, name, parent) {
|
|
3874
|
+
return [...scopes, { name, variables: [], ...parent !== void 0 ? { parent } : {} }];
|
|
3875
|
+
}
|
|
3876
|
+
function popscope(scopes) {
|
|
3877
|
+
if (scopes.length === 0) return scopes;
|
|
3878
|
+
return scopes.slice(0, -1);
|
|
3879
|
+
}
|
|
3880
|
+
function resolvevariable(scopes, name) {
|
|
3881
|
+
for (let index = scopes.length - 1; index >= 0; index -= 1) {
|
|
3882
|
+
const scope = scopes[index];
|
|
3883
|
+
const found = scope.variables.find((variable) => variable.name === name);
|
|
3884
|
+
if (found) return found;
|
|
3885
|
+
if (scope.parent === void 0) continue;
|
|
3886
|
+
const parentindex = scopes.findIndex((candidate) => candidate.name === scope.parent);
|
|
3887
|
+
if (parentindex >= 0 && parentindex < index) {
|
|
3888
|
+
const inherited = resolvevariable([scopes[parentindex]], name);
|
|
3889
|
+
if (inherited) return inherited;
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
return void 0;
|
|
3893
|
+
}
|
|
3894
|
+
function setvariable(scopes, name, kind, value, now) {
|
|
3895
|
+
if (scopes.length === 0) scopes = [{ name: "root", variables: [] }];
|
|
3896
|
+
const target = scopes[scopes.length - 1];
|
|
3897
|
+
const variables = [...target.variables.filter((variable) => variable.name !== name), { name, kind, value, setat: now }];
|
|
3898
|
+
return [...scopes.slice(0, -1), { ...target, variables }];
|
|
3899
|
+
}
|
|
3900
|
+
function coercevariable(value, kind) {
|
|
3901
|
+
if (kind === "number") {
|
|
3902
|
+
const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() !== "" ? Number(value) : NaN;
|
|
3903
|
+
if (!Number.isFinite(parsed)) throw new Error("The bound value is not a finite number.");
|
|
3904
|
+
return parsed;
|
|
3905
|
+
}
|
|
3906
|
+
if (kind === "boolean") {
|
|
3907
|
+
if (typeof value === "boolean") return value;
|
|
3908
|
+
if (value === "true") return true;
|
|
3909
|
+
if (value === "false") return false;
|
|
3910
|
+
throw new Error("The bound value is not a boolean.");
|
|
3911
|
+
}
|
|
3912
|
+
if (kind === "list") {
|
|
3913
|
+
if (Array.isArray(value)) return value.map((item) => String(item));
|
|
3914
|
+
if (typeof value === "string") return value.length === 0 ? [] : value.split(",");
|
|
3915
|
+
throw new Error("The bound value is not a list.");
|
|
3916
|
+
}
|
|
3917
|
+
if (kind === "element") {
|
|
3918
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
3919
|
+
throw new Error("The bound value is not an element reference.");
|
|
3920
|
+
}
|
|
3921
|
+
if (typeof value === "string") return value;
|
|
3922
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
3923
|
+
throw new Error("The bound value is not a string.");
|
|
3924
|
+
}
|
|
3925
|
+
function outcomedetail(outcome, path) {
|
|
3926
|
+
if (!path) return outcome.summary;
|
|
3927
|
+
let current = outcome.details ?? {};
|
|
3928
|
+
for (const segment of path.split(".")) {
|
|
3929
|
+
if (!current || typeof current !== "object" || Array.isArray(current)) return void 0;
|
|
3930
|
+
current = current[segment];
|
|
3931
|
+
}
|
|
3932
|
+
return current;
|
|
3933
|
+
}
|
|
3934
|
+
function bindvariables(scopes, bindings, outputs, now) {
|
|
3935
|
+
let current = scopes;
|
|
3936
|
+
const produced = [];
|
|
3937
|
+
for (const binding of bindings) {
|
|
3938
|
+
const outcome = outputs[binding.stepid];
|
|
3939
|
+
if (!outcome) continue;
|
|
3940
|
+
const raw = outcomedetail(outcome, binding.path);
|
|
3941
|
+
if (raw === void 0) throw new Error(`The binding of ${binding.variable} found no value at ${binding.path ?? "the summary"} of step ${binding.stepid}.`);
|
|
3942
|
+
current = setvariable(current, binding.variable, binding.kind, coercevariable(raw, binding.kind), now);
|
|
3943
|
+
produced.push(binding.variable);
|
|
3944
|
+
}
|
|
3945
|
+
return { scopes: current, produced };
|
|
3946
|
+
}
|
|
3947
|
+
function operandvalue(operand, scopes) {
|
|
3948
|
+
if (operand.ref !== void 0) {
|
|
3949
|
+
const resolved = resolvevariable(scopes, operand.ref);
|
|
3950
|
+
if (!resolved) throw new Error(`The expression references the undefined variable ${operand.ref}.`);
|
|
3951
|
+
return resolved.value;
|
|
3952
|
+
}
|
|
3953
|
+
if (operand.literal === void 0) throw new Error("The expression operand needs a variable reference or a literal.");
|
|
3954
|
+
return operand.literal;
|
|
3955
|
+
}
|
|
3956
|
+
function expressioneval(expression, scopes) {
|
|
3957
|
+
const left = operandvalue(expression.left, scopes);
|
|
3958
|
+
const right = expression.right === void 0 ? void 0 : operandvalue(expression.right, scopes);
|
|
3959
|
+
const operand = (value) => {
|
|
3960
|
+
if (Array.isArray(value)) throw new Error("The expression operand is a list and needs the contains or length operator.");
|
|
3961
|
+
if (value === void 0) throw new Error("The expression operand is missing.");
|
|
3962
|
+
return value;
|
|
3963
|
+
};
|
|
3964
|
+
const numbervalue = (value) => {
|
|
3965
|
+
const primitive = operand(value);
|
|
3966
|
+
if (typeof primitive === "number") return primitive;
|
|
3967
|
+
if (typeof primitive === "string" && primitive.trim() !== "") {
|
|
3968
|
+
const parsed = Number(primitive);
|
|
3969
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
3970
|
+
}
|
|
3971
|
+
throw new Error("The arithmetic operand is not a number.");
|
|
3972
|
+
};
|
|
3973
|
+
const booleanvalue = (value) => {
|
|
3974
|
+
const primitive = operand(value);
|
|
3975
|
+
if (typeof primitive === "boolean") return primitive;
|
|
3976
|
+
throw new Error("The logic operand is not a boolean.");
|
|
3977
|
+
};
|
|
3978
|
+
const stringvalue = (value) => {
|
|
3979
|
+
const primitive = operand(value);
|
|
3980
|
+
if (typeof primitive === "string") return primitive;
|
|
3981
|
+
if (typeof primitive === "number" || typeof primitive === "boolean") return String(primitive);
|
|
3982
|
+
throw new Error("The text operand is not a string.");
|
|
3983
|
+
};
|
|
3984
|
+
switch (expression.operator) {
|
|
3985
|
+
case "add":
|
|
3986
|
+
return numbervalue(left) + numbervalue(right);
|
|
3987
|
+
case "subtract":
|
|
3988
|
+
return numbervalue(left) - numbervalue(right);
|
|
3989
|
+
case "multiply":
|
|
3990
|
+
return numbervalue(left) * numbervalue(right);
|
|
3991
|
+
case "divide": {
|
|
3992
|
+
const divisor = numbervalue(right);
|
|
3993
|
+
if (divisor === 0) throw new Error("The expression divides by zero.");
|
|
3994
|
+
return numbervalue(left) / divisor;
|
|
3995
|
+
}
|
|
3996
|
+
case "modulo": {
|
|
3997
|
+
const divisor = numbervalue(right);
|
|
3998
|
+
if (divisor === 0) throw new Error("The expression divides by zero.");
|
|
3999
|
+
return numbervalue(left) % divisor;
|
|
4000
|
+
}
|
|
4001
|
+
case "equal":
|
|
4002
|
+
return left === right;
|
|
4003
|
+
case "notequal":
|
|
4004
|
+
return left !== right;
|
|
4005
|
+
case "less":
|
|
4006
|
+
return numbervalue(left) < numbervalue(right);
|
|
4007
|
+
case "greater":
|
|
4008
|
+
return numbervalue(left) > numbervalue(right);
|
|
4009
|
+
case "lessequal":
|
|
4010
|
+
return numbervalue(left) <= numbervalue(right);
|
|
4011
|
+
case "greaterequal":
|
|
4012
|
+
return numbervalue(left) >= numbervalue(right);
|
|
4013
|
+
case "and":
|
|
4014
|
+
return booleanvalue(left) && booleanvalue(right);
|
|
4015
|
+
case "or":
|
|
4016
|
+
return booleanvalue(left) || booleanvalue(right);
|
|
4017
|
+
case "not":
|
|
4018
|
+
return !booleanvalue(left);
|
|
4019
|
+
case "concat":
|
|
4020
|
+
return `${stringvalue(left)}${stringvalue(right)}`;
|
|
4021
|
+
case "contains": {
|
|
4022
|
+
if (Array.isArray(left)) return left.includes(stringvalue(right));
|
|
4023
|
+
return stringvalue(left).includes(stringvalue(right));
|
|
4024
|
+
}
|
|
4025
|
+
case "length": {
|
|
4026
|
+
if (Array.isArray(left)) return left.length;
|
|
4027
|
+
return stringvalue(left).length;
|
|
4028
|
+
}
|
|
4029
|
+
default:
|
|
4030
|
+
throw new Error("The reviewed expression operator is unknown.");
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
4033
|
+
function regexextract(rule, text2, now) {
|
|
4034
|
+
const pattern = new RegExp(rule.pattern, rule.flags);
|
|
4035
|
+
const match = pattern.exec(text2);
|
|
4036
|
+
if (!match) return { matched: false, variables: [] };
|
|
4037
|
+
const variables = [];
|
|
4038
|
+
for (const group of rule.groups) {
|
|
4039
|
+
const value = match.groups?.[group];
|
|
4040
|
+
variables.push({ name: group, kind: "string", value: typeof value === "string" ? value : "", setat: now });
|
|
4041
|
+
}
|
|
4042
|
+
return { matched: true, variables };
|
|
4043
|
+
}
|
|
4044
|
+
function waitelementplan(wait) {
|
|
4045
|
+
if (wait.timeout <= 0 || wait.poll <= 0) return { probes: 1, lastwait: 0 };
|
|
4046
|
+
const probes = Math.floor(wait.timeout / wait.poll) + 1;
|
|
4047
|
+
return { probes, lastwait: wait.timeout % wait.poll };
|
|
4048
|
+
}
|
|
4049
|
+
function delayjitter(delay, seed) {
|
|
4050
|
+
if (delay.jitter <= 0) return Math.max(0, delay.base);
|
|
4051
|
+
const sample = seededrandom(seed);
|
|
4052
|
+
return Math.max(0, delay.base - delay.jitter / 2 + sample * delay.jitter);
|
|
4053
|
+
}
|
|
4054
|
+
function seededrandom(seed) {
|
|
4055
|
+
let state = seed >>> 0;
|
|
4056
|
+
state ^= state >>> 16;
|
|
4057
|
+
state = Math.imul(state, 2246822507);
|
|
4058
|
+
state ^= state >>> 13;
|
|
4059
|
+
state = Math.imul(state, 3266489909);
|
|
4060
|
+
state ^= state >>> 16;
|
|
4061
|
+
state = state >>> 0 || 1;
|
|
4062
|
+
state ^= state << 13;
|
|
4063
|
+
state >>>= 0;
|
|
4064
|
+
state ^= state >> 17;
|
|
4065
|
+
state ^= state << 5;
|
|
4066
|
+
state >>>= 0;
|
|
4067
|
+
return state / 4294967296;
|
|
4068
|
+
}
|
|
4069
|
+
function newworkflowrun(input) {
|
|
4070
|
+
return { id: input.id ?? crypto.randomUUID(), workflowid: input.workflowid, state: "pending", cursor: 0, startedat: input.now, ...input.dryrun === true ? { dryrun: true } : {} };
|
|
4071
|
+
}
|
|
4072
|
+
function pauserun(run, now) {
|
|
4073
|
+
if (run.state !== "running") throw new Error("Only a running workflow can pause.");
|
|
4074
|
+
return { ...run, state: "paused", pausedat: now };
|
|
4075
|
+
}
|
|
4076
|
+
function cancelrun(run, reason, now) {
|
|
4077
|
+
if (run.state === "done" || run.state === "cancelled") return run;
|
|
4078
|
+
return { ...run, state: "cancelled", cancelreason: reason, endedat: now };
|
|
4079
|
+
}
|
|
4080
|
+
function interpolate(text2, scopes) {
|
|
4081
|
+
const consumed = [];
|
|
4082
|
+
const resolved = text2.replace(/\$\{([a-z][a-z0-9]*)\}/g, (_whole, name) => {
|
|
4083
|
+
const variable = resolvevariable(scopes, name);
|
|
4084
|
+
if (!variable) throw new Error(`The step references the undefined variable ${name}.`);
|
|
4085
|
+
consumed.push(name);
|
|
4086
|
+
return Array.isArray(variable.value) ? variable.value.join(",") : String(variable.value);
|
|
4087
|
+
});
|
|
4088
|
+
return { text: resolved, consumed };
|
|
4089
|
+
}
|
|
4090
|
+
function runlogof(step, state, startedat, duration, summary, extra) {
|
|
4091
|
+
return { stepid: step.id, label: step.label, state, startedat, duration, summary, ...extra.block !== void 0 ? { block: extra.block } : {}, ...extra.consumed !== void 0 && extra.consumed.length > 0 ? { consumed: extra.consumed } : {}, ...extra.produced !== void 0 && extra.produced.length > 0 ? { produced: extra.produced } : {}, ...extra.checkpoint === true ? { checkpoint: true } : {}, ...extra.details !== void 0 ? { details: extra.details } : {} };
|
|
4092
|
+
}
|
|
4093
|
+
async function runstep(input) {
|
|
4094
|
+
const startedat = input.now;
|
|
4095
|
+
let scopes = input.scopes;
|
|
4096
|
+
const consumed = [];
|
|
4097
|
+
if (input.step.bindings) {
|
|
4098
|
+
const bound = bindvariables(scopes, input.step.bindings.filter((binding) => input.outputs[binding.stepid] !== void 0), input.outputs, input.now);
|
|
4099
|
+
scopes = bound.scopes;
|
|
4100
|
+
}
|
|
4101
|
+
let produced = [];
|
|
4102
|
+
try {
|
|
4103
|
+
if (input.step.expression) {
|
|
4104
|
+
const value2 = expressioneval(input.step.expression, scopes);
|
|
4105
|
+
scopes = setvariable(scopes, input.step.expression.result, input.step.expression.resultkind, coercevariable(value2, input.step.expression.resultkind), input.now);
|
|
4106
|
+
produced = [...produced, input.step.expression.result];
|
|
4107
|
+
}
|
|
4108
|
+
let stepvalue = input.step.value;
|
|
4109
|
+
if (input.step.extract) {
|
|
4110
|
+
const text2 = stepvalue ?? "";
|
|
4111
|
+
const interpolated = interpolate(text2, scopes);
|
|
4112
|
+
consumed.push(...interpolated.consumed);
|
|
4113
|
+
const extraction = regexextract(input.step.extract, interpolated.text, input.now);
|
|
4114
|
+
if (extraction.matched) {
|
|
4115
|
+
for (const variable of extraction.variables) scopes = setvariable(scopes, variable.name, "string", variable.value, input.now);
|
|
4116
|
+
produced = [...produced, ...extraction.variables.map((variable) => variable.name)];
|
|
4117
|
+
}
|
|
4118
|
+
stepvalue = interpolated.text;
|
|
4119
|
+
}
|
|
4120
|
+
const target = input.step.target !== void 0 ? interpolate(input.step.target, scopes) : void 0;
|
|
4121
|
+
if (target) consumed.push(...target.consumed);
|
|
4122
|
+
const value = stepvalue !== void 0 ? interpolate(stepvalue, scopes) : void 0;
|
|
4123
|
+
if (value) consumed.push(...value.consumed);
|
|
4124
|
+
const options = input.step.options !== void 0 ? interpolate(input.step.options, scopes) : void 0;
|
|
4125
|
+
if (options) consumed.push(...options.consumed);
|
|
4126
|
+
const dispatchable = { ...input.step, ...target !== void 0 ? { target: target.text } : {}, ...value !== void 0 ? { value: value.text } : {}, ...options !== void 0 ? { options: options.text } : {} };
|
|
4127
|
+
const output = await input.execute(dispatchable, { scopes, ...input.block !== void 0 ? { block: input.block } : {} });
|
|
4128
|
+
if (input.step.bindings) {
|
|
4129
|
+
const bound = bindvariables(scopes, input.step.bindings, { ...input.outputs, [input.step.id]: { stepid: input.step.id, ok: output.ok, summary: output.summary, ...output.details !== void 0 ? { details: output.details } : {}, at: input.now } }, input.now);
|
|
4130
|
+
scopes = bound.scopes;
|
|
4131
|
+
produced = [.../* @__PURE__ */ new Set([...produced, ...bound.produced])];
|
|
4132
|
+
}
|
|
4133
|
+
const duration = Date.now() - startedat;
|
|
4134
|
+
return { scopes, log: runlogof(input.step, output.ok ? "done" : "failed", startedat, duration, output.summary, { ...input.block !== void 0 ? { block: input.block } : {}, ...consumed.length > 0 ? { consumed } : {}, ...produced.length > 0 ? { produced } : {}, ...output.details !== void 0 ? { details: output.details } : {}, ...output.ok ? { checkpoint: true } : {} }), output };
|
|
4135
|
+
} catch (error) {
|
|
4136
|
+
const duration = Date.now() - startedat;
|
|
4137
|
+
const summary = error instanceof Error ? error.message : String(error);
|
|
4138
|
+
return { scopes, log: runlogof(input.step, "failed", startedat, duration, summary, { ...input.block !== void 0 ? { block: input.block } : {}, ...consumed.length > 0 ? { consumed } : {} }), output: { ok: false, summary } };
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
async function runworkflow(input) {
|
|
4142
|
+
if (input.gates && !input.gates.sessionactive) throw new Error("The workflow refuses to run outside an approved session.");
|
|
4143
|
+
if (input.gates && !input.gates.planapproved) throw new Error("The workflow refuses to run without the approved plan review.");
|
|
4144
|
+
if (input.gates) for (const origin of input.record.origins) {
|
|
4145
|
+
if (!input.gates.origingranted(origin)) throw new Error(`The workflow origin ${origin} falls outside the session grants.`);
|
|
4146
|
+
}
|
|
4147
|
+
if (input.run.state === "done" || input.run.state === "failed" || input.run.state === "cancelled") throw new Error(`The workflow run is already ${input.run.state}.`);
|
|
4148
|
+
const { pausedat, ...resumed } = input.run;
|
|
4149
|
+
void pausedat;
|
|
4150
|
+
let run = input.run.state === "paused" ? { ...resumed, state: "running" } : { ...input.run, state: "running" };
|
|
4151
|
+
let scopes = input.scopes ?? [{ name: "root", variables: [] }];
|
|
4152
|
+
const log = [...input.log ?? []];
|
|
4153
|
+
const outputs = { ...input.outputs ?? {} };
|
|
4154
|
+
let activeblock;
|
|
4155
|
+
for (let index = run.cursor; index < input.record.steps.length; index += 1) {
|
|
4156
|
+
const step = input.record.steps[index];
|
|
4157
|
+
if (step.block !== void 0 && step.block !== activeblock) {
|
|
4158
|
+
scopes = pushscope(scopes, step.block, scopes[scopes.length - 1].name);
|
|
4159
|
+
activeblock = step.block;
|
|
4160
|
+
} else if (step.block === void 0 && activeblock !== void 0) {
|
|
4161
|
+
while (scopes.length > 1) scopes = popscope(scopes);
|
|
4162
|
+
activeblock = void 0;
|
|
4163
|
+
}
|
|
4164
|
+
const executed = await runstep({ step, scopes, outputs, execute: input.execute, now: Date.now(), ...step.block !== void 0 ? { block: step.block } : {} });
|
|
4165
|
+
scopes = executed.scopes;
|
|
4166
|
+
log.push(executed.log);
|
|
4167
|
+
outputs[step.id] = { stepid: step.id, ok: executed.output.ok, summary: executed.output.summary, ...executed.output.details !== void 0 ? { details: executed.output.details } : {}, at: Date.now() };
|
|
4168
|
+
if (!executed.output.ok) {
|
|
4169
|
+
run = { ...run, state: "failed", endedat: Date.now(), failreason: executed.output.summary };
|
|
4170
|
+
return { run, scopes, log, outputs };
|
|
4171
|
+
}
|
|
4172
|
+
run = { ...run, cursor: index + 1 };
|
|
4173
|
+
if (input.oncheckpoint) await input.oncheckpoint({ run, scopes, log });
|
|
4174
|
+
}
|
|
4175
|
+
run = { ...run, state: "done", endedat: Date.now() };
|
|
4176
|
+
return { run, scopes, log, outputs };
|
|
4177
|
+
}
|
|
4178
|
+
function dryrunworkflow(input) {
|
|
4179
|
+
const run = { ...input.run, state: "running", ...input.run.dryrun === true ? { dryrun: true } : { dryrun: true } };
|
|
4180
|
+
let scopes = input.scopes ?? [{ name: "root", variables: [] }];
|
|
4181
|
+
const log = [...input.log ?? []];
|
|
4182
|
+
for (let index = run.cursor; index < input.record.steps.length; index += 1) {
|
|
4183
|
+
const step = input.record.steps[index];
|
|
4184
|
+
const summary = input.projection(step);
|
|
4185
|
+
const entry = summary === void 0 ? runlogof(step, "refused", input.now, 0, `The ${step.kind} step has no read only projection and the dry run refuses it.`, { ...step.block !== void 0 ? { block: step.block } : {} }) : runlogof(step, "done", input.now, 0, summary, { ...step.block !== void 0 ? { block: step.block } : {} });
|
|
4186
|
+
log.push(entry);
|
|
4187
|
+
scopes = setvariable(scopes, `${step.id}outcome`, "boolean", entry.state === "done", input.now);
|
|
4188
|
+
}
|
|
4189
|
+
return { run: { ...run, state: "done", cursor: input.record.steps.length, endedat: input.now }, scopes, log };
|
|
4190
|
+
}
|
|
4191
|
+
|
|
3609
4192
|
// runtimeline.ts
|
|
3610
4193
|
var timelinekinds = ["watchconsole", "watcherrors", "watchtasks"];
|
|
3611
4194
|
var loglevels = ["error", "warn", "info", "log", "debug", "trace"];
|
|
@@ -4016,9 +4599,9 @@ function polldecision(input) {
|
|
|
4016
4599
|
}
|
|
4017
4600
|
|
|
4018
4601
|
// policy.ts
|
|
4019
|
-
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"]);
|
|
4602
|
+
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"]);
|
|
4020
4603
|
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"]);
|
|
4021
|
-
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"]);
|
|
4604
|
+
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"]);
|
|
4022
4605
|
var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
|
|
4023
4606
|
var watchactions = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "watchtab"]);
|
|
4024
4607
|
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"]);
|
|
@@ -4039,6 +4622,7 @@ var cdpactions = /* @__PURE__ */ new Set(["attachcdp", "detachcdp", "cdpcmd", "w
|
|
|
4039
4622
|
var profileractions = /* @__PURE__ */ new Set(["measureflow", "heapshot", "trackmemory", "profilecpu", "watchshifts", "traceload", "annotatetrace", "replaytrace", "capturesourcemaps"]);
|
|
4040
4623
|
var emulationactions = /* @__PURE__ */ new Set(["emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "blackboxscripts"]);
|
|
4041
4624
|
var sessionactions = /* @__PURE__ */ new Set(["persiststate", "capturesession", "restoresession", "namedsessions", "diffsessions", "searchsessions", "exportsessions", "importsessions"]);
|
|
4625
|
+
var workflowactions = /* @__PURE__ */ new Set(["composeworkflow", "savetemplate", "runworkflow", "dryrun", "delay", "waitelement", "compute", "extractvars"]);
|
|
4042
4626
|
var credentialheaders = /* @__PURE__ */ new Set(["authorization", "proxy-authorization", "cookie", "cookie2", "set-cookie", "api-key", "x-api-key", "x-auth-token", "x-session-token", "proxy-authorization"]);
|
|
4043
4627
|
var fieldkinds = ["text", "email", "phone", "date", "number", "select", "check", "radio", "file", "password", "card", "code"];
|
|
4044
4628
|
var layoutmutationactions = /* @__PURE__ */ new Set(["grouptabs", "colorgroup", "collapsegroup", "savelayout", "restorelayout"]);
|
|
@@ -4057,6 +4641,9 @@ function hostpattern(origin) {
|
|
|
4057
4641
|
function issessionkind(kind) {
|
|
4058
4642
|
return sessionactions.has(kind);
|
|
4059
4643
|
}
|
|
4644
|
+
function isworkflowkind(kind) {
|
|
4645
|
+
return workflowactions.has(kind);
|
|
4646
|
+
}
|
|
4060
4647
|
function iswatchkind(kind) {
|
|
4061
4648
|
return watchactions.has(kind);
|
|
4062
4649
|
}
|
|
@@ -5522,6 +6109,162 @@ function sessionfolderunique(name, folders) {
|
|
|
5522
6109
|
function snapshotretentionwindow(settings) {
|
|
5523
6110
|
return settings?.sessionretention;
|
|
5524
6111
|
}
|
|
6112
|
+
function validateworkflowgrammar(step, options) {
|
|
6113
|
+
const kind = step.kind;
|
|
6114
|
+
if (kind === "composeworkflow") {
|
|
6115
|
+
const payload = options.workflow;
|
|
6116
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return { allowed: false, reason: "The workflow composition needs the reviewed workflow payload with its name, version, origins, steps and blocks." };
|
|
6117
|
+
const candidate = payload;
|
|
6118
|
+
if (typeof candidate.name !== "string" || !candidate.name.trim()) return { allowed: false, reason: "The workflow composition needs a reviewed non-empty name." };
|
|
6119
|
+
if (typeof candidate.version !== "number" || !Number.isInteger(candidate.version) || candidate.version < 1) return { allowed: false, reason: "The workflow version must be a positive integer." };
|
|
6120
|
+
if (!Array.isArray(candidate.origins) || candidate.origins.length === 0 || !candidate.origins.every((origin) => typeof origin === "string" && origin.startsWith("https://"))) return { allowed: false, reason: "The workflow needs at least one granted HTTPS origin so every step stays inside the grants." };
|
|
6121
|
+
if (!Array.isArray(candidate.steps) || candidate.steps.length === 0 || !candidate.steps.every((entry) => workflowstepof(entry) !== void 0 || entry && typeof entry === "object" && typeof entry.block === "string")) return { allowed: false, reason: "The workflow needs a non-empty reviewed step list of the workflow step grammar or block invocations." };
|
|
6122
|
+
const blocks = Array.isArray(candidate.blocks) ? candidate.blocks.flatMap((block) => {
|
|
6123
|
+
const parsed = workflowblockof(block);
|
|
6124
|
+
return parsed !== void 0 ? [parsed] : [];
|
|
6125
|
+
}) : [];
|
|
6126
|
+
if (Array.isArray(candidate.blocks) && blocks.length !== candidate.blocks.length) return { allowed: false, reason: "The reviewed block list must carry unique lowercase names, labels and valid child steps." };
|
|
6127
|
+
try {
|
|
6128
|
+
const record2 = composeworkflow({ name: candidate.name, version: candidate.version, origins: candidate.origins, steps: candidate.steps.map((entry) => "block" in entry ? { block: entry.block, label: typeof entry.label === "string" ? entry.label : entry.block } : workflowstepof(entry)), blocks, now: 0, kindallowed: (candidatekind) => {
|
|
6129
|
+
try {
|
|
6130
|
+
actionrisk(candidatekind);
|
|
6131
|
+
return true;
|
|
6132
|
+
} catch {
|
|
6133
|
+
return false;
|
|
6134
|
+
}
|
|
6135
|
+
}, riskof: (candidatekind) => actionrisk(candidatekind) });
|
|
6136
|
+
const inputs = Array.isArray(candidate.inputs) ? candidate.inputs.flatMap((name) => typeof name === "string" ? [name] : []) : void 0;
|
|
6137
|
+
const checked = validateworkflow(record2, { kindallowed: (workflowkind) => {
|
|
6138
|
+
try {
|
|
6139
|
+
actionrisk(workflowkind);
|
|
6140
|
+
return true;
|
|
6141
|
+
} catch {
|
|
6142
|
+
return false;
|
|
6143
|
+
}
|
|
6144
|
+
}, ...inputs !== void 0 ? { inputs } : {} });
|
|
6145
|
+
if (!checked.allowed) return checked;
|
|
6146
|
+
} catch (error) {
|
|
6147
|
+
return { allowed: false, reason: error instanceof Error ? error.message : "The workflow payload failed its composition validation." };
|
|
6148
|
+
}
|
|
6149
|
+
return { allowed: true };
|
|
6150
|
+
}
|
|
6151
|
+
if (kind === "savetemplate") {
|
|
6152
|
+
const payload = options.template && typeof options.template === "object" && !Array.isArray(options.template) ? options.template : {};
|
|
6153
|
+
const template = steptemplateof({ id: "templatereview", origin: "https://example.com", sharedat: 0, ...payload });
|
|
6154
|
+
if (!template) return { allowed: false, reason: "The step template needs a reviewed name and a valid workflow step it shares across workflows." };
|
|
6155
|
+
return { allowed: true };
|
|
6156
|
+
}
|
|
6157
|
+
if (kind === "runworkflow") {
|
|
6158
|
+
if (typeof options.workflowid !== "string" || !options.workflowid.trim()) return { allowed: false, reason: "The workflow run needs the reviewed id of the composed workflow." };
|
|
6159
|
+
if (options.reviewed !== true) return { allowed: false, reason: "Every real workflow run needs the explicit run review with its expanded step list shown before the first step executes." };
|
|
6160
|
+
if (options.variables !== void 0 && (!options.variables || typeof options.variables !== "object" || Array.isArray(options.variables) || !Object.values(options.variables).every((value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean"))) return { allowed: false, reason: "The reviewed run variables must be an object of string, number or boolean values." };
|
|
6161
|
+
return { allowed: true };
|
|
6162
|
+
}
|
|
6163
|
+
if (kind === "dryrun") {
|
|
6164
|
+
if (typeof options.workflowid !== "string" || !options.workflowid.trim()) return { allowed: false, reason: "The dry run needs the reviewed id of the composed workflow." };
|
|
6165
|
+
return { allowed: true };
|
|
6166
|
+
}
|
|
6167
|
+
if (kind === "delay") {
|
|
6168
|
+
const delay = options.delay;
|
|
6169
|
+
if (!delay || typeof delay !== "object" || Array.isArray(delay)) return { allowed: false, reason: "The delay needs a reviewed base and jitter window in options." };
|
|
6170
|
+
const reviewed = delay;
|
|
6171
|
+
if (typeof reviewed.base !== "number" || !Number.isFinite(reviewed.base) || reviewed.base < 0) return { allowed: false, reason: "The reviewed delay base must be zero or a positive number of milliseconds." };
|
|
6172
|
+
if (typeof reviewed.jitter !== "number" || !Number.isFinite(reviewed.jitter) || reviewed.jitter < 0) return { allowed: false, reason: "The reviewed delay jitter window must be zero or a positive number of milliseconds with no code ceiling." };
|
|
6173
|
+
return { allowed: true };
|
|
6174
|
+
}
|
|
6175
|
+
if (kind === "waitelement") {
|
|
6176
|
+
const wait = options.wait;
|
|
6177
|
+
if (!wait || typeof wait !== "object" || Array.isArray(wait)) return { allowed: false, reason: "The element wait needs a reviewed selector, timeout and poll interval in options." };
|
|
6178
|
+
const reviewed = wait;
|
|
6179
|
+
if (typeof reviewed.selector !== "string" || !reviewed.selector.trim()) return { allowed: false, reason: "The element wait needs a reviewed non-empty selector." };
|
|
6180
|
+
if (typeof reviewed.timeout !== "number" || !Number.isFinite(reviewed.timeout) || reviewed.timeout < 0) return { allowed: false, reason: "The reviewed element wait timeout must be zero or a positive number of milliseconds with no code ceiling." };
|
|
6181
|
+
if (typeof reviewed.poll !== "number" || !Number.isFinite(reviewed.poll) || reviewed.poll < 0) return { allowed: false, reason: "The reviewed element wait poll interval must be zero or a positive number of milliseconds with no code ceiling." };
|
|
6182
|
+
return { allowed: true };
|
|
6183
|
+
}
|
|
6184
|
+
if (kind === "compute") {
|
|
6185
|
+
const expression = expressionof(options.expression);
|
|
6186
|
+
if (!expression) return { allowed: false, reason: `The expression step needs a reviewed expression with operands, an operator of the reviewed set (${expressionoperators.join(", ")}) and a result variable of a reviewed kind.` };
|
|
6187
|
+
const operatorcheck = validatexpressionoperators(expression);
|
|
6188
|
+
if (!operatorcheck.allowed) return operatorcheck;
|
|
6189
|
+
return { allowed: true };
|
|
6190
|
+
}
|
|
6191
|
+
if (kind === "extractvars") {
|
|
6192
|
+
const rule = regexruleof(options.rule);
|
|
6193
|
+
if (!rule) return { allowed: false, reason: "The variable extraction needs a reviewed regex rule with its pattern, flags and named capture groups." };
|
|
6194
|
+
const shapecheck = validateregexrule(rule.pattern);
|
|
6195
|
+
if (!shapecheck.allowed) return shapecheck;
|
|
6196
|
+
if (typeof options.text !== "string") return { allowed: false, reason: "The variable extraction needs the reviewed text the regex rule applies to." };
|
|
6197
|
+
return { allowed: true };
|
|
6198
|
+
}
|
|
6199
|
+
return { allowed: true };
|
|
6200
|
+
}
|
|
6201
|
+
function validateregexrule(pattern) {
|
|
6202
|
+
try {
|
|
6203
|
+
new RegExp(pattern);
|
|
6204
|
+
} catch {
|
|
6205
|
+
return { allowed: false, reason: "The reviewed regex pattern does not compile." };
|
|
6206
|
+
}
|
|
6207
|
+
const nestedquantifier = /\((?:[^()\\]|\\.)*[+*}]\)[+*{]/.test(pattern) || /\(\)[+*{]/.test(pattern);
|
|
6208
|
+
if (nestedquantifier) return { allowed: false, reason: "The reviewed regex pattern nests an unbounded quantifier inside a quantified group and is refused because adversarial text could explode the backtracking." };
|
|
6209
|
+
const unboundedrepeat = /\{\d+,\}/.test(pattern);
|
|
6210
|
+
if (unboundedrepeat && /\([^)]*\{\d+,\}[^)]*\)[+*{]/.test(pattern)) return { allowed: false, reason: "The reviewed regex pattern repeats an unbounded group and is refused because adversarial text could explode the backtracking." };
|
|
6211
|
+
return { allowed: true };
|
|
6212
|
+
}
|
|
6213
|
+
function validatexpressionoperators(expression) {
|
|
6214
|
+
const numeric = /* @__PURE__ */ new Set(["add", "subtract", "multiply", "divide", "modulo"]);
|
|
6215
|
+
const logic = /* @__PURE__ */ new Set(["and", "or", "not"]);
|
|
6216
|
+
const comparison = /* @__PURE__ */ new Set(["less", "greater", "lessequal", "greaterequal"]);
|
|
6217
|
+
const text2 = /* @__PURE__ */ new Set(["concat", "contains"]);
|
|
6218
|
+
const operator = expression.operator;
|
|
6219
|
+
if (numeric.has(operator)) {
|
|
6220
|
+
for (const operand of [expression.left, expression.right]) {
|
|
6221
|
+
if (operand === void 0) continue;
|
|
6222
|
+
if (operand.literal !== void 0 && typeof operand.literal === "boolean") return { allowed: false, reason: `The ${operator} operator needs numeric operands; boolean literals are refused.` };
|
|
6223
|
+
}
|
|
6224
|
+
if (expression.resultkind !== "number" && expression.resultkind !== "string") return { allowed: false, reason: `The ${operator} operator needs a number result kind.` };
|
|
6225
|
+
}
|
|
6226
|
+
if (logic.has(operator)) {
|
|
6227
|
+
for (const operand of [expression.left, expression.right]) {
|
|
6228
|
+
if (operand === void 0) continue;
|
|
6229
|
+
if (operand.literal !== void 0 && typeof operand.literal !== "boolean") return { allowed: false, reason: `The ${operator} operator needs boolean operands; non boolean literals are refused.` };
|
|
6230
|
+
}
|
|
6231
|
+
if (expression.resultkind !== "boolean") return { allowed: false, reason: `The ${operator} operator needs a boolean result kind.` };
|
|
6232
|
+
if (operator === "not" && expression.right !== void 0) return { allowed: false, reason: "The not operator takes one operand only." };
|
|
6233
|
+
}
|
|
6234
|
+
if (comparison.has(operator) && expression.resultkind !== "boolean") return { allowed: false, reason: `The ${operator} operator needs a boolean result kind.` };
|
|
6235
|
+
if (text2.has(operator) && expression.resultkind !== "boolean" && expression.resultkind !== "string") return { allowed: false, reason: `The ${operator} operator needs a string or boolean result kind.` };
|
|
6236
|
+
if (operator === "contains" && expression.resultkind !== "boolean") return { allowed: false, reason: "The contains operator needs a boolean result kind." };
|
|
6237
|
+
if (operator === "length") {
|
|
6238
|
+
if (expression.right !== void 0) return { allowed: false, reason: "The length operator takes one operand only." };
|
|
6239
|
+
if (expression.resultkind !== "number") return { allowed: false, reason: "The length operator needs a number result kind." };
|
|
6240
|
+
}
|
|
6241
|
+
if ((operator === "equal" || operator === "notequal") && !(/* @__PURE__ */ new Set(["boolean", "string", "number"])).has(expression.resultkind)) return { allowed: false, reason: "The equality operator needs a primitive result kind." };
|
|
6242
|
+
return { allowed: true };
|
|
6243
|
+
}
|
|
6244
|
+
function workflowgate(input) {
|
|
6245
|
+
const gate = sessiongate({ session: input.session, tabid: input.tabid, origin: input.origin, now: input.now, action: "run the workflow step" });
|
|
6246
|
+
if (!gate.allowed) return gate;
|
|
6247
|
+
if (!input.plan || input.plan.state !== "approved") return { allowed: false, reason: "Workflow steps need the approved plan review before they run." };
|
|
6248
|
+
if (input.step.kind === "runworkflow") {
|
|
6249
|
+
let runoptions = {};
|
|
6250
|
+
try {
|
|
6251
|
+
runoptions = parseoptions(input.step);
|
|
6252
|
+
} catch {
|
|
6253
|
+
runoptions = {};
|
|
6254
|
+
}
|
|
6255
|
+
if (runoptions.reviewed !== true) return { allowed: false, reason: "Every real workflow run needs the explicit run review with its expanded step list shown before the first step executes." };
|
|
6256
|
+
}
|
|
6257
|
+
return { allowed: true };
|
|
6258
|
+
}
|
|
6259
|
+
function dryrunprojection(step) {
|
|
6260
|
+
const risk = resolvedrisk({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.target !== void 0 ? { target: step.target } : {}, ...step.value !== void 0 ? { value: step.value } : {}, ...step.options !== void 0 ? { options: step.options } : {} });
|
|
6261
|
+
if (risk !== "read") return void 0;
|
|
6262
|
+
if (step.kind === "delay") return `The delay step would sleep its reviewed base inside the jitter window.`;
|
|
6263
|
+
if (step.kind === "waitelement") return `The element wait step would poll ${step.target ?? "the reviewed selector"} until appearance or the reviewed timeout.`;
|
|
6264
|
+
if (step.kind === "compute") return `The compute step would evaluate its reviewed expression into the result variable.`;
|
|
6265
|
+
if (step.kind === "extractvars") return `The variable extraction step would apply its reviewed regex rule and store the named captures.`;
|
|
6266
|
+
return `The ${step.kind} step would run read only and mutate nothing.`;
|
|
6267
|
+
}
|
|
5525
6268
|
function permissionstatevalid(state) {
|
|
5526
6269
|
if (!permissionstates.includes(state)) return { allowed: false, reason: `The reviewed permission state must be one of ${permissionstates.join(", ")}.` };
|
|
5527
6270
|
return { allowed: true };
|
|
@@ -6091,6 +6834,10 @@ function validatestep(step, origin) {
|
|
|
6091
6834
|
const sessioncheck = validatesessiongrammar(step, options);
|
|
6092
6835
|
if (!sessioncheck.allowed) return sessioncheck;
|
|
6093
6836
|
}
|
|
6837
|
+
if (isworkflowkind(step.kind)) {
|
|
6838
|
+
const workflowcheck = validateworkflowgrammar(step, options);
|
|
6839
|
+
if (!workflowcheck.allowed) return workflowcheck;
|
|
6840
|
+
}
|
|
6094
6841
|
if (step.kind === "tabcreate") {
|
|
6095
6842
|
if (options.background !== void 0 && typeof options.background !== "boolean") return { allowed: false, reason: "The reviewed background flag must be a boolean." };
|
|
6096
6843
|
if (options.window !== void 0 && (typeof options.window !== "number" || !Number.isInteger(options.window) || options.window < 0)) return { allowed: false, reason: "The reviewed target window id must be a non-negative integer." };
|
|
@@ -6281,6 +7028,10 @@ function canexecute(input) {
|
|
|
6281
7028
|
}
|
|
6282
7029
|
}
|
|
6283
7030
|
}
|
|
7031
|
+
if (isworkflowkind(input.step.kind)) {
|
|
7032
|
+
const workflowgatecheck = workflowgate({ session: input.session, plan: input.plan, step: input.step, tabid: input.tabid, origin: input.origin, now });
|
|
7033
|
+
if (!workflowgatecheck.allowed) return workflowgatecheck;
|
|
7034
|
+
}
|
|
6284
7035
|
if (iscontrolkind(input.step.kind)) {
|
|
6285
7036
|
const controlgate = sessiongate({ session: input.session, tabid: input.tabid, origin: input.origin, now, action: "control the network" });
|
|
6286
7037
|
if (!controlgate.allowed) return controlgate;
|
|
@@ -6364,7 +7115,7 @@ function canexecute(input) {
|
|
|
6364
7115
|
}
|
|
6365
7116
|
|
|
6366
7117
|
// version.ts
|
|
6367
|
-
var packageversion = "1.1.
|
|
7118
|
+
var packageversion = "1.1.50";
|
|
6368
7119
|
|
|
6369
7120
|
// types.ts
|
|
6370
7121
|
var protocolversion = packageversion;
|
|
@@ -6580,6 +7331,29 @@ function parseproposal(value, origin, grants) {
|
|
|
6580
7331
|
}
|
|
6581
7332
|
if (step.kind === "importsessions" && importsessionfile(sessionoptions.file) === void 0) throw new Error("Session import files of unknown format versions are refused.");
|
|
6582
7333
|
}
|
|
7334
|
+
if (isworkflowkind(step.kind)) {
|
|
7335
|
+
let workflowoptions = {};
|
|
7336
|
+
try {
|
|
7337
|
+
workflowoptions = parseoptions(step);
|
|
7338
|
+
} catch {
|
|
7339
|
+
workflowoptions = {};
|
|
7340
|
+
}
|
|
7341
|
+
if (step.kind === "composeworkflow") {
|
|
7342
|
+
const payload = workflowoptions.workflow && typeof workflowoptions.workflow === "object" && !Array.isArray(workflowoptions.workflow) ? workflowoptions.workflow : void 0;
|
|
7343
|
+
const origins = payload && Array.isArray(payload.origins) ? payload.origins.filter((originvalue) => typeof originvalue === "string") : [];
|
|
7344
|
+
for (const workfloworigin of origins) {
|
|
7345
|
+
const granted = covered.some((pattern) => {
|
|
7346
|
+
try {
|
|
7347
|
+
return new URL(workfloworigin).origin === new URL(pattern).origin;
|
|
7348
|
+
} catch {
|
|
7349
|
+
return false;
|
|
7350
|
+
}
|
|
7351
|
+
});
|
|
7352
|
+
if (!granted) throw new Error(`The workflow origin ${workfloworigin} stays outside the grants.`);
|
|
7353
|
+
}
|
|
7354
|
+
}
|
|
7355
|
+
if (step.kind === "runworkflow" && workflowoptions.reviewed !== true) throw new Error("Workflow runs without the explicit run review of the expanded step list are refused.");
|
|
7356
|
+
}
|
|
6583
7357
|
const evaluation = validatestep(step, origin);
|
|
6584
7358
|
if (!evaluation.allowed) throw new Error(evaluation.reason);
|
|
6585
7359
|
const target = outboundtarget(step);
|
|
@@ -6639,6 +7413,70 @@ function parseproposal(value, origin, grants) {
|
|
|
6639
7413
|
};
|
|
6640
7414
|
return { version: protocolversion, plan };
|
|
6641
7415
|
}
|
|
7416
|
+
function parseworkflowproposal(value, origin, grants, dryrun) {
|
|
7417
|
+
const root = record(value);
|
|
7418
|
+
if (root.version !== protocolversion) throw new Error("Unsupported protocol version.");
|
|
7419
|
+
const covered = grants !== void 0 && grants.length > 0 ? grants : [origin];
|
|
7420
|
+
const candidate = record(root.workflow);
|
|
7421
|
+
const name = text(candidate.name, "workflow name");
|
|
7422
|
+
const version = typeof candidate.version === "number" && Number.isInteger(candidate.version) && candidate.version >= 1 ? candidate.version : void 0;
|
|
7423
|
+
if (version === void 0) throw new Error("The workflow version must be a positive integer.");
|
|
7424
|
+
const origins = Array.isArray(candidate.origins) ? candidate.origins : [];
|
|
7425
|
+
if (origins.length === 0 || !origins.every((workfloworigin) => typeof workfloworigin === "string" && workfloworigin.startsWith("https://"))) throw new Error("The workflow needs at least one granted HTTPS origin.");
|
|
7426
|
+
for (const workfloworigin of origins) {
|
|
7427
|
+
const granted = covered.some((pattern) => {
|
|
7428
|
+
try {
|
|
7429
|
+
return new URL(workfloworigin).origin === new URL(pattern).origin;
|
|
7430
|
+
} catch {
|
|
7431
|
+
return false;
|
|
7432
|
+
}
|
|
7433
|
+
});
|
|
7434
|
+
if (!granted) throw new Error(`The workflow origin ${workfloworigin} stays outside the grants.`);
|
|
7435
|
+
}
|
|
7436
|
+
const steps = Array.isArray(candidate.steps) ? candidate.steps : [];
|
|
7437
|
+
if (steps.length === 0) throw new Error("A workflow proposal needs at least one step or block invocation.");
|
|
7438
|
+
const blocks = Array.isArray(candidate.blocks) ? candidate.blocks.flatMap((block) => workflowblockof(block) !== void 0 ? [workflowblockof(block)] : []) : [];
|
|
7439
|
+
if (Array.isArray(candidate.blocks) && blocks.length !== candidate.blocks.length) throw new Error("The reviewed block list must carry unique lowercase names, labels and valid child steps.");
|
|
7440
|
+
const composed = composeworkflow({
|
|
7441
|
+
name,
|
|
7442
|
+
version,
|
|
7443
|
+
origins,
|
|
7444
|
+
steps: steps.map((entry) => {
|
|
7445
|
+
const step = workflowstepof(entry);
|
|
7446
|
+
if (step) return step;
|
|
7447
|
+
const invocation = blockinvocationof(entry);
|
|
7448
|
+
if (invocation) return invocation;
|
|
7449
|
+
throw new Error("Every workflow entry must be a reviewed step or a block invocation.");
|
|
7450
|
+
}),
|
|
7451
|
+
blocks,
|
|
7452
|
+
now: Date.now(),
|
|
7453
|
+
kindallowed: (kind) => {
|
|
7454
|
+
try {
|
|
7455
|
+
actionrisk(kind);
|
|
7456
|
+
return true;
|
|
7457
|
+
} catch {
|
|
7458
|
+
return false;
|
|
7459
|
+
}
|
|
7460
|
+
},
|
|
7461
|
+
riskof: (kind) => actionrisk(kind)
|
|
7462
|
+
});
|
|
7463
|
+
const inputs = Array.isArray(candidate.inputs) ? candidate.inputs.flatMap((inputname) => typeof inputname === "string" ? [inputname] : []) : void 0;
|
|
7464
|
+
const checked = validateworkflow(composed, { kindallowed: (kind) => {
|
|
7465
|
+
try {
|
|
7466
|
+
actionrisk(kind);
|
|
7467
|
+
return true;
|
|
7468
|
+
} catch {
|
|
7469
|
+
return false;
|
|
7470
|
+
}
|
|
7471
|
+
}, ...inputs !== void 0 ? { inputs } : {} });
|
|
7472
|
+
if (!checked.allowed) throw new Error(checked.reason ?? "The workflow proposal failed its validation.");
|
|
7473
|
+
return { version: protocolversion, workflow: composed, ...dryrun === true ? { dryrun: true } : {} };
|
|
7474
|
+
}
|
|
7475
|
+
function workflowoutcome(input) {
|
|
7476
|
+
const selected = input.stepid !== void 0 ? input.entries.filter((entry) => entry.stepid === input.stepid) : input.entries;
|
|
7477
|
+
const steps = selected.map((entry) => ({ stepid: entry.stepid, label: entry.label, state: entry.state, duration: entry.duration, summary: entry.summary, ...entry.block !== void 0 ? { block: entry.block } : {}, ...entry.produced !== void 0 ? { produced: entry.produced } : {}, ...entry.consumed !== void 0 ? { consumed: entry.consumed } : {}, ...entry.checkpoint === true ? { checkpoint: true } : {} }));
|
|
7478
|
+
return { version: protocolversion, runid: input.run.id, workflowid: input.run.workflowid, state: input.run.state, ...input.run.dryrun === true ? { dryrun: true } : {}, steps };
|
|
7479
|
+
}
|
|
6642
7480
|
function stepof(kind, candidate, index) {
|
|
6643
7481
|
return { id: typeof candidate.id === "string" ? candidate.id : `candidate${index + 1}`, kind, summary: typeof candidate.summary === "string" ? candidate.summary : "", risk: "read", ...typeof candidate.options === "string" ? { options: candidate.options } : {} };
|
|
6644
7482
|
}
|
|
@@ -6654,7 +7492,7 @@ function requestbody(input) {
|
|
|
6654
7492
|
return JSON.stringify({ version: protocolversion, objective: input.objective, session: input.session, observation: input.observation, capabilities: input.capabilities });
|
|
6655
7493
|
}
|
|
6656
7494
|
function outcomeresponse(input) {
|
|
6657
|
-
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 } : {} });
|
|
7495
|
+
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 } } : {} });
|
|
6658
7496
|
}
|
|
6659
7497
|
function mapresponse(input) {
|
|
6660
7498
|
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, map: input.map });
|
|
@@ -6803,6 +7641,9 @@ function emulationreport(input) {
|
|
|
6803
7641
|
function sessionreport(input) {
|
|
6804
7642
|
return { version: protocolversion, records: input.records, events: input.events, folders: input.folders, diffs: input.diffs, ...input.auto !== void 0 ? { auto: input.auto } : {}, ...input.crashed === true ? { crashed: true } : {} };
|
|
6805
7643
|
}
|
|
7644
|
+
function workflowreport(input) {
|
|
7645
|
+
return { version: protocolversion, workflows: input.workflows, runs: input.runs, templates: input.templates, log: input.log ?? [], scopes: input.scopes ?? [], provenance: input.provenance ?? [] };
|
|
7646
|
+
}
|
|
6806
7647
|
export {
|
|
6807
7648
|
activelayers,
|
|
6808
7649
|
agentgrammarvalid,
|
|
@@ -6825,12 +7666,14 @@ export {
|
|
|
6825
7666
|
authorizeurl,
|
|
6826
7667
|
authreport,
|
|
6827
7668
|
autointervalof,
|
|
7669
|
+
bindvariables,
|
|
6828
7670
|
blackboxedurls,
|
|
6829
7671
|
blackboxmatches,
|
|
6830
7672
|
blackboxruleof,
|
|
6831
7673
|
blendrows,
|
|
6832
7674
|
blockgate,
|
|
6833
7675
|
blockingduration,
|
|
7676
|
+
blockinvocationof,
|
|
6834
7677
|
blockruleof,
|
|
6835
7678
|
bodyfilterof,
|
|
6836
7679
|
bodymatches,
|
|
@@ -6845,6 +7688,7 @@ export {
|
|
|
6845
7688
|
callgraphql,
|
|
6846
7689
|
callrest,
|
|
6847
7690
|
callsreport,
|
|
7691
|
+
cancelrun,
|
|
6848
7692
|
canexecute,
|
|
6849
7693
|
capturebody,
|
|
6850
7694
|
capturecode,
|
|
@@ -6870,6 +7714,7 @@ export {
|
|
|
6870
7714
|
channelorigin,
|
|
6871
7715
|
closechannel,
|
|
6872
7716
|
collectmessages,
|
|
7717
|
+
composeworkflow,
|
|
6873
7718
|
consolecapture,
|
|
6874
7719
|
consoleconsentcovers,
|
|
6875
7720
|
consolediff,
|
|
@@ -6892,6 +7737,7 @@ export {
|
|
|
6892
7737
|
debuggerconsentcovers,
|
|
6893
7738
|
debugwaitbudgetallowed,
|
|
6894
7739
|
dedupeimages,
|
|
7740
|
+
delayjitter,
|
|
6895
7741
|
actionrisk as deriveactionrisk,
|
|
6896
7742
|
detachcdpsession,
|
|
6897
7743
|
devicepresetof,
|
|
@@ -6899,6 +7745,8 @@ export {
|
|
|
6899
7745
|
diffreviewgrade,
|
|
6900
7746
|
diffsessionrecords,
|
|
6901
7747
|
downloadreport,
|
|
7748
|
+
dryrunprojection,
|
|
7749
|
+
dryrunworkflow,
|
|
6902
7750
|
emugate,
|
|
6903
7751
|
emulationkinds,
|
|
6904
7752
|
emulationreport,
|
|
@@ -6909,11 +7757,15 @@ export {
|
|
|
6909
7757
|
errorreportresponse,
|
|
6910
7758
|
eventresponse,
|
|
6911
7759
|
exchangesreport,
|
|
7760
|
+
expandblocks,
|
|
6912
7761
|
expirelayers,
|
|
6913
7762
|
expireprofilerecords,
|
|
6914
7763
|
expiresessions,
|
|
6915
7764
|
exportpresetlibrary,
|
|
6916
7765
|
exportsessionfile,
|
|
7766
|
+
expressioneval,
|
|
7767
|
+
expressionof,
|
|
7768
|
+
expressionoperators,
|
|
6917
7769
|
extractionreport,
|
|
6918
7770
|
extractvalues,
|
|
6919
7771
|
failureclass,
|
|
@@ -6959,6 +7811,7 @@ export {
|
|
|
6959
7811
|
issessionkind,
|
|
6960
7812
|
issocketkind,
|
|
6961
7813
|
iswatchkind,
|
|
7814
|
+
isworkflowkind,
|
|
6962
7815
|
jsonpathrulesof,
|
|
6963
7816
|
lapseframes,
|
|
6964
7817
|
lapseplanof,
|
|
@@ -6999,6 +7852,7 @@ export {
|
|
|
6999
7852
|
newrecording,
|
|
7000
7853
|
newsessiondiff,
|
|
7001
7854
|
newsessionrecord,
|
|
7855
|
+
newworkflowrun,
|
|
7002
7856
|
normalizeendpoint,
|
|
7003
7857
|
oauthflowof,
|
|
7004
7858
|
observationmodeof,
|
|
@@ -7013,9 +7867,11 @@ export {
|
|
|
7013
7867
|
parseproposal,
|
|
7014
7868
|
parsessetext,
|
|
7015
7869
|
parsetokens,
|
|
7870
|
+
parseworkflowproposal,
|
|
7016
7871
|
passwordconsentgranted,
|
|
7017
7872
|
patternorigin,
|
|
7018
7873
|
pauseretentionwindow,
|
|
7874
|
+
pauserun,
|
|
7019
7875
|
payloadshapeof,
|
|
7020
7876
|
payloadvalid,
|
|
7021
7877
|
payloadwithdefaults,
|
|
@@ -7032,6 +7888,7 @@ export {
|
|
|
7032
7888
|
pollcursorof,
|
|
7033
7889
|
polldecision,
|
|
7034
7890
|
pollurl,
|
|
7891
|
+
popscope,
|
|
7035
7892
|
privatemime,
|
|
7036
7893
|
profilegrantgranted,
|
|
7037
7894
|
profilereport,
|
|
@@ -7042,6 +7899,7 @@ export {
|
|
|
7042
7899
|
proxygate,
|
|
7043
7900
|
proxyrouteof,
|
|
7044
7901
|
publishmessage,
|
|
7902
|
+
pushscope,
|
|
7045
7903
|
quarantinereport,
|
|
7046
7904
|
randomid,
|
|
7047
7905
|
rankapis,
|
|
@@ -7056,6 +7914,8 @@ export {
|
|
|
7056
7914
|
recordwatchvalue,
|
|
7057
7915
|
redactconsoletext,
|
|
7058
7916
|
redactedcookies,
|
|
7917
|
+
regexextract,
|
|
7918
|
+
regexruleof,
|
|
7059
7919
|
regionsteps,
|
|
7060
7920
|
rejectioncapture,
|
|
7061
7921
|
replaytrace,
|
|
@@ -7063,6 +7923,7 @@ export {
|
|
|
7063
7923
|
requestbody,
|
|
7064
7924
|
resolutionverdict,
|
|
7065
7925
|
resolvedrisk,
|
|
7926
|
+
resolvevariable,
|
|
7066
7927
|
resourcefacts,
|
|
7067
7928
|
restoreoriginsgranted,
|
|
7068
7929
|
restoreplanof,
|
|
@@ -7076,6 +7937,8 @@ export {
|
|
|
7076
7937
|
rewritesourcelocation,
|
|
7077
7938
|
rotatelogs,
|
|
7078
7939
|
rotationruleof,
|
|
7940
|
+
runstep,
|
|
7941
|
+
runworkflow,
|
|
7079
7942
|
safetyresponse,
|
|
7080
7943
|
scaledrect,
|
|
7081
7944
|
seamweights,
|
|
@@ -7113,6 +7976,7 @@ export {
|
|
|
7113
7976
|
stackgate,
|
|
7114
7977
|
statusclassof,
|
|
7115
7978
|
stepmodeof,
|
|
7979
|
+
steptemplateof,
|
|
7116
7980
|
stepwindows,
|
|
7117
7981
|
streamsummaries,
|
|
7118
7982
|
streamwindowof,
|
|
@@ -7146,13 +8010,22 @@ export {
|
|
|
7146
8010
|
validatebreakpointcondition,
|
|
7147
8011
|
validatefieldmatch,
|
|
7148
8012
|
validateformrecord,
|
|
8013
|
+
validateregexrule,
|
|
7149
8014
|
validatestep,
|
|
7150
8015
|
validatetargetref,
|
|
7151
8016
|
validatevaluegen,
|
|
8017
|
+
validateworkflow,
|
|
8018
|
+
waitelementplan,
|
|
7152
8019
|
watchcdpevents,
|
|
7153
8020
|
watcherdetached,
|
|
7154
8021
|
watchexpressionof,
|
|
7155
8022
|
watchgate,
|
|
7156
|
-
wizardreport
|
|
8023
|
+
wizardreport,
|
|
8024
|
+
workflowblockof,
|
|
8025
|
+
workflowgate,
|
|
8026
|
+
workflowkinds,
|
|
8027
|
+
workflowoutcome,
|
|
8028
|
+
workflowreport,
|
|
8029
|
+
workflowstepof
|
|
7157
8030
|
};
|
|
7158
8031
|
//# sourceMappingURL=index.js.map
|