@wenathlan/extension 1.1.39 → 1.1.41

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,503 @@
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
+
199
+ // media.ts
200
+ var mediakinds = ["capturepdf", "recordscreen", "captureaudio", "captureframe", "downloadimages", "shotcanvas", "probestream", "readmedia", "readassets", "timelapse", "convertimage", "makethumbs"];
201
+ var defaultpaperwidth = 8.5;
202
+ var defaultpaperheight = 11;
203
+ var defaultmargins = { top: 0.4, right: 0.4, bottom: 0.4, left: 0.4 };
204
+ var pdfpointsperinch = 72;
205
+ var basefontsize = 11;
206
+ function pdfoptionsof(value) {
207
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
208
+ const options = value;
209
+ const normalized = {};
210
+ if (typeof options.paperwidth === "number" && Number.isFinite(options.paperwidth)) normalized.paperwidth = options.paperwidth;
211
+ if (typeof options.paperheight === "number" && Number.isFinite(options.paperheight)) normalized.paperheight = options.paperheight;
212
+ if (options.margins && typeof options.margins === "object" && !Array.isArray(options.margins)) {
213
+ const margins = options.margins;
214
+ const top = typeof margins.top === "number" ? margins.top : defaultmargins.top;
215
+ const right = typeof margins.right === "number" ? margins.right : defaultmargins.right;
216
+ const bottom = typeof margins.bottom === "number" ? margins.bottom : defaultmargins.bottom;
217
+ const left = typeof margins.left === "number" ? margins.left : defaultmargins.left;
218
+ normalized.margins = { top, right, bottom, left };
219
+ }
220
+ if (typeof options.scale === "number" && Number.isFinite(options.scale)) normalized.scale = options.scale;
221
+ if (typeof options.landscape === "boolean") normalized.landscape = options.landscape;
222
+ if (typeof options.paginate === "boolean") normalized.paginate = options.paginate;
223
+ return normalized;
224
+ }
225
+ function pdfpagesize(options) {
226
+ const width = (options.paperwidth ?? defaultpaperwidth) * pdfpointsperinch;
227
+ const height = (options.paperheight ?? defaultpaperheight) * pdfpointsperinch;
228
+ return options.landscape === true ? { width: height, height: width } : { width, height };
229
+ }
230
+ function pdfmargins(options) {
231
+ const margins = options.margins ?? defaultmargins;
232
+ return { top: margins.top * pdfpointsperinch, right: margins.right * pdfpointsperinch, bottom: margins.bottom * pdfpointsperinch, left: margins.left * pdfpointsperinch };
233
+ }
234
+ function pdffontsize(options) {
235
+ return basefontsize * (options.scale ?? 1);
236
+ }
237
+ function pdftextlayout(text2, options) {
238
+ const size = pdfpagesize(options);
239
+ const margins = pdfmargins(options);
240
+ const fontsize = pdffontsize(options);
241
+ const leading = fontsize * 1.35;
242
+ const linesperpage = Math.max(1, Math.floor((size.height - margins.top - margins.bottom) / leading));
243
+ const columns = Math.max(1, Math.floor((size.width - margins.left - margins.right) / (fontsize * 0.5)));
244
+ const wrapped = [];
245
+ for (const paragraph of text2.split(/\r?\n/)) {
246
+ let line = "";
247
+ for (const word of paragraph.split(/\s+/).filter(Boolean)) {
248
+ const candidate = line ? `${line} ${word}` : word;
249
+ if (candidate.length <= columns) {
250
+ line = candidate;
251
+ continue;
252
+ }
253
+ if (line) wrapped.push(line);
254
+ if (word.length <= columns) {
255
+ line = word;
256
+ continue;
257
+ }
258
+ for (let index = 0; index < word.length; index += columns) wrapped.push(word.slice(index, index + columns));
259
+ line = "";
260
+ }
261
+ wrapped.push(line);
262
+ if (wrapped.length >= linesperpage) break;
263
+ }
264
+ return wrapped.slice(0, linesperpage);
265
+ }
266
+ function pdfsegments(scrollheight, viewportheight, breaks) {
267
+ if (scrollheight <= 0) return [];
268
+ const step = viewportheight > 0 ? viewportheight : scrollheight;
269
+ const cuts = [0, ...breaks.filter((top) => Number.isFinite(top) && top > 0 && top < scrollheight).map((top) => Math.round(top))].filter((top, index2, list) => list.indexOf(top) === index2).sort((left, right) => left - right);
270
+ const segments = [];
271
+ let index = 0;
272
+ let cursor = 0;
273
+ while (cursor < scrollheight) {
274
+ while (index < cuts.length && (cuts[index] ?? 0) <= cursor) index += 1;
275
+ const nextcut = index < cuts.length ? cuts[index] : void 0;
276
+ const next = nextcut !== void 0 ? Math.min(nextcut, scrollheight) : Math.min(cursor + step, scrollheight);
277
+ if (next <= cursor) break;
278
+ segments.push({ top: cursor, height: next - cursor });
279
+ cursor = next;
280
+ }
281
+ return segments.length > 0 ? segments : [{ top: 0, height: scrollheight }];
282
+ }
283
+ function pdfescape(text2) {
284
+ let escaped = "";
285
+ for (const character of text2) {
286
+ const code = character.charCodeAt(0);
287
+ if (character === "(" || character === ")" || character === "\\") escaped += `\\${character}`;
288
+ else if (code >= 32 && code <= 255) escaped += character;
289
+ else escaped += "?";
290
+ }
291
+ return escaped;
292
+ }
293
+ function buildpdf(pages, options) {
294
+ const size = pdfpagesize(options);
295
+ const margins = pdfmargins(options);
296
+ const fontsize = pdffontsize(options);
297
+ const leading = fontsize * 1.35;
298
+ const laidout = (pages.length > 0 ? pages : [""]).map((text2) => pdftextlayout(text2, options));
299
+ const objects = [];
300
+ const kids = laidout.map((_, index) => `${4 + index * 2} 0 R`).join(" ");
301
+ objects.push(`<< /Type /Catalog /Pages 2 0 R >>`);
302
+ objects.push(`<< /Type /Pages /Kids [${kids}] /Count ${laidout.length} >>`);
303
+ objects.push(`<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>`);
304
+ for (let pageindex = 0; pageindex < laidout.length; pageindex += 1) {
305
+ const lines = laidout[pageindex] ?? [];
306
+ const operators = ["BT", `/F1 ${fontsize} Tf`, `${leading.toFixed(2)} TL`, `${margins.left.toFixed(2)} ${(size.height - margins.top - fontsize).toFixed(2)} Td`];
307
+ for (let lineindex = 0; lineindex < lines.length; lineindex += 1) {
308
+ if (lineindex > 0) operators.push("T*");
309
+ operators.push(`(${pdfescape(lines[lineindex] ?? "")}) Tj`);
310
+ }
311
+ operators.push("ET");
312
+ const content = operators.join("\n");
313
+ objects.push(`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${size.width.toFixed(2)} ${size.height.toFixed(2)}] /Resources << /Font << /F1 3 0 R >> >> /Contents ${5 + pageindex * 2} 0 R >>`);
314
+ objects.push(`<< /Length ${content.length} >>
315
+ stream
316
+ ${content}
317
+ endstream`);
318
+ }
319
+ let document = "%PDF-1.4\n";
320
+ const offsets = [];
321
+ for (let index = 0; index < objects.length; index += 1) {
322
+ offsets.push(document.length);
323
+ document += `${index + 1} 0 obj
324
+ ${objects[index]}
325
+ endobj
326
+ `;
327
+ }
328
+ const xrefstart = document.length;
329
+ document += `xref
330
+ 0 ${objects.length + 1}
331
+ 0000000000 65535 f
332
+ `;
333
+ for (const offset of offsets) document += `${String(offset).padStart(10, "0")} 00000 n
334
+ `;
335
+ document += `trailer
336
+ << /Size ${objects.length + 1} /Root 1 0 R >>
337
+ startxref
338
+ ${xrefstart}
339
+ %%EOF
340
+ `;
341
+ return { document, bytes: document.length, pages: laidout.length, pagewidth: Math.round(size.width), pageheight: Math.round(size.height) };
342
+ }
343
+ function recordingoptionsof(value) {
344
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
345
+ const options = value;
346
+ const normalized = {};
347
+ if (options.scope === "tab" || options.scope === "run") normalized.scope = options.scope;
348
+ if (typeof options.fps === "number" && Number.isFinite(options.fps)) normalized.fps = options.fps;
349
+ if (typeof options.bitrate === "number" && Number.isFinite(options.bitrate)) normalized.bitrate = options.bitrate;
350
+ if (typeof options.audio === "boolean") normalized.audio = options.audio;
351
+ return normalized;
352
+ }
353
+ function newrecording(input) {
354
+ return {
355
+ id: input.id,
356
+ runid: input.runid,
357
+ stepid: input.stepid,
358
+ tabid: input.tabid,
359
+ kind: input.kind,
360
+ scope: input.options.scope ?? "tab",
361
+ format: input.kind === "audio" ? "evidence" : "frames",
362
+ startedat: input.at,
363
+ at: input.at,
364
+ ...input.options.fps !== void 0 ? { fps: input.options.fps } : {},
365
+ ...input.options.bitrate !== void 0 ? { bitrate: input.options.bitrate } : {},
366
+ ...input.options.audio !== void 0 ? { audio: input.options.audio } : {},
367
+ frames: []
368
+ };
369
+ }
370
+ function finishrecording(record2, endat) {
371
+ return { ...record2, endedat: endat, duration: Math.max(0, endat - record2.startedat) };
372
+ }
373
+ function frameinterval(fps) {
374
+ if (!Number.isFinite(fps) || fps <= 0) return 1e3;
375
+ return Math.max(1, Math.round(1e3 / fps));
376
+ }
377
+ function imagefilterof(value) {
378
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
379
+ const options = value;
380
+ const normalized = {};
381
+ if (typeof options.selector === "string" && options.selector.trim()) normalized.selector = options.selector.trim();
382
+ if (typeof options.minwidth === "number" && Number.isFinite(options.minwidth)) normalized.minwidth = options.minwidth;
383
+ if (typeof options.minheight === "number" && Number.isFinite(options.minheight)) normalized.minheight = options.minheight;
384
+ if (Array.isArray(options.formats) && options.formats.every((item) => typeof item === "string" && item.trim())) normalized.formats = options.formats;
385
+ return normalized;
386
+ }
387
+ function imagematches(image, filter) {
388
+ if (filter.minwidth !== void 0 && image.width < filter.minwidth) return false;
389
+ if (filter.minheight !== void 0 && image.height < filter.minheight) return false;
390
+ if (filter.formats !== void 0 && filter.formats.length > 0) {
391
+ const mime = image.mime.toLowerCase();
392
+ const matches = filter.formats.some((format) => {
393
+ const wanted = format.toLowerCase().trim();
394
+ return mime === wanted || mime === `image/${wanted}` || mime.endsWith(`/${wanted}`);
395
+ });
396
+ if (!matches) return false;
397
+ }
398
+ return true;
399
+ }
400
+ function dedupeimages(images) {
401
+ const seen = /* @__PURE__ */ new Set();
402
+ const unique = [];
403
+ for (const image of images) {
404
+ if (seen.has(image.url)) continue;
405
+ seen.add(image.url);
406
+ unique.push(image);
407
+ }
408
+ return unique;
409
+ }
410
+ function imagenames(rule, run, step, count, extension) {
411
+ const names = [];
412
+ for (let index = 1; index <= Math.max(0, Math.round(count)); index += 1) names.push(buildname(rule, { run, step, sequence: index, kind: "image" }, extension));
413
+ return names;
414
+ }
415
+ function lapseplanof(value) {
416
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
417
+ const options = value;
418
+ if (typeof options.interval !== "number" || !Number.isFinite(options.interval)) return void 0;
419
+ if (typeof options.duration !== "number" || !Number.isFinite(options.duration)) return void 0;
420
+ const format = options.format === "jpeg" || options.format === "webp" ? options.format : "png";
421
+ return { interval: options.interval, duration: options.duration, format };
422
+ }
423
+ function lapseframes(plan) {
424
+ if (!(plan.interval > 0) || !(plan.duration > 0)) return [];
425
+ const frames = [];
426
+ for (let time = 0; time < plan.duration; time += plan.interval) frames.push(Math.round(time));
427
+ return frames;
428
+ }
429
+ function convertdirectiveof(value) {
430
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
431
+ const options = value;
432
+ if (options.target !== "png" && options.target !== "jpeg" && options.target !== "webp") return void 0;
433
+ const normalized = { target: options.target };
434
+ if (options.source === "png" || options.source === "jpeg" || options.source === "webp") normalized.source = options.source;
435
+ if (typeof options.quality === "number" && Number.isFinite(options.quality)) normalized.quality = options.quality;
436
+ return normalized;
437
+ }
438
+ function thumbdirectiveof(value) {
439
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
440
+ const options = value;
441
+ if (typeof options.size !== "number" || !Number.isFinite(options.size) || options.size <= 0) return void 0;
442
+ if (options.fit !== "cover" && options.fit !== "contain") return void 0;
443
+ if (typeof options.suffix !== "string" || !options.suffix.trim()) return void 0;
444
+ return { size: options.size, fit: options.fit, suffix: options.suffix.trim() };
445
+ }
446
+ function thumbgeometry(source, directive) {
447
+ const size = Math.max(1, Math.round(directive.size));
448
+ if (directive.fit === "contain") {
449
+ const scale2 = Math.min(size / Math.max(1, source.width), size / Math.max(1, source.height));
450
+ const dw = Math.max(1, Math.round(source.width * scale2));
451
+ const dh = Math.max(1, Math.round(source.height * scale2));
452
+ return { sx: 0, sy: 0, sw: source.width, sh: source.height, dx: Math.floor((size - dw) / 2), dy: Math.floor((size - dh) / 2), dw, dh, width: size, height: size };
453
+ }
454
+ const scale = Math.max(size / Math.max(1, source.width), size / Math.max(1, source.height));
455
+ const sw = Math.min(source.width, Math.round(size / scale));
456
+ const sh = Math.min(source.height, Math.round(size / scale));
457
+ return { sx: Math.floor((source.width - sw) / 2), sy: Math.floor((source.height - sh) / 2), sw, sh, dx: 0, dy: 0, dw: size, dh: size, width: size, height: size };
458
+ }
459
+ function mediaentries(raw) {
460
+ return raw.map((entry) => ({
461
+ url: typeof entry.url === "string" ? entry.url : "",
462
+ mime: typeof entry.mime === "string" ? entry.mime : "",
463
+ duration: typeof entry.duration === "number" && Number.isFinite(entry.duration) ? entry.duration : 0,
464
+ width: typeof entry.width === "number" && Number.isFinite(entry.width) ? Math.round(entry.width) : 0,
465
+ height: typeof entry.height === "number" && Number.isFinite(entry.height) ? Math.round(entry.height) : 0,
466
+ codecs: typeof entry.codecs === "string" ? entry.codecs : "",
467
+ tracks: Array.isArray(entry.tracks) ? entry.tracks.filter((item) => typeof item === "string") : []
468
+ }));
469
+ }
470
+ function assetentries(raw) {
471
+ return raw.map((entry) => ({
472
+ kind: entry.kind === "logo" ? "logo" : "favicon",
473
+ url: typeof entry.url === "string" ? entry.url : "",
474
+ bytes: typeof entry.bytes === "number" && Number.isFinite(entry.bytes) ? entry.bytes : 0,
475
+ ...typeof entry.sizes === "string" && entry.sizes.trim() ? { sizes: entry.sizes.trim() } : {}
476
+ }));
477
+ }
478
+ function streamsummaries(raw) {
479
+ return raw.map((entry) => {
480
+ const tracks = Array.isArray(entry.tracks) ? entry.tracks : [];
481
+ return {
482
+ kind: typeof entry.kind === "string" ? entry.kind : "stream",
483
+ tracks: tracks.length,
484
+ label: typeof entry.label === "string" ? entry.label : "",
485
+ live: entry.live === true,
486
+ detail: tracks.map((track) => {
487
+ const item = track;
488
+ return {
489
+ kind: typeof item.kind === "string" ? item.kind : "",
490
+ label: typeof item.label === "string" ? item.label : "",
491
+ ...typeof item.width === "number" && Number.isFinite(item.width) ? { width: Math.round(item.width) } : {},
492
+ ...typeof item.height === "number" && Number.isFinite(item.height) ? { height: Math.round(item.height) } : {},
493
+ ...typeof item.framerate === "number" && Number.isFinite(item.framerate) ? { framerate: item.framerate } : {},
494
+ state: typeof item.state === "string" ? item.state : ""
495
+ };
496
+ })
497
+ };
498
+ });
499
+ }
500
+
1
501
  // memory.ts
2
502
  var sessionmemory = class {
3
503
  constructor(adapter) {
@@ -731,24 +1231,136 @@ var sessionmemory = class {
731
1231
  async getmimefilters() {
732
1232
  return await this.adapter.get("mimefilters") ?? [];
733
1233
  }
1234
+ /** 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. */
1235
+ async addcapture(record2) {
1236
+ const records = await this.getcaptures();
1237
+ const retention = (await this.getsettings())?.captureretention;
1238
+ const combined = [record2, ...records.filter((item) => item.id !== record2.id)];
1239
+ const stored = retention === void 0 ? combined : combined.map((item, index) => index < retention ? item : expirecapturebytes(item));
1240
+ await this.adapter.set("captures", stored);
1241
+ }
1242
+ /** Returns every stored capture record with its metadata, newest first. */
1243
+ async getcaptures() {
1244
+ return await this.adapter.get("captures") ?? [];
1245
+ }
1246
+ /** Returns one capture record with its bytes by its id. */
1247
+ async getcapture(id) {
1248
+ return (await this.getcaptures()).find((item) => item.id === id);
1249
+ }
1250
+ /** Returns the capture records filtered by run, step and kind. */
1251
+ async listcaptures(filter) {
1252
+ const records = await this.getcaptures();
1253
+ 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));
1254
+ }
1255
+ /** Records one before and after shotpair of the run with its action context. */
1256
+ async addpair(pair) {
1257
+ const records = await this.getpairs();
1258
+ await this.adapter.set("capturepairs", [pair, ...records.filter((item) => item.id !== pair.id)]);
1259
+ }
1260
+ /** Returns the shotpairs of one run resolved through their before records, newest first; an absent run returns every pair. */
1261
+ async getpairs(runid) {
1262
+ const records = await this.adapter.get("capturepairs") ?? [];
1263
+ if (runid === void 0) return records;
1264
+ const runs = /* @__PURE__ */ new Map();
1265
+ for (const capture of await this.getcaptures()) runs.set(capture.id, capture.runid);
1266
+ return records.filter((item) => runs.get(item.beforeid) === runid);
1267
+ }
1268
+ /** Stores one media record of the 1.1.41 family with its bytes and step linkage, replacing the previous record of that id; the user configured media retention window expires the oldest bytes while the metadata and the recording index always survive. */
1269
+ async addmedia(record2) {
1270
+ const records = await this.getmediarecords();
1271
+ const retention = (await this.getsettings())?.mediaretention;
1272
+ const combined = [record2, ...records.filter((item) => item.id !== record2.id)];
1273
+ const stored = retention === void 0 ? combined : combined.map((item, index) => index < retention ? item : expiremediabytes(item));
1274
+ await this.adapter.set("media", stored);
1275
+ }
1276
+ /** Returns every stored media record, newest first. */
1277
+ async getmediarecords() {
1278
+ return await this.adapter.get("media") ?? [];
1279
+ }
1280
+ /** Returns the media records filtered by run and kind; an absent filter returns every record. */
1281
+ async listmedia(filter) {
1282
+ const records = await this.getmediarecords();
1283
+ return records.filter((item) => (filter.runid === void 0 || item.runid === filter.runid) && (filter.kind === void 0 || mediakindof(item) === filter.kind));
1284
+ }
1285
+ /** Returns one media record by its id. */
1286
+ async getmediarecord(id) {
1287
+ return (await this.getmediarecords()).find((item) => item.id === id);
1288
+ }
1289
+ /** Returns one recording with its file reference and frame index by its id. */
1290
+ async getrecording(id) {
1291
+ const found = await this.getmediarecord(id);
1292
+ return found !== void 0 && "startedat" in found ? found : void 0;
1293
+ }
1294
+ /** Removes one media record by its id; the audit trail keeps its outcome evidence. */
1295
+ async removemedia(id) {
1296
+ await this.adapter.set("media", (await this.getmediarecords()).filter((item) => item.id !== id));
1297
+ }
1298
+ /** Stores one observed image batch of a downloadimages step, replacing the previous batch of that id. */
1299
+ async addimagebatch(batch) {
1300
+ const records = await this.adapter.get("imagebatches") ?? [];
1301
+ await this.adapter.set("imagebatches", [batch, ...records.filter((item) => item.id !== batch.id)]);
1302
+ }
1303
+ /** Returns every observed image batch with its filter match counts, newest first. */
1304
+ async getimagebatches() {
1305
+ return await this.adapter.get("imagebatches") ?? [];
1306
+ }
1307
+ /** Stores one recording consent decision of an origin, replacing the previous record of that id. */
1308
+ async setrecordingconsent(record2) {
1309
+ const records = (await this.adapter.get("recordingconsents") ?? []).filter((item) => item.id !== record2.id);
1310
+ await this.adapter.set("recordingconsents", [record2, ...records]);
1311
+ }
1312
+ /** Returns every recording consent decision with its prompt and origin, newest first. */
1313
+ async getrecordingconsents() {
1314
+ return await this.adapter.get("recordingconsents") ?? [];
1315
+ }
734
1316
  };
1317
+ function mediakindof(record2) {
1318
+ if ("pages" in record2) return "pdf";
1319
+ if ("startedat" in record2) return "recording";
1320
+ if ("timestamp" in record2) return "frame";
1321
+ if ("context" in record2) return "canvas";
1322
+ if ("tracks" in record2) return "stream";
1323
+ return "asset";
1324
+ }
1325
+ function expiremediabytes(record2) {
1326
+ if ("dataurl" in record2) {
1327
+ const source = record2;
1328
+ const copy = { ...source };
1329
+ delete copy.dataurl;
1330
+ return { ...copy, bytesexpired: true };
1331
+ }
1332
+ if ("startedat" in record2) {
1333
+ const source = record2;
1334
+ const copy = { ...source };
1335
+ delete copy.bytes;
1336
+ return { ...copy, bytesexpired: true };
1337
+ }
1338
+ return record2;
1339
+ }
1340
+ function expirecapturebytes(record2) {
1341
+ const { bytes, ...metadata } = record2;
1342
+ void bytes;
1343
+ return { ...metadata, bytesexpired: true };
1344
+ }
735
1345
  function randomid() {
736
1346
  return crypto.randomUUID();
737
1347
  }
738
1348
 
739
1349
  // policy.ts
740
- 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"]);
1350
+ 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"]);
741
1351
  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"]);
1352
+ 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"]);
743
1353
  var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
744
1354
  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"]);
1355
+ 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"]);
746
1356
  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
1357
  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
1358
  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
1359
  var datasetactions = /* @__PURE__ */ new Set(["scrapetable", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "importcsv", "looprows", "transformvalues", "deduperows", "paginateextract", "mergepages", "stamplerows", "previewgrid", "streamdisk", "resumeextract", "logprovenance"]);
750
1360
  var exportactions = /* @__PURE__ */ new Set(["exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk"]);
751
1361
  var filesactions = /* @__PURE__ */ new Set(["batchdownload", "pausedownload", "resumedownload", "verifydownload", "interceptmime", "exportnetlog", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "namecaptures", "cleanupartifacts"]);
1362
+ var captureactions = /* @__PURE__ */ new Set(["shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet"]);
1363
+ var mediaactions = /* @__PURE__ */ new Set(["capturepdf", "recordscreen", "captureaudio", "captureframe", "downloadimages", "shotcanvas", "probestream", "readmedia", "readassets", "timelapse", "convertimage", "makethumbs"]);
752
1364
  var fieldkinds = ["text", "email", "phone", "date", "number", "select", "check", "radio", "file", "password", "card", "code"];
753
1365
  var layoutmutationactions = /* @__PURE__ */ new Set(["grouptabs", "colorgroup", "collapsegroup", "savelayout", "restorelayout"]);
754
1366
  var groupcolors = ["grey", "blue", "red", "yellow", "green", "pink", "purple", "cyan", "orange"];
@@ -805,6 +1417,83 @@ function isexportkind(kind) {
805
1417
  function isfileskind(kind) {
806
1418
  return filesactions.has(kind);
807
1419
  }
1420
+ function iscapturekind(kind) {
1421
+ return captureactions.has(kind);
1422
+ }
1423
+ function capturegate(session, tabid, origin, now) {
1424
+ if (!session || session.stoppedat) return { allowed: false, reason: "No active browser session exists for the capture." };
1425
+ if (session.expiresat <= now) return { allowed: false, reason: "The browser session has expired and cannot capture." };
1426
+ if (session.pausedat) return { allowed: false, reason: "The browser session is paused and cannot capture." };
1427
+ if (session.tabid !== tabid) return { allowed: false, reason: `The capture needs the active tab grant of session tab ${session.tabid} and refuses tab ${tabid}.` };
1428
+ if (!origingranted(session, origin)) return { allowed: false, reason: `The capture of ${origin} needs the session origin grants first.` };
1429
+ return { allowed: true };
1430
+ }
1431
+ function validatecaptureoptions(value) {
1432
+ if (value === void 0) return { allowed: true };
1433
+ if (!value || typeof value !== "object" || Array.isArray(value)) return { allowed: false, reason: "The reviewed capture options must be an object in options.capture." };
1434
+ const options = value;
1435
+ 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." };
1436
+ 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." };
1437
+ 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." };
1438
+ if (options.annotate !== void 0 && typeof options.annotate !== "boolean") return { allowed: false, reason: "The reviewed capture annotation flag must be a boolean." };
1439
+ 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." };
1440
+ return { allowed: true };
1441
+ }
1442
+ function validateregionrect(value) {
1443
+ 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." };
1444
+ const rect = value;
1445
+ for (const field of ["x", "y", "width", "height"]) {
1446
+ if (typeof rect[field] !== "number" || !Number.isFinite(rect[field])) return { allowed: false, reason: `The reviewed regionrect needs a numeric ${field} in css pixels.` };
1447
+ }
1448
+ if (rect.x < 0 || rect.y < 0) return { allowed: false, reason: "The reviewed regionrect refuses negative coordinates." };
1449
+ if (rect.width <= 0 || rect.height <= 0) return { allowed: false, reason: "The reviewed regionrect needs positive width and height values." };
1450
+ return { allowed: true };
1451
+ }
1452
+ function validatecapturenaming(value) {
1453
+ 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." };
1454
+ const rule = value;
1455
+ const segments = ["run", "step", "sequence", "kind"];
1456
+ for (const key of Object.keys(rule)) {
1457
+ if (!segments.includes(key)) return { allowed: false, reason: `The reviewed capturenaming rule refuses the unknown ${key} segment; only run, step, sequence and kind participate.` };
1458
+ }
1459
+ for (const segment of segments) {
1460
+ if (rule[segment] !== void 0 && typeof rule[segment] !== "boolean") return { allowed: false, reason: `The reviewed capturenaming ${segment} flag must be a boolean.` };
1461
+ }
1462
+ 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." };
1463
+ return { allowed: true };
1464
+ }
1465
+ function validatecapturegrammar(step, options) {
1466
+ const kind = step.kind;
1467
+ const optioncheck = validatecaptureoptions(options.capture);
1468
+ if (!optioncheck.allowed) return optioncheck;
1469
+ 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." };
1470
+ 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." };
1471
+ 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." };
1472
+ if (options.naming !== void 0) {
1473
+ const namingcheck = validatecapturenaming(options.naming);
1474
+ if (!namingcheck.allowed) return namingcheck;
1475
+ }
1476
+ if (kind === "shotregion") {
1477
+ const rectcheck = validateregionrect(options.regionrect);
1478
+ if (!rectcheck.allowed) return rectcheck;
1479
+ if (options.reviewed !== true) return { allowed: false, reason: "Every reviewed regionrect needs the explicit reviewed flag before shotregion runs." };
1480
+ if (options.container !== void 0 && !isnonempty(options.container)) return { allowed: false, reason: "The reviewed scrollable container selector must be a non-empty string." };
1481
+ 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." };
1482
+ }
1483
+ if (kind === "contactsheet") {
1484
+ const elements = options.elements;
1485
+ 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." };
1486
+ const layout = options.sheet;
1487
+ if (layout !== void 0) {
1488
+ if (!layout || typeof layout !== "object" || Array.isArray(layout)) return { allowed: false, reason: "The reviewed sheetlayout must be an object with cellsize, columns and label." };
1489
+ const sheet = layout;
1490
+ 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." };
1491
+ 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." };
1492
+ 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." };
1493
+ }
1494
+ }
1495
+ return { allowed: true };
1496
+ }
808
1497
  function exportgranted(session, origin) {
809
1498
  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
1499
  return { allowed: true };
@@ -1373,6 +2062,140 @@ function validatetabsgrammar(step, options) {
1373
2062
  if (kind === "reopenrun" && !isnonempty(options.run)) return { allowed: false, reason: "A reviewed run id is required in options to reopen its tabs." };
1374
2063
  return { allowed: true };
1375
2064
  }
2065
+ function ismediakind(kind) {
2066
+ return mediaactions.has(kind);
2067
+ }
2068
+ function isrecordingkind(kind) {
2069
+ return kind === "recordscreen" || kind === "captureaudio";
2070
+ }
2071
+ function mediagate(session, tabid, origin, now) {
2072
+ if (!session || session.stoppedat) return { allowed: false, reason: "No active browser session exists for the media capture." };
2073
+ if (session.expiresat <= now) return { allowed: false, reason: "The browser session has expired and cannot capture media." };
2074
+ if (session.pausedat) return { allowed: false, reason: "The browser session is paused and cannot capture media." };
2075
+ if (session.tabid !== tabid) return { allowed: false, reason: `The media capture needs the active tab grant of session tab ${session.tabid} and refuses tab ${tabid}.` };
2076
+ if (!origingranted(session, origin)) return { allowed: false, reason: `The media capture of ${origin} needs the session origin grants first.` };
2077
+ return { allowed: true };
2078
+ }
2079
+ function recordingconsentgranted(step) {
2080
+ let options = {};
2081
+ try {
2082
+ options = parseoptions(step);
2083
+ } catch {
2084
+ options = {};
2085
+ }
2086
+ const consentref = options.consentref;
2087
+ if (typeof consentref !== "string" || !consentref.trim()) return { allowed: false, reason: "A recording of user activity requires a reviewed consent ref in options before it starts." };
2088
+ return { allowed: true };
2089
+ }
2090
+ function lapsebudgetallowed(interval, duration, wait) {
2091
+ if (!(interval > 0)) return { allowed: false, reason: "The reviewed lapse interval must be a positive number of milliseconds." };
2092
+ if (!(duration > 0)) return { allowed: false, reason: "The reviewed lapse duration must be a positive number of milliseconds." };
2093
+ if (wait !== void 0 && !(wait >= 0)) return { allowed: false, reason: "The reviewed wait budget must be zero or a positive number of milliseconds." };
2094
+ if (wait !== void 0 && duration > wait) return { allowed: false, reason: `The lapse duration of ${duration} milliseconds exceeds the reviewed wait budget of ${wait} milliseconds; review a wider budget or a shorter duration.` };
2095
+ return { allowed: true };
2096
+ }
2097
+ function validatemediagrammar(step, options) {
2098
+ const kind = step.kind;
2099
+ if (kind === "capturepdf") {
2100
+ const pdf = options.pdf;
2101
+ if (pdf !== void 0) {
2102
+ if (!pdf || typeof pdf !== "object" || Array.isArray(pdf)) return { allowed: false, reason: "The reviewed pdf options must be an object in options.pdf." };
2103
+ const pdfoptions = pdf;
2104
+ if (pdfoptions.paperwidth !== void 0 && (typeof pdfoptions.paperwidth !== "number" || !Number.isFinite(pdfoptions.paperwidth) || pdfoptions.paperwidth <= 0)) return { allowed: false, reason: "The reviewed pdf paper width must be a positive number of inches with no code cap." };
2105
+ if (pdfoptions.paperheight !== void 0 && (typeof pdfoptions.paperheight !== "number" || !Number.isFinite(pdfoptions.paperheight) || pdfoptions.paperheight <= 0)) return { allowed: false, reason: "The reviewed pdf paper height must be a positive number of inches with no code cap." };
2106
+ if (pdfoptions.margins !== void 0) {
2107
+ const margins = pdfoptions.margins;
2108
+ if (!margins || typeof margins !== "object" || Array.isArray(margins)) return { allowed: false, reason: "The reviewed pdf margins must be an object with top, right, bottom and left inches." };
2109
+ for (const side of ["top", "right", "bottom", "left"]) {
2110
+ const value = margins[side];
2111
+ if (value === void 0) continue;
2112
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return { allowed: false, reason: `The reviewed pdf ${side} margin must be zero or a positive number of inches; negative margins are refused.` };
2113
+ }
2114
+ }
2115
+ if (pdfoptions.scale !== void 0 && (typeof pdfoptions.scale !== "number" || !Number.isFinite(pdfoptions.scale) || pdfoptions.scale <= 0)) return { allowed: false, reason: "The reviewed pdf scale must be a positive number with no code cap." };
2116
+ if (pdfoptions.landscape !== void 0 && typeof pdfoptions.landscape !== "boolean") return { allowed: false, reason: "The reviewed pdf landscape flag must be a boolean." };
2117
+ if (pdfoptions.paginate !== void 0 && typeof pdfoptions.paginate !== "boolean") return { allowed: false, reason: "The reviewed pdf paginate flag must be a boolean." };
2118
+ }
2119
+ if (options.breakpoints !== void 0 && (!Array.isArray(options.breakpoints) || options.breakpoints.length === 0 || !options.breakpoints.every((item) => isnonempty(item)))) return { allowed: false, reason: "The reviewed pdf break points must be a non-empty list of selectors when present." };
2120
+ if (options.exporttarget !== void 0 && options.exporttarget !== "memory" && options.exporttarget !== "download") return { allowed: false, reason: "The reviewed pdf export target must be memory or download; pdf documents do not route to the clipboard." };
2121
+ if (options.name !== void 0 && !isnonempty(options.name)) return { allowed: false, reason: "The reviewed pdf artifact name must be a non-empty string." };
2122
+ }
2123
+ if (kind === "recordscreen" || kind === "captureaudio") {
2124
+ const recording = options.recording;
2125
+ if (recording !== void 0) {
2126
+ if (!recording || typeof recording !== "object" || Array.isArray(recording)) return { allowed: false, reason: "The reviewed recording options must be an object in options.recording." };
2127
+ const recordoptions = recording;
2128
+ if (recordoptions.scope !== void 0 && recordoptions.scope !== "tab" && recordoptions.scope !== "run") return { allowed: false, reason: "The reviewed recording scope must be tab or run." };
2129
+ if (recordoptions.fps !== void 0 && (typeof recordoptions.fps !== "number" || !Number.isFinite(recordoptions.fps) || recordoptions.fps <= 0)) return { allowed: false, reason: "The reviewed recording fps must be a positive number with no code ceiling." };
2130
+ if (recordoptions.bitrate !== void 0 && (typeof recordoptions.bitrate !== "number" || !Number.isFinite(recordoptions.bitrate) || recordoptions.bitrate <= 0)) return { allowed: false, reason: "The reviewed recording bitrate must be a positive number with no code ceiling." };
2131
+ if (recordoptions.audio !== void 0 && typeof recordoptions.audio !== "boolean") return { allowed: false, reason: "The reviewed recording audio flag must be a boolean." };
2132
+ }
2133
+ if (options.duration !== void 0 && (typeof options.duration !== "number" || !Number.isFinite(options.duration) || options.duration <= 0)) return { allowed: false, reason: "The reviewed recording duration must be a positive number of milliseconds with no code ceiling." };
2134
+ const consent = recordingconsentgranted(step);
2135
+ if (!consent.allowed) return consent;
2136
+ }
2137
+ if (kind === "captureframe") {
2138
+ if (options.timestamp !== void 0 && (typeof options.timestamp !== "number" || !Number.isFinite(options.timestamp) || options.timestamp < 0)) return { allowed: false, reason: "The reviewed frame timestamp must be zero or a positive number of seconds." };
2139
+ if (options.poster !== void 0 && typeof options.poster !== "boolean") return { allowed: false, reason: "The reviewed poster flag must be a boolean." };
2140
+ const capturecheck = validatecaptureoptions(options.capture);
2141
+ if (!capturecheck.allowed) return capturecheck;
2142
+ }
2143
+ if (kind === "downloadimages") {
2144
+ const filter = options.imagefilter;
2145
+ if (!filter || typeof filter !== "object" || Array.isArray(filter)) return { allowed: false, reason: "A reviewed imagefilter is required in options before any image downloads." };
2146
+ const imagefilter = filter;
2147
+ if (imagefilter.selector !== void 0 && !isnonempty(imagefilter.selector)) return { allowed: false, reason: "The reviewed imagefilter selector must be a non-empty selector from the reviewed selector grammar." };
2148
+ if (imagefilter.minwidth !== void 0 && (typeof imagefilter.minwidth !== "number" || !Number.isFinite(imagefilter.minwidth) || imagefilter.minwidth < 0)) return { allowed: false, reason: "The reviewed imagefilter minimum width must be zero or a positive number of pixels." };
2149
+ if (imagefilter.minheight !== void 0 && (typeof imagefilter.minheight !== "number" || !Number.isFinite(imagefilter.minheight) || imagefilter.minheight < 0)) return { allowed: false, reason: "The reviewed imagefilter minimum height must be zero or a positive number of pixels." };
2150
+ if (imagefilter.formats !== void 0 && (!Array.isArray(imagefilter.formats) || imagefilter.formats.length === 0 || !imagefilter.formats.every((item) => isnonempty(item)))) return { allowed: false, reason: "The reviewed imagefilter format list must be a non-empty list of mime or extension patterns when present." };
2151
+ if (options.naming !== void 0) {
2152
+ const namingcheck = validatecapturenaming(options.naming);
2153
+ if (!namingcheck.allowed) return namingcheck;
2154
+ }
2155
+ }
2156
+ if (kind === "shotcanvas") {
2157
+ const capturecheck = validatecaptureoptions(options.capture);
2158
+ if (!capturecheck.allowed) return capturecheck;
2159
+ }
2160
+ if (kind === "probestream" && options.selector !== void 0 && !isnonempty(options.selector)) return { allowed: false, reason: "The reviewed stream probe scope selector must be a non-empty string." };
2161
+ if (kind === "timelapse") {
2162
+ const lapse = options.lapse;
2163
+ if (!lapse || typeof lapse !== "object" || Array.isArray(lapse)) return { allowed: false, reason: "A reviewed lapse plan with interval, duration and format is required in options." };
2164
+ const plan = lapse;
2165
+ if (typeof plan.interval !== "number" || !Number.isFinite(plan.interval) || plan.interval <= 0) return { allowed: false, reason: "The reviewed lapse interval must be a positive number of milliseconds with no code ceiling." };
2166
+ if (typeof plan.duration !== "number" || !Number.isFinite(plan.duration) || plan.duration <= 0) return { allowed: false, reason: "The reviewed lapse duration must be a positive number of milliseconds with no code ceiling." };
2167
+ if (plan.format !== void 0 && plan.format !== "png" && plan.format !== "jpeg" && plan.format !== "webp") return { allowed: false, reason: "The reviewed lapse format must be png, jpeg or webp." };
2168
+ const budget = lapsebudgetallowed(plan.interval, plan.duration, typeof options.wait === "number" ? options.wait : void 0);
2169
+ if (!budget.allowed) return budget;
2170
+ const capturecheck = validatecaptureoptions(options.capture);
2171
+ if (!capturecheck.allowed) return capturecheck;
2172
+ }
2173
+ if (kind === "convertimage" || kind === "makethumbs") {
2174
+ const single = options.capture;
2175
+ const list = options.captures;
2176
+ const hasone = isnonempty(single);
2177
+ const haslist = Array.isArray(list) && list.length > 0 && list.every((item) => isnonempty(item));
2178
+ if (!hasone && !haslist) return { allowed: false, reason: "A reviewed capture id or a reviewed non-empty capture id list is required in options." };
2179
+ if (hasone && haslist) return { allowed: false, reason: "The reviewed step needs one capture id or a capture id list, not both." };
2180
+ }
2181
+ if (kind === "convertimage") {
2182
+ const convert = options.convert;
2183
+ if (!convert || typeof convert !== "object" || Array.isArray(convert)) return { allowed: false, reason: "A reviewed convert directive with a target format is required in options." };
2184
+ const directive = convert;
2185
+ if (directive.target !== "png" && directive.target !== "jpeg" && directive.target !== "webp") return { allowed: false, reason: "The reviewed conversion target must be png, jpeg or webp." };
2186
+ if (directive.source !== void 0 && directive.source !== "png" && directive.source !== "jpeg" && directive.source !== "webp") return { allowed: false, reason: "The reviewed conversion source must be png, jpeg or webp." };
2187
+ if (directive.quality !== void 0 && (typeof directive.quality !== "number" || !Number.isFinite(directive.quality) || directive.quality < 0 || directive.quality > 100)) return { allowed: false, reason: "The reviewed conversion quality must stay between zero and one hundred with no code cap inside that range." };
2188
+ }
2189
+ if (kind === "makethumbs") {
2190
+ const thumb = options.thumb;
2191
+ if (!thumb || typeof thumb !== "object" || Array.isArray(thumb)) return { allowed: false, reason: "A reviewed thumb directive with size, fit and suffix is required in options." };
2192
+ const directive = thumb;
2193
+ if (typeof directive.size !== "number" || !Number.isFinite(directive.size) || directive.size <= 0) return { allowed: false, reason: "The reviewed thumbnail size must be a positive number of pixels with no fixed set." };
2194
+ if (directive.fit !== "cover" && directive.fit !== "contain") return { allowed: false, reason: "The reviewed thumbnail fit must be cover or contain." };
2195
+ if (!isnonempty(directive.suffix)) return { allowed: false, reason: "The reviewed thumbnail naming suffix must be a non-empty string." };
2196
+ }
2197
+ return { allowed: true };
2198
+ }
1376
2199
  function validatestep(step, origin) {
1377
2200
  if (!allowedactions.has(step.kind)) return { allowed: false, reason: "Unsupported action kind." };
1378
2201
  if (!step.summary.trim()) return { allowed: false, reason: "A human-readable action summary is required." };
@@ -1590,6 +2413,14 @@ function validatestep(step, origin) {
1590
2413
  const filescheck = validatefilesgrammar(step, options);
1591
2414
  if (!filescheck.allowed) return filescheck;
1592
2415
  }
2416
+ if (iscapturekind(step.kind)) {
2417
+ const capturecheck = validatecapturegrammar(step, options);
2418
+ if (!capturecheck.allowed) return capturecheck;
2419
+ }
2420
+ if (ismediakind(step.kind)) {
2421
+ const mediacheck = validatemediagrammar(step, options);
2422
+ if (!mediacheck.allowed) return mediacheck;
2423
+ }
1593
2424
  if (step.kind === "tabcreate") {
1594
2425
  if (options.background !== void 0 && typeof options.background !== "boolean") return { allowed: false, reason: "The reviewed background flag must be a boolean." };
1595
2426
  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 +2480,26 @@ function canexecute(input) {
1649
2480
  if (!clipgate.allowed) return clipgate;
1650
2481
  }
1651
2482
  if (input.step.kind === "interceptmime" && !origingranted(input.session, input.origin)) return { allowed: false, reason: "The download interception is outside the session origin grants." };
2483
+ if (iscapturekind(input.step.kind)) {
2484
+ const capturegatecheck = capturegate(input.session, input.tabid, input.origin, now);
2485
+ if (!capturegatecheck.allowed) return capturegatecheck;
2486
+ let captureoptions = {};
2487
+ try {
2488
+ captureoptions = parseoptions(input.step);
2489
+ } catch {
2490
+ captureoptions = {};
2491
+ }
2492
+ const target = captureoptions.capture?.exporttarget;
2493
+ if (target !== void 0 && target !== "memory" && target !== "download" && target !== "clipboard") return { allowed: false, reason: "The capture export target must be memory, download or clipboard." };
2494
+ }
2495
+ if (ismediakind(input.step.kind)) {
2496
+ const mediagatecheck = mediagate(input.session, input.tabid, input.origin, now);
2497
+ if (!mediagatecheck.allowed) return mediagatecheck;
2498
+ }
2499
+ if (isrecordingkind(input.step.kind)) {
2500
+ const recordinggate = recordingconsentgranted(input.step);
2501
+ if (!recordinggate.allowed) return recordinggate;
2502
+ }
1652
2503
  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
2504
  let options = {};
1654
2505
  try {
@@ -1670,7 +2521,7 @@ function canexecute(input) {
1670
2521
  }
1671
2522
 
1672
2523
  // version.ts
1673
- var packageversion = "1.1.39";
2524
+ var packageversion = "1.1.41";
1674
2525
 
1675
2526
  // types.ts
1676
2527
  var protocolversion = packageversion;
@@ -1734,7 +2585,7 @@ function requestbody(input) {
1734
2585
  return JSON.stringify({ version: protocolversion, objective: input.objective, session: input.session, observation: input.observation, capabilities: input.capabilities });
1735
2586
  }
1736
2587
  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 } : {} });
2588
+ 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 } : {} });
1738
2589
  }
1739
2590
  function mapresponse(input) {
1740
2591
  return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, map: input.map });
@@ -1811,44 +2662,95 @@ function netlogreport(input) {
1811
2662
  function quarantinereport(input) {
1812
2663
  return { version: protocolversion, entries: input.entries };
1813
2664
  }
2665
+ function capturereport(input) {
2666
+ return { version: protocolversion, records: input.records, pairs: input.pairs };
2667
+ }
2668
+ function mediareport(input) {
2669
+ return { version: protocolversion, records: input.records, images: input.images };
2670
+ }
1814
2671
  export {
2672
+ annotationplanof,
2673
+ assetentries,
2674
+ blendrows,
2675
+ buildname,
2676
+ buildpdf,
2677
+ buildsheet,
2678
+ buildstitchplan,
1815
2679
  canexecute,
2680
+ captureelement,
2681
+ captureformats,
2682
+ capturekinds,
2683
+ captureoptionsof,
2684
+ captureregion,
2685
+ capturereport,
2686
+ capturestates,
2687
+ capturestitched,
2688
+ capturetargets,
2689
+ capturevisible,
2690
+ convertdirectiveof,
2691
+ croprect,
2692
+ crossesviewport,
1816
2693
  datasetresponse,
2694
+ dedupeimages,
1817
2695
  actionrisk as deriveactionrisk,
1818
2696
  diffresponse,
1819
2697
  downloadreport,
1820
2698
  errorreportresponse,
1821
2699
  eventresponse,
1822
2700
  extractionreport,
2701
+ finishrecording,
2702
+ fixedheadermatch,
1823
2703
  formreportresponse,
2704
+ frameinterval,
1824
2705
  generatedvalueallowed,
1825
2706
  heldkeysreport,
1826
2707
  hostpattern,
2708
+ imagefilterof,
2709
+ imagematches,
2710
+ imagenames,
1827
2711
  isformkind,
1828
2712
  iswatchkind,
2713
+ lapseframes,
2714
+ lapseplanof,
1829
2715
  layoutreport,
1830
2716
  mapresponse,
2717
+ mediaentries,
2718
+ mediakinds,
2719
+ mediareport,
1831
2720
  navstateresponse,
1832
2721
  netlogreport,
2722
+ newrecording,
1833
2723
  normalizeendpoint,
1834
2724
  observationmodeof,
1835
2725
  observationresponse,
1836
2726
  outcomeresponse,
2727
+ pairstates,
1837
2728
  parseproposal,
1838
2729
  passwordconsentgranted,
2730
+ pdfoptionsof,
2731
+ pdfpagesize,
2732
+ pdfsegments,
2733
+ pdftextlayout,
1839
2734
  profilegrantgranted,
1840
2735
  protocolversion,
1841
2736
  provenancereport,
1842
2737
  quarantinereport,
1843
2738
  randomid,
2739
+ recordingoptionsof,
2740
+ regionsteps,
1844
2741
  requestbody,
1845
2742
  resolutionverdict,
1846
2743
  safetyresponse,
2744
+ scaledrect,
2745
+ seamweights,
1847
2746
  selectorresponse,
1848
2747
  sessionmemory,
1849
2748
  signalsreport,
2749
+ streamsummaries,
1850
2750
  submitreviewgranted,
1851
2751
  tabreportresponse,
2752
+ thumbdirectiveof,
2753
+ thumbgeometry,
1852
2754
  trailreport,
1853
2755
  transformgrammar,
1854
2756
  validatefieldmatch,