mcp-scraper 0.3.46 → 0.4.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 (50) hide show
  1. package/dist/bin/api-server.cjs +2800 -346
  2. package/dist/bin/api-server.cjs.map +1 -1
  3. package/dist/bin/api-server.js +2 -2
  4. package/dist/bin/mcp-scraper-cli.cjs +1 -1
  5. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  6. package/dist/bin/mcp-scraper-cli.js +3 -3
  7. package/dist/bin/mcp-scraper-install.cjs +1 -1
  8. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  9. package/dist/bin/mcp-scraper-install.js +1 -1
  10. package/dist/bin/mcp-stdio-server.cjs +2100 -23
  11. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  12. package/dist/bin/mcp-stdio-server.js +9 -4
  13. package/dist/bin/mcp-stdio-server.js.map +1 -1
  14. package/dist/bin/paa-harvest.js +3 -2
  15. package/dist/bin/paa-harvest.js.map +1 -1
  16. package/dist/{chunk-SS5YBZVI.js → chunk-3NIPPJGP.js} +2184 -514
  17. package/dist/chunk-3NIPPJGP.js.map +1 -0
  18. package/dist/chunk-3UH3BEIZ.js +158 -0
  19. package/dist/chunk-3UH3BEIZ.js.map +1 -0
  20. package/dist/{chunk-BRVX6RDN.js → chunk-6TDUY7CA.js} +5 -159
  21. package/dist/chunk-6TDUY7CA.js.map +1 -0
  22. package/dist/chunk-GWRIO6JT.js +419 -0
  23. package/dist/chunk-GWRIO6JT.js.map +1 -0
  24. package/dist/{chunk-RXNHY3TF.js → chunk-HBC4C75S.js} +11 -9
  25. package/dist/{chunk-RXNHY3TF.js.map → chunk-HBC4C75S.js.map} +1 -1
  26. package/dist/chunk-HPV4VOQX.js +27 -0
  27. package/dist/chunk-HPV4VOQX.js.map +1 -0
  28. package/dist/chunk-IXDYL7TE.js +7 -0
  29. package/dist/chunk-IXDYL7TE.js.map +1 -0
  30. package/dist/chunk-JOEZJL4I.js +130 -0
  31. package/dist/chunk-JOEZJL4I.js.map +1 -0
  32. package/dist/{chunk-3PRO376E.js → chunk-M2S27J6Z.js} +1 -25
  33. package/dist/chunk-M2S27J6Z.js.map +1 -0
  34. package/dist/extract-bundle-UKE273TV.js +276 -0
  35. package/dist/extract-bundle-UKE273TV.js.map +1 -0
  36. package/dist/index.js +3 -2
  37. package/dist/index.js.map +1 -1
  38. package/dist/{server-MGE3GYJW.js → server-Z4WKTE6F.js} +169 -195
  39. package/dist/server-Z4WKTE6F.js.map +1 -0
  40. package/dist/site-extract-repository-2MQBAOX5.js +30 -0
  41. package/dist/site-extract-repository-2MQBAOX5.js.map +1 -0
  42. package/dist/{worker-4CVMSUZR.js → worker-RVZXIALX.js} +8 -5
  43. package/dist/{worker-4CVMSUZR.js.map → worker-RVZXIALX.js.map} +1 -1
  44. package/package.json +2 -1
  45. package/dist/chunk-3PRO376E.js.map +0 -1
  46. package/dist/chunk-BRVX6RDN.js.map +0 -1
  47. package/dist/chunk-SS5YBZVI.js.map +0 -1
  48. package/dist/chunk-WT6OT2T3.js +0 -7
  49. package/dist/chunk-WT6OT2T3.js.map +0 -1
  50. package/dist/server-MGE3GYJW.js.map +0 -1
@@ -0,0 +1,419 @@
1
+ // src/api/seo-link-report.ts
2
+ function registrableDomain(host) {
3
+ const h = host.replace(/^www\./, "").toLowerCase();
4
+ const parts = h.split(".");
5
+ return parts.length <= 2 ? h : parts.slice(-2).join(".");
6
+ }
7
+ function buildLinkReport(edges, metrics, siteUrl) {
8
+ let siteReg = "";
9
+ try {
10
+ siteReg = registrableDomain(new URL(siteUrl).hostname);
11
+ } catch {
12
+ siteReg = "";
13
+ }
14
+ const internalEdges = edges.filter((e) => e.internal);
15
+ const pages = metrics.length;
16
+ const orphans = metrics.filter((m) => m.orphan).length;
17
+ const brokenInternal = internalEdges.filter((e) => e.targetStatus != null && e.targetStatus >= 400).length;
18
+ const sumInlinks = metrics.reduce((a, m) => a + m.inlinks, 0);
19
+ const sumOutlinks = metrics.reduce((a, m) => a + m.outlinksInternal + m.outlinksExternal, 0);
20
+ const distribution = { zero: 0, oneToTwo: 0, threeToTen: 0, elevenPlus: 0 };
21
+ for (const m of metrics) {
22
+ if (m.inlinks === 0) distribution.zero++;
23
+ else if (m.inlinks <= 2) distribution.oneToTwo++;
24
+ else if (m.inlinks <= 10) distribution.threeToTen++;
25
+ else distribution.elevenPlus++;
26
+ }
27
+ const topByInlinks = [...metrics].sort((a, b) => b.inlinks - a.inlinks).slice(0, 20).map((m) => ({ url: m.url, inlinks: m.inlinks, outlinksInternal: m.outlinksInternal, outlinksExternal: m.outlinksExternal }));
28
+ const domMap = /* @__PURE__ */ new Map();
29
+ let externalTotal = 0;
30
+ for (const e of edges) {
31
+ let domain;
32
+ try {
33
+ domain = registrableDomain(new URL(e.to).hostname);
34
+ } catch {
35
+ continue;
36
+ }
37
+ if (!domain || domain === siteReg) continue;
38
+ externalTotal++;
39
+ const d = domMap.get(domain) ?? { links: 0, nofollow: 0, pages: /* @__PURE__ */ new Set() };
40
+ d.links++;
41
+ if (e.nofollow) d.nofollow++;
42
+ d.pages.add(e.from);
43
+ domMap.set(domain, d);
44
+ }
45
+ const externalDomains = [...domMap.entries()].map(([domain, d]) => ({ domain, links: d.links, nofollow: d.nofollow, pages: d.pages.size })).sort((a, b) => b.links - a.links);
46
+ const round = (n) => Math.round(n * 10) / 10;
47
+ return {
48
+ summary: {
49
+ internal: {
50
+ totalLinks: internalEdges.length,
51
+ pages,
52
+ orphans,
53
+ brokenInternal,
54
+ avgInlinks: pages ? round(sumInlinks / pages) : 0,
55
+ avgOutlinks: pages ? round(sumOutlinks / pages) : 0,
56
+ distribution,
57
+ topByInlinks
58
+ },
59
+ external: {
60
+ totalLinks: externalTotal,
61
+ uniqueDomains: externalDomains.length,
62
+ topDomains: externalDomains.slice(0, 20)
63
+ }
64
+ },
65
+ externalDomains
66
+ };
67
+ }
68
+ function renderLinkReport(r) {
69
+ const s = r.summary;
70
+ const lines = [
71
+ `## Link analysis`,
72
+ `**Internal:** ${s.internal.totalLinks} links \xB7 ${s.internal.pages} pages \xB7 avg ${s.internal.avgInlinks} inlinks/page \xB7 ${s.internal.orphans} orphans \xB7 ${s.internal.brokenInternal} broken`,
73
+ `**External:** ${s.external.totalLinks} links to ${s.external.uniqueDomains} domains`,
74
+ ``,
75
+ `### Inlink distribution`,
76
+ `- 0 inlinks (orphans): ${s.internal.distribution.zero}`,
77
+ `- 1\u20132: ${s.internal.distribution.oneToTwo}`,
78
+ `- 3\u201310: ${s.internal.distribution.threeToTen}`,
79
+ `- 11+: ${s.internal.distribution.elevenPlus}`,
80
+ ``,
81
+ `### Top 20 internal pages by inlinks`,
82
+ `| inlinks | out (int/ext) | URL |`,
83
+ `|---|---|---|`,
84
+ ...s.internal.topByInlinks.map((p) => `| ${p.inlinks} | ${p.outlinksInternal}/${p.outlinksExternal} | ${p.url} |`),
85
+ ``,
86
+ `### Top 20 external domains by links`,
87
+ `| links | nofollow | from pages | domain |`,
88
+ `|---|---|---|---|`,
89
+ ...s.external.topDomains.map((d) => `| ${d.links} | ${d.nofollow} | ${d.pages} | ${d.domain} |`)
90
+ ];
91
+ return lines.join("\n");
92
+ }
93
+
94
+ // src/api/seo-issues.ts
95
+ var THIN_WORDS = 200;
96
+ var TITLE_MAX = 60;
97
+ var TITLE_PX_MAX = 561;
98
+ var TITLE_MIN = 30;
99
+ var META_MAX = 155;
100
+ var META_MIN = 70;
101
+ var H1_MAX = 70;
102
+ var URL_MAX = 115;
103
+ function dupes(pages, key) {
104
+ const groups = /* @__PURE__ */ new Map();
105
+ for (const p of pages) {
106
+ const k = key(p);
107
+ if (k === null || k === void 0 || k === "") continue;
108
+ const ks = String(k);
109
+ if (!groups.has(ks)) groups.set(ks, []);
110
+ groups.get(ks).push(p.url);
111
+ }
112
+ return [...groups.values()].filter((g) => g.length > 1).flat();
113
+ }
114
+ function computeIssues(pages, metrics, precomputedBrokenLinkPages) {
115
+ const group = (urls) => ({ count: urls.length, urls: urls.slice(0, 200) });
116
+ const where = (fn) => pages.filter(fn).map((p) => p.url);
117
+ const ok = (p) => p.status === 200;
118
+ const pathname = (u) => {
119
+ try {
120
+ return new URL(u).pathname;
121
+ } catch {
122
+ return "";
123
+ }
124
+ };
125
+ const report = {
126
+ "title.missing": group(where((p) => ok(p) && !p.title)),
127
+ "title.duplicate": group(dupes(pages.filter(ok), (p) => p.title)),
128
+ "title.tooLong": group(where((p) => (p.titleLength ?? 0) > TITLE_MAX || (p.titlePixels ?? 0) > TITLE_PX_MAX)),
129
+ "title.tooShort": group(where((p) => p.title != null && (p.titleLength ?? 0) < TITLE_MIN)),
130
+ "title.sameAsH1": group(where((p) => !!p.title && !!p.h1 && p.title.trim() === p.h1.trim())),
131
+ "meta.missing": group(where((p) => ok(p) && !p.metaDescription)),
132
+ "meta.duplicate": group(dupes(pages.filter(ok), (p) => p.metaDescription)),
133
+ "meta.tooLong": group(where((p) => (p.metaDescLength ?? 0) > META_MAX)),
134
+ "meta.tooShort": group(where((p) => p.metaDescription != null && (p.metaDescLength ?? 0) < META_MIN)),
135
+ "h1.missing": group(where((p) => ok(p) && !p.h1)),
136
+ "h1.multiple": group(where((p) => !!p.h1_2)),
137
+ "h1.duplicate": group(dupes(pages.filter(ok), (p) => p.h1)),
138
+ "h1.tooLong": group(where((p) => (p.h1?.length ?? 0) > H1_MAX)),
139
+ "h2.missing": group(where((p) => ok(p) && p.h2Count === 0)),
140
+ "indexability.nonIndexable": group(where((p) => !p.indexable)),
141
+ "indexability.noindex": group(where((p) => p.indexabilityReason === "noindex")),
142
+ "canonical.missing": group(where((p) => ok(p) && !p.canonicalUrl)),
143
+ "canonical.canonicalised": group(where((p) => p.indexabilityReason === "canonicalised")),
144
+ "response.broken4xx": group(where((p) => (p.status ?? 0) >= 400 && (p.status ?? 0) < 500)),
145
+ "response.error5xx": group(where((p) => (p.status ?? 0) >= 500)),
146
+ "response.redirect3xx": group(where((p) => (p.status ?? 0) >= 300 && (p.status ?? 0) < 400)),
147
+ "response.noResponse": group(where((p) => p.status === null)),
148
+ "content.thin": group(where((p) => ok(p) && p.wordCount > 0 && p.wordCount < THIN_WORDS)),
149
+ "content.exactDuplicate": group(dupes(pages.filter((p) => ok(p) && p.contentHash), (p) => p.contentHash)),
150
+ "images.missingAlt": group(where((p) => p.imagesMissingAlt > 0)),
151
+ "schema.missing": group(where((p) => ok(p) && p.schemaTypes.length === 0)),
152
+ "url.tooLong": group(where((p) => p.url.length > URL_MAX)),
153
+ "url.uppercase": group(where((p) => /[A-Z]/.test(pathname(p.url)))),
154
+ "url.underscores": group(where((p) => pathname(p.url).includes("_"))),
155
+ "links.orphan": group([...metrics.values()].filter((m) => m.orphan).map((m) => m.url))
156
+ };
157
+ let brokenLinkPages = precomputedBrokenLinkPages;
158
+ if (!brokenLinkPages) {
159
+ const normUrl = (u) => {
160
+ try {
161
+ const x = new URL(u);
162
+ x.hash = "";
163
+ return (x.origin + x.pathname).replace(/\/+$/, "") + x.search;
164
+ } catch {
165
+ return u.replace(/#.*$/, "").replace(/\/+$/, "");
166
+ }
167
+ };
168
+ const statusByUrl = new Map(pages.map((p) => [normUrl(p.url), p.status]));
169
+ brokenLinkPages = /* @__PURE__ */ new Set();
170
+ for (const p of pages) {
171
+ for (const l of p.outlinks ?? []) {
172
+ if (!l.internal) continue;
173
+ const st = statusByUrl.get(normUrl(l.href));
174
+ if (st != null && st >= 400) brokenLinkPages.add(p.url);
175
+ }
176
+ }
177
+ }
178
+ report["links.brokenInternal"] = group([...brokenLinkPages]);
179
+ return report;
180
+ }
181
+ function renderIssueReport(siteUrl, pages, report, metrics) {
182
+ const total = pages.length;
183
+ const sev = (key) => key.startsWith("response.broken") || key.startsWith("response.error") || key.startsWith("links.broken") ? "\u{1F534}" : key.startsWith("title.missing") || key.startsWith("h1.missing") || key.startsWith("indexability") || key.startsWith("canonical.missing") ? "\u{1F7E0}" : "\u{1F7E1}";
184
+ const rows = Object.entries(report).filter(([, g]) => g.count > 0).sort((a, b) => b[1].count - a[1].count).map(([k, g]) => `| ${sev(k)} | \`${k}\` | ${g.count} | ${g.urls.slice(0, 3).join(" \xB7 ")}${g.urls.length > 3 ? " \u2026" : ""} |`);
185
+ const depths = [...metrics.values()].map((m) => m.crawlDepth).filter((d) => d != null);
186
+ const maxDepth = depths.length ? Math.max(...depths) : 0;
187
+ const orphans = [...metrics.values()].filter((m) => m.orphan).length;
188
+ const topLinked = [...metrics.values()].sort((a, b) => b.inlinks - a.inlinks).slice(0, 5);
189
+ return [
190
+ `# SEO Crawl Report: ${siteUrl}`,
191
+ `**${total} pages crawled** \xB7 max crawl depth ${maxDepth} \xB7 ${orphans} orphan page(s)`,
192
+ `
193
+ ## Issues
194
+ | | Issue | Count | Examples |
195
+ |---|-------|-------|----------|
196
+ ${rows.join("\n") || "| \u2705 | none | 0 | \u2014 |"}`,
197
+ `
198
+ ## Most-linked pages
199
+ ${topLinked.map((m) => `- ${m.inlinks} inlinks \xB7 depth ${m.crawlDepth ?? "\u2014"} \xB7 ${m.url}`).join("\n")}`,
200
+ `
201
+ _Thresholds: title ${TITLE_MAX}ch/${TITLE_PX_MAX}px, meta ${META_MAX}ch, H1 ${H1_MAX}ch, thin <${THIN_WORDS} words, URL ${URL_MAX}ch. Pixel widths are estimates._`
202
+ ].join("\n");
203
+ }
204
+
205
+ // src/api/image-audit.ts
206
+ var OVER_BYTES = 100 * 1024;
207
+ var MODERN = /* @__PURE__ */ new Set(["webp", "avif", "svg", "svg+xml"]);
208
+ function formatBytes(n) {
209
+ if (n == null) return null;
210
+ if (n < 1024) return `${n} B`;
211
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
212
+ return `${(n / (1024 * 1024)).toFixed(2)} MB`;
213
+ }
214
+ var decodeEntities = (u) => u.replace(/&amp;/g, "&").replace(/&#0?38;/g, "&").replace(/&#x26;/gi, "&").trim();
215
+ var dedupKey = (u) => u.replace(/^https?:\/\//i, "//").replace(/\/$/, "");
216
+ var formatOf = (ct, url) => {
217
+ if (ct) {
218
+ const m = ct.split(";")[0].trim().toLowerCase();
219
+ if (m.startsWith("image/")) return m.replace("image/", "");
220
+ }
221
+ return (url.split("?")[0].match(/\.([a-z0-9]+)$/i)?.[1] || "unknown").toLowerCase();
222
+ };
223
+ function collectUrls(pages) {
224
+ const byKey = /* @__PURE__ */ new Map();
225
+ for (const p of pages) for (const raw of p.imageLinks || []) {
226
+ const u = decodeEntities(raw);
227
+ if (!/^https?:\/\//i.test(u)) continue;
228
+ if (/[{}]|%7[bd]/i.test(u)) continue;
229
+ const k = dedupKey(u);
230
+ const prev = byKey.get(k);
231
+ if (!prev || /^https:/i.test(u) && /^http:/i.test(prev)) byKey.set(k, u);
232
+ }
233
+ return [...byKey.values()];
234
+ }
235
+ async function sizeAndType(url, timeoutMs) {
236
+ const ctrl = new AbortController();
237
+ const t = setTimeout(() => ctrl.abort(), timeoutMs);
238
+ const read = (res) => ({
239
+ len: res.headers.get("content-length"),
240
+ cr: res.headers.get("content-range"),
241
+ ct: res.headers.get("content-type"),
242
+ status: res.status
243
+ });
244
+ try {
245
+ let bytes = null;
246
+ let ct = null;
247
+ let status = null;
248
+ try {
249
+ const h = read(await fetch(url, { method: "HEAD", redirect: "follow", signal: ctrl.signal }));
250
+ status = h.status;
251
+ ct = h.ct;
252
+ if (h.len) bytes = Number(h.len);
253
+ } catch {
254
+ }
255
+ if (bytes == null) {
256
+ const g = await fetch(url, { method: "GET", headers: { Range: "bytes=0-0" }, redirect: "follow", signal: ctrl.signal });
257
+ const r = read(g);
258
+ status = status ?? r.status;
259
+ ct = ct ?? r.ct;
260
+ if (r.cr && r.cr.includes("/")) {
261
+ const tail = r.cr.split("/")[1];
262
+ if (tail && tail !== "*") bytes = Number(tail);
263
+ } else if (r.len) bytes = Number(r.len);
264
+ try {
265
+ await g.body?.cancel();
266
+ } catch {
267
+ }
268
+ }
269
+ return { url, status, bytes: Number.isFinite(bytes) ? bytes : null, contentType: ct };
270
+ } catch (e) {
271
+ return { url, status: null, bytes: null, contentType: null, error: String(e.message || e) };
272
+ } finally {
273
+ clearTimeout(t);
274
+ }
275
+ }
276
+ async function pool(items, n, fn) {
277
+ const out = new Array(items.length);
278
+ let i = 0;
279
+ await Promise.all(Array.from({ length: Math.min(n, items.length) }, async () => {
280
+ while (i < items.length) {
281
+ const idx = i++;
282
+ out[idx] = await fn(items[idx]);
283
+ }
284
+ }));
285
+ return out;
286
+ }
287
+ async function auditImages(pages, opts = {}) {
288
+ const concurrency = opts.concurrency ?? 12;
289
+ const timeoutMs = opts.timeoutMs ?? 12e3;
290
+ const urls = collectUrls(pages).slice(0, opts.max ?? 5e3);
291
+ const heads = await pool(urls, concurrency, (u) => sizeAndType(u, timeoutMs));
292
+ const rows = heads.map((r) => {
293
+ const format = formatOf(r.contentType, r.url);
294
+ return {
295
+ ...r,
296
+ size: formatBytes(r.bytes),
297
+ format,
298
+ over100kb: r.bytes != null && r.bytes > OVER_BYTES,
299
+ legacyFormat: format !== "unknown" && !MODERN.has(format)
300
+ };
301
+ });
302
+ const sized = rows.filter((r) => r.bytes != null);
303
+ const totalBytes = sized.reduce((a, r) => a + r.bytes, 0);
304
+ const formatCounts = {};
305
+ for (const r of rows) formatCounts[r.format] = (formatCounts[r.format] || 0) + 1;
306
+ return {
307
+ rows: rows.sort((a, b) => (b.bytes ?? 0) - (a.bytes ?? 0)),
308
+ summary: {
309
+ unique: rows.length,
310
+ sized: sized.length,
311
+ totalBytes,
312
+ totalSize: formatBytes(totalBytes) ?? "0 B",
313
+ avgSize: formatBytes(Math.round(totalBytes / (sized.length || 1))) ?? "0 B",
314
+ over100kb: rows.filter((r) => r.over100kb).length,
315
+ legacyFormat: rows.filter((r) => r.legacyFormat).length,
316
+ formatCounts
317
+ }
318
+ };
319
+ }
320
+ function renderImageSection(audit) {
321
+ const s = audit.summary;
322
+ const fmt = Object.entries(s.formatCounts).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}:${v}`).join(" ");
323
+ const heaviest = audit.rows.filter((r) => r.over100kb).slice(0, 15);
324
+ const lines = [
325
+ `## Images`,
326
+ `**${s.unique} unique images** \xB7 ${s.totalSize} total \xB7 ${s.avgSize} avg \xB7 ${s.over100kb} over 100 KB \xB7 ${s.legacyFormat} legacy format`,
327
+ `Formats: ${fmt}`
328
+ ];
329
+ if (heaviest.length) {
330
+ lines.push("", "| Size | Format | URL |", "|------|--------|-----|");
331
+ for (const r of heaviest) lines.push(`| ${r.size} | ${r.format} | ${r.url} |`);
332
+ }
333
+ return lines.join("\n");
334
+ }
335
+
336
+ // src/api/blob-store.ts
337
+ import { mkdirSync, writeFileSync } from "fs";
338
+ import { homedir } from "os";
339
+ import { join, dirname } from "path";
340
+ function byteLength(data) {
341
+ return Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data);
342
+ }
343
+ var LocalBlobStore = class {
344
+ constructor(baseDir) {
345
+ this.baseDir = baseDir;
346
+ }
347
+ baseDir;
348
+ kind = "local";
349
+ async put(key, data, contentType = "application/octet-stream") {
350
+ const path = join(this.baseDir, "blobs", key);
351
+ mkdirSync(dirname(path), { recursive: true });
352
+ writeFileSync(path, data);
353
+ return { key, url: `file://${path}`, bytes: byteLength(data), contentType };
354
+ }
355
+ async get(key) {
356
+ const path = join(this.baseDir, "blobs", key);
357
+ try {
358
+ const { readFileSync } = await import("fs");
359
+ return readFileSync(path);
360
+ } catch {
361
+ return null;
362
+ }
363
+ }
364
+ };
365
+ function localBaseDir() {
366
+ return process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || join(homedir(), "Downloads", "mcp-scraper");
367
+ }
368
+ var cached = null;
369
+ function getBlobStore() {
370
+ if (cached) return cached;
371
+ if (process.env.BLOB_READ_WRITE_TOKEN) {
372
+ cached = new VercelBlobStore(process.env.BLOB_READ_WRITE_TOKEN);
373
+ } else {
374
+ cached = new LocalBlobStore(localBaseDir());
375
+ }
376
+ return cached;
377
+ }
378
+ var VercelBlobStore = class {
379
+ constructor(token) {
380
+ this.token = token;
381
+ }
382
+ token;
383
+ kind = "vercel-blob";
384
+ async put(key, data, contentType = "application/octet-stream") {
385
+ const { put } = await import("@vercel/blob");
386
+ const body = Buffer.isBuffer(data) ? data : Buffer.from(data);
387
+ const result = await put(key, body, {
388
+ access: "public",
389
+ token: this.token,
390
+ contentType,
391
+ addRandomSuffix: true
392
+ });
393
+ return { key, url: result.url, bytes: byteLength(data), contentType };
394
+ }
395
+ async get(key) {
396
+ try {
397
+ const { list } = await import("@vercel/blob");
398
+ const res = await list({ prefix: key, token: this.token, limit: 1 });
399
+ const match = res.blobs.find((b) => b.pathname === key || b.pathname.startsWith(key));
400
+ if (!match) return null;
401
+ const resp = await fetch(match.url);
402
+ if (!resp.ok) return null;
403
+ return Buffer.from(await resp.arrayBuffer());
404
+ } catch {
405
+ return null;
406
+ }
407
+ }
408
+ };
409
+
410
+ export {
411
+ buildLinkReport,
412
+ renderLinkReport,
413
+ computeIssues,
414
+ renderIssueReport,
415
+ auditImages,
416
+ renderImageSection,
417
+ getBlobStore
418
+ };
419
+ //# sourceMappingURL=chunk-GWRIO6JT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/seo-link-report.ts","../src/api/seo-issues.ts","../src/api/image-audit.ts","../src/api/blob-store.ts"],"sourcesContent":["import type { LinkEdge, PageLinkMetrics } from './seo-link-graph.js'\n\nexport interface ExtDomainRow { domain: string; links: number; nofollow: number; pages: number }\n\nexport interface LinkReportSummary {\n internal: {\n totalLinks: number\n pages: number\n orphans: number\n brokenInternal: number\n avgInlinks: number\n avgOutlinks: number\n distribution: { zero: number; oneToTwo: number; threeToTen: number; elevenPlus: number }\n topByInlinks: Array<{ url: string; inlinks: number; outlinksInternal: number; outlinksExternal: number }>\n }\n external: {\n totalLinks: number\n uniqueDomains: number\n topDomains: ExtDomainRow[]\n }\n}\n\nexport interface LinkReport {\n summary: LinkReportSummary\n externalDomains: ExtDomainRow[]\n}\n\nfunction registrableDomain(host: string): string {\n const h = host.replace(/^www\\./, '').toLowerCase()\n const parts = h.split('.')\n return parts.length <= 2 ? h : parts.slice(-2).join('.')\n}\n\nexport function buildLinkReport(edges: LinkEdge[], metrics: PageLinkMetrics[], siteUrl: string): LinkReport {\n let siteReg = ''\n try { siteReg = registrableDomain(new URL(siteUrl).hostname) } catch { siteReg = '' }\n const internalEdges = edges.filter(e => e.internal)\n const pages = metrics.length\n const orphans = metrics.filter(m => m.orphan).length\n const brokenInternal = internalEdges.filter(e => e.targetStatus != null && e.targetStatus >= 400).length\n const sumInlinks = metrics.reduce((a, m) => a + m.inlinks, 0)\n const sumOutlinks = metrics.reduce((a, m) => a + m.outlinksInternal + m.outlinksExternal, 0)\n\n const distribution = { zero: 0, oneToTwo: 0, threeToTen: 0, elevenPlus: 0 }\n for (const m of metrics) {\n if (m.inlinks === 0) distribution.zero++\n else if (m.inlinks <= 2) distribution.oneToTwo++\n else if (m.inlinks <= 10) distribution.threeToTen++\n else distribution.elevenPlus++\n }\n\n const topByInlinks = [...metrics].sort((a, b) => b.inlinks - a.inlinks).slice(0, 20)\n .map(m => ({ url: m.url, inlinks: m.inlinks, outlinksInternal: m.outlinksInternal, outlinksExternal: m.outlinksExternal }))\n\n const domMap = new Map<string, { links: number; nofollow: number; pages: Set<string> }>()\n let externalTotal = 0\n for (const e of edges) {\n let domain: string\n try { domain = registrableDomain(new URL(e.to).hostname) } catch { continue }\n if (!domain || domain === siteReg) continue\n externalTotal++\n const d = domMap.get(domain) ?? { links: 0, nofollow: 0, pages: new Set<string>() }\n d.links++\n if (e.nofollow) d.nofollow++\n d.pages.add(e.from)\n domMap.set(domain, d)\n }\n const externalDomains: ExtDomainRow[] = [...domMap.entries()]\n .map(([domain, d]) => ({ domain, links: d.links, nofollow: d.nofollow, pages: d.pages.size }))\n .sort((a, b) => b.links - a.links)\n\n const round = (n: number) => Math.round(n * 10) / 10\n return {\n summary: {\n internal: {\n totalLinks: internalEdges.length,\n pages, orphans, brokenInternal,\n avgInlinks: pages ? round(sumInlinks / pages) : 0,\n avgOutlinks: pages ? round(sumOutlinks / pages) : 0,\n distribution,\n topByInlinks,\n },\n external: {\n totalLinks: externalTotal,\n uniqueDomains: externalDomains.length,\n topDomains: externalDomains.slice(0, 20),\n },\n },\n externalDomains,\n }\n}\n\nexport function renderLinkReport(r: LinkReport): string {\n const s = r.summary\n const lines = [\n `## Link analysis`,\n `**Internal:** ${s.internal.totalLinks} links · ${s.internal.pages} pages · avg ${s.internal.avgInlinks} inlinks/page · ${s.internal.orphans} orphans · ${s.internal.brokenInternal} broken`,\n `**External:** ${s.external.totalLinks} links to ${s.external.uniqueDomains} domains`,\n ``,\n `### Inlink distribution`,\n `- 0 inlinks (orphans): ${s.internal.distribution.zero}`,\n `- 1–2: ${s.internal.distribution.oneToTwo}`,\n `- 3–10: ${s.internal.distribution.threeToTen}`,\n `- 11+: ${s.internal.distribution.elevenPlus}`,\n ``,\n `### Top 20 internal pages by inlinks`,\n `| inlinks | out (int/ext) | URL |`,\n `|---|---|---|`,\n ...s.internal.topByInlinks.map(p => `| ${p.inlinks} | ${p.outlinksInternal}/${p.outlinksExternal} | ${p.url} |`),\n ``,\n `### Top 20 external domains by links`,\n `| links | nofollow | from pages | domain |`,\n `|---|---|---|---|`,\n ...s.external.topDomains.map(d => `| ${d.links} | ${d.nofollow} | ${d.pages} | ${d.domain} |`),\n ]\n return lines.join('\\n')\n}\n","import type { PageData } from './site-extractor.js'\nimport type { PageLinkMetrics } from './seo-link-graph.js'\n\nexport interface IssueGroup { count: number; urls: string[] }\nexport type IssueReport = Record<string, IssueGroup>\n\nconst THIN_WORDS = 200\nconst TITLE_MAX = 60\nconst TITLE_PX_MAX = 561\nconst TITLE_MIN = 30\nconst META_MAX = 155\nconst META_MIN = 70\nconst H1_MAX = 70\nconst URL_MAX = 115\n\nfunction dupes<T>(pages: PageData[], key: (p: PageData) => T | null | undefined): string[] {\n const groups = new Map<string, string[]>()\n for (const p of pages) {\n const k = key(p)\n if (k === null || k === undefined || k === '') continue\n const ks = String(k)\n if (!groups.has(ks)) groups.set(ks, [])\n groups.get(ks)!.push(p.url)\n }\n return [...groups.values()].filter(g => g.length > 1).flat()\n}\n\nexport function computeIssues(pages: PageData[], metrics: Map<string, PageLinkMetrics>, precomputedBrokenLinkPages?: Set<string>): IssueReport {\n const group = (urls: string[]): IssueGroup => ({ count: urls.length, urls: urls.slice(0, 200) })\n const where = (fn: (p: PageData) => boolean) => pages.filter(fn).map(p => p.url)\n const ok = (p: PageData) => p.status === 200\n const pathname = (u: string) => { try { return new URL(u).pathname } catch { return '' } }\n\n const report: IssueReport = {\n 'title.missing': group(where(p => ok(p) && !p.title)),\n 'title.duplicate': group(dupes(pages.filter(ok), p => p.title)),\n 'title.tooLong': group(where(p => (p.titleLength ?? 0) > TITLE_MAX || (p.titlePixels ?? 0) > TITLE_PX_MAX)),\n 'title.tooShort': group(where(p => p.title != null && (p.titleLength ?? 0) < TITLE_MIN)),\n 'title.sameAsH1': group(where(p => !!p.title && !!p.h1 && p.title.trim() === p.h1.trim())),\n 'meta.missing': group(where(p => ok(p) && !p.metaDescription)),\n 'meta.duplicate': group(dupes(pages.filter(ok), p => p.metaDescription)),\n 'meta.tooLong': group(where(p => (p.metaDescLength ?? 0) > META_MAX)),\n 'meta.tooShort': group(where(p => p.metaDescription != null && (p.metaDescLength ?? 0) < META_MIN)),\n 'h1.missing': group(where(p => ok(p) && !p.h1)),\n 'h1.multiple': group(where(p => !!p.h1_2)),\n 'h1.duplicate': group(dupes(pages.filter(ok), p => p.h1)),\n 'h1.tooLong': group(where(p => (p.h1?.length ?? 0) > H1_MAX)),\n 'h2.missing': group(where(p => ok(p) && p.h2Count === 0)),\n 'indexability.nonIndexable': group(where(p => !p.indexable)),\n 'indexability.noindex': group(where(p => p.indexabilityReason === 'noindex')),\n 'canonical.missing': group(where(p => ok(p) && !p.canonicalUrl)),\n 'canonical.canonicalised': group(where(p => p.indexabilityReason === 'canonicalised')),\n 'response.broken4xx': group(where(p => (p.status ?? 0) >= 400 && (p.status ?? 0) < 500)),\n 'response.error5xx': group(where(p => (p.status ?? 0) >= 500)),\n 'response.redirect3xx': group(where(p => (p.status ?? 0) >= 300 && (p.status ?? 0) < 400)),\n 'response.noResponse': group(where(p => p.status === null)),\n 'content.thin': group(where(p => ok(p) && p.wordCount > 0 && p.wordCount < THIN_WORDS)),\n 'content.exactDuplicate': group(dupes(pages.filter(p => ok(p) && p.contentHash), p => p.contentHash)),\n 'images.missingAlt': group(where(p => p.imagesMissingAlt > 0)),\n 'schema.missing': group(where(p => ok(p) && p.schemaTypes.length === 0)),\n 'url.tooLong': group(where(p => p.url.length > URL_MAX)),\n 'url.uppercase': group(where(p => /[A-Z]/.test(pathname(p.url)))),\n 'url.underscores': group(where(p => pathname(p.url).includes('_'))),\n 'links.orphan': group([...metrics.values()].filter(m => m.orphan).map(m => m.url)),\n }\n\n let brokenLinkPages = precomputedBrokenLinkPages\n if (!brokenLinkPages) {\n const normUrl = (u: string) => { try { const x = new URL(u); x.hash = ''; return (x.origin + x.pathname).replace(/\\/+$/, '') + x.search } catch { return u.replace(/#.*$/, '').replace(/\\/+$/, '') } }\n const statusByUrl = new Map(pages.map(p => [normUrl(p.url), p.status]))\n brokenLinkPages = new Set<string>()\n for (const p of pages) {\n for (const l of p.outlinks ?? []) {\n if (!l.internal) continue\n const st = statusByUrl.get(normUrl(l.href))\n if (st != null && st >= 400) brokenLinkPages.add(p.url)\n }\n }\n }\n report['links.brokenInternal'] = group([...brokenLinkPages])\n\n return report\n}\n\nexport function renderIssueReport(siteUrl: string, pages: PageData[], report: IssueReport, metrics: Map<string, PageLinkMetrics>): string {\n const total = pages.length\n const sev = (key: string): string => (\n key.startsWith('response.broken') || key.startsWith('response.error') || key.startsWith('links.broken') ? '🔴'\n : key.startsWith('title.missing') || key.startsWith('h1.missing') || key.startsWith('indexability') || key.startsWith('canonical.missing') ? '🟠'\n : '🟡'\n )\n const rows = Object.entries(report)\n .filter(([, g]) => g.count > 0)\n .sort((a, b) => b[1].count - a[1].count)\n .map(([k, g]) => `| ${sev(k)} | \\`${k}\\` | ${g.count} | ${g.urls.slice(0, 3).join(' · ')}${g.urls.length > 3 ? ' …' : ''} |`)\n\n const depths = [...metrics.values()].map(m => m.crawlDepth).filter((d): d is number => d != null)\n const maxDepth = depths.length ? Math.max(...depths) : 0\n const orphans = [...metrics.values()].filter(m => m.orphan).length\n const topLinked = [...metrics.values()].sort((a, b) => b.inlinks - a.inlinks).slice(0, 5)\n\n return [\n `# SEO Crawl Report: ${siteUrl}`,\n `**${total} pages crawled** · max crawl depth ${maxDepth} · ${orphans} orphan page(s)`,\n `\\n## Issues\\n| | Issue | Count | Examples |\\n|---|-------|-------|----------|\\n${rows.join('\\n') || '| ✅ | none | 0 | — |'}`,\n `\\n## Most-linked pages\\n${topLinked.map(m => `- ${m.inlinks} inlinks · depth ${m.crawlDepth ?? '—'} · ${m.url}`).join('\\n')}`,\n `\\n_Thresholds: title ${TITLE_MAX}ch/${TITLE_PX_MAX}px, meta ${META_MAX}ch, H1 ${H1_MAX}ch, thin <${THIN_WORDS} words, URL ${URL_MAX}ch. Pixel widths are estimates._`,\n ].join('\\n')\n}\n","import type { PageData } from './site-extractor.js'\n\nexport interface ImageRow {\n url: string\n status: number | null\n bytes: number | null\n size: string | null\n contentType: string | null\n format: string\n over100kb: boolean\n legacyFormat: boolean\n error?: string\n}\n\nexport interface ImageAuditSummary {\n unique: number\n sized: number\n totalBytes: number\n totalSize: string\n avgSize: string\n over100kb: number\n legacyFormat: number\n formatCounts: Record<string, number>\n}\n\nexport interface ImageAudit {\n rows: ImageRow[]\n summary: ImageAuditSummary\n}\n\nconst OVER_BYTES = 100 * 1024\nconst MODERN = new Set(['webp', 'avif', 'svg', 'svg+xml'])\n\nexport function formatBytes(n: number | null): string | null {\n if (n == null) return null\n if (n < 1024) return `${n} B`\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`\n return `${(n / (1024 * 1024)).toFixed(2)} MB`\n}\n\nconst decodeEntities = (u: string): string =>\n u.replace(/&amp;/g, '&').replace(/&#0?38;/g, '&').replace(/&#x26;/gi, '&').trim()\n\nconst dedupKey = (u: string): string => u.replace(/^https?:\\/\\//i, '//').replace(/\\/$/, '')\n\nconst formatOf = (ct: string | null, url: string): string => {\n if (ct) { const m = ct.split(';')[0].trim().toLowerCase(); if (m.startsWith('image/')) return m.replace('image/', '') }\n return (url.split('?')[0].match(/\\.([a-z0-9]+)$/i)?.[1] || 'unknown').toLowerCase()\n}\n\nfunction collectUrls(pages: PageData[]): string[] {\n const byKey = new Map<string, string>()\n for (const p of pages) for (const raw of (p.imageLinks || [])) {\n const u = decodeEntities(raw)\n if (!/^https?:\\/\\//i.test(u)) continue\n if (/[{}]|%7[bd]/i.test(u)) continue\n const k = dedupKey(u)\n const prev = byKey.get(k)\n if (!prev || (/^https:/i.test(u) && /^http:/i.test(prev))) byKey.set(k, u)\n }\n return [...byKey.values()]\n}\n\nasync function sizeAndType(url: string, timeoutMs: number): Promise<Omit<ImageRow, 'size' | 'format' | 'over100kb' | 'legacyFormat'>> {\n const ctrl = new AbortController()\n const t = setTimeout(() => ctrl.abort(), timeoutMs)\n const read = (res: Response) => ({\n len: res.headers.get('content-length'),\n cr: res.headers.get('content-range'),\n ct: res.headers.get('content-type'),\n status: res.status,\n })\n try {\n let bytes: number | null = null\n let ct: string | null = null\n let status: number | null = null\n try {\n const h = read(await fetch(url, { method: 'HEAD', redirect: 'follow', signal: ctrl.signal }))\n status = h.status; ct = h.ct\n if (h.len) bytes = Number(h.len)\n } catch { /* fall through to ranged GET */ }\n if (bytes == null) {\n const g = await fetch(url, { method: 'GET', headers: { Range: 'bytes=0-0' }, redirect: 'follow', signal: ctrl.signal })\n const r = read(g)\n status = status ?? r.status; ct = ct ?? r.ct\n if (r.cr && r.cr.includes('/')) { const tail = r.cr.split('/')[1]; if (tail && tail !== '*') bytes = Number(tail) }\n else if (r.len) bytes = Number(r.len)\n try { await g.body?.cancel() } catch { /* ignore */ }\n }\n return { url, status, bytes: Number.isFinite(bytes as number) ? bytes : null, contentType: ct }\n } catch (e) {\n return { url, status: null, bytes: null, contentType: null, error: String((e as Error).message || e) }\n } finally {\n clearTimeout(t)\n }\n}\n\nasync function pool<T, R>(items: T[], n: number, fn: (item: T) => Promise<R>): Promise<R[]> {\n const out = new Array<R>(items.length)\n let i = 0\n await Promise.all(Array.from({ length: Math.min(n, items.length) }, async () => {\n while (i < items.length) { const idx = i++; out[idx] = await fn(items[idx]) }\n }))\n return out\n}\n\nexport async function auditImages(\n pages: PageData[],\n opts: { concurrency?: number; timeoutMs?: number; max?: number } = {},\n): Promise<ImageAudit> {\n const concurrency = opts.concurrency ?? 12\n const timeoutMs = opts.timeoutMs ?? 12_000\n const urls = collectUrls(pages).slice(0, opts.max ?? 5000)\n\n const heads = await pool(urls, concurrency, (u) => sizeAndType(u, timeoutMs))\n const rows: ImageRow[] = heads.map(r => {\n const format = formatOf(r.contentType, r.url)\n return {\n ...r,\n size: formatBytes(r.bytes),\n format,\n over100kb: r.bytes != null && r.bytes > OVER_BYTES,\n legacyFormat: format !== 'unknown' && !MODERN.has(format),\n }\n })\n\n const sized = rows.filter(r => r.bytes != null)\n const totalBytes = sized.reduce((a, r) => a + (r.bytes as number), 0)\n const formatCounts: Record<string, number> = {}\n for (const r of rows) formatCounts[r.format] = (formatCounts[r.format] || 0) + 1\n\n return {\n rows: rows.sort((a, b) => (b.bytes ?? 0) - (a.bytes ?? 0)),\n summary: {\n unique: rows.length,\n sized: sized.length,\n totalBytes,\n totalSize: formatBytes(totalBytes) ?? '0 B',\n avgSize: formatBytes(Math.round(totalBytes / (sized.length || 1))) ?? '0 B',\n over100kb: rows.filter(r => r.over100kb).length,\n legacyFormat: rows.filter(r => r.legacyFormat).length,\n formatCounts,\n },\n }\n}\n\nexport function renderImageSection(audit: ImageAudit): string {\n const s = audit.summary\n const fmt = Object.entries(s.formatCounts).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}:${v}`).join(' ')\n const heaviest = audit.rows.filter(r => r.over100kb).slice(0, 15)\n const lines = [\n `## Images`,\n `**${s.unique} unique images** · ${s.totalSize} total · ${s.avgSize} avg · ${s.over100kb} over 100 KB · ${s.legacyFormat} legacy format`,\n `Formats: ${fmt}`,\n ]\n if (heaviest.length) {\n lines.push('', '| Size | Format | URL |', '|------|--------|-----|')\n for (const r of heaviest) lines.push(`| ${r.size} | ${r.format} | ${r.url} |`)\n }\n return lines.join('\\n')\n}\n","import { mkdirSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join, dirname } from 'node:path'\n\nexport interface StoredArtifact {\n key: string\n url: string\n bytes: number\n contentType: string\n}\n\nexport interface BlobStore {\n readonly kind: 'local' | 'vercel-blob'\n put(key: string, data: Buffer | string, contentType?: string): Promise<StoredArtifact>\n get(key: string): Promise<Buffer | null>\n}\n\nfunction byteLength(data: Buffer | string): number {\n return Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data)\n}\n\nexport class LocalBlobStore implements BlobStore {\n readonly kind = 'local' as const\n constructor(private readonly baseDir: string) {}\n\n async put(key: string, data: Buffer | string, contentType = 'application/octet-stream'): Promise<StoredArtifact> {\n const path = join(this.baseDir, 'blobs', key)\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, data)\n return { key, url: `file://${path}`, bytes: byteLength(data), contentType }\n }\n\n async get(key: string): Promise<Buffer | null> {\n const path = join(this.baseDir, 'blobs', key)\n try {\n const { readFileSync } = await import('node:fs')\n return readFileSync(path)\n } catch {\n return null\n }\n }\n}\n\nfunction localBaseDir(): string {\n return process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || join(homedir(), 'Downloads', 'mcp-scraper')\n}\n\nlet cached: BlobStore | null = null\n\nexport function getBlobStore(): BlobStore {\n if (cached) return cached\n if (process.env.BLOB_READ_WRITE_TOKEN) {\n cached = new VercelBlobStore(process.env.BLOB_READ_WRITE_TOKEN)\n } else {\n cached = new LocalBlobStore(localBaseDir())\n }\n return cached\n}\n\nexport function resetBlobStoreCache(): void {\n cached = null\n}\n\nexport class VercelBlobStore implements BlobStore {\n readonly kind = 'vercel-blob' as const\n constructor(private readonly token: string) {}\n\n async put(key: string, data: Buffer | string, contentType = 'application/octet-stream'): Promise<StoredArtifact> {\n const { put } = await import('@vercel/blob')\n const body = Buffer.isBuffer(data) ? data : Buffer.from(data)\n const result = await put(key, body, {\n access: 'public',\n token: this.token,\n contentType,\n addRandomSuffix: true,\n })\n return { key, url: result.url, bytes: byteLength(data), contentType }\n }\n\n async get(key: string): Promise<Buffer | null> {\n try {\n const { list } = await import('@vercel/blob')\n const res = await list({ prefix: key, token: this.token, limit: 1 })\n const match = res.blobs.find(b => b.pathname === key || b.pathname.startsWith(key))\n if (!match) return null\n const resp = await fetch(match.url)\n if (!resp.ok) return null\n return Buffer.from(await resp.arrayBuffer())\n } catch {\n return null\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,13 +1,7 @@
1
1
  import {
2
- CaptchaError,
3
- ExtractionError,
4
- LocationMismatchError,
5
- RECAPTCHA_INSTRUCTIONS,
6
- RequestAbortedError,
7
2
  browserServiceApiKey,
8
- browserServiceProxyId,
9
- sanitizeVendorName
10
- } from "./chunk-3PRO376E.js";
3
+ browserServiceProxyId
4
+ } from "./chunk-HPV4VOQX.js";
11
5
  import {
12
6
  postToMemoryLibrary
13
7
  } from "./chunk-K443GQY5.js";
@@ -16,6 +10,14 @@ import {
16
10
  HarvestOptionsSchema,
17
11
  RawPAAItemSchema
18
12
  } from "./chunk-BP27CZ5Q.js";
13
+ import {
14
+ CaptchaError,
15
+ ExtractionError,
16
+ LocationMismatchError,
17
+ RECAPTCHA_INSTRUCTIONS,
18
+ RequestAbortedError,
19
+ sanitizeVendorName
20
+ } from "./chunk-M2S27J6Z.js";
19
21
  import {
20
22
  getDb
21
23
  } from "./chunk-FUVQR6GK.js";
@@ -3256,4 +3258,4 @@ export {
3256
3258
  resolveKernelProxyId,
3257
3259
  harvest
3258
3260
  };
3259
- //# sourceMappingURL=chunk-RXNHY3TF.js.map
3261
+ //# sourceMappingURL=chunk-HBC4C75S.js.map