@extenshi/cli 0.20.0 → 0.22.0

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.
Files changed (122) hide show
  1. package/README.md +4 -0
  2. package/dist/amo-source-detect.d.ts +18 -0
  3. package/dist/amo-source-detect.d.ts.map +1 -0
  4. package/dist/amo-source-detect.js +41 -0
  5. package/dist/amo-source-detect.js.map +1 -0
  6. package/dist/amo-source.d.ts +41 -0
  7. package/dist/amo-source.d.ts.map +1 -0
  8. package/dist/amo-source.js +240 -0
  9. package/dist/amo-source.js.map +1 -0
  10. package/dist/amowebstore-md.d.ts +38 -0
  11. package/dist/amowebstore-md.d.ts.map +1 -0
  12. package/dist/amowebstore-md.js +118 -0
  13. package/dist/amowebstore-md.js.map +1 -0
  14. package/dist/auto-evidence.d.ts +100 -0
  15. package/dist/auto-evidence.d.ts.map +1 -0
  16. package/dist/auto-evidence.js +197 -0
  17. package/dist/auto-evidence.js.map +1 -0
  18. package/dist/cli.js +320 -8
  19. package/dist/cli.js.map +1 -1
  20. package/dist/edgewebstore-md.d.ts +26 -0
  21. package/dist/edgewebstore-md.d.ts.map +1 -0
  22. package/dist/edgewebstore-md.js +95 -0
  23. package/dist/edgewebstore-md.js.map +1 -0
  24. package/dist/evidence-ingest.d.ts +60 -0
  25. package/dist/evidence-ingest.d.ts.map +1 -0
  26. package/dist/evidence-ingest.js +141 -0
  27. package/dist/evidence-ingest.js.map +1 -0
  28. package/dist/expected-error.d.ts +9 -0
  29. package/dist/expected-error.d.ts.map +1 -1
  30. package/dist/expected-error.js +16 -1
  31. package/dist/expected-error.js.map +1 -1
  32. package/dist/firefox-rdp.d.ts +55 -0
  33. package/dist/firefox-rdp.d.ts.map +1 -0
  34. package/dist/firefox-rdp.js +203 -0
  35. package/dist/firefox-rdp.js.map +1 -0
  36. package/dist/gecko-id.d.ts +55 -0
  37. package/dist/gecko-id.d.ts.map +1 -0
  38. package/dist/gecko-id.js +132 -0
  39. package/dist/gecko-id.js.map +1 -0
  40. package/dist/generate-listing.d.ts +19 -8
  41. package/dist/generate-listing.d.ts.map +1 -1
  42. package/dist/generate-listing.js +66 -18
  43. package/dist/generate-listing.js.map +1 -1
  44. package/dist/icon.d.ts +18 -0
  45. package/dist/icon.d.ts.map +1 -1
  46. package/dist/icon.js +29 -20
  47. package/dist/icon.js.map +1 -1
  48. package/dist/json-ld.d.ts +89 -0
  49. package/dist/json-ld.d.ts.map +1 -0
  50. package/dist/json-ld.js +118 -0
  51. package/dist/json-ld.js.map +1 -0
  52. package/dist/landing-page.d.ts +123 -0
  53. package/dist/landing-page.d.ts.map +1 -0
  54. package/dist/landing-page.js +405 -0
  55. package/dist/landing-page.js.map +1 -0
  56. package/dist/media.d.ts +42 -0
  57. package/dist/media.d.ts.map +1 -0
  58. package/dist/media.js +96 -0
  59. package/dist/media.js.map +1 -0
  60. package/dist/package.d.ts +163 -0
  61. package/dist/package.d.ts.map +1 -0
  62. package/dist/package.js +500 -0
  63. package/dist/package.js.map +1 -0
  64. package/dist/page.d.ts +141 -0
  65. package/dist/page.d.ts.map +1 -0
  66. package/dist/page.js +227 -0
  67. package/dist/page.js.map +1 -0
  68. package/dist/pay-contract.d.ts +20 -13
  69. package/dist/pay-contract.d.ts.map +1 -1
  70. package/dist/pay-contract.js +20 -11
  71. package/dist/pay-contract.js.map +1 -1
  72. package/dist/pay-test-cycle.d.ts +40 -0
  73. package/dist/pay-test-cycle.d.ts.map +1 -0
  74. package/dist/pay-test-cycle.js +207 -0
  75. package/dist/pay-test-cycle.js.map +1 -0
  76. package/dist/pay.d.ts +1 -1
  77. package/dist/pay.d.ts.map +1 -1
  78. package/dist/pay.js +1 -0
  79. package/dist/pay.js.map +1 -1
  80. package/dist/project.d.ts +39 -1
  81. package/dist/project.d.ts.map +1 -1
  82. package/dist/project.js +231 -20
  83. package/dist/project.js.map +1 -1
  84. package/dist/publish.d.ts +33 -0
  85. package/dist/publish.d.ts.map +1 -1
  86. package/dist/publish.js +113 -2
  87. package/dist/publish.js.map +1 -1
  88. package/dist/review-checks.d.ts +13 -0
  89. package/dist/review-checks.d.ts.map +1 -1
  90. package/dist/review-checks.js.map +1 -1
  91. package/dist/review-risk.d.ts +10 -1
  92. package/dist/review-risk.d.ts.map +1 -1
  93. package/dist/review-risk.js +1 -0
  94. package/dist/review-risk.js.map +1 -1
  95. package/dist/scan.d.ts +3 -2
  96. package/dist/scan.d.ts.map +1 -1
  97. package/dist/scan.js +4 -2
  98. package/dist/scan.js.map +1 -1
  99. package/dist/screenshots-scenes.d.ts +1383 -0
  100. package/dist/screenshots-scenes.d.ts.map +1 -0
  101. package/dist/screenshots-scenes.js +276 -0
  102. package/dist/screenshots-scenes.js.map +1 -0
  103. package/dist/screenshots.d.ts +145 -0
  104. package/dist/screenshots.d.ts.map +1 -0
  105. package/dist/screenshots.js +557 -0
  106. package/dist/screenshots.js.map +1 -0
  107. package/dist/smoke.d.ts +81 -0
  108. package/dist/smoke.d.ts.map +1 -0
  109. package/dist/smoke.js +491 -0
  110. package/dist/smoke.js.map +1 -0
  111. package/dist/store-assets.d.ts +139 -0
  112. package/dist/store-assets.d.ts.map +1 -0
  113. package/dist/store-assets.js +582 -0
  114. package/dist/store-assets.js.map +1 -0
  115. package/dist/telemetry.d.ts.map +1 -1
  116. package/dist/telemetry.js +3 -0
  117. package/dist/telemetry.js.map +1 -1
  118. package/dist/zip.d.ts +57 -0
  119. package/dist/zip.d.ts.map +1 -0
  120. package/dist/zip.js +134 -0
  121. package/dist/zip.js.map +1 -0
  122. package/package.json +4 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshots-scenes.d.ts","sourceRoot":"","sources":["../src/screenshots-scenes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Declarative scenes for `extenshi screenshots` — the file format, and the
3
+ * pure helpers (locale mapping, extension ids, layout, naming) the runner and
4
+ * its tests share. Nothing here touches a browser.
5
+ *
6
+ * scenes.json (version 1):
7
+ *
8
+ * {
9
+ * "version": 1,
10
+ * "viewport": { "width": 1280, "height": 800 }, // default capture size (CSS px)
11
+ * "deviceScaleFactor": 1, // 2 = sharper crops, downscaled on compose
12
+ * "colorScheme": "light",
13
+ * "time": "2026-01-15T10:00:00Z", // optional fixed Date.now()
14
+ * "fixtures": "fixtures", // dir served at http://127.0.0.1:<port>/ (default: scenes dir)
15
+ * "frame": { "background": "#eef2ff", "margin": 48, "shadow": true, "radius": 12 },
16
+ * "setup": [ { "storage": { "area": "local", "set": { "onboarded": true } } } ],
17
+ * "scenes": [
18
+ * { "name": "popup", "open": "popup", "steps": [ { "click": "#enable" } ] },
19
+ * { "name": "on-a-page", "open": "fixture:article.{locale}.html",
20
+ * "steps": [ { "mouse": { "x": 640, "y": 330 } }, { "wait": 400 } ] },
21
+ * { "name": "options", "open": "options", "crop": { "selector": "main", "padding": 24 } }
22
+ * ]
23
+ * }
24
+ *
25
+ * `open`: popup | options | page:<extension path> | fixture:<file> | url:<https://…>.
26
+ * `{locale}` / `{lang}` in `open` expand to the _locales code (pt_BR) / BCP 47 tag (pt-BR).
27
+ * Steps: click, hover, type (+text), press, mouse {x,y}, scroll {x?,y}, wait <ms>,
28
+ * waitFor <selector>, storage {area, set?, remove?, clear?} (runs in the
29
+ * extension's own context), eval <js expression> (runs in the scene page).
30
+ * `crop`: viewport (default) | content (default for popup) | fullPage | {selector, padding}.
31
+ * `fit`: contain (default; the capture is centered on the frame background,
32
+ * never upscaled beyond its captured pixels) | cover (fills the store size).
33
+ */
34
+ import { createHash } from 'node:crypto';
35
+ import { z } from 'zod';
36
+ import { InvalidInputError } from './expected-error.js';
37
+ const selector = z.string().min(1).max(500);
38
+ const color = z
39
+ .string()
40
+ .max(60)
41
+ .regex(/^(#[0-9a-f]{3,8}|[a-z]{3,20}|rgba?\([\d\s.,%]+\))$/i, 'must be a CSS color (#hex, rgb() or a name)');
42
+ export const stepSchema = z.union([
43
+ z.object({ click: selector }).strict(),
44
+ z.object({ hover: selector }).strict(),
45
+ z.object({ type: selector, text: z.string().max(2000) }).strict(),
46
+ z.object({ press: z.string().min(1).max(40) }).strict(),
47
+ z
48
+ .object({
49
+ mouse: z.object({ x: z.number().min(0).max(10000), y: z.number().min(0).max(10000) }).strict(),
50
+ })
51
+ .strict(),
52
+ z.object({ scroll: z.object({ x: z.number().default(0), y: z.number() }).strict() }).strict(),
53
+ z.object({ wait: z.number().int().min(0).max(30_000) }).strict(),
54
+ z
55
+ .object({
56
+ waitFor: selector,
57
+ state: z.enum(['visible', 'hidden', 'attached', 'detached']).default('visible'),
58
+ })
59
+ .strict(),
60
+ z
61
+ .object({
62
+ storage: z
63
+ .object({
64
+ area: z.enum(['local', 'sync', 'session']).default('local'),
65
+ set: z.record(z.unknown()).optional(),
66
+ remove: z.array(z.string().max(200)).max(100).optional(),
67
+ clear: z.boolean().optional(),
68
+ })
69
+ .strict(),
70
+ })
71
+ .strict(),
72
+ z.object({ eval: z.string().min(1).max(20_000) }).strict(),
73
+ ]);
74
+ const viewportSchema = z
75
+ .object({ width: z.number().int().min(200).max(3840), height: z.number().int().min(150).max(2400) })
76
+ .strict();
77
+ const frameSchema = z
78
+ .object({
79
+ background: color.optional(),
80
+ /** Second colour: a top-to-bottom gradient from `background`. */
81
+ backgroundTo: color.optional(),
82
+ margin: z.number().int().min(0).max(400).optional(),
83
+ shadow: z.boolean().optional(),
84
+ radius: z.number().int().min(0).max(64).optional(),
85
+ })
86
+ .strict();
87
+ export const OPEN_PATTERN = /^(popup|options|page:.+|fixture:.+|url:https:\/\/.+)$/;
88
+ const sceneSchema = z
89
+ .object({
90
+ name: z.string().regex(/^[a-z0-9][a-z0-9-]{0,40}$/, 'scene names are lowercase letters, digits and "-"'),
91
+ open: z
92
+ .string()
93
+ .max(1000)
94
+ .regex(OPEN_PATTERN, 'open must be popup | options | page:<path> | fixture:<file> | url:https://…'),
95
+ viewport: viewportSchema.optional(),
96
+ colorScheme: z.enum(['light', 'dark']).optional(),
97
+ /** JS run before the page's own scripts (Playwright addInitScript). */
98
+ init: z.string().max(20_000).optional(),
99
+ steps: z.array(stepSchema).max(60).default([]),
100
+ crop: z
101
+ .union([
102
+ z.enum(['viewport', 'content', 'fullPage']),
103
+ z.object({ selector, padding: z.number().int().min(0).max(400).default(0) }).strict(),
104
+ ])
105
+ .optional(),
106
+ fit: z.enum(['contain', 'cover']).default('contain'),
107
+ frame: frameSchema.optional(),
108
+ stores: z
109
+ .array(z.enum(['chrome', 'edge', 'firefox']))
110
+ .min(1)
111
+ .optional(),
112
+ })
113
+ .strict();
114
+ export const scenesFileSchema = z
115
+ .object({
116
+ $schema: z.string().optional(),
117
+ version: z.literal(1).default(1),
118
+ viewport: viewportSchema.default({ width: 1280, height: 800 }),
119
+ deviceScaleFactor: z.number().min(1).max(3).default(1),
120
+ colorScheme: z.enum(['light', 'dark']).default('light'),
121
+ time: z.string().datetime({ offset: true }).optional(),
122
+ fixtures: z.string().max(500).optional(),
123
+ animations: z.enum(['disabled', 'allow']).default('disabled'),
124
+ frame: frameSchema.default({}),
125
+ setup: z.array(stepSchema).max(60).default([]),
126
+ scenes: z.array(sceneSchema).min(1).max(12),
127
+ })
128
+ .strict()
129
+ .superRefine((file, ctx) => {
130
+ const seen = new Set();
131
+ for (const [i, scene] of file.scenes.entries()) {
132
+ if (seen.has(scene.name))
133
+ ctx.addIssue({
134
+ code: 'custom',
135
+ path: ['scenes', i, 'name'],
136
+ message: `duplicate scene name "${scene.name}"`,
137
+ });
138
+ seen.add(scene.name);
139
+ }
140
+ });
141
+ export function parseScenes(raw) {
142
+ let json;
143
+ try {
144
+ json = JSON.parse(raw);
145
+ }
146
+ catch (error) {
147
+ throw new InvalidInputError(`Scenes file is not valid JSON: ${error.message}`);
148
+ }
149
+ const parsed = scenesFileSchema.safeParse(json);
150
+ if (!parsed.success) {
151
+ const issues = parsed.error.issues.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`).join('; ');
152
+ throw new InvalidInputError(`Invalid scenes file — ${issues}`);
153
+ }
154
+ return parsed.data;
155
+ }
156
+ // ── Locales ─────────────────────────────────────────────────────────────────
157
+ const LOCALE_CODE = /^[a-z]{2,3}(_[A-Za-z0-9]{2,4})?$/;
158
+ /** `_locales` code → the BCP 47 tag Chromium's --lang expects (pt_BR → pt-BR, es_419 → es-419). */
159
+ export function chromeLang(locale) {
160
+ return locale.replace('_', '-');
161
+ }
162
+ /**
163
+ * Which `_locales/<dir>` Chrome renders for a UI locale: the exact locale, then
164
+ * its language, then default_locale. (chrome.i18n's documented lookup order.)
165
+ */
166
+ export function resolveCatalogLocale(uiLocale, available, defaultLocale) {
167
+ const exact = uiLocale.replace('-', '_');
168
+ const lower = available.map((l) => l.toLowerCase());
169
+ const hit = lower.indexOf(exact.toLowerCase());
170
+ if (hit >= 0)
171
+ return available[hit];
172
+ const language = exact.split('_')[0].toLowerCase();
173
+ const base = lower.indexOf(language);
174
+ if (base >= 0)
175
+ return available[base];
176
+ return defaultLocale ?? null;
177
+ }
178
+ export function parseLocales(value, available, defaultLocale) {
179
+ if (!value) {
180
+ if (available.length)
181
+ return [...available].sort((a, b) => a === defaultLocale ? -1 : b === defaultLocale ? 1 : a.localeCompare(b));
182
+ return [defaultLocale ?? 'en'];
183
+ }
184
+ const out = [
185
+ ...new Set(value
186
+ .split(',')
187
+ .map((l) => l.trim())
188
+ .filter(Boolean)),
189
+ ];
190
+ for (const locale of out) {
191
+ if (!LOCALE_CODE.test(locale))
192
+ throw new InvalidInputError(`"${locale}" is not a locale code (use en, de, pt_BR…)`);
193
+ if (available.length && !available.includes(locale))
194
+ throw new InvalidInputError(`The extension has no _locales/${locale} (it has ${available.join(', ')}). Chrome would fall back to ` +
195
+ `${defaultLocale ?? 'the default locale'}, so a "${locale}" screenshot would be in the wrong language.`);
196
+ }
197
+ return out;
198
+ }
199
+ /**
200
+ * One message that proves which catalog is active: present in `messages`,
201
+ * different from the default locale's, and free of `$` placeholders (which
202
+ * chrome.i18n would substitute).
203
+ */
204
+ export function pickSampleMessage(messages, defaults) {
205
+ if (!messages)
206
+ return null;
207
+ for (const [key, value] of Object.entries(messages)) {
208
+ const message = value?.message;
209
+ if (typeof message !== 'string' || !message.trim() || message.includes('$') || key.startsWith('@@'))
210
+ continue;
211
+ if (defaults && defaults[key]?.message === message)
212
+ continue;
213
+ return { key, message };
214
+ }
215
+ return null;
216
+ }
217
+ // ── Extension identity ──────────────────────────────────────────────────────
218
+ function idFromHash(hex) {
219
+ return [...hex.slice(0, 32)].map((c) => String.fromCharCode(97 + Number.parseInt(c, 16))).join('');
220
+ }
221
+ /** Chrome's id for an unpacked extension: sha256 of its absolute (real) path, a–p encoded. */
222
+ export function extensionIdForPath(realPath) {
223
+ return idFromHash(createHash('sha256').update(realPath).digest('hex'));
224
+ }
225
+ /** Chrome's id when the manifest carries a `key` (base64 DER public key). */
226
+ export function extensionIdForKey(key) {
227
+ return idFromHash(createHash('sha256')
228
+ .update(Buffer.from(key.replace(/\s+/g, ''), 'base64'))
229
+ .digest('hex'));
230
+ }
231
+ /**
232
+ * Where a capture of `content` CSS px (captured at `scale` device pixels per
233
+ * CSS px) lands on a `canvas`: `contain` centers it inside the margin and never
234
+ * magnifies past its captured pixels; `cover` fills the canvas.
235
+ */
236
+ export function placeCapture(content, canvas, opts) {
237
+ if (opts.fit === 'cover') {
238
+ const s = Math.max(canvas.width / content.width, canvas.height / content.height);
239
+ const width = content.width * s;
240
+ const height = content.height * s;
241
+ return { x: (canvas.width - width) / 2, y: (canvas.height - height) / 2, width, height };
242
+ }
243
+ const exact = content.width === canvas.width && content.height === canvas.height;
244
+ const margin = exact ? 0 : opts.margin;
245
+ const fit = Math.min((canvas.width - 2 * margin) / content.width, (canvas.height - 2 * margin) / content.height);
246
+ // Pixels available per CSS px on the canvas (1 per canvas px) vs captured.
247
+ const s = Math.min(fit, opts.scale);
248
+ const width = content.width * s;
249
+ const height = content.height * s;
250
+ return { x: (canvas.width - width) / 2, y: (canvas.height - height) / 2, width, height };
251
+ }
252
+ export function screenshotFileName(index, scene, size) {
253
+ return `${String(index + 1).padStart(2, '0')}-${scene}-${size.width}x${size.height}.png`;
254
+ }
255
+ /** Width/height from a PNG's IHDR. */
256
+ export function pngDimensions(png) {
257
+ const b = Buffer.from(png.buffer, png.byteOffset, png.byteLength);
258
+ if (b.length < 24 || b.readUInt32BE(12) !== 0x49484452)
259
+ throw new Error('Not a PNG');
260
+ return { width: b.readUInt32BE(16), height: b.readUInt32BE(20) };
261
+ }
262
+ /**
263
+ * macOS Chromium ignores --lang: its UI language comes from AppleLanguages,
264
+ * which Cocoa reads from `-AppleLanguages (xx)` in argv. Playwright refuses
265
+ * positional arguments, so this wrapper appends them — and drops Playwright's
266
+ * trailing `about:blank`, because headless Chromium rejects a second startup
267
+ * target (the `(xx)` value is parsed as one).
268
+ */
269
+ export function macLocaleWrapper(executable, lang) {
270
+ const quote = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
271
+ return ('#!/bin/sh\n' +
272
+ '# Generated by extenshi screenshots: run Chromium with a macOS UI language.\n' +
273
+ 'for a; do shift; [ "$a" = about:blank ] || set -- "$@" "$a"; done\n' +
274
+ `exec ${quote(executable)} "$@" -AppleLanguages ${quote(`(${lang})`)}\n`);
275
+ }
276
+ //# sourceMappingURL=screenshots-scenes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshots-scenes.js","sourceRoot":"","sources":["../src/screenshots-scenes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * `extenshi screenshots <unpacked-dir|zip> --scenes scenes.json` — store
3
+ * screenshots per locale, without a human.
4
+ *
5
+ * Loads the build into Chromium (Playwright, resolved lazily from the project or
6
+ * the CLI's own install — never bundled), runs the declarative scenes from
7
+ * screenshots-scenes.ts once per locale, and writes each store's screenshot size
8
+ * (store-assets.ts STORE_SCREENSHOT_SPECS) with stable names:
9
+ *
10
+ * <out>/<store>/<locale>/01-popup-1280x800.png
11
+ * <out>/screenshots.json (index: files, sha256, verified locales)
12
+ *
13
+ * Locale switching is the part that silently goes wrong elsewhere, so it is
14
+ * verified, not assumed: each locale gets a fresh Chromium whose UI language is
15
+ * set per platform (--lang; LANGUAGE on Linux; -AppleLanguages on macOS, where
16
+ * --lang is ignored), then `chrome.i18n` inside the extension must report that
17
+ * locale AND render a message from `_locales/<locale>`. A mismatch fails the run
18
+ * instead of producing English screenshots labelled German.
19
+ *
20
+ * Determinism: fixed viewport and device scale factor, `reducedMotion`,
21
+ * animations/transitions/caret disabled, UTC timezone, optional fixed clock,
22
+ * fonts + images awaited before every capture, and the store canvas composed
23
+ * with resvg (no browser scaling). The source directory is never modified — the
24
+ * build is staged into a temporary copy (a zip is extracted there).
25
+ *
26
+ * TODO(evidence): `--evidence` (record `screenshots` evidence per locale) is
27
+ * deliberately not implemented here — it belongs to the shared `--evidence`
28
+ * mechanism being added for `package` / `test smoke`. screenshots.json already
29
+ * carries per-locale file lists and hashes for it to consume.
30
+ */
31
+ import { type Size, type StoreId } from './store-assets.js';
32
+ type Json = Record<string, any>;
33
+ interface PwPage {
34
+ goto(url: string, opts?: Json): Promise<unknown>;
35
+ url(): string;
36
+ close(): Promise<void>;
37
+ evaluate<T>(fn: string | ((arg: any) => T | Promise<T>), arg?: unknown): Promise<T>;
38
+ screenshot(opts?: Json): Promise<Buffer>;
39
+ setViewportSize(size: Size): Promise<void>;
40
+ emulateMedia(opts: Json): Promise<void>;
41
+ addInitScript(script: Json): Promise<void>;
42
+ waitForTimeout(ms: number): Promise<void>;
43
+ locator(selector: string): any;
44
+ keyboard: {
45
+ press(key: string): Promise<void>;
46
+ };
47
+ mouse: {
48
+ move(x: number, y: number): Promise<void>;
49
+ wheel(dx: number, dy: number): Promise<void>;
50
+ };
51
+ clock?: {
52
+ setFixedTime(time: Date): Promise<void>;
53
+ };
54
+ }
55
+ interface PwContext {
56
+ pages(): PwPage[];
57
+ newPage(): Promise<PwPage>;
58
+ serviceWorkers(): {
59
+ url(): string;
60
+ }[];
61
+ waitForEvent(event: string, opts?: Json): Promise<unknown>;
62
+ close(): Promise<void>;
63
+ browser(): {
64
+ version(): string;
65
+ } | null;
66
+ }
67
+ interface Playwright {
68
+ chromium: {
69
+ executablePath(): string;
70
+ launchPersistentContext(dir: string, opts: Json): Promise<PwContext>;
71
+ };
72
+ }
73
+ export declare const PROBE_PAGE = "__extenshi_screenshots__.html";
74
+ /** Resolve Playwright from the project first, then from the CLI's own install. */
75
+ export declare function loadPlaywright(cwd?: string, bases?: string[]): Playwright;
76
+ export interface StagedExtension {
77
+ dir: string;
78
+ id: string;
79
+ manifest: Json;
80
+ locales: string[];
81
+ defaultLocale?: string;
82
+ messages: Record<string, Record<string, {
83
+ message?: unknown;
84
+ }> | null>;
85
+ warnings: string[];
86
+ }
87
+ /**
88
+ * Copy (or unzip) the build into `work/extension`, never touching the source.
89
+ * The copy gets one extra, empty page — the probe the runner uses to reach
90
+ * chrome.i18n / chrome.storage in the extension's own context.
91
+ */
92
+ export declare function stageExtension(input: string, work: string): Promise<StagedExtension>;
93
+ /** Static server for fixture pages on 127.0.0.1 — content scripts do not run on file://. */
94
+ export declare function startFixtureServer(root: string): Promise<{
95
+ origin: string;
96
+ close(): Promise<void>;
97
+ }>;
98
+ interface Capture {
99
+ png: Buffer;
100
+ css: Size;
101
+ }
102
+ /** Compose a capture onto a store-size canvas with resvg (exact pixels, no browser scaling). */
103
+ export declare function composeOnCanvas(capture: Capture, canvas: Size, opts: {
104
+ fit: 'contain' | 'cover';
105
+ dsf: number;
106
+ background: string;
107
+ backgroundTo?: string;
108
+ margin: number;
109
+ shadow: boolean;
110
+ radius: number;
111
+ }): Promise<Buffer>;
112
+ export interface ScreenshotsOptions {
113
+ scenes: string;
114
+ locales?: string;
115
+ store?: string;
116
+ out?: string;
117
+ /** Use each store's smaller accepted size (Chrome 640×400, Edge 640×480, AMO 640×400). */
118
+ small?: boolean;
119
+ headed?: boolean;
120
+ json?: boolean;
121
+ }
122
+ export interface ScreenshotFile {
123
+ store: StoreId;
124
+ locale: string;
125
+ scene: string;
126
+ path: string;
127
+ width: number;
128
+ height: number;
129
+ sha256: string;
130
+ }
131
+ export interface ScreenshotsResult {
132
+ outDir: string;
133
+ files: ScreenshotFile[];
134
+ locales: {
135
+ locale: string;
136
+ uiLocale: string;
137
+ catalog: string | null;
138
+ sample: string | null;
139
+ }[];
140
+ warnings: string[];
141
+ }
142
+ export declare function runScreenshots(input: string, opts: ScreenshotsOptions): Promise<ScreenshotsResult>;
143
+ export declare function runScreenshotsCommand(input: string, opts: ScreenshotsOptions): Promise<void>;
144
+ export {};
145
+ //# sourceMappingURL=screenshots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshots.d.ts","sourceRoot":"","sources":["../src/screenshots.ts"],"names":[],"mappings":"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"}