mcp-scraper 0.65.1 → 0.66.1

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 (89) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/README.md +11 -6
  3. package/dist/{analytics-repository-IKE53S3E.js → analytics-repository-RUXBFSFX.js} +1 -2
  4. package/dist/bin/api-server.cjs +1844 -71
  5. package/dist/bin/api-server.js +4 -5
  6. package/dist/bin/mcp-scraper-cli.cjs +1 -2
  7. package/dist/bin/mcp-scraper-cli.js +6 -7
  8. package/dist/bin/mcp-scraper-install.cjs +7 -3
  9. package/dist/bin/mcp-scraper-install.js +2 -3
  10. package/dist/bin/mcp-stdio-server.cjs +5150 -3467
  11. package/dist/bin/mcp-stdio-server.js +11 -11
  12. package/dist/bin/paa-harvest.cjs +8 -3
  13. package/dist/bin/paa-harvest.js +4 -5
  14. package/dist/{chunk-5PIO7QBG.js → chunk-3PIXKLGZ.js} +3 -4
  15. package/dist/{chunk-VIWT35S6.js → chunk-4OT7BAIE.js} +1 -2
  16. package/dist/{chunk-ORKXE7VX.js → chunk-4P3PHFPQ.js} +11 -6
  17. package/dist/{chunk-AMLFKPLL.js → chunk-75VW7CWE.js} +4 -7
  18. package/dist/{chunk-FG6LJGJ7.js → chunk-77LQV73B.js} +0 -1
  19. package/dist/{chunk-DKIG2TEE.js → chunk-AQKJOSIB.js} +2 -3
  20. package/dist/{chunk-2XUXVKT4.js → chunk-AYJHI2FK.js} +0 -1
  21. package/dist/{chunk-5BEPOFKG.js → chunk-CNLLTD5B.js} +0 -1
  22. package/dist/{chunk-EKJ65E3Z.js → chunk-DNM65UCK.js} +0 -1
  23. package/dist/{chunk-PDAKCYHZ.js → chunk-E4LMY5OJ.js} +6258 -3747
  24. package/dist/{chunk-MQGBCWZD.js → chunk-GGZEC22A.js} +64 -1
  25. package/dist/{chunk-4VG3NUUY.js → chunk-GTGSD4YS.js} +2 -2
  26. package/dist/{chunk-MQQS7ONH.js → chunk-KBTUPRTF.js} +8 -296
  27. package/dist/{chunk-XPEN6OG5.js → chunk-NS754CRS.js} +15 -3
  28. package/dist/{chunk-UN4LZVCB.js → chunk-OZJMVCDK.js} +1 -2
  29. package/dist/{chunk-342OUCSG.js → chunk-PGJQDMC2.js} +1 -2
  30. package/dist/{chunk-G3P3ZDB4.js → chunk-RJ7JVYKU.js} +0 -1
  31. package/dist/{chunk-N54JS5WP.js → chunk-TNJIPV74.js} +1 -2
  32. package/dist/{chunk-4LINSJNI.js → chunk-TNLGHNLX.js} +1 -2
  33. package/dist/chunk-VRJ7CO6L.js +6 -0
  34. package/dist/chunk-VXLU74YZ.js +293 -0
  35. package/dist/{chunk-DCWXVAQT.js → chunk-WID3MFRS.js} +6 -2
  36. package/dist/{db-BRI465XQ.js → db-PO7N7ZP3.js} +1 -2
  37. package/dist/{extract-bundle-UWKJT4MU.js → extract-bundle-SIBFUA6I.js} +8 -10
  38. package/dist/index.cjs +8 -3
  39. package/dist/index.js +4 -5
  40. package/dist/{lead-list-enrichment-repository-ODWGRVCQ.js → lead-list-enrichment-repository-OTAUQONJ.js} +2 -3
  41. package/dist/{location-data-repository-67MMEVZQ.js → location-data-repository-RM2KJ3H5.js} +3 -4
  42. package/dist/{server-RSHSZBUZ.js → server-ELEJNRRE.js} +875 -1629
  43. package/dist/{site-extract-repository-J3RH3MOS.js → site-extract-repository-ASYEJO7Z.js} +4 -5
  44. package/dist/{worker-YKRIK5LS.js → worker-MAVYYWM7.js} +8 -9
  45. package/package.json +3 -1
  46. package/dist/analytics-repository-IKE53S3E.js.map +0 -1
  47. package/dist/bin/api-server.cjs.map +0 -1
  48. package/dist/bin/api-server.js.map +0 -1
  49. package/dist/bin/mcp-scraper-cli.cjs.map +0 -1
  50. package/dist/bin/mcp-scraper-cli.js.map +0 -1
  51. package/dist/bin/mcp-scraper-install.cjs.map +0 -1
  52. package/dist/bin/mcp-scraper-install.js.map +0 -1
  53. package/dist/bin/mcp-stdio-server.cjs.map +0 -1
  54. package/dist/bin/mcp-stdio-server.js.map +0 -1
  55. package/dist/bin/paa-harvest.cjs.map +0 -1
  56. package/dist/bin/paa-harvest.js.map +0 -1
  57. package/dist/chunk-2XUXVKT4.js.map +0 -1
  58. package/dist/chunk-342OUCSG.js.map +0 -1
  59. package/dist/chunk-4LINSJNI.js.map +0 -1
  60. package/dist/chunk-4VG3NUUY.js.map +0 -1
  61. package/dist/chunk-5BEPOFKG.js.map +0 -1
  62. package/dist/chunk-5PIO7QBG.js.map +0 -1
  63. package/dist/chunk-AMLFKPLL.js.map +0 -1
  64. package/dist/chunk-CGKWNXJR.js +0 -7
  65. package/dist/chunk-CGKWNXJR.js.map +0 -1
  66. package/dist/chunk-DCWXVAQT.js.map +0 -1
  67. package/dist/chunk-DKIG2TEE.js.map +0 -1
  68. package/dist/chunk-EKJ65E3Z.js.map +0 -1
  69. package/dist/chunk-FG6LJGJ7.js.map +0 -1
  70. package/dist/chunk-G3P3ZDB4.js.map +0 -1
  71. package/dist/chunk-MQGBCWZD.js.map +0 -1
  72. package/dist/chunk-MQQS7ONH.js.map +0 -1
  73. package/dist/chunk-N54JS5WP.js.map +0 -1
  74. package/dist/chunk-ORKXE7VX.js.map +0 -1
  75. package/dist/chunk-PDAKCYHZ.js.map +0 -1
  76. package/dist/chunk-UN4LZVCB.js.map +0 -1
  77. package/dist/chunk-UVFB24RZ.js +0 -67
  78. package/dist/chunk-UVFB24RZ.js.map +0 -1
  79. package/dist/chunk-VIWT35S6.js.map +0 -1
  80. package/dist/chunk-XPEN6OG5.js.map +0 -1
  81. package/dist/db-BRI465XQ.js.map +0 -1
  82. package/dist/extract-bundle-UWKJT4MU.js.map +0 -1
  83. package/dist/index.cjs.map +0 -1
  84. package/dist/index.js.map +0 -1
  85. package/dist/lead-list-enrichment-repository-ODWGRVCQ.js.map +0 -1
  86. package/dist/location-data-repository-67MMEVZQ.js.map +0 -1
  87. package/dist/server-RSHSZBUZ.js.map +0 -1
  88. package/dist/site-extract-repository-J3RH3MOS.js.map +0 -1
  89. package/dist/worker-YKRIK5LS.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/vendor-errors.ts"],"sourcesContent":["import {\n AuthenticationError as KernelAuthenticationError,\n APIConnectionError as KernelAPIConnectionError,\n APIConnectionTimeoutError as KernelAPIConnectionTimeoutError,\n InternalServerError as KernelInternalServerError,\n PermissionDeniedError as KernelPermissionDeniedError,\n} from '@onkernel/sdk'\n\nconst BRIGHTDATA_NOT_CONFIGURED_MESSAGE = 'SERP browser service is not configured'\n\nexport function isVendorUnavailableError(err: unknown, message: string): boolean {\n return err instanceof KernelAuthenticationError\n || err instanceof KernelPermissionDeniedError\n || err instanceof KernelAPIConnectionError\n || err instanceof KernelAPIConnectionTimeoutError\n || err instanceof KernelInternalServerError\n || message === BRIGHTDATA_NOT_CONFIGURED_MESSAGE\n}\n"],"mappings":";AAAA;AAAA,EACE,uBAAuB;AAAA,EACvB,sBAAsB;AAAA,EACtB,6BAA6B;AAAA,EAC7B,uBAAuB;AAAA,EACvB,yBAAyB;AAAA,OACpB;AAEP,IAAM,oCAAoC;AAEnC,SAAS,yBAAyB,KAAc,SAA0B;AAC/E,SAAO,eAAe,6BACjB,eAAe,+BACf,eAAe,4BACf,eAAe,mCACf,eAAe,6BACf,YAAY;AACnB;","names":[]}
@@ -1,67 +0,0 @@
1
- // src/api/url-utils.ts
2
- import { isIP } from "net";
3
- import { lookup } from "dns/promises";
4
- import ipaddr from "ipaddr.js";
5
- function unbracketIpLiteral(value) {
6
- return value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
7
- }
8
- function isPrivateIpAddress(address) {
9
- const normalized = unbracketIpLiteral(address);
10
- if (!isIP(normalized)) return false;
11
- try {
12
- const parsed = ipaddr.parse(normalized);
13
- const isExtraNonGlobalIpv4 = (ipv4) => {
14
- const extraNonGlobal = [
15
- ["192.0.0.0", 24],
16
- ["192.0.2.0", 24],
17
- ["198.18.0.0", 15],
18
- ["198.51.100.0", 24],
19
- ["203.0.113.0", 24]
20
- ];
21
- return extraNonGlobal.some(([network, bits]) => ipv4.match(ipaddr.parse(network), bits));
22
- };
23
- if (parsed instanceof ipaddr.IPv6 && parsed.isIPv4MappedAddress()) {
24
- const mapped = parsed.toIPv4Address();
25
- return mapped.range() !== "unicast" || isExtraNonGlobalIpv4(mapped);
26
- }
27
- if (parsed instanceof ipaddr.IPv4) {
28
- if (isExtraNonGlobalIpv4(parsed)) return true;
29
- }
30
- return parsed.range() !== "unicast";
31
- } catch {
32
- return true;
33
- }
34
- }
35
- async function resolvesToPrivateAddress(hostname) {
36
- const host = unbracketIpLiteral(hostname.toLowerCase());
37
- if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) return true;
38
- if (isPrivateIpAddress(host)) return true;
39
- try {
40
- const addresses = await lookup(host, { all: true, verbatim: true });
41
- return addresses.length === 0 || addresses.some((entry) => isPrivateIpAddress(entry.address));
42
- } catch {
43
- return true;
44
- }
45
- }
46
- async function validatePublicHttpUrl(raw, opts) {
47
- let parsed;
48
- try {
49
- parsed = new URL(raw.trim());
50
- } catch {
51
- return { error: `Invalid ${opts.field}` };
52
- }
53
- const allowedProtocols = opts.requireHttps ? ["https:"] : ["http:", "https:"];
54
- if (!allowedProtocols.includes(parsed.protocol)) {
55
- return { error: opts.requireHttps ? `${opts.field} must use https` : `${opts.field} must use http or https` };
56
- }
57
- if (await resolvesToPrivateAddress(parsed.hostname)) {
58
- return { error: `${opts.field} must resolve to a public internet host` };
59
- }
60
- return { parsed };
61
- }
62
-
63
- export {
64
- isPrivateIpAddress,
65
- validatePublicHttpUrl
66
- };
67
- //# sourceMappingURL=chunk-UVFB24RZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/url-utils.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"],"mappings":";AAAA,SAAS,YAAY;AACrB,SAAS,cAAc;AACvB,OAAO,YAAY;AAEnB,SAAS,mBAAmB,OAAuB;AACjD,SAAO,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI;AAC7E;AAEO,SAAS,mBAAmB,SAA0B;AAC3D,QAAM,aAAa,mBAAmB,OAAO;AAC7C,MAAI,CAAC,KAAK,UAAU,EAAG,QAAO;AAC9B,MAAI;AACF,UAAM,SAAS,OAAO,MAAM,UAAU;AACtC,UAAM,uBAAuB,CAAC,SAAoD;AAChF,YAAM,iBAA0C;AAAA,QAC9C,CAAC,aAAa,EAAE;AAAA,QAChB,CAAC,aAAa,EAAE;AAAA,QAChB,CAAC,cAAc,EAAE;AAAA,QACjB,CAAC,gBAAgB,EAAE;AAAA,QACnB,CAAC,eAAe,EAAE;AAAA,MACpB;AACA,aAAO,eAAe,KAAK,CAAC,CAAC,SAAS,IAAI,MAAM,KAAK,MAAM,OAAO,MAAM,OAAO,GAAuC,IAAI,CAAC;AAAA,IAC7H;AACA,QAAI,kBAAkB,OAAO,QAAQ,OAAO,oBAAoB,GAAG;AACjE,YAAM,SAAS,OAAO,cAAc;AACpC,aAAO,OAAO,MAAM,MAAM,aAAa,qBAAqB,MAAM;AAAA,IACpE;AACA,QAAI,kBAAkB,OAAO,MAAM;AACjC,UAAI,qBAAqB,MAAM,EAAG,QAAO;AAAA,IAC3C;AAIA,WAAO,OAAO,MAAM,MAAM;AAAA,EAC5B,QAAQ;AAAE,WAAO;AAAA,EAAK;AACxB;AAEA,eAAsB,yBAAyB,UAAoC;AACjF,QAAM,OAAO,mBAAmB,SAAS,YAAY,CAAC;AACtD,MAAI,SAAS,eAAe,KAAK,SAAS,YAAY,KAAK,KAAK,SAAS,QAAQ,EAAG,QAAO;AAC3F,MAAI,mBAAmB,IAAI,EAAG,QAAO;AACrC,MAAI;AACF,UAAM,YAAY,MAAM,OAAO,MAAM,EAAE,KAAK,MAAM,UAAU,KAAK,CAAC;AAClE,WAAO,UAAU,WAAW,KAAK,UAAU,KAAK,CAAC,UAAU,mBAAmB,MAAM,OAAO,CAAC;AAAA,EAC9F,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,sBAAsB,KAAa,MAA4F;AACnJ,MAAI;AACJ,MAAI;AACF,aAAS,IAAI,IAAI,IAAI,KAAK,CAAC;AAAA,EAC7B,QAAQ;AACN,WAAO,EAAE,OAAO,WAAW,KAAK,KAAK,GAAG;AAAA,EAC1C;AACA,QAAM,mBAAmB,KAAK,eAAe,CAAC,QAAQ,IAAI,CAAC,SAAS,QAAQ;AAC5E,MAAI,CAAC,iBAAiB,SAAS,OAAO,QAAQ,GAAG;AAC/C,WAAO,EAAE,OAAO,KAAK,eAAe,GAAG,KAAK,KAAK,oBAAoB,GAAG,KAAK,KAAK,0BAA0B;AAAA,EAC9G;AACA,MAAI,MAAM,yBAAyB,OAAO,QAAQ,GAAG;AACnD,WAAO,EAAE,OAAO,GAAG,KAAK,KAAK,0CAA0C;AAAA,EACzE;AACA,SAAO,EAAE,OAAO;AAClB;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/outbound-sanitize.ts"],"sourcesContent":["import { publicErrorMessage, sanitizeVendorName } from '../errors.js'\n\nconst KEY_RENAMES: Record<string, string> = {\n kernel: 'browserRuntime',\n}\n\nconst ERROR_VALUE_KEYS = /error|message/i\nconst PRIVATE_UPSTREAM_FAILURE = /(?:spending|billing|organization|account).{0,80}(?:cap|limit|blocked|disabled)|(?:quota|capacity).{0,40}(?:reached|exceeded)|https?:\\/\\/\\S*(?:dashboard|onkernel)/i\nconst PRIVATE_RUNTIME_FAILURE = /\\b(?:ENOENT|ENOTDIR|EACCES|EPERM|EISDIR|EMFILE|ENFILE)\\b|\\b(?:mkdir|open|stat|lstat|readFile|writeFile)\\s+['\"]?(?:\\/|[A-Za-z]:\\\\)|(?:^|[\\s'\"])(?:\\/Users|\\/home|\\/tmp|\\/var|\\/private|\\/opt|\\/srv|\\/root)\\//i\nconst INTERNAL_DIAGNOSTIC_KEYS = new Set([\n 'kernel_session_id',\n 'browser_session_id',\n 'kernelSessionId',\n 'browserSessionId',\n 'sessionId',\n 'kernel_delete_started',\n 'session_cleanup_started',\n 'kernelDeleteStarted',\n 'sessionCleanupStarted',\n 'kernel_delete_succeeded',\n 'session_cleanup_succeeded',\n 'kernelDeleteSucceeded',\n 'sessionCleanupSucceeded',\n 'kernel_delete_error',\n 'session_cleanup_error',\n 'kernelDeleteError',\n 'sessionCleanupError',\n 'kernelProxyId',\n 'proxyId',\n 'requestedProxyIdSuffix',\n 'retrievedProxyIdSuffix',\n 'provider',\n 'providerName',\n 'service',\n 'serviceName',\n 'vendor',\n 'vendorName',\n 'organization',\n 'organizationId',\n 'accountId',\n])\n\nconst VENDOR_URL_KEYS = new Set([\n 'hosted_url',\n 'hostedUrl',\n 'live_view_url',\n 'liveViewUrl',\n 'cdp_ws_url',\n 'cdpWsUrl',\n 'browser_live_view_url',\n])\nconst VENDOR_URL_RE = /\\b(?:wss?|https?):\\/\\/[^\\s\"'<>]*\\bonkernel\\.com[^\\s\"'<>]*/gi\n\nfunction redactVendorUrls(value: string): string {\n return value.replace(VENDOR_URL_RE, '[browser-service]')\n}\n\nexport function sanitizeOutboundDiagnostics<T>(value: T, parentKey = ''): T {\n if (typeof value === 'string') {\n let out = redactVendorUrls(value)\n if (ERROR_VALUE_KEYS.test(parentKey) && (PRIVATE_UPSTREAM_FAILURE.test(value) || PRIVATE_RUNTIME_FAILURE.test(value))) {\n out = publicErrorMessage('service_unavailable')\n } else if (ERROR_VALUE_KEYS.test(parentKey)) {\n out = sanitizeVendorName(out)\n }\n return out as T\n }\n if (Array.isArray(value)) return value.map(v => sanitizeOutboundDiagnostics(v, parentKey)) as T\n if (value !== null && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n if (INTERNAL_DIAGNOSTIC_KEYS.has(key)) continue\n const renamed = KEY_RENAMES[key] ?? key\n if (VENDOR_URL_KEYS.has(key)) {\n out[renamed] = null\n continue\n }\n out[renamed] = sanitizeOutboundDiagnostics(val, key)\n }\n return out as T\n }\n return value\n}\n\nexport function sanitizeAttempts<T>(attempts: T[]): T[] {\n return attempts.map(a => sanitizeOutboundDiagnostics(a))\n}\n\nexport function sanitizeHarvestResult<T extends Record<string, unknown>>(result: T): T {\n const diagnostics = result?.diagnostics as Record<string, unknown> | undefined\n if (!diagnostics?.debug) return result\n return {\n ...result,\n diagnostics: {\n ...diagnostics,\n debug: sanitizeOutboundDiagnostics(diagnostics.debug),\n },\n }\n}\n"],"mappings":";;;;;;AAEA,IAAM,cAAsC;AAAA,EAC1C,QAAQ;AACV;AAEA,IAAM,mBAAmB;AACzB,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,2BAA2B,oBAAI,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,gBAAgB;AAEtB,SAAS,iBAAiB,OAAuB;AAC/C,SAAO,MAAM,QAAQ,eAAe,mBAAmB;AACzD;AAEO,SAAS,4BAA+B,OAAU,YAAY,IAAO;AAC1E,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,MAAM,iBAAiB,KAAK;AAChC,QAAI,iBAAiB,KAAK,SAAS,MAAM,yBAAyB,KAAK,KAAK,KAAK,wBAAwB,KAAK,KAAK,IAAI;AACrH,YAAM,mBAAmB,qBAAqB;AAAA,IAChD,WAAW,iBAAiB,KAAK,SAAS,GAAG;AAC3C,YAAM,mBAAmB,GAAG;AAAA,IAC9B;AACA,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,OAAK,4BAA4B,GAAG,SAAS,CAAC;AACzF,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,UAAM,MAA+B,CAAC;AACtC,eAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAgC,GAAG;AACzE,UAAI,yBAAyB,IAAI,GAAG,EAAG;AACvC,YAAM,UAAU,YAAY,GAAG,KAAK;AACpC,UAAI,gBAAgB,IAAI,GAAG,GAAG;AAC5B,YAAI,OAAO,IAAI;AACf;AAAA,MACF;AACA,UAAI,OAAO,IAAI,4BAA4B,KAAK,GAAG;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,iBAAoB,UAAoB;AACtD,SAAO,SAAS,IAAI,OAAK,4BAA4B,CAAC,CAAC;AACzD;AAEO,SAAS,sBAAyD,QAAc;AACrF,QAAM,cAAc,QAAQ;AAC5B,MAAI,CAAC,aAAa,MAAO,QAAO;AAChC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,aAAa;AAAA,MACX,GAAG;AAAA,MACH,OAAO,4BAA4B,YAAY,KAAK;AAAA,IACtD;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/webhook.ts","../src/api/harvest-problems.ts","../src/api/harvest-attempt-events.ts"],"sourcesContent":["export async function deliverWebhook(url: string, payload: object, retries = 3): Promise<void> {\n for (let attempt = 1; attempt <= retries; attempt++) {\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n signal: AbortSignal.timeout(10_000),\n })\n if (res.ok) return\n console.warn(`[webhook] attempt ${attempt} → ${res.status} from ${url}`)\n } catch (err) {\n console.warn(`[webhook] attempt ${attempt} failed:`, err instanceof Error ? err.message : err)\n }\n if (attempt < retries) await new Promise((r) => setTimeout(r, 1000 * attempt * 2))\n }\n console.error(`[webhook] gave up after ${retries} attempts for ${url}`)\n}\n","import {\n buildPublicErrorEnvelope,\n CaptchaError,\n LocationMismatchError,\n PUBLIC_SERVICE_UNAVAILABLE_MESSAGE,\n RequestAbortedError,\n type PublicChargeStatus,\n type PublicErrorDetails,\n type PublicErrorEnvelope,\n publicErrorMessage,\n} from '../errors.js'\nimport { isVendorUnavailableError } from './vendor-errors.js'\n\nexport type HarvestProblemCode =\n | 'request_aborted'\n | 'captcha_exhausted'\n | 'location_mismatch'\n | 'proxy_tunnel_failed'\n | 'proxy_unavailable'\n | 'harvest_timeout'\n | 'service_unavailable'\n | 'vendor_unavailable'\n | 'extraction_failed'\n\nexport interface HarvestProblem {\n error_code: HarvestProblemCode\n error_type: string\n message: string\n retryable: boolean\n httpStatus: number\n terminalStatus: 'cancelled' | 'failed'\n}\n\nexport interface PublicErrorContext {\n retryAfterSeconds?: number\n chargeStatus?: PublicChargeStatus\n details?: PublicErrorDetails\n}\n\nexport type PublicErrorResponse = PublicErrorEnvelope & { error: string }\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nfunction looksLikeTimeout(err: unknown, message: string): boolean {\n if (err instanceof DOMException && (err.name === 'TimeoutError' || err.name === 'AbortError')) return true\n return /timeout|timed out|Timeout \\d+ms exceeded|deadline/i.test(message)\n}\n\nfunction looksLikeCaptcha(message: string): boolean {\n return /captcha|recaptcha|unusual traffic|google\\.com\\/sorry|blocked/i.test(message)\n}\n\nfunction looksLikeProxyTunnelFailure(message: string): boolean {\n return /ERR_TUNNEL_CONNECTION_FAILED|ERR_PROXY_CONNECTION_FAILED|ERR_SOCKS_CONNECTION_FAILED|tunnel connection failed|proxy connection failed|transport error: proxy/i.test(message)\n}\n\nfunction looksLikeProxyUnavailable(message: string): boolean {\n return /proxy unavailable|proxy_unavailable|connection_test_failed|did not return a proxy id|configured fallback/i.test(message)\n}\n\nfunction looksLikeInternalServiceUnavailable(message: string): boolean {\n return /(?:spending|billing|organization|account).{0,80}(?:cap|limit|blocked|disabled)|(?:quota|capacity).{0,40}(?:reached|exceeded)|https?:\\/\\/\\S*dashboard/i.test(message)\n}\n\nexport function classifyHarvestProblem(err: unknown): HarvestProblem {\n const message = errorMessage(err)\n\n if (err instanceof RequestAbortedError) {\n return {\n error_code: 'request_aborted',\n error_type: 'request_aborted',\n message: publicErrorMessage('request_aborted'),\n retryable: true,\n httpStatus: 408,\n terminalStatus: 'cancelled',\n }\n }\n\n if (err instanceof CaptchaError || looksLikeCaptcha(message)) {\n return {\n error_code: 'captcha_exhausted',\n error_type: 'captcha',\n message: publicErrorMessage('captcha_exhausted'),\n retryable: true,\n httpStatus: 503,\n terminalStatus: 'failed',\n }\n }\n\n if (isVendorUnavailableError(err, message)) {\n return {\n error_code: 'vendor_unavailable',\n error_type: 'service_unavailable',\n message: publicErrorMessage('vendor_unavailable'),\n retryable: true,\n httpStatus: 503,\n terminalStatus: 'failed',\n }\n }\n\n if (err instanceof LocationMismatchError) {\n return {\n error_code: 'location_mismatch',\n error_type: 'location_mismatch',\n message: publicErrorMessage('location_mismatch'),\n retryable: true,\n httpStatus: 503,\n terminalStatus: 'failed',\n }\n }\n\n if (looksLikeProxyTunnelFailure(message)) {\n return {\n error_code: 'proxy_tunnel_failed',\n error_type: 'connection',\n message: publicErrorMessage('proxy_tunnel_failed'),\n retryable: true,\n httpStatus: 503,\n terminalStatus: 'failed',\n }\n }\n\n if (looksLikeProxyUnavailable(message)) {\n return {\n error_code: 'proxy_unavailable',\n error_type: 'connection',\n message: publicErrorMessage('proxy_unavailable'),\n retryable: true,\n httpStatus: 503,\n terminalStatus: 'failed',\n }\n }\n\n if (looksLikeTimeout(err, message)) {\n return {\n error_code: 'harvest_timeout',\n error_type: 'timeout',\n message: publicErrorMessage('harvest_timeout'),\n retryable: true,\n httpStatus: 504,\n terminalStatus: 'failed',\n }\n }\n\n if (looksLikeInternalServiceUnavailable(message)) {\n return {\n error_code: 'service_unavailable',\n error_type: 'service_unavailable',\n message: PUBLIC_SERVICE_UNAVAILABLE_MESSAGE,\n retryable: true,\n httpStatus: 503,\n terminalStatus: 'failed',\n }\n }\n\n return {\n error_code: 'extraction_failed',\n error_type: 'extraction',\n message: PUBLIC_SERVICE_UNAVAILABLE_MESSAGE,\n retryable: false,\n httpStatus: 500,\n terminalStatus: 'failed',\n }\n}\n\nexport function serializeHarvestProblem(problem: HarvestProblem): string {\n return JSON.stringify({\n error_code: problem.error_code,\n error_type: problem.error_type,\n message: problem.message,\n retryable: problem.retryable,\n })\n}\n\nexport function harvestProblemResponse(problem: HarvestProblem, context: PublicErrorContext = {}): PublicErrorResponse {\n const envelope = buildPublicErrorEnvelope({\n errorCode: problem.error_code,\n errorType: problem.error_type,\n retryable: problem.retryable,\n retryAfterSeconds: context.retryAfterSeconds,\n chargeStatus: context.chargeStatus,\n details: context.details,\n })\n return {\n error: envelope.message,\n ...envelope,\n }\n}\n\nexport function harvestProblemEnvelope(problem: HarvestProblem, context: PublicErrorContext = {}): PublicErrorEnvelope {\n const { error: _legacyAlias, ...envelope } = harvestProblemResponse(problem, context)\n return envelope\n}\n\n/**\n * Shared public boundary for private execution failures. Callers may attach\n * settlement state only when their own billing branch has proved it.\n */\nexport function publicErrorResponse(err: unknown, context: PublicErrorContext = {}): PublicErrorResponse {\n return harvestProblemResponse(classifyHarvestProblem(err), context)\n}\n\nexport interface PublicErrorBoundaryResult {\n body: PublicErrorResponse\n status: 408 | 500 | 503 | 504\n}\n\n/**\n * Classify an execution failure once so HTTP routes cannot drift from the\n * shared public envelope or accidentally expose the private exception text.\n */\nexport function publicErrorBoundary(err: unknown, context: PublicErrorContext = {}): PublicErrorBoundaryResult {\n const problem = classifyHarvestProblem(err)\n return {\n body: harvestProblemResponse(problem, context),\n status: problem.httpStatus as PublicErrorBoundaryResult['status'],\n }\n}\n","import type { HarvestAttemptLogEvent } from '../harvest.js'\nimport { finishHarvestAttempt, startHarvestAttempt } from './db.js'\n\nexport function createHarvestAttemptRecorder(jobId: string, userId: number | bigint) {\n return async (event: HarvestAttemptLogEvent): Promise<void> => {\n if (event.type === 'started') {\n await startHarvestAttempt({\n jobId,\n userId,\n attemptNumber: event.attemptNumber,\n maxAttempts: event.maxAttempts,\n query: event.query,\n location: event.location,\n maxQuestions: event.maxQuestions,\n startedAt: event.startedAt,\n })\n return\n }\n\n await finishHarvestAttempt({\n jobId,\n attemptNumber: event.attemptNumber,\n outcome: event.outcome,\n kernelSessionId: event.kernelSessionId,\n questionCount: event.questionCount,\n durationMs: event.durationMs,\n error: event.error,\n willRetry: event.willRetry,\n kernelDeleteStarted: event.cleanup.kernelDeleteStarted,\n kernelDeleteSucceeded: event.cleanup.kernelDeleteSucceeded,\n kernelDeleteError: event.cleanup.kernelDeleteError,\n browserCloseSucceeded: event.cleanup.browserCloseSucceeded,\n browserCloseError: event.cleanup.browserCloseError,\n debug: event.debug,\n completedAt: event.completedAt,\n })\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/extract-bundle.ts","../src/api/site-content-similarity.ts"],"sourcesContent":["import { createWriteStream, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { basename, join } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport { createGzip } from 'node:zlib'\nimport { once } from 'node:events'\nimport { finished } from 'node:stream/promises'\nimport { ZipFile } from 'yazl'\nimport pLimit from 'p-limit'\nimport { getDb } from './db.js'\nimport { computeIssues, renderIssueReport } from './seo-issues.js'\nimport { renderLinkReport, type ExtDomainRow, type LinkReport } from './seo-link-report.js'\nimport type { PageLinkMetrics } from './seo-link-graph.js'\nimport type { SeoAudit } from './seo-audit.js'\nimport type { ExtractJobArtifact, ExtractJobRow } from './site-extract-repository.js'\nimport { extractJobLimitInfo } from './site-extract-repository.js'\nimport type { PageData } from './site-extractor.js'\nimport { publicizeExtractionFailure } from './extraction-problems.js'\nimport { renderImageSection, type ImageAudit } from './image-audit.js'\nimport { downloadAsset } from '../lib/media-extractor.js'\nimport { createSiteExtractBundleArtifactStream, createSiteExtractImageArtifact } from './site-extract-artifacts.js'\nimport { createSiteExtractContentReader } from './site-extract-content-store.js'\nimport {\n analyzeSiteContentSimilarity,\n type EmbedSimilarityTexts,\n type SimilarityPageInput,\n type SiteSimilarityRow,\n} from './site-content-similarity.js'\n\nexport const SITE_EXTRACT_PAGE_CHUNK = 25\nconst MAX_IMAGES_PER_PAGE = 20\nconst MAX_IMAGES_PER_SITE = 500\nconst IMAGE_DOWNLOAD_CONCURRENCY = 8\nconst MAX_IMAGE_BYTES = 10 * 1024 * 1024\nconst MAX_SITE_IMAGE_BYTES = 100 * 1024 * 1024\nexport const MAX_ANALYZED_LINK_EDGES = 250_000\n\nfunction normalize(u: string): string {\n return u.split('#')[0].replace(/\\/$/, '')\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\nfunction safeImageFilename(url: string, index: number): string {\n try {\n const u = new URL(url)\n const base = basename(u.pathname).replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 80)\n return base || `image-${index}`\n } catch {\n return `image-${index}`\n }\n}\n\nfunction slugFactory() {\n const counts = new Map<string, number>()\n return (url: string): string => {\n const base = url.replace(/^https?:\\/\\//, '').replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 80) || 'page'\n const n = counts.get(base) ?? 0\n counts.set(base, n + 1)\n return n ? `${base}-${n}` : base\n }\n}\n\nasync function* pageChunks(jobId: string): AsyncGenerator<PageData[]> {\n const db = getDb()\n let lastRowId = 0\n for (;;) {\n const res = await db.execute({\n sql: `SELECT rowid AS cursor_id, page\n FROM site_extract_pages\n WHERE job_id = ? AND rowid > ?\n ORDER BY rowid\n LIMIT ${SITE_EXTRACT_PAGE_CHUNK}`,\n args: [jobId, lastRowId],\n })\n if (!res.rows.length) return\n lastRowId = Number(res.rows.at(-1)?.cursor_id ?? lastRowId)\n if (!Number.isSafeInteger(lastRowId) || lastRowId <= 0) throw new Error('site extract page cursor is invalid')\n yield res.rows.map(r => JSON.parse(String((r as unknown as Record<string, unknown>).page)) as PageData)\n }\n}\n\nexport interface AssembleExtras {\n branding?: unknown\n imageAudit?: ImageAudit | null\n seoAudit?: SeoAudit | null\n /** Test seam; production uses the configured Jina embedding provider. */\n embedSimilarityTexts?: EmbedSimilarityTexts\n}\n\nfunction csvCell(value: string | number | boolean | null): string {\n const text = value == null ? '' : String(value)\n return /[\",\\r\\n]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text\n}\n\nfunction similarityTableRow(row: SiteSimilarityRow): Record<string, string | number | boolean | null> {\n return {\n source_url: row.sourceUrl,\n source_title: row.sourceTitle,\n target_url: row.targetUrl,\n target_title: row.targetTitle,\n similarity: row.similarity,\n similarity_percent: row.similarityPercent,\n corpus_percentile: row.corpusPercentile,\n exact_content_duplicate: row.exactContentDuplicate,\n source_word_count: row.sourceWordCount,\n target_word_count: row.targetWordCount,\n cluster_id: row.clusterId,\n }\n}\n\nexport async function assembleExtractArtifacts(job: ExtractJobRow, extras: AssembleExtras = {}): Promise<ExtractJobArtifact[]> {\n const dir = join(tmpdir(), `extract-bundle-${job.id}-${Date.now()}`)\n const downloadImages = job.options.downloadImages === true\n if (job.userId == null) throw new Error('site extract artifact owner is missing')\n const readPageContent = createSiteExtractContentReader(String(job.userId))\n mkdirSync(dir, { recursive: true })\n if (downloadImages) mkdirSync(join(dir, 'images'), { recursive: true })\n const captureRenderedDom = job.options.captureRenderedDom === true\n const semanticSimilarity = job.options.semanticSimilarity === true\n if (captureRenderedDom) mkdirSync(join(dir, 'rendered-dom'), { recursive: true })\n try {\n const metas: PageData[] = []\n const similarityPages: SimilarityPageInput[] = []\n const renderedDomManifest: Array<{\n url: string\n path: string\n bytes: number\n truncated: boolean\n sanitized: boolean\n }> = []\n const domSlug = slugFactory()\n const pageExportEntries: Array<{\n pageId: string\n url: string\n jsonPath: string\n htmlPath: string | null\n markdownPath: string | null\n legacyMarkdownPath: string | null\n jsonSha256: string\n htmlSha256: string | null\n markdownSha256: string | null\n htmlBytes: number\n markdownBytes: number\n }> = []\n const waybackTimeline = job.options.waybackTimeline as {\n rootUrl?: string\n timeline?: { months?: string[]; from?: string; to?: string; intervalMonths?: number; urls?: string[] }\n maxPagesPerSnapshot?: number\n } | undefined\n const statusByUrl = new Map<string, number | null>()\n for await (const chunk of pageChunks(job.id)) {\n for (const p of chunk) {\n statusByUrl.set(normalize(p.url), p.status)\n // Keep only fields needed by computeIssues/renderIssueReport. Holding\n // every bounded PageData field for 10k pages can still consume\n // hundreds of MiB even though DB reads are streamed in small chunks.\n metas.push({\n url: p.url,\n status: p.status,\n title: p.title,\n titleLength: p.titleLength,\n titlePixels: p.titlePixels,\n metaDescription: p.metaDescription,\n metaDescLength: p.metaDescLength,\n h1: p.h1,\n h1_2: p.h1_2,\n h2Count: p.h2Count,\n extractionStatus: p.extractionStatus,\n indexable: p.indexable,\n indexabilityReason: p.indexabilityReason,\n canonicalUrl: p.canonicalUrl ? p.url : null,\n wordCount: p.wordCount,\n contentHash: p.contentHash,\n imagesMissingAlt: p.imagesMissingAlt,\n schemaTypes: p.schemaTypes.length > 0 ? ['present'] : [],\n outlinks: [],\n } as unknown as PageData)\n const pageId = p.pageId ?? createHash('sha256').update(p.archivedUrl ?? p.url).digest('hex')\n const pageDir = join(dir, 'pages', pageId)\n mkdirSync(pageDir, { recursive: true })\n const content = p.contentRef ? await readPageContent(p.contentRef) : null\n const html = content?.html ?? null\n const markdown = content?.markdown ?? p.bodyMarkdown ?? null\n if (semanticSimilarity && p.extractionStatus === 'successful' && markdown?.trim()) {\n similarityPages.push({\n url: p.url,\n title: p.title,\n bodyMarkdown: markdown,\n contentHash: p.contentHash,\n wordCount: p.wordCount,\n })\n }\n if (captureRenderedDom && html != null) {\n const relativePath = `rendered-dom/${domSlug(p.url)}.html.txt`\n writeFileSync(join(dir, relativePath), html)\n renderedDomManifest.push({\n url: p.url,\n path: relativePath,\n bytes: Buffer.byteLength(html),\n truncated: p.renderedDomTruncated === true,\n sanitized: p.renderedDomSanitized === true,\n })\n }\n const htmlPath = html == null ? null : `pages/${pageId}/page.html`\n const markdownPath = markdown == null ? null : `pages/${pageId}/page.md`\n const legacyMarkdownPath = markdown == null || !p.archiveRequestedMonth\n ? null\n : `pages/${p.archiveRequestedMonth}/${pageId}.md`\n if (html != null && htmlPath) writeFileSync(join(dir, htmlPath), html)\n if (markdown != null && markdownPath) writeFileSync(join(dir, markdownPath), markdown)\n if (markdown != null && legacyMarkdownPath) {\n mkdirSync(join(dir, 'pages', p.archiveRequestedMonth!), { recursive: true })\n writeFileSync(join(dir, legacyMarkdownPath), markdown)\n }\n const { bodyMarkdown: _body, contentRef: _contentRef, discoveryLinks: _discovery, ...metadata } = p\n const pageRecord = {\n version: 'site-export-page.v1',\n ...metadata,\n pageId,\n content: {\n htmlPath,\n markdownPath,\n htmlBytes: html == null ? 0 : Buffer.byteLength(html),\n markdownBytes: markdown == null ? 0 : Buffer.byteLength(markdown),\n htmlSha256: html == null ? null : createHash('sha256').update(html).digest('hex'),\n markdownSha256: markdown == null ? null : createHash('sha256').update(markdown).digest('hex'),\n },\n }\n const pageJson = JSON.stringify(pageRecord, null, 2)\n const jsonPath = `pages/${pageId}/page.json`\n writeFileSync(join(dir, jsonPath), pageJson)\n pageExportEntries.push({\n pageId,\n url: p.archivedUrl ?? p.url,\n jsonPath,\n htmlPath,\n markdownPath,\n legacyMarkdownPath,\n jsonSha256: createHash('sha256').update(pageJson).digest('hex'),\n htmlSha256: pageRecord.content.htmlSha256,\n markdownSha256: pageRecord.content.markdownSha256,\n htmlBytes: pageRecord.content.htmlBytes,\n markdownBytes: pageRecord.content.markdownBytes,\n })\n }\n }\n\n const gz = createGzip()\n const linksOut = createWriteStream(join(dir, 'links.jsonl.gz'))\n gz.pipe(linksOut)\n const gzWrite = async (line: string) => { if (!gz.write(line)) await once(gz, 'drain') }\n const schemaOut = createWriteStream(join(dir, 'schema.jsonl'))\n const schemaWrite = async (line: string) => { if (!schemaOut.write(line)) await once(schemaOut, 'drain') }\n const failuresOut = createWriteStream(join(dir, 'failures.jsonl'))\n const failureWrite = async (line: string) => { if (!failuresOut.write(line)) await once(failuresOut, 'drain') }\n\n const inboundFrom = new Map<string, Set<string>>()\n const anchorCounts = new Map<string, Map<string, number>>()\n const adjacency = new Map<string, Set<string>>()\n const outCounts = new Map<string, { int: number; ext: number }>()\n const domMap = new Map<string, { links: number; nofollow: number; pages: Set<string> }>()\n const brokenLinkPages = new Set<string>()\n let internalTotal = 0\n let externalTotal = 0\n let brokenInternal = 0\n let streamedLinkEdges = 0\n let analyzedLinkEdges = 0\n let linkAnalysisTruncated = false\n let siteReg = ''\n try { siteReg = registrableDomain(new URL(job.startUrl).hostname) } catch { siteReg = '' }\n\n const imageLimit = pLimit(IMAGE_DOWNLOAD_CONCURRENCY)\n const imageDownloads: Promise<void>[] = []\n const imageManifest: Array<{\n imageId: string\n sourcePage: string\n sourceUrl: string\n path: string | null\n status: 'not_requested' | 'downloaded' | 'failed' | 'skipped_page_limit' | 'skipped_site_limit'\n mimeType: string | null\n bytes: number | null\n sha256: string | null\n failureCode: string | null\n failureReason: string | null\n artifactId: string | null\n }> = []\n const imageArtifacts: ExtractJobArtifact[] = []\n let imagesQueued = 0\n let imagesFailed = 0\n let imageBytesDownloaded = 0\n const consumeImageBytes = (bytes: number) => {\n if (imageBytesDownloaded + bytes > MAX_SITE_IMAGE_BYTES) return false\n imageBytesDownloaded += bytes\n return true\n }\n\n for await (const chunk of pageChunks(job.id)) {\n for (const p of chunk) {\n if (p.schema?.length) await schemaWrite(JSON.stringify({ url: p.url, schema: p.schema }) + '\\n')\n if (p.extractionStatus === 'failed') {\n const { failureCode, failureReason } = publicizeExtractionFailure(p.failureCode, p.failureReason)\n await failureWrite(JSON.stringify({\n url: p.url,\n status: p.status,\n via: p.via,\n failureCode,\n failureReason,\n fetchAttempts: p.fetchAttempts ?? [],\n }) + '\\n')\n }\n if (p.imageLinks?.length) {\n for (const [idx, imgUrl] of p.imageLinks.entries()) {\n const imageId = createHash('sha256').update(`${p.url}\\0${imgUrl}`).digest('hex')\n const record: (typeof imageManifest)[number] = {\n imageId,\n sourcePage: p.url,\n sourceUrl: imgUrl,\n path: null,\n status: 'not_requested',\n mimeType: null,\n bytes: null,\n sha256: null,\n failureCode: null,\n failureReason: null,\n artifactId: null,\n }\n imageManifest.push(record)\n if (!downloadImages) continue\n if (idx >= MAX_IMAGES_PER_PAGE) {\n record.status = 'skipped_page_limit'\n record.failureCode = 'page_image_limit'\n record.failureReason = `Only the first ${MAX_IMAGES_PER_PAGE} image candidates are downloaded per page.`\n continue\n }\n if (imagesQueued >= MAX_IMAGES_PER_SITE) {\n record.status = 'skipped_site_limit'\n record.failureCode = 'site_image_limit'\n record.failureReason = `Only the first ${MAX_IMAGES_PER_SITE} image candidates are downloaded per site.`\n continue\n }\n imagesQueued++\n const filename = `${imageId}-${safeImageFilename(imgUrl, idx)}`\n const outputPath = join(dir, 'images')\n imageDownloads.push(\n imageLimit(() => downloadAsset(imgUrl, outputPath, filename, {\n expectedType: 'image',\n maxBytes: MAX_IMAGE_BYTES,\n consumeBytes: consumeImageBytes,\n })).then(async result => {\n const bytes = readFileSync(result.savedPath)\n const artifact = await createSiteExtractImageArtifact({\n ownerId: String(job.userId),\n jobId: job.id,\n imageId,\n filename,\n contentType: result.mimeType ?? 'application/octet-stream',\n content: bytes,\n sourceUrl: imgUrl,\n sourcePage: p.url,\n })\n imageArtifacts.push(artifact)\n record.status = 'downloaded'\n record.path = `images/${filename}`\n record.artifactId = artifact.key\n record.mimeType = result.mimeType\n record.bytes = result.sizeBytes\n record.sha256 = createHash('sha256').update(bytes).digest('hex')\n }, error => {\n imagesFailed++\n record.status = 'failed'\n record.failureCode = 'image_download_failed'\n record.failureReason = (error instanceof Error ? error.message : String(error)).replace(/\\s+/g, ' ').slice(0, 500)\n }),\n )\n }\n }\n const from = normalize(p.url)\n const oc = { int: 0, ext: 0 }\n for (const l of p.outlinks ?? []) {\n const nofollow = (l.rel ?? '').split(/\\s+/).includes('nofollow')\n const to = normalize(l.href)\n const targetStatus = statusByUrl.get(to) ?? null\n await gzWrite(JSON.stringify({ from: p.url, to: l.href, anchor: l.anchor, rel: l.rel, internal: l.internal, nofollow, targetStatus }) + '\\n')\n streamedLinkEdges++\n if (analyzedLinkEdges >= MAX_ANALYZED_LINK_EDGES) {\n linkAnalysisTruncated = true\n continue\n }\n analyzedLinkEdges++\n if (l.internal) {\n oc.int++\n internalTotal++\n if (!inboundFrom.has(to)) inboundFrom.set(to, new Set())\n inboundFrom.get(to)!.add(from)\n if (l.anchor) {\n if (!anchorCounts.has(to)) anchorCounts.set(to, new Map())\n const ac = anchorCounts.get(to)!\n ac.set(l.anchor, (ac.get(l.anchor) ?? 0) + 1)\n }\n if (!nofollow && (statusByUrl.get(to) === 200 || !statusByUrl.has(to))) {\n if (!adjacency.has(from)) adjacency.set(from, new Set())\n adjacency.get(from)!.add(to)\n }\n if (targetStatus != null && targetStatus >= 400) {\n brokenInternal++\n brokenLinkPages.add(p.url)\n }\n } else {\n oc.ext++\n let domain = ''\n try { domain = registrableDomain(new URL(l.href).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 (nofollow) d.nofollow++\n d.pages.add(p.url)\n domMap.set(domain, d)\n }\n }\n outCounts.set(p.url, oc)\n }\n }\n const outputFinished = Promise.all([finished(linksOut), finished(schemaOut), finished(failuresOut)])\n gz.end()\n schemaOut.end()\n failuresOut.end()\n await outputFinished\n await Promise.all(imageDownloads)\n\n const depth = new Map<string, number>()\n const start = normalize(job.startUrl)\n depth.set(start, 0)\n const queue: string[] = [start]\n while (queue.length > 0) {\n const cur = queue.shift()!\n const d = depth.get(cur)!\n for (const next of adjacency.get(cur) ?? []) {\n if (!depth.has(next)) { depth.set(next, d + 1); queue.push(next) }\n }\n }\n\n const metrics = new Map<string, PageLinkMetrics>()\n for (const p of metas) {\n const key = normalize(p.url)\n const inbound = inboundFrom.get(key) ?? new Set()\n const ac = anchorCounts.get(key)\n const topAnchors = ac\n ? [...ac.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(e => e[0])\n : []\n const oc = outCounts.get(p.url) ?? { int: 0, ext: 0 }\n metrics.set(p.url, {\n url: p.url,\n inlinks: inbound.size,\n uniqueInlinks: inbound.size,\n outlinksInternal: oc.int,\n outlinksExternal: oc.ext,\n crawlDepth: depth.has(key) ? depth.get(key)! : null,\n orphan: inbound.size === 0 && key !== start,\n topAnchors,\n })\n }\n\n const issues = computeIssues(metas, metrics, brokenLinkPages)\n let reportMd = renderIssueReport(job.startUrl, metas, issues, metrics)\n const limits = extractJobLimitInfo(job)\n const crawlSummary = {\n jobId: job.id,\n startUrl: job.startUrl,\n status: job.successfulUrls === 0\n ? 'failed'\n : job.failedUrls > 0 || job.remainingUrls > 0 || limits.creditTruncated\n ? 'partial'\n : 'complete',\n ...limits,\n discovered: job.totalUrls,\n attempted: job.attemptedUrls,\n successful: job.successfulUrls,\n failed: job.failedUrls,\n remaining: job.remainingUrls,\n linkAnalysis: {\n truncated: linkAnalysisTruncated,\n analyzedEdges: analyzedLinkEdges,\n streamedEdges: streamedLinkEdges,\n edgeCap: MAX_ANALYZED_LINK_EDGES,\n },\n generatedAt: new Date().toISOString(),\n }\n reportMd = [\n `## Crawl delivery`,\n `- Discovered: ${crawlSummary.discovered}`,\n `- Attempted: ${crawlSummary.attempted}`,\n `- Successful: ${crawlSummary.successful}`,\n `- Failed: ${crawlSummary.failed}`,\n `- Remaining: ${crawlSummary.remaining}`,\n `- Requested page cap: ${limits.requestedMaxPages}`,\n `- Funded page cap: ${limits.effectiveMaxPages}`,\n `- Credit-truncated: ${limits.creditTruncated ? 'yes' : 'no'}`,\n `- Link analysis: ${analyzedLinkEdges}/${streamedLinkEdges} edges${linkAnalysisTruncated ? ` (capped at ${MAX_ANALYZED_LINK_EDGES})` : ''}`,\n '',\n reportMd,\n ].join('\\n')\n if (extras.imageAudit) reportMd += `\\n\\n${renderImageSection(extras.imageAudit)}`\n\n const metricValues = [...metrics.values()]\n const round = (n: number) => Math.round(n * 10) / 10\n const distribution = { zero: 0, oneToTwo: 0, threeToTen: 0, elevenPlus: 0 }\n let sumInlinks = 0\n let sumOutlinks = 0\n for (const m of metricValues) {\n sumInlinks += m.inlinks\n sumOutlinks += m.outlinksInternal + m.outlinksExternal\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 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 const linkReport: LinkReport = {\n summary: {\n internal: {\n totalLinks: internalTotal,\n pages: metas.length,\n orphans: metricValues.filter(m => m.orphan).length,\n brokenInternal,\n avgInlinks: metas.length ? round(sumInlinks / metas.length) : 0,\n avgOutlinks: metas.length ? round(sumOutlinks / metas.length) : 0,\n distribution,\n topByInlinks: [...metricValues].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 external: {\n totalLinks: externalTotal,\n uniqueDomains: externalDomains.length,\n topDomains: externalDomains.slice(0, 20),\n },\n },\n externalDomains,\n }\n\n const pagesOut = createWriteStream(join(dir, 'pages.jsonl'))\n const pageExportById = new Map(pageExportEntries.map(entry => [entry.pageId, entry]))\n const captureMatrixOut = waybackTimeline\n ? createWriteStream(join(dir, 'capture-matrix.jsonl'))\n : null\n const capturedCells = new Set<string>()\n const captureCellKey = (month: string | null | undefined, url: string) => {\n let normalized = url\n try { normalized = new URL(url).href } catch { /** Keep the bounded stored value. */ }\n return `${month ?? ''}\\0${normalized}`\n }\n for await (const chunk of pageChunks(job.id)) {\n for (const page of chunk) {\n const publicFailure = page.extractionStatus === 'failed'\n ? publicizeExtractionFailure(page.failureCode, page.failureReason)\n : { failureCode: null, failureReason: null }\n const { bodyMarkdown: _body, schema: _schema, outlinks: _outlinks, contentRef: _contentRef, ...boundedPage } = page\n const m = metrics.get(page.url)\n const exported = page.pageId ? pageExportById.get(page.pageId) : undefined\n const row = {\n ...boundedPage,\n ...(page.extractionStatus === 'failed' ? publicFailure : {}),\n representations: exported ? {\n jsonPath: exported.jsonPath,\n htmlPath: exported.htmlPath,\n markdownPath: exported.markdownPath,\n jsonSha256: exported.jsonSha256,\n htmlSha256: exported.htmlSha256,\n markdownSha256: exported.markdownSha256,\n htmlBytes: exported.htmlBytes,\n markdownBytes: exported.markdownBytes,\n } : null,\n inlinks: m?.inlinks ?? 0,\n crawlDepth: m?.crawlDepth ?? null,\n orphan: m?.orphan ?? false,\n }\n if (!pagesOut.write(JSON.stringify(row) + '\\n')) await once(pagesOut, 'drain')\n if (captureMatrixOut) {\n const cellKey = captureCellKey(page.archiveRequestedMonth, page.originalUrl ?? page.url)\n capturedCells.add(cellKey)\n const captureRow = {\n requestedMonth: page.archiveRequestedMonth ?? null,\n captureTimestamp: page.archiveTimestamp ?? null,\n originalUrl: page.originalUrl ?? page.url,\n archivedUrl: page.archivedUrl ?? null,\n status: page.extractionStatus === 'successful' ? 'captured' : 'failed',\n httpStatus: page.status,\n contentHash: page.contentHash || null,\n wordCount: page.wordCount,\n failureCode: publicFailure.failureCode,\n failureReason: publicFailure.failureReason,\n }\n if (!captureMatrixOut.write(JSON.stringify(captureRow) + '\\n')) await once(captureMatrixOut, 'drain')\n }\n }\n }\n if (captureMatrixOut && waybackTimeline?.timeline?.urls) {\n const timeline = waybackTimeline.timeline\n const requestedUrls = timeline.urls!\n const months = (() => {\n if (timeline.months?.length) return [...new Set(timeline.months)].sort()\n if (!timeline.from || !timeline.to) return []\n const values: string[] = []\n const cursor = new Date(`${timeline.from}-01T00:00:00Z`)\n const end = new Date(`${timeline.to}-01T00:00:00Z`)\n while (cursor <= end && values.length < 60) {\n values.push(`${cursor.getUTCFullYear()}-${String(cursor.getUTCMonth() + 1).padStart(2, '0')}`)\n cursor.setUTCMonth(cursor.getUTCMonth() + (timeline.intervalMonths ?? 1))\n }\n return values\n })()\n for (const requestedMonth of months) {\n for (const originalUrl of requestedUrls) {\n if (capturedCells.has(captureCellKey(requestedMonth, originalUrl))) continue\n if (!captureMatrixOut.write(JSON.stringify({\n requestedMonth,\n captureTimestamp: null,\n originalUrl,\n archivedUrl: null,\n status: 'missing',\n httpStatus: null,\n contentHash: null,\n wordCount: 0,\n failureCode: 'wayback_capture_missing',\n failureReason: 'No successful HTML capture was available in the requested month.',\n }) + '\\n')) await once(captureMatrixOut, 'drain')\n }\n }\n }\n const pagesFinished = finished(pagesOut)\n const captureMatrixFinished = captureMatrixOut ? finished(captureMatrixOut) : Promise.resolve()\n pagesOut.end()\n captureMatrixOut?.end()\n await Promise.all([pagesFinished, captureMatrixFinished])\n\n if (captureRenderedDom) {\n writeFileSync(\n join(dir, 'rendered-dom', 'manifest.jsonl'),\n renderedDomManifest.map(row => JSON.stringify(row)).join('\\n'),\n )\n }\n\n if (semanticSimilarity) {\n const analysis = await analyzeSiteContentSimilarity(similarityPages, {\n threshold: Number(job.options.similarityThreshold ?? undefined),\n maxPairs: Number(job.options.similarityMaxPairs ?? undefined),\n embedTexts: extras.embedSimilarityTexts,\n })\n const tableRows = analysis.rows.map(similarityTableRow)\n const columns = tableRows.length > 0 ? Object.keys(tableRows[0]) : [\n 'source_url',\n 'source_title',\n 'target_url',\n 'target_title',\n 'similarity',\n 'similarity_percent',\n 'corpus_percentile',\n 'exact_content_duplicate',\n 'source_word_count',\n 'target_word_count',\n 'cluster_id',\n ]\n const csv = [\n columns.join(','),\n ...tableRows.map(row => columns.map(column => csvCell(row[column] ?? null)).join(',')),\n ].join('\\n') + '\\n'\n const { rows: _rows, clusters: _clusters, ...summary } = analysis\n writeFileSync(join(dir, 'similarity-table.csv'), csv)\n writeFileSync(join(dir, 'similarity.jsonl'), tableRows.map(row => JSON.stringify(row)).join('\\n'))\n writeFileSync(join(dir, 'similarity-table-schema.json'), JSON.stringify({\n tableNameSuggestion: `site_similarity_${new URL(job.startUrl).hostname.replace(/[^a-z0-9]+/gi, '_').replace(/^_+|_+$/g, '').toLowerCase()}`,\n defaultSort: [{ column: 'similarity', direction: 'desc' }],\n columns: {\n source_url: 'text',\n source_title: 'text',\n target_url: 'text',\n target_title: 'text',\n similarity: 'number',\n similarity_percent: 'number',\n corpus_percentile: 'number',\n exact_content_duplicate: 'boolean',\n source_word_count: 'integer',\n target_word_count: 'integer',\n cluster_id: 'text',\n },\n }, null, 2))\n writeFileSync(join(dir, 'similarity-summary.json'), JSON.stringify(summary, null, 2))\n writeFileSync(join(dir, 'content-clusters.json'), JSON.stringify(analysis.clusters, null, 2))\n reportMd += [\n '',\n '## Rendered content similarity',\n `- Compared pages: ${analysis.comparedPages}`,\n `- Raw cosine threshold: ${analysis.threshold}`,\n `- Corpus score distribution: min ${analysis.scoreDistribution.min ?? 'n/a'} / median ${analysis.scoreDistribution.median ?? 'n/a'} / p90 ${analysis.scoreDistribution.p90 ?? 'n/a'} / max ${analysis.scoreDistribution.max ?? 'n/a'}`,\n `- Qualifying pairs: ${analysis.qualifyingPairs}`,\n `- Returned table rows: ${analysis.returnedPairs}${analysis.pairsTruncated ? ' (capped)' : ''}`,\n `- Multi-page clusters: ${analysis.clusters.length}`,\n `- Embedding model: ${analysis.model} (${analysis.dimensions} dimensions)`,\n `- Corpus boilerplate removed: ${analysis.boilerplateRemoval.removedBlockSignatures} repeated block signatures / ${analysis.boilerplateRemoval.removedCharacters} characters`,\n `- Corpus SHA-256: ${analysis.corpusSha256}`,\n ].join('\\n')\n }\n\n writeFileSync(join(dir, 'report.md'), reportMd)\n writeFileSync(join(dir, 'crawl-summary.json'), JSON.stringify(crawlSummary, null, 2))\n writeFileSync(join(dir, 'images-manifest.jsonl'), imageManifest.map(record => JSON.stringify(record)).join('\\n'))\n writeFileSync(join(dir, 'manifest.json'), JSON.stringify({\n version: 'site-export.v1',\n jobId: job.id,\n startUrl: job.startUrl,\n generatedAt: crawlSummary.generatedAt,\n outputProfile: {\n json: true,\n html: true,\n markdown: true,\n imageManifest: true,\n imageBytes: downloadImages,\n },\n pages: [...pageExportEntries].sort((a, b) => a.pageId.localeCompare(b.pageId)),\n imagesManifestPath: 'images-manifest.jsonl',\n download: 'This ZIP is the complete human export. AI clients should use site_export_read and site_export_image.',\n }, null, 2))\n if (waybackTimeline) {\n writeFileSync(join(dir, 'wayback-manifest.json'), JSON.stringify({\n rootUrl: waybackTimeline.rootUrl ?? job.startUrl,\n requested: waybackTimeline.timeline ?? null,\n maxPagesPerSnapshot: waybackTimeline.maxPagesPerSnapshot ?? null,\n captureMatrix: 'capture-matrix.jsonl',\n }, null, 2))\n }\n writeFileSync(join(dir, 'issues.json'), JSON.stringify(issues, null, 2))\n writeFileSync(join(dir, 'link-metrics.jsonl'), metricValues.map(m => JSON.stringify(m)).join('\\n'))\n writeFileSync(join(dir, 'link-report.md'), renderLinkReport(linkReport))\n writeFileSync(join(dir, 'links-summary.json'), JSON.stringify(linkReport.summary, null, 2))\n writeFileSync(join(dir, 'external-domains.json'), JSON.stringify(linkReport.externalDomains, null, 2))\n if (extras.imageAudit) {\n writeFileSync(join(dir, 'images.jsonl'), extras.imageAudit.rows.map(r => JSON.stringify(r)).join('\\n'))\n writeFileSync(join(dir, 'images-summary.json'), JSON.stringify(extras.imageAudit.summary, null, 2))\n }\n if (extras.seoAudit) writeFileSync(join(dir, 'seo-audit.json'), JSON.stringify(extras.seoAudit, null, 2))\n if (extras.branding) writeFileSync(join(dir, 'branding.json'), JSON.stringify(extras.branding, null, 2))\n if (downloadImages) {\n writeFileSync(join(dir, 'images-download-summary.json'), JSON.stringify({\n queued: imagesQueued,\n downloaded: imagesQueued - imagesFailed,\n failed: imagesFailed,\n downloadedBytes: imageBytesDownloaded,\n perPageCap: MAX_IMAGES_PER_PAGE,\n perSiteCap: MAX_IMAGES_PER_SITE,\n perFileByteCap: MAX_IMAGE_BYTES,\n totalByteCap: MAX_SITE_IMAGE_BYTES,\n }, null, 2))\n }\n\n const artifactFiles: Array<{ name: string; type: string }> = [\n { name: 'manifest.json', type: 'application/json' },\n { name: 'images-manifest.jsonl', type: 'application/x-ndjson' },\n { name: 'report.md', type: 'text/markdown' },\n { name: 'crawl-summary.json', type: 'application/json' },\n { name: 'failures.jsonl', type: 'application/x-ndjson' },\n { name: 'schema.jsonl', type: 'application/x-ndjson' },\n { name: 'issues.json', type: 'application/json' },\n { name: 'pages.jsonl', type: 'application/x-ndjson' },\n { name: 'links.jsonl.gz', type: 'application/gzip' },\n { name: 'link-metrics.jsonl', type: 'application/x-ndjson' },\n { name: 'link-report.md', type: 'text/markdown' },\n { name: 'links-summary.json', type: 'application/json' },\n { name: 'external-domains.json', type: 'application/json' },\n ]\n if (captureRenderedDom) {\n artifactFiles.push({ name: 'rendered-dom/manifest.jsonl', type: 'application/x-ndjson' })\n for (const row of renderedDomManifest) artifactFiles.push({ name: row.path, type: 'text/plain' })\n }\n if (semanticSimilarity) {\n artifactFiles.push({ name: 'similarity-table.csv', type: 'text/csv' })\n artifactFiles.push({ name: 'similarity.jsonl', type: 'application/x-ndjson' })\n artifactFiles.push({ name: 'similarity-table-schema.json', type: 'application/json' })\n artifactFiles.push({ name: 'similarity-summary.json', type: 'application/json' })\n artifactFiles.push({ name: 'content-clusters.json', type: 'application/json' })\n }\n if (waybackTimeline) {\n artifactFiles.push({ name: 'wayback-manifest.json', type: 'application/json' })\n artifactFiles.push({ name: 'capture-matrix.jsonl', type: 'application/x-ndjson' })\n }\n if (extras.imageAudit) {\n artifactFiles.push({ name: 'images.jsonl', type: 'application/x-ndjson' })\n artifactFiles.push({ name: 'images-summary.json', type: 'application/json' })\n }\n if (extras.seoAudit) artifactFiles.push({ name: 'seo-audit.json', type: 'application/json' })\n if (extras.branding) artifactFiles.push({ name: 'branding.json', type: 'application/json' })\n if (downloadImages) artifactFiles.push({ name: 'images-download-summary.json', type: 'application/json' })\n\n const zip = new ZipFile()\n const artifactPromise = createSiteExtractBundleArtifactStream({\n ownerId: String(job.userId),\n jobId: job.id,\n // Artifact retention starts when this bundle is assembled, including a\n // later support re-finalization, rather than when the crawl was queued.\n createdAt: new Date(),\n content: zip.outputStream,\n })\n for (const f of artifactFiles) zip.addFile(join(dir, f.name), f.name)\n const orderedPageEntries = [...pageExportEntries].sort((a, b) => a.pageId.localeCompare(b.pageId))\n for (const entry of orderedPageEntries) if (entry.markdownPath) zip.addFile(join(dir, entry.markdownPath), entry.markdownPath)\n for (const entry of orderedPageEntries) if (entry.legacyMarkdownPath) zip.addFile(join(dir, entry.legacyMarkdownPath), entry.legacyMarkdownPath)\n for (const entry of orderedPageEntries) if (entry.htmlPath) zip.addFile(join(dir, entry.htmlPath), entry.htmlPath)\n for (const entry of orderedPageEntries) zip.addFile(join(dir, entry.jsonPath), entry.jsonPath)\n if (downloadImages && imagesQueued > imagesFailed) {\n const imagesDir = join(dir, 'images')\n for (const rel of readdirSync(imagesDir, { recursive: true }) as string[]) {\n const full = join(imagesDir, rel)\n if (statSync(full).isFile()) zip.addFile(full, `images/${rel.split('\\\\').join('/')}`)\n }\n }\n zip.end()\n return [await artifactPromise, ...imageArtifacts]\n } finally {\n rmSync(dir, { recursive: true, force: true })\n }\n}\n","import { createHash } from 'node:crypto'\nimport { commonsEmbedDim, commonsEmbedModel, embedCommonsTexts } from './commons-embeddings.js'\n\nexport const MAX_SIMILARITY_PAGES = 500\nexport const DEFAULT_SIMILARITY_THRESHOLD = 0.9\nexport const DEFAULT_SIMILARITY_MAX_PAIRS = 10_000\nexport const MAX_SIMILARITY_PAIRS = 50_000\n\nexport interface SimilarityPageInput {\n url: string\n title: string | null\n bodyMarkdown: string\n contentHash: string\n wordCount: number\n}\n\nexport interface SiteSimilarityRow {\n sourceUrl: string\n sourceTitle: string | null\n targetUrl: string\n targetTitle: string | null\n similarity: number\n similarityPercent: number\n corpusPercentile: number\n exactContentDuplicate: boolean\n sourceWordCount: number\n targetWordCount: number\n clusterId: string | null\n}\n\nexport interface SiteSimilarityCluster {\n clusterId: string\n pageCount: number\n urls: string[]\n}\n\nexport interface SiteSimilarityAnalysis {\n generatedAt: string\n provider: 'jina'\n model: string\n dimensions: number\n threshold: number\n requestedMaxPairs: number\n comparedPages: number\n possiblePairs: number\n qualifyingPairs: number\n returnedPairs: number\n pairsTruncated: boolean\n corpusSha256: string\n analysisSha256: string\n scoreDistribution: {\n min: number | null\n p25: number | null\n median: number | null\n p75: number | null\n p90: number | null\n max: number | null\n }\n boilerplateRemoval: {\n method: 'corpus_repeated_markdown_blocks'\n minimumPageCount: number | null\n removedBlockSignatures: number\n removedCharacters: number\n }\n rows: SiteSimilarityRow[]\n clusters: SiteSimilarityCluster[]\n}\n\nexport type EmbedSimilarityTexts = (texts: string[]) => Promise<number[][]>\n\nfunction round(value: number, places: number): number {\n const scale = 10 ** places\n return Math.round(value * scale) / scale\n}\n\nexport function cosineSimilarity(a: number[], b: number[]): number {\n if (a.length === 0 || a.length !== b.length) throw new Error('Similarity vectors must have the same non-zero dimension.')\n let dot = 0\n let normA = 0\n let normB = 0\n for (let index = 0; index < a.length; index++) {\n dot += a[index] * b[index]\n normA += a[index] * a[index]\n normB += b[index] * b[index]\n }\n if (normA === 0 || normB === 0) return 0\n return Math.max(-1, Math.min(1, dot / (Math.sqrt(normA) * Math.sqrt(normB))))\n}\n\nfunction corpusHash(pages: SimilarityPageInput[]): string {\n const digest = createHash('sha256')\n for (const page of [...pages].sort((a, b) => a.url.localeCompare(b.url))) {\n digest.update(page.url)\n digest.update('\\0')\n digest.update(page.contentHash)\n digest.update('\\0')\n }\n return digest.digest('hex')\n}\n\nfunction markdownBlockSignature(block: string): string | null {\n const normalized = block\n .replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/\\[([^\\]]+)\\]\\([^)]*\\)/g, '$1')\n .replace(/https?:\\/\\/\\S+/gi, ' ')\n .replace(/&(?:amp|nbsp|quot|#39);/gi, ' ')\n .replace(/[#>*_`~|\\\\-]+/g, ' ')\n .replace(/[^\\p{L}\\p{N}]+/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .toLowerCase()\n return normalized.length >= 12 ? normalized : null\n}\n\nfunction prepareEmbeddingTexts(pages: SimilarityPageInput[]): {\n texts: string[]\n minimumPageCount: number | null\n removedBlockSignatures: number\n removedCharacters: number\n} {\n const blocksByPage = pages.map(page => page.bodyMarkdown.split(/\\n{2,}/).map(block => block.trim()).filter(Boolean))\n const minimumPageCount = pages.length >= 4 ? Math.max(3, Math.ceil(pages.length * 0.5)) : null\n const pageFrequency = new Map<string, number>()\n for (const blocks of blocksByPage) {\n const pageSignatures = new Set(blocks.map(markdownBlockSignature).filter((value): value is string => Boolean(value)))\n for (const signature of pageSignatures) pageFrequency.set(signature, (pageFrequency.get(signature) ?? 0) + 1)\n }\n const repeated = new Set<string>()\n if (minimumPageCount != null) {\n for (const [signature, count] of pageFrequency) {\n if (count >= minimumPageCount) repeated.add(signature)\n }\n }\n let removedCharacters = 0\n const texts = pages.map((page, pageIndex) => {\n const kept: string[] = []\n for (const block of blocksByPage[pageIndex]) {\n const signature = markdownBlockSignature(block)\n if (signature && repeated.has(signature)) {\n removedCharacters += block.length\n continue\n }\n kept.push(block)\n }\n const cleaned = kept.join('\\n\\n').trim()\n const content = cleaned.length >= 60 ? cleaned : page.bodyMarkdown\n return `${page.title?.trim() || 'Untitled page'}\\n\\n${content}`\n })\n return {\n texts,\n minimumPageCount,\n removedBlockSignatures: repeated.size,\n removedCharacters,\n }\n}\n\nclass DisjointSet {\n private readonly parent: number[]\n\n constructor(size: number) {\n this.parent = Array.from({ length: size }, (_, index) => index)\n }\n\n find(value: number): number {\n const parent = this.parent[value]\n if (parent !== value) this.parent[value] = this.find(parent)\n return this.parent[value]\n }\n\n union(a: number, b: number): void {\n const rootA = this.find(a)\n const rootB = this.find(b)\n if (rootA !== rootB) this.parent[rootB] = rootA\n }\n}\n\nexport async function analyzeSiteContentSimilarity(\n pages: SimilarityPageInput[],\n options: {\n threshold?: number\n maxPairs?: number\n embedTexts?: EmbedSimilarityTexts\n model?: string\n dimensions?: number\n } = {},\n): Promise<SiteSimilarityAnalysis> {\n const eligible = pages\n .filter(page => page.bodyMarkdown.trim().length > 0)\n .slice(0, MAX_SIMILARITY_PAGES)\n const requestedThreshold = Number.isFinite(options.threshold) ? options.threshold! : DEFAULT_SIMILARITY_THRESHOLD\n const requestedMaxPairs = Number.isFinite(options.maxPairs) ? options.maxPairs! : DEFAULT_SIMILARITY_MAX_PAIRS\n const threshold = Math.max(0, Math.min(1, requestedThreshold))\n const maxPairs = Math.max(1, Math.min(MAX_SIMILARITY_PAIRS, Math.floor(requestedMaxPairs)))\n const model = options.model ?? commonsEmbedModel()\n const dimensions = options.dimensions ?? commonsEmbedDim()\n const embedTexts = options.embedTexts ?? embedCommonsTexts\n const prepared = prepareEmbeddingTexts(eligible)\n const uniqueTexts: string[] = []\n const textIndexByHash = new Map<string, number>()\n const pageTextIndexes: number[] = []\n\n for (const [pageIndex, page] of eligible.entries()) {\n const key = page.contentHash || createHash('sha256').update(page.bodyMarkdown).digest('hex')\n let textIndex = textIndexByHash.get(key)\n if (textIndex == null) {\n textIndex = uniqueTexts.length\n textIndexByHash.set(key, textIndex)\n uniqueTexts.push(prepared.texts[pageIndex])\n }\n pageTextIndexes.push(textIndex)\n }\n\n const uniqueVectors: number[][] = []\n for (let offset = 0; offset < uniqueTexts.length; offset += 64) {\n uniqueVectors.push(...await embedTexts(uniqueTexts.slice(offset, offset + 64)))\n }\n if (uniqueVectors.length !== uniqueTexts.length) {\n throw new Error(`Embedding provider returned ${uniqueVectors.length} vectors for ${uniqueTexts.length} unique page bodies.`)\n }\n\n const vectors = pageTextIndexes.map(index => uniqueVectors[index])\n const sets = new DisjointSet(eligible.length)\n const allScores: number[] = []\n const qualifying: Array<{ source: number; target: number; score: number }> = []\n for (let source = 0; source < eligible.length; source++) {\n for (let target = source + 1; target < eligible.length; target++) {\n const score = cosineSimilarity(vectors[source], vectors[target])\n allScores.push(score)\n if (score < threshold) continue\n qualifying.push({ source, target, score })\n sets.union(source, target)\n }\n }\n qualifying.sort((a, b) => b.score - a.score\n || eligible[a.source].url.localeCompare(eligible[b.source].url)\n || eligible[a.target].url.localeCompare(eligible[b.target].url))\n const sortedScores = [...allScores].sort((a, b) => a - b)\n const quantile = (value: number): number | null => {\n if (!sortedScores.length) return null\n return round(sortedScores[Math.floor((sortedScores.length - 1) * value)], 6)\n }\n\n const membersByRoot = new Map<number, number[]>()\n for (let index = 0; index < eligible.length; index++) {\n const root = sets.find(index)\n const members = membersByRoot.get(root) ?? []\n members.push(index)\n membersByRoot.set(root, members)\n }\n const clusterIdByPage = new Map<number, string>()\n const clusters = [...membersByRoot.values()]\n .filter(members => members.length > 1)\n .sort((a, b) => b.length - a.length || eligible[a[0]].url.localeCompare(eligible[b[0]].url))\n .map((members, index) => {\n const clusterId = `cluster-${String(index + 1).padStart(3, '0')}`\n for (const member of members) clusterIdByPage.set(member, clusterId)\n return {\n clusterId,\n pageCount: members.length,\n urls: members.map(member => eligible[member].url).sort(),\n }\n })\n\n const rows = qualifying.slice(0, maxPairs).map((pair, pairIndex) => {\n const source = eligible[pair.source]\n const target = eligible[pair.target]\n const similarity = round(pair.score, 6)\n return {\n sourceUrl: source.url,\n sourceTitle: source.title,\n targetUrl: target.url,\n targetTitle: target.title,\n similarity,\n similarityPercent: round(similarity * 100, 2),\n corpusPercentile: sortedScores.length <= 1\n ? 100\n : round((1 - pairIndex / (sortedScores.length - 1)) * 100, 2),\n exactContentDuplicate: Boolean(source.contentHash && source.contentHash === target.contentHash),\n sourceWordCount: source.wordCount,\n targetWordCount: target.wordCount,\n clusterId: clusterIdByPage.get(pair.source) ?? null,\n }\n })\n const corpusSha256 = corpusHash(eligible)\n const analysisSha256 = createHash('sha256')\n .update(JSON.stringify({\n corpusSha256,\n model,\n dimensions,\n threshold,\n maxPairs,\n boilerplateRemoval: {\n method: 'corpus_repeated_markdown_blocks',\n minimumPageCount: prepared.minimumPageCount,\n removedBlockSignatures: prepared.removedBlockSignatures,\n },\n }))\n .digest('hex')\n\n return {\n generatedAt: new Date().toISOString(),\n provider: 'jina',\n model,\n dimensions,\n threshold,\n requestedMaxPairs: maxPairs,\n comparedPages: eligible.length,\n possiblePairs: eligible.length * Math.max(0, eligible.length - 1) / 2,\n qualifyingPairs: qualifying.length,\n returnedPairs: rows.length,\n pairsTruncated: qualifying.length > rows.length,\n corpusSha256,\n analysisSha256,\n scoreDistribution: {\n min: quantile(0),\n p25: quantile(0.25),\n median: quantile(0.5),\n p75: quantile(0.75),\n p90: quantile(0.9),\n max: quantile(1),\n },\n boilerplateRemoval: {\n method: 'corpus_repeated_markdown_blocks',\n minimumPageCount: prepared.minimumPageCount,\n removedBlockSignatures: prepared.removedBlockSignatures,\n removedCharacters: prepared.removedCharacters,\n },\n rows,\n clusters,\n }\n}\n"],"mappings":"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","names":["createHash","createHash","round"]}