@wasao/kagemusha 0.1.0 → 0.2.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 (96) hide show
  1. package/README.md +497 -58
  2. package/dist/commands/add.d.ts +6 -0
  3. package/dist/commands/add.d.ts.map +1 -0
  4. package/dist/commands/add.js +26 -0
  5. package/dist/commands/add.js.map +1 -0
  6. package/dist/commands/capture.d.ts +4 -2
  7. package/dist/commands/capture.d.ts.map +1 -1
  8. package/dist/commands/capture.js +236 -11
  9. package/dist/commands/capture.js.map +1 -1
  10. package/dist/commands/discover.d.ts +2 -0
  11. package/dist/commands/discover.d.ts.map +1 -0
  12. package/dist/commands/discover.js +62 -0
  13. package/dist/commands/discover.js.map +1 -0
  14. package/dist/commands/edit.d.ts +6 -0
  15. package/dist/commands/edit.d.ts.map +1 -0
  16. package/dist/commands/edit.js +120 -0
  17. package/dist/commands/edit.js.map +1 -0
  18. package/dist/commands/init.d.ts +1 -1
  19. package/dist/commands/init.d.ts.map +1 -1
  20. package/dist/commands/init.js +220 -118
  21. package/dist/commands/init.js.map +1 -1
  22. package/dist/commands/list.d.ts +2 -0
  23. package/dist/commands/list.d.ts.map +1 -0
  24. package/dist/commands/list.js +33 -0
  25. package/dist/commands/list.js.map +1 -0
  26. package/dist/commands/login.d.ts +6 -0
  27. package/dist/commands/login.d.ts.map +1 -0
  28. package/dist/commands/login.js +142 -0
  29. package/dist/commands/login.js.map +1 -0
  30. package/dist/commands/validate.js +1 -1
  31. package/dist/commands/validate.js.map +1 -1
  32. package/dist/editor/inject-script.d.ts +2 -0
  33. package/dist/editor/inject-script.d.ts.map +1 -0
  34. package/dist/editor/inject-script.js +768 -0
  35. package/dist/editor/inject-script.js.map +1 -0
  36. package/dist/index.js +32 -20
  37. package/dist/index.js.map +1 -1
  38. package/dist/lib/annotate.d.ts +2 -2
  39. package/dist/lib/annotate.d.ts.map +1 -1
  40. package/dist/lib/annotate.js +36 -44
  41. package/dist/lib/annotate.js.map +1 -1
  42. package/dist/lib/auth.d.ts +18 -0
  43. package/dist/lib/auth.d.ts.map +1 -0
  44. package/dist/lib/auth.js +45 -0
  45. package/dist/lib/auth.js.map +1 -0
  46. package/dist/lib/aws-error.d.ts +7 -0
  47. package/dist/lib/aws-error.d.ts.map +1 -0
  48. package/dist/lib/aws-error.js +74 -0
  49. package/dist/lib/aws-error.js.map +1 -0
  50. package/dist/lib/canonical.d.ts +22 -0
  51. package/dist/lib/canonical.d.ts.map +1 -0
  52. package/dist/lib/canonical.js +92 -0
  53. package/dist/lib/canonical.js.map +1 -0
  54. package/dist/lib/config.d.ts +2 -0
  55. package/dist/lib/config.d.ts.map +1 -1
  56. package/dist/lib/config.js +23 -13
  57. package/dist/lib/config.js.map +1 -1
  58. package/dist/lib/crawl.d.ts +1 -1
  59. package/dist/lib/crawl.d.ts.map +1 -1
  60. package/dist/lib/crawl.js +213 -20
  61. package/dist/lib/crawl.js.map +1 -1
  62. package/dist/lib/definition.d.ts +2 -0
  63. package/dist/lib/definition.d.ts.map +1 -0
  64. package/dist/lib/definition.js +6 -0
  65. package/dist/lib/definition.js.map +1 -0
  66. package/dist/lib/diff.d.ts +52 -0
  67. package/dist/lib/diff.d.ts.map +1 -0
  68. package/dist/lib/diff.js +41 -0
  69. package/dist/lib/diff.js.map +1 -0
  70. package/dist/lib/login-error.d.ts +10 -0
  71. package/dist/lib/login-error.d.ts.map +1 -0
  72. package/dist/lib/login-error.js +13 -0
  73. package/dist/lib/login-error.js.map +1 -0
  74. package/dist/lib/screenshot.d.ts +8 -2
  75. package/dist/lib/screenshot.d.ts.map +1 -1
  76. package/dist/lib/screenshot.js +44 -61
  77. package/dist/lib/screenshot.js.map +1 -1
  78. package/dist/lib/staging.d.ts +8 -0
  79. package/dist/lib/staging.d.ts.map +1 -0
  80. package/dist/lib/staging.js +24 -0
  81. package/dist/lib/staging.js.map +1 -0
  82. package/dist/types.d.ts +5 -23
  83. package/dist/types.d.ts.map +1 -1
  84. package/package.json +18 -11
  85. package/dist/commands/preview.d.ts +0 -6
  86. package/dist/commands/preview.d.ts.map +0 -1
  87. package/dist/commands/preview.js +0 -33
  88. package/dist/commands/preview.js.map +0 -1
  89. package/dist/commands/run.d.ts +0 -6
  90. package/dist/commands/run.d.ts.map +0 -1
  91. package/dist/commands/run.js +0 -39
  92. package/dist/commands/run.js.map +0 -1
  93. package/dist/lib/upload.d.ts +0 -9
  94. package/dist/lib/upload.d.ts.map +0 -1
  95. package/dist/lib/upload.js +0 -43
  96. package/dist/lib/upload.js.map +0 -1
@@ -0,0 +1,92 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { GetObjectCommand, NoSuchKey, PutObjectCommand, S3Client, } from "@aws-sdk/client-s3";
4
+ const DEFAULT_OUTPUT_DIR = "screenshots";
5
+ export const getOutputDir = (config, projectRoot) => {
6
+ const configured = config.publish?.outputDir ?? DEFAULT_OUTPUT_DIR;
7
+ return path.isAbsolute(configured)
8
+ ? configured
9
+ : path.join(projectRoot, configured);
10
+ };
11
+ export const getCanonicalPath = (config, projectRoot, id) => path.join(getOutputDir(config, projectRoot), `${id}.png`);
12
+ // Extract AWS region from a virtual-hosted–style S3 URL or s3.<region>.amazonaws.com endpoint.
13
+ // Returns undefined for legacy global URLs (s3.amazonaws.com) or custom CDN domains.
14
+ const extractRegionFromCdnBase = (cdnBaseUrl) => {
15
+ if (!cdnBaseUrl)
16
+ return undefined;
17
+ const m = cdnBaseUrl.match(/\.s3[.-]([a-z0-9-]+)\.amazonaws\.com/i);
18
+ return m?.[1];
19
+ };
20
+ /**
21
+ * S3-backed canonical store.
22
+ * Local mode has no remote — outputDir itself is the source of truth.
23
+ */
24
+ export class S3Canonical {
25
+ bucket;
26
+ cdnBaseUrl;
27
+ client;
28
+ constructor(bucket, cdnBaseUrl) {
29
+ this.bucket = bucket;
30
+ this.cdnBaseUrl = cdnBaseUrl;
31
+ const region = extractRegionFromCdnBase(cdnBaseUrl);
32
+ this.client = new S3Client(region ? { region } : {});
33
+ }
34
+ keyOf(id) {
35
+ return `${id}/latest.png`;
36
+ }
37
+ /** Download canonical for `id` to `localPath`. Returns "not-found" if absent. */
38
+ async fetch(id, localPath) {
39
+ try {
40
+ const res = await this.client.send(new GetObjectCommand({ Bucket: this.bucket, Key: this.keyOf(id) }));
41
+ const bytes = await res.Body?.transformToByteArray();
42
+ if (!bytes)
43
+ return "not-found";
44
+ fs.mkdirSync(path.dirname(localPath), { recursive: true });
45
+ fs.writeFileSync(localPath, bytes);
46
+ return "ok";
47
+ }
48
+ catch (e) {
49
+ if (e instanceof NoSuchKey)
50
+ return "not-found";
51
+ if (e?.name === "NoSuchKey")
52
+ return "not-found";
53
+ if (e?.Code === "NoSuchKey")
54
+ return "not-found";
55
+ throw e;
56
+ }
57
+ }
58
+ /** Upload `localPath` as the canonical for `id`. */
59
+ async push(id, localPath) {
60
+ const body = fs.readFileSync(localPath);
61
+ await this.client.send(new PutObjectCommand({
62
+ Bucket: this.bucket,
63
+ Key: this.keyOf(id),
64
+ Body: body,
65
+ ContentType: "image/png",
66
+ CacheControl: "no-cache",
67
+ }));
68
+ // History snapshot for debug / rollback. Replace `:` so the key works
69
+ // in URLs without %3A encoding (S3 accepts it but URL-embedding breaks).
70
+ const timestamp = new Date().toISOString().replaceAll(":", "-");
71
+ const historyKey = `${id}/${timestamp}.png`;
72
+ await this.client.send(new PutObjectCommand({
73
+ Bucket: this.bucket,
74
+ Key: historyKey,
75
+ Body: body,
76
+ ContentType: "image/png",
77
+ }));
78
+ }
79
+ label() {
80
+ return this.cdnBaseUrl ?? `s3://${this.bucket}`;
81
+ }
82
+ }
83
+ export const createS3Canonical = (config) => {
84
+ const publish = config.publish;
85
+ if (publish?.destination !== "s3")
86
+ return null;
87
+ if (!publish.cdnBucket) {
88
+ throw new Error("publish.cdnBucket is required for s3 destination");
89
+ }
90
+ return new S3Canonical(publish.cdnBucket, publish.cdnBaseUrl);
91
+ };
92
+ //# sourceMappingURL=canonical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/lib/canonical.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
1
  import type { KagemushaConfig, Route, ScreenshotDefinition } from "../types.js";
2
2
  export declare function findProjectRoot(startDir?: string): string;
3
3
  export declare function loadConfig(projectRoot?: string): KagemushaConfig;
4
+ export declare function getDefinitionsPath(projectRoot?: string): string;
4
5
  export declare function loadDefinitions(projectRoot?: string): ScreenshotDefinition[];
6
+ export declare function saveDefinitions(definitions: ScreenshotDefinition[], projectRoot?: string): void;
5
7
  export declare function loadRouting(projectRoot?: string): Route[];
6
8
  export declare function loadDefinitionById(id: string, projectRoot?: string): ScreenshotDefinition | undefined;
7
9
  export declare function validateConfig(config: KagemushaConfig): string[];
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAMhF,wBAAgB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAWxE;AAED,wBAAgB,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,eAAe,CAYhE;AAED,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAa5E;AAED,wBAAgB,WAAW,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,EAAE,CAWzD;AAED,wBAAgB,kBAAkB,CACjC,EAAE,EAAE,MAAM,EACV,WAAW,CAAC,EAAE,MAAM,GAClB,oBAAoB,GAAG,SAAS,CAGlC;AAkBD,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,EAAE,CAWhE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,oBAAoB,GAAG,MAAM,EAAE,CActE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAMhF,wBAAgB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAWxE;AAED,wBAAgB,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,eAAe,CAYhE;AAED,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAS5E;AAED,wBAAgB,eAAe,CAC9B,WAAW,EAAE,oBAAoB,EAAE,EACnC,WAAW,CAAC,EAAE,MAAM,GAClB,IAAI,CAIN;AAED,wBAAgB,WAAW,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,EAAE,CAWzD;AAED,wBAAgB,kBAAkB,CACjC,EAAE,EAAE,MAAM,EACV,WAAW,CAAC,EAAE,MAAM,GAClB,oBAAoB,GAAG,SAAS,CAGlC;AA0BD,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,EAAE,CAWhE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAWtE"}
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { parse as parseYaml } from "yaml";
4
4
  const CONFIG_FILENAME = "kagemusha.config.yaml";
5
- const DEFINITIONS_DIR = ".kagemusha/definitions";
5
+ const DEFINITIONS_FILE = ".kagemusha/definitions.json";
6
6
  const ROUTING_FILENAME = ".kagemusha/routing.yaml";
7
7
  export function findProjectRoot(startDir = process.cwd()) {
8
8
  let dir = startDir;
@@ -25,17 +25,22 @@ export function loadConfig(projectRoot) {
25
25
  resolveEnvVars(config);
26
26
  return config;
27
27
  }
28
- export function loadDefinitions(projectRoot) {
28
+ export function getDefinitionsPath(projectRoot) {
29
29
  const root = projectRoot ?? findProjectRoot();
30
- const defsDir = path.join(root, DEFINITIONS_DIR);
31
- if (!fs.existsSync(defsDir)) {
30
+ return path.join(root, DEFINITIONS_FILE);
31
+ }
32
+ export function loadDefinitions(projectRoot) {
33
+ const defsPath = getDefinitionsPath(projectRoot);
34
+ if (!fs.existsSync(defsPath)) {
32
35
  return [];
33
36
  }
34
- const files = fs.readdirSync(defsDir).filter((f) => f.endsWith(".json"));
35
- return files.map((file) => {
36
- const content = fs.readFileSync(path.join(defsDir, file), "utf-8");
37
- return JSON.parse(content);
38
- });
37
+ const content = fs.readFileSync(defsPath, "utf-8");
38
+ return JSON.parse(content);
39
+ }
40
+ export function saveDefinitions(definitions, projectRoot) {
41
+ const defsPath = getDefinitionsPath(projectRoot);
42
+ fs.mkdirSync(path.dirname(defsPath), { recursive: true });
43
+ fs.writeFileSync(defsPath, `${JSON.stringify(definitions, null, 2)}\n`);
39
44
  }
40
45
  export function loadRouting(projectRoot) {
41
46
  const root = projectRoot ?? findProjectRoot();
@@ -57,7 +62,13 @@ function resolveEnvVars(obj) {
57
62
  if (typeof obj === "object") {
58
63
  for (const [key, value] of Object.entries(obj)) {
59
64
  if (typeof value === "string") {
60
- obj[key] = value.replace(/\$\{(\w+)\}/g, (_, envVar) => process.env[envVar] ?? "");
65
+ obj[key] = value.replace(/\$\{(\w+)\}/g, (_, envVar) => {
66
+ const v = process.env[envVar];
67
+ if (v === undefined) {
68
+ throw new Error(`Environment variable \${${envVar}} is referenced in kagemusha.config.yaml but not set.`);
69
+ }
70
+ return v;
71
+ });
61
72
  }
62
73
  else if (typeof value === "object") {
63
74
  resolveEnvVars(value);
@@ -83,9 +94,8 @@ export function validateDefinition(def) {
83
94
  errors.push("url is required");
84
95
  if (!def.capture)
85
96
  errors.push("capture is required");
86
- if (def.capture &&
87
- !["fullPage", "selector", "crop"].includes(def.capture.mode)) {
88
- errors.push(`capture.mode must be "fullPage", "selector", or "crop"`);
97
+ if (def.capture && !["fullPage", "crop"].includes(def.capture.mode)) {
98
+ errors.push(`capture.mode must be "fullPage" or "crop"`);
89
99
  }
90
100
  return errors;
91
101
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -2,5 +2,5 @@ export interface DiscoveredPage {
2
2
  path: string;
3
3
  title: string;
4
4
  }
5
- export declare function discoverPages(baseUrl: string, maxDepth?: number, maxPages?: number): Promise<DiscoveredPage[]>;
5
+ export declare const discoverPages: (baseUrl: string, projectRoot?: string, maxDepth?: number, maxPages?: number) => Promise<DiscoveredPage[]>;
6
6
  //# sourceMappingURL=crawl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"crawl.d.ts","sourceRoot":"","sources":["../../src/lib/crawl.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,aAAa,CAClC,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAAU,EACpB,QAAQ,GAAE,MAAW,GACnB,OAAO,CAAC,cAAc,EAAE,CAAC,CAqD3B"}
1
+ {"version":3,"file":"crawl.d.ts","sourceRoot":"","sources":["../../src/lib/crawl.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,aAAa,GACzB,SAAS,MAAM,EACf,cAAc,MAAM,EACpB,iBAAY,EACZ,iBAAc,KACZ,OAAO,CAAC,cAAc,EAAE,CA6L1B,CAAC"}
package/dist/lib/crawl.js CHANGED
@@ -1,12 +1,101 @@
1
- export async function discoverPages(baseUrl, maxDepth = 2, maxPages = 50) {
1
+ import fs from "node:fs";
2
+ import chalk from "chalk";
3
+ import { authContextOptions, getAuthMetaPath } from "./auth.js";
4
+ export const discoverPages = async (baseUrl, projectRoot, maxDepth = 3, maxPages = 200) => {
2
5
  const { chromium } = await import("playwright-chromium");
3
6
  const browser = await chromium.launch({ headless: true });
4
- const context = await browser.newContext();
7
+ const context = await browser.newContext(authContextOptions(projectRoot));
5
8
  const origin = new URL(baseUrl).origin;
6
9
  const visited = new Set();
7
10
  const results = [];
8
- const queue = [{ url: baseUrl, depth: 0 }];
11
+ const metaPath = projectRoot ? getAuthMetaPath(projectRoot) : "";
12
+ let startUrl = baseUrl;
13
+ let loginPath = "";
14
+ if (metaPath && fs.existsSync(metaPath)) {
15
+ const meta = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
16
+ if (meta.loginPath) {
17
+ loginPath = meta.loginPath;
18
+ const loginUrl = new URL(meta.loginPath, baseUrl).toString();
19
+ results.push({ path: meta.loginPath, title: "Login" });
20
+ visited.add(normalizeUrl(loginUrl, origin) ?? loginUrl);
21
+ }
22
+ if (meta.landingPath) {
23
+ startUrl = new URL(meta.landingPath, baseUrl).toString();
24
+ }
25
+ }
26
+ const seenPatterns = new Set();
9
27
  try {
28
+ // Phase 1: Click nav elements on start page to discover SPA routes
29
+ console.log(chalk.gray(" Phase 1: Clicking navigation elements...\n"));
30
+ const navUrls = await discoverByClicking(context, startUrl, origin, loginPath);
31
+ // Add start page
32
+ const startNorm = normalizeUrl(startUrl, origin);
33
+ if (startNorm) {
34
+ const startPattern = toPattern(new URL(startNorm).pathname);
35
+ seenPatterns.add(startPattern);
36
+ visited.add(startNorm);
37
+ }
38
+ // Queue nav-discovered URLs for BFS
39
+ const queue = [];
40
+ for (const url of navUrls) {
41
+ const norm = normalizeUrl(url, origin);
42
+ if (!norm || visited.has(norm))
43
+ continue;
44
+ const pat = toPattern(new URL(norm).pathname);
45
+ if (seenPatterns.has(pat))
46
+ continue;
47
+ queue.push({ url: norm, depth: 1 });
48
+ }
49
+ // Also queue startUrl for link collection
50
+ if (startNorm && !visited.has(startNorm)) {
51
+ queue.unshift({ url: startNorm, depth: 0 });
52
+ }
53
+ // Add start page to results
54
+ const startPage = await context.newPage();
55
+ let sessionExpired = false;
56
+ try {
57
+ await startPage.goto(startUrl, {
58
+ waitUntil: "networkidle",
59
+ timeout: 60000,
60
+ });
61
+ const title = await startPage.title();
62
+ const pagePath = new URL(startPage.url()).pathname;
63
+ // Detect expired session
64
+ if (loginPath && pagePath === loginPath) {
65
+ console.log(chalk.yellow(`\n⚠ Redirected to ${loginPath} — session expired? Run "kagemusha login" first.\n`));
66
+ sessionExpired = true;
67
+ }
68
+ else {
69
+ const startPattern = toPattern(pagePath);
70
+ seenPatterns.add(startPattern);
71
+ results.push({ path: pagePath, title: title || pagePath });
72
+ console.log(chalk.gray(` ${pagePath}`) +
73
+ ` ${chalk.green("✓")} ${chalk.white(title)}`);
74
+ // Collect <a href> links from start page
75
+ const links = await collectLinks(startPage, origin);
76
+ for (const link of links) {
77
+ if (visited.has(link))
78
+ continue;
79
+ const linkPattern = toPattern(new URL(link).pathname);
80
+ if (seenPatterns.has(linkPattern))
81
+ continue;
82
+ queue.push({ url: link, depth: 1 });
83
+ }
84
+ }
85
+ }
86
+ catch (e) {
87
+ console.log(chalk.yellow(`\n⚠ Start page failed: ${e instanceof Error ? e.message : e}. Continuing with nav-discovered URLs.\n`));
88
+ }
89
+ finally {
90
+ await startPage.close().catch(() => { });
91
+ }
92
+ if (sessionExpired) {
93
+ return results;
94
+ }
95
+ // Phase 2: BFS crawl from discovered URLs
96
+ if (queue.length > 0) {
97
+ console.log(chalk.gray(`\n Phase 2: Crawling ${queue.length} discovered URLs...\n`));
98
+ }
10
99
  while (queue.length > 0 && results.length < maxPages) {
11
100
  const item = queue.shift();
12
101
  if (!item)
@@ -14,15 +103,29 @@ export async function discoverPages(baseUrl, maxDepth = 2, maxPages = 50) {
14
103
  const normalized = normalizeUrl(item.url, origin);
15
104
  if (!normalized || visited.has(normalized))
16
105
  continue;
106
+ const pattern = toPattern(new URL(normalized).pathname);
107
+ if (seenPatterns.has(pattern))
108
+ continue;
109
+ seenPatterns.add(pattern);
17
110
  visited.add(normalized);
111
+ const urlPath = new URL(normalized).pathname;
112
+ process.stdout.write(chalk.gray(` ${urlPath}`));
113
+ const page = await context.newPage();
18
114
  try {
19
- const page = await context.newPage();
20
115
  await page.goto(normalized, {
21
- waitUntil: "domcontentloaded",
22
- timeout: 10000,
116
+ waitUntil: "networkidle",
117
+ timeout: 60000,
23
118
  });
24
119
  const title = await page.title();
25
120
  const pagePath = new URL(page.url()).pathname;
121
+ // Skip if redirected to a known pattern
122
+ const finalPattern = toPattern(pagePath);
123
+ if (finalPattern !== pattern && seenPatterns.has(finalPattern)) {
124
+ process.stdout.write(chalk.gray(" (skip)\n"));
125
+ continue;
126
+ }
127
+ seenPatterns.add(finalPattern);
128
+ process.stdout.write(` ${chalk.green("✓")} ${chalk.white(title)}\n`);
26
129
  results.push({
27
130
  path: pagePath,
28
131
  title: title || pagePath,
@@ -30,36 +133,128 @@ export async function discoverPages(baseUrl, maxDepth = 2, maxPages = 50) {
30
133
  if (item.depth < maxDepth) {
31
134
  const links = await collectLinks(page, origin);
32
135
  for (const link of links) {
33
- if (!visited.has(link)) {
34
- queue.push({ url: link, depth: item.depth + 1 });
35
- }
136
+ if (visited.has(link))
137
+ continue;
138
+ const linkPattern = toPattern(new URL(link).pathname);
139
+ if (seenPatterns.has(linkPattern))
140
+ continue;
141
+ queue.push({ url: link, depth: item.depth + 1 });
36
142
  }
37
143
  }
38
- await page.close();
39
144
  }
40
145
  catch {
41
- // Skip pages that fail to load
146
+ process.stdout.write(chalk.yellow(" (timeout, skip)\n"));
147
+ }
148
+ finally {
149
+ await page.close().catch(() => { });
42
150
  }
43
151
  }
152
+ if (results.length >= maxPages) {
153
+ console.log(chalk.gray(`\n Reached max ${maxPages} pages, stopping.\n`));
154
+ }
44
155
  }
45
156
  finally {
46
157
  await browser.close();
47
158
  }
48
159
  return results;
49
- }
50
- async function collectLinks(page, origin) {
160
+ };
161
+ // Click nav/sidebar link elements and collect URLs they navigate to.
162
+ // We collect accessible names (text || aria-label) up front, then re-resolve
163
+ // each label by name on every iteration so SPA re-renders don't cause us
164
+ // to click the wrong element.
165
+ const discoverByClicking = async (context, startUrl, origin, loginPath) => {
166
+ const page = await context.newPage();
167
+ try {
168
+ await page.goto(startUrl, { waitUntil: "networkidle", timeout: 60000 });
169
+ // Check if redirected to login
170
+ if (loginPath && new URL(page.url()).pathname === loginPath) {
171
+ return [];
172
+ }
173
+ // Collect accessible labels for nav links first, then page-wide links.
174
+ const candidates = [];
175
+ const seen = new Set();
176
+ // Use accessible name (text || aria-label) so getByRole({ name }) can
177
+ // resolve the element again on click. Other attributes don't participate
178
+ // in accessible name and would be unreachable.
179
+ const collectLabels = async (locator, preferNav) => {
180
+ const count = await locator.count();
181
+ for (let i = 0; i < count; i++) {
182
+ const el = locator.nth(i);
183
+ let name = ((await el.textContent().catch(() => null)) ?? "").trim();
184
+ if (!name) {
185
+ name = ((await el.getAttribute("aria-label").catch(() => null)) ?? "").trim();
186
+ }
187
+ if (!name || seen.has(name))
188
+ continue;
189
+ seen.add(name);
190
+ candidates.push({ name, preferNav });
191
+ }
192
+ };
193
+ await collectLabels(page.getByRole("navigation").getByRole("link"), true);
194
+ await collectLabels(page.getByRole("link"), false);
195
+ console.log(chalk.gray(` Found ${candidates.length} link label(s) to try\n`));
196
+ const discoveredUrls = [];
197
+ for (const { name, preferNav } of candidates) {
198
+ try {
199
+ const root = preferNav
200
+ ? page
201
+ .getByRole("navigation")
202
+ .getByRole("link", { name, exact: true })
203
+ : page.getByRole("link", { name, exact: true });
204
+ const el = root.first();
205
+ if (!(await el.isVisible().catch(() => false)))
206
+ continue;
207
+ const beforeUrl = page.url();
208
+ await el.click({ timeout: 3000 });
209
+ await page
210
+ .waitForLoadState("networkidle", { timeout: 5000 })
211
+ .catch(() => { });
212
+ await page.waitForTimeout(500);
213
+ const afterUrl = page.url();
214
+ if (afterUrl !== beforeUrl && new URL(afterUrl).origin === origin) {
215
+ const afterPath = new URL(afterUrl).pathname;
216
+ if (afterPath !== loginPath) {
217
+ discoveredUrls.push(afterUrl);
218
+ console.log(chalk.green(` + ${afterPath}`) + chalk.gray(` ${name}`));
219
+ }
220
+ await page.goto(startUrl, {
221
+ waitUntil: "networkidle",
222
+ timeout: 10000,
223
+ });
224
+ }
225
+ }
226
+ catch {
227
+ // Skip elements that can't be clicked or text didn't resolve
228
+ }
229
+ }
230
+ return discoveredUrls;
231
+ }
232
+ finally {
233
+ await page.close().catch(() => { });
234
+ }
235
+ };
236
+ // Replace numeric IDs, UUIDs, and hex strings with * to detect same-structure URLs
237
+ const toPattern = (pathname) => pathname
238
+ .split("/")
239
+ .map((seg) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(seg)
240
+ ? "*"
241
+ : /^\d+$/.test(seg)
242
+ ? "*"
243
+ : /^[0-9a-f]{8,}$/i.test(seg)
244
+ ? "*"
245
+ : seg)
246
+ .join("/");
247
+ const collectLinks = async (page, origin) => {
51
248
  const hrefs = await page.evaluate(() => Array.from(document.querySelectorAll("a[href]")).map((a) => a.href));
52
249
  return hrefs
53
250
  .map((href) => normalizeUrl(href, origin))
54
251
  .filter((url) => url !== null);
55
- }
56
- function normalizeUrl(url, origin) {
252
+ };
253
+ const normalizeUrl = (url, origin) => {
57
254
  try {
58
255
  const parsed = new URL(url, origin);
59
- // Same origin only
60
256
  if (parsed.origin !== origin)
61
257
  return null;
62
- // Skip non-page resources
63
258
  const skip = [
64
259
  ".js",
65
260
  ".css",
@@ -80,10 +275,8 @@ function normalizeUrl(url, origin) {
80
275
  ];
81
276
  if (skip.some((ext) => parsed.pathname.endsWith(ext)))
82
277
  return null;
83
- // Skip anchors and mailto
84
278
  if (url.startsWith("mailto:") || url.startsWith("tel:"))
85
279
  return null;
86
- // Remove hash and search params for deduplication
87
280
  parsed.hash = "";
88
281
  parsed.search = "";
89
282
  return parsed.toString();
@@ -91,5 +284,5 @@ function normalizeUrl(url, origin) {
91
284
  catch {
92
285
  return null;
93
286
  }
94
- }
287
+ };
95
288
  //# sourceMappingURL=crawl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"crawl.js","sourceRoot":"","sources":["../../src/lib/crawl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"crawl.js","sourceRoot":"","sources":["../../src/lib/crawl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const deriveIdFromPath: (urlPath: string) => string;
2
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/lib/definition.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,KAAG,MAKT,CAAC"}
@@ -0,0 +1,6 @@
1
+ export const deriveIdFromPath = (urlPath) => urlPath
2
+ .replace(/^\//, "")
3
+ .replace(/\.\w+$/, "")
4
+ .replace(/[/\\]/g, "-")
5
+ .replace(/[^a-zA-Z0-9-]/g, "") || "page";
6
+ //# sourceMappingURL=definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.js","sourceRoot":"","sources":["../../src/lib/definition.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAU,EAAE,CAC3D,OAAO;KACL,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;KAClB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;KACrB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;KACtB,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC"}
@@ -0,0 +1,52 @@
1
+ export interface Dimensions {
2
+ width: number;
3
+ height: number;
4
+ }
5
+ export type DiffStatus = {
6
+ id: string;
7
+ status: "unchanged";
8
+ } | {
9
+ id: string;
10
+ status: "new";
11
+ } | {
12
+ id: string;
13
+ status: "missing";
14
+ reason?: string;
15
+ } | {
16
+ id: string;
17
+ status: "changed";
18
+ reason: "pixel-diff";
19
+ diffPercentage: number;
20
+ diffPath: string;
21
+ } | {
22
+ id: string;
23
+ status: "changed";
24
+ reason: "layout-diff";
25
+ canonical: Dimensions;
26
+ staging: Dimensions;
27
+ };
28
+ export interface DiffOptions {
29
+ /** Color difference threshold per pixel (0-1). Lower = stricter. Default 0.1 */
30
+ pixelThreshold?: number;
31
+ /** Ignore anti-aliased pixels (treat them as equal). Default true */
32
+ ignoreAntiAliasing?: boolean;
33
+ }
34
+ export type DiffResult = {
35
+ match: true;
36
+ } | {
37
+ match: false;
38
+ reason: "layout-diff";
39
+ canonical: Dimensions;
40
+ staging: Dimensions;
41
+ } | {
42
+ match: false;
43
+ reason: "pixel-diff";
44
+ diffCount: number;
45
+ diffPercentage: number;
46
+ };
47
+ /**
48
+ * Compare two PNG files using pixelmatch and write the diff visualization.
49
+ * If dimensions differ, returns layout-diff without writing a diff image.
50
+ */
51
+ export declare const diffImages: (baseline: string, current: string, diffPath: string, options?: DiffOptions) => Promise<DiffResult>;
52
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/lib/diff.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,UAAU,GACnB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACnC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD;IACA,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAChB,GACD;IACA,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,UAAU,CAAC;IACtB,OAAO,EAAE,UAAU,CAAC;CACnB,CAAC;AAEL,MAAM,WAAW,WAAW;IAC3B,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,MAAM,UAAU,GACnB;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IACA,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,UAAU,CAAC;IACtB,OAAO,EAAE,UAAU,CAAC;CACnB,GACD;IACA,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACtB,CAAC;AAKL;;;GAGG;AACH,eAAO,MAAM,UAAU,GACtB,UAAU,MAAM,EAChB,SAAS,MAAM,EACf,UAAU,MAAM,EAChB,UAAS,WAAgB,KACvB,OAAO,CAAC,UAAU,CAoCpB,CAAC"}