mcp-scraper 0.41.1 → 0.42.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 (59) hide show
  1. package/README.md +2 -2
  2. package/dist/bin/api-server.cjs +4325 -3077
  3. package/dist/bin/api-server.cjs.map +1 -1
  4. package/dist/bin/api-server.js +3 -3
  5. package/dist/bin/mcp-scraper-cli.cjs +1 -1
  6. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  7. package/dist/bin/mcp-scraper-cli.js +1 -1
  8. package/dist/bin/mcp-scraper-install.cjs +2 -2
  9. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  10. package/dist/bin/mcp-scraper-install.js +2 -2
  11. package/dist/bin/mcp-stdio-server.cjs +2821 -2309
  12. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  13. package/dist/bin/mcp-stdio-server.js +9 -6
  14. package/dist/bin/mcp-stdio-server.js.map +1 -1
  15. package/dist/bin/paa-harvest.cjs.map +1 -1
  16. package/dist/bin/paa-harvest.js +3 -3
  17. package/dist/{chunk-6J57U6HA.js → chunk-4MFUKI4X.js} +2 -2
  18. package/dist/{chunk-VE5T5UPM.js → chunk-6O6DPKLX.js} +2983 -2450
  19. package/dist/chunk-6O6DPKLX.js.map +1 -0
  20. package/dist/{chunk-QZXKQB7Y.js → chunk-6Q7V4IQV.js} +2 -2
  21. package/dist/{chunk-EHES33KB.js → chunk-DAS7L4SF.js} +2 -2
  22. package/dist/{chunk-JVIW4GK2.js → chunk-DH42LIR3.js} +2 -2
  23. package/dist/{chunk-XELSA2MS.js → chunk-ENJQ2NSX.js} +2 -2
  24. package/dist/{chunk-XELSA2MS.js.map → chunk-ENJQ2NSX.js.map} +1 -1
  25. package/dist/{chunk-IQTT7CAB.js → chunk-FCFQ634B.js} +28 -2
  26. package/dist/chunk-FCFQ634B.js.map +1 -0
  27. package/dist/{chunk-345BQXZH.js → chunk-MJKVDLVR.js} +18 -13
  28. package/dist/chunk-MJKVDLVR.js.map +1 -0
  29. package/dist/{chunk-27DUCRAZ.js → chunk-QOWBJ4YY.js} +2 -2
  30. package/dist/chunk-S5OVG2MK.js +7 -0
  31. package/dist/chunk-S5OVG2MK.js.map +1 -0
  32. package/dist/{chunk-CS4HE6QY.js → chunk-ZBQ6EXZW.js} +2 -2
  33. package/dist/{db-LVVU6NOK.js → db-C5ELI55I.js} +2 -2
  34. package/dist/{extract-bundle-SKXEDG4Z.js → extract-bundle-DMZ63HZU.js} +5 -5
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.js +3 -3
  37. package/dist/{location-data-repository-NBTCOA7B.js → location-data-repository-SHEOIBTL.js} +3 -3
  38. package/dist/{server-PKTDPCB2.js → server-MVCGZ4OK.js} +1154 -516
  39. package/dist/server-MVCGZ4OK.js.map +1 -0
  40. package/dist/{site-extract-repository-6GX72U4N.js → site-extract-repository-B42SIGAZ.js} +3 -3
  41. package/dist/{worker-5RWLFSAJ.js → worker-4R3UWQZS.js} +5 -5
  42. package/package.json +1 -1
  43. package/dist/chunk-345BQXZH.js.map +0 -1
  44. package/dist/chunk-IQTT7CAB.js.map +0 -1
  45. package/dist/chunk-R3EME5HH.js +0 -7
  46. package/dist/chunk-R3EME5HH.js.map +0 -1
  47. package/dist/chunk-VE5T5UPM.js.map +0 -1
  48. package/dist/server-PKTDPCB2.js.map +0 -1
  49. /package/dist/{chunk-6J57U6HA.js.map → chunk-4MFUKI4X.js.map} +0 -0
  50. /package/dist/{chunk-QZXKQB7Y.js.map → chunk-6Q7V4IQV.js.map} +0 -0
  51. /package/dist/{chunk-EHES33KB.js.map → chunk-DAS7L4SF.js.map} +0 -0
  52. /package/dist/{chunk-JVIW4GK2.js.map → chunk-DH42LIR3.js.map} +0 -0
  53. /package/dist/{chunk-27DUCRAZ.js.map → chunk-QOWBJ4YY.js.map} +0 -0
  54. /package/dist/{chunk-CS4HE6QY.js.map → chunk-ZBQ6EXZW.js.map} +0 -0
  55. /package/dist/{db-LVVU6NOK.js.map → db-C5ELI55I.js.map} +0 -0
  56. /package/dist/{extract-bundle-SKXEDG4Z.js.map → extract-bundle-DMZ63HZU.js.map} +0 -0
  57. /package/dist/{location-data-repository-NBTCOA7B.js.map → location-data-repository-SHEOIBTL.js.map} +0 -0
  58. /package/dist/{site-extract-repository-6GX72U4N.js.map → site-extract-repository-B42SIGAZ.js.map} +0 -0
  59. /package/dist/{worker-5RWLFSAJ.js.map → worker-4R3UWQZS.js.map} +0 -0
@@ -438,6 +438,7 @@ import { homedir } from "os";
438
438
  import { dirname, join } from "path";
439
439
  import { Transform } from "stream";
440
440
  import { pipeline } from "stream/promises";
441
+ var DURABLE_ARTIFACT_EXPIRES_AT = "9999-12-31T23:59:59.999Z";
441
442
  function hostedByEnvironment() {
442
443
  return process.env.VERCEL === "1" || process.env.NODE_ENV === "production";
443
444
  }
@@ -479,7 +480,7 @@ function createdAtMs(value) {
479
480
  return timestamp;
480
481
  }
481
482
  function validatePolicy(policy) {
482
- if (!Number.isSafeInteger(policy.artifactTtlMs) || policy.artifactTtlMs <= 0) {
483
+ if (policy.artifactTtlMs !== null && (!Number.isSafeInteger(policy.artifactTtlMs) || policy.artifactTtlMs <= 0)) {
483
484
  throw new Error("private artifact TTL must be a positive integer");
484
485
  }
485
486
  if (!Number.isSafeInteger(policy.downloadTtlMs) || policy.downloadTtlMs <= 0) {
@@ -505,7 +506,7 @@ function privateArtifactOwnerId(artifactId, prefix) {
505
506
  if (!artifactId.startsWith(normalized) || artifactId.includes("..")) return null;
506
507
  const rest = artifactId.slice(normalized.length);
507
508
  const segments = rest.split("/");
508
- if (segments.length !== 2) return null;
509
+ if (segments.length < 2) return null;
509
510
  try {
510
511
  return requiredSafeSegment(segments[0] ?? "", "ownerId");
511
512
  } catch {
@@ -515,13 +516,14 @@ function privateArtifactOwnerId(artifactId, prefix) {
515
516
  function privateArtifactExpiresAt(artifactId, policy) {
516
517
  const validated = validatePolicy(policy);
517
518
  if (privateArtifactOwnerId(artifactId, validated.prefix) === null) return null;
519
+ if (validated.artifactTtlMs === null) return null;
518
520
  const timestamp = artifactTimestamp(artifactId, validated.prefix);
519
521
  return timestamp === null ? null : new Date(timestamp + validated.artifactTtlMs);
520
522
  }
521
523
  async function signedDownloadUrl(pathname, expiresAt, policy) {
522
524
  const token = policy.token?.trim();
523
525
  if (!token) return null;
524
- const validUntil = Math.min(Date.now() + policy.downloadTtlMs, expiresAt.getTime());
526
+ const validUntil = expiresAt ? Math.min(Date.now() + policy.downloadTtlMs, expiresAt.getTime()) : Date.now() + policy.downloadTtlMs;
525
527
  if (validUntil <= Date.now()) return null;
526
528
  const { issueSignedToken, presignUrl } = await import("@vercel/blob");
527
529
  const signedToken = await issueSignedToken({
@@ -542,12 +544,13 @@ async function createPrivateArtifact(args) {
542
544
  const policy = { ...args.policy, ...validatePolicy(args.policy) };
543
545
  const ownerId = requiredSafeSegment(args.ownerId, "ownerId");
544
546
  const artifactKey = requiredSafeArtifactKey(args.artifactKey);
547
+ const scope = (args.scopeSegments ?? []).map((segment, index) => requiredSafeSegment(segment, `scopeSegments[${index}]`));
545
548
  const timestamp = createdAtMs(args.createdAt);
546
- const requestedPathname = `${policy.prefix}${ownerId}/${timestamp}-${artifactKey}`;
549
+ const requestedPathname = `${policy.prefix}${ownerId}/${scope.length ? `${scope.join("/")}/` : ""}${timestamp}-${artifactKey}`;
547
550
  const body = Buffer.isBuffer(args.content) ? args.content : Buffer.from(args.content);
548
551
  const bytes = body.length;
549
552
  const sha256 = createHash("sha256").update(body).digest("hex");
550
- const expiresAt = new Date(timestamp + policy.artifactTtlMs);
553
+ const expiresAt = policy.artifactTtlMs === null ? null : new Date(timestamp + policy.artifactTtlMs);
551
554
  const token = policy.token?.trim() || null;
552
555
  let artifactId = requestedPathname;
553
556
  if (token) {
@@ -575,7 +578,7 @@ async function createPrivateArtifact(args) {
575
578
  contentType: args.contentType,
576
579
  bytes,
577
580
  sha256,
578
- expiresAt: expiresAt.toISOString(),
581
+ expiresAt: expiresAt?.toISOString() ?? DURABLE_ARTIFACT_EXPIRES_AT,
579
582
  downloadUrl: download?.url ?? null,
580
583
  downloadUrlExpiresAt: download?.expiresAt ?? null
581
584
  };
@@ -584,9 +587,10 @@ async function createPrivateArtifactFromStream(args) {
584
587
  const policy = { ...args.policy, ...validatePolicy(args.policy) };
585
588
  const ownerId = requiredSafeSegment(args.ownerId, "ownerId");
586
589
  const artifactKey = requiredSafeArtifactKey(args.artifactKey);
590
+ const scope = (args.scopeSegments ?? []).map((segment, index) => requiredSafeSegment(segment, `scopeSegments[${index}]`));
587
591
  const timestamp = createdAtMs(args.createdAt);
588
- const requestedPathname = `${policy.prefix}${ownerId}/${timestamp}-${artifactKey}`;
589
- const expiresAt = new Date(timestamp + policy.artifactTtlMs);
592
+ const requestedPathname = `${policy.prefix}${ownerId}/${scope.length ? `${scope.join("/")}/` : ""}${timestamp}-${artifactKey}`;
593
+ const expiresAt = policy.artifactTtlMs === null ? null : new Date(timestamp + policy.artifactTtlMs);
590
594
  const token = policy.token?.trim() || null;
591
595
  const hash = createHash("sha256");
592
596
  let bytes = 0;
@@ -633,7 +637,7 @@ async function createPrivateArtifactFromStream(args) {
633
637
  contentType: args.contentType,
634
638
  bytes,
635
639
  sha256,
636
- expiresAt: expiresAt.toISOString(),
640
+ expiresAt: expiresAt?.toISOString() ?? DURABLE_ARTIFACT_EXPIRES_AT,
637
641
  downloadUrl: download?.url ?? null,
638
642
  downloadUrlExpiresAt: download?.expiresAt ?? null
639
643
  };
@@ -641,13 +645,13 @@ async function createPrivateArtifactFromStream(args) {
641
645
  async function renewPrivateArtifactDownload(args) {
642
646
  if (privateArtifactOwnerId(args.artifactId, args.policy.prefix) !== args.ownerId) return null;
643
647
  const expiresAt = privateArtifactExpiresAt(args.artifactId, args.policy);
644
- if (!expiresAt || expiresAt.getTime() <= Date.now()) return null;
648
+ if (args.policy.artifactTtlMs !== null && (!expiresAt || expiresAt.getTime() <= Date.now())) return null;
645
649
  const download = await signedDownloadUrl(args.artifactId, expiresAt, args.policy);
646
650
  if (!download) return null;
647
651
  return {
648
652
  downloadUrl: download.url,
649
653
  downloadUrlExpiresAt: download.expiresAt,
650
- expiresAt: expiresAt.toISOString()
654
+ expiresAt: expiresAt?.toISOString() ?? DURABLE_ARTIFACT_EXPIRES_AT
651
655
  };
652
656
  }
653
657
  async function streamToBuffer(stream) {
@@ -665,8 +669,9 @@ async function streamToBuffer(stream) {
665
669
  return Buffer.concat(chunks);
666
670
  }
667
671
  async function readPrivateArtifactWindow(args) {
672
+ if (privateArtifactOwnerId(args.artifactId, args.policy.prefix) === null) return null;
668
673
  const expiresAt = privateArtifactExpiresAt(args.artifactId, args.policy);
669
- if (!expiresAt || expiresAt.getTime() <= Date.now()) return null;
674
+ if (args.policy.artifactTtlMs !== null && (!expiresAt || expiresAt.getTime() <= Date.now())) return null;
670
675
  if (!Number.isSafeInteger(args.offset) || args.offset < 0) throw new Error("private artifact offset is invalid");
671
676
  if (!Number.isSafeInteger(args.maxBytes) || args.maxBytes <= 0) throw new Error("private artifact maxBytes is invalid");
672
677
  const token = args.policy.token?.trim() || null;
@@ -709,4 +714,4 @@ export {
709
714
  renewPrivateArtifactDownload,
710
715
  readPrivateArtifactWindow
711
716
  };
712
- //# sourceMappingURL=chunk-345BQXZH.js.map
717
+ //# sourceMappingURL=chunk-MJKVDLVR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/url-utils.ts","../src/api/image-audit.ts","../src/api/seo-link-report.ts","../src/api/seo-issues.ts","../src/api/private-artifacts.ts"],"sourcesContent":["import { isIP } from 'node:net'\nimport { lookup } from 'node:dns/promises'\nimport ipaddr from 'ipaddr.js'\n\nfunction unbracketIpLiteral(value: string): string {\n return value.startsWith('[') && value.endsWith(']') ? value.slice(1, -1) : value\n}\n\nexport function isPrivateIpAddress(address: string): boolean {\n const normalized = unbracketIpLiteral(address)\n if (!isIP(normalized)) return false\n try {\n const parsed = ipaddr.parse(normalized)\n const isExtraNonGlobalIpv4 = (ipv4: InstanceType<typeof ipaddr.IPv4>): boolean => {\n const extraNonGlobal: Array<[string, number]> = [\n ['192.0.0.0', 24],\n ['192.0.2.0', 24],\n ['198.18.0.0', 15],\n ['198.51.100.0', 24],\n ['203.0.113.0', 24],\n ]\n return extraNonGlobal.some(([network, bits]) => ipv4.match(ipaddr.parse(network) as InstanceType<typeof ipaddr.IPv4>, bits))\n }\n if (parsed instanceof ipaddr.IPv6 && parsed.isIPv4MappedAddress()) {\n const mapped = parsed.toIPv4Address()\n return mapped.range() !== 'unicast' || isExtraNonGlobalIpv4(mapped)\n }\n if (parsed instanceof ipaddr.IPv4) {\n if (isExtraNonGlobalIpv4(parsed)) return true\n }\n // Despite the historical function name, outbound URL validation needs to\n // reject every non-global range: loopback/private/link-local plus CGNAT,\n // multicast, documentation, benchmark, reserved and unspecified space.\n return parsed.range() !== 'unicast'\n } catch { return true }\n}\n\nexport async function resolvesToPrivateAddress(hostname: string): Promise<boolean> {\n const host = unbracketIpLiteral(hostname.toLowerCase())\n if (host === 'localhost' || host.endsWith('.localhost') || host.endsWith('.local')) return true\n if (isPrivateIpAddress(host)) return true\n try {\n const addresses = await lookup(host, { all: true, verbatim: true })\n return addresses.length === 0 || addresses.some((entry) => isPrivateIpAddress(entry.address))\n } catch {\n // URL safety must fail closed when DNS cannot establish a public target.\n return true\n }\n}\n\nexport async function validatePublicHttpUrl(raw: string, opts: { field: string; requireHttps?: boolean }): Promise<{ parsed?: URL; error?: string }> {\n let parsed: URL\n try {\n parsed = new URL(raw.trim())\n } catch {\n return { error: `Invalid ${opts.field}` }\n }\n const allowedProtocols = opts.requireHttps ? ['https:'] : ['http:', 'https:']\n if (!allowedProtocols.includes(parsed.protocol)) {\n return { error: opts.requireHttps ? `${opts.field} must use https` : `${opts.field} must use http or https` }\n }\n if (await resolvesToPrivateAddress(parsed.hostname)) {\n return { error: `${opts.field} must resolve to a public internet host` }\n }\n return { parsed }\n}\n","import type { PageData } from './site-extractor.js'\nimport { validatePublicHttpUrl } from './url-utils.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 sampleTruncated?: boolean\n sampleCap?: 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 const safeFetch = async (method: 'HEAD' | 'GET'): Promise<Response> => {\n let target = url\n for (let redirects = 0; redirects <= 5; redirects++) {\n const checked = await validatePublicHttpUrl(target, { field: 'image URL' })\n if (checked.error || !checked.parsed) throw new Error(checked.error ?? 'Image URL was rejected')\n const response = await fetch(checked.parsed.href, {\n method,\n ...(method === 'GET' ? { headers: { Range: 'bytes=0-0' } } : {}),\n redirect: 'manual',\n signal: ctrl.signal,\n })\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location')\n if (!location) throw new Error(`HTTP ${response.status} redirect did not include Location`)\n target = new URL(location, checked.parsed.href).href\n continue\n }\n return response\n }\n throw new Error('Image request exceeded five redirects')\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 safeFetch('HEAD'))\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 safeFetch('GET')\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 return auditImageUrls(collectUrls(pages), opts)\n}\n\nexport async function auditImageUrls(\n inputUrls: string[],\n opts: { concurrency?: number; timeoutMs?: number; max?: number; sampleTruncated?: boolean } = {},\n): Promise<ImageAudit> {\n const concurrency = opts.concurrency ?? 12\n const timeoutMs = opts.timeoutMs ?? 12_000\n const max = opts.max ?? 5000\n const urls = collectUrls([{ imageLinks: inputUrls } as PageData]).slice(0, max)\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 ...(opts.sampleTruncated ? { sampleTruncated: true, sampleCap: max } : {}),\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 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 extracted = (p: PageData) => p.extractionStatus !== 'failed'\n const ok = (p: PageData) => extracted(p) && p.status === 200\n const extractedUrls = new Set(pages.filter(extracted).map(page => page.url))\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 // A transport/extraction failure is not an SEO conclusion about the URL.\n // Keep it in a dedicated crawl bucket so empty records cannot become a\n // wall of false missing-title/H1/non-indexable findings.\n 'crawl.extractionFailed': group(where(p => !extracted(p))),\n 'indexability.nonIndexable': group(where(p => extracted(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 => extracted(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 && extractedUrls.has(m.url)).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 successful = pages.filter(page => page.extractionStatus !== 'failed').length\n const failed = total - successful\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 extractedUrls = new Set(pages.filter(page => page.extractionStatus !== 'failed').map(page => page.url))\n const orphans = [...metrics.values()].filter(m => m.orphan && extractedUrls.has(m.url)).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 attempted** · ${successful} extracted · ${failed} failed · 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 { createHash } from 'node:crypto'\nimport { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { createWriteStream } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { Readable, Transform } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\n\nexport interface PrivateArtifactPolicy {\n prefix: string\n artifactTtlMs: number | null\n downloadTtlMs: number\n token?: string | null\n localBaseDir?: string\n hosted?: boolean\n}\n\nexport interface PrivateArtifactPointer {\n artifactId: string\n filename: string\n contentType: string\n bytes: number\n sha256: string\n expiresAt: string\n downloadUrl: string | null\n downloadUrlExpiresAt: string | null\n}\n\nexport interface PrivateArtifactWindow {\n text: string\n totalBytes: number\n nextOffset: number | null\n}\n\nconst DURABLE_ARTIFACT_EXPIRES_AT = '9999-12-31T23:59:59.999Z'\n\nfunction hostedByEnvironment(): boolean {\n return process.env.VERCEL === '1' || process.env.NODE_ENV === 'production'\n}\n\nfunction policyHosted(policy: PrivateArtifactPolicy): boolean {\n return policy.hosted ?? hostedByEnvironment()\n}\n\nfunction policyLocalBaseDir(policy: PrivateArtifactPolicy): string {\n return policy.localBaseDir?.trim()\n || process.env.MCP_SCRAPER_OUTPUT_DIR?.trim()\n || join(homedir(), 'Downloads', 'mcp-scraper')\n}\n\nfunction normalizedPrefix(prefix: string): string {\n const normalized = prefix.replace(/^\\/+/, '').replace(/\\/+$/, '')\n if (!normalized || normalized.includes('..') || !/^[a-zA-Z0-9/_-]+$/.test(normalized)) {\n throw new Error('private artifact prefix is invalid')\n }\n return `${normalized}/`\n}\n\nfunction requiredSafeSegment(value: string, field: string): string {\n const trimmed = value.trim()\n if (!/^[a-zA-Z0-9_-]{1,160}$/.test(trimmed)) {\n throw new Error(`${field} must contain only letters, numbers, underscores, or hyphens`)\n }\n return trimmed\n}\n\nfunction requiredSafeArtifactKey(value: string): string {\n const trimmed = value.trim()\n if (!/^[a-zA-Z0-9_.-]{1,200}$/.test(trimmed) || trimmed === '.' || trimmed === '..') {\n throw new Error('private artifact key is invalid')\n }\n return trimmed\n}\n\nfunction safeDownloadFilename(value: string): string {\n const normalized = value.trim().replace(/[^a-zA-Z0-9_.-]+/g, '-').replace(/^-+|-+$/g, '')\n return (normalized || 'artifact').slice(0, 160)\n}\n\nfunction createdAtMs(value: Date | string | number): number {\n const normalized = typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(value)\n ? `${value.replace(' ', 'T')}Z`\n : value\n const timestamp = normalized instanceof Date\n ? normalized.getTime()\n : typeof normalized === 'number'\n ? normalized\n : new Date(normalized).getTime()\n if (!Number.isSafeInteger(timestamp) || timestamp <= 0) throw new Error('private artifact createdAt is invalid')\n return timestamp\n}\n\nfunction validatePolicy(policy: PrivateArtifactPolicy): {\n prefix: string\n artifactTtlMs: number | null\n downloadTtlMs: number\n} {\n if (policy.artifactTtlMs !== null && (!Number.isSafeInteger(policy.artifactTtlMs) || policy.artifactTtlMs <= 0)) {\n throw new Error('private artifact TTL must be a positive integer')\n }\n if (!Number.isSafeInteger(policy.downloadTtlMs) || policy.downloadTtlMs <= 0) {\n throw new Error('private artifact download TTL must be a positive integer')\n }\n return {\n prefix: normalizedPrefix(policy.prefix),\n artifactTtlMs: policy.artifactTtlMs,\n downloadTtlMs: policy.downloadTtlMs,\n }\n}\n\nfunction artifactTimestamp(artifactId: string, prefix: string): number | null {\n const normalized = normalizedPrefix(prefix)\n if (!artifactId.startsWith(normalized)) return null\n const filename = artifactId.split('/').at(-1) ?? ''\n const match = filename.match(/^(\\d{13})-/)\n if (!match) return null\n const timestamp = Number(match[1])\n return Number.isSafeInteger(timestamp) && timestamp > 0 ? timestamp : null\n}\n\nexport function privateArtifactOwnerId(artifactId: string, prefix: string): string | null {\n const normalized = normalizedPrefix(prefix)\n if (!artifactId.startsWith(normalized) || artifactId.includes('..')) return null\n const rest = artifactId.slice(normalized.length)\n const segments = rest.split('/')\n if (segments.length < 2) return null\n try {\n return requiredSafeSegment(segments[0] ?? '', 'ownerId')\n } catch {\n return null\n }\n}\n\nexport function privateArtifactExpiresAt(artifactId: string, policy: PrivateArtifactPolicy): Date | null {\n const validated = validatePolicy(policy)\n if (privateArtifactOwnerId(artifactId, validated.prefix) === null) return null\n if (validated.artifactTtlMs === null) return null\n const timestamp = artifactTimestamp(artifactId, validated.prefix)\n return timestamp === null ? null : new Date(timestamp + validated.artifactTtlMs)\n}\n\nasync function signedDownloadUrl(pathname: string, expiresAt: Date | null, policy: PrivateArtifactPolicy): Promise<{\n url: string\n expiresAt: string\n} | null> {\n const token = policy.token?.trim()\n if (!token) return null\n const validUntil = expiresAt\n ? Math.min(Date.now() + policy.downloadTtlMs, expiresAt.getTime())\n : Date.now() + policy.downloadTtlMs\n if (validUntil <= Date.now()) return null\n const { issueSignedToken, presignUrl } = await import('@vercel/blob')\n const signedToken = await issueSignedToken({\n token,\n pathname,\n operations: ['get'],\n validUntil,\n })\n const { presignedUrl } = await presignUrl(signedToken, {\n access: 'private',\n operation: 'get',\n pathname,\n validUntil,\n })\n return { url: presignedUrl, expiresAt: new Date(validUntil).toISOString() }\n}\n\nexport async function createPrivateArtifact(args: {\n policy: PrivateArtifactPolicy\n ownerId: string\n artifactKey: string\n createdAt: Date | string | number\n filename: string\n contentType: string\n content: string | Buffer\n scopeSegments?: string[]\n}): Promise<PrivateArtifactPointer> {\n const policy = { ...args.policy, ...validatePolicy(args.policy) }\n const ownerId = requiredSafeSegment(args.ownerId, 'ownerId')\n const artifactKey = requiredSafeArtifactKey(args.artifactKey)\n const scope = (args.scopeSegments ?? []).map((segment, index) => requiredSafeSegment(segment, `scopeSegments[${index}]`))\n const timestamp = createdAtMs(args.createdAt)\n const requestedPathname = `${policy.prefix}${ownerId}/${scope.length ? `${scope.join('/')}/` : ''}${timestamp}-${artifactKey}`\n const body = Buffer.isBuffer(args.content) ? args.content : Buffer.from(args.content)\n const bytes = body.length\n const sha256 = createHash('sha256').update(body).digest('hex')\n const expiresAt = policy.artifactTtlMs === null ? null : new Date(timestamp + policy.artifactTtlMs)\n const token = policy.token?.trim() || null\n\n let artifactId = requestedPathname\n if (token) {\n const { put } = await import('@vercel/blob')\n const stored = await put(requestedPathname, body, {\n access: 'private',\n token,\n contentType: args.contentType,\n addRandomSuffix: false,\n allowOverwrite: true,\n cacheControlMaxAge: 60,\n multipart: bytes > 100 * 1024 * 1024,\n })\n artifactId = stored.pathname\n } else {\n if (policyHosted(policy)) throw new Error('private_artifact_blob_not_configured')\n const path = join(policyLocalBaseDir(policy), 'blobs', requestedPathname)\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, body)\n }\n\n const download = await signedDownloadUrl(artifactId, expiresAt, policy)\n return {\n artifactId,\n filename: safeDownloadFilename(args.filename),\n contentType: args.contentType,\n bytes,\n sha256,\n expiresAt: expiresAt?.toISOString() ?? DURABLE_ARTIFACT_EXPIRES_AT,\n downloadUrl: download?.url ?? null,\n downloadUrlExpiresAt: download?.expiresAt ?? null,\n }\n}\n\nexport async function createPrivateArtifactFromStream(args: {\n policy: PrivateArtifactPolicy\n ownerId: string\n artifactKey: string\n createdAt: Date | string | number\n filename: string\n contentType: string\n content: Readable\n scopeSegments?: string[]\n}): Promise<PrivateArtifactPointer> {\n const policy = { ...args.policy, ...validatePolicy(args.policy) }\n const ownerId = requiredSafeSegment(args.ownerId, 'ownerId')\n const artifactKey = requiredSafeArtifactKey(args.artifactKey)\n const scope = (args.scopeSegments ?? []).map((segment, index) => requiredSafeSegment(segment, `scopeSegments[${index}]`))\n const timestamp = createdAtMs(args.createdAt)\n const requestedPathname = `${policy.prefix}${ownerId}/${scope.length ? `${scope.join('/')}/` : ''}${timestamp}-${artifactKey}`\n const expiresAt = policy.artifactTtlMs === null ? null : new Date(timestamp + policy.artifactTtlMs)\n const token = policy.token?.trim() || null\n const hash = createHash('sha256')\n let bytes = 0\n const meter = new Transform({\n transform(chunk: Buffer, _encoding, callback) {\n bytes += chunk.length\n hash.update(chunk)\n callback(null, chunk)\n },\n })\n\n let artifactId = requestedPathname\n if (token) {\n const { put } = await import('@vercel/blob')\n const pumping = pipeline(args.content, meter)\n try {\n const stored = await put(requestedPathname, meter, {\n access: 'private',\n token,\n contentType: args.contentType,\n addRandomSuffix: false,\n allowOverwrite: true,\n cacheControlMaxAge: 60,\n multipart: true,\n })\n await pumping\n artifactId = stored.pathname\n } catch (error) {\n args.content.destroy(error instanceof Error ? error : new Error(String(error)))\n meter.destroy(error instanceof Error ? error : new Error(String(error)))\n await pumping.catch(() => undefined)\n throw error\n }\n } else {\n if (policyHosted(policy)) throw new Error('private_artifact_blob_not_configured')\n const path = join(policyLocalBaseDir(policy), 'blobs', requestedPathname)\n await mkdir(dirname(path), { recursive: true })\n await pipeline(args.content, meter, createWriteStream(path))\n }\n\n const sha256 = hash.digest('hex')\n const download = await signedDownloadUrl(artifactId, expiresAt, policy)\n return {\n artifactId,\n filename: safeDownloadFilename(args.filename),\n contentType: args.contentType,\n bytes,\n sha256,\n expiresAt: expiresAt?.toISOString() ?? DURABLE_ARTIFACT_EXPIRES_AT,\n downloadUrl: download?.url ?? null,\n downloadUrlExpiresAt: download?.expiresAt ?? null,\n }\n}\n\nexport async function renewPrivateArtifactDownload(args: {\n policy: PrivateArtifactPolicy\n artifactId: string\n ownerId: string\n}): Promise<{ downloadUrl: string; downloadUrlExpiresAt: string; expiresAt: string } | null> {\n if (privateArtifactOwnerId(args.artifactId, args.policy.prefix) !== args.ownerId) return null\n const expiresAt = privateArtifactExpiresAt(args.artifactId, args.policy)\n if (args.policy.artifactTtlMs !== null && (!expiresAt || expiresAt.getTime() <= Date.now())) return null\n const download = await signedDownloadUrl(args.artifactId, expiresAt, args.policy)\n if (!download) return null\n return {\n downloadUrl: download.url,\n downloadUrlExpiresAt: download.expiresAt,\n expiresAt: expiresAt?.toISOString() ?? DURABLE_ARTIFACT_EXPIRES_AT,\n }\n}\n\nasync function streamToBuffer(stream: ReadableStream<Uint8Array>): Promise<Buffer> {\n const reader = stream.getReader()\n const chunks: Buffer[] = []\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (value) chunks.push(Buffer.from(value))\n }\n } finally {\n reader.releaseLock()\n }\n return Buffer.concat(chunks)\n}\n\nexport async function readPrivateArtifactWindow(args: {\n policy: PrivateArtifactPolicy\n artifactId: string\n offset: number\n maxBytes: number\n}): Promise<PrivateArtifactWindow | null> {\n if (privateArtifactOwnerId(args.artifactId, args.policy.prefix) === null) return null\n const expiresAt = privateArtifactExpiresAt(args.artifactId, args.policy)\n if (args.policy.artifactTtlMs !== null && (!expiresAt || expiresAt.getTime() <= Date.now())) return null\n if (!Number.isSafeInteger(args.offset) || args.offset < 0) throw new Error('private artifact offset is invalid')\n if (!Number.isSafeInteger(args.maxBytes) || args.maxBytes <= 0) throw new Error('private artifact maxBytes is invalid')\n\n const token = args.policy.token?.trim() || null\n let buffer: Buffer\n if (token) {\n const { get } = await import('@vercel/blob')\n const result = await get(args.artifactId, { access: 'private', token, useCache: false })\n if (!result || result.statusCode !== 200) return null\n buffer = await streamToBuffer(result.stream)\n } else {\n if (policyHosted(args.policy)) return null\n try {\n buffer = await readFile(join(policyLocalBaseDir(args.policy), 'blobs', args.artifactId))\n } catch {\n return null\n }\n }\n\n const totalBytes = buffer.length\n const end = Math.min(totalBytes, args.offset + args.maxBytes)\n return {\n text: buffer.subarray(args.offset, end).toString('utf8'),\n totalBytes,\n nextOffset: end < totalBytes ? end : null,\n }\n}\n"],"mappings":"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","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-G3P3ZDB4.js";
4
4
  import {
5
5
  getDb
6
- } from "./chunk-IQTT7CAB.js";
6
+ } from "./chunk-FCFQ634B.js";
7
7
 
8
8
  // src/api/location-data-repository.ts
9
9
  import { createHash, randomUUID } from "crypto";
@@ -681,4 +681,4 @@ export {
681
681
  importHostedCensusPlacesCsv,
682
682
  queryHostedLocationMarkets
683
683
  };
684
- //# sourceMappingURL=chunk-27DUCRAZ.js.map
684
+ //# sourceMappingURL=chunk-QOWBJ4YY.js.map
@@ -0,0 +1,7 @@
1
+ // src/version.ts
2
+ var PACKAGE_VERSION = "0.42.0";
3
+
4
+ export {
5
+ PACKAGE_VERSION
6
+ };
7
+ //# sourceMappingURL=chunk-S5OVG2MK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["export const PACKAGE_VERSION = '0.42.0'\n"],"mappings":";AAAO,IAAM,kBAAkB;","names":[]}
@@ -8,7 +8,7 @@ import {
8
8
  import {
9
9
  finishHarvestAttempt,
10
10
  startHarvestAttempt
11
- } from "./chunk-IQTT7CAB.js";
11
+ } from "./chunk-FCFQ634B.js";
12
12
 
13
13
  // src/api/webhook.ts
14
14
  async function deliverWebhook(url, payload, retries = 3) {
@@ -191,4 +191,4 @@ export {
191
191
  harvestProblemResponse,
192
192
  createHarvestAttemptRecorder
193
193
  };
194
- //# sourceMappingURL=chunk-CS4HE6QY.js.map
194
+ //# sourceMappingURL=chunk-ZBQ6EXZW.js.map
@@ -123,7 +123,7 @@ import {
123
123
  updateKpoJobState,
124
124
  upsertPageSnapshot,
125
125
  verifyPassword
126
- } from "./chunk-IQTT7CAB.js";
126
+ } from "./chunk-FCFQ634B.js";
127
127
  export {
128
128
  CORE_SCHEMA_VERSION,
129
129
  CREDIT_LOTS_EPOCH,
@@ -250,4 +250,4 @@ export {
250
250
  upsertPageSnapshot,
251
251
  verifyPassword
252
252
  };
253
- //# sourceMappingURL=db-LVVU6NOK.js.map
253
+ //# sourceMappingURL=db-C5ELI55I.js.map
@@ -1,21 +1,21 @@
1
1
  import {
2
2
  createSiteExtractBundleArtifactStream,
3
3
  downloadAsset
4
- } from "./chunk-QZXKQB7Y.js";
4
+ } from "./chunk-6Q7V4IQV.js";
5
5
  import {
6
6
  computeIssues,
7
7
  renderImageSection,
8
8
  renderIssueReport,
9
9
  renderLinkReport
10
- } from "./chunk-345BQXZH.js";
10
+ } from "./chunk-MJKVDLVR.js";
11
11
  import {
12
12
  extractJobLimitInfo
13
- } from "./chunk-6J57U6HA.js";
13
+ } from "./chunk-4MFUKI4X.js";
14
14
  import "./chunk-SBLGBZZB.js";
15
15
  import "./chunk-5UN33CGU.js";
16
16
  import {
17
17
  getDb
18
- } from "./chunk-IQTT7CAB.js";
18
+ } from "./chunk-FCFQ634B.js";
19
19
 
20
20
  // src/api/extract-bundle.ts
21
21
  import { createWriteStream, mkdirSync, readdirSync, rmSync, statSync, writeFileSync } from "fs";
@@ -565,4 +565,4 @@ export {
565
565
  SITE_EXTRACT_PAGE_CHUNK,
566
566
  assembleExtractArtifacts
567
567
  };
568
- //# sourceMappingURL=extract-bundle-SKXEDG4Z.js.map
568
+ //# sourceMappingURL=extract-bundle-DMZ63HZU.js.map