@wenathlan/extension 1.1.39 → 1.1.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,201 @@
1
+ // capture.ts
2
+ var captureformats = ["png", "jpeg", "webp"];
3
+ var capturetargets = ["memory", "download", "clipboard"];
4
+ var capturekinds = ["shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet"];
5
+ function captureoptionsof(value) {
6
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
7
+ const options = value;
8
+ const normalized = {};
9
+ if (options.format === "png" || options.format === "jpeg" || options.format === "webp") normalized.format = options.format;
10
+ if (typeof options.quality === "number" && Number.isFinite(options.quality)) normalized.quality = options.quality;
11
+ if (typeof options.pixelratio === "number" && Number.isFinite(options.pixelratio)) normalized.pixelratio = options.pixelratio;
12
+ if (typeof options.annotate === "boolean") normalized.annotate = options.annotate;
13
+ if (options.exporttarget === "memory" || options.exporttarget === "download" || options.exporttarget === "clipboard") normalized.exporttarget = options.exporttarget;
14
+ return normalized;
15
+ }
16
+ function capturevisible(input) {
17
+ const ratio = input.options.pixelratio ?? 1;
18
+ return {
19
+ id: input.id,
20
+ runid: input.runid,
21
+ stepid: input.stepid,
22
+ kind: "shotview",
23
+ format: input.options.format ?? "png",
24
+ width: Math.round(input.viewport.width * ratio),
25
+ height: Math.round(input.viewport.height * ratio),
26
+ capturedat: input.at,
27
+ bytes: input.dataurl,
28
+ ...input.name !== void 0 ? { name: input.name } : {},
29
+ ...input.options.annotate === true ? { annotated: true } : {},
30
+ ...input.options.exporttarget !== void 0 ? { exporttarget: input.options.exporttarget } : {},
31
+ ...input.target !== void 0 ? { target: input.target } : {}
32
+ };
33
+ }
34
+ function capturestitched(input) {
35
+ const ratio = input.options.pixelratio ?? 1;
36
+ return {
37
+ id: input.id,
38
+ runid: input.runid,
39
+ stepid: input.stepid,
40
+ kind: "shotfullpage",
41
+ format: input.options.format ?? "png",
42
+ width: Math.round(input.plan.scrollwidth * ratio),
43
+ height: Math.round(input.plan.scrollheight * ratio),
44
+ capturedat: input.at,
45
+ bytes: input.dataurl,
46
+ ...input.name !== void 0 ? { name: input.name } : {},
47
+ ...input.options.annotate === true ? { annotated: true } : {},
48
+ ...input.options.exporttarget !== void 0 ? { exporttarget: input.options.exporttarget } : {}
49
+ };
50
+ }
51
+ function captureelement(input) {
52
+ const ratio = input.options.pixelratio ?? 1;
53
+ const scaled = scaledrect(input.rect, ratio);
54
+ return {
55
+ id: input.id,
56
+ runid: input.runid,
57
+ stepid: input.stepid,
58
+ kind: "shotelement",
59
+ format: input.options.format ?? "png",
60
+ width: scaled.width,
61
+ height: scaled.height,
62
+ capturedat: input.at,
63
+ bytes: input.dataurl,
64
+ ...input.name !== void 0 ? { name: input.name } : {},
65
+ ...input.options.annotate === true ? { annotated: true } : {},
66
+ ...input.options.exporttarget !== void 0 ? { exporttarget: input.options.exporttarget } : {},
67
+ ...input.target !== void 0 ? { target: input.target } : {}
68
+ };
69
+ }
70
+ function captureregion(input) {
71
+ const ratio = input.options.pixelratio ?? 1;
72
+ const scaled = scaledrect(input.rect, ratio);
73
+ return {
74
+ id: input.id,
75
+ runid: input.runid,
76
+ stepid: input.stepid,
77
+ kind: "shotregion",
78
+ format: input.options.format ?? "png",
79
+ width: scaled.width,
80
+ height: scaled.height,
81
+ capturedat: input.at,
82
+ bytes: input.dataurl,
83
+ ...input.name !== void 0 ? { name: input.name } : {},
84
+ ...input.options.annotate === true ? { annotated: true } : {},
85
+ ...input.options.exporttarget !== void 0 ? { exporttarget: input.options.exporttarget } : {},
86
+ ...input.target !== void 0 ? { target: input.target } : {}
87
+ };
88
+ }
89
+ function pairstates(before, after, action, at, id) {
90
+ if (!before) return { skipped: "before", reason: "The before shot was not captured, so no state pair exists." };
91
+ if (!after) return { skipped: "after", reason: `The action of kind ${action.kind} failed before the after shot, so the state pair is skipped.` };
92
+ return {
93
+ pair: {
94
+ id,
95
+ beforeid: before.id,
96
+ afterid: after.id,
97
+ actionkind: action.kind,
98
+ ...action.target !== void 0 ? { target: action.target } : {},
99
+ ...action.domsnapshotid !== void 0 ? { domsnapshotid: action.domsnapshotid } : {},
100
+ at
101
+ },
102
+ reason: `Paired the before shot ${before.id} with the after shot ${after.id} around the ${action.kind} action.`
103
+ };
104
+ }
105
+ function capturestates(input) {
106
+ if (input.policy !== "beforeafter") return { reason: `The ${input.policy} capture policy takes no state pair around the ${input.actionkind} action.` };
107
+ return pairstates(input.before, input.after, { kind: input.actionkind, ...input.target !== void 0 ? { target: input.target } : {}, ...input.domsnapshotid !== void 0 ? { domsnapshotid: input.domsnapshotid } : {} }, input.at, input.id);
108
+ }
109
+ function buildstitchplan(input) {
110
+ const overlap = Math.max(0, Math.round(input.overlap ?? 0));
111
+ const stepy = Math.max(1, input.viewportheight - overlap);
112
+ const columns = Math.max(1, Math.ceil(input.scrollwidth / input.viewportwidth));
113
+ const rows = input.scrollheight <= input.viewportheight ? 1 : Math.max(1, Math.ceil((input.scrollheight - overlap) / stepy));
114
+ const tiles = [];
115
+ for (let column = 0; column < columns; column += 1) {
116
+ for (let row = 0; row < rows; row += 1) {
117
+ const x = Math.min(column * input.viewportwidth, Math.max(0, input.scrollwidth - input.viewportwidth));
118
+ const y = rows === 1 ? 0 : Math.min(row * stepy, Math.max(0, input.scrollheight - input.viewportheight));
119
+ tiles.push({ x: Math.round(x), y: Math.round(y) });
120
+ }
121
+ }
122
+ return { columns, rows, tiles, overlap, scrollwidth: Math.round(input.scrollwidth), scrollheight: Math.round(input.scrollheight), viewportwidth: Math.round(input.viewportwidth), viewportheight: Math.round(input.viewportheight) };
123
+ }
124
+ function seamweights(overlap) {
125
+ if (overlap <= 0) return [];
126
+ const weights = [];
127
+ for (let index = 0; index < overlap; index += 1) weights.push((index + 1) / (overlap + 1));
128
+ return weights;
129
+ }
130
+ function blendrows(upper, lower) {
131
+ const weights = seamweights(upper.length);
132
+ return upper.map((value, index) => {
133
+ const weight = weights[index] ?? 1;
134
+ return value * (1 - weight) + (lower[index] ?? value) * weight;
135
+ });
136
+ }
137
+ function fixedheadermatch(band, firstband) {
138
+ if (band.length === 0 || band.length !== firstband.length) return false;
139
+ return band.every((value, index) => value === firstband[index]);
140
+ }
141
+ function scaledrect(rect, pixelratio) {
142
+ const ratio = pixelratio >= 1 ? pixelratio : 1;
143
+ return { x: Math.round(rect.x * ratio), y: Math.round(rect.y * ratio), width: Math.round(rect.width * ratio), height: Math.round(rect.height * ratio) };
144
+ }
145
+ function croprect(rect, viewport) {
146
+ const x = Math.max(0, rect.x);
147
+ const y = Math.max(0, rect.y);
148
+ return { x: Math.round(x), y: Math.round(y), width: Math.round(Math.max(0, Math.min(rect.width, viewport.width - x))), height: Math.round(Math.max(0, Math.min(rect.height, viewport.height - y))) };
149
+ }
150
+ function crossesviewport(rect, viewport) {
151
+ return rect.x < 0 || rect.y < 0 || rect.x + rect.width > viewport.width || rect.y + rect.height > viewport.height;
152
+ }
153
+ function regionsteps(containerheight, viewportstep) {
154
+ if (containerheight <= 0 || viewportstep <= 0) return [0];
155
+ const steps = [];
156
+ for (let top = 0; top < containerheight; top += viewportstep) {
157
+ const clamped = Math.min(top, Math.max(0, containerheight - viewportstep));
158
+ if (!steps.includes(clamped)) steps.push(clamped);
159
+ }
160
+ return steps;
161
+ }
162
+ function buildsheet(cells, layout) {
163
+ const columns = Math.max(1, Math.round(layout.columns));
164
+ const rows = Math.max(1, Math.ceil(cells.length / columns));
165
+ const placed = cells.map((cell, index) => {
166
+ const column = index % columns;
167
+ const row = Math.floor(index / columns);
168
+ const label = cell.label ?? "";
169
+ const caption = layout.label === "none" ? "" : layout.label === "index" ? `${index + 1}` : layout.label === "selector" ? cell.selector : label ? `${index + 1} \xB7 ${cell.selector} \xB7 ${label}` : `${index + 1} \xB7 ${cell.selector}`;
170
+ return { index, column, row, selector: cell.selector, label, caption };
171
+ });
172
+ return { columns, rows, cells: placed };
173
+ }
174
+ function capturepart(value) {
175
+ return value.replace(/[^a-z0-9-]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase() || "capture";
176
+ }
177
+ function buildname(rule, parts, extension) {
178
+ const segments = [];
179
+ if (rule.run) segments.push(capturepart(parts.run));
180
+ if (rule.step) segments.push(capturepart(parts.step));
181
+ if (rule.sequence) segments.push(String(Math.max(0, Math.round(parts.sequence))));
182
+ if (rule.kind) segments.push(capturepart(parts.kind));
183
+ const safeextension = extension.replace(/^\.+/, "").toLowerCase() || "png";
184
+ return `${(segments.length > 0 ? segments : ["capture"]).join("-")}.${safeextension}`;
185
+ }
186
+ function annotationplanof(input) {
187
+ const inset = Math.min(24, Math.max(8, Math.round(Math.min(input.width, input.height) / 12)));
188
+ const plan = {
189
+ marker: { x: inset, y: inset, number: Math.max(1, Math.round(input.step)) },
190
+ footer: `${new Date(input.at).toISOString()} \xB7 ${input.url}`
191
+ };
192
+ if (input.rect !== void 0) {
193
+ const expansion = 2;
194
+ plan.outline = { x: Math.round(input.rect.x - expansion), y: Math.round(input.rect.y - expansion), width: Math.round(input.rect.width + expansion * 2), height: Math.round(input.rect.height + expansion * 2) };
195
+ }
196
+ return plan;
197
+ }
198
+
1
199
  // memory.ts
2
200
  var sessionmemory = class {
3
201
  constructor(adapter) {
@@ -731,7 +929,46 @@ var sessionmemory = class {
731
929
  async getmimefilters() {
732
930
  return await this.adapter.get("mimefilters") ?? [];
733
931
  }
932
+ /** Stores one capture record with its bytes and step linkage, replacing the previous record of that id; the user configured capture retention window expires the oldest bytes while the metadata always survives for the audit trail. */
933
+ async addcapture(record2) {
934
+ const records = await this.getcaptures();
935
+ const retention = (await this.getsettings())?.captureretention;
936
+ const combined = [record2, ...records.filter((item) => item.id !== record2.id)];
937
+ const stored = retention === void 0 ? combined : combined.map((item, index) => index < retention ? item : expirecapturebytes(item));
938
+ await this.adapter.set("captures", stored);
939
+ }
940
+ /** Returns every stored capture record with its metadata, newest first. */
941
+ async getcaptures() {
942
+ return await this.adapter.get("captures") ?? [];
943
+ }
944
+ /** Returns one capture record with its bytes by its id. */
945
+ async getcapture(id) {
946
+ return (await this.getcaptures()).find((item) => item.id === id);
947
+ }
948
+ /** Returns the capture records filtered by run, step and kind. */
949
+ async listcaptures(filter) {
950
+ const records = await this.getcaptures();
951
+ return records.filter((item) => (filter.runid === void 0 || item.runid === filter.runid) && (filter.stepid === void 0 || item.stepid === filter.stepid) && (filter.kind === void 0 || item.kind === filter.kind));
952
+ }
953
+ /** Records one before and after shotpair of the run with its action context. */
954
+ async addpair(pair) {
955
+ const records = await this.getpairs();
956
+ await this.adapter.set("capturepairs", [pair, ...records.filter((item) => item.id !== pair.id)]);
957
+ }
958
+ /** Returns the shotpairs of one run resolved through their before records, newest first; an absent run returns every pair. */
959
+ async getpairs(runid) {
960
+ const records = await this.adapter.get("capturepairs") ?? [];
961
+ if (runid === void 0) return records;
962
+ const runs = /* @__PURE__ */ new Map();
963
+ for (const capture of await this.getcaptures()) runs.set(capture.id, capture.runid);
964
+ return records.filter((item) => runs.get(item.beforeid) === runid);
965
+ }
734
966
  };
967
+ function expirecapturebytes(record2) {
968
+ const { bytes, ...metadata } = record2;
969
+ void bytes;
970
+ return { ...metadata, bytesexpired: true };
971
+ }
735
972
  function randomid() {
736
973
  return crypto.randomUUID();
737
974
  }
@@ -739,16 +976,17 @@ function randomid() {
739
976
  // policy.ts
740
977
  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"]);
741
978
  var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction"]);
742
- 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"]);
979
+ 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"]);
743
980
  var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
744
981
  var watchactions = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "watchtab"]);
745
- 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"]);
982
+ 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"]);
746
983
  var valueactions = /* @__PURE__ */ new Set(["presskey", "drag", "drop", "upload", "readattribute", "removeattribute", "waittext", "evaluate", "zoomset", "tabactivate", "tabclose", "tabreload", "windowclose", "windowresize", "tabcreate", "windowcreate", "downloadfile", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "chooseradio", "setslider", "setdate", "setcolor", "followlink", "setfragment", "handleauth", "navintent", "openclipboard", "checksafe", "reopentab", "spanav", "duplicatetab", "pintab", "mutetab", "movetab", "movetabwindow", "searchtabs", "badgetab", "attachmeta", "focuswindow", "maximizewindow", "minimizewindow", "restorewindow", "incognitowindow", "asksubmit", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcode", "consentpassword", "pausedownload", "resumedownload", "verifydownload", "writeclipboard", "quarantinedownload", "scanvirus"]);
747
984
  var tabscommandactions = /* @__PURE__ */ new Set(["querytabs", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "watchtab", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "savelayout", "restorelayout", "findclones", "searchtabs", "badgetab", "attachmeta", "listaudio", "reopenrun", "snapshotsession"]);
748
985
  var formactions = /* @__PURE__ */ new Set(["fillform", "filllabel", "fillplaceholder", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "submitform", "readerrors", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "handoffcaptcha", "fillcard", "fillcode", "consentpassword", "skiphoneypot", "detectlogin", "detecttemplate"]);
749
986
  var datasetactions = /* @__PURE__ */ new Set(["scrapetable", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "importcsv", "looprows", "transformvalues", "deduperows", "paginateextract", "mergepages", "stamplerows", "previewgrid", "streamdisk", "resumeextract", "logprovenance"]);
750
987
  var exportactions = /* @__PURE__ */ new Set(["exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk"]);
751
988
  var filesactions = /* @__PURE__ */ new Set(["batchdownload", "pausedownload", "resumedownload", "verifydownload", "interceptmime", "exportnetlog", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "namecaptures", "cleanupartifacts"]);
989
+ var captureactions = /* @__PURE__ */ new Set(["shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet"]);
752
990
  var fieldkinds = ["text", "email", "phone", "date", "number", "select", "check", "radio", "file", "password", "card", "code"];
753
991
  var layoutmutationactions = /* @__PURE__ */ new Set(["grouptabs", "colorgroup", "collapsegroup", "savelayout", "restorelayout"]);
754
992
  var groupcolors = ["grey", "blue", "red", "yellow", "green", "pink", "purple", "cyan", "orange"];
@@ -805,6 +1043,83 @@ function isexportkind(kind) {
805
1043
  function isfileskind(kind) {
806
1044
  return filesactions.has(kind);
807
1045
  }
1046
+ function iscapturekind(kind) {
1047
+ return captureactions.has(kind);
1048
+ }
1049
+ function capturegate(session, tabid, origin, now) {
1050
+ if (!session || session.stoppedat) return { allowed: false, reason: "No active browser session exists for the capture." };
1051
+ if (session.expiresat <= now) return { allowed: false, reason: "The browser session has expired and cannot capture." };
1052
+ if (session.pausedat) return { allowed: false, reason: "The browser session is paused and cannot capture." };
1053
+ if (session.tabid !== tabid) return { allowed: false, reason: `The capture needs the active tab grant of session tab ${session.tabid} and refuses tab ${tabid}.` };
1054
+ if (!origingranted(session, origin)) return { allowed: false, reason: `The capture of ${origin} needs the session origin grants first.` };
1055
+ return { allowed: true };
1056
+ }
1057
+ function validatecaptureoptions(value) {
1058
+ if (value === void 0) return { allowed: true };
1059
+ if (!value || typeof value !== "object" || Array.isArray(value)) return { allowed: false, reason: "The reviewed capture options must be an object in options.capture." };
1060
+ const options = value;
1061
+ if (options.format !== void 0 && options.format !== "png" && options.format !== "jpeg" && options.format !== "webp") return { allowed: false, reason: "The reviewed capture format must be png, jpeg or webp." };
1062
+ if (options.quality !== void 0 && (typeof options.quality !== "number" || !Number.isFinite(options.quality) || options.quality < 0 || options.quality > 100)) return { allowed: false, reason: "The reviewed capture quality must stay between zero and one hundred; any value in that range is the user choice with no code cap." };
1063
+ if (options.pixelratio !== void 0 && (typeof options.pixelratio !== "number" || !Number.isFinite(options.pixelratio) || options.pixelratio < 1)) return { allowed: false, reason: "The reviewed pixel ratio starts at one and climbs to any user configured ceiling with no code ceiling." };
1064
+ if (options.annotate !== void 0 && typeof options.annotate !== "boolean") return { allowed: false, reason: "The reviewed capture annotation flag must be a boolean." };
1065
+ if (options.exporttarget !== void 0 && options.exporttarget !== "memory" && options.exporttarget !== "download" && options.exporttarget !== "clipboard") return { allowed: false, reason: "The reviewed capture export target must be memory, download or clipboard." };
1066
+ return { allowed: true };
1067
+ }
1068
+ function validateregionrect(value) {
1069
+ if (!value || typeof value !== "object" || Array.isArray(value)) return { allowed: false, reason: "A reviewed regionrect with x, y, width and height in css pixels is required in options." };
1070
+ const rect = value;
1071
+ for (const field of ["x", "y", "width", "height"]) {
1072
+ if (typeof rect[field] !== "number" || !Number.isFinite(rect[field])) return { allowed: false, reason: `The reviewed regionrect needs a numeric ${field} in css pixels.` };
1073
+ }
1074
+ if (rect.x < 0 || rect.y < 0) return { allowed: false, reason: "The reviewed regionrect refuses negative coordinates." };
1075
+ if (rect.width <= 0 || rect.height <= 0) return { allowed: false, reason: "The reviewed regionrect needs positive width and height values." };
1076
+ return { allowed: true };
1077
+ }
1078
+ function validatecapturenaming(value) {
1079
+ if (!value || typeof value !== "object" || Array.isArray(value)) return { allowed: false, reason: "A reviewed capturenaming rule with run, step, sequence and kind flags is required." };
1080
+ const rule = value;
1081
+ const segments = ["run", "step", "sequence", "kind"];
1082
+ for (const key of Object.keys(rule)) {
1083
+ if (!segments.includes(key)) return { allowed: false, reason: `The reviewed capturenaming rule refuses the unknown ${key} segment; only run, step, sequence and kind participate.` };
1084
+ }
1085
+ for (const segment of segments) {
1086
+ if (rule[segment] !== void 0 && typeof rule[segment] !== "boolean") return { allowed: false, reason: `The reviewed capturenaming ${segment} flag must be a boolean.` };
1087
+ }
1088
+ if (!segments.some((segment) => rule[segment] === true)) return { allowed: false, reason: "The reviewed capturenaming rule needs at least one enabled segment of run, step, sequence and kind." };
1089
+ return { allowed: true };
1090
+ }
1091
+ function validatecapturegrammar(step, options) {
1092
+ const kind = step.kind;
1093
+ const optioncheck = validatecaptureoptions(options.capture);
1094
+ if (!optioncheck.allowed) return optioncheck;
1095
+ if (options.settle !== void 0 && (typeof options.settle !== "number" || !Number.isFinite(options.settle) || options.settle < 0)) return { allowed: false, reason: "The reviewed capture settle window must be zero or a positive number of milliseconds." };
1096
+ if (options.overlap !== void 0 && (typeof options.overlap !== "number" || !Number.isInteger(options.overlap) || options.overlap < 0)) return { allowed: false, reason: "The reviewed stitch overlap must be zero or a positive number of rows." };
1097
+ if (options.wait !== void 0 && (typeof options.wait !== "number" || !Number.isFinite(options.wait) || options.wait < 0)) return { allowed: false, reason: "The reviewed capture wait window must be zero or a positive number of milliseconds." };
1098
+ if (options.naming !== void 0) {
1099
+ const namingcheck = validatecapturenaming(options.naming);
1100
+ if (!namingcheck.allowed) return namingcheck;
1101
+ }
1102
+ if (kind === "shotregion") {
1103
+ const rectcheck = validateregionrect(options.regionrect);
1104
+ if (!rectcheck.allowed) return rectcheck;
1105
+ if (options.reviewed !== true) return { allowed: false, reason: "Every reviewed regionrect needs the explicit reviewed flag before shotregion runs." };
1106
+ if (options.container !== void 0 && !isnonempty(options.container)) return { allowed: false, reason: "The reviewed scrollable container selector must be a non-empty string." };
1107
+ if (options.steps !== void 0 && (typeof options.steps !== "number" || !Number.isInteger(options.steps) || options.steps < 1)) return { allowed: false, reason: "The reviewed container scroll steps must be a positive integer with no code ceiling." };
1108
+ }
1109
+ if (kind === "contactsheet") {
1110
+ const elements = options.elements;
1111
+ if (!Array.isArray(elements) || elements.length === 0 || !elements.every((item) => isnonempty(item))) return { allowed: false, reason: "A reviewed non-empty list of element selectors is required in options for the contact sheet; the cell count stays the user choice." };
1112
+ const layout = options.sheet;
1113
+ if (layout !== void 0) {
1114
+ if (!layout || typeof layout !== "object" || Array.isArray(layout)) return { allowed: false, reason: "The reviewed sheetlayout must be an object with cellsize, columns and label." };
1115
+ const sheet = layout;
1116
+ if (typeof sheet.cellsize !== "number" || !Number.isFinite(sheet.cellsize) || sheet.cellsize <= 0) return { allowed: false, reason: "The reviewed contact sheet cell size must be a positive number of pixels." };
1117
+ if (typeof sheet.columns !== "number" || !Number.isInteger(sheet.columns) || sheet.columns < 1) return { allowed: false, reason: "The reviewed contact sheet column count must be a positive integer with no code ceiling." };
1118
+ if (sheet.label !== void 0 && sheet.label !== "none" && sheet.label !== "index" && sheet.label !== "selector" && sheet.label !== "both") return { allowed: false, reason: "The reviewed contact sheet label style must be none, index, selector or both." };
1119
+ }
1120
+ }
1121
+ return { allowed: true };
1122
+ }
808
1123
  function exportgranted(session, origin) {
809
1124
  if (!origingranted(session, origin)) return { allowed: false, reason: `The export of extracted data from ${origin} needs the session origin grants before it leaves local memory.` };
810
1125
  return { allowed: true };
@@ -1590,6 +1905,10 @@ function validatestep(step, origin) {
1590
1905
  const filescheck = validatefilesgrammar(step, options);
1591
1906
  if (!filescheck.allowed) return filescheck;
1592
1907
  }
1908
+ if (iscapturekind(step.kind)) {
1909
+ const capturecheck = validatecapturegrammar(step, options);
1910
+ if (!capturecheck.allowed) return capturecheck;
1911
+ }
1593
1912
  if (step.kind === "tabcreate") {
1594
1913
  if (options.background !== void 0 && typeof options.background !== "boolean") return { allowed: false, reason: "The reviewed background flag must be a boolean." };
1595
1914
  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." };
@@ -1649,6 +1968,18 @@ function canexecute(input) {
1649
1968
  if (!clipgate.allowed) return clipgate;
1650
1969
  }
1651
1970
  if (input.step.kind === "interceptmime" && !origingranted(input.session, input.origin)) return { allowed: false, reason: "The download interception is outside the session origin grants." };
1971
+ if (iscapturekind(input.step.kind)) {
1972
+ const capturegatecheck = capturegate(input.session, input.tabid, input.origin, now);
1973
+ if (!capturegatecheck.allowed) return capturegatecheck;
1974
+ let captureoptions = {};
1975
+ try {
1976
+ captureoptions = parseoptions(input.step);
1977
+ } catch {
1978
+ captureoptions = {};
1979
+ }
1980
+ const target = captureoptions.capture?.exporttarget;
1981
+ if (target !== void 0 && target !== "memory" && target !== "download" && target !== "clipboard") return { allowed: false, reason: "The capture export target must be memory, download or clipboard." };
1982
+ }
1652
1983
  if (input.step.kind === "openlink" || input.step.kind === "openprivate" || input.step.kind === "batchopen" || input.step.kind === "prefetch" || input.step.kind === "deeplink" || input.step.kind === "reopentab") {
1653
1984
  let options = {};
1654
1985
  try {
@@ -1670,7 +2001,7 @@ function canexecute(input) {
1670
2001
  }
1671
2002
 
1672
2003
  // version.ts
1673
- var packageversion = "1.1.39";
2004
+ var packageversion = "1.1.40";
1674
2005
 
1675
2006
  // types.ts
1676
2007
  var protocolversion = packageversion;
@@ -1734,7 +2065,7 @@ function requestbody(input) {
1734
2065
  return JSON.stringify({ version: protocolversion, objective: input.objective, session: input.session, observation: input.observation, capabilities: input.capabilities });
1735
2066
  }
1736
2067
  function outcomeresponse(input) {
1737
- return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, outcome: input.outcome, ...input.resolvedtarget ? { resolvedtarget: input.resolvedtarget } : {} });
2068
+ 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 } : {} });
1738
2069
  }
1739
2070
  function mapresponse(input) {
1740
2071
  return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, map: input.map });
@@ -1811,8 +2142,28 @@ function netlogreport(input) {
1811
2142
  function quarantinereport(input) {
1812
2143
  return { version: protocolversion, entries: input.entries };
1813
2144
  }
2145
+ function capturereport(input) {
2146
+ return { version: protocolversion, records: input.records, pairs: input.pairs };
2147
+ }
1814
2148
  export {
2149
+ annotationplanof,
2150
+ blendrows,
2151
+ buildname,
2152
+ buildsheet,
2153
+ buildstitchplan,
1815
2154
  canexecute,
2155
+ captureelement,
2156
+ captureformats,
2157
+ capturekinds,
2158
+ captureoptionsof,
2159
+ captureregion,
2160
+ capturereport,
2161
+ capturestates,
2162
+ capturestitched,
2163
+ capturetargets,
2164
+ capturevisible,
2165
+ croprect,
2166
+ crossesviewport,
1816
2167
  datasetresponse,
1817
2168
  actionrisk as deriveactionrisk,
1818
2169
  diffresponse,
@@ -1820,6 +2171,7 @@ export {
1820
2171
  errorreportresponse,
1821
2172
  eventresponse,
1822
2173
  extractionreport,
2174
+ fixedheadermatch,
1823
2175
  formreportresponse,
1824
2176
  generatedvalueallowed,
1825
2177
  heldkeysreport,
@@ -1834,6 +2186,7 @@ export {
1834
2186
  observationmodeof,
1835
2187
  observationresponse,
1836
2188
  outcomeresponse,
2189
+ pairstates,
1837
2190
  parseproposal,
1838
2191
  passwordconsentgranted,
1839
2192
  profilegrantgranted,
@@ -1841,9 +2194,12 @@ export {
1841
2194
  provenancereport,
1842
2195
  quarantinereport,
1843
2196
  randomid,
2197
+ regionsteps,
1844
2198
  requestbody,
1845
2199
  resolutionverdict,
1846
2200
  safetyresponse,
2201
+ scaledrect,
2202
+ seamweights,
1847
2203
  selectorresponse,
1848
2204
  sessionmemory,
1849
2205
  signalsreport,