mcp-scraper 0.64.1 → 0.65.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.
- package/CHANGELOG.md +16 -0
- package/README.md +2 -2
- package/dist/bin/api-server.cjs +1028 -496
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +2 -2
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.cjs +49 -8
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +4 -4
- package/dist/{chunk-TRSZEK2D.js → chunk-2XUXVKT4.js} +3 -3
- package/dist/{chunk-TRSZEK2D.js.map → chunk-2XUXVKT4.js.map} +1 -1
- package/dist/{chunk-BRKCPONM.js → chunk-5PIO7QBG.js} +2 -2
- package/dist/{chunk-5QYSY5KI.js → chunk-AMLFKPLL.js} +139 -3
- package/dist/chunk-AMLFKPLL.js.map +1 -0
- package/dist/chunk-CGKWNXJR.js +7 -0
- package/dist/chunk-CGKWNXJR.js.map +1 -0
- package/dist/{chunk-3NXLGTC6.js → chunk-DCWXVAQT.js} +2 -2
- package/dist/{chunk-3NXLGTC6.js.map → chunk-DCWXVAQT.js.map} +1 -1
- package/dist/{chunk-P3NESXFX.js → chunk-PDAKCYHZ.js} +50 -9
- package/dist/chunk-PDAKCYHZ.js.map +1 -0
- package/dist/{extract-bundle-FW23CEMG.js → extract-bundle-UWKJT4MU.js} +371 -14
- package/dist/extract-bundle-UWKJT4MU.js.map +1 -0
- package/dist/{server-PGKMCRF5.js → server-RSHSZBUZ.js} +170 -163
- package/dist/server-RSHSZBUZ.js.map +1 -0
- package/dist/{site-extract-repository-UXSFD2QM.js → site-extract-repository-J3RH3MOS.js} +3 -3
- package/dist/{worker-DD243CON.js → worker-YKRIK5LS.js} +2 -2
- package/package.json +3 -1
- package/dist/chunk-3WNPHRGG.js +0 -7
- package/dist/chunk-3WNPHRGG.js.map +0 -1
- package/dist/chunk-5QYSY5KI.js.map +0 -1
- package/dist/chunk-P3NESXFX.js.map +0 -1
- package/dist/extract-bundle-FW23CEMG.js.map +0 -1
- package/dist/server-PGKMCRF5.js.map +0 -1
- /package/dist/{chunk-BRKCPONM.js.map → chunk-5PIO7QBG.js.map} +0 -0
- /package/dist/{site-extract-repository-UXSFD2QM.js.map → site-extract-repository-J3RH3MOS.js.map} +0 -0
- /package/dist/{worker-DD243CON.js.map → worker-YKRIK5LS.js.map} +0 -0
package/dist/bin/api-server.cjs
CHANGED
|
@@ -9070,7 +9070,7 @@ async function scrollAndStitch(page, device = "desktop") {
|
|
|
9070
9070
|
await page.setViewportSize(vp);
|
|
9071
9071
|
let previousHeight = 0;
|
|
9072
9072
|
let stableRounds = 0;
|
|
9073
|
-
for (let
|
|
9073
|
+
for (let round2 = 0; round2 < LAZY_SCROLL_ROUNDS && stableRounds < 2; round2++) {
|
|
9074
9074
|
const height = await page.evaluate(() => {
|
|
9075
9075
|
for (const image of Array.from(document.querySelectorAll('img[loading="lazy"]'))) {
|
|
9076
9076
|
image.loading = "eager";
|
|
@@ -9719,8 +9719,9 @@ async function fetchText(url, auditedHost, timeoutMs = 1e4) {
|
|
|
9719
9719
|
}
|
|
9720
9720
|
function extractSitemapLocs(xml) {
|
|
9721
9721
|
const locs = [];
|
|
9722
|
-
for (const m of xml.matchAll(/<loc
|
|
9723
|
-
const candidate = m[1].trim();
|
|
9722
|
+
for (const m of xml.matchAll(/<loc\b[^>]*>\s*(?:<!\[CDATA\[([\s\S]*?)\]\]>|([^<]+))\s*<\/loc>/gi)) {
|
|
9723
|
+
const candidate = (m[1] ?? m[2] ?? "").replace(/&/gi, "&").replace(/</gi, "<").replace(/>/gi, ">").replace(/"/gi, '"').replace(/'|'/gi, "'").trim();
|
|
9724
|
+
if (!/^https?:\/\//i.test(candidate)) continue;
|
|
9724
9725
|
if (boundedDiscoveredUrl(candidate)) locs.push(candidate);
|
|
9725
9726
|
}
|
|
9726
9727
|
return locs;
|
|
@@ -10059,7 +10060,52 @@ async function createBrowserWithRetry(client2, headless) {
|
|
|
10059
10060
|
}
|
|
10060
10061
|
throw new Error("unreachable");
|
|
10061
10062
|
}
|
|
10062
|
-
async function
|
|
10063
|
+
async function settleRenderedPage(page) {
|
|
10064
|
+
await page.waitForLoadState("load", { timeout: 8e3 }).catch(() => void 0);
|
|
10065
|
+
await page.waitForLoadState("networkidle", { timeout: 5e3 }).catch(() => void 0);
|
|
10066
|
+
await page.evaluate(async () => {
|
|
10067
|
+
const wait = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
10068
|
+
const height = Math.max(document.documentElement?.scrollHeight ?? 0, document.body?.scrollHeight ?? 0);
|
|
10069
|
+
const viewport = Math.max(1, window.innerHeight);
|
|
10070
|
+
const steps = Math.min(12, Math.max(1, Math.ceil(height / viewport)));
|
|
10071
|
+
for (let index = 1; index <= steps; index++) {
|
|
10072
|
+
window.scrollTo(0, Math.min(height, index * viewport));
|
|
10073
|
+
await wait(120);
|
|
10074
|
+
}
|
|
10075
|
+
window.scrollTo(0, 0);
|
|
10076
|
+
await wait(250);
|
|
10077
|
+
}).catch(() => void 0);
|
|
10078
|
+
}
|
|
10079
|
+
async function captureInertRenderedDom(page) {
|
|
10080
|
+
return page.evaluate((maxBytes) => {
|
|
10081
|
+
const root = document.documentElement?.cloneNode(true);
|
|
10082
|
+
if (!root) return { renderedDom: "", renderedDomTruncated: false, renderedDomSanitized: true };
|
|
10083
|
+
root.querySelectorAll('script,noscript,template,iframe,object,embed,meta[http-equiv="refresh"]').forEach((node) => node.remove());
|
|
10084
|
+
root.querySelectorAll("*").forEach((node) => {
|
|
10085
|
+
for (const attribute of [...node.attributes]) {
|
|
10086
|
+
const name = attribute.name.toLowerCase();
|
|
10087
|
+
const value = attribute.value.trim().toLowerCase();
|
|
10088
|
+
if (name.startsWith("on") || (name === "href" || name === "src" || name === "action") && value.startsWith("javascript:")) {
|
|
10089
|
+
node.removeAttribute(attribute.name);
|
|
10090
|
+
}
|
|
10091
|
+
}
|
|
10092
|
+
});
|
|
10093
|
+
const html = "<!doctype html>\n" + root.outerHTML;
|
|
10094
|
+
const encoder = new TextEncoder();
|
|
10095
|
+
if (encoder.encode(html).byteLength <= maxBytes) {
|
|
10096
|
+
return { renderedDom: html, renderedDomTruncated: false, renderedDomSanitized: true };
|
|
10097
|
+
}
|
|
10098
|
+
let low = 0;
|
|
10099
|
+
let high = html.length;
|
|
10100
|
+
while (low < high) {
|
|
10101
|
+
const middle = Math.ceil((low + high) / 2);
|
|
10102
|
+
if (encoder.encode(html.slice(0, middle)).byteLength <= maxBytes) low = middle;
|
|
10103
|
+
else high = middle - 1;
|
|
10104
|
+
}
|
|
10105
|
+
return { renderedDom: html.slice(0, low), renderedDomTruncated: true, renderedDomSanitized: true };
|
|
10106
|
+
}, MAX_RENDERED_DOM_BYTES);
|
|
10107
|
+
}
|
|
10108
|
+
async function crawlPage(context, url, headless, telemetry, options) {
|
|
10063
10109
|
const startedAt = Date.now();
|
|
10064
10110
|
let page = null;
|
|
10065
10111
|
let guardState = null;
|
|
@@ -10068,6 +10114,7 @@ async function crawlPage(context, url, headless, telemetry) {
|
|
|
10068
10114
|
guardState = await installBrowserRequestGuard(page, url);
|
|
10069
10115
|
const work = (async (p) => {
|
|
10070
10116
|
const resp = await p.goto(url, { waitUntil: "domcontentloaded", timeout: 3e4 });
|
|
10117
|
+
if (options.renderJavaScript || options.captureRenderedDom) await settleRenderedPage(p);
|
|
10071
10118
|
let html = await p.evaluate((maxBytes) => {
|
|
10072
10119
|
const value = document.documentElement?.outerHTML ?? "";
|
|
10073
10120
|
if (new TextEncoder().encode(value).byteLength > maxBytes) throw new Error(`Browser HTML exceeds ${maxBytes} byte limit`);
|
|
@@ -10103,6 +10150,7 @@ async function crawlPage(context, url, headless, telemetry) {
|
|
|
10103
10150
|
};
|
|
10104
10151
|
}
|
|
10105
10152
|
const isHttpError = resp != null && (resp.status() < 200 || resp.status() >= 300);
|
|
10153
|
+
const rendered = options.captureRenderedDom ? await captureInertRenderedDom(p) : null;
|
|
10106
10154
|
return {
|
|
10107
10155
|
url,
|
|
10108
10156
|
html,
|
|
@@ -10114,10 +10162,12 @@ async function crawlPage(context, url, headless, telemetry) {
|
|
|
10114
10162
|
...isHttpError ? { errorCode: `browser_http_${resp.status()}`, error: `Browser fetch returned HTTP ${resp.status()}` } : {},
|
|
10115
10163
|
browserMode: headless ? "stealth_headless" : "stealth_headful",
|
|
10116
10164
|
challengeDetected: false,
|
|
10117
|
-
stopReason: isHttpError ? "http_error" : "usable_page"
|
|
10165
|
+
stopReason: isHttpError ? "http_error" : "usable_page",
|
|
10166
|
+
...rendered ?? {}
|
|
10118
10167
|
};
|
|
10119
10168
|
})(page);
|
|
10120
|
-
const
|
|
10169
|
+
const hardTimeoutMs = options.renderJavaScript || options.captureRenderedDom ? 55e3 : PAGE_HARD_TIMEOUT_MS;
|
|
10170
|
+
const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error("page-hard-timeout")), hardTimeoutMs));
|
|
10121
10171
|
return await Promise.race([work, timeout]);
|
|
10122
10172
|
} catch (error) {
|
|
10123
10173
|
const message = guardState?.blockedReason ?? (error instanceof Error ? error.message : String(error));
|
|
@@ -10189,7 +10239,7 @@ async function crawlWithRotation(urls, opts) {
|
|
|
10189
10239
|
}
|
|
10190
10240
|
const context = await browser.newContext(withRuntimeUserAgent({ serviceWorkers: "block" }, runtimeUserAgent));
|
|
10191
10241
|
try {
|
|
10192
|
-
r = await crawlPage(context, url, passHeadless, { client: client2, sessionId: kb.session_id });
|
|
10242
|
+
r = await crawlPage(context, url, passHeadless, { client: client2, sessionId: kb.session_id }, opts);
|
|
10193
10243
|
} finally {
|
|
10194
10244
|
await context.close().catch(() => {
|
|
10195
10245
|
});
|
|
@@ -10247,7 +10297,7 @@ async function crawlWithRotation(urls, opts) {
|
|
|
10247
10297
|
attemptErrors: ["No browser result was recorded."]
|
|
10248
10298
|
});
|
|
10249
10299
|
}
|
|
10250
|
-
var import_sdk3, import_playwright3, DEFAULT_CONCURRENCY, DEFAULT_URLS_PER_BROWSER, DEFAULT_HEADLESS, PAGE_HARD_TIMEOUT_MS;
|
|
10300
|
+
var import_sdk3, import_playwright3, DEFAULT_CONCURRENCY, DEFAULT_URLS_PER_BROWSER, DEFAULT_HEADLESS, MAX_RENDERED_DOM_BYTES, PAGE_HARD_TIMEOUT_MS;
|
|
10251
10301
|
var init_rotating_proxy_crawl = __esm({
|
|
10252
10302
|
"src/api/rotating-proxy-crawl.ts"() {
|
|
10253
10303
|
"use strict";
|
|
@@ -10264,6 +10314,7 @@ var init_rotating_proxy_crawl = __esm({
|
|
|
10264
10314
|
DEFAULT_CONCURRENCY = 1;
|
|
10265
10315
|
DEFAULT_URLS_PER_BROWSER = 10;
|
|
10266
10316
|
DEFAULT_HEADLESS = true;
|
|
10317
|
+
MAX_RENDERED_DOM_BYTES = 256 * 1024;
|
|
10267
10318
|
PAGE_HARD_TIMEOUT_MS = 35e3;
|
|
10268
10319
|
}
|
|
10269
10320
|
});
|
|
@@ -10559,7 +10610,7 @@ function buildLinkReport(edges, metrics, siteUrl) {
|
|
|
10559
10610
|
domMap.set(domain, d);
|
|
10560
10611
|
}
|
|
10561
10612
|
const externalDomains = [...domMap.entries()].map(([domain, d]) => ({ domain, links: d.links, nofollow: d.nofollow, pages: d.pages.size })).sort((a, b) => b.links - a.links);
|
|
10562
|
-
const
|
|
10613
|
+
const round2 = (n) => Math.round(n * 10) / 10;
|
|
10563
10614
|
return {
|
|
10564
10615
|
summary: {
|
|
10565
10616
|
internal: {
|
|
@@ -10567,8 +10618,8 @@ function buildLinkReport(edges, metrics, siteUrl) {
|
|
|
10567
10618
|
pages,
|
|
10568
10619
|
orphans,
|
|
10569
10620
|
brokenInternal,
|
|
10570
|
-
avgInlinks: pages ?
|
|
10571
|
-
avgOutlinks: pages ?
|
|
10621
|
+
avgInlinks: pages ? round2(sumInlinks / pages) : 0,
|
|
10622
|
+
avgOutlinks: pages ? round2(sumOutlinks / pages) : 0,
|
|
10572
10623
|
distribution,
|
|
10573
10624
|
topByInlinks
|
|
10574
10625
|
},
|
|
@@ -11832,17 +11883,29 @@ async function mapWithConcurrency(items, concurrency, fn) {
|
|
|
11832
11883
|
}
|
|
11833
11884
|
async function extractPagesRotating(urls, opts) {
|
|
11834
11885
|
const uniqueUrls = [...new Set(urls)];
|
|
11835
|
-
const
|
|
11886
|
+
const initialPages = await mapWithConcurrency(uniqueUrls, opts.concurrency ?? EXTRACT_CONCURRENCY, async (url) => {
|
|
11836
11887
|
const checked = await validatePublicHttpUrl(url, { field: "page URL" });
|
|
11837
|
-
if (checked.error || !checked.parsed)
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11888
|
+
if (checked.error || !checked.parsed) {
|
|
11889
|
+
if (!opts.forceBrowserRender) return fetchPagePlain(url);
|
|
11890
|
+
const attempt2 = failedAttempt("browser", null, 0, "unsafe_url", checked.error ?? "Page URL was rejected.");
|
|
11891
|
+
return emptyPageData(url, null, "browser", { code: attempt2.errorCode, message: attempt2.error, attempts: [attempt2] });
|
|
11892
|
+
}
|
|
11893
|
+
if (normalizeUrl(checked.parsed.href, checked.parsed.href)) {
|
|
11894
|
+
if (!opts.forceBrowserRender) return fetchPagePlain(url);
|
|
11895
|
+
return emptyPageData(url, null, "browser", {
|
|
11896
|
+
code: "browser_pending",
|
|
11897
|
+
message: "Awaiting forced JavaScript rendering.",
|
|
11898
|
+
attempts: []
|
|
11899
|
+
});
|
|
11900
|
+
}
|
|
11901
|
+
const method = opts.forceBrowserRender ? "browser" : "fetch";
|
|
11902
|
+
const attempt = failedAttempt(method, null, 0, "non_page_url", "The URL points to an asset, feed, API, account route, or other non-page path excluded from text-page extraction.");
|
|
11903
|
+
const page = emptyPageData(url, null, method, { code: attempt.errorCode, message: attempt.error, attempts: [attempt] });
|
|
11841
11904
|
page.contentKind = "excluded_url";
|
|
11842
11905
|
return page;
|
|
11843
11906
|
});
|
|
11844
|
-
const byUrl = new Map(
|
|
11845
|
-
const browserTargets =
|
|
11907
|
+
const byUrl = new Map(initialPages.map((page) => [page.url, page]));
|
|
11908
|
+
const browserTargets = opts.forceBrowserRender ? initialPages.filter((page) => page.failureCode === "browser_pending").map((page) => page.url) : initialPages.filter((page) => !isPageExtractionSuccessful(page) && ![
|
|
11846
11909
|
"unsafe_url",
|
|
11847
11910
|
"unsafe_redirect",
|
|
11848
11911
|
"cross_site_redirect",
|
|
@@ -11854,7 +11917,9 @@ async function extractPagesRotating(urls, opts) {
|
|
|
11854
11917
|
const fetched = await crawlWithRotation(browserTargets, {
|
|
11855
11918
|
apiKey: opts.kernelApiKey,
|
|
11856
11919
|
concurrency: opts.concurrency,
|
|
11857
|
-
urlsPerBrowser: opts.urlsPerBrowser
|
|
11920
|
+
urlsPerBrowser: opts.urlsPerBrowser,
|
|
11921
|
+
renderJavaScript: opts.forceBrowserRender,
|
|
11922
|
+
captureRenderedDom: opts.captureRenderedDom
|
|
11858
11923
|
});
|
|
11859
11924
|
for (const result of fetched) {
|
|
11860
11925
|
const plainPage = byUrl.get(result.url);
|
|
@@ -11871,12 +11936,17 @@ async function extractPagesRotating(urls, opts) {
|
|
|
11871
11936
|
const browserOk = !redirectRejected && Boolean(result.html) && result.status >= 200 && result.status < 300;
|
|
11872
11937
|
if (browserOk) {
|
|
11873
11938
|
const replay = parseWaybackReplayUrl(result.url);
|
|
11874
|
-
|
|
11939
|
+
const page = parsePageData(result.url, result.renderedDom ?? result.html, result.status, "browser", {
|
|
11875
11940
|
headers: result.headers,
|
|
11876
11941
|
responseTimeMs,
|
|
11877
11942
|
redirectUrl: result.redirectUrl,
|
|
11878
11943
|
documentUrl: replay?.originalUrl ?? result.redirectUrl ?? result.url
|
|
11879
|
-
}, [...priorAttempts, ...browserAttemptEntries(result, true)])
|
|
11944
|
+
}, [...priorAttempts, ...browserAttemptEntries(result, true)]);
|
|
11945
|
+
if (result.renderedDom != null) {
|
|
11946
|
+
page.renderedDomTruncated = result.renderedDomTruncated === true;
|
|
11947
|
+
page.renderedDomSanitized = result.renderedDomSanitized === true;
|
|
11948
|
+
}
|
|
11949
|
+
byUrl.set(result.url, page);
|
|
11880
11950
|
continue;
|
|
11881
11951
|
}
|
|
11882
11952
|
const code = redirectRejected ? "unsafe_browser_redirect" : result.errorCode ?? (result.status > 0 ? `browser_http_${result.status}` : result.html ? "browser_invalid_status" : "browser_empty_response");
|
|
@@ -11890,7 +11960,16 @@ async function extractPagesRotating(urls, opts) {
|
|
|
11890
11960
|
}));
|
|
11891
11961
|
}
|
|
11892
11962
|
}
|
|
11893
|
-
|
|
11963
|
+
if (opts.forceBrowserRender && !opts.kernelApiKey) {
|
|
11964
|
+
for (const url of browserTargets) {
|
|
11965
|
+
byUrl.set(url, emptyPageData(url, null, "browser", {
|
|
11966
|
+
code: "browser_service_unconfigured",
|
|
11967
|
+
message: "Forced JavaScript rendering requires the hosted browser service.",
|
|
11968
|
+
attempts: [failedAttempt("browser", null, 0, "browser_service_unconfigured", "Forced JavaScript rendering requires the hosted browser service.")]
|
|
11969
|
+
}));
|
|
11970
|
+
}
|
|
11971
|
+
}
|
|
11972
|
+
return urls.map((url) => byUrl.get(url) ?? emptyPageData(url, null, opts.forceBrowserRender ? "browser" : "fetch", {
|
|
11894
11973
|
code: "result_missing",
|
|
11895
11974
|
message: "No extraction result was recorded."
|
|
11896
11975
|
}));
|
|
@@ -12921,8 +13000,8 @@ var init_product_contract_generated = __esm({
|
|
|
12921
13000
|
"freeSignupCredits": 0
|
|
12922
13001
|
},
|
|
12923
13002
|
"inventory": {
|
|
12924
|
-
"totalTools":
|
|
12925
|
-
"scraperTools":
|
|
13003
|
+
"totalTools": 259,
|
|
13004
|
+
"scraperTools": 158,
|
|
12926
13005
|
"memoryTools": 101
|
|
12927
13006
|
},
|
|
12928
13007
|
"concurrencyPack": {
|
|
@@ -16599,6 +16678,369 @@ var init_extraction_problems = __esm({
|
|
|
16599
16678
|
}
|
|
16600
16679
|
});
|
|
16601
16680
|
|
|
16681
|
+
// src/api/commons-embeddings.ts
|
|
16682
|
+
function commonsEmbedModel() {
|
|
16683
|
+
return (process.env.JINA_EMBED_MODEL ?? "jina-embeddings-v5-omni-small").trim();
|
|
16684
|
+
}
|
|
16685
|
+
function commonsEmbedDim() {
|
|
16686
|
+
return Number((process.env.JINA_EMBED_DIM ?? "1024").trim());
|
|
16687
|
+
}
|
|
16688
|
+
function commonsSemanticSearchConfigured() {
|
|
16689
|
+
return Boolean(process.env.JINA_API_KEY?.trim() && process.env.MEMORY_DATABASE_URL?.trim());
|
|
16690
|
+
}
|
|
16691
|
+
function vectorSql() {
|
|
16692
|
+
if (_vectorSql) return _vectorSql;
|
|
16693
|
+
const url = process.env.MEMORY_DATABASE_URL?.trim();
|
|
16694
|
+
if (!url) throw new Error("MEMORY_DATABASE_URL is not set; Commons semantic search needs the shared Postgres.");
|
|
16695
|
+
_vectorSql = (0, import_serverless.neon)(url);
|
|
16696
|
+
return _vectorSql;
|
|
16697
|
+
}
|
|
16698
|
+
async function ensureCommonsVectorSchema() {
|
|
16699
|
+
if (vectorSchemaReady) return;
|
|
16700
|
+
const dimension = commonsEmbedDim();
|
|
16701
|
+
await vectorSql().query("CREATE EXTENSION IF NOT EXISTS vector");
|
|
16702
|
+
await vectorSql().query(`
|
|
16703
|
+
CREATE TABLE IF NOT EXISTS commons_index_vectors (
|
|
16704
|
+
document_id TEXT PRIMARY KEY,
|
|
16705
|
+
entity_id TEXT NOT NULL,
|
|
16706
|
+
document_type TEXT NOT NULL,
|
|
16707
|
+
title TEXT NOT NULL,
|
|
16708
|
+
embedding vector(${dimension}) NOT NULL,
|
|
16709
|
+
model TEXT NOT NULL,
|
|
16710
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
16711
|
+
)
|
|
16712
|
+
`);
|
|
16713
|
+
await vectorSql().query("CREATE INDEX IF NOT EXISTS commons_index_vectors_entity ON commons_index_vectors(entity_id)");
|
|
16714
|
+
vectorSchemaReady = true;
|
|
16715
|
+
}
|
|
16716
|
+
async function embedCommonsTexts(texts) {
|
|
16717
|
+
const apiKey = process.env.JINA_API_KEY?.trim();
|
|
16718
|
+
if (!apiKey) throw new Error("JINA_API_KEY is not set; Commons semantic search cannot embed.");
|
|
16719
|
+
if (!texts.length) return [];
|
|
16720
|
+
const response = await fetch("https://api.jina.ai/v1/embeddings", {
|
|
16721
|
+
method: "POST",
|
|
16722
|
+
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
16723
|
+
body: JSON.stringify({
|
|
16724
|
+
model: commonsEmbedModel(),
|
|
16725
|
+
dimensions: commonsEmbedDim(),
|
|
16726
|
+
input: texts.map((text2) => ({ text: text2.slice(0, 8e3) }))
|
|
16727
|
+
}),
|
|
16728
|
+
signal: AbortSignal.timeout(6e4)
|
|
16729
|
+
});
|
|
16730
|
+
if (!response.ok) {
|
|
16731
|
+
throw new Error(`Jina embedding request failed with HTTP ${response.status}: ${(await response.text()).slice(0, 200)}`);
|
|
16732
|
+
}
|
|
16733
|
+
const payload = await response.json();
|
|
16734
|
+
const vectors = (payload.data ?? []).map((item) => item.embedding);
|
|
16735
|
+
if (vectors.length !== texts.length) {
|
|
16736
|
+
throw new Error(`Jina returned ${vectors.length} embeddings for ${texts.length} inputs.`);
|
|
16737
|
+
}
|
|
16738
|
+
return vectors;
|
|
16739
|
+
}
|
|
16740
|
+
async function embedQueuedCommonsDocuments(limit = 50) {
|
|
16741
|
+
if (!commonsSemanticSearchConfigured()) return { claimed: 0, embedded: 0, failed: 0, remaining: 0 };
|
|
16742
|
+
await ensureCommonsVectorSchema();
|
|
16743
|
+
const bounded2 = Math.max(1, Math.min(200, Math.floor(limit)));
|
|
16744
|
+
const queued = await getDb().execute({
|
|
16745
|
+
sql: `SELECT id, entity_id, document_type, title, text FROM commons_index_documents
|
|
16746
|
+
WHERE embedding_status IN ('queued', 'failed') ORDER BY updated_at ASC LIMIT ?`,
|
|
16747
|
+
args: [bounded2]
|
|
16748
|
+
});
|
|
16749
|
+
const rows = queued.rows;
|
|
16750
|
+
if (!rows.length) return { claimed: 0, embedded: 0, failed: 0, remaining: await queuedCommonsDocumentCount() };
|
|
16751
|
+
let embedded = 0;
|
|
16752
|
+
let failed = 0;
|
|
16753
|
+
const model = commonsEmbedModel();
|
|
16754
|
+
try {
|
|
16755
|
+
const vectors = await embedCommonsTexts(rows.map((row) => `${row.title}
|
|
16756
|
+
|
|
16757
|
+
${row.text}`));
|
|
16758
|
+
for (const [index, row] of rows.entries()) {
|
|
16759
|
+
const literal = `[${vectors[index].join(",")}]`;
|
|
16760
|
+
await vectorSql().query(
|
|
16761
|
+
`INSERT INTO commons_index_vectors (document_id, entity_id, document_type, title, embedding, model, updated_at)
|
|
16762
|
+
VALUES ($1, $2, $3, $4, $5::vector, $6, now())
|
|
16763
|
+
ON CONFLICT (document_id) DO UPDATE SET entity_id = EXCLUDED.entity_id, document_type = EXCLUDED.document_type,
|
|
16764
|
+
title = EXCLUDED.title, embedding = EXCLUDED.embedding, model = EXCLUDED.model, updated_at = now()`,
|
|
16765
|
+
[row.id, row.entity_id, row.document_type, row.title, literal, model]
|
|
16766
|
+
);
|
|
16767
|
+
await getDb().execute({
|
|
16768
|
+
sql: `UPDATE commons_index_documents SET embedding_status = 'indexed', embedding_provider = ?, embedding_model = ?,
|
|
16769
|
+
vector_ref = ?, indexed_at = ?, error = NULL WHERE id = ?`,
|
|
16770
|
+
args: [COMMONS_EMBED_PROVIDER, model, row.id, (/* @__PURE__ */ new Date()).toISOString(), row.id]
|
|
16771
|
+
});
|
|
16772
|
+
embedded += 1;
|
|
16773
|
+
}
|
|
16774
|
+
} catch (error) {
|
|
16775
|
+
failed = rows.length - embedded;
|
|
16776
|
+
const message = (error instanceof Error ? error.message : String(error)).slice(0, 500);
|
|
16777
|
+
for (const row of rows.slice(embedded)) {
|
|
16778
|
+
await getDb().execute({
|
|
16779
|
+
sql: `UPDATE commons_index_documents SET embedding_status = 'failed', error = ? WHERE id = ?`,
|
|
16780
|
+
args: [message, row.id]
|
|
16781
|
+
}).catch(() => void 0);
|
|
16782
|
+
}
|
|
16783
|
+
}
|
|
16784
|
+
return { claimed: rows.length, embedded, failed, remaining: await queuedCommonsDocumentCount() };
|
|
16785
|
+
}
|
|
16786
|
+
async function queuedCommonsDocumentCount() {
|
|
16787
|
+
const result = await getDb().execute(`SELECT COUNT(*) AS n FROM commons_index_documents WHERE embedding_status IN ('queued', 'failed')`);
|
|
16788
|
+
return Number(result.rows[0]?.n ?? 0);
|
|
16789
|
+
}
|
|
16790
|
+
async function semanticCommonsEntityScores(query, limit = 40) {
|
|
16791
|
+
const scores = /* @__PURE__ */ new Map();
|
|
16792
|
+
if (!commonsSemanticSearchConfigured() || !query.trim()) return scores;
|
|
16793
|
+
await ensureCommonsVectorSchema();
|
|
16794
|
+
const [vector] = await embedCommonsTexts([query]);
|
|
16795
|
+
if (!vector) return scores;
|
|
16796
|
+
const rows = await vectorSql().query(
|
|
16797
|
+
`SELECT entity_id, MAX(1 - (embedding <=> $1::vector)) AS score
|
|
16798
|
+
FROM commons_index_vectors GROUP BY entity_id ORDER BY score DESC LIMIT $2`,
|
|
16799
|
+
[`[${vector.join(",")}]`, Math.max(1, Math.min(100, limit))]
|
|
16800
|
+
);
|
|
16801
|
+
for (const row of rows) scores.set(String(row.entity_id), Number(row.score));
|
|
16802
|
+
return scores;
|
|
16803
|
+
}
|
|
16804
|
+
var import_serverless, COMMONS_EMBED_PROVIDER, _vectorSql, vectorSchemaReady;
|
|
16805
|
+
var init_commons_embeddings = __esm({
|
|
16806
|
+
"src/api/commons-embeddings.ts"() {
|
|
16807
|
+
"use strict";
|
|
16808
|
+
import_serverless = require("@neondatabase/serverless");
|
|
16809
|
+
init_db();
|
|
16810
|
+
COMMONS_EMBED_PROVIDER = "jina";
|
|
16811
|
+
_vectorSql = null;
|
|
16812
|
+
vectorSchemaReady = false;
|
|
16813
|
+
}
|
|
16814
|
+
});
|
|
16815
|
+
|
|
16816
|
+
// src/api/site-content-similarity.ts
|
|
16817
|
+
function round(value, places) {
|
|
16818
|
+
const scale = 10 ** places;
|
|
16819
|
+
return Math.round(value * scale) / scale;
|
|
16820
|
+
}
|
|
16821
|
+
function cosineSimilarity(a, b) {
|
|
16822
|
+
if (a.length === 0 || a.length !== b.length) throw new Error("Similarity vectors must have the same non-zero dimension.");
|
|
16823
|
+
let dot = 0;
|
|
16824
|
+
let normA = 0;
|
|
16825
|
+
let normB = 0;
|
|
16826
|
+
for (let index = 0; index < a.length; index++) {
|
|
16827
|
+
dot += a[index] * b[index];
|
|
16828
|
+
normA += a[index] * a[index];
|
|
16829
|
+
normB += b[index] * b[index];
|
|
16830
|
+
}
|
|
16831
|
+
if (normA === 0 || normB === 0) return 0;
|
|
16832
|
+
return Math.max(-1, Math.min(1, dot / (Math.sqrt(normA) * Math.sqrt(normB))));
|
|
16833
|
+
}
|
|
16834
|
+
function corpusHash(pages) {
|
|
16835
|
+
const digest2 = (0, import_node_crypto6.createHash)("sha256");
|
|
16836
|
+
for (const page of [...pages].sort((a, b) => a.url.localeCompare(b.url))) {
|
|
16837
|
+
digest2.update(page.url);
|
|
16838
|
+
digest2.update("\0");
|
|
16839
|
+
digest2.update(page.contentHash);
|
|
16840
|
+
digest2.update("\0");
|
|
16841
|
+
}
|
|
16842
|
+
return digest2.digest("hex");
|
|
16843
|
+
}
|
|
16844
|
+
function markdownBlockSignature(block) {
|
|
16845
|
+
const normalized = block.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/https?:\/\/\S+/gi, " ").replace(/&(?:amp|nbsp|quot|#39);/gi, " ").replace(/[#>*_`~|\\-]+/g, " ").replace(/[^\p{L}\p{N}]+/gu, " ").replace(/\s+/g, " ").trim().toLowerCase();
|
|
16846
|
+
return normalized.length >= 12 ? normalized : null;
|
|
16847
|
+
}
|
|
16848
|
+
function prepareEmbeddingTexts(pages) {
|
|
16849
|
+
const blocksByPage = pages.map((page) => page.bodyMarkdown.split(/\n{2,}/).map((block) => block.trim()).filter(Boolean));
|
|
16850
|
+
const minimumPageCount = pages.length >= 4 ? Math.max(3, Math.ceil(pages.length * 0.5)) : null;
|
|
16851
|
+
const pageFrequency = /* @__PURE__ */ new Map();
|
|
16852
|
+
for (const blocks of blocksByPage) {
|
|
16853
|
+
const pageSignatures = new Set(blocks.map(markdownBlockSignature).filter((value) => Boolean(value)));
|
|
16854
|
+
for (const signature of pageSignatures) pageFrequency.set(signature, (pageFrequency.get(signature) ?? 0) + 1);
|
|
16855
|
+
}
|
|
16856
|
+
const repeated = /* @__PURE__ */ new Set();
|
|
16857
|
+
if (minimumPageCount != null) {
|
|
16858
|
+
for (const [signature, count] of pageFrequency) {
|
|
16859
|
+
if (count >= minimumPageCount) repeated.add(signature);
|
|
16860
|
+
}
|
|
16861
|
+
}
|
|
16862
|
+
let removedCharacters = 0;
|
|
16863
|
+
const texts = pages.map((page, pageIndex) => {
|
|
16864
|
+
const kept = [];
|
|
16865
|
+
for (const block of blocksByPage[pageIndex]) {
|
|
16866
|
+
const signature = markdownBlockSignature(block);
|
|
16867
|
+
if (signature && repeated.has(signature)) {
|
|
16868
|
+
removedCharacters += block.length;
|
|
16869
|
+
continue;
|
|
16870
|
+
}
|
|
16871
|
+
kept.push(block);
|
|
16872
|
+
}
|
|
16873
|
+
const cleaned = kept.join("\n\n").trim();
|
|
16874
|
+
const content = cleaned.length >= 60 ? cleaned : page.bodyMarkdown;
|
|
16875
|
+
return `${page.title?.trim() || "Untitled page"}
|
|
16876
|
+
|
|
16877
|
+
${content}`;
|
|
16878
|
+
});
|
|
16879
|
+
return {
|
|
16880
|
+
texts,
|
|
16881
|
+
minimumPageCount,
|
|
16882
|
+
removedBlockSignatures: repeated.size,
|
|
16883
|
+
removedCharacters
|
|
16884
|
+
};
|
|
16885
|
+
}
|
|
16886
|
+
async function analyzeSiteContentSimilarity(pages, options = {}) {
|
|
16887
|
+
const eligible = pages.filter((page) => page.bodyMarkdown.trim().length > 0).slice(0, MAX_SIMILARITY_PAGES);
|
|
16888
|
+
const requestedThreshold = Number.isFinite(options.threshold) ? options.threshold : DEFAULT_SIMILARITY_THRESHOLD;
|
|
16889
|
+
const requestedMaxPairs = Number.isFinite(options.maxPairs) ? options.maxPairs : DEFAULT_SIMILARITY_MAX_PAIRS;
|
|
16890
|
+
const threshold = Math.max(0, Math.min(1, requestedThreshold));
|
|
16891
|
+
const maxPairs = Math.max(1, Math.min(MAX_SIMILARITY_PAIRS, Math.floor(requestedMaxPairs)));
|
|
16892
|
+
const model = options.model ?? commonsEmbedModel();
|
|
16893
|
+
const dimensions = options.dimensions ?? commonsEmbedDim();
|
|
16894
|
+
const embedTexts = options.embedTexts ?? embedCommonsTexts;
|
|
16895
|
+
const prepared = prepareEmbeddingTexts(eligible);
|
|
16896
|
+
const uniqueTexts = [];
|
|
16897
|
+
const textIndexByHash = /* @__PURE__ */ new Map();
|
|
16898
|
+
const pageTextIndexes = [];
|
|
16899
|
+
for (const [pageIndex, page] of eligible.entries()) {
|
|
16900
|
+
const key = page.contentHash || (0, import_node_crypto6.createHash)("sha256").update(page.bodyMarkdown).digest("hex");
|
|
16901
|
+
let textIndex = textIndexByHash.get(key);
|
|
16902
|
+
if (textIndex == null) {
|
|
16903
|
+
textIndex = uniqueTexts.length;
|
|
16904
|
+
textIndexByHash.set(key, textIndex);
|
|
16905
|
+
uniqueTexts.push(prepared.texts[pageIndex]);
|
|
16906
|
+
}
|
|
16907
|
+
pageTextIndexes.push(textIndex);
|
|
16908
|
+
}
|
|
16909
|
+
const uniqueVectors = [];
|
|
16910
|
+
for (let offset = 0; offset < uniqueTexts.length; offset += 64) {
|
|
16911
|
+
uniqueVectors.push(...await embedTexts(uniqueTexts.slice(offset, offset + 64)));
|
|
16912
|
+
}
|
|
16913
|
+
if (uniqueVectors.length !== uniqueTexts.length) {
|
|
16914
|
+
throw new Error(`Embedding provider returned ${uniqueVectors.length} vectors for ${uniqueTexts.length} unique page bodies.`);
|
|
16915
|
+
}
|
|
16916
|
+
const vectors = pageTextIndexes.map((index) => uniqueVectors[index]);
|
|
16917
|
+
const sets = new DisjointSet(eligible.length);
|
|
16918
|
+
const allScores = [];
|
|
16919
|
+
const qualifying = [];
|
|
16920
|
+
for (let source = 0; source < eligible.length; source++) {
|
|
16921
|
+
for (let target = source + 1; target < eligible.length; target++) {
|
|
16922
|
+
const score = cosineSimilarity(vectors[source], vectors[target]);
|
|
16923
|
+
allScores.push(score);
|
|
16924
|
+
if (score < threshold) continue;
|
|
16925
|
+
qualifying.push({ source, target, score });
|
|
16926
|
+
sets.union(source, target);
|
|
16927
|
+
}
|
|
16928
|
+
}
|
|
16929
|
+
qualifying.sort((a, b) => b.score - a.score || eligible[a.source].url.localeCompare(eligible[b.source].url) || eligible[a.target].url.localeCompare(eligible[b.target].url));
|
|
16930
|
+
const sortedScores = [...allScores].sort((a, b) => a - b);
|
|
16931
|
+
const quantile = (value) => {
|
|
16932
|
+
if (!sortedScores.length) return null;
|
|
16933
|
+
return round(sortedScores[Math.floor((sortedScores.length - 1) * value)], 6);
|
|
16934
|
+
};
|
|
16935
|
+
const membersByRoot = /* @__PURE__ */ new Map();
|
|
16936
|
+
for (let index = 0; index < eligible.length; index++) {
|
|
16937
|
+
const root = sets.find(index);
|
|
16938
|
+
const members = membersByRoot.get(root) ?? [];
|
|
16939
|
+
members.push(index);
|
|
16940
|
+
membersByRoot.set(root, members);
|
|
16941
|
+
}
|
|
16942
|
+
const clusterIdByPage = /* @__PURE__ */ new Map();
|
|
16943
|
+
const clusters = [...membersByRoot.values()].filter((members) => members.length > 1).sort((a, b) => b.length - a.length || eligible[a[0]].url.localeCompare(eligible[b[0]].url)).map((members, index) => {
|
|
16944
|
+
const clusterId = `cluster-${String(index + 1).padStart(3, "0")}`;
|
|
16945
|
+
for (const member of members) clusterIdByPage.set(member, clusterId);
|
|
16946
|
+
return {
|
|
16947
|
+
clusterId,
|
|
16948
|
+
pageCount: members.length,
|
|
16949
|
+
urls: members.map((member) => eligible[member].url).sort()
|
|
16950
|
+
};
|
|
16951
|
+
});
|
|
16952
|
+
const rows = qualifying.slice(0, maxPairs).map((pair, pairIndex) => {
|
|
16953
|
+
const source = eligible[pair.source];
|
|
16954
|
+
const target = eligible[pair.target];
|
|
16955
|
+
const similarity2 = round(pair.score, 6);
|
|
16956
|
+
return {
|
|
16957
|
+
sourceUrl: source.url,
|
|
16958
|
+
sourceTitle: source.title,
|
|
16959
|
+
targetUrl: target.url,
|
|
16960
|
+
targetTitle: target.title,
|
|
16961
|
+
similarity: similarity2,
|
|
16962
|
+
similarityPercent: round(similarity2 * 100, 2),
|
|
16963
|
+
corpusPercentile: sortedScores.length <= 1 ? 100 : round((1 - pairIndex / (sortedScores.length - 1)) * 100, 2),
|
|
16964
|
+
exactContentDuplicate: Boolean(source.contentHash && source.contentHash === target.contentHash),
|
|
16965
|
+
sourceWordCount: source.wordCount,
|
|
16966
|
+
targetWordCount: target.wordCount,
|
|
16967
|
+
clusterId: clusterIdByPage.get(pair.source) ?? null
|
|
16968
|
+
};
|
|
16969
|
+
});
|
|
16970
|
+
const corpusSha256 = corpusHash(eligible);
|
|
16971
|
+
const analysisSha256 = (0, import_node_crypto6.createHash)("sha256").update(JSON.stringify({
|
|
16972
|
+
corpusSha256,
|
|
16973
|
+
model,
|
|
16974
|
+
dimensions,
|
|
16975
|
+
threshold,
|
|
16976
|
+
maxPairs,
|
|
16977
|
+
boilerplateRemoval: {
|
|
16978
|
+
method: "corpus_repeated_markdown_blocks",
|
|
16979
|
+
minimumPageCount: prepared.minimumPageCount,
|
|
16980
|
+
removedBlockSignatures: prepared.removedBlockSignatures
|
|
16981
|
+
}
|
|
16982
|
+
})).digest("hex");
|
|
16983
|
+
return {
|
|
16984
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16985
|
+
provider: "jina",
|
|
16986
|
+
model,
|
|
16987
|
+
dimensions,
|
|
16988
|
+
threshold,
|
|
16989
|
+
requestedMaxPairs: maxPairs,
|
|
16990
|
+
comparedPages: eligible.length,
|
|
16991
|
+
possiblePairs: eligible.length * Math.max(0, eligible.length - 1) / 2,
|
|
16992
|
+
qualifyingPairs: qualifying.length,
|
|
16993
|
+
returnedPairs: rows.length,
|
|
16994
|
+
pairsTruncated: qualifying.length > rows.length,
|
|
16995
|
+
corpusSha256,
|
|
16996
|
+
analysisSha256,
|
|
16997
|
+
scoreDistribution: {
|
|
16998
|
+
min: quantile(0),
|
|
16999
|
+
p25: quantile(0.25),
|
|
17000
|
+
median: quantile(0.5),
|
|
17001
|
+
p75: quantile(0.75),
|
|
17002
|
+
p90: quantile(0.9),
|
|
17003
|
+
max: quantile(1)
|
|
17004
|
+
},
|
|
17005
|
+
boilerplateRemoval: {
|
|
17006
|
+
method: "corpus_repeated_markdown_blocks",
|
|
17007
|
+
minimumPageCount: prepared.minimumPageCount,
|
|
17008
|
+
removedBlockSignatures: prepared.removedBlockSignatures,
|
|
17009
|
+
removedCharacters: prepared.removedCharacters
|
|
17010
|
+
},
|
|
17011
|
+
rows,
|
|
17012
|
+
clusters
|
|
17013
|
+
};
|
|
17014
|
+
}
|
|
17015
|
+
var import_node_crypto6, MAX_SIMILARITY_PAGES, DEFAULT_SIMILARITY_THRESHOLD, DEFAULT_SIMILARITY_MAX_PAIRS, MAX_SIMILARITY_PAIRS, DisjointSet;
|
|
17016
|
+
var init_site_content_similarity = __esm({
|
|
17017
|
+
"src/api/site-content-similarity.ts"() {
|
|
17018
|
+
"use strict";
|
|
17019
|
+
import_node_crypto6 = require("crypto");
|
|
17020
|
+
init_commons_embeddings();
|
|
17021
|
+
MAX_SIMILARITY_PAGES = 500;
|
|
17022
|
+
DEFAULT_SIMILARITY_THRESHOLD = 0.9;
|
|
17023
|
+
DEFAULT_SIMILARITY_MAX_PAIRS = 1e4;
|
|
17024
|
+
MAX_SIMILARITY_PAIRS = 5e4;
|
|
17025
|
+
DisjointSet = class {
|
|
17026
|
+
parent;
|
|
17027
|
+
constructor(size) {
|
|
17028
|
+
this.parent = Array.from({ length: size }, (_, index) => index);
|
|
17029
|
+
}
|
|
17030
|
+
find(value) {
|
|
17031
|
+
const parent = this.parent[value];
|
|
17032
|
+
if (parent !== value) this.parent[value] = this.find(parent);
|
|
17033
|
+
return this.parent[value];
|
|
17034
|
+
}
|
|
17035
|
+
union(a, b) {
|
|
17036
|
+
const rootA = this.find(a);
|
|
17037
|
+
const rootB = this.find(b);
|
|
17038
|
+
if (rootA !== rootB) this.parent[rootB] = rootA;
|
|
17039
|
+
}
|
|
17040
|
+
};
|
|
17041
|
+
}
|
|
17042
|
+
});
|
|
17043
|
+
|
|
16602
17044
|
// src/api/extract-bundle.ts
|
|
16603
17045
|
var extract_bundle_exports = {};
|
|
16604
17046
|
__export(extract_bundle_exports, {
|
|
@@ -16623,6 +17065,15 @@ function safeImageFilename(url, index) {
|
|
|
16623
17065
|
return `image-${index}`;
|
|
16624
17066
|
}
|
|
16625
17067
|
}
|
|
17068
|
+
function slugFactory() {
|
|
17069
|
+
const counts = /* @__PURE__ */ new Map();
|
|
17070
|
+
return (url) => {
|
|
17071
|
+
const base = url.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "page";
|
|
17072
|
+
const n = counts.get(base) ?? 0;
|
|
17073
|
+
counts.set(base, n + 1);
|
|
17074
|
+
return n ? `${base}-${n}` : base;
|
|
17075
|
+
};
|
|
17076
|
+
}
|
|
16626
17077
|
async function* pageChunks(jobId2) {
|
|
16627
17078
|
const db = getDb();
|
|
16628
17079
|
let lastRowId = 0;
|
|
@@ -16641,6 +17092,25 @@ async function* pageChunks(jobId2) {
|
|
|
16641
17092
|
yield res.rows.map((r) => JSON.parse(String(r.page)));
|
|
16642
17093
|
}
|
|
16643
17094
|
}
|
|
17095
|
+
function csvCell(value) {
|
|
17096
|
+
const text2 = value == null ? "" : String(value);
|
|
17097
|
+
return /[",\r\n]/.test(text2) ? `"${text2.replace(/"/g, '""')}"` : text2;
|
|
17098
|
+
}
|
|
17099
|
+
function similarityTableRow(row) {
|
|
17100
|
+
return {
|
|
17101
|
+
source_url: row.sourceUrl,
|
|
17102
|
+
source_title: row.sourceTitle,
|
|
17103
|
+
target_url: row.targetUrl,
|
|
17104
|
+
target_title: row.targetTitle,
|
|
17105
|
+
similarity: row.similarity,
|
|
17106
|
+
similarity_percent: row.similarityPercent,
|
|
17107
|
+
corpus_percentile: row.corpusPercentile,
|
|
17108
|
+
exact_content_duplicate: row.exactContentDuplicate,
|
|
17109
|
+
source_word_count: row.sourceWordCount,
|
|
17110
|
+
target_word_count: row.targetWordCount,
|
|
17111
|
+
cluster_id: row.clusterId
|
|
17112
|
+
};
|
|
17113
|
+
}
|
|
16644
17114
|
async function assembleExtractArtifacts(job, extras = {}) {
|
|
16645
17115
|
const dir = (0, import_node_path3.join)((0, import_node_os3.tmpdir)(), `extract-bundle-${job.id}-${Date.now()}`);
|
|
16646
17116
|
const downloadImages = job.options.downloadImages === true;
|
|
@@ -16648,8 +17118,14 @@ async function assembleExtractArtifacts(job, extras = {}) {
|
|
|
16648
17118
|
const readPageContent = createSiteExtractContentReader(String(job.userId));
|
|
16649
17119
|
(0, import_node_fs3.mkdirSync)(dir, { recursive: true });
|
|
16650
17120
|
if (downloadImages) (0, import_node_fs3.mkdirSync)((0, import_node_path3.join)(dir, "images"), { recursive: true });
|
|
17121
|
+
const captureRenderedDom = job.options.captureRenderedDom === true;
|
|
17122
|
+
const semanticSimilarity = job.options.semanticSimilarity === true;
|
|
17123
|
+
if (captureRenderedDom) (0, import_node_fs3.mkdirSync)((0, import_node_path3.join)(dir, "rendered-dom"), { recursive: true });
|
|
16651
17124
|
try {
|
|
16652
17125
|
const metas = [];
|
|
17126
|
+
const similarityPages = [];
|
|
17127
|
+
const renderedDomManifest = [];
|
|
17128
|
+
const domSlug = slugFactory();
|
|
16653
17129
|
const pageExportEntries = [];
|
|
16654
17130
|
const waybackTimeline = job.options.waybackTimeline;
|
|
16655
17131
|
const statusByUrl = /* @__PURE__ */ new Map();
|
|
@@ -16677,12 +17153,32 @@ async function assembleExtractArtifacts(job, extras = {}) {
|
|
|
16677
17153
|
schemaTypes: p.schemaTypes.length > 0 ? ["present"] : [],
|
|
16678
17154
|
outlinks: []
|
|
16679
17155
|
});
|
|
16680
|
-
const pageId = p.pageId ?? (0,
|
|
17156
|
+
const pageId = p.pageId ?? (0, import_node_crypto7.createHash)("sha256").update(p.archivedUrl ?? p.url).digest("hex");
|
|
16681
17157
|
const pageDir = (0, import_node_path3.join)(dir, "pages", pageId);
|
|
16682
17158
|
(0, import_node_fs3.mkdirSync)(pageDir, { recursive: true });
|
|
16683
17159
|
const content = p.contentRef ? await readPageContent(p.contentRef) : null;
|
|
16684
17160
|
const html = content?.html ?? null;
|
|
16685
17161
|
const markdown = content?.markdown ?? p.bodyMarkdown ?? null;
|
|
17162
|
+
if (semanticSimilarity && p.extractionStatus === "successful" && markdown?.trim()) {
|
|
17163
|
+
similarityPages.push({
|
|
17164
|
+
url: p.url,
|
|
17165
|
+
title: p.title,
|
|
17166
|
+
bodyMarkdown: markdown,
|
|
17167
|
+
contentHash: p.contentHash,
|
|
17168
|
+
wordCount: p.wordCount
|
|
17169
|
+
});
|
|
17170
|
+
}
|
|
17171
|
+
if (captureRenderedDom && html != null) {
|
|
17172
|
+
const relativePath = `rendered-dom/${domSlug(p.url)}.html.txt`;
|
|
17173
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, relativePath), html);
|
|
17174
|
+
renderedDomManifest.push({
|
|
17175
|
+
url: p.url,
|
|
17176
|
+
path: relativePath,
|
|
17177
|
+
bytes: Buffer.byteLength(html),
|
|
17178
|
+
truncated: p.renderedDomTruncated === true,
|
|
17179
|
+
sanitized: p.renderedDomSanitized === true
|
|
17180
|
+
});
|
|
17181
|
+
}
|
|
16686
17182
|
const htmlPath = html == null ? null : `pages/${pageId}/page.html`;
|
|
16687
17183
|
const markdownPath = markdown == null ? null : `pages/${pageId}/page.md`;
|
|
16688
17184
|
const legacyMarkdownPath = markdown == null || !p.archiveRequestedMonth ? null : `pages/${p.archiveRequestedMonth}/${pageId}.md`;
|
|
@@ -16702,8 +17198,8 @@ async function assembleExtractArtifacts(job, extras = {}) {
|
|
|
16702
17198
|
markdownPath,
|
|
16703
17199
|
htmlBytes: html == null ? 0 : Buffer.byteLength(html),
|
|
16704
17200
|
markdownBytes: markdown == null ? 0 : Buffer.byteLength(markdown),
|
|
16705
|
-
htmlSha256: html == null ? null : (0,
|
|
16706
|
-
markdownSha256: markdown == null ? null : (0,
|
|
17201
|
+
htmlSha256: html == null ? null : (0, import_node_crypto7.createHash)("sha256").update(html).digest("hex"),
|
|
17202
|
+
markdownSha256: markdown == null ? null : (0, import_node_crypto7.createHash)("sha256").update(markdown).digest("hex")
|
|
16707
17203
|
}
|
|
16708
17204
|
};
|
|
16709
17205
|
const pageJson = JSON.stringify(pageRecord, null, 2);
|
|
@@ -16716,7 +17212,7 @@ async function assembleExtractArtifacts(job, extras = {}) {
|
|
|
16716
17212
|
htmlPath,
|
|
16717
17213
|
markdownPath,
|
|
16718
17214
|
legacyMarkdownPath,
|
|
16719
|
-
jsonSha256: (0,
|
|
17215
|
+
jsonSha256: (0, import_node_crypto7.createHash)("sha256").update(pageJson).digest("hex"),
|
|
16720
17216
|
htmlSha256: pageRecord.content.htmlSha256,
|
|
16721
17217
|
markdownSha256: pageRecord.content.markdownSha256,
|
|
16722
17218
|
htmlBytes: pageRecord.content.htmlBytes,
|
|
@@ -16784,7 +17280,7 @@ async function assembleExtractArtifacts(job, extras = {}) {
|
|
|
16784
17280
|
}
|
|
16785
17281
|
if (p.imageLinks?.length) {
|
|
16786
17282
|
for (const [idx, imgUrl] of p.imageLinks.entries()) {
|
|
16787
|
-
const imageId = (0,
|
|
17283
|
+
const imageId = (0, import_node_crypto7.createHash)("sha256").update(`${p.url}\0${imgUrl}`).digest("hex");
|
|
16788
17284
|
const record = {
|
|
16789
17285
|
imageId,
|
|
16790
17286
|
sourcePage: p.url,
|
|
@@ -16838,7 +17334,7 @@ async function assembleExtractArtifacts(job, extras = {}) {
|
|
|
16838
17334
|
record.artifactId = artifact.key;
|
|
16839
17335
|
record.mimeType = result.mimeType;
|
|
16840
17336
|
record.bytes = result.sizeBytes;
|
|
16841
|
-
record.sha256 = (0,
|
|
17337
|
+
record.sha256 = (0, import_node_crypto7.createHash)("sha256").update(bytes).digest("hex");
|
|
16842
17338
|
}, (error) => {
|
|
16843
17339
|
imagesFailed++;
|
|
16844
17340
|
record.status = "failed";
|
|
@@ -16976,7 +17472,7 @@ async function assembleExtractArtifacts(job, extras = {}) {
|
|
|
16976
17472
|
|
|
16977
17473
|
${renderImageSection(extras.imageAudit)}`;
|
|
16978
17474
|
const metricValues = [...metrics.values()];
|
|
16979
|
-
const
|
|
17475
|
+
const round2 = (n) => Math.round(n * 10) / 10;
|
|
16980
17476
|
const distribution = { zero: 0, oneToTwo: 0, threeToTen: 0, elevenPlus: 0 };
|
|
16981
17477
|
let sumInlinks = 0;
|
|
16982
17478
|
let sumOutlinks = 0;
|
|
@@ -16996,8 +17492,8 @@ ${renderImageSection(extras.imageAudit)}`;
|
|
|
16996
17492
|
pages: metas.length,
|
|
16997
17493
|
orphans: metricValues.filter((m) => m.orphan).length,
|
|
16998
17494
|
brokenInternal,
|
|
16999
|
-
avgInlinks: metas.length ?
|
|
17000
|
-
avgOutlinks: metas.length ?
|
|
17495
|
+
avgInlinks: metas.length ? round2(sumInlinks / metas.length) : 0,
|
|
17496
|
+
avgOutlinks: metas.length ? round2(sumOutlinks / metas.length) : 0,
|
|
17001
17497
|
distribution,
|
|
17002
17498
|
topByInlinks: [...metricValues].sort((a, b) => b.inlinks - a.inlinks).slice(0, 20).map((m) => ({ url: m.url, inlinks: m.inlinks, outlinksInternal: m.outlinksInternal, outlinksExternal: m.outlinksExternal }))
|
|
17003
17499
|
},
|
|
@@ -17102,6 +17598,72 @@ ${renderImageSection(extras.imageAudit)}`;
|
|
|
17102
17598
|
pagesOut.end();
|
|
17103
17599
|
captureMatrixOut?.end();
|
|
17104
17600
|
await Promise.all([pagesFinished, captureMatrixFinished]);
|
|
17601
|
+
if (captureRenderedDom) {
|
|
17602
|
+
(0, import_node_fs3.writeFileSync)(
|
|
17603
|
+
(0, import_node_path3.join)(dir, "rendered-dom", "manifest.jsonl"),
|
|
17604
|
+
renderedDomManifest.map((row) => JSON.stringify(row)).join("\n")
|
|
17605
|
+
);
|
|
17606
|
+
}
|
|
17607
|
+
if (semanticSimilarity) {
|
|
17608
|
+
const analysis = await analyzeSiteContentSimilarity(similarityPages, {
|
|
17609
|
+
threshold: Number(job.options.similarityThreshold ?? void 0),
|
|
17610
|
+
maxPairs: Number(job.options.similarityMaxPairs ?? void 0),
|
|
17611
|
+
embedTexts: extras.embedSimilarityTexts
|
|
17612
|
+
});
|
|
17613
|
+
const tableRows = analysis.rows.map(similarityTableRow);
|
|
17614
|
+
const columns = tableRows.length > 0 ? Object.keys(tableRows[0]) : [
|
|
17615
|
+
"source_url",
|
|
17616
|
+
"source_title",
|
|
17617
|
+
"target_url",
|
|
17618
|
+
"target_title",
|
|
17619
|
+
"similarity",
|
|
17620
|
+
"similarity_percent",
|
|
17621
|
+
"corpus_percentile",
|
|
17622
|
+
"exact_content_duplicate",
|
|
17623
|
+
"source_word_count",
|
|
17624
|
+
"target_word_count",
|
|
17625
|
+
"cluster_id"
|
|
17626
|
+
];
|
|
17627
|
+
const csv = [
|
|
17628
|
+
columns.join(","),
|
|
17629
|
+
...tableRows.map((row) => columns.map((column) => csvCell(row[column] ?? null)).join(","))
|
|
17630
|
+
].join("\n") + "\n";
|
|
17631
|
+
const { rows: _rows, clusters: _clusters, ...summary } = analysis;
|
|
17632
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "similarity-table.csv"), csv);
|
|
17633
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "similarity.jsonl"), tableRows.map((row) => JSON.stringify(row)).join("\n"));
|
|
17634
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "similarity-table-schema.json"), JSON.stringify({
|
|
17635
|
+
tableNameSuggestion: `site_similarity_${new URL(job.startUrl).hostname.replace(/[^a-z0-9]+/gi, "_").replace(/^_+|_+$/g, "").toLowerCase()}`,
|
|
17636
|
+
defaultSort: [{ column: "similarity", direction: "desc" }],
|
|
17637
|
+
columns: {
|
|
17638
|
+
source_url: "text",
|
|
17639
|
+
source_title: "text",
|
|
17640
|
+
target_url: "text",
|
|
17641
|
+
target_title: "text",
|
|
17642
|
+
similarity: "number",
|
|
17643
|
+
similarity_percent: "number",
|
|
17644
|
+
corpus_percentile: "number",
|
|
17645
|
+
exact_content_duplicate: "boolean",
|
|
17646
|
+
source_word_count: "integer",
|
|
17647
|
+
target_word_count: "integer",
|
|
17648
|
+
cluster_id: "text"
|
|
17649
|
+
}
|
|
17650
|
+
}, null, 2));
|
|
17651
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "similarity-summary.json"), JSON.stringify(summary, null, 2));
|
|
17652
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "content-clusters.json"), JSON.stringify(analysis.clusters, null, 2));
|
|
17653
|
+
reportMd += [
|
|
17654
|
+
"",
|
|
17655
|
+
"## Rendered content similarity",
|
|
17656
|
+
`- Compared pages: ${analysis.comparedPages}`,
|
|
17657
|
+
`- Raw cosine threshold: ${analysis.threshold}`,
|
|
17658
|
+
`- 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"}`,
|
|
17659
|
+
`- Qualifying pairs: ${analysis.qualifyingPairs}`,
|
|
17660
|
+
`- Returned table rows: ${analysis.returnedPairs}${analysis.pairsTruncated ? " (capped)" : ""}`,
|
|
17661
|
+
`- Multi-page clusters: ${analysis.clusters.length}`,
|
|
17662
|
+
`- Embedding model: ${analysis.model} (${analysis.dimensions} dimensions)`,
|
|
17663
|
+
`- Corpus boilerplate removed: ${analysis.boilerplateRemoval.removedBlockSignatures} repeated block signatures / ${analysis.boilerplateRemoval.removedCharacters} characters`,
|
|
17664
|
+
`- Corpus SHA-256: ${analysis.corpusSha256}`
|
|
17665
|
+
].join("\n");
|
|
17666
|
+
}
|
|
17105
17667
|
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "report.md"), reportMd);
|
|
17106
17668
|
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "crawl-summary.json"), JSON.stringify(crawlSummary, null, 2));
|
|
17107
17669
|
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "images-manifest.jsonl"), imageManifest.map((record) => JSON.stringify(record)).join("\n"));
|
|
@@ -17167,6 +17729,17 @@ ${renderImageSection(extras.imageAudit)}`;
|
|
|
17167
17729
|
{ name: "links-summary.json", type: "application/json" },
|
|
17168
17730
|
{ name: "external-domains.json", type: "application/json" }
|
|
17169
17731
|
];
|
|
17732
|
+
if (captureRenderedDom) {
|
|
17733
|
+
artifactFiles.push({ name: "rendered-dom/manifest.jsonl", type: "application/x-ndjson" });
|
|
17734
|
+
for (const row of renderedDomManifest) artifactFiles.push({ name: row.path, type: "text/plain" });
|
|
17735
|
+
}
|
|
17736
|
+
if (semanticSimilarity) {
|
|
17737
|
+
artifactFiles.push({ name: "similarity-table.csv", type: "text/csv" });
|
|
17738
|
+
artifactFiles.push({ name: "similarity.jsonl", type: "application/x-ndjson" });
|
|
17739
|
+
artifactFiles.push({ name: "similarity-table-schema.json", type: "application/json" });
|
|
17740
|
+
artifactFiles.push({ name: "similarity-summary.json", type: "application/json" });
|
|
17741
|
+
artifactFiles.push({ name: "content-clusters.json", type: "application/json" });
|
|
17742
|
+
}
|
|
17170
17743
|
if (waybackTimeline) {
|
|
17171
17744
|
artifactFiles.push({ name: "wayback-manifest.json", type: "application/json" });
|
|
17172
17745
|
artifactFiles.push({ name: "capture-matrix.jsonl", type: "application/x-ndjson" });
|
|
@@ -17206,12 +17779,12 @@ ${renderImageSection(extras.imageAudit)}`;
|
|
|
17206
17779
|
(0, import_node_fs3.rmSync)(dir, { recursive: true, force: true });
|
|
17207
17780
|
}
|
|
17208
17781
|
}
|
|
17209
|
-
var import_node_fs3,
|
|
17782
|
+
var import_node_fs3, import_node_crypto7, import_node_path3, import_node_os3, import_node_zlib2, import_node_events, import_promises5, import_yazl, import_p_limit4, SITE_EXTRACT_PAGE_CHUNK, MAX_IMAGES_PER_PAGE, MAX_IMAGES_PER_SITE, IMAGE_DOWNLOAD_CONCURRENCY, MAX_IMAGE_BYTES, MAX_SITE_IMAGE_BYTES, MAX_ANALYZED_LINK_EDGES;
|
|
17210
17783
|
var init_extract_bundle = __esm({
|
|
17211
17784
|
"src/api/extract-bundle.ts"() {
|
|
17212
17785
|
"use strict";
|
|
17213
17786
|
import_node_fs3 = require("fs");
|
|
17214
|
-
|
|
17787
|
+
import_node_crypto7 = require("crypto");
|
|
17215
17788
|
import_node_path3 = require("path");
|
|
17216
17789
|
import_node_os3 = require("os");
|
|
17217
17790
|
import_node_zlib2 = require("zlib");
|
|
@@ -17228,6 +17801,7 @@ var init_extract_bundle = __esm({
|
|
|
17228
17801
|
init_media_extractor();
|
|
17229
17802
|
init_site_extract_artifacts();
|
|
17230
17803
|
init_site_extract_content_store();
|
|
17804
|
+
init_site_content_similarity();
|
|
17231
17805
|
SITE_EXTRACT_PAGE_CHUNK = 25;
|
|
17232
17806
|
MAX_IMAGES_PER_PAGE = 20;
|
|
17233
17807
|
MAX_IMAGES_PER_SITE = 500;
|
|
@@ -17338,6 +17912,8 @@ var init_site_extract = __esm({
|
|
|
17338
17912
|
const maxPages = Number(job.options.maxPages ?? 1e4);
|
|
17339
17913
|
const concurrency = Number(job.options.concurrency ?? 1);
|
|
17340
17914
|
const urlsPerBrowser = Number(job.options.urlsPerBrowser ?? job.options.rotateProxyEvery ?? 10);
|
|
17915
|
+
const captureRenderedDom = job.options.captureRenderedDom === true;
|
|
17916
|
+
const forceBrowserRender = job.options.renderJavaScript === true || job.options.semanticSimilarity === true || captureRenderedDom;
|
|
17341
17917
|
const batchSize = siteExtractBatchSize(concurrency, urlsPerBrowser);
|
|
17342
17918
|
const waybackReplay = parseWaybackReplayUrl(job.startUrl);
|
|
17343
17919
|
const waybackTimeline = job.options.waybackTimeline;
|
|
@@ -17420,7 +17996,13 @@ var init_site_extract = __esm({
|
|
|
17420
17996
|
if (!batch.length) break;
|
|
17421
17997
|
const frontierCapacity = Math.max(0, maxPages - seen.size);
|
|
17422
17998
|
const newLinks = await step.run(`crawl-batch-${i}`, async () => {
|
|
17423
|
-
const pages = await runWithCostContext(costContext, () => extractPagesRotating(batch, {
|
|
17999
|
+
const pages = await runWithCostContext(costContext, () => extractPagesRotating(batch, {
|
|
18000
|
+
kernelApiKey: key,
|
|
18001
|
+
concurrency,
|
|
18002
|
+
urlsPerBrowser,
|
|
18003
|
+
forceBrowserRender,
|
|
18004
|
+
captureRenderedDom
|
|
18005
|
+
}));
|
|
17424
18006
|
const storedPages = pages.map((p) => withWaybackProvenance({
|
|
17425
18007
|
...p,
|
|
17426
18008
|
// parsePageData deliberately keeps large bodies non-enumerable so
|
|
@@ -17709,9 +18291,9 @@ async function signedDownloadUrl2(pathname, expiresAt) {
|
|
|
17709
18291
|
async function createConnectedDataArtifact(args) {
|
|
17710
18292
|
const createdAt = Date.now();
|
|
17711
18293
|
const filename2 = `${safeFilename2(args.filename).replace(/\.jsonl$/i, "")}.jsonl`;
|
|
17712
|
-
const requestedPathname = `${CONNECTED_DATA_ARTIFACT_PREFIX}${args.ownerId}/${createdAt}-${args.exportId}-${(0,
|
|
18294
|
+
const requestedPathname = `${CONNECTED_DATA_ARTIFACT_PREFIX}${args.ownerId}/${createdAt}-${args.exportId}-${(0, import_node_crypto8.randomUUID)()}.jsonl`;
|
|
17713
18295
|
const bytes = Buffer.byteLength(args.content);
|
|
17714
|
-
const sha2565 = (0,
|
|
18296
|
+
const sha2565 = (0, import_node_crypto8.createHash)("sha256").update(args.content).digest("hex");
|
|
17715
18297
|
const expiresAt = new Date(createdAt + CONNECTED_DATA_ARTIFACT_TTL_MS);
|
|
17716
18298
|
const token6 = privateBlobToken();
|
|
17717
18299
|
let artifactId = requestedPathname;
|
|
@@ -17824,11 +18406,11 @@ async function cleanupExpiredConnectedDataArtifacts(args = {}) {
|
|
|
17824
18406
|
}
|
|
17825
18407
|
return { deleted, store: "private-vercel-blob" };
|
|
17826
18408
|
}
|
|
17827
|
-
var
|
|
18409
|
+
var import_node_crypto8, import_promises6, import_node_os4, import_node_path4, CONNECTED_DATA_ARTIFACT_PREFIX, CONNECTED_DATA_ARTIFACT_TTL_MS, CONNECTED_DATA_DOWNLOAD_TTL_MS;
|
|
17828
18410
|
var init_connected_data_artifacts = __esm({
|
|
17829
18411
|
"src/api/connected-data-artifacts.ts"() {
|
|
17830
18412
|
"use strict";
|
|
17831
|
-
|
|
18413
|
+
import_node_crypto8 = require("crypto");
|
|
17832
18414
|
import_promises6 = require("fs/promises");
|
|
17833
18415
|
import_node_os4 = require("os");
|
|
17834
18416
|
import_node_path4 = require("path");
|
|
@@ -17927,7 +18509,7 @@ var init_directory_artifacts = __esm({
|
|
|
17927
18509
|
// src/mcp/report-artifact-offload.ts
|
|
17928
18510
|
async function offloadReport(toolName, ownerId2, report) {
|
|
17929
18511
|
const timestamp2 = Date.now();
|
|
17930
|
-
const random = (0,
|
|
18512
|
+
const random = (0, import_node_crypto9.randomBytes)(6).toString("hex");
|
|
17931
18513
|
const stored = await createPrivateArtifact({
|
|
17932
18514
|
policy: REPORT_ARTIFACT_POLICY,
|
|
17933
18515
|
ownerId: ownerId2,
|
|
@@ -17988,11 +18570,11 @@ function summaryEnvelope(executiveSummary, offloaded) {
|
|
|
17988
18570
|
"Read it with report_artifact_read (supports offset/maxBytes windowing)."
|
|
17989
18571
|
].join("\n");
|
|
17990
18572
|
}
|
|
17991
|
-
var
|
|
18573
|
+
var import_node_crypto9, REPORT_BLOB_TTL_MS, REPORT_BLOB_PREFIX, PREVIEW_CHARS, REPORT_ARTIFACT_POLICY, ARTIFACT_OFFLOAD_ENABLED;
|
|
17992
18574
|
var init_report_artifact_offload = __esm({
|
|
17993
18575
|
"src/mcp/report-artifact-offload.ts"() {
|
|
17994
18576
|
"use strict";
|
|
17995
|
-
|
|
18577
|
+
import_node_crypto9 = require("crypto");
|
|
17996
18578
|
init_private_artifacts();
|
|
17997
18579
|
init_connected_data_artifacts();
|
|
17998
18580
|
init_directory_artifacts();
|
|
@@ -19184,7 +19766,7 @@ function buildSeoExport(siteUrl, pages, branding) {
|
|
|
19184
19766
|
branding: branding ?? void 0
|
|
19185
19767
|
};
|
|
19186
19768
|
}
|
|
19187
|
-
function formatBackgroundJobStarted(toolLabel, data, delivery) {
|
|
19769
|
+
function formatBackgroundJobStarted(toolLabel, url, data, delivery) {
|
|
19188
19770
|
if (data.status !== "pending" || typeof data.jobId !== "string") return null;
|
|
19189
19771
|
const jobId2 = data.jobId;
|
|
19190
19772
|
const full = [
|
|
@@ -19199,6 +19781,7 @@ Poll \`check_site_export\` with this jobId. When ready, use \`site_export_read\`
|
|
|
19199
19781
|
return {
|
|
19200
19782
|
content: [{ type: "text", text: full }],
|
|
19201
19783
|
structuredContent: {
|
|
19784
|
+
url,
|
|
19202
19785
|
jobId: jobId2,
|
|
19203
19786
|
status: "pending",
|
|
19204
19787
|
requestedMaxPages: data.requestedMaxPages,
|
|
@@ -19219,7 +19802,8 @@ async function formatExtractSite(raw, input, ctx) {
|
|
|
19219
19802
|
const parsed = parseData(raw);
|
|
19220
19803
|
if ("error" in parsed) return formattedErrorResult(parsed.error);
|
|
19221
19804
|
const started = formatBackgroundJobStarted(
|
|
19222
|
-
"Multi-Page Site Content Crawl",
|
|
19805
|
+
input.toolLabel ?? "Multi-Page Site Content Crawl",
|
|
19806
|
+
input.url,
|
|
19223
19807
|
parsed.data,
|
|
19224
19808
|
{
|
|
19225
19809
|
requested: input.delivery ?? "auto",
|
|
@@ -19350,6 +19934,7 @@ async function formatAuditSite(raw, input, ctx) {
|
|
|
19350
19934
|
if ("error" in parsed) return formattedErrorResult(parsed.error);
|
|
19351
19935
|
const started = formatBackgroundJobStarted(
|
|
19352
19936
|
"Technical SEO Audit",
|
|
19937
|
+
input.url,
|
|
19353
19938
|
parsed.data,
|
|
19354
19939
|
{
|
|
19355
19940
|
requested: input.delivery ?? "auto",
|
|
@@ -22884,7 +23469,7 @@ function backupProxyAvailable() {
|
|
|
22884
23469
|
}
|
|
22885
23470
|
function randomStickySessionId() {
|
|
22886
23471
|
let digits = "";
|
|
22887
|
-
for (let i = 0; i < 10; i++) digits += String((0,
|
|
23472
|
+
for (let i = 0; i < 10; i++) digits += String((0, import_node_crypto10.randomInt)(0, 10));
|
|
22888
23473
|
return digits;
|
|
22889
23474
|
}
|
|
22890
23475
|
function buildBackupUsername(opts = {}) {
|
|
@@ -22942,11 +23527,11 @@ async function cleanupBackupProxyId(kernelApiKey, proxyId) {
|
|
|
22942
23527
|
} catch {
|
|
22943
23528
|
}
|
|
22944
23529
|
}
|
|
22945
|
-
var
|
|
23530
|
+
var import_node_crypto10, import_sdk7, BACKUP_PROXY_HOST, BACKUP_PROXY_PORT, BACKUP_STICKY_SESSION_MINUTES, BACKUP_LAST_RESORT_ATTEMPTS;
|
|
22946
23531
|
var init_backup_proxy = __esm({
|
|
22947
23532
|
"src/backup-proxy.ts"() {
|
|
22948
23533
|
"use strict";
|
|
22949
|
-
|
|
23534
|
+
import_node_crypto10 = require("crypto");
|
|
22950
23535
|
import_sdk7 = __toESM(require("@onkernel/sdk"), 1);
|
|
22951
23536
|
BACKUP_PROXY_HOST = "pr.oxylabs.io";
|
|
22952
23537
|
BACKUP_PROXY_PORT = 7777;
|
|
@@ -24351,7 +24936,7 @@ function csvRecords(text2) {
|
|
|
24351
24936
|
return record;
|
|
24352
24937
|
});
|
|
24353
24938
|
}
|
|
24354
|
-
function
|
|
24939
|
+
function csvCell2(value) {
|
|
24355
24940
|
if (value === null || value === void 0) return "";
|
|
24356
24941
|
const text2 = String(value);
|
|
24357
24942
|
return /[",\n\r]/.test(text2) ? `"${text2.replace(/"/g, '""')}"` : text2;
|
|
@@ -24359,7 +24944,7 @@ function csvCell(value) {
|
|
|
24359
24944
|
function rowsToCsv(headers, rows) {
|
|
24360
24945
|
return [
|
|
24361
24946
|
headers.join(","),
|
|
24362
|
-
...rows.map((row) => headers.map((header) =>
|
|
24947
|
+
...rows.map((row) => headers.map((header) => csvCell2(row[header])).join(","))
|
|
24363
24948
|
].join("\n") + "\n";
|
|
24364
24949
|
}
|
|
24365
24950
|
var init_csv = __esm({
|
|
@@ -24755,12 +25340,12 @@ async function getHostedZipGroups(stateInput) {
|
|
|
24755
25340
|
async function importHostedZipGroupsCsv(input) {
|
|
24756
25341
|
await ensureHostedLocationDataSchema();
|
|
24757
25342
|
const sourceUrl = normalizedSourceUrl(input.sourceUrl);
|
|
24758
|
-
const sha2565 = (0,
|
|
25343
|
+
const sha2565 = (0, import_node_crypto11.createHash)("sha256").update(input.csv).digest("hex");
|
|
24759
25344
|
const active = await getActiveHostedLocationDataset();
|
|
24760
25345
|
if (active?.sha256 === sha2565) return { dataset: active, duplicate: true };
|
|
24761
25346
|
const parsed = parseHostedZipGroupsCsv(input.csv);
|
|
24762
25347
|
assertNationwideZipCoverage(parsed);
|
|
24763
|
-
const id = `loc_${(0,
|
|
25348
|
+
const id = `loc_${(0, import_node_crypto11.randomUUID)().replaceAll("-", "")}`;
|
|
24764
25349
|
const db = getDb();
|
|
24765
25350
|
await db.execute({
|
|
24766
25351
|
sql: `
|
|
@@ -24828,12 +25413,12 @@ async function importHostedCensusPlacesCsv(input) {
|
|
|
24828
25413
|
if (!state) throw new Error("state must be a two-letter US state abbreviation");
|
|
24829
25414
|
const kind = censusDatasetKind(state);
|
|
24830
25415
|
const sourceUrl = normalizedSourceUrl(input.sourceUrl);
|
|
24831
|
-
const sha2565 = (0,
|
|
25416
|
+
const sha2565 = (0, import_node_crypto11.createHash)("sha256").update(input.csv).digest("hex");
|
|
24832
25417
|
const active = await getActiveHostedDataset(kind);
|
|
24833
25418
|
if (active?.sha256 === sha2565) return { dataset: active, duplicate: true };
|
|
24834
25419
|
const stateFips = STATE_FIPS_BY_ABBR[state];
|
|
24835
25420
|
const parsed = parseHostedCensusPlacesCsv(input.csv, stateFips);
|
|
24836
|
-
const id = `loc_${(0,
|
|
25421
|
+
const id = `loc_${(0, import_node_crypto11.randomUUID)().replaceAll("-", "")}`;
|
|
24837
25422
|
const db = getDb();
|
|
24838
25423
|
await db.execute({
|
|
24839
25424
|
sql: `
|
|
@@ -24956,11 +25541,11 @@ async function queryHostedLocationMarkets(input) {
|
|
|
24956
25541
|
warnings
|
|
24957
25542
|
};
|
|
24958
25543
|
}
|
|
24959
|
-
var
|
|
25544
|
+
var import_node_crypto11, HOSTED_ZIP_DATASET_KIND, HOSTED_CENSUS_DATASET_PREFIX, MIN_NATIONWIDE_ZIP_COUNT, REQUIRED_LOCATION_STATE_CODES, STATE_FIPS_BY_ABBR, REQUIRED_LOCATION_STATE_SET, IMPORT_BATCH_SIZE, MAX_SOURCE_URL_LENGTH, schemaDb, schemaPromise;
|
|
24960
25545
|
var init_location_data_repository = __esm({
|
|
24961
25546
|
"src/api/location-data-repository.ts"() {
|
|
24962
25547
|
"use strict";
|
|
24963
|
-
|
|
25548
|
+
import_node_crypto11 = require("crypto");
|
|
24964
25549
|
init_db();
|
|
24965
25550
|
init_csv();
|
|
24966
25551
|
HOSTED_ZIP_DATASET_KIND = "us_zip_groups";
|
|
@@ -26274,7 +26859,7 @@ async function claimDirectoryWorkflowOutbox(input) {
|
|
|
26274
26859
|
const workerId = requiredBoundedString(input.workerId, "outbox worker id", 160);
|
|
26275
26860
|
const limit = Math.max(1, Math.min(100, Math.trunc(input.limit ?? 25)));
|
|
26276
26861
|
const leaseSeconds = Math.max(30, Math.min(3600, Math.trunc(input.leaseSeconds ?? 120)));
|
|
26277
|
-
const claimToken = `${workerId}:${(0,
|
|
26862
|
+
const claimToken = `${workerId}:${(0, import_node_crypto12.randomUUID)()}`;
|
|
26278
26863
|
const leaseModifier = `+${leaseSeconds} seconds`;
|
|
26279
26864
|
const results = await getDb().batch([
|
|
26280
26865
|
{
|
|
@@ -26334,11 +26919,11 @@ async function markDirectoryWorkflowOutboxFailed(input) {
|
|
|
26334
26919
|
});
|
|
26335
26920
|
return Number(result.rowsAffected ?? 0) > 0;
|
|
26336
26921
|
}
|
|
26337
|
-
var
|
|
26922
|
+
var import_node_crypto12, DIRECTORY_EVENT_NAME, TERMINAL_JOB_STATUSES, DIRECTORY_MAX_DISPATCH_ATTEMPTS, DIRECTORY_START_DEADLINE_MINUTES, DIRECTORY_RUNNING_STALE_MINUTES, schemaDb2, schemaPromise2;
|
|
26338
26923
|
var init_directory_workflow_repository = __esm({
|
|
26339
26924
|
"src/api/directory-workflow-repository.ts"() {
|
|
26340
26925
|
"use strict";
|
|
26341
|
-
|
|
26926
|
+
import_node_crypto12 = require("crypto");
|
|
26342
26927
|
init_db();
|
|
26343
26928
|
DIRECTORY_EVENT_NAME = "mcp-scraper/directory.requested";
|
|
26344
26929
|
TERMINAL_JOB_STATUSES = /* @__PURE__ */ new Set(["succeeded", "partial", "failed"]);
|
|
@@ -26452,7 +27037,7 @@ async function acquireConcurrencyGate(user, operation, options = {}) {
|
|
|
26452
27037
|
return { ok: true, lockId: null, active: await countActiveUsageForUser(user.id, true), limit, operation, reused: true };
|
|
26453
27038
|
}
|
|
26454
27039
|
await expireConcurrencyLocksForUser(user.id);
|
|
26455
|
-
const lockId = `cl_${(0,
|
|
27040
|
+
const lockId = `cl_${(0, import_node_crypto13.randomUUID)().replace(/-/g, "").slice(0, 24)}`;
|
|
26456
27041
|
const res = await getDb().execute({
|
|
26457
27042
|
sql: `INSERT INTO concurrency_locks (id, user_id, operation, status, expires_at, metadata)
|
|
26458
27043
|
SELECT ?, ?, ?, 'active', datetime('now', ?), ?
|
|
@@ -26502,11 +27087,11 @@ async function extendConcurrencyGate(lockId, ttlSeconds = DEFAULT_LOCK_TTL_SECON
|
|
|
26502
27087
|
args: [lockTtlModifier(ttlSeconds), lockId]
|
|
26503
27088
|
});
|
|
26504
27089
|
}
|
|
26505
|
-
var
|
|
27090
|
+
var import_node_crypto13, DEFAULT_LOCK_TTL_SECONDS, DEFAULT_RETRY_AFTER_SECONDS, MAX_LOCK_TTL_SECONDS;
|
|
26506
27091
|
var init_concurrency_gates = __esm({
|
|
26507
27092
|
"src/api/concurrency-gates.ts"() {
|
|
26508
27093
|
"use strict";
|
|
26509
|
-
|
|
27094
|
+
import_node_crypto13 = require("crypto");
|
|
26510
27095
|
init_db();
|
|
26511
27096
|
init_rates();
|
|
26512
27097
|
DEFAULT_LOCK_TTL_SECONDS = 15 * 60;
|
|
@@ -27573,7 +28158,7 @@ var init_PAAExtractor = __esm({
|
|
|
27573
28158
|
if (remainingHumanClickDelayMs > 0) await page.waitForTimeout(remainingHumanClickDelayMs);
|
|
27574
28159
|
return "ok";
|
|
27575
28160
|
};
|
|
27576
|
-
let
|
|
28161
|
+
let round2 = 0;
|
|
27577
28162
|
let growthWaits = 0;
|
|
27578
28163
|
while (true) {
|
|
27579
28164
|
if (options.softDeadlineMs && Date.now() >= options.softDeadlineMs) break;
|
|
@@ -27601,7 +28186,7 @@ var init_PAAExtractor = __esm({
|
|
|
27601
28186
|
continue;
|
|
27602
28187
|
}
|
|
27603
28188
|
growthWaits = 0;
|
|
27604
|
-
this.reporter.onDepth(++
|
|
28189
|
+
this.reporter.onDepth(++round2);
|
|
27605
28190
|
await this.throwIfCaptcha(page, "Google PAA expansion");
|
|
27606
28191
|
clickedOnceEver.add(target.q);
|
|
27607
28192
|
const expansionStatus = await expandOneItemSerially(target.q);
|
|
@@ -30138,10 +30723,10 @@ function stableCanonicalJson(value) {
|
|
|
30138
30723
|
return JSON.stringify(normalize4(value));
|
|
30139
30724
|
}
|
|
30140
30725
|
function leadListEnrichmentFingerprint(input) {
|
|
30141
|
-
return (0,
|
|
30726
|
+
return (0, import_node_crypto14.createHash)("sha256").update(stableCanonicalJson(input)).digest("hex");
|
|
30142
30727
|
}
|
|
30143
30728
|
function leadListRowInputDigest(row) {
|
|
30144
|
-
return (0,
|
|
30729
|
+
return (0, import_node_crypto14.createHash)("sha256").update(stableCanonicalJson(row)).digest("hex");
|
|
30145
30730
|
}
|
|
30146
30731
|
function emptyUsage() {
|
|
30147
30732
|
return { mapsAttempts: 0, pageAttempts: 0, pageSuccesses: 0, serpSearches: 0 };
|
|
@@ -30614,7 +31199,7 @@ async function claimLeadListEnrichmentOutbox(input) {
|
|
|
30614
31199
|
const workerId = requiredBoundedString2(input.workerId, "outbox worker id", 160);
|
|
30615
31200
|
const limit = Math.max(1, Math.min(100, Math.trunc(input.limit ?? 25)));
|
|
30616
31201
|
const leaseSeconds = Math.max(30, Math.min(3600, Math.trunc(input.leaseSeconds ?? 120)));
|
|
30617
|
-
const claimToken = `${workerId}:${(0,
|
|
31202
|
+
const claimToken = `${workerId}:${(0, import_node_crypto14.randomUUID)()}`;
|
|
30618
31203
|
const results = await getDb().batch([{
|
|
30619
31204
|
sql: `UPDATE lead_list_enrichment_outbox SET status='dispatching',attempts=attempts+1,locked_by=?,
|
|
30620
31205
|
locked_until=datetime('now',?),updated_at=datetime('now') WHERE id IN (SELECT id FROM lead_list_enrichment_outbox
|
|
@@ -30640,11 +31225,11 @@ async function markLeadListEnrichmentOutboxFailed(input) {
|
|
|
30640
31225
|
WHERE id=? AND status='dispatching' AND locked_by=?`, args: [`+${retryAfterSeconds} seconds`, String(input.error).slice(0, 2e3), input.id, input.claimToken] });
|
|
30641
31226
|
return Number(result.rowsAffected ?? 0) > 0;
|
|
30642
31227
|
}
|
|
30643
|
-
var
|
|
31228
|
+
var import_node_crypto14, EVENT_NAME, TERMINAL_JOB_STATUSES2, TERMINAL_ROW_STATUSES, LEAD_LIST_MAX_DISPATCH_ATTEMPTS, LEAD_LIST_START_DEADLINE_MINUTES, LEAD_LIST_RUNNING_STALE_MINUTES, schemaDb3, schemaPromise3;
|
|
30644
31229
|
var init_lead_list_enrichment_repository = __esm({
|
|
30645
31230
|
"src/api/lead-list-enrichment-repository.ts"() {
|
|
30646
31231
|
"use strict";
|
|
30647
|
-
|
|
31232
|
+
import_node_crypto14 = require("crypto");
|
|
30648
31233
|
init_db();
|
|
30649
31234
|
EVENT_NAME = "mcp-scraper/lead-list-enrichment.requested";
|
|
30650
31235
|
TERMINAL_JOB_STATUSES2 = /* @__PURE__ */ new Set(["complete", "partial", "empty", "failed", "cancelled"]);
|
|
@@ -31222,7 +31807,7 @@ var init_paa_harvest_settlement = __esm({
|
|
|
31222
31807
|
|
|
31223
31808
|
// src/api/serp-identity-db.ts
|
|
31224
31809
|
async function createSerpIdentityRow(input) {
|
|
31225
|
-
const id = `serpi_${(0,
|
|
31810
|
+
const id = `serpi_${(0, import_node_crypto15.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
31226
31811
|
await getDb().execute({
|
|
31227
31812
|
sql: `INSERT INTO serp_identities
|
|
31228
31813
|
(id, user_id, name, kernel_profile_name, kernel_proxy_id, proxy_type, country, status)
|
|
@@ -31267,11 +31852,11 @@ async function deleteSerpIdentityRow(userId, name) {
|
|
|
31267
31852
|
args: [userId, name]
|
|
31268
31853
|
});
|
|
31269
31854
|
}
|
|
31270
|
-
var
|
|
31855
|
+
var import_node_crypto15;
|
|
31271
31856
|
var init_serp_identity_db = __esm({
|
|
31272
31857
|
"src/api/serp-identity-db.ts"() {
|
|
31273
31858
|
"use strict";
|
|
31274
|
-
|
|
31859
|
+
import_node_crypto15 = require("crypto");
|
|
31275
31860
|
init_db();
|
|
31276
31861
|
}
|
|
31277
31862
|
});
|
|
@@ -32018,7 +32603,7 @@ async function runDurablePaaCapture(input) {
|
|
|
32018
32603
|
const { gzipSync: gzipSync2 } = await import("zlib");
|
|
32019
32604
|
rawDomGzip = gzipSync2(transported);
|
|
32020
32605
|
}
|
|
32021
|
-
rawDomSha256 = (0,
|
|
32606
|
+
rawDomSha256 = (0, import_node_crypto16.createHash)("sha256").update(rawDomGzip).digest("hex");
|
|
32022
32607
|
}
|
|
32023
32608
|
}
|
|
32024
32609
|
const selected = Array.from(records.values()).slice(0, input.maxQuestions);
|
|
@@ -32102,12 +32687,12 @@ async function runDurablePaaCapture(input) {
|
|
|
32102
32687
|
}
|
|
32103
32688
|
throw new Error("paa_work_deadline_exhausted_before_capture");
|
|
32104
32689
|
}
|
|
32105
|
-
var import_sdk9,
|
|
32690
|
+
var import_sdk9, import_node_crypto16, PAA_INVOCATION_BUDGET_MS, PAA_BROWSER_WORK_BUDGET_MS, PAA_SOLVER_BUDGET_MS, RAW_PREPARE_CODE;
|
|
32106
32691
|
var init_durable_capture = __esm({
|
|
32107
32692
|
"src/paa/durable-capture.ts"() {
|
|
32108
32693
|
"use strict";
|
|
32109
32694
|
import_sdk9 = __toESM(require("@onkernel/sdk"), 1);
|
|
32110
|
-
|
|
32695
|
+
import_node_crypto16 = require("crypto");
|
|
32111
32696
|
init_selectors();
|
|
32112
32697
|
init_uule();
|
|
32113
32698
|
PAA_INVOCATION_BUDGET_MS = 28e4;
|
|
@@ -32535,7 +33120,7 @@ function mapSubmission(row) {
|
|
|
32535
33120
|
async function event(submissionId, eventType, actorKind, actorId, metadata = {}) {
|
|
32536
33121
|
await getDb().execute({
|
|
32537
33122
|
sql: `INSERT INTO local_sourcebook_events (id, submission_id, event_type, actor_kind, actor_id, metadata_json) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
32538
|
-
args: [(0,
|
|
33123
|
+
args: [(0, import_node_crypto17.randomUUID)(), submissionId, eventType, actorKind, actorId, JSON.stringify(metadata)]
|
|
32539
33124
|
});
|
|
32540
33125
|
}
|
|
32541
33126
|
async function createLocalSourcebookSubmission(input) {
|
|
@@ -32549,7 +33134,7 @@ async function createLocalSourcebookSubmission(input) {
|
|
|
32549
33134
|
return submission;
|
|
32550
33135
|
}
|
|
32551
33136
|
}
|
|
32552
|
-
const id = `lsb_${(0,
|
|
33137
|
+
const id = `lsb_${(0, import_node_crypto17.randomUUID)().replace(/-/g, "")}`;
|
|
32553
33138
|
const coverage = {
|
|
32554
33139
|
requested: ["website_crawl", "structured_data", "services_products", "service_areas", "genuine_images", "staff_team", "review_sources"],
|
|
32555
33140
|
crawl: { state: "queued", pagesDiscovered: 0, pagesCaptured: 0 },
|
|
@@ -32690,11 +33275,11 @@ async function getPublicLocalSourcebook(category, state, slug4) {
|
|
|
32690
33275
|
const result = await getDb().execute({ sql: `SELECT r.payload_json FROM local_sourcebook_submissions s JOIN local_sourcebook_revisions r ON r.submission_id = s.id AND r.revision = s.published_revision WHERE s.category = ? AND s.state = ? AND s.slug = ? AND s.published_revision IS NOT NULL AND s.status NOT IN ('unpublished', 'rejected') LIMIT 1`, args: [category, state, slug4] });
|
|
32691
33276
|
return result.rows[0] ? parseJson3(result.rows[0].payload_json) : null;
|
|
32692
33277
|
}
|
|
32693
|
-
var
|
|
33278
|
+
var import_node_crypto17, LOCAL_SOURCEBOOK_CATEGORIES, schemaPromise4, schemaDb4;
|
|
32694
33279
|
var init_local_sourcebook_repository = __esm({
|
|
32695
33280
|
"src/api/local-sourcebook-repository.ts"() {
|
|
32696
33281
|
"use strict";
|
|
32697
|
-
|
|
33282
|
+
import_node_crypto17 = require("crypto");
|
|
32698
33283
|
init_db();
|
|
32699
33284
|
LOCAL_SOURCEBOOK_CATEGORIES = ["home", "professional", "restaurants", "financial", "realestate", "auto", "wellness"];
|
|
32700
33285
|
schemaPromise4 = null;
|
|
@@ -33846,7 +34431,7 @@ var init_local_sourcebook_schema = __esm({
|
|
|
33846
34431
|
|
|
33847
34432
|
// src/api/local-sourcebook-compiler.ts
|
|
33848
34433
|
function digest(value) {
|
|
33849
|
-
return (0,
|
|
34434
|
+
return (0, import_node_crypto18.createHash)("sha256").update(value).digest("hex").slice(0, 20);
|
|
33850
34435
|
}
|
|
33851
34436
|
function unique(values, limit = 100) {
|
|
33852
34437
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -34283,11 +34868,11 @@ function compileLocalSourcebookListing(input) {
|
|
|
34283
34868
|
}
|
|
34284
34869
|
};
|
|
34285
34870
|
}
|
|
34286
|
-
var
|
|
34871
|
+
var import_node_crypto18, CATEGORY_LABELS, STATE_NAMES, GENERIC_HEADINGS, SERVICE_PATH, PRODUCT_PATH, TEAM_PATH, WORK_PATH, CREDENTIAL_PATH, BLOG_PATH, LOCATION_PATH, REVIEW_THEME_RULES;
|
|
34287
34872
|
var init_local_sourcebook_compiler = __esm({
|
|
34288
34873
|
"src/api/local-sourcebook-compiler.ts"() {
|
|
34289
34874
|
"use strict";
|
|
34290
|
-
|
|
34875
|
+
import_node_crypto18 = require("crypto");
|
|
34291
34876
|
init_local_sourcebook_public_urls();
|
|
34292
34877
|
init_local_sourcebook_schema();
|
|
34293
34878
|
CATEGORY_LABELS = {
|
|
@@ -34644,6 +35229,11 @@ async function prepareSiteExtractStart(input) {
|
|
|
34644
35229
|
urlsPerBrowser: input.urlsPerBrowser,
|
|
34645
35230
|
formats: input.formats,
|
|
34646
35231
|
downloadImages: input.downloadImages,
|
|
35232
|
+
renderJavaScript: input.renderJavaScript === true,
|
|
35233
|
+
captureRenderedDom: input.captureRenderedDom === true,
|
|
35234
|
+
semanticSimilarity: input.semanticSimilarity === true,
|
|
35235
|
+
similarityThreshold: input.similarityThreshold,
|
|
35236
|
+
similarityMaxPairs: input.similarityMaxPairs,
|
|
34647
35237
|
...input.waybackReplay ? {
|
|
34648
35238
|
waybackReplay: input.waybackReplay,
|
|
34649
35239
|
disableLinkDiscovery: true
|
|
@@ -35388,15 +35978,15 @@ function normalizeIdempotencyKey(value) {
|
|
|
35388
35978
|
return key;
|
|
35389
35979
|
}
|
|
35390
35980
|
function tokenFor(id, idempotencyKey4) {
|
|
35391
|
-
return (0,
|
|
35981
|
+
return (0, import_node_crypto19.createHmac)("sha256", billingSecret()).update(id).update(":").update(idempotencyKey4).digest("base64url");
|
|
35392
35982
|
}
|
|
35393
35983
|
function tokenHash(token6) {
|
|
35394
|
-
return (0,
|
|
35984
|
+
return (0, import_node_crypto19.createHash)("sha256").update(token6).digest("hex");
|
|
35395
35985
|
}
|
|
35396
35986
|
function verifyToken(row, token6) {
|
|
35397
35987
|
const expected = Buffer.from(row.token_hash, "hex");
|
|
35398
35988
|
const actual = Buffer.from(tokenHash(token6), "hex");
|
|
35399
|
-
if (expected.length !== actual.length || !(0,
|
|
35989
|
+
if (expected.length !== actual.length || !(0, import_node_crypto19.timingSafeEqual)(expected, actual)) {
|
|
35400
35990
|
throw new UnifiedBillingError("unauthorized", "invalid billing authorization token", 401);
|
|
35401
35991
|
}
|
|
35402
35992
|
}
|
|
@@ -35511,7 +36101,7 @@ async function authorizeScheduledRun(args) {
|
|
|
35511
36101
|
{ balanceMc, requiredMc: SCHEDULED_RUN_BASE_MC }
|
|
35512
36102
|
);
|
|
35513
36103
|
}
|
|
35514
|
-
const id = (0,
|
|
36104
|
+
const id = (0, import_node_crypto19.randomUUID)();
|
|
35515
36105
|
const token6 = tokenFor(id, idempotencyKey4);
|
|
35516
36106
|
const expiresAt = new Date(Date.now() + AUTHORIZATION_TTL_MS).toISOString();
|
|
35517
36107
|
const inserted = await getDb().execute({
|
|
@@ -35579,7 +36169,7 @@ async function startScheduledRun(args) {
|
|
|
35579
36169
|
if (!authorization || !["starting", "started"].includes(authorization.status)) {
|
|
35580
36170
|
throw new UnifiedBillingError("authorization_closed", "billing authorization is no longer startable", 409);
|
|
35581
36171
|
}
|
|
35582
|
-
const eventId = existing?.id ?? (0,
|
|
36172
|
+
const eventId = existing?.id ?? (0, import_node_crypto19.randomUUID)();
|
|
35583
36173
|
if (!existing) {
|
|
35584
36174
|
await getDb().execute({
|
|
35585
36175
|
sql: "INSERT OR IGNORE INTO billing_events (id, user_id, authorization_id, idempotency_key, billing_class, source_surface, status, amount_mc, multiplier_bps, metadata) VALUES (?, ?, ?, ?, ?, ?, 'capturing', ?, ?, ?)",
|
|
@@ -35718,7 +36308,7 @@ async function settleScheduledRun(args) {
|
|
|
35718
36308
|
...modelCostUnreported ? { modelCostUnreported: true } : {},
|
|
35719
36309
|
...pendingReason ? { reason: pendingReason } : {}
|
|
35720
36310
|
});
|
|
35721
|
-
const eventId = existing?.id ?? (0,
|
|
36311
|
+
const eventId = existing?.id ?? (0, import_node_crypto19.randomUUID)();
|
|
35722
36312
|
const status = pendingReason ? "cost_pending" : "settling";
|
|
35723
36313
|
const eventValues = [
|
|
35724
36314
|
modelMc,
|
|
@@ -35843,11 +36433,11 @@ async function voidScheduledRunAuthorization(args) {
|
|
|
35843
36433
|
}
|
|
35844
36434
|
return { ok: true, status: authorization.status };
|
|
35845
36435
|
}
|
|
35846
|
-
var
|
|
36436
|
+
var import_node_crypto19, SCHEDULED_RUN_BILLING_CLASS, SCHEDULED_RUN_SOURCE_SURFACE, AUTHORIZATION_TTL_MS, UnifiedBillingError;
|
|
35847
36437
|
var init_unified_billing = __esm({
|
|
35848
36438
|
"src/api/unified-billing.ts"() {
|
|
35849
36439
|
"use strict";
|
|
35850
|
-
|
|
36440
|
+
import_node_crypto19 = require("crypto");
|
|
35851
36441
|
init_db();
|
|
35852
36442
|
init_rates();
|
|
35853
36443
|
init_scheduling_access();
|
|
@@ -35879,14 +36469,14 @@ function getSessionSecret() {
|
|
|
35879
36469
|
function safeEqualHex(a, b) {
|
|
35880
36470
|
if (a.length !== b.length) return false;
|
|
35881
36471
|
try {
|
|
35882
|
-
return (0,
|
|
36472
|
+
return (0, import_node_crypto20.timingSafeEqual)(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
|
|
35883
36473
|
} catch {
|
|
35884
36474
|
return false;
|
|
35885
36475
|
}
|
|
35886
36476
|
}
|
|
35887
36477
|
function signSession(userId) {
|
|
35888
36478
|
const payload = String(userId);
|
|
35889
|
-
const sig = (0,
|
|
36479
|
+
const sig = (0, import_node_crypto20.createHmac)("sha256", secret()).update(payload).digest("hex");
|
|
35890
36480
|
return `${payload}.${sig}`;
|
|
35891
36481
|
}
|
|
35892
36482
|
function verifySession(token6) {
|
|
@@ -35894,16 +36484,16 @@ function verifySession(token6) {
|
|
|
35894
36484
|
if (dot === -1) return null;
|
|
35895
36485
|
const payload = token6.slice(0, dot);
|
|
35896
36486
|
const sig = token6.slice(dot + 1);
|
|
35897
|
-
const expected = (0,
|
|
36487
|
+
const expected = (0, import_node_crypto20.createHmac)("sha256", secret()).update(payload).digest("hex");
|
|
35898
36488
|
if (!safeEqualHex(sig, expected)) return null;
|
|
35899
36489
|
const id = parseInt(payload);
|
|
35900
36490
|
return isNaN(id) ? null : id;
|
|
35901
36491
|
}
|
|
35902
|
-
var
|
|
36492
|
+
var import_node_crypto20, isProduction, secret;
|
|
35903
36493
|
var init_session = __esm({
|
|
35904
36494
|
"src/api/session.ts"() {
|
|
35905
36495
|
"use strict";
|
|
35906
|
-
|
|
36496
|
+
import_node_crypto20 = require("crypto");
|
|
35907
36497
|
isProduction = () => process.env.NODE_ENV === "production" || process.env.VERCEL === "1";
|
|
35908
36498
|
secret = () => getSessionSecret();
|
|
35909
36499
|
}
|
|
@@ -35921,11 +36511,11 @@ function isMemoryOperator(email) {
|
|
|
35921
36511
|
return ops.includes(email.trim().toLowerCase());
|
|
35922
36512
|
}
|
|
35923
36513
|
function encKey() {
|
|
35924
|
-
return (0,
|
|
36514
|
+
return (0, import_node_crypto21.scryptSync)(getSessionSecret(), "mcp-memory-key-v1", 32);
|
|
35925
36515
|
}
|
|
35926
36516
|
function encryptMemoryKey(secret2) {
|
|
35927
|
-
const iv = (0,
|
|
35928
|
-
const cipher = (0,
|
|
36517
|
+
const iv = (0, import_node_crypto21.randomBytes)(12);
|
|
36518
|
+
const cipher = (0, import_node_crypto21.createCipheriv)("aes-256-gcm", encKey(), iv);
|
|
35929
36519
|
const enc = Buffer.concat([cipher.update(secret2, "utf8"), cipher.final()]);
|
|
35930
36520
|
const tag = cipher.getAuthTag();
|
|
35931
36521
|
return `${iv.toString("base64")}:${tag.toString("base64")}:${enc.toString("base64")}`;
|
|
@@ -35933,7 +36523,7 @@ function encryptMemoryKey(secret2) {
|
|
|
35933
36523
|
function decryptMemoryKey(stored) {
|
|
35934
36524
|
try {
|
|
35935
36525
|
const [ivB, tagB, dataB] = stored.split(":");
|
|
35936
|
-
const decipher = (0,
|
|
36526
|
+
const decipher = (0, import_node_crypto21.createDecipheriv)("aes-256-gcm", encKey(), Buffer.from(ivB, "base64"));
|
|
35937
36527
|
decipher.setAuthTag(Buffer.from(tagB, "base64"));
|
|
35938
36528
|
return Buffer.concat([decipher.update(Buffer.from(dataB, "base64")), decipher.final()]).toString("utf8");
|
|
35939
36529
|
} catch {
|
|
@@ -36047,11 +36637,11 @@ async function syncScheduledActionCredentials(user) {
|
|
|
36047
36637
|
}, {});
|
|
36048
36638
|
return { ok: res.ok, error: res.error };
|
|
36049
36639
|
}
|
|
36050
|
-
var
|
|
36640
|
+
var import_node_crypto21, import_provision_defaults, import_set_schedule_entitlement, MEMORY_BASE_URL, ADMIN_KEY;
|
|
36051
36641
|
var init_memory = __esm({
|
|
36052
36642
|
"src/api/memory.ts"() {
|
|
36053
36643
|
"use strict";
|
|
36054
|
-
|
|
36644
|
+
import_node_crypto21 = require("crypto");
|
|
36055
36645
|
init_session();
|
|
36056
36646
|
init_db();
|
|
36057
36647
|
init_rates();
|
|
@@ -36101,7 +36691,7 @@ var init_connected_cost_telemetry = __esm({
|
|
|
36101
36691
|
|
|
36102
36692
|
// src/api/connected-usage-billing.ts
|
|
36103
36693
|
function hash(value) {
|
|
36104
|
-
return (0,
|
|
36694
|
+
return (0, import_node_crypto22.createHash)("sha256").update(value).digest("hex");
|
|
36105
36695
|
}
|
|
36106
36696
|
function eventKey(idempotencyKey4) {
|
|
36107
36697
|
return `connected-usage:${hash(idempotencyKey4)}`;
|
|
@@ -36373,7 +36963,7 @@ async function settleConnectedUsage(rawInput) {
|
|
|
36373
36963
|
sql: `INSERT OR IGNORE INTO billing_events
|
|
36374
36964
|
(id, user_id, idempotency_key, billing_class, source_surface, status, amount_mc, metadata)
|
|
36375
36965
|
VALUES (?, ?, ?, ?, ?, 'settling', ?, ?)`,
|
|
36376
|
-
args: [(0,
|
|
36966
|
+
args: [(0, import_node_crypto22.randomUUID)(), user.id, key, CONNECTED_USAGE_BILLING_CLASS, input.sourceSurface, charge2.amountMc, encodeMetadata(storedMetadata)]
|
|
36377
36967
|
});
|
|
36378
36968
|
let event2 = await readEvent(key);
|
|
36379
36969
|
if (!event2) throw new Error("connected usage receipt insert completed without a readable event");
|
|
@@ -36462,11 +37052,11 @@ async function listConnectedUsageHistory(userId, limit = 100) {
|
|
|
36462
37052
|
}
|
|
36463
37053
|
return history;
|
|
36464
37054
|
}
|
|
36465
|
-
var
|
|
37055
|
+
var import_node_crypto22, import_zod17, CONNECTED_USAGE_BILLING_CLASS, CONNECTED_USAGE_DEFAULT_SOURCE_SURFACE, ConnectedUsageSafeMetadataSchema, ConnectedUsageSettlementInputSchema, ConnectedUsagePreflightInputSchema, ConnectedUsageBillingError;
|
|
36466
37056
|
var init_connected_usage_billing = __esm({
|
|
36467
37057
|
"src/api/connected-usage-billing.ts"() {
|
|
36468
37058
|
"use strict";
|
|
36469
|
-
|
|
37059
|
+
import_node_crypto22 = require("crypto");
|
|
36470
37060
|
import_zod17 = require("zod");
|
|
36471
37061
|
init_connected_cost_telemetry();
|
|
36472
37062
|
init_db();
|
|
@@ -38115,7 +38705,27 @@ var init_server_schemas = __esm({
|
|
|
38115
38705
|
downloadImages: import_zod22.z.boolean().optional(),
|
|
38116
38706
|
preserveMedia: import_zod22.z.boolean().optional(),
|
|
38117
38707
|
delivery: import_zod22.z.enum(["auto", "artifact"]).optional(),
|
|
38118
|
-
formats: import_zod22.z.array(import_zod22.z.enum(["markdown", "html", "links", "json", "images", "branding", "issues"])).optional()
|
|
38708
|
+
formats: import_zod22.z.array(import_zod22.z.enum(["markdown", "html", "links", "json", "images", "branding", "issues"])).optional(),
|
|
38709
|
+
renderJavaScript: import_zod22.z.boolean().optional(),
|
|
38710
|
+
captureRenderedDom: import_zod22.z.boolean().optional(),
|
|
38711
|
+
semanticSimilarity: import_zod22.z.boolean().optional(),
|
|
38712
|
+
similarityThreshold: import_zod22.z.number().min(0).max(1).optional(),
|
|
38713
|
+
similarityMaxPairs: import_zod22.z.number().int().min(1).max(5e4).optional()
|
|
38714
|
+
}).superRefine((value, ctx) => {
|
|
38715
|
+
if (value.semanticSimilarity && (value.maxPages ?? 100) > 500) {
|
|
38716
|
+
ctx.addIssue({
|
|
38717
|
+
code: import_zod22.z.ZodIssueCode.custom,
|
|
38718
|
+
path: ["maxPages"],
|
|
38719
|
+
message: "semanticSimilarity supports at most 500 pages per analysis."
|
|
38720
|
+
});
|
|
38721
|
+
}
|
|
38722
|
+
if (value.semanticSimilarity && value.wayback) {
|
|
38723
|
+
ctx.addIssue({
|
|
38724
|
+
code: import_zod22.z.ZodIssueCode.custom,
|
|
38725
|
+
path: ["wayback"],
|
|
38726
|
+
message: "semanticSimilarity analyzes one live rendered corpus and cannot be combined with a Wayback timeline."
|
|
38727
|
+
});
|
|
38728
|
+
}
|
|
38119
38729
|
});
|
|
38120
38730
|
SiteExportReadBodySchema = import_zod22.z.object({
|
|
38121
38731
|
jobId: import_zod22.z.string().trim().min(1),
|
|
@@ -40415,7 +41025,7 @@ async function applyAdjustment(input) {
|
|
|
40415
41025
|
const credits = validateCredits(input.credits, input.confirmLarge === true);
|
|
40416
41026
|
const reason = validateReason(input.reason);
|
|
40417
41027
|
const actor = validateActor(input.actor);
|
|
40418
|
-
const reference = input.reference?.trim() || `adj_${(0,
|
|
41028
|
+
const reference = input.reference?.trim() || `adj_${(0, import_node_crypto23.randomUUID)()}`;
|
|
40419
41029
|
if (reference.length > 120) throw new AdminCreditError(400, "reference must be at most 120 characters");
|
|
40420
41030
|
const db = getDb();
|
|
40421
41031
|
const existing = await db.execute({
|
|
@@ -40560,11 +41170,11 @@ async function lookupAccount(target, limit = 20) {
|
|
|
40560
41170
|
}))
|
|
40561
41171
|
};
|
|
40562
41172
|
}
|
|
40563
|
-
var
|
|
41173
|
+
var import_node_crypto23, MIN_ADJUSTMENT_CREDITS, LARGE_ADJUSTMENT_CREDITS, MAX_ADJUSTMENT_CREDITS, MIN_REASON_LENGTH, MAX_REASON_LENGTH, MAX_ACTOR_LENGTH, AdminCreditError;
|
|
40564
41174
|
var init_admin_credits = __esm({
|
|
40565
41175
|
"src/api/admin-credits.ts"() {
|
|
40566
41176
|
"use strict";
|
|
40567
|
-
|
|
41177
|
+
import_node_crypto23 = require("crypto");
|
|
40568
41178
|
init_db();
|
|
40569
41179
|
init_rates();
|
|
40570
41180
|
MIN_ADJUSTMENT_CREDITS = 1;
|
|
@@ -42529,7 +43139,7 @@ async function packageMapsMedia(args) {
|
|
|
42529
43139
|
files.push({ path: "summary.json", content: Buffer.from(JSON.stringify(summary, null, 2)) });
|
|
42530
43140
|
files.push({ path: "images.jsonl", content: Buffer.from(cleanImages.map((image) => JSON.stringify(image)).join("\n") + "\n") });
|
|
42531
43141
|
const archive = await zipBuffer(files);
|
|
42532
|
-
const id = (0,
|
|
43142
|
+
const id = (0, import_node_crypto24.randomBytes)(6).toString("hex");
|
|
42533
43143
|
const pointer = await createPrivateArtifact({
|
|
42534
43144
|
policy: policy3(),
|
|
42535
43145
|
ownerId: args.ownerId,
|
|
@@ -42542,13 +43152,13 @@ async function packageMapsMedia(args) {
|
|
|
42542
43152
|
const localPath = token() ? null : (0, import_node_path13.join)(process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || (0, import_node_path13.join)((0, import_node_os9.homedir)(), "Downloads", "mcp-scraper"), "blobs", pointer.artifactId);
|
|
42543
43153
|
return { media: args.media, artifact: { ...pointer, localPath } };
|
|
42544
43154
|
}
|
|
42545
|
-
var import_node_os9, import_node_path13,
|
|
43155
|
+
var import_node_os9, import_node_path13, import_node_crypto24, import_yazl2, import_p_limit5, MAPS_MEDIA_ARTIFACT_PREFIX, MAPS_MEDIA_ARTIFACT_TTL_MS, MAPS_MEDIA_DOWNLOAD_TTL_MS, MAX_IMAGE_BYTES2, MAX_ARCHIVE_IMAGE_BYTES, MAX_INLINE_IMAGE_BYTES, MAX_INLINE_TOTAL_BYTES, DOWNLOAD_CONCURRENCY, MAX_REDIRECTS;
|
|
42546
43156
|
var init_maps_media_artifacts = __esm({
|
|
42547
43157
|
"src/api/maps-media-artifacts.ts"() {
|
|
42548
43158
|
"use strict";
|
|
42549
43159
|
import_node_os9 = require("os");
|
|
42550
43160
|
import_node_path13 = require("path");
|
|
42551
|
-
|
|
43161
|
+
import_node_crypto24 = require("crypto");
|
|
42552
43162
|
import_yazl2 = require("yazl");
|
|
42553
43163
|
import_p_limit5 = __toESM(require("p-limit"), 1);
|
|
42554
43164
|
init_private_artifacts();
|
|
@@ -43172,7 +43782,7 @@ function retryDelaySeconds(attempts) {
|
|
|
43172
43782
|
}
|
|
43173
43783
|
async function dispatchPendingDirectoryWorkflows(limit = 25) {
|
|
43174
43784
|
const rows = await claimDirectoryWorkflowOutbox({
|
|
43175
|
-
workerId: `directory-dispatch-${process.pid}-${(0,
|
|
43785
|
+
workerId: `directory-dispatch-${process.pid}-${(0, import_node_crypto25.randomUUID)().slice(0, 8)}`,
|
|
43176
43786
|
limit
|
|
43177
43787
|
});
|
|
43178
43788
|
const result = { claimed: rows.length, dispatched: 0, failed: 0 };
|
|
@@ -43194,11 +43804,11 @@ async function dispatchPendingDirectoryWorkflows(limit = 25) {
|
|
|
43194
43804
|
}
|
|
43195
43805
|
return result;
|
|
43196
43806
|
}
|
|
43197
|
-
var
|
|
43807
|
+
var import_node_crypto25;
|
|
43198
43808
|
var init_directory_workflow_dispatch = __esm({
|
|
43199
43809
|
"src/api/directory-workflow-dispatch.ts"() {
|
|
43200
43810
|
"use strict";
|
|
43201
|
-
|
|
43811
|
+
import_node_crypto25 = require("crypto");
|
|
43202
43812
|
init_client();
|
|
43203
43813
|
init_directory_workflow_repository();
|
|
43204
43814
|
}
|
|
@@ -43210,7 +43820,7 @@ function safeOptions(options) {
|
|
|
43210
43820
|
return safe2;
|
|
43211
43821
|
}
|
|
43212
43822
|
function requestFingerprint(options) {
|
|
43213
|
-
return (0,
|
|
43823
|
+
return (0, import_node_crypto26.createHash)("sha256").update(JSON.stringify(safeOptions(options))).digest("hex");
|
|
43214
43824
|
}
|
|
43215
43825
|
function idempotencyKey(raw) {
|
|
43216
43826
|
if (raw !== void 0) {
|
|
@@ -43219,14 +43829,14 @@ function idempotencyKey(raw) {
|
|
|
43219
43829
|
if (trimmed.length > 500) return { ok: false, message: "Idempotency-Key must be 500 characters or fewer." };
|
|
43220
43830
|
return { ok: true, key: trimmed };
|
|
43221
43831
|
}
|
|
43222
|
-
return { ok: true, key: `directory-${(0,
|
|
43832
|
+
return { ok: true, key: `directory-${(0, import_node_crypto26.randomUUID)()}` };
|
|
43223
43833
|
}
|
|
43224
43834
|
function debitKeyFor(userId, responseKey) {
|
|
43225
|
-
const digest2 = (0,
|
|
43835
|
+
const digest2 = (0, import_node_crypto26.createHash)("sha256").update(String(userId)).update("\0").update(responseKey).digest("hex");
|
|
43226
43836
|
return `directory-workflow:${userId}:${digest2}`;
|
|
43227
43837
|
}
|
|
43228
43838
|
function jobId() {
|
|
43229
|
-
return `dir_${(0,
|
|
43839
|
+
return `dir_${(0, import_node_crypto26.randomUUID)().replace(/-/g, "")}`;
|
|
43230
43840
|
}
|
|
43231
43841
|
function publicStatus(job, result) {
|
|
43232
43842
|
if (job.status === "failed") return "failed";
|
|
@@ -43335,7 +43945,7 @@ async function runSynchronously(c, user, options, plan, responseKey) {
|
|
|
43335
43945
|
const csv = renderDirectoryWorkflowCsv(result);
|
|
43336
43946
|
const artifact = await createDirectoryCsvArtifact({
|
|
43337
43947
|
ownerId: String(user.id),
|
|
43338
|
-
jobId: (0,
|
|
43948
|
+
jobId: (0, import_node_crypto26.createHash)("sha256").update(debitKey2).digest("hex").slice(0, 32),
|
|
43339
43949
|
createdAt: result.extractedAt,
|
|
43340
43950
|
filename: `${options.state}-${options.query}-directory.csv`,
|
|
43341
43951
|
csv,
|
|
@@ -43391,11 +44001,11 @@ async function runSynchronously(c, user, options, plan, responseKey) {
|
|
|
43391
44001
|
await releaseConcurrencyGate(gate.lockId);
|
|
43392
44002
|
}
|
|
43393
44003
|
}
|
|
43394
|
-
var
|
|
44004
|
+
var import_node_crypto26, import_hono16, directoryApp;
|
|
43395
44005
|
var init_directory_routes = __esm({
|
|
43396
44006
|
"src/api/directory-routes.ts"() {
|
|
43397
44007
|
"use strict";
|
|
43398
|
-
|
|
44008
|
+
import_node_crypto26 = require("crypto");
|
|
43399
44009
|
import_hono16 = require("hono");
|
|
43400
44010
|
init_api_auth();
|
|
43401
44011
|
init_db();
|
|
@@ -43613,10 +44223,10 @@ function bounded(value, field, min, max) {
|
|
|
43613
44223
|
return normalized;
|
|
43614
44224
|
}
|
|
43615
44225
|
function newLeadListUploadId() {
|
|
43616
|
-
return `upl_${(0,
|
|
44226
|
+
return `upl_${(0, import_node_crypto27.randomUUID)().replace(/-/g, "")}`;
|
|
43617
44227
|
}
|
|
43618
44228
|
function newImportedLeadListId() {
|
|
43619
|
-
return `lst_${(0,
|
|
44229
|
+
return `lst_${(0, import_node_crypto27.randomUUID)().replace(/-/g, "")}`;
|
|
43620
44230
|
}
|
|
43621
44231
|
async function ensureLeadListImportRepositorySchema() {
|
|
43622
44232
|
const db = getDb();
|
|
@@ -43816,11 +44426,11 @@ async function deleteExpiredLeadListInputRecords(now = /* @__PURE__ */ new Date(
|
|
|
43816
44426
|
], "write");
|
|
43817
44427
|
return { uploads: Number(uploads.rowsAffected ?? 0), lists: Number(lists.rowsAffected ?? 0) };
|
|
43818
44428
|
}
|
|
43819
|
-
var
|
|
44429
|
+
var import_node_crypto27, schemaDb5, schemaPromise5;
|
|
43820
44430
|
var init_lead_list_import_repository = __esm({
|
|
43821
44431
|
"src/api/lead-list-import-repository.ts"() {
|
|
43822
44432
|
"use strict";
|
|
43823
|
-
|
|
44433
|
+
import_node_crypto27 = require("crypto");
|
|
43824
44434
|
init_db();
|
|
43825
44435
|
schemaDb5 = null;
|
|
43826
44436
|
schemaPromise5 = null;
|
|
@@ -43862,7 +44472,7 @@ function safeFilenameHint(value) {
|
|
|
43862
44472
|
return cleaned || null;
|
|
43863
44473
|
}
|
|
43864
44474
|
function requestFingerprint2(filenameHint) {
|
|
43865
|
-
return (0,
|
|
44475
|
+
return (0, import_node_crypto28.createHash)("sha256").update(JSON.stringify({ filenameHint })).digest("hex");
|
|
43866
44476
|
}
|
|
43867
44477
|
function publicBaseUrl() {
|
|
43868
44478
|
const configured = process.env.MCP_SCRAPER_PUBLIC_BASE_URL?.trim() || process.env.PUBLIC_BASE_URL?.trim() || (process.env.VERCEL_PROJECT_PRODUCTION_URL ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}` : "") || "https://mcpscraper.dev";
|
|
@@ -44018,7 +44628,7 @@ async function inspectLeadListUpload(uploadId, ownerId2) {
|
|
|
44018
44628
|
maxBytes: LEAD_LIST_UPLOAD_MAX_BYTES
|
|
44019
44629
|
});
|
|
44020
44630
|
if (!buffer) return null;
|
|
44021
|
-
const sha2565 = (0,
|
|
44631
|
+
const sha2565 = (0, import_node_crypto28.createHash)("sha256").update(buffer).digest("hex");
|
|
44022
44632
|
const completed = await completeLeadListUpload({
|
|
44023
44633
|
id: record.id,
|
|
44024
44634
|
ownerId: record.ownerId,
|
|
@@ -44142,11 +44752,11 @@ async function cleanupExpiredLeadListInputs(args = {}) {
|
|
|
44142
44752
|
const records = await deleteExpiredLeadListInputRecords(now);
|
|
44143
44753
|
return { deletedBlobs, deletedUploadRecords: records.uploads, deletedListRecords: records.lists };
|
|
44144
44754
|
}
|
|
44145
|
-
var
|
|
44755
|
+
var import_node_crypto28, import_promises11, import_node_os10, import_node_path14, LEAD_LIST_UPLOAD_PREFIX, LEAD_LIST_NORMALIZED_PREFIX, LEAD_LIST_UPLOAD_MAX_BYTES, LEAD_LIST_UPLOAD_URL_TTL_MS, LEAD_LIST_UPLOAD_SOURCE_TTL_MS, LEAD_LIST_NORMALIZED_TTL_MS, LEAD_LIST_DOWNLOAD_TTL_MS, LEAD_LIST_UPLOAD_MIME_TYPES;
|
|
44146
44756
|
var init_lead_list_input_artifacts = __esm({
|
|
44147
44757
|
"src/api/lead-list-input-artifacts.ts"() {
|
|
44148
44758
|
"use strict";
|
|
44149
|
-
|
|
44759
|
+
import_node_crypto28 = require("crypto");
|
|
44150
44760
|
import_promises11 = require("fs/promises");
|
|
44151
44761
|
import_node_os10 = require("os");
|
|
44152
44762
|
import_node_path14 = require("path");
|
|
@@ -44529,7 +45139,7 @@ function canonicalize(value) {
|
|
|
44529
45139
|
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${canonicalize(object[key])}`).join(",")}}`;
|
|
44530
45140
|
}
|
|
44531
45141
|
function fingerprint(value) {
|
|
44532
|
-
return (0,
|
|
45142
|
+
return (0, import_node_crypto29.createHash)("sha256").update(canonicalize(value)).digest("hex");
|
|
44533
45143
|
}
|
|
44534
45144
|
async function safeJson(c) {
|
|
44535
45145
|
try {
|
|
@@ -44606,11 +45216,11 @@ function textDelimiter(raw, text2, observedMime) {
|
|
|
44606
45216
|
if (observedMime === "text/tab-separated-values") return " ";
|
|
44607
45217
|
return detectLeadListTextDelimiter(text2);
|
|
44608
45218
|
}
|
|
44609
|
-
var
|
|
45219
|
+
var import_node_crypto29, import_hono17, leadListInputApp;
|
|
44610
45220
|
var init_lead_list_input_routes = __esm({
|
|
44611
45221
|
"src/api/lead-list-input-routes.ts"() {
|
|
44612
45222
|
"use strict";
|
|
44613
|
-
|
|
45223
|
+
import_node_crypto29 = require("crypto");
|
|
44614
45224
|
import_hono17 = require("hono");
|
|
44615
45225
|
init_api_auth();
|
|
44616
45226
|
init_lead_list_input_artifacts();
|
|
@@ -44802,7 +45412,7 @@ function retryDelaySeconds2(attempts) {
|
|
|
44802
45412
|
return Math.min(3600, Math.max(15, 15 * 2 ** Math.min(8, Math.max(0, attempts - 1))));
|
|
44803
45413
|
}
|
|
44804
45414
|
async function dispatchPendingLeadListEnrichments(limit = 25) {
|
|
44805
|
-
const rows = await claimLeadListEnrichmentOutbox({ workerId: `lead-list-dispatch-${process.pid}-${(0,
|
|
45415
|
+
const rows = await claimLeadListEnrichmentOutbox({ workerId: `lead-list-dispatch-${process.pid}-${(0, import_node_crypto30.randomUUID)().slice(0, 8)}`, limit });
|
|
44806
45416
|
const result = { claimed: rows.length, dispatched: 0, failed: 0 };
|
|
44807
45417
|
for (const row of rows) {
|
|
44808
45418
|
if (!row.claimToken) continue;
|
|
@@ -44821,11 +45431,11 @@ async function dispatchPendingLeadListEnrichments(limit = 25) {
|
|
|
44821
45431
|
}
|
|
44822
45432
|
return result;
|
|
44823
45433
|
}
|
|
44824
|
-
var
|
|
45434
|
+
var import_node_crypto30;
|
|
44825
45435
|
var init_lead_list_enrichment_dispatch = __esm({
|
|
44826
45436
|
"src/api/lead-list-enrichment-dispatch.ts"() {
|
|
44827
45437
|
"use strict";
|
|
44828
|
-
|
|
45438
|
+
import_node_crypto30 = require("crypto");
|
|
44829
45439
|
init_client();
|
|
44830
45440
|
init_lead_list_enrichment_repository();
|
|
44831
45441
|
}
|
|
@@ -44841,15 +45451,15 @@ function idempotencyKey2(raw) {
|
|
|
44841
45451
|
return { ok: true, value };
|
|
44842
45452
|
}
|
|
44843
45453
|
function newJobId() {
|
|
44844
|
-
return `lle_${(0,
|
|
45454
|
+
return `lle_${(0, import_node_crypto31.randomUUID)().replace(/-/g, "")}`;
|
|
44845
45455
|
}
|
|
44846
45456
|
function debitKeyFor2(userId, key) {
|
|
44847
|
-
const digest2 = (0,
|
|
45457
|
+
const digest2 = (0, import_node_crypto31.createHash)("sha256").update(String(userId)).update("\0").update(key).digest("hex");
|
|
44848
45458
|
return `lead-list-enrichment:${userId}:${digest2}`;
|
|
44849
45459
|
}
|
|
44850
45460
|
function inlineSourceDigest(headers, rows) {
|
|
44851
45461
|
const values = rows.map((row) => headers.map((header) => row[header] ?? null));
|
|
44852
|
-
return (0,
|
|
45462
|
+
return (0, import_node_crypto31.createHash)("sha256").update(stableCanonicalJson({ headers, values })).digest("hex");
|
|
44853
45463
|
}
|
|
44854
45464
|
function issueMessage(error) {
|
|
44855
45465
|
const issue = error.issues[0];
|
|
@@ -45047,11 +45657,11 @@ async function resolveInput(ownerId2, parsed) {
|
|
|
45047
45657
|
sourceDigest: sourceDigest ?? inlineSourceDigest(normalized.headers, rows)
|
|
45048
45658
|
};
|
|
45049
45659
|
}
|
|
45050
|
-
var
|
|
45660
|
+
var import_node_crypto31, import_hono18, import_zod31, SourceSchema, StartSchema, TERMINAL, leadListEnrichmentApp;
|
|
45051
45661
|
var init_lead_list_enrichment_routes = __esm({
|
|
45052
45662
|
"src/api/lead-list-enrichment-routes.ts"() {
|
|
45053
45663
|
"use strict";
|
|
45054
|
-
|
|
45664
|
+
import_node_crypto31 = require("crypto");
|
|
45055
45665
|
import_hono18 = require("hono");
|
|
45056
45666
|
import_zod31 = require("zod");
|
|
45057
45667
|
init_api_auth();
|
|
@@ -48244,7 +48854,7 @@ async function readManifestFromSummary(summary) {
|
|
|
48244
48854
|
function webhookSignature(body, timestamp2) {
|
|
48245
48855
|
const secret2 = process.env.MCP_SCRAPER_WEBHOOK_SECRET?.trim();
|
|
48246
48856
|
if (!secret2) return null;
|
|
48247
|
-
return (0,
|
|
48857
|
+
return (0, import_node_crypto32.createHmac)("sha256", secret2).update(`${timestamp2}.${body}`).digest("hex");
|
|
48248
48858
|
}
|
|
48249
48859
|
async function deliverWorkflowWebhook(input) {
|
|
48250
48860
|
if (!input.webhookUrl) return;
|
|
@@ -48451,11 +49061,11 @@ async function dispatchDueWorkflowSchedules(apiUrl, limit = 3) {
|
|
|
48451
49061
|
}
|
|
48452
49062
|
return { dispatched: results.length, results };
|
|
48453
49063
|
}
|
|
48454
|
-
var
|
|
49064
|
+
var import_node_crypto32, import_promises14, import_hono21, import_zod41, workflowApp, WorkflowInputSchema, WorkflowIdSchema, CadenceSchema, ScheduleStatusSchema, RunBodySchema, ScheduleCreateSchema, SchedulePatchSchema, TERMINAL_RUN_STATUSES;
|
|
48455
49065
|
var init_workflow_routes = __esm({
|
|
48456
49066
|
"src/api/workflow-routes.ts"() {
|
|
48457
49067
|
"use strict";
|
|
48458
|
-
|
|
49068
|
+
import_node_crypto32 = require("crypto");
|
|
48459
49069
|
import_promises14 = require("fs/promises");
|
|
48460
49070
|
import_hono21 = require("hono");
|
|
48461
49071
|
import_zod41 = require("zod");
|
|
@@ -48736,7 +49346,7 @@ var init_workflow_routes = __esm({
|
|
|
48736
49346
|
// src/serp-intelligence/page-snapshot-extractor.ts
|
|
48737
49347
|
function sha2562(value) {
|
|
48738
49348
|
if (!value) return null;
|
|
48739
|
-
return (0,
|
|
49349
|
+
return (0, import_node_crypto33.createHash)("sha256").update(value).digest("hex");
|
|
48740
49350
|
}
|
|
48741
49351
|
function countWords(markdown) {
|
|
48742
49352
|
const matches = markdown.trim().match(/\b[\p{L}\p{N}][\p{L}\p{N}'-]*\b/gu);
|
|
@@ -49036,11 +49646,11 @@ async function capturePageSnapshots(targets, options = {}) {
|
|
|
49036
49646
|
}
|
|
49037
49647
|
};
|
|
49038
49648
|
}
|
|
49039
|
-
var
|
|
49649
|
+
var import_node_crypto33, import_p_limit6, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_CONTENT_CHARS;
|
|
49040
49650
|
var init_page_snapshot_extractor = __esm({
|
|
49041
49651
|
"src/serp-intelligence/page-snapshot-extractor.ts"() {
|
|
49042
49652
|
"use strict";
|
|
49043
|
-
|
|
49653
|
+
import_node_crypto33 = require("crypto");
|
|
49044
49654
|
import_p_limit6 = __toESM(require("p-limit"), 1);
|
|
49045
49655
|
init_kpo_extractor();
|
|
49046
49656
|
init_url_utils();
|
|
@@ -49536,21 +50146,21 @@ async function logRequestEventBestEffort(input) {
|
|
|
49536
50146
|
}
|
|
49537
50147
|
}
|
|
49538
50148
|
function captureBillingKeys(userId, suppliedKey, body) {
|
|
49539
|
-
const responseKey = suppliedKey?.trim() || (0,
|
|
49540
|
-
const requestFingerprint3 = (0,
|
|
49541
|
-
const keyDigest = (0,
|
|
50149
|
+
const responseKey = suppliedKey?.trim() || (0, import_node_crypto34.randomUUID)();
|
|
50150
|
+
const requestFingerprint3 = (0, import_node_crypto34.createHash)("sha256").update(JSON.stringify(body)).digest("hex");
|
|
50151
|
+
const keyDigest = (0, import_node_crypto34.createHash)("sha256").update(String(userId)).update("\0").update(responseKey).digest("hex");
|
|
49542
50152
|
return {
|
|
49543
50153
|
responseKey,
|
|
49544
50154
|
debitKey: `serp-capture:${userId}:${keyDigest}`,
|
|
49545
50155
|
debitDescription: `${body.query} [request:${requestFingerprint3}]`
|
|
49546
50156
|
};
|
|
49547
50157
|
}
|
|
49548
|
-
var import_hono22,
|
|
50158
|
+
var import_hono22, import_node_crypto34, SERP_INTELLIGENCE_RATE_LIMIT, SERP_INTELLIGENCE_RATE_WINDOW_SECONDS, POST_CAPTURE_ROUTE_LABEL, POST_PAGE_SNAPSHOTS_ROUTE_LABEL, SERP_CAPTURE_BILLING_SOURCE, serpIntelligenceApp;
|
|
49549
50159
|
var init_serp_intelligence_routes = __esm({
|
|
49550
50160
|
"src/api/serp-intelligence-routes.ts"() {
|
|
49551
50161
|
"use strict";
|
|
49552
50162
|
import_hono22 = require("hono");
|
|
49553
|
-
|
|
50163
|
+
import_node_crypto34 = require("crypto");
|
|
49554
50164
|
init_browser_service_env();
|
|
49555
50165
|
init_page_snapshot_extractor();
|
|
49556
50166
|
init_serp_capture_service();
|
|
@@ -49787,7 +50397,7 @@ var PACKAGE_VERSION;
|
|
|
49787
50397
|
var init_version = __esm({
|
|
49788
50398
|
"src/version.ts"() {
|
|
49789
50399
|
"use strict";
|
|
49790
|
-
PACKAGE_VERSION = "0.
|
|
50400
|
+
PACKAGE_VERSION = "0.65.1";
|
|
49791
50401
|
}
|
|
49792
50402
|
});
|
|
49793
50403
|
|
|
@@ -49818,6 +50428,8 @@ seam is noted so you can chain them.
|
|
|
49818
50428
|
- Whole site -> **extract_site** (takes a url). It durably retains complete per-page JSON, acquired HTML,
|
|
49819
50429
|
and Markdown. Poll **check_site_export**, then call **site_export_read** for the manifest or a page view;
|
|
49820
50430
|
call **site_export_image** for downloaded image IDs.
|
|
50431
|
+
- JavaScript-rendered page overlap/cannibalization -> **analyze_site_similarity**. It returns dedicated
|
|
50432
|
+
raw-cosine page pairs, corpus percentiles, threshold clusters, and rendered-page artifacts.
|
|
49821
50433
|
- Wayback replay URLs work with the same tools: \`extract_url\` removes playback chrome and can return
|
|
49822
50434
|
a featured image; \`extract_site\` batches nearby archived HTML captures for the replayed site.
|
|
49823
50435
|
- For multiple archive months, pass \`extract_site.wayback\` with explicit \`months\` or a \`from\`/\`to\`
|
|
@@ -50231,6 +50843,7 @@ var init_output_schema_registry = __esm({
|
|
|
50231
50843
|
ESSENTIAL_OUTPUT_SCHEMA_TOOLS = /* @__PURE__ */ new Set([
|
|
50232
50844
|
"extract_url",
|
|
50233
50845
|
"extract_site",
|
|
50846
|
+
"analyze_site_similarity",
|
|
50234
50847
|
"audit_site",
|
|
50235
50848
|
"check_site_export",
|
|
50236
50849
|
"site_export_read",
|
|
@@ -51628,7 +52241,7 @@ var init_contracts = __esm({
|
|
|
51628
52241
|
});
|
|
51629
52242
|
|
|
51630
52243
|
// src/mcp/mcp-tool-schemas.ts
|
|
51631
|
-
var import_zod45, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, SiteExportReadInputSchema, SiteExportImageInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LeadScalarSchema2, LeadRowSchema, LeadColumnMapSchema2, LeadRowsImportSourceSchema, LeadCsvTextImportSourceSchema, LeadUploadImportSourceSchema, LeadListUploadStartInputSchema, LeadListImportInputSchema, LeadRowsEnrichmentSourceSchema, ImportedLeadListSourceSchema, LeadListEnrichInputSchema, LeadListEnrichStatusInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsGetEntityLinksetInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsClaimInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsHostImageInputSchema, CommonsGetProposalInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookSchemaTypeInputSchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomImageSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, CommonsPublicationSubdomainSchema, CommonsPreparePublicationInputSchema, CommonsValidatePublicationInputSchema, CommonsClaimPublicationInputSchema, CommonsPublishEditorialInputSchema, CommonsUpdateEditorialArticleInputSchema, CommonsGetPublicationInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LeadSuggestedColumnOutputSchema, LeadColumnMapSuggestionOutputSchema, LeadArtifactOutputSchema, LeadListUploadStartOutputSchema, LeadListImportOutputSchema, LeadCandidateOutputSchema, LeadProgressOutputSchema, LeadBillingOutputSchema, LeadAssociatedPersonSourceOutputSchema, LeadAssociatedPersonOutputSchema, LeadSampleRowOutputSchema, LeadListEnrichmentOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, PageMediaAssetOutput, PageMediaArtifactOutput, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, SiteExportReadOutputSchema, SiteExportImageOutputSchema, ArchiveEntryOutputSchema, ArchiveReadOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, WaybackCaptureOutputSchema, MapWaybackSnapshotsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, RedditTrendingOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, TranscriptSignalOutput, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema, ReportArtifactReadInputSchema, ReportArtifactReadOutputSchema, ListServiceConnectionsInputSchema, ListServiceConnectionsOutputSchema, TestServiceConnectionInputSchema, TestServiceConnectionOutputSchema, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, SearchConsoleTableColumnSchema, SearchConsoleTableFilterSchema, ExportSearchConsoleTableDataInputSchema, ExportSearchConsoleTableDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GmailSearchContactsInputSchema, GmailSearchContactsOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
|
|
52244
|
+
var import_zod45, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AnalyzeSiteSimilarityInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, SiteExportReadInputSchema, SiteExportImageInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LeadScalarSchema2, LeadRowSchema, LeadColumnMapSchema2, LeadRowsImportSourceSchema, LeadCsvTextImportSourceSchema, LeadUploadImportSourceSchema, LeadListUploadStartInputSchema, LeadListImportInputSchema, LeadRowsEnrichmentSourceSchema, ImportedLeadListSourceSchema, LeadListEnrichInputSchema, LeadListEnrichStatusInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsGetEntityLinksetInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsClaimInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsHostImageInputSchema, CommonsGetProposalInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookSchemaTypeInputSchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomImageSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, CommonsPublicationSubdomainSchema, CommonsPreparePublicationInputSchema, CommonsValidatePublicationInputSchema, CommonsClaimPublicationInputSchema, CommonsPublishEditorialInputSchema, CommonsUpdateEditorialArticleInputSchema, CommonsGetPublicationInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LeadSuggestedColumnOutputSchema, LeadColumnMapSuggestionOutputSchema, LeadArtifactOutputSchema, LeadListUploadStartOutputSchema, LeadListImportOutputSchema, LeadCandidateOutputSchema, LeadProgressOutputSchema, LeadBillingOutputSchema, LeadAssociatedPersonSourceOutputSchema, LeadAssociatedPersonOutputSchema, LeadSampleRowOutputSchema, LeadListEnrichmentOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, PageMediaAssetOutput, PageMediaArtifactOutput, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, SiteExportReadOutputSchema, SiteExportImageOutputSchema, ArchiveEntryOutputSchema, ArchiveReadOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, WaybackCaptureOutputSchema, MapWaybackSnapshotsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, RedditTrendingOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, TranscriptSignalOutput, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema, ReportArtifactReadInputSchema, ReportArtifactReadOutputSchema, ListServiceConnectionsInputSchema, ListServiceConnectionsOutputSchema, TestServiceConnectionInputSchema, TestServiceConnectionOutputSchema, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, SearchConsoleTableColumnSchema, SearchConsoleTableFilterSchema, ExportSearchConsoleTableDataInputSchema, ExportSearchConsoleTableDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GmailSearchContactsInputSchema, GmailSearchContactsOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
|
|
51632
52245
|
var init_mcp_tool_schemas = __esm({
|
|
51633
52246
|
"src/mcp/mcp-tool-schemas.ts"() {
|
|
51634
52247
|
"use strict";
|
|
@@ -51738,6 +52351,13 @@ var init_mcp_tool_schemas = __esm({
|
|
|
51738
52351
|
preserveMedia: import_zod45.z.boolean().default(false).describe("Include supported images in the export bundle. This is the preferred replacement for downloadImages."),
|
|
51739
52352
|
downloadImages: import_zod45.z.boolean().optional().describe("Deprecated alias for preserveMedia. Omit when using preserveMedia; when omitted, image preservation defaults to false.")
|
|
51740
52353
|
};
|
|
52354
|
+
AnalyzeSiteSimilarityInputSchema = {
|
|
52355
|
+
url: WebsiteUrlOrDomainSchema.describe("Public live site to render and compare. Bare domains default to https://."),
|
|
52356
|
+
maxPages: import_zod45.z.number().int().min(2).max(500).default(100).describe("Maximum rendered pages to compare; default 100, maximum 500."),
|
|
52357
|
+
similarityThreshold: import_zod45.z.number().min(0).max(1).default(0.9).describe("Minimum raw cosine score retained in the pair table; default 0.90."),
|
|
52358
|
+
similarityMaxPairs: import_zod45.z.number().int().min(1).max(5e4).default(1e4).describe("Maximum scored pairs retained, highest first; default 10,000."),
|
|
52359
|
+
idempotencyKey: import_zod45.z.string().trim().min(8).max(200).describe("Required unique opaque ID for this intended analysis. Reuse only when retrying the same call; use a new value for an intentional rerun.")
|
|
52360
|
+
};
|
|
51741
52361
|
AuditSiteInputSchema = {
|
|
51742
52362
|
url: WebsiteUrlOrDomainSchema.describe("Public website URL or domain for a full technical SEO audit (issues, link graph, indexability, headings, images). Bare domains default to https://. For plain content use extract_site instead."),
|
|
51743
52363
|
maxPages: import_zod45.z.number().int().min(1).max(1e4).optional().describe("Maximum pages to crawl and audit. MCP audits always run as durable background exports and return a jobId; poll check_site_export for the hosted audit ZIP."),
|
|
@@ -51750,17 +52370,17 @@ var init_mcp_tool_schemas = __esm({
|
|
|
51750
52370
|
downloadImages: import_zod45.z.boolean().optional().describe("Deprecated alias for preserveMedia. Omit when using preserveMedia; when omitted, image preservation defaults to false.")
|
|
51751
52371
|
};
|
|
51752
52372
|
CheckSiteExportInputSchema = {
|
|
51753
|
-
jobId: import_zod45.z.string().min(1).describe("The jobId returned by extract_site or audit_site. Poll until status is complete, partial, or failed; partial jobs still return
|
|
52373
|
+
jobId: import_zod45.z.string().min(1).describe("The jobId returned by extract_site, analyze_site_similarity, or audit_site. Poll until status is complete, partial, or failed; partial jobs still return successful content and failure details.")
|
|
51754
52374
|
};
|
|
51755
52375
|
SiteExportReadInputSchema = {
|
|
51756
|
-
jobId: import_zod45.z.string().min(1).describe("Site export job ID returned by extract_site or audit_site."),
|
|
52376
|
+
jobId: import_zod45.z.string().min(1).describe("Site export job ID returned by extract_site, analyze_site_similarity, or audit_site."),
|
|
51757
52377
|
pageId: import_zod45.z.string().regex(/^[a-f0-9]{64}$/).optional().describe("Page ID returned by a manifest read. Omit to list the export manifest."),
|
|
51758
52378
|
format: import_zod45.z.enum(["manifest", "json", "html", "markdown"]).default("manifest").describe("manifest lists page/image IDs; JSON, HTML, and Markdown read one page representation."),
|
|
51759
52379
|
offset: import_zod45.z.number().int().min(0).default(0).describe("UTF-8 byte offset. Continue from nextOffset until it is null."),
|
|
51760
52380
|
maxBytes: import_zod45.z.number().int().min(1).max(1e6).default(64e3).describe("Maximum UTF-8 bytes returned in this window.")
|
|
51761
52381
|
};
|
|
51762
52382
|
SiteExportImageInputSchema = {
|
|
51763
|
-
jobId: import_zod45.z.string().min(1).describe("Site export job ID returned by extract_site or audit_site."),
|
|
52383
|
+
jobId: import_zod45.z.string().min(1).describe("Site export job ID returned by extract_site, analyze_site_similarity, or audit_site."),
|
|
51764
52384
|
imageId: import_zod45.z.string().regex(/^[a-f0-9]{64}$/).describe("Downloaded image ID returned by a site_export_read manifest.")
|
|
51765
52385
|
};
|
|
51766
52386
|
ArchiveReadInputSchema = {
|
|
@@ -54928,11 +55548,11 @@ function requireTasksCapability(capabilityValue) {
|
|
|
54928
55548
|
);
|
|
54929
55549
|
}
|
|
54930
55550
|
function taskKey(secret2) {
|
|
54931
|
-
return (0,
|
|
55551
|
+
return (0, import_node_crypto35.createHash)("sha256").update("mcp-scraper-task-handle\0", "utf8").update(secret2, "utf8").digest();
|
|
54932
55552
|
}
|
|
54933
55553
|
function encodeTaskHandle(payload, secret2) {
|
|
54934
|
-
const nonce = (0,
|
|
54935
|
-
const cipher = (0,
|
|
55554
|
+
const nonce = (0, import_node_crypto35.randomBytes)(12);
|
|
55555
|
+
const cipher = (0, import_node_crypto35.createCipheriv)("aes-256-gcm", taskKey(secret2), nonce);
|
|
54936
55556
|
const ciphertext = Buffer.concat([
|
|
54937
55557
|
cipher.update(JSON.stringify(payload), "utf8"),
|
|
54938
55558
|
cipher.final()
|
|
@@ -54949,7 +55569,7 @@ function decodeTaskHandle(taskId, secret2, ownerId2) {
|
|
|
54949
55569
|
const nonce = bytes.subarray(0, 12);
|
|
54950
55570
|
const tag = bytes.subarray(bytes.length - 16);
|
|
54951
55571
|
const ciphertext = bytes.subarray(12, bytes.length - 16);
|
|
54952
|
-
const decipher = (0,
|
|
55572
|
+
const decipher = (0, import_node_crypto35.createDecipheriv)("aes-256-gcm", taskKey(secret2), nonce);
|
|
54953
55573
|
decipher.setAuthTag(tag);
|
|
54954
55574
|
const parsed = JSON.parse(Buffer.concat([
|
|
54955
55575
|
decipher.update(ciphertext),
|
|
@@ -55177,12 +55797,12 @@ async function handleMcpTasksHttpRequest(request, executor, options) {
|
|
|
55177
55797
|
return taskHttpError(id, error instanceof import_server.ProtocolError ? error : new import_server.ProtocolError(-32603, error instanceof Error ? error.message : "Internal error"));
|
|
55178
55798
|
}
|
|
55179
55799
|
}
|
|
55180
|
-
var import_server,
|
|
55800
|
+
var import_server, import_node_crypto35, import_zod46, MCP_TASKS_EXTENSION_ID, TASK_HANDLE_VERSION, TASK_TTL_MS, TASK_POLL_INTERVAL_MS, TASK_INVALID_PARAMS, TASK_MISSING_CAPABILITY;
|
|
55181
55801
|
var init_mcp_tasks_extension = __esm({
|
|
55182
55802
|
"src/mcp/mcp-tasks-extension.ts"() {
|
|
55183
55803
|
"use strict";
|
|
55184
55804
|
import_server = require("@modelcontextprotocol/server");
|
|
55185
|
-
|
|
55805
|
+
import_node_crypto35 = require("crypto");
|
|
55186
55806
|
import_zod46 = require("zod");
|
|
55187
55807
|
MCP_TASKS_EXTENSION_ID = "io.modelcontextprotocol/tasks";
|
|
55188
55808
|
TASK_HANDLE_VERSION = "mt1";
|
|
@@ -55480,7 +56100,7 @@ var init_analytics_mcp_tools = __esm({
|
|
|
55480
56100
|
|
|
55481
56101
|
// src/mcp/paa-mcp-server.ts
|
|
55482
56102
|
function hashOwnerId(callerKey) {
|
|
55483
|
-
return (0,
|
|
56103
|
+
return (0, import_node_crypto36.createHash)("sha256").update(callerKey).digest("hex").slice(0, 24);
|
|
55484
56104
|
}
|
|
55485
56105
|
function liveWebToolAnnotations(title) {
|
|
55486
56106
|
return {
|
|
@@ -55693,6 +56313,21 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
55693
56313
|
await formatExtractSite(await executor.extractSite(input), input, ctx),
|
|
55694
56314
|
requestContext
|
|
55695
56315
|
));
|
|
56316
|
+
server.registerTool("analyze_site_similarity", {
|
|
56317
|
+
title: "Rendered Site Content Similarity",
|
|
56318
|
+
description: "Find overlapping or competing live pages. Forces JavaScript rendering, retains bounded inert DOM plus clean Markdown, and returns raw-cosine pairs, corpus percentiles, clusters, and table-ready files in a private ZIP. Poll check_site_export; the scores measure content overlap, not intent or proof of cannibalization.",
|
|
56319
|
+
inputSchema: AnalyzeSiteSimilarityInputSchema,
|
|
56320
|
+
outputSchema: recordOutputSchema("analyze_site_similarity", ExtractSiteOutputSchema),
|
|
56321
|
+
annotations: { ...liveWebToolAnnotations("Rendered Site Content Similarity"), readOnlyHint: false }
|
|
56322
|
+
}, async (input, requestContext) => tasks.taskify(
|
|
56323
|
+
"site_export",
|
|
56324
|
+
await formatExtractSite(
|
|
56325
|
+
await executor.analyzeSiteSimilarity(input),
|
|
56326
|
+
{ ...input, toolLabel: "Rendered Site Content Similarity" },
|
|
56327
|
+
ctx
|
|
56328
|
+
),
|
|
56329
|
+
requestContext
|
|
56330
|
+
));
|
|
55696
56331
|
server.registerTool("audit_site", {
|
|
55697
56332
|
title: "Technical SEO Audit",
|
|
55698
56333
|
description: `Run a full technical SEO audit (Screaming-Frog-style) on a public website: on-page issues, internal link graph, indexability, heading/image analysis. Pass a new idempotencyKey for each intended audit and reuse it only when retrying that call. Every MCP audit starts a durable export; poll check_site_export for discovered, attempted, successful, failed, and remaining counts plus ${fileBehavior("the saved ZIP.", "the owner-scoped downloadable ZIP.")} Use extract_site instead for plain page content.`,
|
|
@@ -55706,7 +56341,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
55706
56341
|
));
|
|
55707
56342
|
server.registerTool("check_site_export", {
|
|
55708
56343
|
title: "Check Site Export",
|
|
55709
|
-
description: "Poll a background extract_site or audit_site job. Reports
|
|
56344
|
+
description: "Poll a background extract_site, analyze_site_similarity, or audit_site job. Reports page counters and a stable public error envelope when terminal. Complete and partial jobs expose direct AI readback and a downloadable ZIP.",
|
|
55710
56345
|
inputSchema: CheckSiteExportInputSchema,
|
|
55711
56346
|
outputSchema: recordOutputSchema("check_site_export", CheckSiteExportOutputSchema),
|
|
55712
56347
|
annotations: { ...liveWebToolAnnotations("Check Site Export"), readOnlyHint: false }
|
|
@@ -56445,7 +57080,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
56445
57080
|
annotations: { title: "Set Scheduled Action Connections", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
56446
57081
|
}, async (input) => executor.setScheduledActionConnections(input));
|
|
56447
57082
|
}
|
|
56448
|
-
var import_server2, import_zod48, import_node_fs11, import_node_path17,
|
|
57083
|
+
var import_server2, import_zod48, import_node_fs11, import_node_path17, import_node_crypto36, ACTION_CONFIRMATION_SCHEMA;
|
|
56449
57084
|
var init_paa_mcp_server = __esm({
|
|
56450
57085
|
"src/mcp/paa-mcp-server.ts"() {
|
|
56451
57086
|
"use strict";
|
|
@@ -56453,7 +57088,7 @@ var init_paa_mcp_server = __esm({
|
|
|
56453
57088
|
import_zod48 = require("zod");
|
|
56454
57089
|
import_node_fs11 = require("fs");
|
|
56455
57090
|
import_node_path17 = require("path");
|
|
56456
|
-
|
|
57091
|
+
import_node_crypto36 = require("crypto");
|
|
56457
57092
|
init_version();
|
|
56458
57093
|
init_rates();
|
|
56459
57094
|
init_mcp_response_formatter();
|
|
@@ -56574,11 +57209,11 @@ function analyticsReportPath(input, report) {
|
|
|
56574
57209
|
const suffix2 = query.size ? `?${query.toString()}` : "";
|
|
56575
57210
|
return `/analytics/sites/${encodeURIComponent(input.siteId)}/${report}${suffix2}`;
|
|
56576
57211
|
}
|
|
56577
|
-
var
|
|
57212
|
+
var import_node_crypto37, HttpMcpToolExecutor;
|
|
56578
57213
|
var init_http_mcp_tool_executor = __esm({
|
|
56579
57214
|
"src/mcp/http-mcp-tool-executor.ts"() {
|
|
56580
57215
|
"use strict";
|
|
56581
|
-
|
|
57216
|
+
import_node_crypto37 = require("crypto");
|
|
56582
57217
|
init_harvest_timeout();
|
|
56583
57218
|
init_browser_service_env();
|
|
56584
57219
|
init_errors();
|
|
@@ -56647,13 +57282,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
56647
57282
|
});
|
|
56648
57283
|
}
|
|
56649
57284
|
async callDirectoryWorkflowStart(body, explicitIdempotencyKey) {
|
|
56650
|
-
const idempotencyKey4 = `mcp-directory-${(0,
|
|
57285
|
+
const idempotencyKey4 = `mcp-directory-${(0, import_node_crypto37.createHash)("sha256").update(explicitIdempotencyKey).digest("hex")}`;
|
|
56651
57286
|
return this.call("/directory/run", body, this.timeoutMs, "POST", {
|
|
56652
57287
|
"Idempotency-Key": idempotencyKey4
|
|
56653
57288
|
});
|
|
56654
57289
|
}
|
|
56655
57290
|
async callSiteExtractStart(toolName, body, explicitIdempotencyKey) {
|
|
56656
|
-
const idempotencyKey4 = `mcp-site-${(0,
|
|
57291
|
+
const idempotencyKey4 = `mcp-site-${(0, import_node_crypto37.createHash)("sha256").update(toolName).update("\0").update(explicitIdempotencyKey).digest("hex")}`;
|
|
56657
57292
|
return this.call("/extract-site", body, this.timeoutMs, "POST", {
|
|
56658
57293
|
"Idempotency-Key": idempotencyKey4
|
|
56659
57294
|
});
|
|
@@ -56741,6 +57376,19 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
56741
57376
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
56742
57377
|
return this.callSiteExtractStart("extract_site", { ...body, background: true }, idempotencyKey4);
|
|
56743
57378
|
}
|
|
57379
|
+
analyzeSiteSimilarity(input) {
|
|
57380
|
+
const { idempotencyKey: idempotencyKey4, similarityThreshold, similarityMaxPairs, ...body } = input;
|
|
57381
|
+
return this.callSiteExtractStart("analyze_site_similarity", {
|
|
57382
|
+
...body,
|
|
57383
|
+
background: true,
|
|
57384
|
+
formats: ["markdown", "links", "json"],
|
|
57385
|
+
renderJavaScript: true,
|
|
57386
|
+
captureRenderedDom: true,
|
|
57387
|
+
semanticSimilarity: true,
|
|
57388
|
+
similarityThreshold,
|
|
57389
|
+
similarityMaxPairs
|
|
57390
|
+
}, idempotencyKey4);
|
|
57391
|
+
}
|
|
56744
57392
|
auditSite(input) {
|
|
56745
57393
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
56746
57394
|
const requestBody = {
|
|
@@ -57075,7 +57723,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57075
57723
|
report: input.report,
|
|
57076
57724
|
format: input.format
|
|
57077
57725
|
}, this.timeoutMs, "POST", {
|
|
57078
|
-
"Idempotency-Key": `analytics-export-${(0,
|
|
57726
|
+
"Idempotency-Key": `analytics-export-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57079
57727
|
});
|
|
57080
57728
|
}
|
|
57081
57729
|
commonsSearchEntities(input) {
|
|
@@ -57114,7 +57762,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57114
57762
|
commonsSubmitEntity(input) {
|
|
57115
57763
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57116
57764
|
return this.call("/commons/entities/propose", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57117
|
-
"Idempotency-Key": `commons-${(0,
|
|
57765
|
+
"Idempotency-Key": `commons-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57118
57766
|
});
|
|
57119
57767
|
}
|
|
57120
57768
|
commonsGetEntityLedger(input) {
|
|
@@ -57129,7 +57777,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57129
57777
|
commonsUpdateEditorialArticle(input) {
|
|
57130
57778
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57131
57779
|
return this.call("/commons/publications/articles", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57132
|
-
"Idempotency-Key": `commons-article-${(0,
|
|
57780
|
+
"Idempotency-Key": `commons-article-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57133
57781
|
});
|
|
57134
57782
|
}
|
|
57135
57783
|
commonsSaveFilter(input) {
|
|
@@ -57150,13 +57798,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57150
57798
|
commonsClaimPublication(input) {
|
|
57151
57799
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57152
57800
|
return this.call("/commons/publications/claim", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57153
|
-
"Idempotency-Key": `commons-publication-claim-${(0,
|
|
57801
|
+
"Idempotency-Key": `commons-publication-claim-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57154
57802
|
});
|
|
57155
57803
|
}
|
|
57156
57804
|
commonsPublishEditorial(input) {
|
|
57157
57805
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57158
57806
|
return this.call("/commons/publications/publish", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57159
|
-
"Idempotency-Key": `commons-publication-publish-${(0,
|
|
57807
|
+
"Idempotency-Key": `commons-publication-publish-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57160
57808
|
});
|
|
57161
57809
|
}
|
|
57162
57810
|
commonsGetPublication(input) {
|
|
@@ -57164,13 +57812,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57164
57812
|
return this.getJson(input.subdomain ? `/commons/publications/${encodeURIComponent(input.subdomain)}?${query}` : `/commons/publications/me?${query}`);
|
|
57165
57813
|
}
|
|
57166
57814
|
async captureSerpSnapshot(input) {
|
|
57167
|
-
const fingerprint2 = (0,
|
|
57815
|
+
const fingerprint2 = (0, import_node_crypto37.createHash)("sha256").update(JSON.stringify(input)).digest("hex");
|
|
57168
57816
|
const now = Date.now();
|
|
57169
57817
|
for (const [pendingFingerprint, pendingEntry] of this.pendingSerpCaptureBillingKeys) {
|
|
57170
57818
|
if (pendingEntry.expiresAt <= now) this.pendingSerpCaptureBillingKeys.delete(pendingFingerprint);
|
|
57171
57819
|
}
|
|
57172
57820
|
const pending = this.pendingSerpCaptureBillingKeys.get(fingerprint2);
|
|
57173
|
-
const idempotencyKey4 = pending && pending.expiresAt > now ? pending.key : (0,
|
|
57821
|
+
const idempotencyKey4 = pending && pending.expiresAt > now ? pending.key : (0, import_node_crypto37.randomUUID)();
|
|
57174
57822
|
this.pendingSerpCaptureBillingKeys.set(fingerprint2, {
|
|
57175
57823
|
key: idempotencyKey4,
|
|
57176
57824
|
expiresAt: now + 15 * 6e4
|
|
@@ -61647,7 +62295,7 @@ async function createImageSourceArtifact(args) {
|
|
|
61647
62295
|
if (args.content.length === 0 || args.content.length > IMAGE_SOURCE_MAX_BYTES) {
|
|
61648
62296
|
throw new Error("image_source_size_invalid");
|
|
61649
62297
|
}
|
|
61650
|
-
const id = (0,
|
|
62298
|
+
const id = (0, import_node_crypto38.randomUUID)().replaceAll("-", "");
|
|
61651
62299
|
return createPrivateArtifact({
|
|
61652
62300
|
policy: policy4(),
|
|
61653
62301
|
ownerId: args.ownerId,
|
|
@@ -61666,11 +62314,11 @@ async function readOwnedImageSourceArtifact(args) {
|
|
|
61666
62314
|
maxBytes: IMAGE_SOURCE_MAX_BYTES
|
|
61667
62315
|
});
|
|
61668
62316
|
}
|
|
61669
|
-
var
|
|
62317
|
+
var import_node_crypto38, IMAGE_SOURCE_ARTIFACT_PREFIX, IMAGE_SOURCE_ARTIFACT_TTL_MS, IMAGE_SOURCE_DOWNLOAD_TTL_MS, IMAGE_SOURCE_MAX_BYTES, ALLOWED_IMAGE_TYPES;
|
|
61670
62318
|
var init_image_source_artifacts = __esm({
|
|
61671
62319
|
"src/api/image-source-artifacts.ts"() {
|
|
61672
62320
|
"use strict";
|
|
61673
|
-
|
|
62321
|
+
import_node_crypto38 = require("crypto");
|
|
61674
62322
|
init_private_artifacts();
|
|
61675
62323
|
IMAGE_SOURCE_ARTIFACT_PREFIX = "image-sources/";
|
|
61676
62324
|
IMAGE_SOURCE_ARTIFACT_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -63284,7 +63932,7 @@ async function runBrowserAgentMigration() {
|
|
|
63284
63932
|
}
|
|
63285
63933
|
async function createExtensionRow(input) {
|
|
63286
63934
|
const db = getDb();
|
|
63287
|
-
const id = `bext_${(0,
|
|
63935
|
+
const id = `bext_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
63288
63936
|
await db.execute({
|
|
63289
63937
|
sql: `INSERT INTO browser_agent_extensions (id, user_id, name, backend_id, backend_name, source, source_url, size_bytes)
|
|
63290
63938
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
@@ -63319,7 +63967,7 @@ async function deleteExtensionRow(userId, name) {
|
|
|
63319
63967
|
}
|
|
63320
63968
|
async function createAuthConnectionRow(input) {
|
|
63321
63969
|
const db = getDb();
|
|
63322
|
-
const connectionId = `authc_${(0,
|
|
63970
|
+
const connectionId = `authc_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
63323
63971
|
await db.execute({
|
|
63324
63972
|
sql: `INSERT INTO browser_auth_connections (connection_id, domain, profile, account_email, note, status, browser_agent_session_id)
|
|
63325
63973
|
VALUES (?, ?, ?, ?, ?, 'NEEDS_AUTH', ?)`,
|
|
@@ -63404,7 +64052,7 @@ async function deleteProfileLabel(userId, profile) {
|
|
|
63404
64052
|
}
|
|
63405
64053
|
async function createSessionRow(input) {
|
|
63406
64054
|
const db = getDb();
|
|
63407
|
-
const id = `bas_${(0,
|
|
64055
|
+
const id = `bas_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
63408
64056
|
await db.execute({
|
|
63409
64057
|
sql: `INSERT INTO browser_agent_sessions (id, runtime_session_id, live_view_url, cdp_ws_url, status, label, user_id, concurrency_lock_id, last_action_at)
|
|
63410
64058
|
VALUES (?, ?, ?, ?, 'open', ?, ?, ?, datetime('now'))`,
|
|
@@ -63481,7 +64129,7 @@ async function recordAction(input) {
|
|
|
63481
64129
|
sql: `INSERT INTO browser_agent_actions (id, session_id, type, params_json, ok, error)
|
|
63482
64130
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
63483
64131
|
args: [
|
|
63484
|
-
`baa_${(0,
|
|
64132
|
+
`baa_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`,
|
|
63485
64133
|
input.sessionId,
|
|
63486
64134
|
input.type,
|
|
63487
64135
|
input.params == null ? null : JSON.stringify(input.params),
|
|
@@ -63521,11 +64169,11 @@ async function listReplayRows(sessionId) {
|
|
|
63521
64169
|
});
|
|
63522
64170
|
return res.rows;
|
|
63523
64171
|
}
|
|
63524
|
-
var
|
|
64172
|
+
var import_node_crypto39, _ready2, _migrationPromise2, ORPHANED_SESSION_STATUS;
|
|
63525
64173
|
var init_browser_agent_db = __esm({
|
|
63526
64174
|
"src/api/browser-agent-db.ts"() {
|
|
63527
64175
|
"use strict";
|
|
63528
|
-
|
|
64176
|
+
import_node_crypto39 = require("crypto");
|
|
63529
64177
|
init_db();
|
|
63530
64178
|
_ready2 = false;
|
|
63531
64179
|
_migrationPromise2 = null;
|
|
@@ -64672,8 +65320,8 @@ function kernelClient() {
|
|
|
64672
65320
|
return new import_sdk11.default({ apiKey });
|
|
64673
65321
|
}
|
|
64674
65322
|
function backendName(userId, name, resource) {
|
|
64675
|
-
const digest2 = (0,
|
|
64676
|
-
const nonce = (0,
|
|
65323
|
+
const digest2 = (0, import_node_crypto40.createHash)("sha256").update(`${userId}:${name}`).digest("hex").slice(0, 16);
|
|
65324
|
+
const nonce = (0, import_node_crypto40.randomUUID)().replace(/-/g, "").slice(0, 8);
|
|
64677
65325
|
return `mcp-serp-${resource}-${digest2}-${nonce}`;
|
|
64678
65326
|
}
|
|
64679
65327
|
function isNotFound2(error) {
|
|
@@ -64751,11 +65399,11 @@ async function deleteSerpIdentity(userId, name) {
|
|
|
64751
65399
|
throw error;
|
|
64752
65400
|
}
|
|
64753
65401
|
}
|
|
64754
|
-
var
|
|
65402
|
+
var import_node_crypto40, import_sdk11, MAX_SERP_IDENTITIES_PER_USER;
|
|
64755
65403
|
var init_serp_identity_service = __esm({
|
|
64756
65404
|
"src/api/serp-identity-service.ts"() {
|
|
64757
65405
|
"use strict";
|
|
64758
|
-
|
|
65406
|
+
import_node_crypto40 = require("crypto");
|
|
64759
65407
|
import_sdk11 = __toESM(require("@onkernel/sdk"), 1);
|
|
64760
65408
|
init_browser_service_env();
|
|
64761
65409
|
init_serp_identity_db();
|
|
@@ -65466,7 +66114,7 @@ function buildBrowserAgentRoutes() {
|
|
|
65466
66114
|
}
|
|
65467
66115
|
const existing = await getExtensionRow(user.id, name);
|
|
65468
66116
|
if (existing) return c.json({ error: `an extension named "${name}" already exists \u2014 delete it first or pick another name` }, 409);
|
|
65469
|
-
const backendName2 = `u${user.id}_${(0,
|
|
66117
|
+
const backendName2 = `u${user.id}_${(0, import_node_crypto41.randomUUID)().replace(/-/g, "")}`;
|
|
65470
66118
|
try {
|
|
65471
66119
|
const imported = await importExtensionFromStore(storeUrl, backendName2);
|
|
65472
66120
|
const row = await createExtensionRow({
|
|
@@ -65525,11 +66173,11 @@ function buildBrowserAgentRoutes() {
|
|
|
65525
66173
|
});
|
|
65526
66174
|
return app2;
|
|
65527
66175
|
}
|
|
65528
|
-
var
|
|
66176
|
+
var import_node_crypto41, import_hono24, auth, DEFAULT_BROWSER_SESSION_LOCK_TTL_SECONDS, EXTENSION_NAME_RE, SERP_IDENTITY_NAME_RE;
|
|
65529
66177
|
var init_browser_agent_routes = __esm({
|
|
65530
66178
|
"src/api/browser-agent-routes.ts"() {
|
|
65531
66179
|
"use strict";
|
|
65532
|
-
|
|
66180
|
+
import_node_crypto41 = require("crypto");
|
|
65533
66181
|
import_hono24 = require("hono");
|
|
65534
66182
|
init_api_auth();
|
|
65535
66183
|
init_errors();
|
|
@@ -66087,7 +66735,7 @@ async function getKeys() {
|
|
|
66087
66735
|
const privateKey = await (0, import_jose2.importPKCS8)(pem, "RS256", { extractable: true });
|
|
66088
66736
|
const full = await (0, import_jose2.exportJWK)(privateKey);
|
|
66089
66737
|
const publicJwk = { kty: full.kty, n: full.n, e: full.e };
|
|
66090
|
-
const kid = (0,
|
|
66738
|
+
const kid = (0, import_node_crypto42.createHash)("sha256").update(JSON.stringify({ e: publicJwk.e, kty: publicJwk.kty, n: publicJwk.n })).digest("base64url").slice(0, 16);
|
|
66091
66739
|
publicJwk.kid = kid;
|
|
66092
66740
|
publicJwk.alg = "RS256";
|
|
66093
66741
|
publicJwk.use = "sig";
|
|
@@ -66266,23 +66914,23 @@ async function validateAuthRequest(p) {
|
|
|
66266
66914
|
}
|
|
66267
66915
|
function pkceMatches(verifier, challenge) {
|
|
66268
66916
|
if (!verifier) return false;
|
|
66269
|
-
const computed = (0,
|
|
66917
|
+
const computed = (0, import_node_crypto42.createHash)("sha256").update(verifier).digest("base64url");
|
|
66270
66918
|
return computed === challenge;
|
|
66271
66919
|
}
|
|
66272
66920
|
async function mintAccessToken(identity, scope, plan, audience) {
|
|
66273
66921
|
const { privateKey, kid } = await getKeys();
|
|
66274
|
-
return new import_jose2.SignJWT({ scope, plan }).setProtectedHeader({ alg: "RS256", kid }).setIssuer(ISSUER).setSubject(identity).setAudience(audience).setIssuedAt().setJti((0,
|
|
66922
|
+
return new import_jose2.SignJWT({ scope, plan }).setProtectedHeader({ alg: "RS256", kid }).setIssuer(ISSUER).setSubject(identity).setAudience(audience).setIssuedAt().setJti((0, import_node_crypto42.randomUUID)()).setExpirationTime(`${ACCESS_TTL_SECONDS}s`).sign(privateKey);
|
|
66275
66923
|
}
|
|
66276
66924
|
function tokenErrorResponse(c, error, description, status) {
|
|
66277
66925
|
return c.json({ error, error_description: description }, status);
|
|
66278
66926
|
}
|
|
66279
|
-
var import_hono26, import_cookie,
|
|
66927
|
+
var import_hono26, import_cookie, import_node_crypto42, import_jose2, ISSUER, RESOURCE, SCRAPER_RESOURCE, MEMORY_SCOPES, SCRAPER_SCOPES, SUPPORTED_SCOPES, ACCESS_TTL_SECONDS, REFRESH_TTL_SECONDS, CODE_TTL_SECONDS, ROTATION_GRACE_SECONDS, OAUTH_DATABASE_TIMEOUT_MS, OAuthDatabaseUnavailableError, secureCookies, sessionCookieOptions, cachedKeys, oauthApp;
|
|
66280
66928
|
var init_oauth_routes = __esm({
|
|
66281
66929
|
"src/api/oauth-routes.ts"() {
|
|
66282
66930
|
"use strict";
|
|
66283
66931
|
import_hono26 = require("hono");
|
|
66284
66932
|
import_cookie = require("hono/cookie");
|
|
66285
|
-
|
|
66933
|
+
import_node_crypto42 = require("crypto");
|
|
66286
66934
|
import_jose2 = require("jose");
|
|
66287
66935
|
init_session();
|
|
66288
66936
|
init_db();
|
|
@@ -66389,7 +67037,7 @@ var init_oauth_routes = __esm({
|
|
|
66389
67037
|
}
|
|
66390
67038
|
}
|
|
66391
67039
|
const clientName = typeof body.client_name === "string" ? body.client_name : null;
|
|
66392
|
-
const clientId = `client_${(0,
|
|
67040
|
+
const clientId = `client_${(0, import_node_crypto42.randomBytes)(16).toString("hex")}`;
|
|
66393
67041
|
await withOAuthDatabaseDeadline("register-client", registerClient(clientId, redirectUris, clientName));
|
|
66394
67042
|
console.log("[oauth-dcr] register OK client_id=%s redirect_uris=%s", clientId, JSON.stringify(redirectUris));
|
|
66395
67043
|
return c.json({
|
|
@@ -66442,7 +67090,7 @@ var init_oauth_routes = __esm({
|
|
|
66442
67090
|
if (action3 === "deny") return redirectWithError(p.redirect_uri, p.state, "access_denied");
|
|
66443
67091
|
if (action3 !== "approve") return c.text("unsupported action", 400);
|
|
66444
67092
|
const scope = negotiateScope(p.scope, user, p.resource);
|
|
66445
|
-
const code = `code_${(0,
|
|
67093
|
+
const code = `code_${(0, import_node_crypto42.randomBytes)(32).toString("base64url")}`;
|
|
66446
67094
|
const expiresAt = new Date(Date.now() + CODE_TTL_SECONDS * 1e3).toISOString();
|
|
66447
67095
|
await withOAuthDatabaseDeadline("put-authorization-code", putCode({
|
|
66448
67096
|
code,
|
|
@@ -66481,7 +67129,7 @@ var init_oauth_routes = __esm({
|
|
|
66481
67129
|
const plan = user ? resolvePlan(user) : "free";
|
|
66482
67130
|
const audience = record.resource ?? RESOURCE();
|
|
66483
67131
|
const accessToken = await mintAccessToken(record.identity, record.scope, plan, audience);
|
|
66484
|
-
const refreshToken = `rt_${(0,
|
|
67132
|
+
const refreshToken = `rt_${(0, import_node_crypto42.randomBytes)(40).toString("base64url")}`;
|
|
66485
67133
|
await withOAuthDatabaseDeadline("put-refresh-token", putRefresh({
|
|
66486
67134
|
refresh_token: refreshToken,
|
|
66487
67135
|
client_id: clientId,
|
|
@@ -66511,7 +67159,7 @@ var init_oauth_routes = __esm({
|
|
|
66511
67159
|
const plan = user ? resolvePlan(user) : "free";
|
|
66512
67160
|
const audience = record.resource ?? RESOURCE();
|
|
66513
67161
|
const accessToken = await mintAccessToken(record.identity, record.scope, plan, audience);
|
|
66514
|
-
const nextRefresh = `rt_${(0,
|
|
67162
|
+
const nextRefresh = `rt_${(0, import_node_crypto42.randomBytes)(40).toString("base64url")}`;
|
|
66515
67163
|
await withOAuthDatabaseDeadline("rotate-refresh-token", rotateRefresh(refreshToken, {
|
|
66516
67164
|
refresh_token: nextRefresh,
|
|
66517
67165
|
client_id: record.client_id,
|
|
@@ -67931,7 +68579,7 @@ function quoteUntrusted(value) {
|
|
|
67931
68579
|
return clean3.split("\n").map((line) => `> ${line}`).join("\n");
|
|
67932
68580
|
}
|
|
67933
68581
|
function shortHash(value, length = 24) {
|
|
67934
|
-
return (0,
|
|
68582
|
+
return (0, import_node_crypto43.createHash)("sha256").update(value).digest("hex").slice(0, length);
|
|
67935
68583
|
}
|
|
67936
68584
|
function safePathPart(value) {
|
|
67937
68585
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "contact";
|
|
@@ -68419,11 +69067,11 @@ async function captureSupportMessage(memoryKey, email, options) {
|
|
|
68419
69067
|
direction: options.direction
|
|
68420
69068
|
};
|
|
68421
69069
|
}
|
|
68422
|
-
var
|
|
69070
|
+
var import_node_crypto43, SUPPORT_TAGS, ISSUE_TAGS;
|
|
68423
69071
|
var init_resend_support_thread = __esm({
|
|
68424
69072
|
"src/api/resend-support-thread.ts"() {
|
|
68425
69073
|
"use strict";
|
|
68426
|
-
|
|
69074
|
+
import_node_crypto43 = require("crypto");
|
|
68427
69075
|
init_memory();
|
|
68428
69076
|
SUPPORT_TAGS = [
|
|
68429
69077
|
{
|
|
@@ -69008,7 +69656,7 @@ async function claimWorkshopRegistration(input) {
|
|
|
69008
69656
|
) < ?
|
|
69009
69657
|
`,
|
|
69010
69658
|
args: [
|
|
69011
|
-
(0,
|
|
69659
|
+
(0, import_node_crypto44.randomUUID)(),
|
|
69012
69660
|
input.eventSlug,
|
|
69013
69661
|
input.email,
|
|
69014
69662
|
input.firstName,
|
|
@@ -69025,7 +69673,7 @@ async function claimWorkshopRegistration(input) {
|
|
|
69025
69673
|
id, event_slug, email, first_name, last_name, status
|
|
69026
69674
|
) VALUES (?, ?, ?, ?, ?, 'waitlisted')
|
|
69027
69675
|
`,
|
|
69028
|
-
args: [(0,
|
|
69676
|
+
args: [(0, import_node_crypto44.randomUUID)(), input.eventSlug, input.email, input.firstName, input.lastName || null]
|
|
69029
69677
|
});
|
|
69030
69678
|
const waitlisted = await getWorkshopRegistration(input.eventSlug, input.email);
|
|
69031
69679
|
if (!waitlisted) throw new Error("workshop registration could not be claimed");
|
|
@@ -69040,7 +69688,7 @@ async function registerWorkshopInterest(input) {
|
|
|
69040
69688
|
id, event_slug, email, first_name, last_name, status
|
|
69041
69689
|
) VALUES (?, ?, ?, ?, ?, 'interested')
|
|
69042
69690
|
`,
|
|
69043
|
-
args: [(0,
|
|
69691
|
+
args: [(0, import_node_crypto44.randomUUID)(), input.eventSlug, input.email, input.firstName, input.lastName || null]
|
|
69044
69692
|
});
|
|
69045
69693
|
const registration = await getWorkshopRegistration(input.eventSlug, input.email);
|
|
69046
69694
|
if (!registration) throw new Error("workshop interest could not be recorded");
|
|
@@ -69070,11 +69718,11 @@ async function updateWorkshopRegistration(id, patch) {
|
|
|
69070
69718
|
args: [...entries.map(([, value]) => value), id]
|
|
69071
69719
|
});
|
|
69072
69720
|
}
|
|
69073
|
-
var
|
|
69721
|
+
var import_node_crypto44;
|
|
69074
69722
|
var init_workshop_registration_repository = __esm({
|
|
69075
69723
|
"src/api/workshop-registration-repository.ts"() {
|
|
69076
69724
|
"use strict";
|
|
69077
|
-
|
|
69725
|
+
import_node_crypto44 = require("crypto");
|
|
69078
69726
|
init_db();
|
|
69079
69727
|
}
|
|
69080
69728
|
});
|
|
@@ -69647,7 +70295,7 @@ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
|
|
|
69647
70295
|
articleCount: articles.length,
|
|
69648
70296
|
wordCount: totalWordCount,
|
|
69649
70297
|
bytes,
|
|
69650
|
-
sha256: (0,
|
|
70298
|
+
sha256: (0, import_node_crypto45.createHash)("sha256").update(html).digest("hex"),
|
|
69651
70299
|
warnings
|
|
69652
70300
|
};
|
|
69653
70301
|
}
|
|
@@ -69730,14 +70378,14 @@ ${provenance}`;
|
|
|
69730
70378
|
...rendered,
|
|
69731
70379
|
html,
|
|
69732
70380
|
bytes: Buffer.byteLength(html),
|
|
69733
|
-
sha256: (0,
|
|
70381
|
+
sha256: (0, import_node_crypto45.createHash)("sha256").update(html).digest("hex")
|
|
69734
70382
|
};
|
|
69735
70383
|
}
|
|
69736
|
-
var
|
|
70384
|
+
var import_node_crypto45, import_node_fs14, import_node_path21, import_marked, runtimeEntryDir, assetCache;
|
|
69737
70385
|
var init_render = __esm({
|
|
69738
70386
|
"src/editorial-reading-room/render.ts"() {
|
|
69739
70387
|
"use strict";
|
|
69740
|
-
|
|
70388
|
+
import_node_crypto45 = require("crypto");
|
|
69741
70389
|
import_node_fs14 = require("fs");
|
|
69742
70390
|
import_node_path21 = require("path");
|
|
69743
70391
|
import_marked = require("marked");
|
|
@@ -70001,7 +70649,7 @@ async function hostCommonsImage(input) {
|
|
|
70001
70649
|
415
|
|
70002
70650
|
);
|
|
70003
70651
|
}
|
|
70004
|
-
const digest2 = (0,
|
|
70652
|
+
const digest2 = (0, import_node_crypto46.createHash)("sha256").update(bytes).digest("hex");
|
|
70005
70653
|
const existing = await getDb().execute({
|
|
70006
70654
|
sql: "SELECT id, url, content_type, bytes, source_url FROM commons_images WHERE digest = ? LIMIT 1",
|
|
70007
70655
|
args: [digest2]
|
|
@@ -70089,11 +70737,11 @@ async function hostEntityImages(input) {
|
|
|
70089
70737
|
}
|
|
70090
70738
|
return rewrite;
|
|
70091
70739
|
}
|
|
70092
|
-
var
|
|
70740
|
+
var import_node_crypto46, import_promises16, import_node_net2, COMMONS_IMAGE_MAX_BYTES, COMMONS_IMAGE_MAX_REDIRECTS, COMMONS_IMAGE_FETCH_TIMEOUT_MS, CommonsImageError, imageSchemaReady, hostOverride;
|
|
70093
70741
|
var init_commons_image_store = __esm({
|
|
70094
70742
|
"src/api/commons-image-store.ts"() {
|
|
70095
70743
|
"use strict";
|
|
70096
|
-
|
|
70744
|
+
import_node_crypto46 = require("crypto");
|
|
70097
70745
|
import_promises16 = require("dns/promises");
|
|
70098
70746
|
import_node_net2 = require("net");
|
|
70099
70747
|
init_blob_store();
|
|
@@ -70116,141 +70764,6 @@ var init_commons_image_store = __esm({
|
|
|
70116
70764
|
}
|
|
70117
70765
|
});
|
|
70118
70766
|
|
|
70119
|
-
// src/api/commons-embeddings.ts
|
|
70120
|
-
function commonsEmbedModel() {
|
|
70121
|
-
return (process.env.JINA_EMBED_MODEL ?? "jina-embeddings-v5-omni-small").trim();
|
|
70122
|
-
}
|
|
70123
|
-
function commonsEmbedDim() {
|
|
70124
|
-
return Number((process.env.JINA_EMBED_DIM ?? "1024").trim());
|
|
70125
|
-
}
|
|
70126
|
-
function commonsSemanticSearchConfigured() {
|
|
70127
|
-
return Boolean(process.env.JINA_API_KEY?.trim() && process.env.MEMORY_DATABASE_URL?.trim());
|
|
70128
|
-
}
|
|
70129
|
-
function vectorSql() {
|
|
70130
|
-
if (_vectorSql) return _vectorSql;
|
|
70131
|
-
const url = process.env.MEMORY_DATABASE_URL?.trim();
|
|
70132
|
-
if (!url) throw new Error("MEMORY_DATABASE_URL is not set; Commons semantic search needs the shared Postgres.");
|
|
70133
|
-
_vectorSql = (0, import_serverless.neon)(url);
|
|
70134
|
-
return _vectorSql;
|
|
70135
|
-
}
|
|
70136
|
-
async function ensureCommonsVectorSchema() {
|
|
70137
|
-
if (vectorSchemaReady) return;
|
|
70138
|
-
const dimension = commonsEmbedDim();
|
|
70139
|
-
await vectorSql().query("CREATE EXTENSION IF NOT EXISTS vector");
|
|
70140
|
-
await vectorSql().query(`
|
|
70141
|
-
CREATE TABLE IF NOT EXISTS commons_index_vectors (
|
|
70142
|
-
document_id TEXT PRIMARY KEY,
|
|
70143
|
-
entity_id TEXT NOT NULL,
|
|
70144
|
-
document_type TEXT NOT NULL,
|
|
70145
|
-
title TEXT NOT NULL,
|
|
70146
|
-
embedding vector(${dimension}) NOT NULL,
|
|
70147
|
-
model TEXT NOT NULL,
|
|
70148
|
-
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
70149
|
-
)
|
|
70150
|
-
`);
|
|
70151
|
-
await vectorSql().query("CREATE INDEX IF NOT EXISTS commons_index_vectors_entity ON commons_index_vectors(entity_id)");
|
|
70152
|
-
vectorSchemaReady = true;
|
|
70153
|
-
}
|
|
70154
|
-
async function embedCommonsTexts(texts) {
|
|
70155
|
-
const apiKey = process.env.JINA_API_KEY?.trim();
|
|
70156
|
-
if (!apiKey) throw new Error("JINA_API_KEY is not set; Commons semantic search cannot embed.");
|
|
70157
|
-
if (!texts.length) return [];
|
|
70158
|
-
const response = await fetch("https://api.jina.ai/v1/embeddings", {
|
|
70159
|
-
method: "POST",
|
|
70160
|
-
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
70161
|
-
body: JSON.stringify({
|
|
70162
|
-
model: commonsEmbedModel(),
|
|
70163
|
-
dimensions: commonsEmbedDim(),
|
|
70164
|
-
input: texts.map((text2) => ({ text: text2.slice(0, 8e3) }))
|
|
70165
|
-
}),
|
|
70166
|
-
signal: AbortSignal.timeout(6e4)
|
|
70167
|
-
});
|
|
70168
|
-
if (!response.ok) {
|
|
70169
|
-
throw new Error(`Jina embedding request failed with HTTP ${response.status}: ${(await response.text()).slice(0, 200)}`);
|
|
70170
|
-
}
|
|
70171
|
-
const payload = await response.json();
|
|
70172
|
-
const vectors = (payload.data ?? []).map((item) => item.embedding);
|
|
70173
|
-
if (vectors.length !== texts.length) {
|
|
70174
|
-
throw new Error(`Jina returned ${vectors.length} embeddings for ${texts.length} inputs.`);
|
|
70175
|
-
}
|
|
70176
|
-
return vectors;
|
|
70177
|
-
}
|
|
70178
|
-
async function embedQueuedCommonsDocuments(limit = 50) {
|
|
70179
|
-
if (!commonsSemanticSearchConfigured()) return { claimed: 0, embedded: 0, failed: 0, remaining: 0 };
|
|
70180
|
-
await ensureCommonsVectorSchema();
|
|
70181
|
-
const bounded2 = Math.max(1, Math.min(200, Math.floor(limit)));
|
|
70182
|
-
const queued = await getDb().execute({
|
|
70183
|
-
sql: `SELECT id, entity_id, document_type, title, text FROM commons_index_documents
|
|
70184
|
-
WHERE embedding_status IN ('queued', 'failed') ORDER BY updated_at ASC LIMIT ?`,
|
|
70185
|
-
args: [bounded2]
|
|
70186
|
-
});
|
|
70187
|
-
const rows = queued.rows;
|
|
70188
|
-
if (!rows.length) return { claimed: 0, embedded: 0, failed: 0, remaining: await queuedCommonsDocumentCount() };
|
|
70189
|
-
let embedded = 0;
|
|
70190
|
-
let failed = 0;
|
|
70191
|
-
const model = commonsEmbedModel();
|
|
70192
|
-
try {
|
|
70193
|
-
const vectors = await embedCommonsTexts(rows.map((row) => `${row.title}
|
|
70194
|
-
|
|
70195
|
-
${row.text}`));
|
|
70196
|
-
for (const [index, row] of rows.entries()) {
|
|
70197
|
-
const literal = `[${vectors[index].join(",")}]`;
|
|
70198
|
-
await vectorSql().query(
|
|
70199
|
-
`INSERT INTO commons_index_vectors (document_id, entity_id, document_type, title, embedding, model, updated_at)
|
|
70200
|
-
VALUES ($1, $2, $3, $4, $5::vector, $6, now())
|
|
70201
|
-
ON CONFLICT (document_id) DO UPDATE SET entity_id = EXCLUDED.entity_id, document_type = EXCLUDED.document_type,
|
|
70202
|
-
title = EXCLUDED.title, embedding = EXCLUDED.embedding, model = EXCLUDED.model, updated_at = now()`,
|
|
70203
|
-
[row.id, row.entity_id, row.document_type, row.title, literal, model]
|
|
70204
|
-
);
|
|
70205
|
-
await getDb().execute({
|
|
70206
|
-
sql: `UPDATE commons_index_documents SET embedding_status = 'indexed', embedding_provider = ?, embedding_model = ?,
|
|
70207
|
-
vector_ref = ?, indexed_at = ?, error = NULL WHERE id = ?`,
|
|
70208
|
-
args: [COMMONS_EMBED_PROVIDER, model, row.id, (/* @__PURE__ */ new Date()).toISOString(), row.id]
|
|
70209
|
-
});
|
|
70210
|
-
embedded += 1;
|
|
70211
|
-
}
|
|
70212
|
-
} catch (error) {
|
|
70213
|
-
failed = rows.length - embedded;
|
|
70214
|
-
const message = (error instanceof Error ? error.message : String(error)).slice(0, 500);
|
|
70215
|
-
for (const row of rows.slice(embedded)) {
|
|
70216
|
-
await getDb().execute({
|
|
70217
|
-
sql: `UPDATE commons_index_documents SET embedding_status = 'failed', error = ? WHERE id = ?`,
|
|
70218
|
-
args: [message, row.id]
|
|
70219
|
-
}).catch(() => void 0);
|
|
70220
|
-
}
|
|
70221
|
-
}
|
|
70222
|
-
return { claimed: rows.length, embedded, failed, remaining: await queuedCommonsDocumentCount() };
|
|
70223
|
-
}
|
|
70224
|
-
async function queuedCommonsDocumentCount() {
|
|
70225
|
-
const result = await getDb().execute(`SELECT COUNT(*) AS n FROM commons_index_documents WHERE embedding_status IN ('queued', 'failed')`);
|
|
70226
|
-
return Number(result.rows[0]?.n ?? 0);
|
|
70227
|
-
}
|
|
70228
|
-
async function semanticCommonsEntityScores(query, limit = 40) {
|
|
70229
|
-
const scores = /* @__PURE__ */ new Map();
|
|
70230
|
-
if (!commonsSemanticSearchConfigured() || !query.trim()) return scores;
|
|
70231
|
-
await ensureCommonsVectorSchema();
|
|
70232
|
-
const [vector] = await embedCommonsTexts([query]);
|
|
70233
|
-
if (!vector) return scores;
|
|
70234
|
-
const rows = await vectorSql().query(
|
|
70235
|
-
`SELECT entity_id, MAX(1 - (embedding <=> $1::vector)) AS score
|
|
70236
|
-
FROM commons_index_vectors GROUP BY entity_id ORDER BY score DESC LIMIT $2`,
|
|
70237
|
-
[`[${vector.join(",")}]`, Math.max(1, Math.min(100, limit))]
|
|
70238
|
-
);
|
|
70239
|
-
for (const row of rows) scores.set(String(row.entity_id), Number(row.score));
|
|
70240
|
-
return scores;
|
|
70241
|
-
}
|
|
70242
|
-
var import_serverless, COMMONS_EMBED_PROVIDER, _vectorSql, vectorSchemaReady;
|
|
70243
|
-
var init_commons_embeddings = __esm({
|
|
70244
|
-
"src/api/commons-embeddings.ts"() {
|
|
70245
|
-
"use strict";
|
|
70246
|
-
import_serverless = require("@neondatabase/serverless");
|
|
70247
|
-
init_db();
|
|
70248
|
-
COMMONS_EMBED_PROVIDER = "jina";
|
|
70249
|
-
_vectorSql = null;
|
|
70250
|
-
vectorSchemaReady = false;
|
|
70251
|
-
}
|
|
70252
|
-
});
|
|
70253
|
-
|
|
70254
70767
|
// src/api/schema-presence.ts
|
|
70255
70768
|
async function loadSchemaObjects() {
|
|
70256
70769
|
const res = await getDb().execute(
|
|
@@ -70353,7 +70866,7 @@ function buildCommonsLinkset(entity, claims) {
|
|
|
70353
70866
|
context[claim.predicate] = targets;
|
|
70354
70867
|
}
|
|
70355
70868
|
const document2 = { linkset: [context] };
|
|
70356
|
-
const etag = `"${(0,
|
|
70869
|
+
const etag = `"${(0, import_node_crypto47.createHash)("sha256").update(JSON.stringify(document2)).digest("hex")}"`;
|
|
70357
70870
|
return { document: document2, etag, publicUrl, linksetUrl, profile: COMMONS_RELATIONSHIP_PROFILE };
|
|
70358
70871
|
}
|
|
70359
70872
|
function commonsLinksetDiscoveryHeader(idOrSlug) {
|
|
@@ -70421,11 +70934,11 @@ function normalizeHreflang(value) {
|
|
|
70421
70934
|
const languages = [...new Set(value.map((item) => optionalText(item, 80)).filter((item) => Boolean(item)))];
|
|
70422
70935
|
return languages.length ? languages : void 0;
|
|
70423
70936
|
}
|
|
70424
|
-
var
|
|
70937
|
+
var import_node_crypto47, COMMONS_LINKSET_MEDIA_TYPE, COMMONS_RELATIONSHIP_PROFILE, REGISTERED_RELATIONS;
|
|
70425
70938
|
var init_commons_linksets = __esm({
|
|
70426
70939
|
"src/api/commons-linksets.ts"() {
|
|
70427
70940
|
"use strict";
|
|
70428
|
-
|
|
70941
|
+
import_node_crypto47 = require("crypto");
|
|
70429
70942
|
COMMONS_LINKSET_MEDIA_TYPE = "application/linkset+json";
|
|
70430
70943
|
COMMONS_RELATIONSHIP_PROFILE = "https://mcpscraper.dev/commons/profiles/relationships/v1";
|
|
70431
70944
|
REGISTERED_RELATIONS = /* @__PURE__ */ new Set([
|
|
@@ -71065,7 +71578,7 @@ async function submitCommonsEntity(input, user) {
|
|
|
71065
71578
|
const existingClaims = existing && normalized.claims !== void 0 ? await getCommonsClaimsByEntityId(existing.id) : [];
|
|
71066
71579
|
const safety = evaluatePublishSafety(normalized, existing);
|
|
71067
71580
|
const shouldApply = safety.safe && normalized.reviewPolicy !== "always_review";
|
|
71068
|
-
const proposalId = `commons-proposal-${(0,
|
|
71581
|
+
const proposalId = `commons-proposal-${(0, import_node_crypto48.randomUUID)()}`;
|
|
71069
71582
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
71070
71583
|
const entityId = existing?.id ?? normalized.entityId ?? allocateEntityId();
|
|
71071
71584
|
const proposalStatus = shouldApply ? "accepted" : "pending_review";
|
|
@@ -71120,7 +71633,7 @@ async function submitCommonsEntity(input, user) {
|
|
|
71120
71633
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
71121
71634
|
`,
|
|
71122
71635
|
args: [
|
|
71123
|
-
`commons-ledger-${(0,
|
|
71636
|
+
`commons-ledger-${(0, import_node_crypto48.randomUUID)()}`,
|
|
71124
71637
|
nextEntity.id,
|
|
71125
71638
|
proposalId,
|
|
71126
71639
|
user.id,
|
|
@@ -71226,7 +71739,7 @@ async function saveCommonsFilter(input, user) {
|
|
|
71226
71739
|
sql: "SELECT id FROM commons_saved_filters WHERE user_id = ? AND name = ? LIMIT 1",
|
|
71227
71740
|
args: [user.id, name]
|
|
71228
71741
|
});
|
|
71229
|
-
const id = existing.rows[0]?.id != null ? String(existing.rows[0].id) : `commons-filter-${(0,
|
|
71742
|
+
const id = existing.rows[0]?.id != null ? String(existing.rows[0].id) : `commons-filter-${(0, import_node_crypto48.randomUUID)()}`;
|
|
71230
71743
|
await getDb().execute({
|
|
71231
71744
|
sql: `
|
|
71232
71745
|
INSERT INTO commons_saved_filters (id, user_id, name, description, filter_json, created_at, updated_at)
|
|
@@ -72004,7 +72517,7 @@ function commonsIndexDocuments(entity, now) {
|
|
|
72004
72517
|
return documents;
|
|
72005
72518
|
}
|
|
72006
72519
|
function commonsIndexDocumentId(entityId, documentType, documentKey) {
|
|
72007
|
-
return `commons-index-${(0,
|
|
72520
|
+
return `commons-index-${(0, import_node_crypto48.createHash)("sha256").update(`${entityId}
|
|
72008
72521
|
${documentType}
|
|
72009
72522
|
${documentKey}`).digest("hex").slice(0, 32)}`;
|
|
72010
72523
|
}
|
|
@@ -72570,11 +73083,11 @@ function jsonLikeValue(value) {
|
|
|
72570
73083
|
function escapeLike(value) {
|
|
72571
73084
|
return value.replace(/[%_]/g, "");
|
|
72572
73085
|
}
|
|
72573
|
-
var
|
|
73086
|
+
var import_node_crypto48, COMMONS_SCHEMA_VERSION, DEFAULT_COMMONS_BASE_URL, DEFAULT_ENTITY_TYPE, COMMONS_ENTITY_PROFILES, schemaReady, COMMONS_SCHEMA_OBJECTS, SEARCH_CANDIDATE_LIMIT, CommonsRepositoryError;
|
|
72574
73087
|
var init_commons_repository = __esm({
|
|
72575
73088
|
"src/api/commons-repository.ts"() {
|
|
72576
73089
|
"use strict";
|
|
72577
|
-
|
|
73090
|
+
import_node_crypto48 = require("crypto");
|
|
72578
73091
|
init_db();
|
|
72579
73092
|
init_commons_image_store();
|
|
72580
73093
|
init_commons_embeddings();
|
|
@@ -72953,7 +73466,7 @@ async function claimCommonsPublication(input, user) {
|
|
|
72953
73466
|
}
|
|
72954
73467
|
const existingName = await getCommonsPublicationBySubdomain(subdomain);
|
|
72955
73468
|
if (existingName) throw new CommonsPublicationError("publication_name_unavailable", "That publication name is already claimed.", 409);
|
|
72956
|
-
const id = `tcpub_${(0,
|
|
73469
|
+
const id = `tcpub_${(0, import_node_crypto49.randomUUID)()}`;
|
|
72957
73470
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
72958
73471
|
try {
|
|
72959
73472
|
await getDb().execute({
|
|
@@ -73005,7 +73518,7 @@ async function publishCommonsEditorial(input, user) {
|
|
|
73005
73518
|
const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
|
|
73006
73519
|
const rendered = renderEditorialReadingRoom(editionInput);
|
|
73007
73520
|
const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
|
|
73008
|
-
const editionId = `tced_${(0,
|
|
73521
|
+
const editionId = `tced_${(0, import_node_crypto49.randomUUID)()}`;
|
|
73009
73522
|
const revision = (latest?.revision ?? 0) + 1;
|
|
73010
73523
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
73011
73524
|
await getDb().batch([
|
|
@@ -73029,7 +73542,7 @@ async function publishCommonsEditorial(input, user) {
|
|
|
73029
73542
|
JSON.stringify(editionInput.articles),
|
|
73030
73543
|
html,
|
|
73031
73544
|
rendered.filename,
|
|
73032
|
-
(0,
|
|
73545
|
+
(0, import_node_crypto49.createHash)("sha256").update(html).digest("hex"),
|
|
73033
73546
|
rendered.articleCount,
|
|
73034
73547
|
rendered.wordCount,
|
|
73035
73548
|
Buffer.byteLength(html),
|
|
@@ -73087,7 +73600,7 @@ async function updateCommonsEditorialArticle(input, user) {
|
|
|
73087
73600
|
const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
|
|
73088
73601
|
const rendered = renderEditorialReadingRoom(editionInput);
|
|
73089
73602
|
const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
|
|
73090
|
-
const editionId = `tced_${(0,
|
|
73603
|
+
const editionId = `tced_${(0, import_node_crypto49.randomUUID)()}`;
|
|
73091
73604
|
const revision = latest.revision + 1;
|
|
73092
73605
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
73093
73606
|
await getDb().batch([
|
|
@@ -73111,7 +73624,7 @@ async function updateCommonsEditorialArticle(input, user) {
|
|
|
73111
73624
|
JSON.stringify(nextArticles),
|
|
73112
73625
|
html,
|
|
73113
73626
|
rendered.filename,
|
|
73114
|
-
(0,
|
|
73627
|
+
(0, import_node_crypto49.createHash)("sha256").update(html).digest("hex"),
|
|
73115
73628
|
rendered.articleCount,
|
|
73116
73629
|
rendered.wordCount,
|
|
73117
73630
|
Buffer.byteLength(html),
|
|
@@ -73316,11 +73829,11 @@ function addPublicMetadata(html, canonicalUrl, publicationTitle) {
|
|
|
73316
73829
|
"</head>"
|
|
73317
73830
|
].join("\n"));
|
|
73318
73831
|
}
|
|
73319
|
-
var
|
|
73832
|
+
var import_node_crypto49, PUBLICATION_ROOT_DOMAIN, RESERVED_SUBDOMAINS, CommonsPublicationError;
|
|
73320
73833
|
var init_commons_publication_repository = __esm({
|
|
73321
73834
|
"src/api/commons-publication-repository.ts"() {
|
|
73322
73835
|
"use strict";
|
|
73323
|
-
|
|
73836
|
+
import_node_crypto49 = require("crypto");
|
|
73324
73837
|
init_db();
|
|
73325
73838
|
init_commons_repository();
|
|
73326
73839
|
init_render();
|
|
@@ -74553,7 +75066,7 @@ async function migrateAnalytics() {
|
|
|
74553
75066
|
}
|
|
74554
75067
|
function normalizeSlug2(value) {
|
|
74555
75068
|
const slug4 = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
74556
|
-
return slug4 || `site-${(0,
|
|
75069
|
+
return slug4 || `site-${(0, import_node_crypto50.randomBytes)(4).toString("hex")}`;
|
|
74557
75070
|
}
|
|
74558
75071
|
function normalizeObservedHostname(origin) {
|
|
74559
75072
|
if (!origin || origin === "null") return null;
|
|
@@ -74566,7 +75079,7 @@ function normalizeObservedHostname(origin) {
|
|
|
74566
75079
|
}
|
|
74567
75080
|
}
|
|
74568
75081
|
function publicPixelId() {
|
|
74569
|
-
return `px_${(0,
|
|
75082
|
+
return `px_${(0, import_node_crypto50.randomBytes)(18).toString("base64url")}`;
|
|
74570
75083
|
}
|
|
74571
75084
|
function mapRows(rows) {
|
|
74572
75085
|
return rows;
|
|
@@ -74598,7 +75111,7 @@ async function requireEditor(client2, siteId, userId) {
|
|
|
74598
75111
|
async function createAnalyticsSite(input) {
|
|
74599
75112
|
const db = getAnalyticsPool();
|
|
74600
75113
|
const client2 = await db.connect();
|
|
74601
|
-
const id = (0,
|
|
75114
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
74602
75115
|
const baseSlug = normalizeSlug2(input.slug || input.name);
|
|
74603
75116
|
try {
|
|
74604
75117
|
await client2.query("BEGIN");
|
|
@@ -74614,7 +75127,7 @@ async function createAnalyticsSite(input) {
|
|
|
74614
75127
|
} catch (error) {
|
|
74615
75128
|
const code = error.code;
|
|
74616
75129
|
if (code !== "23505" || attempt === 2) throw error;
|
|
74617
|
-
slug4 = `${baseSlug}-${(0,
|
|
75130
|
+
slug4 = `${baseSlug}-${(0, import_node_crypto50.randomBytes)(2).toString("hex")}`;
|
|
74618
75131
|
}
|
|
74619
75132
|
}
|
|
74620
75133
|
await client2.query(
|
|
@@ -74829,7 +75342,7 @@ async function createAnalyticsPixel(input) {
|
|
|
74829
75342
|
VALUES ($1, $2, $3, $4, $5)
|
|
74830
75343
|
RETURNING id, site_id, public_id, name, environment, status, created_at::text, NULL::text AS last_event_at`,
|
|
74831
75344
|
[
|
|
74832
|
-
(0,
|
|
75345
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
74833
75346
|
input.siteId,
|
|
74834
75347
|
publicPixelId(),
|
|
74835
75348
|
input.name.trim(),
|
|
@@ -74906,7 +75419,7 @@ async function setAnalyticsPixelDomainState(input) {
|
|
|
74906
75419
|
SELECT $1, p.id, $4, $5 FROM analytics_pixels p WHERE p.id = $2 AND p.site_id = $3
|
|
74907
75420
|
ON CONFLICT(pixel_id, hostname) DO UPDATE SET state = EXCLUDED.state, updated_at = now()
|
|
74908
75421
|
RETURNING id`,
|
|
74909
|
-
[(0,
|
|
75422
|
+
[(0, import_node_crypto50.randomUUID)(), input.pixelId, input.siteId, hostname, input.state]
|
|
74910
75423
|
);
|
|
74911
75424
|
if (!result.rowCount)
|
|
74912
75425
|
throw new AnalyticsRepositoryError(
|
|
@@ -74956,7 +75469,7 @@ function sanitizeAnalyticsProperties(value) {
|
|
|
74956
75469
|
}
|
|
74957
75470
|
async function ingestAnalyticsEvents(input) {
|
|
74958
75471
|
const db = getAnalyticsPool();
|
|
74959
|
-
const requestId = `air_${(0,
|
|
75472
|
+
const requestId = `air_${(0, import_node_crypto50.randomUUID)()}`;
|
|
74960
75473
|
const hostname = normalizeObservedHostname(input.origin);
|
|
74961
75474
|
const pixelResult = await db.query(
|
|
74962
75475
|
`SELECT p.id, p.site_id, p.status,
|
|
@@ -74977,7 +75490,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
74977
75490
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
74978
75491
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
74979
75492
|
[
|
|
74980
|
-
(0,
|
|
75493
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
74981
75494
|
requestId,
|
|
74982
75495
|
pixel?.site_id ?? null,
|
|
74983
75496
|
pixel?.id ?? null,
|
|
@@ -75002,7 +75515,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75002
75515
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
75003
75516
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
75004
75517
|
[
|
|
75005
|
-
(0,
|
|
75518
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75006
75519
|
requestId,
|
|
75007
75520
|
pixel.site_id,
|
|
75008
75521
|
pixel.id,
|
|
@@ -75027,7 +75540,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75027
75540
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, rejected_count, reason_codes)
|
|
75028
75541
|
VALUES ($1, $2, $3, $4, $5, $6::jsonb)`,
|
|
75029
75542
|
[
|
|
75030
|
-
(0,
|
|
75543
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75031
75544
|
requestId,
|
|
75032
75545
|
pixel.site_id,
|
|
75033
75546
|
pixel.id,
|
|
@@ -75051,7 +75564,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75051
75564
|
ON CONFLICT(pixel_id, hostname) DO UPDATE
|
|
75052
75565
|
SET last_seen_at = now(), updated_at = now()
|
|
75053
75566
|
RETURNING state`,
|
|
75054
|
-
[(0,
|
|
75567
|
+
[(0, import_node_crypto50.randomUUID)(), pixel.id, hostname]
|
|
75055
75568
|
);
|
|
75056
75569
|
if (domainResult.rows[0]?.state !== "approved") {
|
|
75057
75570
|
await db.query(
|
|
@@ -75065,7 +75578,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75065
75578
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
75066
75579
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
75067
75580
|
[
|
|
75068
|
-
(0,
|
|
75581
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75069
75582
|
requestId,
|
|
75070
75583
|
pixel.site_id,
|
|
75071
75584
|
pixel.id,
|
|
@@ -75115,7 +75628,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75115
75628
|
$23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33
|
|
75116
75629
|
) ON CONFLICT(site_id, event_id) DO NOTHING`,
|
|
75117
75630
|
[
|
|
75118
|
-
(0,
|
|
75631
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75119
75632
|
event2.eventId,
|
|
75120
75633
|
pixel.site_id,
|
|
75121
75634
|
pixel.id,
|
|
@@ -75173,7 +75686,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75173
75686
|
id, request_id, site_id, pixel_id, hostname, accepted_count, rejected_count, reason_codes
|
|
75174
75687
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb)`,
|
|
75175
75688
|
[
|
|
75176
|
-
(0,
|
|
75689
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75177
75690
|
requestId,
|
|
75178
75691
|
pixel.site_id,
|
|
75179
75692
|
pixel.id,
|
|
@@ -75205,7 +75718,7 @@ function normalizeGeographyCode(value, max) {
|
|
|
75205
75718
|
return normalized && /^[A-Z0-9-]+$/.test(normalized) ? normalized.slice(0, max) : null;
|
|
75206
75719
|
}
|
|
75207
75720
|
function pageFingerprint(scope, siteId, filters) {
|
|
75208
|
-
return (0,
|
|
75721
|
+
return (0, import_node_crypto50.createHash)("sha256").update(JSON.stringify({ scope, siteId, filters })).digest("base64url").slice(0, 18);
|
|
75209
75722
|
}
|
|
75210
75723
|
function decodePageOffset(cursor, fingerprint2) {
|
|
75211
75724
|
if (!cursor) return 0;
|
|
@@ -75255,7 +75768,7 @@ async function createAnalyticsConversion(input) {
|
|
|
75255
75768
|
404
|
|
75256
75769
|
);
|
|
75257
75770
|
}
|
|
75258
|
-
const id = (0,
|
|
75771
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
75259
75772
|
const resolvedPerson = input.sessionId ? await db.query(
|
|
75260
75773
|
`SELECT e.person_id FROM analytics_identity_nodes n JOIN analytics_identity_edges e ON e.identity_node_id = n.id
|
|
75261
75774
|
WHERE n.site_id = $1 AND n.kind = 'session_id' AND n.value_hmac = $2 ORDER BY e.confidence DESC LIMIT 1`,
|
|
@@ -76004,7 +76517,7 @@ async function createAnalyticsCampaignLink(input) {
|
|
|
76004
76517
|
404
|
|
76005
76518
|
);
|
|
76006
76519
|
}
|
|
76007
|
-
const shortCode = (input.shortCode?.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "-") || (0,
|
|
76520
|
+
const shortCode = (input.shortCode?.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "-") || (0, import_node_crypto50.randomBytes)(5).toString("base64url").toLowerCase()).slice(0, 48);
|
|
76008
76521
|
try {
|
|
76009
76522
|
const result = await db.query(
|
|
76010
76523
|
`INSERT INTO analytics_campaign_links(
|
|
@@ -76013,7 +76526,7 @@ async function createAnalyticsCampaignLink(input) {
|
|
|
76013
76526
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
|
|
76014
76527
|
RETURNING *, 0::int AS click_count`,
|
|
76015
76528
|
[
|
|
76016
|
-
(0,
|
|
76529
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76017
76530
|
input.siteId,
|
|
76018
76531
|
input.pixelId ?? null,
|
|
76019
76532
|
input.name.trim(),
|
|
@@ -76084,7 +76597,7 @@ async function resolveAnalyticsCampaignLink(shortCode, referrer) {
|
|
|
76084
76597
|
if (!row) return null;
|
|
76085
76598
|
await db.query(
|
|
76086
76599
|
`INSERT INTO analytics_campaign_clicks(id, link_id, referrer) VALUES ($1, $2, $3)`,
|
|
76087
|
-
[(0,
|
|
76600
|
+
[(0, import_node_crypto50.randomUUID)(), row.id, normalizeAnalyticsUrl(referrer || void 0)]
|
|
76088
76601
|
);
|
|
76089
76602
|
return buildTaggedCampaignUrl(row);
|
|
76090
76603
|
}
|
|
@@ -76102,14 +76615,14 @@ async function createAnalyticsForm(input) {
|
|
|
76102
76615
|
404
|
|
76103
76616
|
);
|
|
76104
76617
|
const baseSlug = normalizeSlug2(input.name);
|
|
76105
|
-
const slug4 = `${baseSlug}-${(0,
|
|
76106
|
-
const publicId = `form_${(0,
|
|
76618
|
+
const slug4 = `${baseSlug}-${(0, import_node_crypto50.randomBytes)(3).toString("hex")}`;
|
|
76619
|
+
const publicId = `form_${(0, import_node_crypto50.randomBytes)(18).toString("base64url")}`;
|
|
76107
76620
|
const result = await db.query(
|
|
76108
76621
|
`INSERT INTO analytics_forms(id, public_id, site_id, pixel_id, name, slug, fields, brand, submit_label, success_message, redirect_url, consent_text, status, created_by_user_id)
|
|
76109
76622
|
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb,$9,$10,$11,$12,$13,$14)
|
|
76110
76623
|
RETURNING *, 0::int AS submission_count`,
|
|
76111
76624
|
[
|
|
76112
|
-
(0,
|
|
76625
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76113
76626
|
publicId,
|
|
76114
76627
|
input.siteId,
|
|
76115
76628
|
input.pixelId,
|
|
@@ -76154,7 +76667,7 @@ async function getPublicAnalyticsForm(publicId) {
|
|
|
76154
76667
|
return result.rows[0] ?? null;
|
|
76155
76668
|
}
|
|
76156
76669
|
async function recordAnalyticsFormSubmission(input) {
|
|
76157
|
-
const id = (0,
|
|
76670
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76158
76671
|
await getAnalyticsPool().query(
|
|
76159
76672
|
`INSERT INTO analytics_form_submissions(id, form_id, site_id, pixel_id, visitor_id, session_id, crm_person_ref, source, medium, campaign, crm_delivery_status, click_ids)
|
|
76160
76673
|
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12::jsonb)`,
|
|
@@ -76185,7 +76698,7 @@ function sanitizeClickIds(value) {
|
|
|
76185
76698
|
return output;
|
|
76186
76699
|
}
|
|
76187
76700
|
function identityHmac(kind, value) {
|
|
76188
|
-
return (0,
|
|
76701
|
+
return (0, import_node_crypto50.createHmac)("sha256", getSessionSecret()).update(`${kind}:${value.trim().toLowerCase()}`).digest("hex");
|
|
76189
76702
|
}
|
|
76190
76703
|
async function linkAnalyticsFormIdentity(input) {
|
|
76191
76704
|
const client2 = await getAnalyticsPool().connect();
|
|
@@ -76194,7 +76707,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
76194
76707
|
const person = await client2.query(
|
|
76195
76708
|
`INSERT INTO analytics_people(id, site_id, crm_person_ref) VALUES ($1,$2,$3)
|
|
76196
76709
|
ON CONFLICT(site_id, crm_person_ref) DO UPDATE SET last_seen_at = now() RETURNING id`,
|
|
76197
|
-
[(0,
|
|
76710
|
+
[(0, import_node_crypto50.randomUUID)(), input.siteId, input.crmPersonRef]
|
|
76198
76711
|
);
|
|
76199
76712
|
const personId = person.rows[0].id;
|
|
76200
76713
|
const signals = [];
|
|
@@ -76241,7 +76754,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
76241
76754
|
`INSERT INTO analytics_identity_nodes(id, site_id, kind, value_hmac) VALUES ($1,$2,$3,$4)
|
|
76242
76755
|
ON CONFLICT(site_id, kind, value_hmac) DO UPDATE SET last_seen_at = now() RETURNING id`,
|
|
76243
76756
|
[
|
|
76244
|
-
(0,
|
|
76757
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76245
76758
|
input.siteId,
|
|
76246
76759
|
signal.kind,
|
|
76247
76760
|
identityHmac(signal.kind, signal.value)
|
|
@@ -76252,7 +76765,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
76252
76765
|
VALUES ($1,$2,$3,$4,$5,$6)
|
|
76253
76766
|
ON CONFLICT(person_id, identity_node_id, evidence_kind) DO UPDATE SET last_seen_at = now(), confidence = greatest(analytics_identity_edges.confidence, EXCLUDED.confidence)`,
|
|
76254
76767
|
[
|
|
76255
|
-
(0,
|
|
76768
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76256
76769
|
input.siteId,
|
|
76257
76770
|
personId,
|
|
76258
76771
|
node.rows[0].id,
|
|
@@ -76350,7 +76863,7 @@ async function createAnalyticsCrmImport(input) {
|
|
|
76350
76863
|
const db = getAnalyticsPool();
|
|
76351
76864
|
await requireEditor(db, input.siteId, input.userId);
|
|
76352
76865
|
const client2 = await db.connect();
|
|
76353
|
-
const id = (0,
|
|
76866
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76354
76867
|
try {
|
|
76355
76868
|
await client2.query("BEGIN");
|
|
76356
76869
|
await client2.query(
|
|
@@ -76370,7 +76883,7 @@ async function createAnalyticsCrmImport(input) {
|
|
|
76370
76883
|
await client2.query(
|
|
76371
76884
|
`INSERT INTO analytics_crm_import_rows(id, import_id, crm_person_ref, payload_ciphertext)
|
|
76372
76885
|
VALUES ($1,$2,$3,$4) ON CONFLICT(import_id, crm_person_ref) DO NOTHING`,
|
|
76373
|
-
[(0,
|
|
76886
|
+
[(0, import_node_crypto50.randomUUID)(), id, row.crmPersonRef, row.payloadCiphertext]
|
|
76374
76887
|
);
|
|
76375
76888
|
}
|
|
76376
76889
|
await client2.query("COMMIT");
|
|
@@ -76409,7 +76922,7 @@ async function createAnalyticsActivationDestination(input) {
|
|
|
76409
76922
|
`INSERT INTO analytics_activation_destinations(id, site_id, platform, name, connection_ref, external_dataset_id, event_mapping, created_by_user_id)
|
|
76410
76923
|
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8) RETURNING *`,
|
|
76411
76924
|
[
|
|
76412
|
-
(0,
|
|
76925
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76413
76926
|
input.siteId,
|
|
76414
76927
|
input.platform,
|
|
76415
76928
|
input.name.trim(),
|
|
@@ -76461,7 +76974,7 @@ async function queueAnalyticsActivation(input) {
|
|
|
76461
76974
|
`INSERT INTO analytics_activation_jobs(id, destination_id, conversion_id, person_id, payload_ciphertext)
|
|
76462
76975
|
VALUES ($1,$2,$3,$4,$5) ON CONFLICT(destination_id, conversion_id) DO NOTHING`,
|
|
76463
76976
|
[
|
|
76464
|
-
(0,
|
|
76977
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76465
76978
|
destination.id,
|
|
76466
76979
|
input.conversionId,
|
|
76467
76980
|
input.personId ?? null,
|
|
@@ -76473,7 +76986,7 @@ async function queueAnalyticsActivation(input) {
|
|
|
76473
76986
|
return queued;
|
|
76474
76987
|
}
|
|
76475
76988
|
async function queueAnalyticsFormDelivery(input) {
|
|
76476
|
-
const id = (0,
|
|
76989
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76477
76990
|
await getAnalyticsPool().query(
|
|
76478
76991
|
`INSERT INTO analytics_form_delivery_jobs(id, submission_id, owner_user_id, payload_ciphertext, last_error_code)
|
|
76479
76992
|
VALUES ($1,$2,$3,$4,$5)`,
|
|
@@ -76600,7 +77113,7 @@ async function analyticsHealth(siteId, userId) {
|
|
|
76600
77113
|
}
|
|
76601
77114
|
async function refreshAnalyticsDailyRollups(input) {
|
|
76602
77115
|
const db = getAnalyticsPool();
|
|
76603
|
-
const runId = (0,
|
|
77116
|
+
const runId = (0, import_node_crypto50.randomUUID)();
|
|
76604
77117
|
await db.query(
|
|
76605
77118
|
`INSERT INTO analytics_rollup_runs(id, window_start, window_end, status) VALUES ($1, $2, $3, 'running')`,
|
|
76606
77119
|
[runId, input.start, input.end]
|
|
@@ -76694,7 +77207,7 @@ async function refreshAnalyticsDailyRollupsIfDue(now = /* @__PURE__ */ new Date(
|
|
|
76694
77207
|
lockClient.release();
|
|
76695
77208
|
}
|
|
76696
77209
|
}
|
|
76697
|
-
function
|
|
77210
|
+
function csvCell3(value) {
|
|
76698
77211
|
const text2 = value == null ? "" : String(value);
|
|
76699
77212
|
return /[\n\r,\"]/.test(text2) ? `"${text2.replaceAll('"', '""')}"` : text2;
|
|
76700
77213
|
}
|
|
@@ -76704,7 +77217,7 @@ function rowsToCsv2(rows) {
|
|
|
76704
77217
|
return [
|
|
76705
77218
|
columns.join(","),
|
|
76706
77219
|
...rows.map(
|
|
76707
|
-
(row) => columns.map((column) =>
|
|
77220
|
+
(row) => columns.map((column) => csvCell3(row[column])).join(",")
|
|
76708
77221
|
)
|
|
76709
77222
|
].join("\n");
|
|
76710
77223
|
}
|
|
@@ -76797,7 +77310,7 @@ async function createAnalyticsExport(input) {
|
|
|
76797
77310
|
`Generated ${(/* @__PURE__ */ new Date()).toISOString()} from the governed ${input.report} report contract.`
|
|
76798
77311
|
].join("\n");
|
|
76799
77312
|
}
|
|
76800
|
-
const id = (0,
|
|
77313
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76801
77314
|
const inserted = await getAnalyticsPool().query(
|
|
76802
77315
|
`INSERT INTO analytics_exports(id, site_id, requested_by_user_id, idempotency_key, report, format, filters, content)
|
|
76803
77316
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8)
|
|
@@ -76830,11 +77343,11 @@ async function createAnalyticsExport(input) {
|
|
|
76830
77343
|
}
|
|
76831
77344
|
return describeArtifact(replay.rows[0]);
|
|
76832
77345
|
}
|
|
76833
|
-
var
|
|
77346
|
+
var import_node_crypto50, import_pg, AnalyticsRepositoryError, pool2, MAX_ENGAGED_MS, ENGAGED_SESSION_MS, blockedPropertyName, inferredFamilySql, ANALYTICS_CONTENT_SORTS, clickIdKeys;
|
|
76834
77347
|
var init_analytics_repository = __esm({
|
|
76835
77348
|
"src/api/analytics-repository.ts"() {
|
|
76836
77349
|
"use strict";
|
|
76837
|
-
|
|
77350
|
+
import_node_crypto50 = require("crypto");
|
|
76838
77351
|
import_pg = require("pg");
|
|
76839
77352
|
init_session();
|
|
76840
77353
|
init_analytics_attribution();
|
|
@@ -77073,8 +77586,8 @@ function dashboardCallbackUrl() {
|
|
|
77073
77586
|
}
|
|
77074
77587
|
async function createThorbitConnectUrl(userId) {
|
|
77075
77588
|
if (!bridgeConfigured()) throw new Error("Thorbit X-Ray account bridge is not configured");
|
|
77076
|
-
const state = (0,
|
|
77077
|
-
const stateHash = (0,
|
|
77589
|
+
const state = (0, import_node_crypto51.randomBytes)(32).toString("base64url");
|
|
77590
|
+
const stateHash = (0, import_node_crypto51.createHash)("sha256").update(state).digest("hex");
|
|
77078
77591
|
await getAnalyticsPool().query(
|
|
77079
77592
|
`INSERT INTO analytics_thorbit_connect_states(state_hash,user_id,expires_at)
|
|
77080
77593
|
VALUES ($1,$2,now()+interval '10 minutes')
|
|
@@ -77089,9 +77602,9 @@ async function createThorbitConnectUrl(userId) {
|
|
|
77089
77602
|
function verifyThorbitAssertion(token6) {
|
|
77090
77603
|
const [encoded, signature] = token6.split(".");
|
|
77091
77604
|
if (!encoded || !signature || !bridgeConfigured()) throw new Error("Invalid Thorbit assertion");
|
|
77092
|
-
const expected = (0,
|
|
77605
|
+
const expected = (0, import_node_crypto51.createHmac)("sha256", bridgeSecret()).update(encoded).digest();
|
|
77093
77606
|
const actual = Buffer.from(signature, "base64url");
|
|
77094
|
-
if (actual.length !== expected.length || !(0,
|
|
77607
|
+
if (actual.length !== expected.length || !(0, import_node_crypto51.timingSafeEqual)(actual, expected)) {
|
|
77095
77608
|
throw new Error("Invalid Thorbit assertion signature");
|
|
77096
77609
|
}
|
|
77097
77610
|
const parsed = AssertionSchema.safeParse(
|
|
@@ -77103,7 +77616,7 @@ function verifyThorbitAssertion(token6) {
|
|
|
77103
77616
|
return parsed.data.entitlement;
|
|
77104
77617
|
}
|
|
77105
77618
|
async function consumeThorbitConnectCallback(input) {
|
|
77106
|
-
const stateHash = (0,
|
|
77619
|
+
const stateHash = (0, import_node_crypto51.createHash)("sha256").update(input.state).digest("hex");
|
|
77107
77620
|
const client2 = await getAnalyticsPool().connect();
|
|
77108
77621
|
try {
|
|
77109
77622
|
await client2.query("BEGIN");
|
|
@@ -77143,11 +77656,11 @@ async function disconnectAnalyticsEntitlement(userId) {
|
|
|
77143
77656
|
[userId]
|
|
77144
77657
|
);
|
|
77145
77658
|
}
|
|
77146
|
-
var
|
|
77659
|
+
var import_node_crypto51, import_zod55, THORBIT_PRODUCT_URL, REFRESH_INTERVAL_MS, ELIGIBLE_GRACE_MS, TRIAL_LENGTH_MS, ThorbitEntitlementSchema, AssertionSchema;
|
|
77147
77660
|
var init_analytics_entitlement = __esm({
|
|
77148
77661
|
"src/api/analytics-entitlement.ts"() {
|
|
77149
77662
|
"use strict";
|
|
77150
|
-
|
|
77663
|
+
import_node_crypto51 = require("crypto");
|
|
77151
77664
|
import_zod55 = require("zod");
|
|
77152
77665
|
init_analytics_repository();
|
|
77153
77666
|
THORBIT_PRODUCT_URL = "https://thorbit.ai";
|
|
@@ -77287,14 +77800,14 @@ function renderPublicForm(form, placementUrl) {
|
|
|
77287
77800
|
const brand = form.brand;
|
|
77288
77801
|
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>:root{font-family:ui-sans-serif,system-ui;color:${escapeHtml8(brand.textColor)};background:${escapeHtml8(brand.backgroundColor)}}*{box-sizing:border-box}body{margin:0;padding:18px}form{display:grid;gap:14px}label{display:grid;gap:6px;font-size:13px;font-weight:650}.check{grid-template-columns:auto 1fr;align-items:center}.check span{grid-column:2}.check input{grid-column:1;grid-row:1}input,textarea,select{width:100%;min-height:44px;padding:10px 12px;border:1px solid #ccd3df;border-radius:${brand.radius}px;background:white;color:inherit;font:inherit}textarea{min-height:110px;resize:vertical}button{min-height:46px;border:0;border-radius:${brand.radius}px;color:white;background:${escapeHtml8(brand.primaryColor)};font:inherit;font-weight:750;cursor:pointer}.consent{margin:0;color:#667085;font-size:11px;line-height:1.45}.notice{display:none;padding:12px;border-radius:${brand.radius}px;background:#edf8f2;color:#17613c}.hp{position:absolute!important;left:-9999px!important}</style></head><body><form id="mcp-form">${fields}<label class="hp">Website<input name="website" autocomplete="off" tabindex="-1"></label>${form.consent_text ? `<p class="consent">${escapeHtml8(form.consent_text)}</p>` : ""}<button>${escapeHtml8(form.submit_label)}</button><div class="notice" role="status"></div></form><script>(()=>{const form=document.querySelector('#mcp-form'),notice=form.querySelector('.notice'),q=new URLSearchParams(location.search);form.addEventListener('submit',async event=>{event.preventDefault();const button=form.querySelector('button');button.disabled=true;const raw=Object.fromEntries(new FormData(form).entries()),website=String(raw.website||''),clickIds={};delete raw.website;for(const k of ['fbclid','gclid','gbraid','wbraid','ttclid','rdt_cid','msclkid']){const v=q.get(k);if(v)clickIds[k]=v}try{const response=await fetch('/analytics/forms/${escapeHtml8(form.public_id)}/submissions',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({data:raw,website,placementUrl:${JSON.stringify(placementUrl)},visitorId:q.get('visitor')||undefined,sessionId:q.get('session')||undefined,source:q.get('source')||undefined,medium:q.get('medium')||undefined,campaign:q.get('campaign')||undefined,clickIds})});if(!response.ok)throw new Error('submit');notice.textContent=${JSON.stringify(form.success_message)};notice.style.display='block';form.reset();${form.redirect_url ? `setTimeout(()=>{top.location.href=${JSON.stringify(form.redirect_url)}},700);` : ""}}catch{notice.textContent='Your response could not be submitted. Please try again.';notice.style.display='block'}finally{button.disabled=false}})})()</script></body></html>`;
|
|
77289
77802
|
}
|
|
77290
|
-
var import_hono34, import_factory6, import_zod56,
|
|
77803
|
+
var import_hono34, import_factory6, import_zod56, import_node_crypto52, import_papaparse6, analyticsApp, auth3, entitlementGuard, ThorbitApiKeySchema, ThorbitCallbackSchema, SiteInputSchema, PixelInputSchema, PixelUpdateSchema, EventSchema, IngestionSchema, ConversionSchema, ExportSchema2, CampaignLinkSchema, FormFieldSchema, FormInputSchema, FormSubmissionSchema, CrmImportSchema, ActivationDestinationSchema, BusinessModelSchema, AdSpendSchema;
|
|
77291
77804
|
var init_analytics_routes = __esm({
|
|
77292
77805
|
"src/api/analytics-routes.ts"() {
|
|
77293
77806
|
"use strict";
|
|
77294
77807
|
import_hono34 = require("hono");
|
|
77295
77808
|
import_factory6 = require("hono/factory");
|
|
77296
77809
|
import_zod56 = require("zod");
|
|
77297
|
-
|
|
77810
|
+
import_node_crypto52 = require("crypto");
|
|
77298
77811
|
import_papaparse6 = __toESM(require("papaparse"), 1);
|
|
77299
77812
|
init_api_auth();
|
|
77300
77813
|
init_db();
|
|
@@ -77625,7 +78138,7 @@ var init_analytics_routes = __esm({
|
|
|
77625
78138
|
const lastName = typeof data.last_name === "string" ? data.last_name.trim() : "";
|
|
77626
78139
|
const fullName = [firstName, lastName].filter(Boolean).join(" ") || (typeof data.name === "string" ? data.name.trim() : "") || email || "Website lead";
|
|
77627
78140
|
const identitySeed = email || `${fullName}:${Date.now()}`;
|
|
77628
|
-
const suffix2 = (0,
|
|
78141
|
+
const suffix2 = (0, import_node_crypto52.createHash)("sha256").update(identitySeed).digest("hex").slice(0, 12);
|
|
77629
78142
|
const path6 = `Leads/person-${suffix2}`;
|
|
77630
78143
|
const { key: memoryKey, error: memoryKeyError } = await getOrCreateUserMemoryKey(user);
|
|
77631
78144
|
const existing = memoryKey ? await memoryCall("getTool", { vault: "People", path: path6 }, memoryKey) : { ok: false, error: memoryKeyError || "memory_credential_unavailable" };
|
|
@@ -77724,9 +78237,9 @@ Submitted the published form.
|
|
|
77724
78237
|
occurredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
77725
78238
|
});
|
|
77726
78239
|
const match = {
|
|
77727
|
-
...email ? { emailSha256: (0,
|
|
78240
|
+
...email ? { emailSha256: (0, import_node_crypto52.createHash)("sha256").update(email).digest("hex") } : {},
|
|
77728
78241
|
...phone ? {
|
|
77729
|
-
phoneSha256: (0,
|
|
78242
|
+
phoneSha256: (0, import_node_crypto52.createHash)("sha256").update(phone.replace(/\D/g, "")).digest("hex")
|
|
77730
78243
|
} : {}
|
|
77731
78244
|
};
|
|
77732
78245
|
const activationQueued = await queueAnalyticsActivation({
|
|
@@ -78154,7 +78667,7 @@ Submitted the published form.
|
|
|
78154
78667
|
rejectedCount += 1;
|
|
78155
78668
|
continue;
|
|
78156
78669
|
}
|
|
78157
|
-
const digest2 = (0,
|
|
78670
|
+
const digest2 = (0, import_node_crypto52.createHash)("sha256").update(
|
|
78158
78671
|
`${parsed.data.sourceSystem}:${externalId || email || phone || `${fullName}:${index}`}`
|
|
78159
78672
|
).digest("hex").slice(0, 16);
|
|
78160
78673
|
const path6 = `Leads/person-${digest2}`;
|
|
@@ -78612,13 +79125,13 @@ var init_analytics_delivery = __esm({
|
|
|
78612
79125
|
|
|
78613
79126
|
// src/api/scheduled-artifact-owner.ts
|
|
78614
79127
|
function scheduledArtifactOwnerIdForApiKey(apiKey) {
|
|
78615
|
-
return (0,
|
|
79128
|
+
return (0, import_node_crypto53.createHash)("sha256").update(apiKey).digest("hex").slice(0, 24);
|
|
78616
79129
|
}
|
|
78617
|
-
var
|
|
79130
|
+
var import_node_crypto53;
|
|
78618
79131
|
var init_scheduled_artifact_owner = __esm({
|
|
78619
79132
|
"src/api/scheduled-artifact-owner.ts"() {
|
|
78620
79133
|
"use strict";
|
|
78621
|
-
|
|
79134
|
+
import_node_crypto53 = require("crypto");
|
|
78622
79135
|
}
|
|
78623
79136
|
});
|
|
78624
79137
|
|
|
@@ -78675,7 +79188,7 @@ async function ensureScheduledRunViewLinksSchema() {
|
|
|
78675
79188
|
schemaReady2 = true;
|
|
78676
79189
|
}
|
|
78677
79190
|
function tokenHash2(token6) {
|
|
78678
|
-
return (0,
|
|
79191
|
+
return (0, import_node_crypto54.createHash)("sha256").update(token6).digest("hex");
|
|
78679
79192
|
}
|
|
78680
79193
|
function mapRow(row) {
|
|
78681
79194
|
return {
|
|
@@ -78695,9 +79208,9 @@ function mapRow(row) {
|
|
|
78695
79208
|
async function createScheduledRunViewLink(input) {
|
|
78696
79209
|
await ensureScheduledRunViewLinksSchema();
|
|
78697
79210
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
78698
|
-
const token6 = (0,
|
|
79211
|
+
const token6 = (0, import_node_crypto54.randomBytes)(32).toString("base64url");
|
|
78699
79212
|
const record = {
|
|
78700
|
-
shareId: (0,
|
|
79213
|
+
shareId: (0, import_node_crypto54.randomUUID)(),
|
|
78701
79214
|
ownerId: input.ownerId,
|
|
78702
79215
|
runId: input.runId,
|
|
78703
79216
|
artifactId: input.artifactId,
|
|
@@ -78760,11 +79273,11 @@ async function revokeScheduledRunViewLink(ownerId2, runId, shareId, now = /* @__
|
|
|
78760
79273
|
});
|
|
78761
79274
|
return result.rowsAffected > 0;
|
|
78762
79275
|
}
|
|
78763
|
-
var
|
|
79276
|
+
var import_node_crypto54, schemaReady2;
|
|
78764
79277
|
var init_scheduled_run_view_links = __esm({
|
|
78765
79278
|
"src/api/scheduled-run-view-links.ts"() {
|
|
78766
79279
|
"use strict";
|
|
78767
|
-
|
|
79280
|
+
import_node_crypto54 = require("crypto");
|
|
78768
79281
|
init_db();
|
|
78769
79282
|
schemaReady2 = false;
|
|
78770
79283
|
}
|
|
@@ -78830,15 +79343,15 @@ ${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id=
|
|
|
78830
79343
|
html,
|
|
78831
79344
|
filename: `${input.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "personal-authority"}.html`,
|
|
78832
79345
|
bytes,
|
|
78833
|
-
sha256: (0,
|
|
79346
|
+
sha256: (0, import_node_crypto55.createHash)("sha256").update(html).digest("hex"),
|
|
78834
79347
|
generatedAt: generatedAtIso
|
|
78835
79348
|
};
|
|
78836
79349
|
}
|
|
78837
|
-
var
|
|
79350
|
+
var import_node_crypto55;
|
|
78838
79351
|
var init_render2 = __esm({
|
|
78839
79352
|
"src/personal-authority/render.ts"() {
|
|
78840
79353
|
"use strict";
|
|
78841
|
-
|
|
79354
|
+
import_node_crypto55 = require("crypto");
|
|
78842
79355
|
}
|
|
78843
79356
|
});
|
|
78844
79357
|
|
|
@@ -78941,15 +79454,15 @@ ${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id
|
|
|
78941
79454
|
html,
|
|
78942
79455
|
filename: `${input.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "personal-authority"}.html`,
|
|
78943
79456
|
bytes,
|
|
78944
|
-
sha256: (0,
|
|
79457
|
+
sha256: (0, import_node_crypto56.createHash)("sha256").update(html).digest("hex"),
|
|
78945
79458
|
generatedAt: generatedAtIso
|
|
78946
79459
|
};
|
|
78947
79460
|
}
|
|
78948
|
-
var
|
|
79461
|
+
var import_node_crypto56, FONT_STACKS;
|
|
78949
79462
|
var init_render_v2 = __esm({
|
|
78950
79463
|
"src/personal-authority/render-v2.ts"() {
|
|
78951
79464
|
"use strict";
|
|
78952
|
-
|
|
79465
|
+
import_node_crypto56 = require("crypto");
|
|
78953
79466
|
init_contracts();
|
|
78954
79467
|
FONT_STACKS = Object.freeze({
|
|
78955
79468
|
"editorial-serif": "Iowan Old Style, Baskerville, Times New Roman, serif",
|
|
@@ -79065,15 +79578,15 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
|
|
|
79065
79578
|
@media(max-width:620px){.desk-section__grid--panorama,.desk-section__grid--mosaic,.desk-section__grid--tiles{grid-template-columns:1fr}.story-card--panorama{display:block}.story-card--panorama h3,.story-card--mosaic-lead h3{font-size:34px}.story-card--mosaic-lead{grid-column:auto;grid-row:auto}.desk-section__grid--tiles>.story-card:nth-child(3n+2){margin-top:0}}
|
|
79066
79579
|
</style></head><body data-theme="${escapeHtml11(config.theme)}" id="top" data-scheduled-renderer="newsroom_publisher_v1">${ticker}${masthead}${navigation}<main>${leadGrid}${latest}${sections}${newsletter}${pressRoom}${trustCenter}</main>${trustFooter}</body></html>`;
|
|
79067
79580
|
const bytes = Buffer.byteLength(html);
|
|
79068
|
-
const sha2565 = (0,
|
|
79581
|
+
const sha2565 = (0, import_node_crypto57.createHash)("sha256").update(html).digest("hex");
|
|
79069
79582
|
const filename2 = `${brand.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "newsroom"}-news-site.html`;
|
|
79070
79583
|
return { html, filename: filename2, bytes, sha256: sha2565, generatedAt: generatedAtIso };
|
|
79071
79584
|
}
|
|
79072
|
-
var
|
|
79585
|
+
var import_node_crypto57;
|
|
79073
79586
|
var init_render3 = __esm({
|
|
79074
79587
|
"src/newsroom-publisher/render.ts"() {
|
|
79075
79588
|
"use strict";
|
|
79076
|
-
|
|
79589
|
+
import_node_crypto57 = require("crypto");
|
|
79077
79590
|
}
|
|
79078
79591
|
});
|
|
79079
79592
|
|
|
@@ -79165,7 +79678,7 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
79165
79678
|
:root{--ink:#10213d;--ink2:#1c355a;--blue:#2563eb;--blue2:#1749b6;--mint:#45d5aa;--paper:#f7f5f0;--line:#dce4ef;--card:#fff;--body:#475569;--serif:Iowan Old Style,Palatino Linotype,Palatino,Georgia,serif;--sans:Inter,Avenir Next,ui-sans-serif,system-ui,sans-serif}body[data-theme="slate"]{--ink:#1e293b;--ink2:#334155;--blue:#475569;--blue2:#1e293b;--mint:#94a3b8;--paper:#f8fafc}body[data-theme="forest"]{--ink:#12352e;--ink2:#23584c;--blue:#147d64;--blue2:#0c5b48;--mint:#79d8bd;--paper:#f4f8f3}*{box-sizing:border-box}html{scroll-behavior:smooth;background:var(--paper)}body{margin:0;color:#252a33;background:var(--paper);font-family:var(--sans);line-height:1.6}a{color:inherit}button{font:inherit}button:focus-visible,a:focus-visible{outline:3px solid var(--mint);outline-offset:3px}.progress{position:fixed;z-index:50;top:0;left:0;height:4px;width:0;background:var(--mint)}.hero{position:relative;overflow:hidden;color:#fff;background:var(--ink)}.hero:after{position:absolute;right:-110px;top:-150px;width:420px;height:420px;border:1px solid #ffffff1a;border-radius:50%;content:""}.hero-inner{position:relative;z-index:1;max-width:1240px;margin:auto;padding:58px 42px 126px}.breadcrumb{display:flex;gap:8px;margin-bottom:34px;color:#dbeafecc;font-size:14px}.eyebrow{display:block;color:var(--blue);font-size:12px;font-weight:800;letter-spacing:.16em;text-transform:uppercase}.hero .eyebrow{color:var(--mint)}h1,h2,h3,p{margin-top:0}.hero h1{max-width:1000px;margin:14px 0 24px;font:700 clamp(44px,6vw,78px)/.98 var(--serif);letter-spacing:-.035em}.hero .dek{max-width:780px;color:#dbeafe;font-size:20px}.contributors{margin-top:30px;color:#eff6ff;font-size:14px}.contributors a{font-weight:800}.meta{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:#dbeafecc}.layout{position:relative;z-index:2;display:grid;grid-template-columns:minmax(0,760px) 290px;gap:64px;max-width:1240px;margin:-78px auto 0;padding:0 42px 80px}.main{min-width:0}.takeaways{padding:38px 44px;border-radius:24px;background:#fff;box-shadow:0 24px 70px #10213d24}.takeaways h2{margin:5px 0 20px;font:700 32px/1.1 var(--serif);color:var(--ink)}.takeaways ul{display:grid;gap:16px;margin:0;padding:0;list-style:none}.takeaways li{position:relative;padding-left:26px;color:var(--body);font-size:17px}.takeaways li:before{position:absolute;left:2px;top:.7em;width:8px;height:8px;border-radius:50%;background:var(--blue);content:""}.intro{padding:40px 0 4px}.intro p,.article-section>p{margin-bottom:22px;color:var(--body);font:400 18px/1.75 var(--sans)}.article-section{scroll-margin-top:28px;padding-top:45px}.article-section h2,.faq h2{margin:6px 0 20px;color:var(--ink);font:700 38px/1.08 var(--serif);letter-spacing:-.02em}.article-section ul{display:grid;gap:10px;margin:22px 0;padding-left:24px;color:var(--body);font-size:17px}.article-section li::marker{color:var(--blue)}.callout{margin:34px 0;padding:24px 28px;border-left:4px solid var(--blue);border-radius:0 16px 16px 0;background:#fff}.callout span{color:var(--blue);font-size:11px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}.callout h3{margin:5px 0 8px;color:var(--ink);font:700 24px/1.15 var(--serif)}.callout p{margin:0;color:var(--body)}.rail{padding-top:0}.sidebar-media{overflow:hidden;margin:0 0 18px;border:1px solid #dbeafe;border-radius:16px;background:#fff}.sidebar-media img,.sidebar-media svg{display:block;width:100%;aspect-ratio:16/9;object-fit:cover}.sidebar-media figcaption{padding:10px 13px;color:#64748b;font-size:11px}.disclosure{margin-bottom:28px;border-top:1px solid #dbeafe;border-bottom:1px solid #dbeafe}.disclosure button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:14px;padding:15px 0;border:0;color:#64748b;background:transparent;text-align:left;font-size:12px;cursor:pointer}.disclosure button b{color:var(--blue);font-size:18px;transition:transform .2s}.disclosure button[aria-expanded="true"] b{transform:rotate(180deg)}.disclosure p{padding:0 0 16px;margin:0;color:#64748b;font-size:12px}.toc{position:sticky;top:30px;padding:22px;border:1px solid var(--line);border-radius:16px;background:#fff;box-shadow:0 2px 5px #10213d12}.toc header{display:flex;align-items:center;justify-content:space-between}.toc header strong{color:var(--ink);font:700 21px/1 var(--serif)}.toc header button{width:34px;height:34px;border:0;border-radius:50%;color:var(--blue);background:transparent;cursor:pointer}.toc nav{display:grid;margin-top:14px}.toc nav a{display:flex;align-items:flex-start;gap:11px;padding:8px 0;color:#64748b;text-decoration:none;font-size:13px;line-height:1.35}.toc nav i{width:8px;height:8px;margin-top:5px;border:2px solid #bfdbfe;border-radius:50%}.toc nav a[aria-current="location"]{color:var(--ink);font-weight:800}.toc nav a[aria-current="location"] i{border-color:var(--blue);background:var(--blue)}.back-top{width:100%;margin-top:18px;padding:16px 0 0;border:0;border-top:1px solid var(--line);color:var(--blue);background:transparent;text-align:right;font-size:13px;font-weight:800;cursor:pointer}.faq{scroll-margin-top:28px;padding-top:64px}.faq>div{border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.faq article+article{border-top:1px solid var(--line)}.faq h3{margin:0}.faq h3 button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:18px;padding:19px 0;border:0;color:var(--ink);background:transparent;text-align:left;font-weight:800;cursor:pointer}.faq h3 b{color:var(--blue);font-size:22px}.faq article>p{padding:0 0 20px;margin:0;color:var(--body);font-size:16px}.author-card{margin-top:64px;padding:32px 36px;border-radius:18px;background:#fff}.article-actions{display:flex;flex-wrap:wrap;justify-content:space-between;gap:14px}.article-actions button{display:inline-flex;min-height:46px;align-items:center;justify-content:center;gap:8px;padding:8px 18px;border:2px solid var(--blue);border-radius:999px;color:var(--ink);background:#fff;font-weight:800;cursor:pointer}.article-actions button:hover{color:#fff;background:var(--blue)}.action-status{min-height:20px;margin:8px 0 0;color:var(--blue);text-align:right;font-size:13px;font-weight:700}.author-grid{display:grid;grid-template-columns:auto 1fr auto;gap:22px;align-items:center;margin-top:24px}.author-portrait{width:88px;height:88px;border-radius:50%;object-fit:cover}.author-initials{display:grid;place-items:center;color:var(--ink);background:#fecdd3;font-size:22px;font-weight:900}.author-grid span{color:#64748b;font-size:13px}.author-grid h2{margin:2px 0;color:var(--ink);font:700 27px/1 var(--serif)}.author-grid h2 a{text-decoration:none}.author-grid p{margin:8px 0;color:#64748b;font-size:14px}.author-grid nav{display:flex;flex-wrap:wrap;gap:14px}.author-grid nav a{color:#64748b;font-size:12px}.author-more{display:inline-flex;min-height:48px;align-items:center;justify-content:center;padding:10px 24px;border:2px solid var(--blue);color:var(--blue);text-align:center;text-decoration:none;font-size:13px;font-weight:800}.author-bio{margin:24px 0 0!important;padding-top:20px;border-top:1px solid var(--line);color:var(--body);font-size:16px}dialog{width:min(720px,calc(100% - 30px));max-height:calc(100dvh - 30px);padding:0;border:0;border-radius:18px;color:var(--ink);background:#fff;box-shadow:0 24px 70px #10213d38}dialog::backdrop{background:#0f172a7a;backdrop-filter:blur(2px)}dialog>div{position:relative;padding:30px}dialog h2{margin:0 50px 2px 0;font:700 30px/1.1 var(--serif)}dialog>div>p{color:#64748b}.dialog-close{position:absolute;top:13px;right:13px;width:44px;height:44px;border:0;border-radius:50%;color:var(--blue);background:transparent;font-size:29px;cursor:pointer}dialog section{border-top:1px solid var(--line)}dialog section button{display:block;width:100%;padding:17px 5px;border:0;border-bottom:1px solid var(--line);color:var(--body);background:#fff;text-align:left;line-height:1.65;cursor:pointer}.citation-status{min-height:22px;margin:14px 0 0!important;color:var(--blue)!important;font-size:13px;font-weight:800}.generated{max-width:1156px;margin:-52px auto 50px;padding:0 42px;color:#94a3b8;font-size:11px}@media(max-width:900px){.layout{display:block}.rail{display:none}.hero-inner{padding-bottom:116px}}@media(max-width:620px){.hero-inner{padding:36px 20px 104px}.hero h1{font-size:46px}.hero .dek{font-size:17px}.layout{margin-top:-70px;padding:0 16px 54px}.takeaways{padding:28px 24px}.article-section h2,.faq h2{font-size:32px}.author-card{padding:24px}.article-actions{display:grid;justify-content:start}.author-grid{grid-template-columns:1fr;gap:12px}.author-more{width:100%}dialog>div{padding:24px}.generated{padding:0 20px}}
|
|
79166
79679
|
</style></head><body data-theme="${escapeHtml12(config.theme)}" data-scheduled-renderer="blog_article_v1"><div class="progress" aria-hidden="true"></div><header class="hero"><div class="hero-inner"><nav class="breadcrumb" aria-label="Breadcrumb"><a href="${safeHref4(input.canonicalUrl)}">${escapeHtml12(input.category)}</a><span>/</span><span>Article</span></nav><span class="eyebrow">${escapeHtml12(input.eyebrow)}</span><h1>${escapeHtml12(input.title)}</h1>${input.dek ? `<p class="dek">${escapeHtml12(input.dek)}</p>` : ""}<div class="contributors">${contributorText}<div class="meta"><time datetime="${escapeHtml12(articleDate)}">Updated ${formatDate2(articleDate)}</time><span>\u2022</span><span>${input.readTimeMinutes} min read</span>${input.reviewer ? "<span>\u2022</span><strong>Expert reviewed</strong>" : ""}</div></div></div></header><main class="layout"><article class="main"><section class="takeaways"><span class="eyebrow">The short answer</span><h2>Key takeaways</h2><ul>${input.keyTakeaways.map((item) => `<li>${escapeHtml12(item)}</li>`).join("")}</ul></section><section class="intro">${input.introduction.map((paragraph) => `<p>${escapeHtml12(paragraph)}</p>`).join("")}</section>${sections}${faq}${author}</article><div class="rail">${media}${disclosure}${toc}</div></main>${config.showGeneratedAt ? `<p class="generated">Rendered ${formatDate2(generatedAtIso)} by MCP Scraper.</p>` : ""}${citationDialog}<script>(()=>{const citations=${jsonForScript(citationValues)};const canonical=${jsonForScript(input.canonicalUrl)};const title=${jsonForScript(input.title)};const progress=document.querySelector('.progress');const tocLinks=[...document.querySelectorAll('.toc nav a')];const targets=tocLinks.map(link=>document.querySelector(link.hash)).filter(Boolean);const update=()=>{const max=document.documentElement.scrollHeight-innerHeight;if(progress)progress.style.width=(max>0?scrollY/max*100:0)+'%';let active=targets[0]?.id;for(const target of targets){if(target.getBoundingClientRect().top<=innerHeight*.55)active=target.id}tocLinks.forEach(link=>link.toggleAttribute('aria-current',link.hash==='#'+active));tocLinks.forEach(link=>{if(link.hash==='#'+active)link.setAttribute('aria-current','location');else link.removeAttribute('aria-current')})};addEventListener('scroll',update,{passive:true});addEventListener('resize',update);update();document.querySelectorAll('.faq h3 button').forEach(button=>button.addEventListener('click',()=>{const panel=document.getElementById(button.getAttribute('aria-controls'));const open=button.getAttribute('aria-expanded')==='true';button.setAttribute('aria-expanded',String(!open));panel.hidden=open;button.querySelector('b').textContent=open?'+':'\u2212'}));const disclosure=document.querySelector('.disclosure button');disclosure?.addEventListener('click',()=>{const panel=document.getElementById(disclosure.getAttribute('aria-controls'));const open=disclosure.getAttribute('aria-expanded')==='true';disclosure.setAttribute('aria-expanded',String(!open));panel.hidden=open});const tocToggle=document.querySelector('.toc header button');tocToggle?.addEventListener('click',()=>{const nav=document.getElementById('toc-links');const open=tocToggle.getAttribute('aria-expanded')==='true';tocToggle.setAttribute('aria-expanded',String(!open));nav.hidden=open;tocToggle.textContent=open?'\u2304':'\u2303'});document.querySelector('.back-top')?.addEventListener('click',()=>scrollTo({top:0,behavior:'smooth'}));const copy=async text=>{try{await navigator.clipboard.writeText(text)}catch{const area=document.createElement('textarea');area.value=text;area.style.position='fixed';area.style.opacity='0';document.body.append(area);area.select();document.execCommand('copy');area.remove()}};const dialog=document.getElementById('citation-dialog');document.querySelector('[data-cite]')?.addEventListener('click',()=>dialog.showModal());document.querySelector('.dialog-close')?.addEventListener('click',()=>dialog.close());dialog?.addEventListener('click',event=>{if(event.target===dialog)dialog.close()});document.querySelectorAll('[data-citation]').forEach(button=>button.addEventListener('click',async()=>{const style=button.dataset.citation;await copy(citations[style]);document.querySelector('.citation-status').textContent=style+' citation copied to clipboard.'}));document.querySelector('[data-share]')?.addEventListener('click',async()=>{const status=document.querySelector('.action-status');if(navigator.share){try{await navigator.share({title,url:canonical});status.textContent='Sharing options opened.';return}catch(error){if(error.name==='AbortError')return}}await copy(canonical);status.textContent='Article link copied to clipboard.'})})()</script></body></html>`;
|
|
79167
79680
|
const bytes = Buffer.byteLength(html);
|
|
79168
|
-
const sha2565 = (0,
|
|
79681
|
+
const sha2565 = (0, import_node_crypto58.createHash)("sha256").update(html).digest("hex");
|
|
79169
79682
|
return {
|
|
79170
79683
|
html,
|
|
79171
79684
|
filename: "blog-article.html",
|
|
@@ -79175,11 +79688,11 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
79175
79688
|
generatedAt: generatedAtIso
|
|
79176
79689
|
};
|
|
79177
79690
|
}
|
|
79178
|
-
var
|
|
79691
|
+
var import_node_crypto58;
|
|
79179
79692
|
var init_render4 = __esm({
|
|
79180
79693
|
"src/blog-article/render.ts"() {
|
|
79181
79694
|
"use strict";
|
|
79182
|
-
|
|
79695
|
+
import_node_crypto58 = require("crypto");
|
|
79183
79696
|
}
|
|
79184
79697
|
});
|
|
79185
79698
|
|
|
@@ -79510,7 +80023,7 @@ function policy6() {
|
|
|
79510
80023
|
};
|
|
79511
80024
|
}
|
|
79512
80025
|
function runStorageSegment(runId) {
|
|
79513
|
-
return /^[a-zA-Z0-9_-]{1,160}$/.test(runId) ? runId : `run-${(0,
|
|
80026
|
+
return /^[a-zA-Z0-9_-]{1,160}$/.test(runId) ? runId : `run-${(0, import_node_crypto59.createHash)("sha256").update(runId).digest("hex").slice(0, 32)}`;
|
|
79514
80027
|
}
|
|
79515
80028
|
async function createScheduledRunArtifact(args) {
|
|
79516
80029
|
if (args.rendered.bytes > SCHEDULED_RUN_ARTIFACT_MAX_BYTES) {
|
|
@@ -79551,12 +80064,12 @@ async function readScheduledRunArtifact(args) {
|
|
|
79551
80064
|
if (!window2 || window2.nextOffset !== null || window2.totalBytes > SCHEDULED_RUN_ARTIFACT_MAX_BYTES) return null;
|
|
79552
80065
|
return window2.text;
|
|
79553
80066
|
}
|
|
79554
|
-
var
|
|
80067
|
+
var import_node_crypto59, SCHEDULED_RUN_ARTIFACT_PREFIX, SCHEDULED_RUN_ARTIFACT_DOWNLOAD_TTL_MS, SCHEDULED_RUN_ARTIFACT_MAX_BYTES;
|
|
79555
80068
|
var init_scheduled_run_artifact_store = __esm({
|
|
79556
80069
|
"src/scheduled-artifacts/scheduled-run-artifact-store.ts"() {
|
|
79557
80070
|
"use strict";
|
|
79558
80071
|
init_private_artifacts();
|
|
79559
|
-
|
|
80072
|
+
import_node_crypto59 = require("crypto");
|
|
79560
80073
|
SCHEDULED_RUN_ARTIFACT_PREFIX = "scheduled-run-artifacts/";
|
|
79561
80074
|
SCHEDULED_RUN_ARTIFACT_DOWNLOAD_TTL_MS = 15 * 60 * 1e3;
|
|
79562
80075
|
SCHEDULED_RUN_ARTIFACT_MAX_BYTES = 2e6;
|
|
@@ -79774,7 +80287,7 @@ async function reconcileDiscoveredNangoConnections(identity, discovered) {
|
|
|
79774
80287
|
updated_at = excluded.updated_at
|
|
79775
80288
|
`,
|
|
79776
80289
|
args: [
|
|
79777
|
-
(0,
|
|
80290
|
+
(0, import_node_crypto60.randomUUID)(),
|
|
79778
80291
|
userId,
|
|
79779
80292
|
connection.providerConfigKey,
|
|
79780
80293
|
connection.provider,
|
|
@@ -79845,7 +80358,7 @@ async function recordServiceConnectionHealth(args) {
|
|
|
79845
80358
|
});
|
|
79846
80359
|
await getDb().execute({
|
|
79847
80360
|
sql: `INSERT INTO service_connection_health_events (id, connection_id, operational_status, failure_code, retryable, evidence_source) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
79848
|
-
args: [(0,
|
|
80361
|
+
args: [(0, import_node_crypto60.randomUUID)(), args.connectionId, args.operationalStatus, args.failureCode ?? null, args.retryable == null ? null : args.retryable ? 1 : 0, args.evidenceSource]
|
|
79849
80362
|
});
|
|
79850
80363
|
}
|
|
79851
80364
|
async function setServiceConnectionActions(identity, connectionId, enabled) {
|
|
@@ -79885,7 +80398,7 @@ async function claimServiceConnectionAction(args) {
|
|
|
79885
80398
|
if (!connection) throw new Error("service_connection_not_found");
|
|
79886
80399
|
const inserted = await getDb().execute({
|
|
79887
80400
|
sql: `INSERT OR IGNORE INTO service_connection_action_audit (id, connection_id, user_id, tool, request_id, status, request_digest) VALUES (?, ?, ?, ?, ?, 'started', ?)`,
|
|
79888
|
-
args: [(0,
|
|
80401
|
+
args: [(0, import_node_crypto60.randomUUID)(), connection.id, connection.userId, args.tool, args.requestId, args.requestDigest]
|
|
79889
80402
|
});
|
|
79890
80403
|
if (Number(inserted.rowsAffected ?? 0) === 1) return { claimed: true };
|
|
79891
80404
|
const existing = await getDb().execute({
|
|
@@ -79910,11 +80423,11 @@ async function claimServiceConnectionAction(args) {
|
|
|
79910
80423
|
...result !== void 0 ? { result } : {}
|
|
79911
80424
|
};
|
|
79912
80425
|
}
|
|
79913
|
-
var
|
|
80426
|
+
var import_node_crypto60, schemaReady3, schemaDb6;
|
|
79914
80427
|
var init_service_connections = __esm({
|
|
79915
80428
|
"src/api/service-connections.ts"() {
|
|
79916
80429
|
"use strict";
|
|
79917
|
-
|
|
80430
|
+
import_node_crypto60 = require("crypto");
|
|
79918
80431
|
init_db();
|
|
79919
80432
|
schemaReady3 = null;
|
|
79920
80433
|
schemaDb6 = null;
|
|
@@ -79928,8 +80441,8 @@ function signingSecret() {
|
|
|
79928
80441
|
return secret2;
|
|
79929
80442
|
}
|
|
79930
80443
|
function schedulerIntegrationSignature(args) {
|
|
79931
|
-
const bodyHash = (0,
|
|
79932
|
-
return (0,
|
|
80444
|
+
const bodyHash = (0, import_node_crypto61.createHash)("sha256").update(args.body).digest("hex");
|
|
80445
|
+
return (0, import_node_crypto61.createHmac)("sha256", args.secret).update(`${args.method.toUpperCase()}
|
|
79933
80446
|
${args.path}
|
|
79934
80447
|
${args.timestamp}
|
|
79935
80448
|
${args.nonce}
|
|
@@ -79976,17 +80489,17 @@ async function verifySchedulerIntegrationRequest(request, rawBody) {
|
|
|
79976
80489
|
});
|
|
79977
80490
|
const suppliedBytes = Buffer.from(signature, "hex");
|
|
79978
80491
|
const expectedBytes = Buffer.from(expected, "hex");
|
|
79979
|
-
if (suppliedBytes.length !== expectedBytes.length || !(0,
|
|
80492
|
+
if (suppliedBytes.length !== expectedBytes.length || !(0, import_node_crypto61.timingSafeEqual)(suppliedBytes, expectedBytes)) {
|
|
79980
80493
|
throw new SchedulerIntegrationAuthError("invalid_signature");
|
|
79981
80494
|
}
|
|
79982
80495
|
await claimNonce(nonce, timestampMs);
|
|
79983
80496
|
return { requestId };
|
|
79984
80497
|
}
|
|
79985
|
-
var
|
|
80498
|
+
var import_node_crypto61, MAX_CLOCK_SKEW_MS, SchedulerIntegrationAuthError;
|
|
79986
80499
|
var init_scheduler_integration_auth = __esm({
|
|
79987
80500
|
"src/api/scheduler-integration-auth.ts"() {
|
|
79988
80501
|
"use strict";
|
|
79989
|
-
|
|
80502
|
+
import_node_crypto61 = require("crypto");
|
|
79990
80503
|
init_db();
|
|
79991
80504
|
init_service_connections();
|
|
79992
80505
|
MAX_CLOCK_SKEW_MS = 5 * 60 * 1e3;
|
|
@@ -80148,7 +80661,7 @@ function requestedSiteMaxPages(maxPages) {
|
|
|
80148
80661
|
return Math.min(ABSOLUTE_SITE_MAX_PAGES, Math.max(1, maxPages ?? DEFAULT_SITE_MAX_PAGES));
|
|
80149
80662
|
}
|
|
80150
80663
|
function shouldRunSiteExtractInBackground(input) {
|
|
80151
|
-
return input.background === true || input.downloadImages === true || input.preserveMedia === true || requestedSiteMaxPages(input.maxPages) > MAX_SYNCHRONOUS_SITE_PAGES;
|
|
80664
|
+
return input.background === true || input.downloadImages === true || input.preserveMedia === true || input.renderJavaScript === true || input.captureRenderedDom === true || input.semanticSimilarity === true || requestedSiteMaxPages(input.maxPages) > MAX_SYNCHRONOUS_SITE_PAGES;
|
|
80152
80665
|
}
|
|
80153
80666
|
var MAX_SYNCHRONOUS_SITE_PAGES, DEFAULT_SITE_MAX_PAGES, ABSOLUTE_SITE_MAX_PAGES;
|
|
80154
80667
|
var init_site_extract_policy = __esm({
|
|
@@ -80294,7 +80807,7 @@ async function fetchMedia(rawUrl, expectedType) {
|
|
|
80294
80807
|
finalUrl: checked.parsed.href,
|
|
80295
80808
|
width: dimensions?.width ?? null,
|
|
80296
80809
|
height: dimensions?.height ?? null,
|
|
80297
|
-
sha256: (0,
|
|
80810
|
+
sha256: (0, import_node_crypto62.createHash)("sha256").update(bytes).digest("hex")
|
|
80298
80811
|
};
|
|
80299
80812
|
}
|
|
80300
80813
|
throw new Error("media_redirect_rejected");
|
|
@@ -80408,7 +80921,7 @@ async function packagePageMedia(args) {
|
|
|
80408
80921
|
files.push({ path: "summary.json", content: Buffer.from(JSON.stringify(summary, null, 2)) });
|
|
80409
80922
|
files.push({ path: "media.jsonl", content: Buffer.from(cleanAssets.map((asset) => JSON.stringify(asset)).join("\n") + "\n") });
|
|
80410
80923
|
const archive = await zipBuffer2(files);
|
|
80411
|
-
const id = (0,
|
|
80924
|
+
const id = (0, import_node_crypto62.randomBytes)(6).toString("hex");
|
|
80412
80925
|
const pointer = await createPrivateArtifact({
|
|
80413
80926
|
policy: policy7(),
|
|
80414
80927
|
ownerId: args.ownerId,
|
|
@@ -80421,11 +80934,11 @@ async function packagePageMedia(args) {
|
|
|
80421
80934
|
const localPath = token5() ? null : (0, import_node_path22.join)(process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || (0, import_node_path22.join)((0, import_node_os15.homedir)(), "Downloads", "mcp-scraper"), "blobs", pointer.artifactId);
|
|
80422
80935
|
return { media: args.media, artifact: { ...pointer, localPath } };
|
|
80423
80936
|
}
|
|
80424
|
-
var
|
|
80937
|
+
var import_node_crypto62, import_node_os15, import_node_path22, import_p_limit7, import_yazl3, PAGE_MEDIA_ARTIFACT_PREFIX, PAGE_MEDIA_ARTIFACT_TTL_MS, PAGE_MEDIA_DOWNLOAD_TTL_MS, MAX_FILE_BYTES, MAX_ARCHIVE_MEDIA_BYTES, MAX_INLINE_IMAGE_BYTES2, MAX_INLINE_TOTAL_BYTES2, DOWNLOAD_CONCURRENCY2, MAX_REDIRECTS3;
|
|
80425
80938
|
var init_page_media_artifacts = __esm({
|
|
80426
80939
|
"src/api/page-media-artifacts.ts"() {
|
|
80427
80940
|
"use strict";
|
|
80428
|
-
|
|
80941
|
+
import_node_crypto62 = require("crypto");
|
|
80429
80942
|
import_node_os15 = require("os");
|
|
80430
80943
|
import_node_path22 = require("path");
|
|
80431
80944
|
import_p_limit7 = __toESM(require("p-limit"), 1);
|
|
@@ -80534,7 +81047,7 @@ var init_site_extract_reconciliation = __esm({
|
|
|
80534
81047
|
|
|
80535
81048
|
// src/api/page-diff.ts
|
|
80536
81049
|
function sha256Hex(value) {
|
|
80537
|
-
return (0,
|
|
81050
|
+
return (0, import_node_crypto63.createHash)("sha256").update(value).digest("hex");
|
|
80538
81051
|
}
|
|
80539
81052
|
function truncateForStorage(value, maxChars = MAX_SNAPSHOT_CONTENT_CHARS) {
|
|
80540
81053
|
if (value.length <= maxChars) return { value, truncated: false };
|
|
@@ -80591,11 +81104,11 @@ function diffPageContent(oldContent, newContent) {
|
|
|
80591
81104
|
totalChangedLineCount
|
|
80592
81105
|
};
|
|
80593
81106
|
}
|
|
80594
|
-
var
|
|
81107
|
+
var import_node_crypto63, import_diff, MAX_SNAPSHOT_CONTENT_CHARS, MAX_DIFF_HUNKS, MAX_DIFF_LINES_PER_RESPONSE;
|
|
80595
81108
|
var init_page_diff = __esm({
|
|
80596
81109
|
"src/api/page-diff.ts"() {
|
|
80597
81110
|
"use strict";
|
|
80598
|
-
|
|
81111
|
+
import_node_crypto63 = require("crypto");
|
|
80599
81112
|
import_diff = require("diff");
|
|
80600
81113
|
MAX_SNAPSHOT_CONTENT_CHARS = 25e4;
|
|
80601
81114
|
MAX_DIFF_HUNKS = 200;
|
|
@@ -80669,7 +81182,7 @@ var init_scrape_vault_sink = __esm({
|
|
|
80669
81182
|
|
|
80670
81183
|
// src/api/scrape-image-sink.ts
|
|
80671
81184
|
function idempotencyKey3(userId, vault, input) {
|
|
80672
|
-
return `scrape-image-${(0,
|
|
81185
|
+
return `scrape-image-${(0, import_node_crypto64.createHash)("sha256").update(`${userId}\0${vault}\0${input.sourceKind}\0${input.sourceUrl}\0${input.imageUrl ?? ""}\0${input.imageBase64 ?? ""}`).digest("hex")}`;
|
|
80673
81186
|
}
|
|
80674
81187
|
async function persistScrapeImagesToMemory(user, inputs, vault) {
|
|
80675
81188
|
const selected = inputs.slice(0, MAX_IMAGES_PER_SCRAPE);
|
|
@@ -80711,11 +81224,11 @@ async function persistScrapeImagesToMemory(user, inputs, vault) {
|
|
|
80711
81224
|
assets
|
|
80712
81225
|
};
|
|
80713
81226
|
}
|
|
80714
|
-
var
|
|
81227
|
+
var import_node_crypto64, MAX_IMAGES_PER_SCRAPE;
|
|
80715
81228
|
var init_scrape_image_sink = __esm({
|
|
80716
81229
|
"src/api/scrape-image-sink.ts"() {
|
|
80717
81230
|
"use strict";
|
|
80718
|
-
|
|
81231
|
+
import_node_crypto64 = require("crypto");
|
|
80719
81232
|
init_memory();
|
|
80720
81233
|
MAX_IMAGES_PER_SCRAPE = 25;
|
|
80721
81234
|
}
|
|
@@ -81168,7 +81681,7 @@ function canonicalJson(value) {
|
|
|
81168
81681
|
return JSON.stringify(value);
|
|
81169
81682
|
}
|
|
81170
81683
|
function sha2563(value) {
|
|
81171
|
-
return (0,
|
|
81684
|
+
return (0, import_node_crypto65.createHash)("sha256").update(value).digest("hex");
|
|
81172
81685
|
}
|
|
81173
81686
|
function sensitiveKey(key) {
|
|
81174
81687
|
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
@@ -81383,11 +81896,11 @@ async function importServiceConnectionToMemory(identity, input, dependencies) {
|
|
|
81383
81896
|
...!searchReady ? { warning: "The snapshot was stored, but no search chunks were indexed yet." } : {}
|
|
81384
81897
|
};
|
|
81385
81898
|
}
|
|
81386
|
-
var
|
|
81899
|
+
var import_node_crypto65, CONNECTION_MEMORY_IMPORT_MAX_ARGS_BYTES, CONNECTION_MEMORY_IMPORT_MAX_RESULT_BYTES, CONNECTION_MEMORY_IMPORT_MAX_STRING_CHARS, CONNECTION_MEMORY_IMPORT_MAX_DEPTH, ConnectionMemoryImportError;
|
|
81387
81900
|
var init_connection_memory_import = __esm({
|
|
81388
81901
|
"src/api/connection-memory-import.ts"() {
|
|
81389
81902
|
"use strict";
|
|
81390
|
-
|
|
81903
|
+
import_node_crypto65 = require("crypto");
|
|
81391
81904
|
init_slugify();
|
|
81392
81905
|
CONNECTION_MEMORY_IMPORT_MAX_ARGS_BYTES = 64 * 1024;
|
|
81393
81906
|
CONNECTION_MEMORY_IMPORT_MAX_RESULT_BYTES = 1e6;
|
|
@@ -81471,7 +81984,7 @@ var init_scrape_blob_cleanup = __esm({
|
|
|
81471
81984
|
|
|
81472
81985
|
// src/api/site-export-reader.ts
|
|
81473
81986
|
function sha2564(value) {
|
|
81474
|
-
return (0,
|
|
81987
|
+
return (0, import_node_crypto66.createHash)("sha256").update(value).digest("hex");
|
|
81475
81988
|
}
|
|
81476
81989
|
function publicPageRecord(page) {
|
|
81477
81990
|
const { bodyMarkdown: _body, contentRef: _contentRef, discoveryLinks: _discovery, ...metadata } = page;
|
|
@@ -81579,11 +82092,11 @@ async function readOwnedSiteExportImage(input) {
|
|
|
81579
82092
|
if (!bytes || artifact.sha256 && sha2564(bytes) !== artifact.sha256) return null;
|
|
81580
82093
|
return { bytes, artifact };
|
|
81581
82094
|
}
|
|
81582
|
-
var
|
|
82095
|
+
var import_node_crypto66, SiteExportFormatUnavailableError;
|
|
81583
82096
|
var init_site_export_reader = __esm({
|
|
81584
82097
|
"src/api/site-export-reader.ts"() {
|
|
81585
82098
|
"use strict";
|
|
81586
|
-
|
|
82099
|
+
import_node_crypto66 = require("crypto");
|
|
81587
82100
|
init_site_extract_repository();
|
|
81588
82101
|
init_site_extract_content_store();
|
|
81589
82102
|
init_site_extract_artifacts();
|
|
@@ -81734,7 +82247,7 @@ function finitePositive(value, fallback) {
|
|
|
81734
82247
|
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
81735
82248
|
}
|
|
81736
82249
|
async function collectConnectedDataExport(args) {
|
|
81737
|
-
const exportId = (0,
|
|
82250
|
+
const exportId = (0, import_node_crypto67.randomUUID)();
|
|
81738
82251
|
const now = args.now ?? Date.now;
|
|
81739
82252
|
const startedAt = now();
|
|
81740
82253
|
const budgetMs = finitePositive(CONNECTED_DATA_EXPORT_BUDGET_MS, 24e4);
|
|
@@ -81848,11 +82361,11 @@ ${lines.length ? `${lines.join("\n")}
|
|
|
81848
82361
|
untrustedContent: true
|
|
81849
82362
|
};
|
|
81850
82363
|
}
|
|
81851
|
-
var
|
|
82364
|
+
var import_node_crypto67, CONNECTED_DATA_INLINE_BUDGET_BYTES, CONNECTED_DATA_MAX_EXPORT_BYTES, CONNECTED_DATA_EXPORT_BUDGET_MS, CONNECTED_DATA_PAGE_START_HEADROOM_MS, CONNECTED_DATA_DATASETS, ConnectedDataExportValidationError;
|
|
81852
82365
|
var init_connected_data_export = __esm({
|
|
81853
82366
|
"src/api/connected-data-export.ts"() {
|
|
81854
82367
|
"use strict";
|
|
81855
|
-
|
|
82368
|
+
import_node_crypto67 = require("crypto");
|
|
81856
82369
|
CONNECTED_DATA_INLINE_BUDGET_BYTES = Number(
|
|
81857
82370
|
process.env.MCP_SCRAPER_CONNECTED_DATA_INLINE_BUDGET_BYTES ?? 5e4
|
|
81858
82371
|
);
|
|
@@ -81966,7 +82479,7 @@ async function exportSearchConsoleTableData(args) {
|
|
|
81966
82479
|
offset += rows.length;
|
|
81967
82480
|
if (stoppedForBytes || rows.length < limit || offset >= matchedRows) break;
|
|
81968
82481
|
}
|
|
81969
|
-
const exportId = (0,
|
|
82482
|
+
const exportId = (0, import_node_crypto68.randomUUID)();
|
|
81970
82483
|
const artifact = await args.writeArtifact({
|
|
81971
82484
|
ownerId: args.ownerId,
|
|
81972
82485
|
exportId,
|
|
@@ -81988,11 +82501,11 @@ async function exportSearchConsoleTableData(args) {
|
|
|
81988
82501
|
warnings
|
|
81989
82502
|
};
|
|
81990
82503
|
}
|
|
81991
|
-
var
|
|
82504
|
+
var import_node_crypto68, SEARCH_CONSOLE_TABLE_EXPORT_MAX_ROWS, SEARCH_CONSOLE_TABLE_EXPORT_PAGE_SIZE, SEARCH_CONSOLE_TABLE_EXPORT_MAX_BYTES, SEARCH_CONSOLE_TABLE_COLUMNS, SearchConsoleTableExportValidationError;
|
|
81992
82505
|
var init_search_console_table_export = __esm({
|
|
81993
82506
|
"src/api/search-console-table-export.ts"() {
|
|
81994
82507
|
"use strict";
|
|
81995
|
-
|
|
82508
|
+
import_node_crypto68 = require("crypto");
|
|
81996
82509
|
SEARCH_CONSOLE_TABLE_EXPORT_MAX_ROWS = 5e4;
|
|
81997
82510
|
SEARCH_CONSOLE_TABLE_EXPORT_PAGE_SIZE = 2e3;
|
|
81998
82511
|
SEARCH_CONSOLE_TABLE_EXPORT_MAX_BYTES = 50 * 1024 * 1024;
|
|
@@ -83171,7 +83684,7 @@ async function listNangoToolsDirect(identity, connectionId) {
|
|
|
83171
83684
|
});
|
|
83172
83685
|
const readTools = [...policies.values()].filter((policy8) => policy8.classification === "read").map((policy8) => policy8.name);
|
|
83173
83686
|
const actionTools = [...policies.values()].filter((policy8) => policy8.classification === "action").map((policy8) => policy8.name);
|
|
83174
|
-
const revision = (0,
|
|
83687
|
+
const revision = (0, import_node_crypto69.createHash)("sha256").update(JSON.stringify(tools.map((tool) => ({ name: tool.name, inputSchema: tool.inputSchema })))).digest("hex");
|
|
83175
83688
|
await updateServiceConnectionTools(connection.id, readTools, actionTools, revision);
|
|
83176
83689
|
const refreshed = await getOwnedServiceConnection(identity, connection.id);
|
|
83177
83690
|
return { connection: refreshed ?? { ...connection, readTools, actionTools, toolRevision: revision }, tools };
|
|
@@ -83198,8 +83711,8 @@ async function callNangoToolDirect(args) {
|
|
|
83198
83711
|
identity: args.identity,
|
|
83199
83712
|
ratePolicyVersion: CONNECTED_USAGE_RATE_POLICY_VERSION
|
|
83200
83713
|
});
|
|
83201
|
-
const requestId = args.requestId?.trim() || (0,
|
|
83202
|
-
const idempotencyKey4 = `main-nango:${(0,
|
|
83714
|
+
const requestId = args.requestId?.trim() || (0, import_node_crypto69.randomUUID)();
|
|
83715
|
+
const idempotencyKey4 = `main-nango:${(0, import_node_crypto69.createHash)("sha256").update(args.identity.toLowerCase()).update("\0").update(connection.id).update("\0").update(args.tool).update("\0").update(requestId).digest("hex")}`;
|
|
83203
83716
|
const startedAt = /* @__PURE__ */ new Date();
|
|
83204
83717
|
const started = performance.now();
|
|
83205
83718
|
let result;
|
|
@@ -83224,7 +83737,7 @@ async function callNangoToolDirect(args) {
|
|
|
83224
83737
|
toolName: args.tool,
|
|
83225
83738
|
operationKind: args.operationKind ?? args.classification,
|
|
83226
83739
|
outcome: providerError ? "error" : "partial",
|
|
83227
|
-
requestId: requestId.length <= 200 ? requestId : (0,
|
|
83740
|
+
requestId: requestId.length <= 200 ? requestId : (0, import_node_crypto69.createHash)("sha256").update(requestId).digest("hex"),
|
|
83228
83741
|
startedAt: startedAt.toISOString(),
|
|
83229
83742
|
completedAt: completedAt.toISOString()
|
|
83230
83743
|
}
|
|
@@ -83266,15 +83779,15 @@ async function describeNangoToolDirect(identity, connectionId, toolName) {
|
|
|
83266
83779
|
providerContractHash: MAIN_INTEGRATION_CONTRACT_HASH,
|
|
83267
83780
|
protocolVersion: null,
|
|
83268
83781
|
schemaSource: "live_tools_list",
|
|
83269
|
-
schemaHash: (0,
|
|
83782
|
+
schemaHash: (0, import_node_crypto69.createHash)("sha256").update(JSON.stringify(projected)).digest("hex"),
|
|
83270
83783
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
83271
83784
|
};
|
|
83272
83785
|
}
|
|
83273
|
-
var
|
|
83786
|
+
var import_node_crypto69, import_client15, DEFAULT_NANGO_MCP_URL, NANGO_TIMEOUT_MS, NANGO_CONNECTION_PAGE_SIZE, NANGO_CONNECTION_MAX_PAGES, MAIN_INTEGRATION_CONTRACT_VERSION, MAIN_INTEGRATION_CONTRACT_HASH, MainNangoTransportError;
|
|
83274
83787
|
var init_main_nango_transport = __esm({
|
|
83275
83788
|
"src/api/main-nango-transport.ts"() {
|
|
83276
83789
|
"use strict";
|
|
83277
|
-
|
|
83790
|
+
import_node_crypto69 = require("crypto");
|
|
83278
83791
|
import_client15 = require("@modelcontextprotocol/client");
|
|
83279
83792
|
init_service_connections();
|
|
83280
83793
|
init_connected_usage_billing();
|
|
@@ -83898,8 +84411,8 @@ async function setScheduleConnectionActionsEnabled(identity, connectionId, enabl
|
|
|
83898
84411
|
return data.connection.actionsEnabled === true;
|
|
83899
84412
|
}
|
|
83900
84413
|
async function callScheduleConnectionAction(identity, connectionId, input, tool, idempotencyKey4) {
|
|
83901
|
-
const requestId = `main-connected-action:${(0,
|
|
83902
|
-
const requestDigest = (0,
|
|
84414
|
+
const requestId = `main-connected-action:${(0, import_node_crypto70.createHash)("sha256").update(identity).update("\0").update(idempotencyKey4?.trim() || (0, import_node_crypto70.randomUUID)()).digest("hex")}`;
|
|
84415
|
+
const requestDigest = (0, import_node_crypto70.createHash)("sha256").update(connectionId).update("\0").update(tool?.trim() ?? "").update("\0").update(canonicalJson2(input)).digest("hex");
|
|
83903
84416
|
if (mainOwnsIntegrations()) {
|
|
83904
84417
|
const selectedTool = tool?.trim();
|
|
83905
84418
|
if (!selectedTool) throw new NangoControlError("An action tool is required.", 400, "invalid_request", false);
|
|
@@ -84050,7 +84563,7 @@ function canonicalJson2(value) {
|
|
|
84050
84563
|
return JSON.stringify(value);
|
|
84051
84564
|
}
|
|
84052
84565
|
function projectedToolSchemaHash(tool) {
|
|
84053
|
-
return (0,
|
|
84566
|
+
return (0, import_node_crypto70.createHash)("sha256").update(canonicalJson2(tool)).digest("hex");
|
|
84054
84567
|
}
|
|
84055
84568
|
async function describeNangoTool(identity, connectionId, tool, fresh) {
|
|
84056
84569
|
if (mainOwnsIntegrations()) {
|
|
@@ -84327,11 +84840,11 @@ async function callMainOwnedExportPage(identity, input) {
|
|
|
84327
84840
|
untrustedContent: true
|
|
84328
84841
|
};
|
|
84329
84842
|
}
|
|
84330
|
-
var
|
|
84843
|
+
var import_node_crypto70, DEFAULT_NANGO_CONTROL_URL, DISABLED_NANGO_TOOLS, CONNECTION_SYNC_REQUIRED_TOOLS, CONNECTION_SYNC_OPTIONAL_TOOLS, NangoControlError, ScheduleConnectionValidationError, SAFE_CONTROL_ERROR_CODES, FIXED_CONTROL_ERROR_MESSAGES, CONTROL_ERROR_CODE_ALIASES;
|
|
84331
84844
|
var init_nango_control = __esm({
|
|
84332
84845
|
"src/api/nango-control.ts"() {
|
|
84333
84846
|
"use strict";
|
|
84334
|
-
|
|
84847
|
+
import_node_crypto70 = require("crypto");
|
|
84335
84848
|
init_connected_data_export();
|
|
84336
84849
|
init_slack_connected_data_export();
|
|
84337
84850
|
init_main_nango_transport();
|
|
@@ -84687,7 +85200,7 @@ async function callResendRead(identity, connectionId, tool, args) {
|
|
|
84687
85200
|
return isRecord5(data) ? data.result ?? data : data;
|
|
84688
85201
|
}
|
|
84689
85202
|
async function callResendAction(identity, connectionId, tool, input, idempotencyKey4) {
|
|
84690
|
-
const requestId = `main-resend-action:${(0,
|
|
85203
|
+
const requestId = `main-resend-action:${(0, import_node_crypto71.createHash)("sha256").update(identity).update("\0").update(idempotencyKey4.trim()).digest("hex")}`;
|
|
84691
85204
|
const body = await controlRequest2("/api/internal/resend/actions/call", {
|
|
84692
85205
|
method: "POST",
|
|
84693
85206
|
headers: { "x-request-id": requestId },
|
|
@@ -84752,12 +85265,12 @@ async function callResendExportPage(identity, input) {
|
|
|
84752
85265
|
untrustedContent: true
|
|
84753
85266
|
};
|
|
84754
85267
|
}
|
|
84755
|
-
var
|
|
85268
|
+
var import_node_crypto71, DEFAULT_CONNECTION_CONTROL_URL, RESEND_PROVIDER_CONFIG_KEY, RESEND_LOGO_URL, RESEND_DOCS_URL, RESEND_ADMIN_BLOCKED_TOOLS, RESEND_CONNECTION_SYNC_REQUIRED_TOOLS, ResendControlError;
|
|
84756
85269
|
var init_resend_control = __esm({
|
|
84757
85270
|
"src/api/resend-control.ts"() {
|
|
84758
85271
|
"use strict";
|
|
84759
85272
|
init_connected_data_export();
|
|
84760
|
-
|
|
85273
|
+
import_node_crypto71 = require("crypto");
|
|
84761
85274
|
DEFAULT_CONNECTION_CONTROL_URL = "https://mcp-scraper-scheduler.vercel.app";
|
|
84762
85275
|
RESEND_PROVIDER_CONFIG_KEY = "resend";
|
|
84763
85276
|
RESEND_LOGO_URL = "https://cdn.resend.com/brand/resend-icon-black.svg";
|
|
@@ -85364,7 +85877,7 @@ function settleWithinTickBudget(label, unfinished, work, onDeadlineOrError) {
|
|
|
85364
85877
|
);
|
|
85365
85878
|
});
|
|
85366
85879
|
}
|
|
85367
|
-
var import_resend3,
|
|
85880
|
+
var import_resend3, import_node_crypto72, import_hono38, import_hono39, import_factory8, import_cookie2, import_stripe2, secureCookies2, isProduction2, sessionCookieOptions2, requireAllowedOrigin, auth4, sessionAuth, requireIntegrationsTier, requirePaidSchedulingTier, app, deploymentProfile, STRIPE_API_VERSION, SYNC_HARVEST_TIMEOUT_OVERRIDE_MS, CRON_TICK_BUDGET_MS, CRON_TICK_DRAIN_BUDGET_MS;
|
|
85368
85881
|
var init_server = __esm({
|
|
85369
85882
|
"src/api/server.ts"() {
|
|
85370
85883
|
"use strict";
|
|
@@ -85377,7 +85890,7 @@ var init_server = __esm({
|
|
|
85377
85890
|
init_og();
|
|
85378
85891
|
import_resend3 = require("resend");
|
|
85379
85892
|
init_url_utils();
|
|
85380
|
-
|
|
85893
|
+
import_node_crypto72 = require("crypto");
|
|
85381
85894
|
init_kpo_extractor();
|
|
85382
85895
|
init_screenshot();
|
|
85383
85896
|
init_media_extractor();
|
|
@@ -86938,7 +87451,7 @@ var init_server = __esm({
|
|
|
86938
87451
|
if (!harvestOk) return c.json(insufficientBalanceResponse(harvestBal, harvestCost), 402);
|
|
86939
87452
|
jobId2 = await createJob(user.id, options.query, { ...options, billingHoldMc: harvestCost }, body.callback_url);
|
|
86940
87453
|
} else {
|
|
86941
|
-
jobId2 = (0,
|
|
87454
|
+
jobId2 = (0, import_node_crypto72.randomUUID)();
|
|
86942
87455
|
const billingDebitKey = `paa-harvest:${jobId2}:hold`;
|
|
86943
87456
|
const description = `PAA harvest: ${options.query}`.slice(0, 500);
|
|
86944
87457
|
const hold = await debitMcIdempotent(
|
|
@@ -87773,6 +88286,13 @@ var init_server = __esm({
|
|
|
87773
88286
|
const bodyResult = ExtractSiteBodySchema.safeParse(raw);
|
|
87774
88287
|
if (!bodyResult.success) return c.json({ error: bodyResult.error.issues[0]?.message ?? "Invalid request" }, 400);
|
|
87775
88288
|
const body = bodyResult.data;
|
|
88289
|
+
if (body.semanticSimilarity && !process.env.JINA_API_KEY?.trim()) {
|
|
88290
|
+
return c.json({
|
|
88291
|
+
error: "Semantic site similarity is not configured on this deployment.",
|
|
88292
|
+
errorCode: "semantic_similarity_unconfigured",
|
|
88293
|
+
retryable: false
|
|
88294
|
+
}, 503);
|
|
88295
|
+
}
|
|
87776
88296
|
if (body.preserveMedia !== void 0 && body.downloadImages !== void 0 && body.preserveMedia !== body.downloadImages) {
|
|
87777
88297
|
return c.json({ error: "preserveMedia conflicts with deprecated downloadImages." }, 400);
|
|
87778
88298
|
}
|
|
@@ -87826,7 +88346,12 @@ var init_server = __esm({
|
|
|
87826
88346
|
maxPages: requestedMaxPages,
|
|
87827
88347
|
rotateProxyEvery: body.rotateProxyEvery ?? 10,
|
|
87828
88348
|
formats: [...body.formats ?? []].sort(),
|
|
87829
|
-
downloadImages
|
|
88349
|
+
downloadImages,
|
|
88350
|
+
renderJavaScript: body.renderJavaScript === true,
|
|
88351
|
+
captureRenderedDom: body.captureRenderedDom === true,
|
|
88352
|
+
semanticSimilarity: body.semanticSimilarity === true,
|
|
88353
|
+
similarityThreshold: body.similarityThreshold ?? null,
|
|
88354
|
+
similarityMaxPairs: body.similarityMaxPairs ?? null
|
|
87830
88355
|
}));
|
|
87831
88356
|
const prepared = await prepareSiteExtractStart({
|
|
87832
88357
|
jobId: jobId2,
|
|
@@ -87840,6 +88365,11 @@ var init_server = __esm({
|
|
|
87840
88365
|
urlsPerBrowser: body.rotateProxyEvery ?? 10,
|
|
87841
88366
|
formats: body.formats,
|
|
87842
88367
|
downloadImages,
|
|
88368
|
+
renderJavaScript: body.renderJavaScript === true,
|
|
88369
|
+
captureRenderedDom: body.captureRenderedDom === true,
|
|
88370
|
+
semanticSimilarity: body.semanticSimilarity === true,
|
|
88371
|
+
similarityThreshold: body.similarityThreshold,
|
|
88372
|
+
similarityMaxPairs: body.similarityMaxPairs,
|
|
87843
88373
|
debitKey: `site-extract:${user.id}:${jobId2}:hold`,
|
|
87844
88374
|
waybackReplay: waybackReplay && !body.wayback ? {
|
|
87845
88375
|
timestamp: waybackReplay.timestamp,
|
|
@@ -87933,8 +88463,10 @@ var init_server = __esm({
|
|
|
87933
88463
|
startUrl: crawlStartUrl,
|
|
87934
88464
|
maxPages: siteMaxPages,
|
|
87935
88465
|
seedUrls: waybackCaptures?.map((capture) => capture.rawReplayUrl),
|
|
87936
|
-
kernelApiKey: rotateProxies || wantsBranding || body.browserFallback || body.kernelFallback ? browserServiceApiKey() : void 0,
|
|
88466
|
+
kernelApiKey: rotateProxies || wantsBranding || body.browserFallback || body.kernelFallback || body.renderJavaScript || body.captureRenderedDom || body.semanticSimilarity ? browserServiceApiKey() : void 0,
|
|
87937
88467
|
formats: body.formats,
|
|
88468
|
+
forceBrowserRender: body.renderJavaScript || body.captureRenderedDom || body.semanticSimilarity,
|
|
88469
|
+
captureRenderedDom: body.captureRenderedDom,
|
|
87938
88470
|
...rotateProxies ? {
|
|
87939
88471
|
rotateProxyEvery: body.rotateProxyEvery ?? 30,
|
|
87940
88472
|
parallelism: concurrencyLimitForUser(user)
|