heroshot 0.16.0 → 0.18.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.
- package/README.md +14 -14
- package/dist/cli/cli.js +19 -27
- package/dist/index.js +1 -2
- package/dist/mcp/index.js +5 -10975
- package/dist/{snippet-Fc-PkcTD.js → snippet-ZcZmuryj.js} +126 -128
- package/dist/templates/heroshotReadme.txt +1 -1
- package/editor/dist/editor.js +1733 -1194
- package/package.json +16 -16
|
@@ -9,7 +9,6 @@ import { homedir, platform } from "node:os";
|
|
|
9
9
|
import { chromium } from "playwright";
|
|
10
10
|
import { execSync } from "node:child_process";
|
|
11
11
|
import pLimit from "p-limit";
|
|
12
|
-
|
|
13
12
|
//#region src/ui.ts
|
|
14
13
|
/**
|
|
15
14
|
* Terminal UI using @clack/prompts
|
|
@@ -83,7 +82,6 @@ function spinner$1() {
|
|
|
83
82
|
function log$1(text) {
|
|
84
83
|
console.log(text);
|
|
85
84
|
}
|
|
86
|
-
|
|
87
85
|
//#endregion
|
|
88
86
|
//#region src/actionSchema.ts
|
|
89
87
|
/**
|
|
@@ -211,7 +209,6 @@ const actionSchema = z.discriminatedUnion("type", [
|
|
|
211
209
|
]);
|
|
212
210
|
/** Array of actions to execute sequentially before screenshot capture */
|
|
213
211
|
const actionsSchema = z.array(actionSchema).describe("Ordered list of actions to execute before capturing. Actions run sequentially.");
|
|
214
|
-
|
|
215
212
|
//#endregion
|
|
216
213
|
//#region src/utils/generateUid.ts
|
|
217
214
|
/**
|
|
@@ -221,7 +218,6 @@ const actionsSchema = z.array(actionSchema).describe("Ordered list of actions to
|
|
|
221
218
|
function generateUid() {
|
|
222
219
|
return crypto.randomUUID().slice(0, 8);
|
|
223
220
|
}
|
|
224
|
-
|
|
225
221
|
//#endregion
|
|
226
222
|
//#region src/schema.ts
|
|
227
223
|
/**
|
|
@@ -335,33 +331,8 @@ const browserSchema = z.object({
|
|
|
335
331
|
deviceScaleFactor: z.number().min(1).max(3).optional().describe("Device pixel ratio (1 = standard, 2 = retina, 3 = ultra-high DPI)"),
|
|
336
332
|
bypassCSP: z.boolean().optional().describe("Bypass Content-Security-Policy restrictions. Enabled by default for reliable page.evaluate() calls"),
|
|
337
333
|
reducedMotion: z.enum(["reduce", "no-preference"]).optional().describe("Emulate prefers-reduced-motion media feature. Use \"reduce\" to disable animations"),
|
|
338
|
-
userAgent: z.string().optional().describe("Custom user agent string for the browser")
|
|
339
|
-
|
|
340
|
-
/** Shared CLI options for URL capture */
|
|
341
|
-
const shotCliOptionsSchema = z.object({
|
|
342
|
-
selector: z.array(z.string()).optional(),
|
|
343
|
-
output: z.string().optional(),
|
|
344
|
-
padding: z.number().int().min(0).optional(),
|
|
345
|
-
width: z.number().int().positive().optional(),
|
|
346
|
-
height: z.number().int().positive().optional(),
|
|
347
|
-
mobile: z.boolean().optional(),
|
|
348
|
-
tablet: z.boolean().optional(),
|
|
349
|
-
desktop: z.boolean().optional(),
|
|
350
|
-
dark: z.boolean().optional(),
|
|
351
|
-
light: z.boolean().optional(),
|
|
352
|
-
scale: z.number().min(1).max(3).optional(),
|
|
353
|
-
retina: z.boolean().optional(),
|
|
354
|
-
quality: z.number().int().min(1).max(100).optional(),
|
|
355
|
-
viewportOnly: z.boolean().optional(),
|
|
356
|
-
reducedMotion: z.boolean().optional(),
|
|
357
|
-
userAgent: z.string().optional()
|
|
358
|
-
});
|
|
359
|
-
/** CLI command options for URL capture (includes --save and --clean flags) */
|
|
360
|
-
const shotCommandOptionsSchema = shotCliOptionsSchema.extend({
|
|
361
|
-
save: z.boolean().optional(),
|
|
362
|
-
clean: z.boolean().optional(),
|
|
363
|
-
workers: z.number().int().min(1).optional(),
|
|
364
|
-
headed: z.boolean().optional()
|
|
334
|
+
userAgent: z.string().optional().describe("Custom user agent string for the browser"),
|
|
335
|
+
ignoreHTTPSErrors: z.boolean().optional().describe("Ignore TLS certificate errors (self-signed certs, custom CA). Dev-only setting")
|
|
365
336
|
});
|
|
366
337
|
/** Global config */
|
|
367
338
|
const configSchema = z.object({
|
|
@@ -371,9 +342,9 @@ const configSchema = z.object({
|
|
|
371
342
|
browser: browserSchema.optional().describe("Default browser settings applied to all screenshots"),
|
|
372
343
|
workers: z.number().int().min(1).optional().describe("Number of parallel capture workers (default: 1)"),
|
|
373
344
|
screenshots: z.array(screenshotSchema).default([]).describe("Screenshot definitions"),
|
|
374
|
-
hiddenElements: z.record(z.string(), z.array(z.string())).optional().describe("Elements to hide per domain (hostname → CSS selectors)")
|
|
345
|
+
hiddenElements: z.record(z.string(), z.array(z.string())).optional().describe("Elements to hide per domain (hostname → CSS selectors)"),
|
|
346
|
+
locales: z.array(z.string().min(1)).optional().describe("Locale codes (e.g., [\"en\", \"de\"]).")
|
|
375
347
|
});
|
|
376
|
-
|
|
377
348
|
//#endregion
|
|
378
349
|
//#region src/config.ts
|
|
379
350
|
/**
|
|
@@ -384,7 +355,6 @@ const configSchema = z.object({
|
|
|
384
355
|
function parseConfig(input) {
|
|
385
356
|
return configSchema.parse(input);
|
|
386
357
|
}
|
|
387
|
-
|
|
388
358
|
//#endregion
|
|
389
359
|
//#region src/configFile.ts
|
|
390
360
|
const HEROSHOT_DIRECTORY_NAME = ".heroshot";
|
|
@@ -425,7 +395,6 @@ function saveConfig(configPath, config) {
|
|
|
425
395
|
if (!existsSync(parentDirectory)) mkdirSync(parentDirectory, { recursive: true });
|
|
426
396
|
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
427
397
|
}
|
|
428
|
-
|
|
429
398
|
//#endregion
|
|
430
399
|
//#region src/session.ts
|
|
431
400
|
const SESSION_FILENAME = "session.enc";
|
|
@@ -433,7 +402,6 @@ const KEYS_DIRECTORY = path.join(homedir(), ".heroshot", "keys");
|
|
|
433
402
|
const ALGORITHM = "aes-256-gcm";
|
|
434
403
|
const KEY_LENGTH = 32;
|
|
435
404
|
const IV_LENGTH = 16;
|
|
436
|
-
const AUTH_TAG_LENGTH = 16;
|
|
437
405
|
const SALT_LENGTH = 16;
|
|
438
406
|
const SESSION_KEY_LENGTH = 20;
|
|
439
407
|
/**
|
|
@@ -472,9 +440,9 @@ function encrypt(data, sessionKey) {
|
|
|
472
440
|
*/
|
|
473
441
|
function decrypt(encryptedData, sessionKey) {
|
|
474
442
|
const salt = encryptedData.subarray(0, SALT_LENGTH);
|
|
475
|
-
const iv = encryptedData.subarray(SALT_LENGTH,
|
|
476
|
-
const authTag = encryptedData.subarray(
|
|
477
|
-
const ciphertext = encryptedData.subarray(
|
|
443
|
+
const iv = encryptedData.subarray(SALT_LENGTH, 32);
|
|
444
|
+
const authTag = encryptedData.subarray(32, 48);
|
|
445
|
+
const ciphertext = encryptedData.subarray(48);
|
|
478
446
|
const decipher = createDecipheriv(ALGORITHM, deriveKey(sessionKey, salt), iv);
|
|
479
447
|
decipher.setAuthTag(authTag);
|
|
480
448
|
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
@@ -558,7 +526,6 @@ function getSessionKey(cliKey, directory = process.cwd()) {
|
|
|
558
526
|
if (environmentKey) return environmentKey;
|
|
559
527
|
return loadLocalKey(directory);
|
|
560
528
|
}
|
|
561
|
-
|
|
562
529
|
//#endregion
|
|
563
530
|
//#region src/browser/constants.ts
|
|
564
531
|
/** Default viewport dimensions */
|
|
@@ -580,7 +547,6 @@ function findPackageRoot(startDirectory) {
|
|
|
580
547
|
}
|
|
581
548
|
/** Path to editor directory */
|
|
582
549
|
const EDITOR_DIR = path.join(findPackageRoot(path.dirname(fileURLToPath(import.meta.url))), "editor");
|
|
583
|
-
|
|
584
550
|
//#endregion
|
|
585
551
|
//#region src/browser/browserDetect.ts
|
|
586
552
|
/**
|
|
@@ -660,7 +626,6 @@ function detectSystemBrowsers() {
|
|
|
660
626
|
}
|
|
661
627
|
return detected;
|
|
662
628
|
}
|
|
663
|
-
|
|
664
629
|
//#endregion
|
|
665
630
|
//#region src/browser/noBrowserError.ts
|
|
666
631
|
/**
|
|
@@ -682,7 +647,6 @@ function noBrowserError() {
|
|
|
682
647
|
].join("\n");
|
|
683
648
|
return new Error(message);
|
|
684
649
|
}
|
|
685
|
-
|
|
686
650
|
//#endregion
|
|
687
651
|
//#region src/browser/launchBrowser.ts
|
|
688
652
|
/**
|
|
@@ -731,14 +695,16 @@ async function launchBrowser(options = {}) {
|
|
|
731
695
|
...options.storageState && { storageState: options.storageState },
|
|
732
696
|
...options.colorScheme && { colorScheme: options.colorScheme },
|
|
733
697
|
...options.reducedMotion && { reducedMotion: options.reducedMotion },
|
|
734
|
-
...options.userAgent && { userAgent: options.userAgent }
|
|
698
|
+
...options.userAgent && { userAgent: options.userAgent },
|
|
699
|
+
...options.ignoreHTTPSErrors && { ignoreHTTPSErrors: true },
|
|
700
|
+
...options.locale && { locale: options.locale },
|
|
701
|
+
...options.locale && { extraHTTPHeaders: { "Accept-Language": options.locale } }
|
|
735
702
|
});
|
|
736
703
|
return {
|
|
737
704
|
browser,
|
|
738
705
|
context
|
|
739
706
|
};
|
|
740
707
|
}
|
|
741
|
-
|
|
742
708
|
//#endregion
|
|
743
709
|
//#region src/utils/getColorSchemes.ts
|
|
744
710
|
/**
|
|
@@ -752,7 +718,6 @@ function getColorSchemes(setting) {
|
|
|
752
718
|
if (setting === "dark") return ["dark"];
|
|
753
719
|
return ["light", "dark"];
|
|
754
720
|
}
|
|
755
|
-
|
|
756
721
|
//#endregion
|
|
757
722
|
//#region src/sync/configHelpers.ts
|
|
758
723
|
/**
|
|
@@ -778,12 +743,13 @@ function resolveOutputDirectory(configPath, configOutputDirectory, override) {
|
|
|
778
743
|
/**
|
|
779
744
|
* Calculate total number of captures needed.
|
|
780
745
|
*/
|
|
781
|
-
function calculateTotalCaptures(screenshots, schemeCount) {
|
|
746
|
+
function calculateTotalCaptures(screenshots, schemeCount, localeCount = 1) {
|
|
782
747
|
let total = 0;
|
|
783
748
|
const adjustedSchemeCount = Math.max(1, schemeCount);
|
|
749
|
+
const adjustedLocaleCount = Math.max(1, localeCount);
|
|
784
750
|
for (const screenshot of screenshots) {
|
|
785
751
|
const viewportCount = screenshot.viewports?.length ?? 1;
|
|
786
|
-
total += viewportCount * adjustedSchemeCount;
|
|
752
|
+
total += viewportCount * adjustedSchemeCount * adjustedLocaleCount;
|
|
787
753
|
}
|
|
788
754
|
return total;
|
|
789
755
|
}
|
|
@@ -810,10 +776,26 @@ function buildBrowserOptions(config) {
|
|
|
810
776
|
deviceScaleFactor: config.browser?.deviceScaleFactor,
|
|
811
777
|
bypassCSP: config.browser?.bypassCSP,
|
|
812
778
|
reducedMotion: config.browser?.reducedMotion,
|
|
813
|
-
userAgent: config.browser?.userAgent
|
|
779
|
+
userAgent: config.browser?.userAgent,
|
|
780
|
+
ignoreHTTPSErrors: config.browser?.ignoreHTTPSErrors
|
|
814
781
|
};
|
|
815
782
|
}
|
|
816
|
-
|
|
783
|
+
//#endregion
|
|
784
|
+
//#region src/utils/localeUrl.ts
|
|
785
|
+
/**
|
|
786
|
+
* Apply locale to a URL by replacing the {locale} placeholder.
|
|
787
|
+
* If the URL contains no placeholder, it is returned unchanged.
|
|
788
|
+
*
|
|
789
|
+
* @example
|
|
790
|
+
* applyLocale('http://localhost:5173/{locale}/about', 'de')
|
|
791
|
+
* // → 'http://localhost:5173/de/about'
|
|
792
|
+
*
|
|
793
|
+
* applyLocale('http://localhost:5173/about', 'de')
|
|
794
|
+
* // → 'http://localhost:5173/about'
|
|
795
|
+
*/
|
|
796
|
+
function applyLocale(url, locale) {
|
|
797
|
+
return url.replaceAll("{locale}", locale);
|
|
798
|
+
}
|
|
817
799
|
//#endregion
|
|
818
800
|
//#region src/utils/parseViewport.ts
|
|
819
801
|
/**
|
|
@@ -847,7 +829,6 @@ function parseViewport(variant) {
|
|
|
847
829
|
...VIEWPORT_PRESETS.desktop
|
|
848
830
|
};
|
|
849
831
|
}
|
|
850
|
-
|
|
851
832
|
//#endregion
|
|
852
833
|
//#region src/utils/screenshotPath.ts
|
|
853
834
|
/**
|
|
@@ -861,7 +842,7 @@ function slugifySegment(text) {
|
|
|
861
842
|
* Supports subdirectory paths via forward slashes in the name (e.g., "registry/login-01").
|
|
862
843
|
*/
|
|
863
844
|
function generateScreenshotFilename(options) {
|
|
864
|
-
const { name, viewport, colorScheme, format = "png" } = options;
|
|
845
|
+
const { name, viewport, colorScheme, locale, format = "png" } = options;
|
|
865
846
|
const segments = name.split("/").map(slugifySegment).filter(Boolean);
|
|
866
847
|
const directory = segments.length > 1 ? segments.slice(0, -1).join("/") : "";
|
|
867
848
|
const parts = [segments.at(-1) ?? ""];
|
|
@@ -869,9 +850,9 @@ function generateScreenshotFilename(options) {
|
|
|
869
850
|
if (colorScheme) parts.push(colorScheme);
|
|
870
851
|
const extension = format === "jpeg" ? "jpg" : "png";
|
|
871
852
|
const filename = `${parts.join("-")}.${extension}`;
|
|
872
|
-
|
|
853
|
+
const pathWithDirectory = directory ? `${directory}/${filename}` : filename;
|
|
854
|
+
return locale ? `${locale}/${pathWithDirectory}` : pathWithDirectory;
|
|
873
855
|
}
|
|
874
|
-
|
|
875
856
|
//#endregion
|
|
876
857
|
//#region src/sync/actions/click.ts
|
|
877
858
|
/** MCP: locator.click(options) or locator.dblclick(options) */
|
|
@@ -886,7 +867,6 @@ async function executeClick(page, action) {
|
|
|
886
867
|
await (action.doubleClick ? locator.dblclick(options) : locator.click(options));
|
|
887
868
|
} else await (action.doubleClick ? locator.dblclick() : locator.click());
|
|
888
869
|
}
|
|
889
|
-
|
|
890
870
|
//#endregion
|
|
891
871
|
//#region src/sync/actions/drag.ts
|
|
892
872
|
/** MCP: startLocator.dragTo(endLocator) */
|
|
@@ -896,7 +876,6 @@ async function executeDrag(page, action) {
|
|
|
896
876
|
const to = page.locator(action.to);
|
|
897
877
|
await (action.timeout ? from.dragTo(to, { timeout: action.timeout }) : from.dragTo(to));
|
|
898
878
|
}
|
|
899
|
-
|
|
900
879
|
//#endregion
|
|
901
880
|
//#region src/sync/actions/evaluate.ts
|
|
902
881
|
/**
|
|
@@ -911,7 +890,6 @@ async function executeEvaluate(page, action) {
|
|
|
911
890
|
await page.evaluate(`(${action.function})(document.querySelector('${escapedSelector}'))`);
|
|
912
891
|
} else await page.evaluate(`(${action.function})()`);
|
|
913
892
|
}
|
|
914
|
-
|
|
915
893
|
//#endregion
|
|
916
894
|
//#region src/sync/actions/fileUpload.ts
|
|
917
895
|
/** MCP: locator.setInputFiles(paths) */
|
|
@@ -919,7 +897,6 @@ async function executeFileUpload(page, action) {
|
|
|
919
897
|
if (action.type !== "file_upload") return;
|
|
920
898
|
await page.locator(action.selector).setInputFiles(action.paths);
|
|
921
899
|
}
|
|
922
|
-
|
|
923
900
|
//#endregion
|
|
924
901
|
//#region src/sync/actions/fillForm.ts
|
|
925
902
|
/** MCP: locator.fill / setChecked / check / selectOption per field type */
|
|
@@ -945,7 +922,6 @@ async function executeFillForm(page, action) {
|
|
|
945
922
|
}[field.fieldType]?.();
|
|
946
923
|
}
|
|
947
924
|
}
|
|
948
|
-
|
|
949
925
|
//#endregion
|
|
950
926
|
//#region src/sync/actions/handleDialog.ts
|
|
951
927
|
/** MCP: Sets up a one-time dialog handler for the next dialog */
|
|
@@ -956,7 +932,6 @@ function executeHandleDialog(page, action) {
|
|
|
956
932
|
await (accept ? dialog.accept(promptText) : dialog.dismiss());
|
|
957
933
|
});
|
|
958
934
|
}
|
|
959
|
-
|
|
960
935
|
//#endregion
|
|
961
936
|
//#region src/sync/actions/hide.ts
|
|
962
937
|
/** Hide elements by setting visibility: hidden (preserves layout) */
|
|
@@ -966,7 +941,6 @@ async function executeHide(page, action) {
|
|
|
966
941
|
for (const element of elements) element.style.setProperty("visibility", "hidden", "important");
|
|
967
942
|
});
|
|
968
943
|
}
|
|
969
|
-
|
|
970
944
|
//#endregion
|
|
971
945
|
//#region src/sync/actions/hover.ts
|
|
972
946
|
/** MCP: locator.hover() */
|
|
@@ -975,7 +949,6 @@ async function executeHover(page, action) {
|
|
|
975
949
|
const locator = page.locator(action.selector);
|
|
976
950
|
await (action.timeout ? locator.hover({ timeout: action.timeout }) : locator.hover());
|
|
977
951
|
}
|
|
978
|
-
|
|
979
952
|
//#endregion
|
|
980
953
|
//#region src/sync/actions/navigate.ts
|
|
981
954
|
/** MCP: page.goto(url) or page.goBack() */
|
|
@@ -984,7 +957,6 @@ async function executeNavigate(page, action) {
|
|
|
984
957
|
if (action.back) await page.goBack();
|
|
985
958
|
else if (action.url) await page.goto(action.url, { waitUntil: "domcontentloaded" });
|
|
986
959
|
}
|
|
987
|
-
|
|
988
960
|
//#endregion
|
|
989
961
|
//#region src/sync/actions/pressKey.ts
|
|
990
962
|
/** MCP: page.keyboard.press(key) */
|
|
@@ -992,7 +964,6 @@ async function executePressKey(page, action) {
|
|
|
992
964
|
if (action.type !== "press_key") return;
|
|
993
965
|
await page.keyboard.press(action.key);
|
|
994
966
|
}
|
|
995
|
-
|
|
996
967
|
//#endregion
|
|
997
968
|
//#region src/sync/actions/resize.ts
|
|
998
969
|
/** MCP: page.setViewportSize({ width, height }) */
|
|
@@ -1003,7 +974,6 @@ async function executeResize(page, action) {
|
|
|
1003
974
|
height: action.height
|
|
1004
975
|
});
|
|
1005
976
|
}
|
|
1006
|
-
|
|
1007
977
|
//#endregion
|
|
1008
978
|
//#region src/sync/actions/selectOption.ts
|
|
1009
979
|
/** MCP: locator.selectOption(values) */
|
|
@@ -1012,7 +982,6 @@ async function executeSelectOption(page, action) {
|
|
|
1012
982
|
const locator = page.locator(action.selector);
|
|
1013
983
|
await (action.timeout ? locator.selectOption(action.values, { timeout: action.timeout }) : locator.selectOption(action.values));
|
|
1014
984
|
}
|
|
1015
|
-
|
|
1016
985
|
//#endregion
|
|
1017
986
|
//#region src/sync/actions/type.ts
|
|
1018
987
|
/** MCP: locator.fill(text) or locator.pressSequentially(text) */
|
|
@@ -1025,7 +994,6 @@ async function executeType(page, action) {
|
|
|
1025
994
|
} else await (action.slowly ? locator.pressSequentially(action.text) : locator.fill(action.text));
|
|
1026
995
|
if (action.submit) await page.keyboard.press("Enter");
|
|
1027
996
|
}
|
|
1028
|
-
|
|
1029
997
|
//#endregion
|
|
1030
998
|
//#region src/sync/actions/wait.ts
|
|
1031
999
|
/** MCP: waitForTimeout / getByText().waitFor() */
|
|
@@ -1035,7 +1003,6 @@ async function executeWait(page, action) {
|
|
|
1035
1003
|
if (action.text) await page.getByText(action.text).first().waitFor({ state: "visible" });
|
|
1036
1004
|
if (action.textGone) await page.getByText(action.textGone).first().waitFor({ state: "hidden" });
|
|
1037
1005
|
}
|
|
1038
|
-
|
|
1039
1006
|
//#endregion
|
|
1040
1007
|
//#region src/sync/actions/index.ts
|
|
1041
1008
|
/** Dispatch map: action type -> handler function */
|
|
@@ -1065,7 +1032,6 @@ async function executeActions(page, actions) {
|
|
|
1065
1032
|
await actionHandlers[action.type](page, action);
|
|
1066
1033
|
}
|
|
1067
1034
|
}
|
|
1068
|
-
|
|
1069
1035
|
//#endregion
|
|
1070
1036
|
//#region src/sync/annotationOverlay.ts
|
|
1071
1037
|
const OVERLAY_ID$1 = "heroshot-annotation-overlay";
|
|
@@ -1246,7 +1212,6 @@ async function removeAnnotationOverlay(page) {
|
|
|
1246
1212
|
if (existing) existing.remove();
|
|
1247
1213
|
})()`);
|
|
1248
1214
|
}
|
|
1249
|
-
|
|
1250
1215
|
//#endregion
|
|
1251
1216
|
//#region src/sync/borderOverlay.ts
|
|
1252
1217
|
const OVERLAY_ID = "heroshot-border-overlay";
|
|
@@ -1288,7 +1253,6 @@ async function removeBorderOverlay(page) {
|
|
|
1288
1253
|
if (el) el.remove();
|
|
1289
1254
|
})()`);
|
|
1290
1255
|
}
|
|
1291
|
-
|
|
1292
1256
|
//#endregion
|
|
1293
1257
|
//#region src/sync/borderRadiusMask.ts
|
|
1294
1258
|
/**
|
|
@@ -1369,7 +1333,6 @@ async function removeBorderRadiusMask(page) {
|
|
|
1369
1333
|
}
|
|
1370
1334
|
})()`);
|
|
1371
1335
|
}
|
|
1372
|
-
|
|
1373
1336
|
//#endregion
|
|
1374
1337
|
//#region src/sync/elementFinder.ts
|
|
1375
1338
|
/**
|
|
@@ -1399,7 +1362,6 @@ async function findElement(page, selector, maxAttempts = 10, intervalMs = 500) {
|
|
|
1399
1362
|
}
|
|
1400
1363
|
return null;
|
|
1401
1364
|
}
|
|
1402
|
-
|
|
1403
1365
|
//#endregion
|
|
1404
1366
|
//#region src/sync/paddingMask.ts
|
|
1405
1367
|
const MASK_ID = "heroshot-padding-mask";
|
|
@@ -1464,7 +1426,6 @@ async function removePaddingMask(page) {
|
|
|
1464
1426
|
if (existing) existing.remove();
|
|
1465
1427
|
})()`);
|
|
1466
1428
|
}
|
|
1467
|
-
|
|
1468
1429
|
//#endregion
|
|
1469
1430
|
//#region src/sync/browserFunctions.ts
|
|
1470
1431
|
/**
|
|
@@ -1484,7 +1445,6 @@ async function removePaddingMask(page) {
|
|
|
1484
1445
|
function applyColorScheme(isDark) {
|
|
1485
1446
|
document.documentElement.classList.toggle("dark", isDark);
|
|
1486
1447
|
}
|
|
1487
|
-
|
|
1488
1448
|
//#endregion
|
|
1489
1449
|
//#region src/sync/pageScripts.ts
|
|
1490
1450
|
/**
|
|
@@ -1584,7 +1544,6 @@ async function getElementBackgroundColor(page, selector) {
|
|
|
1584
1544
|
async function applyColorSchemeClass(page, colorScheme) {
|
|
1585
1545
|
await page.evaluate(applyColorScheme, colorScheme === "dark");
|
|
1586
1546
|
}
|
|
1587
|
-
|
|
1588
1547
|
//#endregion
|
|
1589
1548
|
//#region src/sync/screenshot.ts
|
|
1590
1549
|
/**
|
|
@@ -1628,7 +1587,6 @@ async function takeScreenshot(options) {
|
|
|
1628
1587
|
omitBackground
|
|
1629
1588
|
});
|
|
1630
1589
|
}
|
|
1631
|
-
|
|
1632
1590
|
//#endregion
|
|
1633
1591
|
//#region src/sync/elementCapture.ts
|
|
1634
1592
|
/**
|
|
@@ -1740,7 +1698,6 @@ async function captureElementScreenshot(options) {
|
|
|
1740
1698
|
if (elementFill === "solid" || elementFill === "transparent") await restoreElementBackground(page, selector);
|
|
1741
1699
|
return { success: true };
|
|
1742
1700
|
}
|
|
1743
|
-
|
|
1744
1701
|
//#endregion
|
|
1745
1702
|
//#region src/sync/results.ts
|
|
1746
1703
|
/**
|
|
@@ -1749,8 +1706,12 @@ async function captureElementScreenshot(options) {
|
|
|
1749
1706
|
/**
|
|
1750
1707
|
* Build a variant ID suffix.
|
|
1751
1708
|
*/
|
|
1752
|
-
function buildVariantSuffix(viewportName, colorScheme) {
|
|
1753
|
-
return [
|
|
1709
|
+
function buildVariantSuffix(viewportName, colorScheme, locale) {
|
|
1710
|
+
return [
|
|
1711
|
+
locale,
|
|
1712
|
+
viewportName,
|
|
1713
|
+
colorScheme
|
|
1714
|
+
].filter(Boolean).join("-");
|
|
1754
1715
|
}
|
|
1755
1716
|
/**
|
|
1756
1717
|
* Show capture results and return summary.
|
|
@@ -1786,7 +1747,6 @@ function showResults(results, outputDirectory, staleFiles, deletedFiles) {
|
|
|
1786
1747
|
deletedFiles: deletedFiles.length > 0 ? deletedFiles : void 0
|
|
1787
1748
|
};
|
|
1788
1749
|
}
|
|
1789
|
-
|
|
1790
1750
|
//#endregion
|
|
1791
1751
|
//#region src/sync/capture.ts
|
|
1792
1752
|
/**
|
|
@@ -1854,18 +1814,20 @@ async function captureScreenshot(page, screenshot, outputDirectory, captureOptio
|
|
|
1854
1814
|
name,
|
|
1855
1815
|
viewport: variant.viewportName,
|
|
1856
1816
|
colorScheme: variant.colorScheme,
|
|
1817
|
+
locale: variant.locale,
|
|
1857
1818
|
format
|
|
1858
1819
|
});
|
|
1859
|
-
const suffix = buildVariantSuffix(variant.viewportName, variant.colorScheme);
|
|
1820
|
+
const suffix = buildVariantSuffix(variant.viewportName, variant.colorScheme, variant.locale);
|
|
1860
1821
|
verbose(`Capturing: ${name}${suffix ? ` (${suffix})` : ""}`);
|
|
1861
|
-
const
|
|
1822
|
+
const effectiveUrl = variant.localeUrl ?? url;
|
|
1823
|
+
const navResult = await navigateAndPrepare(page, effectiveUrl, variant.colorScheme);
|
|
1862
1824
|
if (!navResult.success) return {
|
|
1863
1825
|
...navResult,
|
|
1864
1826
|
filename
|
|
1865
1827
|
};
|
|
1866
1828
|
if (captureOptions.hiddenElements) {
|
|
1867
1829
|
const { hiddenElements: hiddenByDomain } = captureOptions;
|
|
1868
|
-
const { hostname } = new URL(
|
|
1830
|
+
const { hostname } = new URL(effectiveUrl);
|
|
1869
1831
|
if (hiddenByDomain[hostname]?.length) await executeHide(page, {
|
|
1870
1832
|
type: "hide",
|
|
1871
1833
|
selectors: hiddenByDomain[hostname]
|
|
@@ -1928,7 +1890,7 @@ async function captureAndLog(page, screenshot, outputDirectory, captureOptions,
|
|
|
1928
1890
|
await page.waitForTimeout(delay);
|
|
1929
1891
|
}
|
|
1930
1892
|
}
|
|
1931
|
-
const suffix = buildVariantSuffix(variant.viewportName, variant.colorScheme);
|
|
1893
|
+
const suffix = buildVariantSuffix(variant.viewportName, variant.colorScheme, variant.locale);
|
|
1932
1894
|
const displayName = suffix ? `${screenshot.name} (${suffix})` : screenshot.name;
|
|
1933
1895
|
const idSuffix = suffix ? `-${suffix}` : "";
|
|
1934
1896
|
return {
|
|
@@ -1939,38 +1901,47 @@ async function captureAndLog(page, screenshot, outputDirectory, captureOptions,
|
|
|
1939
1901
|
error: result.error
|
|
1940
1902
|
};
|
|
1941
1903
|
}
|
|
1942
|
-
|
|
1943
1904
|
//#endregion
|
|
1944
1905
|
//#region src/sync/parallelCapture.ts
|
|
1945
1906
|
/**
|
|
1946
1907
|
* Parallel screenshot capture with multiple workers.
|
|
1947
1908
|
*/
|
|
1948
1909
|
/**
|
|
1949
|
-
* Build capture jobs from screenshots and
|
|
1910
|
+
* Build capture jobs from screenshots, schemes, and locales.
|
|
1950
1911
|
* Each job represents a single screenshot capture task.
|
|
1951
1912
|
*/
|
|
1952
|
-
function buildCaptureJobs(screenshots, schemes) {
|
|
1913
|
+
function buildCaptureJobs(screenshots, schemes, locales = []) {
|
|
1953
1914
|
const jobs = [];
|
|
1954
1915
|
const hasMultipleSchemes = schemes.length > 1;
|
|
1955
1916
|
const schemesToCapture = schemes.length === 0 ? [void 0] : schemes;
|
|
1917
|
+
const localesToCapture = locales.length === 0 ? [void 0] : locales;
|
|
1956
1918
|
for (const screenshot of screenshots) {
|
|
1957
1919
|
const viewportVariants = screenshot.viewports ?? [];
|
|
1958
1920
|
const hasMultipleViewports = viewportVariants.length > 1;
|
|
1959
|
-
for (const
|
|
1960
|
-
screenshot,
|
|
1961
|
-
|
|
1962
|
-
hasMultipleSchemes,
|
|
1963
|
-
hasMultipleViewports: false
|
|
1964
|
-
});
|
|
1965
|
-
else for (const viewportVariant of viewportVariants) {
|
|
1966
|
-
const parsedViewport = parseViewport(viewportVariant);
|
|
1967
|
-
jobs.push({
|
|
1921
|
+
for (const locale of localesToCapture) {
|
|
1922
|
+
const localeUrl = locale && screenshot.url.includes("{locale}") ? applyLocale(screenshot.url, locale) : void 0;
|
|
1923
|
+
for (const scheme of schemesToCapture) if (viewportVariants.length === 0) jobs.push({
|
|
1968
1924
|
screenshot,
|
|
1969
1925
|
colorScheme: scheme,
|
|
1970
|
-
viewport: parsedViewport,
|
|
1971
1926
|
hasMultipleSchemes,
|
|
1972
|
-
hasMultipleViewports
|
|
1927
|
+
hasMultipleViewports: false,
|
|
1928
|
+
locale,
|
|
1929
|
+
locales,
|
|
1930
|
+
localeUrl
|
|
1973
1931
|
});
|
|
1932
|
+
else for (const viewportVariant of viewportVariants) {
|
|
1933
|
+
const parsedViewport = parseViewport(viewportVariant);
|
|
1934
|
+
jobs.push({
|
|
1935
|
+
screenshot,
|
|
1936
|
+
colorScheme: scheme,
|
|
1937
|
+
viewport: parsedViewport,
|
|
1938
|
+
hasMultipleSchemes,
|
|
1939
|
+
hasMultipleViewports,
|
|
1940
|
+
locale,
|
|
1941
|
+
locales,
|
|
1942
|
+
localeUrl
|
|
1943
|
+
});
|
|
1944
|
+
}
|
|
1974
1945
|
}
|
|
1975
1946
|
}
|
|
1976
1947
|
return jobs;
|
|
@@ -1987,12 +1958,14 @@ async function executeBatch(jobs, outputDirectory, captureOptions, browserOption
|
|
|
1987
1958
|
storageState: browserOptions.storageState,
|
|
1988
1959
|
bypassCSP: browserOptions.bypassCSP,
|
|
1989
1960
|
reducedMotion: browserOptions.reducedMotion,
|
|
1990
|
-
userAgent: browserOptions.userAgent
|
|
1961
|
+
userAgent: browserOptions.userAgent,
|
|
1962
|
+
ignoreHTTPSErrors: browserOptions.ignoreHTTPSErrors,
|
|
1963
|
+
locale: jobs[0]?.locale
|
|
1991
1964
|
});
|
|
1992
1965
|
const page = await context.newPage();
|
|
1993
1966
|
try {
|
|
1994
1967
|
for (const job of jobs) {
|
|
1995
|
-
const { screenshot, colorScheme, viewport, hasMultipleSchemes, hasMultipleViewports } = job;
|
|
1968
|
+
const { screenshot, colorScheme, viewport, hasMultipleSchemes, hasMultipleViewports, locale, locales } = job;
|
|
1996
1969
|
if (viewport) await page.setViewportSize({
|
|
1997
1970
|
width: viewport.width,
|
|
1998
1971
|
height: viewport.height
|
|
@@ -2000,7 +1973,9 @@ async function executeBatch(jobs, outputDirectory, captureOptions, browserOption
|
|
|
2000
1973
|
if (colorScheme) await page.emulateMedia({ colorScheme });
|
|
2001
1974
|
const result = await captureAndLog(page, screenshot, outputDirectory, captureOptions, {
|
|
2002
1975
|
viewportName: hasMultipleViewports ? viewport?.name : void 0,
|
|
2003
|
-
colorScheme: hasMultipleSchemes ? colorScheme : void 0
|
|
1976
|
+
colorScheme: hasMultipleSchemes ? colorScheme : void 0,
|
|
1977
|
+
locale: (locales ?? []).length > 1 ? locale : void 0,
|
|
1978
|
+
localeUrl: job.localeUrl
|
|
2004
1979
|
});
|
|
2005
1980
|
results.push(result);
|
|
2006
1981
|
onProgress(result);
|
|
@@ -2011,16 +1986,17 @@ async function executeBatch(jobs, outputDirectory, captureOptions, browserOption
|
|
|
2011
1986
|
return results;
|
|
2012
1987
|
}
|
|
2013
1988
|
/**
|
|
2014
|
-
* Group jobs by URL to minimize page navigations.
|
|
2015
|
-
* Jobs for the same URL are kept together.
|
|
1989
|
+
* Group jobs by effective URL + locale to minimize page navigations.
|
|
1990
|
+
* Jobs for the same URL AND same locale are kept together.
|
|
1991
|
+
* Locale is a browser context-level setting, so different locales must be separate groups.
|
|
2016
1992
|
*/
|
|
2017
1993
|
function groupJobsByUrl(jobs) {
|
|
2018
1994
|
const groups = /* @__PURE__ */ new Map();
|
|
2019
1995
|
for (const job of jobs) {
|
|
2020
|
-
const
|
|
2021
|
-
const group = groups.get(
|
|
1996
|
+
const key = `${job.localeUrl ?? job.screenshot.url}::${job.locale ?? ""}`;
|
|
1997
|
+
const group = groups.get(key) ?? [];
|
|
2022
1998
|
group.push(job);
|
|
2023
|
-
groups.set(
|
|
1999
|
+
groups.set(key, group);
|
|
2024
2000
|
}
|
|
2025
2001
|
return groups;
|
|
2026
2002
|
}
|
|
@@ -2061,15 +2037,21 @@ async function captureParallel(options) {
|
|
|
2061
2037
|
for (const settled of settledResults) if (settled.status === "fulfilled") allResults.push(...settled.value);
|
|
2062
2038
|
return allResults;
|
|
2063
2039
|
}
|
|
2064
|
-
|
|
2065
2040
|
//#endregion
|
|
2066
2041
|
//#region src/sync/schemeCapture.ts
|
|
2067
2042
|
/**
|
|
2068
|
-
*
|
|
2043
|
+
* Color scheme + locale screenshot capture orchestration.
|
|
2044
|
+
*/
|
|
2045
|
+
/**
|
|
2046
|
+
* Capture screenshots for a single color scheme + locale combination.
|
|
2069
2047
|
* Launches a browser, captures all screenshots, and closes the browser.
|
|
2048
|
+
*
|
|
2049
|
+
* Locale is a browser context-level setting in Playwright, so each locale
|
|
2050
|
+
* gets its own browser launch. This ensures Accept-Language and JS locale APIs
|
|
2051
|
+
* (Intl, navigator.language) reflect the correct locale for all pages captured.
|
|
2070
2052
|
*/
|
|
2071
2053
|
async function captureWithScheme(options) {
|
|
2072
|
-
const { screenshots, outputDirectory, captureOptions, browserOptions, colorScheme, schemes, captureSpinner, progress } = options;
|
|
2054
|
+
const { screenshots, outputDirectory, captureOptions, browserOptions, colorScheme, schemes, locale, locales, captureSpinner, progress } = options;
|
|
2073
2055
|
const results = [];
|
|
2074
2056
|
const { browser, context } = await launchBrowser({
|
|
2075
2057
|
headless: !browserOptions.headed,
|
|
@@ -2079,22 +2061,33 @@ async function captureWithScheme(options) {
|
|
|
2079
2061
|
colorScheme,
|
|
2080
2062
|
bypassCSP: browserOptions.bypassCSP,
|
|
2081
2063
|
reducedMotion: browserOptions.reducedMotion,
|
|
2082
|
-
userAgent: browserOptions.userAgent
|
|
2064
|
+
userAgent: browserOptions.userAgent,
|
|
2065
|
+
ignoreHTTPSErrors: browserOptions.ignoreHTTPSErrors,
|
|
2066
|
+
locale
|
|
2083
2067
|
});
|
|
2084
2068
|
const page = await context.newPage();
|
|
2085
2069
|
if (colorScheme) await page.emulateMedia({ colorScheme });
|
|
2086
2070
|
const hasMultipleSchemes = schemes.length > 1;
|
|
2071
|
+
const hasMultipleLocales = locales.length > 1;
|
|
2087
2072
|
for (const screenshot of screenshots) {
|
|
2088
2073
|
const viewportVariants = screenshot.viewports ?? [];
|
|
2089
2074
|
const hasMultipleViewports = viewportVariants.length > 1;
|
|
2075
|
+
const localeUrl = locale && screenshot.url.includes("{locale}") ? applyLocale(screenshot.url, locale) : void 0;
|
|
2090
2076
|
if (viewportVariants.length === 0) {
|
|
2091
2077
|
progress.captured++;
|
|
2092
|
-
const variant = {
|
|
2093
|
-
|
|
2094
|
-
|
|
2078
|
+
const variant = {
|
|
2079
|
+
colorScheme: hasMultipleSchemes ? colorScheme : void 0,
|
|
2080
|
+
locale: hasMultipleLocales ? locale : void 0,
|
|
2081
|
+
localeUrl
|
|
2082
|
+
};
|
|
2083
|
+
const suffix = [variant.locale, variant.colorScheme].filter(Boolean).join(", ");
|
|
2084
|
+
const suffixDisplay = suffix ? ` (${suffix})` : "";
|
|
2085
|
+
captureSpinner.message(`Capturing ${progress.captured}/${progress.total}: ${screenshot.name}${suffixDisplay}`);
|
|
2095
2086
|
const result = await captureAndLog(page, screenshot, outputDirectory, captureOptions, variant);
|
|
2096
2087
|
results.push(result);
|
|
2097
|
-
|
|
2088
|
+
continue;
|
|
2089
|
+
}
|
|
2090
|
+
for (const viewportVariant of viewportVariants) {
|
|
2098
2091
|
const parsedViewport = parseViewport(viewportVariant);
|
|
2099
2092
|
await page.setViewportSize({
|
|
2100
2093
|
width: parsedViewport.width,
|
|
@@ -2103,9 +2096,15 @@ async function captureWithScheme(options) {
|
|
|
2103
2096
|
progress.captured++;
|
|
2104
2097
|
const variant = {
|
|
2105
2098
|
viewportName: hasMultipleViewports ? parsedViewport.name : void 0,
|
|
2106
|
-
colorScheme: hasMultipleSchemes ? colorScheme : void 0
|
|
2099
|
+
colorScheme: hasMultipleSchemes ? colorScheme : void 0,
|
|
2100
|
+
locale: hasMultipleLocales ? locale : void 0,
|
|
2101
|
+
localeUrl
|
|
2107
2102
|
};
|
|
2108
|
-
const suffix = [
|
|
2103
|
+
const suffix = [
|
|
2104
|
+
variant.locale,
|
|
2105
|
+
variant.viewportName,
|
|
2106
|
+
variant.colorScheme
|
|
2107
|
+
].filter(Boolean).join(", ");
|
|
2109
2108
|
const suffixDisplay = suffix ? ` (${suffix})` : "";
|
|
2110
2109
|
captureSpinner.message(`Capturing ${progress.captured}/${progress.total}: ${screenshot.name}${suffixDisplay}`);
|
|
2111
2110
|
const result = await captureAndLog(page, screenshot, outputDirectory, captureOptions, variant);
|
|
@@ -2115,7 +2114,6 @@ async function captureWithScheme(options) {
|
|
|
2115
2114
|
await browser.close();
|
|
2116
2115
|
return results;
|
|
2117
2116
|
}
|
|
2118
|
-
|
|
2119
2117
|
//#endregion
|
|
2120
2118
|
//#region src/sync/sessionLoader.ts
|
|
2121
2119
|
/**
|
|
@@ -2132,7 +2130,6 @@ function loadEncryptedSession(sessionKeyOption) {
|
|
|
2132
2130
|
}
|
|
2133
2131
|
verbose("Failed to decrypt session - using fresh browser");
|
|
2134
2132
|
}
|
|
2135
|
-
|
|
2136
2133
|
//#endregion
|
|
2137
2134
|
//#region src/sync/files.ts
|
|
2138
2135
|
/**
|
|
@@ -2170,7 +2167,6 @@ function deleteStaleFiles(outputDirectory, staleFiles) {
|
|
|
2170
2167
|
function findStaleFiles(existingFiles, writtenFiles) {
|
|
2171
2168
|
return existingFiles.filter((file) => !writtenFiles.has(file));
|
|
2172
2169
|
}
|
|
2173
|
-
|
|
2174
2170
|
//#endregion
|
|
2175
2171
|
//#region src/sync/staleFiles.ts
|
|
2176
2172
|
/**
|
|
@@ -2193,7 +2189,6 @@ function handleStaleFiles(outputDirectory, results, options) {
|
|
|
2193
2189
|
deleted
|
|
2194
2190
|
};
|
|
2195
2191
|
}
|
|
2196
|
-
|
|
2197
2192
|
//#endregion
|
|
2198
2193
|
//#region src/sync/sync.ts
|
|
2199
2194
|
/**
|
|
@@ -2204,9 +2199,9 @@ function handleStaleFiles(outputDirectory, results, options) {
|
|
|
2204
2199
|
* Execute screenshot capture (parallel or sequential based on workers).
|
|
2205
2200
|
*/
|
|
2206
2201
|
async function executeCapture(context) {
|
|
2207
|
-
const { screenshots, outputDirectory, captureOptions, browserOptions, schemes, workers, captureSpinner, progress } = context;
|
|
2202
|
+
const { screenshots, outputDirectory, captureOptions, browserOptions, schemes, locales, workers, captureSpinner, progress } = context;
|
|
2208
2203
|
if (workers > 1) return captureParallel({
|
|
2209
|
-
jobs: buildCaptureJobs(screenshots, schemes),
|
|
2204
|
+
jobs: buildCaptureJobs(screenshots, schemes, locales),
|
|
2210
2205
|
outputDirectory,
|
|
2211
2206
|
captureOptions,
|
|
2212
2207
|
browserOptions,
|
|
@@ -2216,7 +2211,8 @@ async function executeCapture(context) {
|
|
|
2216
2211
|
});
|
|
2217
2212
|
const results = [];
|
|
2218
2213
|
const schemesToCapture = schemes.length === 0 ? [void 0] : schemes;
|
|
2219
|
-
|
|
2214
|
+
const localesToCapture = locales.length === 0 ? [void 0] : locales;
|
|
2215
|
+
for (const locale of localesToCapture) for (const colorScheme of schemesToCapture) {
|
|
2220
2216
|
const schemeResults = await captureWithScheme({
|
|
2221
2217
|
screenshots,
|
|
2222
2218
|
outputDirectory,
|
|
@@ -2224,6 +2220,8 @@ async function executeCapture(context) {
|
|
|
2224
2220
|
browserOptions,
|
|
2225
2221
|
colorScheme,
|
|
2226
2222
|
schemes,
|
|
2223
|
+
locale,
|
|
2224
|
+
locales,
|
|
2227
2225
|
captureSpinner,
|
|
2228
2226
|
progress
|
|
2229
2227
|
});
|
|
@@ -2265,8 +2263,9 @@ async function sync(options = {}) {
|
|
|
2265
2263
|
const outputDirectory = resolveOutputDirectory(configPath, config.outputDirectory, options.outputDirectory);
|
|
2266
2264
|
const storageState = loadEncryptedSession(options.sessionKey);
|
|
2267
2265
|
const schemes = getColorSchemes(config.browser?.colorScheme);
|
|
2266
|
+
const locales = config.locales ?? [];
|
|
2268
2267
|
const captureOptions = buildCaptureOptions(config, options.viewportOnly);
|
|
2269
|
-
const totalToCapture = calculateTotalCaptures(screenshots, schemes.length);
|
|
2268
|
+
const totalToCapture = calculateTotalCaptures(screenshots, schemes.length, Math.max(1, locales.length));
|
|
2270
2269
|
const browserOptions = {
|
|
2271
2270
|
...buildBrowserOptions(config),
|
|
2272
2271
|
storageState,
|
|
@@ -2284,6 +2283,7 @@ async function sync(options = {}) {
|
|
|
2284
2283
|
captureOptions,
|
|
2285
2284
|
browserOptions,
|
|
2286
2285
|
schemes,
|
|
2286
|
+
locales,
|
|
2287
2287
|
workers,
|
|
2288
2288
|
captureSpinner,
|
|
2289
2289
|
progress: {
|
|
@@ -2310,7 +2310,6 @@ async function sync(options = {}) {
|
|
|
2310
2310
|
});
|
|
2311
2311
|
return showResults(results, outputDirectory, staleFiles, deletedFiles);
|
|
2312
2312
|
}
|
|
2313
|
-
|
|
2314
2313
|
//#endregion
|
|
2315
2314
|
//#region src/cli/snippet.ts
|
|
2316
2315
|
/**
|
|
@@ -2397,6 +2396,5 @@ function snippetAction(pattern, options, configPath) {
|
|
|
2397
2396
|
log$1("");
|
|
2398
2397
|
return true;
|
|
2399
2398
|
}
|
|
2400
|
-
|
|
2401
2399
|
//#endregion
|
|
2402
|
-
export { intro$1 as C, setVerbose as D, outro$1 as E, spinner$1 as O, error as S, note$1 as T, loadConfig as _, launchBrowser as a, screenshotSchema as b, generateSessionKey as c, loadSession as d, saveLocalKey as f, getConfigPath as g, ensureHeroshotDirectory as h, filterScreenshots as i, verbose as k, getSessionPath as l, sessionExists as m, snippetAction as n, DEFAULT_VIEWPORT as o, saveSession as p, sync as r, EDITOR_DIR as s, generateSnippets as t, loadLocalKey as u, saveConfig as v, log$1 as w, generateUid as x, VIEWPORT_PRESETS as y };
|
|
2400
|
+
export { intro$1 as C, setVerbose as D, outro$1 as E, spinner$1 as O, error as S, note$1 as T, loadConfig as _, launchBrowser as a, screenshotSchema as b, generateSessionKey as c, loadSession as d, saveLocalKey as f, getConfigPath as g, ensureHeroshotDirectory as h, filterScreenshots as i, verbose as k, getSessionPath as l, sessionExists as m, snippetAction as n, DEFAULT_VIEWPORT as o, saveSession as p, sync as r, EDITOR_DIR as s, generateSnippets as t, loadLocalKey as u, saveConfig as v, log$1 as w, generateUid as x, VIEWPORT_PRESETS as y };
|