mcp-scraper 0.64.0 → 0.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +2 -2
- package/dist/bin/api-server.cjs +1028 -497
- 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 -9
- 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-5BODYBIP.js +7 -0
- package/dist/chunk-5BODYBIP.js.map +1 -0
- 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-3NXLGTC6.js → chunk-DCWXVAQT.js} +2 -2
- package/dist/{chunk-3NXLGTC6.js.map → chunk-DCWXVAQT.js.map} +1 -1
- package/dist/{chunk-EEW3DMI5.js → chunk-PSKRQDGN.js} +50 -10
- package/dist/chunk-PSKRQDGN.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-TMAWQYZE.js → server-AFEA235I.js} +170 -163
- package/dist/server-AFEA235I.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-5QYSY5KI.js.map +0 -1
- package/dist/chunk-DYSXI6QU.js +0 -7
- package/dist/chunk-DYSXI6QU.js.map +0 -1
- package/dist/chunk-EEW3DMI5.js.map +0 -1
- package/dist/extract-bundle-FW23CEMG.js.map +0 -1
- package/dist/server-TMAWQYZE.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();
|
|
@@ -19219,7 +19801,7 @@ async function formatExtractSite(raw, input, ctx) {
|
|
|
19219
19801
|
const parsed = parseData(raw);
|
|
19220
19802
|
if ("error" in parsed) return formattedErrorResult(parsed.error);
|
|
19221
19803
|
const started = formatBackgroundJobStarted(
|
|
19222
|
-
"Multi-Page Site Content Crawl",
|
|
19804
|
+
input.toolLabel ?? "Multi-Page Site Content Crawl",
|
|
19223
19805
|
parsed.data,
|
|
19224
19806
|
{
|
|
19225
19807
|
requested: input.delivery ?? "auto",
|
|
@@ -20769,7 +21351,8 @@ function formatLeadListImport(raw) {
|
|
|
20769
21351
|
const map = Object.keys(detailedMap).length > 0 ? detailedMap : Object.fromEntries(Object.entries(simpleMap).map(([field, header]) => [field, {
|
|
20770
21352
|
header: header == null ? null : String(header),
|
|
20771
21353
|
confidence: header == null ? 0 : 1,
|
|
20772
|
-
reason: "server_suggestion"
|
|
21354
|
+
reason: "server_suggestion",
|
|
21355
|
+
accepted: header != null
|
|
20773
21356
|
}]));
|
|
20774
21357
|
const mappingLines = Object.entries(map).slice(0, 12).map(([field, suggestion]) => {
|
|
20775
21358
|
const record = structuredRecord(suggestion);
|
|
@@ -22883,7 +23466,7 @@ function backupProxyAvailable() {
|
|
|
22883
23466
|
}
|
|
22884
23467
|
function randomStickySessionId() {
|
|
22885
23468
|
let digits = "";
|
|
22886
|
-
for (let i = 0; i < 10; i++) digits += String((0,
|
|
23469
|
+
for (let i = 0; i < 10; i++) digits += String((0, import_node_crypto10.randomInt)(0, 10));
|
|
22887
23470
|
return digits;
|
|
22888
23471
|
}
|
|
22889
23472
|
function buildBackupUsername(opts = {}) {
|
|
@@ -22941,11 +23524,11 @@ async function cleanupBackupProxyId(kernelApiKey, proxyId) {
|
|
|
22941
23524
|
} catch {
|
|
22942
23525
|
}
|
|
22943
23526
|
}
|
|
22944
|
-
var
|
|
23527
|
+
var import_node_crypto10, import_sdk7, BACKUP_PROXY_HOST, BACKUP_PROXY_PORT, BACKUP_STICKY_SESSION_MINUTES, BACKUP_LAST_RESORT_ATTEMPTS;
|
|
22945
23528
|
var init_backup_proxy = __esm({
|
|
22946
23529
|
"src/backup-proxy.ts"() {
|
|
22947
23530
|
"use strict";
|
|
22948
|
-
|
|
23531
|
+
import_node_crypto10 = require("crypto");
|
|
22949
23532
|
import_sdk7 = __toESM(require("@onkernel/sdk"), 1);
|
|
22950
23533
|
BACKUP_PROXY_HOST = "pr.oxylabs.io";
|
|
22951
23534
|
BACKUP_PROXY_PORT = 7777;
|
|
@@ -24350,7 +24933,7 @@ function csvRecords(text2) {
|
|
|
24350
24933
|
return record;
|
|
24351
24934
|
});
|
|
24352
24935
|
}
|
|
24353
|
-
function
|
|
24936
|
+
function csvCell2(value) {
|
|
24354
24937
|
if (value === null || value === void 0) return "";
|
|
24355
24938
|
const text2 = String(value);
|
|
24356
24939
|
return /[",\n\r]/.test(text2) ? `"${text2.replace(/"/g, '""')}"` : text2;
|
|
@@ -24358,7 +24941,7 @@ function csvCell(value) {
|
|
|
24358
24941
|
function rowsToCsv(headers, rows) {
|
|
24359
24942
|
return [
|
|
24360
24943
|
headers.join(","),
|
|
24361
|
-
...rows.map((row) => headers.map((header) =>
|
|
24944
|
+
...rows.map((row) => headers.map((header) => csvCell2(row[header])).join(","))
|
|
24362
24945
|
].join("\n") + "\n";
|
|
24363
24946
|
}
|
|
24364
24947
|
var init_csv = __esm({
|
|
@@ -24754,12 +25337,12 @@ async function getHostedZipGroups(stateInput) {
|
|
|
24754
25337
|
async function importHostedZipGroupsCsv(input) {
|
|
24755
25338
|
await ensureHostedLocationDataSchema();
|
|
24756
25339
|
const sourceUrl = normalizedSourceUrl(input.sourceUrl);
|
|
24757
|
-
const sha2565 = (0,
|
|
25340
|
+
const sha2565 = (0, import_node_crypto11.createHash)("sha256").update(input.csv).digest("hex");
|
|
24758
25341
|
const active = await getActiveHostedLocationDataset();
|
|
24759
25342
|
if (active?.sha256 === sha2565) return { dataset: active, duplicate: true };
|
|
24760
25343
|
const parsed = parseHostedZipGroupsCsv(input.csv);
|
|
24761
25344
|
assertNationwideZipCoverage(parsed);
|
|
24762
|
-
const id = `loc_${(0,
|
|
25345
|
+
const id = `loc_${(0, import_node_crypto11.randomUUID)().replaceAll("-", "")}`;
|
|
24763
25346
|
const db = getDb();
|
|
24764
25347
|
await db.execute({
|
|
24765
25348
|
sql: `
|
|
@@ -24827,12 +25410,12 @@ async function importHostedCensusPlacesCsv(input) {
|
|
|
24827
25410
|
if (!state) throw new Error("state must be a two-letter US state abbreviation");
|
|
24828
25411
|
const kind = censusDatasetKind(state);
|
|
24829
25412
|
const sourceUrl = normalizedSourceUrl(input.sourceUrl);
|
|
24830
|
-
const sha2565 = (0,
|
|
25413
|
+
const sha2565 = (0, import_node_crypto11.createHash)("sha256").update(input.csv).digest("hex");
|
|
24831
25414
|
const active = await getActiveHostedDataset(kind);
|
|
24832
25415
|
if (active?.sha256 === sha2565) return { dataset: active, duplicate: true };
|
|
24833
25416
|
const stateFips = STATE_FIPS_BY_ABBR[state];
|
|
24834
25417
|
const parsed = parseHostedCensusPlacesCsv(input.csv, stateFips);
|
|
24835
|
-
const id = `loc_${(0,
|
|
25418
|
+
const id = `loc_${(0, import_node_crypto11.randomUUID)().replaceAll("-", "")}`;
|
|
24836
25419
|
const db = getDb();
|
|
24837
25420
|
await db.execute({
|
|
24838
25421
|
sql: `
|
|
@@ -24955,11 +25538,11 @@ async function queryHostedLocationMarkets(input) {
|
|
|
24955
25538
|
warnings
|
|
24956
25539
|
};
|
|
24957
25540
|
}
|
|
24958
|
-
var
|
|
25541
|
+
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;
|
|
24959
25542
|
var init_location_data_repository = __esm({
|
|
24960
25543
|
"src/api/location-data-repository.ts"() {
|
|
24961
25544
|
"use strict";
|
|
24962
|
-
|
|
25545
|
+
import_node_crypto11 = require("crypto");
|
|
24963
25546
|
init_db();
|
|
24964
25547
|
init_csv();
|
|
24965
25548
|
HOSTED_ZIP_DATASET_KIND = "us_zip_groups";
|
|
@@ -26273,7 +26856,7 @@ async function claimDirectoryWorkflowOutbox(input) {
|
|
|
26273
26856
|
const workerId = requiredBoundedString(input.workerId, "outbox worker id", 160);
|
|
26274
26857
|
const limit = Math.max(1, Math.min(100, Math.trunc(input.limit ?? 25)));
|
|
26275
26858
|
const leaseSeconds = Math.max(30, Math.min(3600, Math.trunc(input.leaseSeconds ?? 120)));
|
|
26276
|
-
const claimToken = `${workerId}:${(0,
|
|
26859
|
+
const claimToken = `${workerId}:${(0, import_node_crypto12.randomUUID)()}`;
|
|
26277
26860
|
const leaseModifier = `+${leaseSeconds} seconds`;
|
|
26278
26861
|
const results = await getDb().batch([
|
|
26279
26862
|
{
|
|
@@ -26333,11 +26916,11 @@ async function markDirectoryWorkflowOutboxFailed(input) {
|
|
|
26333
26916
|
});
|
|
26334
26917
|
return Number(result.rowsAffected ?? 0) > 0;
|
|
26335
26918
|
}
|
|
26336
|
-
var
|
|
26919
|
+
var import_node_crypto12, DIRECTORY_EVENT_NAME, TERMINAL_JOB_STATUSES, DIRECTORY_MAX_DISPATCH_ATTEMPTS, DIRECTORY_START_DEADLINE_MINUTES, DIRECTORY_RUNNING_STALE_MINUTES, schemaDb2, schemaPromise2;
|
|
26337
26920
|
var init_directory_workflow_repository = __esm({
|
|
26338
26921
|
"src/api/directory-workflow-repository.ts"() {
|
|
26339
26922
|
"use strict";
|
|
26340
|
-
|
|
26923
|
+
import_node_crypto12 = require("crypto");
|
|
26341
26924
|
init_db();
|
|
26342
26925
|
DIRECTORY_EVENT_NAME = "mcp-scraper/directory.requested";
|
|
26343
26926
|
TERMINAL_JOB_STATUSES = /* @__PURE__ */ new Set(["succeeded", "partial", "failed"]);
|
|
@@ -26451,7 +27034,7 @@ async function acquireConcurrencyGate(user, operation, options = {}) {
|
|
|
26451
27034
|
return { ok: true, lockId: null, active: await countActiveUsageForUser(user.id, true), limit, operation, reused: true };
|
|
26452
27035
|
}
|
|
26453
27036
|
await expireConcurrencyLocksForUser(user.id);
|
|
26454
|
-
const lockId = `cl_${(0,
|
|
27037
|
+
const lockId = `cl_${(0, import_node_crypto13.randomUUID)().replace(/-/g, "").slice(0, 24)}`;
|
|
26455
27038
|
const res = await getDb().execute({
|
|
26456
27039
|
sql: `INSERT INTO concurrency_locks (id, user_id, operation, status, expires_at, metadata)
|
|
26457
27040
|
SELECT ?, ?, ?, 'active', datetime('now', ?), ?
|
|
@@ -26501,11 +27084,11 @@ async function extendConcurrencyGate(lockId, ttlSeconds = DEFAULT_LOCK_TTL_SECON
|
|
|
26501
27084
|
args: [lockTtlModifier(ttlSeconds), lockId]
|
|
26502
27085
|
});
|
|
26503
27086
|
}
|
|
26504
|
-
var
|
|
27087
|
+
var import_node_crypto13, DEFAULT_LOCK_TTL_SECONDS, DEFAULT_RETRY_AFTER_SECONDS, MAX_LOCK_TTL_SECONDS;
|
|
26505
27088
|
var init_concurrency_gates = __esm({
|
|
26506
27089
|
"src/api/concurrency-gates.ts"() {
|
|
26507
27090
|
"use strict";
|
|
26508
|
-
|
|
27091
|
+
import_node_crypto13 = require("crypto");
|
|
26509
27092
|
init_db();
|
|
26510
27093
|
init_rates();
|
|
26511
27094
|
DEFAULT_LOCK_TTL_SECONDS = 15 * 60;
|
|
@@ -27572,7 +28155,7 @@ var init_PAAExtractor = __esm({
|
|
|
27572
28155
|
if (remainingHumanClickDelayMs > 0) await page.waitForTimeout(remainingHumanClickDelayMs);
|
|
27573
28156
|
return "ok";
|
|
27574
28157
|
};
|
|
27575
|
-
let
|
|
28158
|
+
let round2 = 0;
|
|
27576
28159
|
let growthWaits = 0;
|
|
27577
28160
|
while (true) {
|
|
27578
28161
|
if (options.softDeadlineMs && Date.now() >= options.softDeadlineMs) break;
|
|
@@ -27600,7 +28183,7 @@ var init_PAAExtractor = __esm({
|
|
|
27600
28183
|
continue;
|
|
27601
28184
|
}
|
|
27602
28185
|
growthWaits = 0;
|
|
27603
|
-
this.reporter.onDepth(++
|
|
28186
|
+
this.reporter.onDepth(++round2);
|
|
27604
28187
|
await this.throwIfCaptcha(page, "Google PAA expansion");
|
|
27605
28188
|
clickedOnceEver.add(target.q);
|
|
27606
28189
|
const expansionStatus = await expandOneItemSerially(target.q);
|
|
@@ -30137,10 +30720,10 @@ function stableCanonicalJson(value) {
|
|
|
30137
30720
|
return JSON.stringify(normalize4(value));
|
|
30138
30721
|
}
|
|
30139
30722
|
function leadListEnrichmentFingerprint(input) {
|
|
30140
|
-
return (0,
|
|
30723
|
+
return (0, import_node_crypto14.createHash)("sha256").update(stableCanonicalJson(input)).digest("hex");
|
|
30141
30724
|
}
|
|
30142
30725
|
function leadListRowInputDigest(row) {
|
|
30143
|
-
return (0,
|
|
30726
|
+
return (0, import_node_crypto14.createHash)("sha256").update(stableCanonicalJson(row)).digest("hex");
|
|
30144
30727
|
}
|
|
30145
30728
|
function emptyUsage() {
|
|
30146
30729
|
return { mapsAttempts: 0, pageAttempts: 0, pageSuccesses: 0, serpSearches: 0 };
|
|
@@ -30613,7 +31196,7 @@ async function claimLeadListEnrichmentOutbox(input) {
|
|
|
30613
31196
|
const workerId = requiredBoundedString2(input.workerId, "outbox worker id", 160);
|
|
30614
31197
|
const limit = Math.max(1, Math.min(100, Math.trunc(input.limit ?? 25)));
|
|
30615
31198
|
const leaseSeconds = Math.max(30, Math.min(3600, Math.trunc(input.leaseSeconds ?? 120)));
|
|
30616
|
-
const claimToken = `${workerId}:${(0,
|
|
31199
|
+
const claimToken = `${workerId}:${(0, import_node_crypto14.randomUUID)()}`;
|
|
30617
31200
|
const results = await getDb().batch([{
|
|
30618
31201
|
sql: `UPDATE lead_list_enrichment_outbox SET status='dispatching',attempts=attempts+1,locked_by=?,
|
|
30619
31202
|
locked_until=datetime('now',?),updated_at=datetime('now') WHERE id IN (SELECT id FROM lead_list_enrichment_outbox
|
|
@@ -30639,11 +31222,11 @@ async function markLeadListEnrichmentOutboxFailed(input) {
|
|
|
30639
31222
|
WHERE id=? AND status='dispatching' AND locked_by=?`, args: [`+${retryAfterSeconds} seconds`, String(input.error).slice(0, 2e3), input.id, input.claimToken] });
|
|
30640
31223
|
return Number(result.rowsAffected ?? 0) > 0;
|
|
30641
31224
|
}
|
|
30642
|
-
var
|
|
31225
|
+
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;
|
|
30643
31226
|
var init_lead_list_enrichment_repository = __esm({
|
|
30644
31227
|
"src/api/lead-list-enrichment-repository.ts"() {
|
|
30645
31228
|
"use strict";
|
|
30646
|
-
|
|
31229
|
+
import_node_crypto14 = require("crypto");
|
|
30647
31230
|
init_db();
|
|
30648
31231
|
EVENT_NAME = "mcp-scraper/lead-list-enrichment.requested";
|
|
30649
31232
|
TERMINAL_JOB_STATUSES2 = /* @__PURE__ */ new Set(["complete", "partial", "empty", "failed", "cancelled"]);
|
|
@@ -31221,7 +31804,7 @@ var init_paa_harvest_settlement = __esm({
|
|
|
31221
31804
|
|
|
31222
31805
|
// src/api/serp-identity-db.ts
|
|
31223
31806
|
async function createSerpIdentityRow(input) {
|
|
31224
|
-
const id = `serpi_${(0,
|
|
31807
|
+
const id = `serpi_${(0, import_node_crypto15.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
31225
31808
|
await getDb().execute({
|
|
31226
31809
|
sql: `INSERT INTO serp_identities
|
|
31227
31810
|
(id, user_id, name, kernel_profile_name, kernel_proxy_id, proxy_type, country, status)
|
|
@@ -31266,11 +31849,11 @@ async function deleteSerpIdentityRow(userId, name) {
|
|
|
31266
31849
|
args: [userId, name]
|
|
31267
31850
|
});
|
|
31268
31851
|
}
|
|
31269
|
-
var
|
|
31852
|
+
var import_node_crypto15;
|
|
31270
31853
|
var init_serp_identity_db = __esm({
|
|
31271
31854
|
"src/api/serp-identity-db.ts"() {
|
|
31272
31855
|
"use strict";
|
|
31273
|
-
|
|
31856
|
+
import_node_crypto15 = require("crypto");
|
|
31274
31857
|
init_db();
|
|
31275
31858
|
}
|
|
31276
31859
|
});
|
|
@@ -32017,7 +32600,7 @@ async function runDurablePaaCapture(input) {
|
|
|
32017
32600
|
const { gzipSync: gzipSync2 } = await import("zlib");
|
|
32018
32601
|
rawDomGzip = gzipSync2(transported);
|
|
32019
32602
|
}
|
|
32020
|
-
rawDomSha256 = (0,
|
|
32603
|
+
rawDomSha256 = (0, import_node_crypto16.createHash)("sha256").update(rawDomGzip).digest("hex");
|
|
32021
32604
|
}
|
|
32022
32605
|
}
|
|
32023
32606
|
const selected = Array.from(records.values()).slice(0, input.maxQuestions);
|
|
@@ -32101,12 +32684,12 @@ async function runDurablePaaCapture(input) {
|
|
|
32101
32684
|
}
|
|
32102
32685
|
throw new Error("paa_work_deadline_exhausted_before_capture");
|
|
32103
32686
|
}
|
|
32104
|
-
var import_sdk9,
|
|
32687
|
+
var import_sdk9, import_node_crypto16, PAA_INVOCATION_BUDGET_MS, PAA_BROWSER_WORK_BUDGET_MS, PAA_SOLVER_BUDGET_MS, RAW_PREPARE_CODE;
|
|
32105
32688
|
var init_durable_capture = __esm({
|
|
32106
32689
|
"src/paa/durable-capture.ts"() {
|
|
32107
32690
|
"use strict";
|
|
32108
32691
|
import_sdk9 = __toESM(require("@onkernel/sdk"), 1);
|
|
32109
|
-
|
|
32692
|
+
import_node_crypto16 = require("crypto");
|
|
32110
32693
|
init_selectors();
|
|
32111
32694
|
init_uule();
|
|
32112
32695
|
PAA_INVOCATION_BUDGET_MS = 28e4;
|
|
@@ -32534,7 +33117,7 @@ function mapSubmission(row) {
|
|
|
32534
33117
|
async function event(submissionId, eventType, actorKind, actorId, metadata = {}) {
|
|
32535
33118
|
await getDb().execute({
|
|
32536
33119
|
sql: `INSERT INTO local_sourcebook_events (id, submission_id, event_type, actor_kind, actor_id, metadata_json) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
32537
|
-
args: [(0,
|
|
33120
|
+
args: [(0, import_node_crypto17.randomUUID)(), submissionId, eventType, actorKind, actorId, JSON.stringify(metadata)]
|
|
32538
33121
|
});
|
|
32539
33122
|
}
|
|
32540
33123
|
async function createLocalSourcebookSubmission(input) {
|
|
@@ -32548,7 +33131,7 @@ async function createLocalSourcebookSubmission(input) {
|
|
|
32548
33131
|
return submission;
|
|
32549
33132
|
}
|
|
32550
33133
|
}
|
|
32551
|
-
const id = `lsb_${(0,
|
|
33134
|
+
const id = `lsb_${(0, import_node_crypto17.randomUUID)().replace(/-/g, "")}`;
|
|
32552
33135
|
const coverage = {
|
|
32553
33136
|
requested: ["website_crawl", "structured_data", "services_products", "service_areas", "genuine_images", "staff_team", "review_sources"],
|
|
32554
33137
|
crawl: { state: "queued", pagesDiscovered: 0, pagesCaptured: 0 },
|
|
@@ -32689,11 +33272,11 @@ async function getPublicLocalSourcebook(category, state, slug4) {
|
|
|
32689
33272
|
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] });
|
|
32690
33273
|
return result.rows[0] ? parseJson3(result.rows[0].payload_json) : null;
|
|
32691
33274
|
}
|
|
32692
|
-
var
|
|
33275
|
+
var import_node_crypto17, LOCAL_SOURCEBOOK_CATEGORIES, schemaPromise4, schemaDb4;
|
|
32693
33276
|
var init_local_sourcebook_repository = __esm({
|
|
32694
33277
|
"src/api/local-sourcebook-repository.ts"() {
|
|
32695
33278
|
"use strict";
|
|
32696
|
-
|
|
33279
|
+
import_node_crypto17 = require("crypto");
|
|
32697
33280
|
init_db();
|
|
32698
33281
|
LOCAL_SOURCEBOOK_CATEGORIES = ["home", "professional", "restaurants", "financial", "realestate", "auto", "wellness"];
|
|
32699
33282
|
schemaPromise4 = null;
|
|
@@ -33845,7 +34428,7 @@ var init_local_sourcebook_schema = __esm({
|
|
|
33845
34428
|
|
|
33846
34429
|
// src/api/local-sourcebook-compiler.ts
|
|
33847
34430
|
function digest(value) {
|
|
33848
|
-
return (0,
|
|
34431
|
+
return (0, import_node_crypto18.createHash)("sha256").update(value).digest("hex").slice(0, 20);
|
|
33849
34432
|
}
|
|
33850
34433
|
function unique(values, limit = 100) {
|
|
33851
34434
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -34282,11 +34865,11 @@ function compileLocalSourcebookListing(input) {
|
|
|
34282
34865
|
}
|
|
34283
34866
|
};
|
|
34284
34867
|
}
|
|
34285
|
-
var
|
|
34868
|
+
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;
|
|
34286
34869
|
var init_local_sourcebook_compiler = __esm({
|
|
34287
34870
|
"src/api/local-sourcebook-compiler.ts"() {
|
|
34288
34871
|
"use strict";
|
|
34289
|
-
|
|
34872
|
+
import_node_crypto18 = require("crypto");
|
|
34290
34873
|
init_local_sourcebook_public_urls();
|
|
34291
34874
|
init_local_sourcebook_schema();
|
|
34292
34875
|
CATEGORY_LABELS = {
|
|
@@ -34643,6 +35226,11 @@ async function prepareSiteExtractStart(input) {
|
|
|
34643
35226
|
urlsPerBrowser: input.urlsPerBrowser,
|
|
34644
35227
|
formats: input.formats,
|
|
34645
35228
|
downloadImages: input.downloadImages,
|
|
35229
|
+
renderJavaScript: input.renderJavaScript === true,
|
|
35230
|
+
captureRenderedDom: input.captureRenderedDom === true,
|
|
35231
|
+
semanticSimilarity: input.semanticSimilarity === true,
|
|
35232
|
+
similarityThreshold: input.similarityThreshold,
|
|
35233
|
+
similarityMaxPairs: input.similarityMaxPairs,
|
|
34646
35234
|
...input.waybackReplay ? {
|
|
34647
35235
|
waybackReplay: input.waybackReplay,
|
|
34648
35236
|
disableLinkDiscovery: true
|
|
@@ -35387,15 +35975,15 @@ function normalizeIdempotencyKey(value) {
|
|
|
35387
35975
|
return key;
|
|
35388
35976
|
}
|
|
35389
35977
|
function tokenFor(id, idempotencyKey4) {
|
|
35390
|
-
return (0,
|
|
35978
|
+
return (0, import_node_crypto19.createHmac)("sha256", billingSecret()).update(id).update(":").update(idempotencyKey4).digest("base64url");
|
|
35391
35979
|
}
|
|
35392
35980
|
function tokenHash(token6) {
|
|
35393
|
-
return (0,
|
|
35981
|
+
return (0, import_node_crypto19.createHash)("sha256").update(token6).digest("hex");
|
|
35394
35982
|
}
|
|
35395
35983
|
function verifyToken(row, token6) {
|
|
35396
35984
|
const expected = Buffer.from(row.token_hash, "hex");
|
|
35397
35985
|
const actual = Buffer.from(tokenHash(token6), "hex");
|
|
35398
|
-
if (expected.length !== actual.length || !(0,
|
|
35986
|
+
if (expected.length !== actual.length || !(0, import_node_crypto19.timingSafeEqual)(expected, actual)) {
|
|
35399
35987
|
throw new UnifiedBillingError("unauthorized", "invalid billing authorization token", 401);
|
|
35400
35988
|
}
|
|
35401
35989
|
}
|
|
@@ -35510,7 +36098,7 @@ async function authorizeScheduledRun(args) {
|
|
|
35510
36098
|
{ balanceMc, requiredMc: SCHEDULED_RUN_BASE_MC }
|
|
35511
36099
|
);
|
|
35512
36100
|
}
|
|
35513
|
-
const id = (0,
|
|
36101
|
+
const id = (0, import_node_crypto19.randomUUID)();
|
|
35514
36102
|
const token6 = tokenFor(id, idempotencyKey4);
|
|
35515
36103
|
const expiresAt = new Date(Date.now() + AUTHORIZATION_TTL_MS).toISOString();
|
|
35516
36104
|
const inserted = await getDb().execute({
|
|
@@ -35578,7 +36166,7 @@ async function startScheduledRun(args) {
|
|
|
35578
36166
|
if (!authorization || !["starting", "started"].includes(authorization.status)) {
|
|
35579
36167
|
throw new UnifiedBillingError("authorization_closed", "billing authorization is no longer startable", 409);
|
|
35580
36168
|
}
|
|
35581
|
-
const eventId = existing?.id ?? (0,
|
|
36169
|
+
const eventId = existing?.id ?? (0, import_node_crypto19.randomUUID)();
|
|
35582
36170
|
if (!existing) {
|
|
35583
36171
|
await getDb().execute({
|
|
35584
36172
|
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', ?, ?, ?)",
|
|
@@ -35717,7 +36305,7 @@ async function settleScheduledRun(args) {
|
|
|
35717
36305
|
...modelCostUnreported ? { modelCostUnreported: true } : {},
|
|
35718
36306
|
...pendingReason ? { reason: pendingReason } : {}
|
|
35719
36307
|
});
|
|
35720
|
-
const eventId = existing?.id ?? (0,
|
|
36308
|
+
const eventId = existing?.id ?? (0, import_node_crypto19.randomUUID)();
|
|
35721
36309
|
const status = pendingReason ? "cost_pending" : "settling";
|
|
35722
36310
|
const eventValues = [
|
|
35723
36311
|
modelMc,
|
|
@@ -35842,11 +36430,11 @@ async function voidScheduledRunAuthorization(args) {
|
|
|
35842
36430
|
}
|
|
35843
36431
|
return { ok: true, status: authorization.status };
|
|
35844
36432
|
}
|
|
35845
|
-
var
|
|
36433
|
+
var import_node_crypto19, SCHEDULED_RUN_BILLING_CLASS, SCHEDULED_RUN_SOURCE_SURFACE, AUTHORIZATION_TTL_MS, UnifiedBillingError;
|
|
35846
36434
|
var init_unified_billing = __esm({
|
|
35847
36435
|
"src/api/unified-billing.ts"() {
|
|
35848
36436
|
"use strict";
|
|
35849
|
-
|
|
36437
|
+
import_node_crypto19 = require("crypto");
|
|
35850
36438
|
init_db();
|
|
35851
36439
|
init_rates();
|
|
35852
36440
|
init_scheduling_access();
|
|
@@ -35878,14 +36466,14 @@ function getSessionSecret() {
|
|
|
35878
36466
|
function safeEqualHex(a, b) {
|
|
35879
36467
|
if (a.length !== b.length) return false;
|
|
35880
36468
|
try {
|
|
35881
|
-
return (0,
|
|
36469
|
+
return (0, import_node_crypto20.timingSafeEqual)(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
|
|
35882
36470
|
} catch {
|
|
35883
36471
|
return false;
|
|
35884
36472
|
}
|
|
35885
36473
|
}
|
|
35886
36474
|
function signSession(userId) {
|
|
35887
36475
|
const payload = String(userId);
|
|
35888
|
-
const sig = (0,
|
|
36476
|
+
const sig = (0, import_node_crypto20.createHmac)("sha256", secret()).update(payload).digest("hex");
|
|
35889
36477
|
return `${payload}.${sig}`;
|
|
35890
36478
|
}
|
|
35891
36479
|
function verifySession(token6) {
|
|
@@ -35893,16 +36481,16 @@ function verifySession(token6) {
|
|
|
35893
36481
|
if (dot === -1) return null;
|
|
35894
36482
|
const payload = token6.slice(0, dot);
|
|
35895
36483
|
const sig = token6.slice(dot + 1);
|
|
35896
|
-
const expected = (0,
|
|
36484
|
+
const expected = (0, import_node_crypto20.createHmac)("sha256", secret()).update(payload).digest("hex");
|
|
35897
36485
|
if (!safeEqualHex(sig, expected)) return null;
|
|
35898
36486
|
const id = parseInt(payload);
|
|
35899
36487
|
return isNaN(id) ? null : id;
|
|
35900
36488
|
}
|
|
35901
|
-
var
|
|
36489
|
+
var import_node_crypto20, isProduction, secret;
|
|
35902
36490
|
var init_session = __esm({
|
|
35903
36491
|
"src/api/session.ts"() {
|
|
35904
36492
|
"use strict";
|
|
35905
|
-
|
|
36493
|
+
import_node_crypto20 = require("crypto");
|
|
35906
36494
|
isProduction = () => process.env.NODE_ENV === "production" || process.env.VERCEL === "1";
|
|
35907
36495
|
secret = () => getSessionSecret();
|
|
35908
36496
|
}
|
|
@@ -35920,11 +36508,11 @@ function isMemoryOperator(email) {
|
|
|
35920
36508
|
return ops.includes(email.trim().toLowerCase());
|
|
35921
36509
|
}
|
|
35922
36510
|
function encKey() {
|
|
35923
|
-
return (0,
|
|
36511
|
+
return (0, import_node_crypto21.scryptSync)(getSessionSecret(), "mcp-memory-key-v1", 32);
|
|
35924
36512
|
}
|
|
35925
36513
|
function encryptMemoryKey(secret2) {
|
|
35926
|
-
const iv = (0,
|
|
35927
|
-
const cipher = (0,
|
|
36514
|
+
const iv = (0, import_node_crypto21.randomBytes)(12);
|
|
36515
|
+
const cipher = (0, import_node_crypto21.createCipheriv)("aes-256-gcm", encKey(), iv);
|
|
35928
36516
|
const enc = Buffer.concat([cipher.update(secret2, "utf8"), cipher.final()]);
|
|
35929
36517
|
const tag = cipher.getAuthTag();
|
|
35930
36518
|
return `${iv.toString("base64")}:${tag.toString("base64")}:${enc.toString("base64")}`;
|
|
@@ -35932,7 +36520,7 @@ function encryptMemoryKey(secret2) {
|
|
|
35932
36520
|
function decryptMemoryKey(stored) {
|
|
35933
36521
|
try {
|
|
35934
36522
|
const [ivB, tagB, dataB] = stored.split(":");
|
|
35935
|
-
const decipher = (0,
|
|
36523
|
+
const decipher = (0, import_node_crypto21.createDecipheriv)("aes-256-gcm", encKey(), Buffer.from(ivB, "base64"));
|
|
35936
36524
|
decipher.setAuthTag(Buffer.from(tagB, "base64"));
|
|
35937
36525
|
return Buffer.concat([decipher.update(Buffer.from(dataB, "base64")), decipher.final()]).toString("utf8");
|
|
35938
36526
|
} catch {
|
|
@@ -36046,11 +36634,11 @@ async function syncScheduledActionCredentials(user) {
|
|
|
36046
36634
|
}, {});
|
|
36047
36635
|
return { ok: res.ok, error: res.error };
|
|
36048
36636
|
}
|
|
36049
|
-
var
|
|
36637
|
+
var import_node_crypto21, import_provision_defaults, import_set_schedule_entitlement, MEMORY_BASE_URL, ADMIN_KEY;
|
|
36050
36638
|
var init_memory = __esm({
|
|
36051
36639
|
"src/api/memory.ts"() {
|
|
36052
36640
|
"use strict";
|
|
36053
|
-
|
|
36641
|
+
import_node_crypto21 = require("crypto");
|
|
36054
36642
|
init_session();
|
|
36055
36643
|
init_db();
|
|
36056
36644
|
init_rates();
|
|
@@ -36100,7 +36688,7 @@ var init_connected_cost_telemetry = __esm({
|
|
|
36100
36688
|
|
|
36101
36689
|
// src/api/connected-usage-billing.ts
|
|
36102
36690
|
function hash(value) {
|
|
36103
|
-
return (0,
|
|
36691
|
+
return (0, import_node_crypto22.createHash)("sha256").update(value).digest("hex");
|
|
36104
36692
|
}
|
|
36105
36693
|
function eventKey(idempotencyKey4) {
|
|
36106
36694
|
return `connected-usage:${hash(idempotencyKey4)}`;
|
|
@@ -36372,7 +36960,7 @@ async function settleConnectedUsage(rawInput) {
|
|
|
36372
36960
|
sql: `INSERT OR IGNORE INTO billing_events
|
|
36373
36961
|
(id, user_id, idempotency_key, billing_class, source_surface, status, amount_mc, metadata)
|
|
36374
36962
|
VALUES (?, ?, ?, ?, ?, 'settling', ?, ?)`,
|
|
36375
|
-
args: [(0,
|
|
36963
|
+
args: [(0, import_node_crypto22.randomUUID)(), user.id, key, CONNECTED_USAGE_BILLING_CLASS, input.sourceSurface, charge2.amountMc, encodeMetadata(storedMetadata)]
|
|
36376
36964
|
});
|
|
36377
36965
|
let event2 = await readEvent(key);
|
|
36378
36966
|
if (!event2) throw new Error("connected usage receipt insert completed without a readable event");
|
|
@@ -36461,11 +37049,11 @@ async function listConnectedUsageHistory(userId, limit = 100) {
|
|
|
36461
37049
|
}
|
|
36462
37050
|
return history;
|
|
36463
37051
|
}
|
|
36464
|
-
var
|
|
37052
|
+
var import_node_crypto22, import_zod17, CONNECTED_USAGE_BILLING_CLASS, CONNECTED_USAGE_DEFAULT_SOURCE_SURFACE, ConnectedUsageSafeMetadataSchema, ConnectedUsageSettlementInputSchema, ConnectedUsagePreflightInputSchema, ConnectedUsageBillingError;
|
|
36465
37053
|
var init_connected_usage_billing = __esm({
|
|
36466
37054
|
"src/api/connected-usage-billing.ts"() {
|
|
36467
37055
|
"use strict";
|
|
36468
|
-
|
|
37056
|
+
import_node_crypto22 = require("crypto");
|
|
36469
37057
|
import_zod17 = require("zod");
|
|
36470
37058
|
init_connected_cost_telemetry();
|
|
36471
37059
|
init_db();
|
|
@@ -38114,7 +38702,27 @@ var init_server_schemas = __esm({
|
|
|
38114
38702
|
downloadImages: import_zod22.z.boolean().optional(),
|
|
38115
38703
|
preserveMedia: import_zod22.z.boolean().optional(),
|
|
38116
38704
|
delivery: import_zod22.z.enum(["auto", "artifact"]).optional(),
|
|
38117
|
-
formats: import_zod22.z.array(import_zod22.z.enum(["markdown", "html", "links", "json", "images", "branding", "issues"])).optional()
|
|
38705
|
+
formats: import_zod22.z.array(import_zod22.z.enum(["markdown", "html", "links", "json", "images", "branding", "issues"])).optional(),
|
|
38706
|
+
renderJavaScript: import_zod22.z.boolean().optional(),
|
|
38707
|
+
captureRenderedDom: import_zod22.z.boolean().optional(),
|
|
38708
|
+
semanticSimilarity: import_zod22.z.boolean().optional(),
|
|
38709
|
+
similarityThreshold: import_zod22.z.number().min(0).max(1).optional(),
|
|
38710
|
+
similarityMaxPairs: import_zod22.z.number().int().min(1).max(5e4).optional()
|
|
38711
|
+
}).superRefine((value, ctx) => {
|
|
38712
|
+
if (value.semanticSimilarity && (value.maxPages ?? 100) > 500) {
|
|
38713
|
+
ctx.addIssue({
|
|
38714
|
+
code: import_zod22.z.ZodIssueCode.custom,
|
|
38715
|
+
path: ["maxPages"],
|
|
38716
|
+
message: "semanticSimilarity supports at most 500 pages per analysis."
|
|
38717
|
+
});
|
|
38718
|
+
}
|
|
38719
|
+
if (value.semanticSimilarity && value.wayback) {
|
|
38720
|
+
ctx.addIssue({
|
|
38721
|
+
code: import_zod22.z.ZodIssueCode.custom,
|
|
38722
|
+
path: ["wayback"],
|
|
38723
|
+
message: "semanticSimilarity analyzes one live rendered corpus and cannot be combined with a Wayback timeline."
|
|
38724
|
+
});
|
|
38725
|
+
}
|
|
38118
38726
|
});
|
|
38119
38727
|
SiteExportReadBodySchema = import_zod22.z.object({
|
|
38120
38728
|
jobId: import_zod22.z.string().trim().min(1),
|
|
@@ -40414,7 +41022,7 @@ async function applyAdjustment(input) {
|
|
|
40414
41022
|
const credits = validateCredits(input.credits, input.confirmLarge === true);
|
|
40415
41023
|
const reason = validateReason(input.reason);
|
|
40416
41024
|
const actor = validateActor(input.actor);
|
|
40417
|
-
const reference = input.reference?.trim() || `adj_${(0,
|
|
41025
|
+
const reference = input.reference?.trim() || `adj_${(0, import_node_crypto23.randomUUID)()}`;
|
|
40418
41026
|
if (reference.length > 120) throw new AdminCreditError(400, "reference must be at most 120 characters");
|
|
40419
41027
|
const db = getDb();
|
|
40420
41028
|
const existing = await db.execute({
|
|
@@ -40559,11 +41167,11 @@ async function lookupAccount(target, limit = 20) {
|
|
|
40559
41167
|
}))
|
|
40560
41168
|
};
|
|
40561
41169
|
}
|
|
40562
|
-
var
|
|
41170
|
+
var import_node_crypto23, MIN_ADJUSTMENT_CREDITS, LARGE_ADJUSTMENT_CREDITS, MAX_ADJUSTMENT_CREDITS, MIN_REASON_LENGTH, MAX_REASON_LENGTH, MAX_ACTOR_LENGTH, AdminCreditError;
|
|
40563
41171
|
var init_admin_credits = __esm({
|
|
40564
41172
|
"src/api/admin-credits.ts"() {
|
|
40565
41173
|
"use strict";
|
|
40566
|
-
|
|
41174
|
+
import_node_crypto23 = require("crypto");
|
|
40567
41175
|
init_db();
|
|
40568
41176
|
init_rates();
|
|
40569
41177
|
MIN_ADJUSTMENT_CREDITS = 1;
|
|
@@ -42528,7 +43136,7 @@ async function packageMapsMedia(args) {
|
|
|
42528
43136
|
files.push({ path: "summary.json", content: Buffer.from(JSON.stringify(summary, null, 2)) });
|
|
42529
43137
|
files.push({ path: "images.jsonl", content: Buffer.from(cleanImages.map((image) => JSON.stringify(image)).join("\n") + "\n") });
|
|
42530
43138
|
const archive = await zipBuffer(files);
|
|
42531
|
-
const id = (0,
|
|
43139
|
+
const id = (0, import_node_crypto24.randomBytes)(6).toString("hex");
|
|
42532
43140
|
const pointer = await createPrivateArtifact({
|
|
42533
43141
|
policy: policy3(),
|
|
42534
43142
|
ownerId: args.ownerId,
|
|
@@ -42541,13 +43149,13 @@ async function packageMapsMedia(args) {
|
|
|
42541
43149
|
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);
|
|
42542
43150
|
return { media: args.media, artifact: { ...pointer, localPath } };
|
|
42543
43151
|
}
|
|
42544
|
-
var import_node_os9, import_node_path13,
|
|
43152
|
+
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;
|
|
42545
43153
|
var init_maps_media_artifacts = __esm({
|
|
42546
43154
|
"src/api/maps-media-artifacts.ts"() {
|
|
42547
43155
|
"use strict";
|
|
42548
43156
|
import_node_os9 = require("os");
|
|
42549
43157
|
import_node_path13 = require("path");
|
|
42550
|
-
|
|
43158
|
+
import_node_crypto24 = require("crypto");
|
|
42551
43159
|
import_yazl2 = require("yazl");
|
|
42552
43160
|
import_p_limit5 = __toESM(require("p-limit"), 1);
|
|
42553
43161
|
init_private_artifacts();
|
|
@@ -43171,7 +43779,7 @@ function retryDelaySeconds(attempts) {
|
|
|
43171
43779
|
}
|
|
43172
43780
|
async function dispatchPendingDirectoryWorkflows(limit = 25) {
|
|
43173
43781
|
const rows = await claimDirectoryWorkflowOutbox({
|
|
43174
|
-
workerId: `directory-dispatch-${process.pid}-${(0,
|
|
43782
|
+
workerId: `directory-dispatch-${process.pid}-${(0, import_node_crypto25.randomUUID)().slice(0, 8)}`,
|
|
43175
43783
|
limit
|
|
43176
43784
|
});
|
|
43177
43785
|
const result = { claimed: rows.length, dispatched: 0, failed: 0 };
|
|
@@ -43193,11 +43801,11 @@ async function dispatchPendingDirectoryWorkflows(limit = 25) {
|
|
|
43193
43801
|
}
|
|
43194
43802
|
return result;
|
|
43195
43803
|
}
|
|
43196
|
-
var
|
|
43804
|
+
var import_node_crypto25;
|
|
43197
43805
|
var init_directory_workflow_dispatch = __esm({
|
|
43198
43806
|
"src/api/directory-workflow-dispatch.ts"() {
|
|
43199
43807
|
"use strict";
|
|
43200
|
-
|
|
43808
|
+
import_node_crypto25 = require("crypto");
|
|
43201
43809
|
init_client();
|
|
43202
43810
|
init_directory_workflow_repository();
|
|
43203
43811
|
}
|
|
@@ -43209,7 +43817,7 @@ function safeOptions(options) {
|
|
|
43209
43817
|
return safe2;
|
|
43210
43818
|
}
|
|
43211
43819
|
function requestFingerprint(options) {
|
|
43212
|
-
return (0,
|
|
43820
|
+
return (0, import_node_crypto26.createHash)("sha256").update(JSON.stringify(safeOptions(options))).digest("hex");
|
|
43213
43821
|
}
|
|
43214
43822
|
function idempotencyKey(raw) {
|
|
43215
43823
|
if (raw !== void 0) {
|
|
@@ -43218,14 +43826,14 @@ function idempotencyKey(raw) {
|
|
|
43218
43826
|
if (trimmed.length > 500) return { ok: false, message: "Idempotency-Key must be 500 characters or fewer." };
|
|
43219
43827
|
return { ok: true, key: trimmed };
|
|
43220
43828
|
}
|
|
43221
|
-
return { ok: true, key: `directory-${(0,
|
|
43829
|
+
return { ok: true, key: `directory-${(0, import_node_crypto26.randomUUID)()}` };
|
|
43222
43830
|
}
|
|
43223
43831
|
function debitKeyFor(userId, responseKey) {
|
|
43224
|
-
const digest2 = (0,
|
|
43832
|
+
const digest2 = (0, import_node_crypto26.createHash)("sha256").update(String(userId)).update("\0").update(responseKey).digest("hex");
|
|
43225
43833
|
return `directory-workflow:${userId}:${digest2}`;
|
|
43226
43834
|
}
|
|
43227
43835
|
function jobId() {
|
|
43228
|
-
return `dir_${(0,
|
|
43836
|
+
return `dir_${(0, import_node_crypto26.randomUUID)().replace(/-/g, "")}`;
|
|
43229
43837
|
}
|
|
43230
43838
|
function publicStatus(job, result) {
|
|
43231
43839
|
if (job.status === "failed") return "failed";
|
|
@@ -43334,7 +43942,7 @@ async function runSynchronously(c, user, options, plan, responseKey) {
|
|
|
43334
43942
|
const csv = renderDirectoryWorkflowCsv(result);
|
|
43335
43943
|
const artifact = await createDirectoryCsvArtifact({
|
|
43336
43944
|
ownerId: String(user.id),
|
|
43337
|
-
jobId: (0,
|
|
43945
|
+
jobId: (0, import_node_crypto26.createHash)("sha256").update(debitKey2).digest("hex").slice(0, 32),
|
|
43338
43946
|
createdAt: result.extractedAt,
|
|
43339
43947
|
filename: `${options.state}-${options.query}-directory.csv`,
|
|
43340
43948
|
csv,
|
|
@@ -43390,11 +43998,11 @@ async function runSynchronously(c, user, options, plan, responseKey) {
|
|
|
43390
43998
|
await releaseConcurrencyGate(gate.lockId);
|
|
43391
43999
|
}
|
|
43392
44000
|
}
|
|
43393
|
-
var
|
|
44001
|
+
var import_node_crypto26, import_hono16, directoryApp;
|
|
43394
44002
|
var init_directory_routes = __esm({
|
|
43395
44003
|
"src/api/directory-routes.ts"() {
|
|
43396
44004
|
"use strict";
|
|
43397
|
-
|
|
44005
|
+
import_node_crypto26 = require("crypto");
|
|
43398
44006
|
import_hono16 = require("hono");
|
|
43399
44007
|
init_api_auth();
|
|
43400
44008
|
init_db();
|
|
@@ -43612,10 +44220,10 @@ function bounded(value, field, min, max) {
|
|
|
43612
44220
|
return normalized;
|
|
43613
44221
|
}
|
|
43614
44222
|
function newLeadListUploadId() {
|
|
43615
|
-
return `upl_${(0,
|
|
44223
|
+
return `upl_${(0, import_node_crypto27.randomUUID)().replace(/-/g, "")}`;
|
|
43616
44224
|
}
|
|
43617
44225
|
function newImportedLeadListId() {
|
|
43618
|
-
return `lst_${(0,
|
|
44226
|
+
return `lst_${(0, import_node_crypto27.randomUUID)().replace(/-/g, "")}`;
|
|
43619
44227
|
}
|
|
43620
44228
|
async function ensureLeadListImportRepositorySchema() {
|
|
43621
44229
|
const db = getDb();
|
|
@@ -43815,11 +44423,11 @@ async function deleteExpiredLeadListInputRecords(now = /* @__PURE__ */ new Date(
|
|
|
43815
44423
|
], "write");
|
|
43816
44424
|
return { uploads: Number(uploads.rowsAffected ?? 0), lists: Number(lists.rowsAffected ?? 0) };
|
|
43817
44425
|
}
|
|
43818
|
-
var
|
|
44426
|
+
var import_node_crypto27, schemaDb5, schemaPromise5;
|
|
43819
44427
|
var init_lead_list_import_repository = __esm({
|
|
43820
44428
|
"src/api/lead-list-import-repository.ts"() {
|
|
43821
44429
|
"use strict";
|
|
43822
|
-
|
|
44430
|
+
import_node_crypto27 = require("crypto");
|
|
43823
44431
|
init_db();
|
|
43824
44432
|
schemaDb5 = null;
|
|
43825
44433
|
schemaPromise5 = null;
|
|
@@ -43861,7 +44469,7 @@ function safeFilenameHint(value) {
|
|
|
43861
44469
|
return cleaned || null;
|
|
43862
44470
|
}
|
|
43863
44471
|
function requestFingerprint2(filenameHint) {
|
|
43864
|
-
return (0,
|
|
44472
|
+
return (0, import_node_crypto28.createHash)("sha256").update(JSON.stringify({ filenameHint })).digest("hex");
|
|
43865
44473
|
}
|
|
43866
44474
|
function publicBaseUrl() {
|
|
43867
44475
|
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";
|
|
@@ -44017,7 +44625,7 @@ async function inspectLeadListUpload(uploadId, ownerId2) {
|
|
|
44017
44625
|
maxBytes: LEAD_LIST_UPLOAD_MAX_BYTES
|
|
44018
44626
|
});
|
|
44019
44627
|
if (!buffer) return null;
|
|
44020
|
-
const sha2565 = (0,
|
|
44628
|
+
const sha2565 = (0, import_node_crypto28.createHash)("sha256").update(buffer).digest("hex");
|
|
44021
44629
|
const completed = await completeLeadListUpload({
|
|
44022
44630
|
id: record.id,
|
|
44023
44631
|
ownerId: record.ownerId,
|
|
@@ -44141,11 +44749,11 @@ async function cleanupExpiredLeadListInputs(args = {}) {
|
|
|
44141
44749
|
const records = await deleteExpiredLeadListInputRecords(now);
|
|
44142
44750
|
return { deletedBlobs, deletedUploadRecords: records.uploads, deletedListRecords: records.lists };
|
|
44143
44751
|
}
|
|
44144
|
-
var
|
|
44752
|
+
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;
|
|
44145
44753
|
var init_lead_list_input_artifacts = __esm({
|
|
44146
44754
|
"src/api/lead-list-input-artifacts.ts"() {
|
|
44147
44755
|
"use strict";
|
|
44148
|
-
|
|
44756
|
+
import_node_crypto28 = require("crypto");
|
|
44149
44757
|
import_promises11 = require("fs/promises");
|
|
44150
44758
|
import_node_os10 = require("os");
|
|
44151
44759
|
import_node_path14 = require("path");
|
|
@@ -44528,7 +45136,7 @@ function canonicalize(value) {
|
|
|
44528
45136
|
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${canonicalize(object[key])}`).join(",")}}`;
|
|
44529
45137
|
}
|
|
44530
45138
|
function fingerprint(value) {
|
|
44531
|
-
return (0,
|
|
45139
|
+
return (0, import_node_crypto29.createHash)("sha256").update(canonicalize(value)).digest("hex");
|
|
44532
45140
|
}
|
|
44533
45141
|
async function safeJson(c) {
|
|
44534
45142
|
try {
|
|
@@ -44605,11 +45213,11 @@ function textDelimiter(raw, text2, observedMime) {
|
|
|
44605
45213
|
if (observedMime === "text/tab-separated-values") return " ";
|
|
44606
45214
|
return detectLeadListTextDelimiter(text2);
|
|
44607
45215
|
}
|
|
44608
|
-
var
|
|
45216
|
+
var import_node_crypto29, import_hono17, leadListInputApp;
|
|
44609
45217
|
var init_lead_list_input_routes = __esm({
|
|
44610
45218
|
"src/api/lead-list-input-routes.ts"() {
|
|
44611
45219
|
"use strict";
|
|
44612
|
-
|
|
45220
|
+
import_node_crypto29 = require("crypto");
|
|
44613
45221
|
import_hono17 = require("hono");
|
|
44614
45222
|
init_api_auth();
|
|
44615
45223
|
init_lead_list_input_artifacts();
|
|
@@ -44801,7 +45409,7 @@ function retryDelaySeconds2(attempts) {
|
|
|
44801
45409
|
return Math.min(3600, Math.max(15, 15 * 2 ** Math.min(8, Math.max(0, attempts - 1))));
|
|
44802
45410
|
}
|
|
44803
45411
|
async function dispatchPendingLeadListEnrichments(limit = 25) {
|
|
44804
|
-
const rows = await claimLeadListEnrichmentOutbox({ workerId: `lead-list-dispatch-${process.pid}-${(0,
|
|
45412
|
+
const rows = await claimLeadListEnrichmentOutbox({ workerId: `lead-list-dispatch-${process.pid}-${(0, import_node_crypto30.randomUUID)().slice(0, 8)}`, limit });
|
|
44805
45413
|
const result = { claimed: rows.length, dispatched: 0, failed: 0 };
|
|
44806
45414
|
for (const row of rows) {
|
|
44807
45415
|
if (!row.claimToken) continue;
|
|
@@ -44820,11 +45428,11 @@ async function dispatchPendingLeadListEnrichments(limit = 25) {
|
|
|
44820
45428
|
}
|
|
44821
45429
|
return result;
|
|
44822
45430
|
}
|
|
44823
|
-
var
|
|
45431
|
+
var import_node_crypto30;
|
|
44824
45432
|
var init_lead_list_enrichment_dispatch = __esm({
|
|
44825
45433
|
"src/api/lead-list-enrichment-dispatch.ts"() {
|
|
44826
45434
|
"use strict";
|
|
44827
|
-
|
|
45435
|
+
import_node_crypto30 = require("crypto");
|
|
44828
45436
|
init_client();
|
|
44829
45437
|
init_lead_list_enrichment_repository();
|
|
44830
45438
|
}
|
|
@@ -44840,15 +45448,15 @@ function idempotencyKey2(raw) {
|
|
|
44840
45448
|
return { ok: true, value };
|
|
44841
45449
|
}
|
|
44842
45450
|
function newJobId() {
|
|
44843
|
-
return `lle_${(0,
|
|
45451
|
+
return `lle_${(0, import_node_crypto31.randomUUID)().replace(/-/g, "")}`;
|
|
44844
45452
|
}
|
|
44845
45453
|
function debitKeyFor2(userId, key) {
|
|
44846
|
-
const digest2 = (0,
|
|
45454
|
+
const digest2 = (0, import_node_crypto31.createHash)("sha256").update(String(userId)).update("\0").update(key).digest("hex");
|
|
44847
45455
|
return `lead-list-enrichment:${userId}:${digest2}`;
|
|
44848
45456
|
}
|
|
44849
45457
|
function inlineSourceDigest(headers, rows) {
|
|
44850
45458
|
const values = rows.map((row) => headers.map((header) => row[header] ?? null));
|
|
44851
|
-
return (0,
|
|
45459
|
+
return (0, import_node_crypto31.createHash)("sha256").update(stableCanonicalJson({ headers, values })).digest("hex");
|
|
44852
45460
|
}
|
|
44853
45461
|
function issueMessage(error) {
|
|
44854
45462
|
const issue = error.issues[0];
|
|
@@ -45046,11 +45654,11 @@ async function resolveInput(ownerId2, parsed) {
|
|
|
45046
45654
|
sourceDigest: sourceDigest ?? inlineSourceDigest(normalized.headers, rows)
|
|
45047
45655
|
};
|
|
45048
45656
|
}
|
|
45049
|
-
var
|
|
45657
|
+
var import_node_crypto31, import_hono18, import_zod31, SourceSchema, StartSchema, TERMINAL, leadListEnrichmentApp;
|
|
45050
45658
|
var init_lead_list_enrichment_routes = __esm({
|
|
45051
45659
|
"src/api/lead-list-enrichment-routes.ts"() {
|
|
45052
45660
|
"use strict";
|
|
45053
|
-
|
|
45661
|
+
import_node_crypto31 = require("crypto");
|
|
45054
45662
|
import_hono18 = require("hono");
|
|
45055
45663
|
import_zod31 = require("zod");
|
|
45056
45664
|
init_api_auth();
|
|
@@ -48243,7 +48851,7 @@ async function readManifestFromSummary(summary) {
|
|
|
48243
48851
|
function webhookSignature(body, timestamp2) {
|
|
48244
48852
|
const secret2 = process.env.MCP_SCRAPER_WEBHOOK_SECRET?.trim();
|
|
48245
48853
|
if (!secret2) return null;
|
|
48246
|
-
return (0,
|
|
48854
|
+
return (0, import_node_crypto32.createHmac)("sha256", secret2).update(`${timestamp2}.${body}`).digest("hex");
|
|
48247
48855
|
}
|
|
48248
48856
|
async function deliverWorkflowWebhook(input) {
|
|
48249
48857
|
if (!input.webhookUrl) return;
|
|
@@ -48450,11 +49058,11 @@ async function dispatchDueWorkflowSchedules(apiUrl, limit = 3) {
|
|
|
48450
49058
|
}
|
|
48451
49059
|
return { dispatched: results.length, results };
|
|
48452
49060
|
}
|
|
48453
|
-
var
|
|
49061
|
+
var import_node_crypto32, import_promises14, import_hono21, import_zod41, workflowApp, WorkflowInputSchema, WorkflowIdSchema, CadenceSchema, ScheduleStatusSchema, RunBodySchema, ScheduleCreateSchema, SchedulePatchSchema, TERMINAL_RUN_STATUSES;
|
|
48454
49062
|
var init_workflow_routes = __esm({
|
|
48455
49063
|
"src/api/workflow-routes.ts"() {
|
|
48456
49064
|
"use strict";
|
|
48457
|
-
|
|
49065
|
+
import_node_crypto32 = require("crypto");
|
|
48458
49066
|
import_promises14 = require("fs/promises");
|
|
48459
49067
|
import_hono21 = require("hono");
|
|
48460
49068
|
import_zod41 = require("zod");
|
|
@@ -48735,7 +49343,7 @@ var init_workflow_routes = __esm({
|
|
|
48735
49343
|
// src/serp-intelligence/page-snapshot-extractor.ts
|
|
48736
49344
|
function sha2562(value) {
|
|
48737
49345
|
if (!value) return null;
|
|
48738
|
-
return (0,
|
|
49346
|
+
return (0, import_node_crypto33.createHash)("sha256").update(value).digest("hex");
|
|
48739
49347
|
}
|
|
48740
49348
|
function countWords(markdown) {
|
|
48741
49349
|
const matches = markdown.trim().match(/\b[\p{L}\p{N}][\p{L}\p{N}'-]*\b/gu);
|
|
@@ -49035,11 +49643,11 @@ async function capturePageSnapshots(targets, options = {}) {
|
|
|
49035
49643
|
}
|
|
49036
49644
|
};
|
|
49037
49645
|
}
|
|
49038
|
-
var
|
|
49646
|
+
var import_node_crypto33, import_p_limit6, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_CONTENT_CHARS;
|
|
49039
49647
|
var init_page_snapshot_extractor = __esm({
|
|
49040
49648
|
"src/serp-intelligence/page-snapshot-extractor.ts"() {
|
|
49041
49649
|
"use strict";
|
|
49042
|
-
|
|
49650
|
+
import_node_crypto33 = require("crypto");
|
|
49043
49651
|
import_p_limit6 = __toESM(require("p-limit"), 1);
|
|
49044
49652
|
init_kpo_extractor();
|
|
49045
49653
|
init_url_utils();
|
|
@@ -49535,21 +50143,21 @@ async function logRequestEventBestEffort(input) {
|
|
|
49535
50143
|
}
|
|
49536
50144
|
}
|
|
49537
50145
|
function captureBillingKeys(userId, suppliedKey, body) {
|
|
49538
|
-
const responseKey = suppliedKey?.trim() || (0,
|
|
49539
|
-
const requestFingerprint3 = (0,
|
|
49540
|
-
const keyDigest = (0,
|
|
50146
|
+
const responseKey = suppliedKey?.trim() || (0, import_node_crypto34.randomUUID)();
|
|
50147
|
+
const requestFingerprint3 = (0, import_node_crypto34.createHash)("sha256").update(JSON.stringify(body)).digest("hex");
|
|
50148
|
+
const keyDigest = (0, import_node_crypto34.createHash)("sha256").update(String(userId)).update("\0").update(responseKey).digest("hex");
|
|
49541
50149
|
return {
|
|
49542
50150
|
responseKey,
|
|
49543
50151
|
debitKey: `serp-capture:${userId}:${keyDigest}`,
|
|
49544
50152
|
debitDescription: `${body.query} [request:${requestFingerprint3}]`
|
|
49545
50153
|
};
|
|
49546
50154
|
}
|
|
49547
|
-
var import_hono22,
|
|
50155
|
+
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;
|
|
49548
50156
|
var init_serp_intelligence_routes = __esm({
|
|
49549
50157
|
"src/api/serp-intelligence-routes.ts"() {
|
|
49550
50158
|
"use strict";
|
|
49551
50159
|
import_hono22 = require("hono");
|
|
49552
|
-
|
|
50160
|
+
import_node_crypto34 = require("crypto");
|
|
49553
50161
|
init_browser_service_env();
|
|
49554
50162
|
init_page_snapshot_extractor();
|
|
49555
50163
|
init_serp_capture_service();
|
|
@@ -49786,7 +50394,7 @@ var PACKAGE_VERSION;
|
|
|
49786
50394
|
var init_version = __esm({
|
|
49787
50395
|
"src/version.ts"() {
|
|
49788
50396
|
"use strict";
|
|
49789
|
-
PACKAGE_VERSION = "0.
|
|
50397
|
+
PACKAGE_VERSION = "0.65.0";
|
|
49790
50398
|
}
|
|
49791
50399
|
});
|
|
49792
50400
|
|
|
@@ -49817,6 +50425,8 @@ seam is noted so you can chain them.
|
|
|
49817
50425
|
- Whole site -> **extract_site** (takes a url). It durably retains complete per-page JSON, acquired HTML,
|
|
49818
50426
|
and Markdown. Poll **check_site_export**, then call **site_export_read** for the manifest or a page view;
|
|
49819
50427
|
call **site_export_image** for downloaded image IDs.
|
|
50428
|
+
- JavaScript-rendered page overlap/cannibalization -> **analyze_site_similarity**. It returns dedicated
|
|
50429
|
+
raw-cosine page pairs, corpus percentiles, threshold clusters, and rendered-page artifacts.
|
|
49820
50430
|
- Wayback replay URLs work with the same tools: \`extract_url\` removes playback chrome and can return
|
|
49821
50431
|
a featured image; \`extract_site\` batches nearby archived HTML captures for the replayed site.
|
|
49822
50432
|
- For multiple archive months, pass \`extract_site.wayback\` with explicit \`months\` or a \`from\`/\`to\`
|
|
@@ -50230,6 +50840,7 @@ var init_output_schema_registry = __esm({
|
|
|
50230
50840
|
ESSENTIAL_OUTPUT_SCHEMA_TOOLS = /* @__PURE__ */ new Set([
|
|
50231
50841
|
"extract_url",
|
|
50232
50842
|
"extract_site",
|
|
50843
|
+
"analyze_site_similarity",
|
|
50233
50844
|
"audit_site",
|
|
50234
50845
|
"check_site_export",
|
|
50235
50846
|
"site_export_read",
|
|
@@ -51627,7 +52238,7 @@ var init_contracts = __esm({
|
|
|
51627
52238
|
});
|
|
51628
52239
|
|
|
51629
52240
|
// src/mcp/mcp-tool-schemas.ts
|
|
51630
|
-
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;
|
|
52241
|
+
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;
|
|
51631
52242
|
var init_mcp_tool_schemas = __esm({
|
|
51632
52243
|
"src/mcp/mcp-tool-schemas.ts"() {
|
|
51633
52244
|
"use strict";
|
|
@@ -51737,6 +52348,13 @@ var init_mcp_tool_schemas = __esm({
|
|
|
51737
52348
|
preserveMedia: import_zod45.z.boolean().default(false).describe("Include supported images in the export bundle. This is the preferred replacement for downloadImages."),
|
|
51738
52349
|
downloadImages: import_zod45.z.boolean().optional().describe("Deprecated alias for preserveMedia. Omit when using preserveMedia; when omitted, image preservation defaults to false.")
|
|
51739
52350
|
};
|
|
52351
|
+
AnalyzeSiteSimilarityInputSchema = {
|
|
52352
|
+
url: WebsiteUrlOrDomainSchema.describe("Public live site to render and compare. Bare domains default to https://."),
|
|
52353
|
+
maxPages: import_zod45.z.number().int().min(2).max(500).default(100).describe("Maximum rendered pages to compare; default 100, maximum 500."),
|
|
52354
|
+
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."),
|
|
52355
|
+
similarityMaxPairs: import_zod45.z.number().int().min(1).max(5e4).default(1e4).describe("Maximum scored pairs retained, highest first; default 10,000."),
|
|
52356
|
+
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.")
|
|
52357
|
+
};
|
|
51740
52358
|
AuditSiteInputSchema = {
|
|
51741
52359
|
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."),
|
|
51742
52360
|
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."),
|
|
@@ -51749,17 +52367,17 @@ var init_mcp_tool_schemas = __esm({
|
|
|
51749
52367
|
downloadImages: import_zod45.z.boolean().optional().describe("Deprecated alias for preserveMedia. Omit when using preserveMedia; when omitted, image preservation defaults to false.")
|
|
51750
52368
|
};
|
|
51751
52369
|
CheckSiteExportInputSchema = {
|
|
51752
|
-
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
|
|
52370
|
+
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.")
|
|
51753
52371
|
};
|
|
51754
52372
|
SiteExportReadInputSchema = {
|
|
51755
|
-
jobId: import_zod45.z.string().min(1).describe("Site export job ID returned by extract_site or audit_site."),
|
|
52373
|
+
jobId: import_zod45.z.string().min(1).describe("Site export job ID returned by extract_site, analyze_site_similarity, or audit_site."),
|
|
51756
52374
|
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."),
|
|
51757
52375
|
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."),
|
|
51758
52376
|
offset: import_zod45.z.number().int().min(0).default(0).describe("UTF-8 byte offset. Continue from nextOffset until it is null."),
|
|
51759
52377
|
maxBytes: import_zod45.z.number().int().min(1).max(1e6).default(64e3).describe("Maximum UTF-8 bytes returned in this window.")
|
|
51760
52378
|
};
|
|
51761
52379
|
SiteExportImageInputSchema = {
|
|
51762
|
-
jobId: import_zod45.z.string().min(1).describe("Site export job ID returned by extract_site or audit_site."),
|
|
52380
|
+
jobId: import_zod45.z.string().min(1).describe("Site export job ID returned by extract_site, analyze_site_similarity, or audit_site."),
|
|
51763
52381
|
imageId: import_zod45.z.string().regex(/^[a-f0-9]{64}$/).describe("Downloaded image ID returned by a site_export_read manifest.")
|
|
51764
52382
|
};
|
|
51765
52383
|
ArchiveReadInputSchema = {
|
|
@@ -52587,7 +53205,8 @@ var init_mcp_tool_schemas = __esm({
|
|
|
52587
53205
|
LeadSuggestedColumnOutputSchema = import_zod45.z.object({
|
|
52588
53206
|
header: NullableString,
|
|
52589
53207
|
confidence: import_zod45.z.number().min(0).max(1),
|
|
52590
|
-
reason: import_zod45.z.string()
|
|
53208
|
+
reason: import_zod45.z.string(),
|
|
53209
|
+
accepted: import_zod45.z.boolean()
|
|
52591
53210
|
}).strict();
|
|
52592
53211
|
LeadColumnMapSuggestionOutputSchema = import_zod45.z.object({
|
|
52593
53212
|
name: LeadSuggestedColumnOutputSchema,
|
|
@@ -54926,11 +55545,11 @@ function requireTasksCapability(capabilityValue) {
|
|
|
54926
55545
|
);
|
|
54927
55546
|
}
|
|
54928
55547
|
function taskKey(secret2) {
|
|
54929
|
-
return (0,
|
|
55548
|
+
return (0, import_node_crypto35.createHash)("sha256").update("mcp-scraper-task-handle\0", "utf8").update(secret2, "utf8").digest();
|
|
54930
55549
|
}
|
|
54931
55550
|
function encodeTaskHandle(payload, secret2) {
|
|
54932
|
-
const nonce = (0,
|
|
54933
|
-
const cipher = (0,
|
|
55551
|
+
const nonce = (0, import_node_crypto35.randomBytes)(12);
|
|
55552
|
+
const cipher = (0, import_node_crypto35.createCipheriv)("aes-256-gcm", taskKey(secret2), nonce);
|
|
54934
55553
|
const ciphertext = Buffer.concat([
|
|
54935
55554
|
cipher.update(JSON.stringify(payload), "utf8"),
|
|
54936
55555
|
cipher.final()
|
|
@@ -54947,7 +55566,7 @@ function decodeTaskHandle(taskId, secret2, ownerId2) {
|
|
|
54947
55566
|
const nonce = bytes.subarray(0, 12);
|
|
54948
55567
|
const tag = bytes.subarray(bytes.length - 16);
|
|
54949
55568
|
const ciphertext = bytes.subarray(12, bytes.length - 16);
|
|
54950
|
-
const decipher = (0,
|
|
55569
|
+
const decipher = (0, import_node_crypto35.createDecipheriv)("aes-256-gcm", taskKey(secret2), nonce);
|
|
54951
55570
|
decipher.setAuthTag(tag);
|
|
54952
55571
|
const parsed = JSON.parse(Buffer.concat([
|
|
54953
55572
|
decipher.update(ciphertext),
|
|
@@ -55175,12 +55794,12 @@ async function handleMcpTasksHttpRequest(request, executor, options) {
|
|
|
55175
55794
|
return taskHttpError(id, error instanceof import_server.ProtocolError ? error : new import_server.ProtocolError(-32603, error instanceof Error ? error.message : "Internal error"));
|
|
55176
55795
|
}
|
|
55177
55796
|
}
|
|
55178
|
-
var import_server,
|
|
55797
|
+
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;
|
|
55179
55798
|
var init_mcp_tasks_extension = __esm({
|
|
55180
55799
|
"src/mcp/mcp-tasks-extension.ts"() {
|
|
55181
55800
|
"use strict";
|
|
55182
55801
|
import_server = require("@modelcontextprotocol/server");
|
|
55183
|
-
|
|
55802
|
+
import_node_crypto35 = require("crypto");
|
|
55184
55803
|
import_zod46 = require("zod");
|
|
55185
55804
|
MCP_TASKS_EXTENSION_ID = "io.modelcontextprotocol/tasks";
|
|
55186
55805
|
TASK_HANDLE_VERSION = "mt1";
|
|
@@ -55478,7 +56097,7 @@ var init_analytics_mcp_tools = __esm({
|
|
|
55478
56097
|
|
|
55479
56098
|
// src/mcp/paa-mcp-server.ts
|
|
55480
56099
|
function hashOwnerId(callerKey) {
|
|
55481
|
-
return (0,
|
|
56100
|
+
return (0, import_node_crypto36.createHash)("sha256").update(callerKey).digest("hex").slice(0, 24);
|
|
55482
56101
|
}
|
|
55483
56102
|
function liveWebToolAnnotations(title) {
|
|
55484
56103
|
return {
|
|
@@ -55691,6 +56310,21 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
55691
56310
|
await formatExtractSite(await executor.extractSite(input), input, ctx),
|
|
55692
56311
|
requestContext
|
|
55693
56312
|
));
|
|
56313
|
+
server.registerTool("analyze_site_similarity", {
|
|
56314
|
+
title: "Rendered Site Content Similarity",
|
|
56315
|
+
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.",
|
|
56316
|
+
inputSchema: AnalyzeSiteSimilarityInputSchema,
|
|
56317
|
+
outputSchema: recordOutputSchema("analyze_site_similarity", ExtractSiteOutputSchema),
|
|
56318
|
+
annotations: { ...liveWebToolAnnotations("Rendered Site Content Similarity"), readOnlyHint: false }
|
|
56319
|
+
}, async (input, requestContext) => tasks.taskify(
|
|
56320
|
+
"site_export",
|
|
56321
|
+
await formatExtractSite(
|
|
56322
|
+
await executor.analyzeSiteSimilarity(input),
|
|
56323
|
+
{ ...input, toolLabel: "Rendered Site Content Similarity" },
|
|
56324
|
+
ctx
|
|
56325
|
+
),
|
|
56326
|
+
requestContext
|
|
56327
|
+
));
|
|
55694
56328
|
server.registerTool("audit_site", {
|
|
55695
56329
|
title: "Technical SEO Audit",
|
|
55696
56330
|
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.`,
|
|
@@ -55704,7 +56338,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
55704
56338
|
));
|
|
55705
56339
|
server.registerTool("check_site_export", {
|
|
55706
56340
|
title: "Check Site Export",
|
|
55707
|
-
description: "Poll a background extract_site or audit_site job. Reports
|
|
56341
|
+
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.",
|
|
55708
56342
|
inputSchema: CheckSiteExportInputSchema,
|
|
55709
56343
|
outputSchema: recordOutputSchema("check_site_export", CheckSiteExportOutputSchema),
|
|
55710
56344
|
annotations: { ...liveWebToolAnnotations("Check Site Export"), readOnlyHint: false }
|
|
@@ -56443,7 +57077,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
56443
57077
|
annotations: { title: "Set Scheduled Action Connections", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
56444
57078
|
}, async (input) => executor.setScheduledActionConnections(input));
|
|
56445
57079
|
}
|
|
56446
|
-
var import_server2, import_zod48, import_node_fs11, import_node_path17,
|
|
57080
|
+
var import_server2, import_zod48, import_node_fs11, import_node_path17, import_node_crypto36, ACTION_CONFIRMATION_SCHEMA;
|
|
56447
57081
|
var init_paa_mcp_server = __esm({
|
|
56448
57082
|
"src/mcp/paa-mcp-server.ts"() {
|
|
56449
57083
|
"use strict";
|
|
@@ -56451,7 +57085,7 @@ var init_paa_mcp_server = __esm({
|
|
|
56451
57085
|
import_zod48 = require("zod");
|
|
56452
57086
|
import_node_fs11 = require("fs");
|
|
56453
57087
|
import_node_path17 = require("path");
|
|
56454
|
-
|
|
57088
|
+
import_node_crypto36 = require("crypto");
|
|
56455
57089
|
init_version();
|
|
56456
57090
|
init_rates();
|
|
56457
57091
|
init_mcp_response_formatter();
|
|
@@ -56572,11 +57206,11 @@ function analyticsReportPath(input, report) {
|
|
|
56572
57206
|
const suffix2 = query.size ? `?${query.toString()}` : "";
|
|
56573
57207
|
return `/analytics/sites/${encodeURIComponent(input.siteId)}/${report}${suffix2}`;
|
|
56574
57208
|
}
|
|
56575
|
-
var
|
|
57209
|
+
var import_node_crypto37, HttpMcpToolExecutor;
|
|
56576
57210
|
var init_http_mcp_tool_executor = __esm({
|
|
56577
57211
|
"src/mcp/http-mcp-tool-executor.ts"() {
|
|
56578
57212
|
"use strict";
|
|
56579
|
-
|
|
57213
|
+
import_node_crypto37 = require("crypto");
|
|
56580
57214
|
init_harvest_timeout();
|
|
56581
57215
|
init_browser_service_env();
|
|
56582
57216
|
init_errors();
|
|
@@ -56645,13 +57279,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
56645
57279
|
});
|
|
56646
57280
|
}
|
|
56647
57281
|
async callDirectoryWorkflowStart(body, explicitIdempotencyKey) {
|
|
56648
|
-
const idempotencyKey4 = `mcp-directory-${(0,
|
|
57282
|
+
const idempotencyKey4 = `mcp-directory-${(0, import_node_crypto37.createHash)("sha256").update(explicitIdempotencyKey).digest("hex")}`;
|
|
56649
57283
|
return this.call("/directory/run", body, this.timeoutMs, "POST", {
|
|
56650
57284
|
"Idempotency-Key": idempotencyKey4
|
|
56651
57285
|
});
|
|
56652
57286
|
}
|
|
56653
57287
|
async callSiteExtractStart(toolName, body, explicitIdempotencyKey) {
|
|
56654
|
-
const idempotencyKey4 = `mcp-site-${(0,
|
|
57288
|
+
const idempotencyKey4 = `mcp-site-${(0, import_node_crypto37.createHash)("sha256").update(toolName).update("\0").update(explicitIdempotencyKey).digest("hex")}`;
|
|
56655
57289
|
return this.call("/extract-site", body, this.timeoutMs, "POST", {
|
|
56656
57290
|
"Idempotency-Key": idempotencyKey4
|
|
56657
57291
|
});
|
|
@@ -56739,6 +57373,19 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
56739
57373
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
56740
57374
|
return this.callSiteExtractStart("extract_site", { ...body, background: true }, idempotencyKey4);
|
|
56741
57375
|
}
|
|
57376
|
+
analyzeSiteSimilarity(input) {
|
|
57377
|
+
const { idempotencyKey: idempotencyKey4, similarityThreshold, similarityMaxPairs, ...body } = input;
|
|
57378
|
+
return this.callSiteExtractStart("analyze_site_similarity", {
|
|
57379
|
+
...body,
|
|
57380
|
+
background: true,
|
|
57381
|
+
formats: ["markdown", "links", "json"],
|
|
57382
|
+
renderJavaScript: true,
|
|
57383
|
+
captureRenderedDom: true,
|
|
57384
|
+
semanticSimilarity: true,
|
|
57385
|
+
similarityThreshold,
|
|
57386
|
+
similarityMaxPairs
|
|
57387
|
+
}, idempotencyKey4);
|
|
57388
|
+
}
|
|
56742
57389
|
auditSite(input) {
|
|
56743
57390
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
56744
57391
|
const requestBody = {
|
|
@@ -57073,7 +57720,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57073
57720
|
report: input.report,
|
|
57074
57721
|
format: input.format
|
|
57075
57722
|
}, this.timeoutMs, "POST", {
|
|
57076
|
-
"Idempotency-Key": `analytics-export-${(0,
|
|
57723
|
+
"Idempotency-Key": `analytics-export-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57077
57724
|
});
|
|
57078
57725
|
}
|
|
57079
57726
|
commonsSearchEntities(input) {
|
|
@@ -57112,7 +57759,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57112
57759
|
commonsSubmitEntity(input) {
|
|
57113
57760
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57114
57761
|
return this.call("/commons/entities/propose", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57115
|
-
"Idempotency-Key": `commons-${(0,
|
|
57762
|
+
"Idempotency-Key": `commons-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57116
57763
|
});
|
|
57117
57764
|
}
|
|
57118
57765
|
commonsGetEntityLedger(input) {
|
|
@@ -57127,7 +57774,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57127
57774
|
commonsUpdateEditorialArticle(input) {
|
|
57128
57775
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57129
57776
|
return this.call("/commons/publications/articles", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57130
|
-
"Idempotency-Key": `commons-article-${(0,
|
|
57777
|
+
"Idempotency-Key": `commons-article-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57131
57778
|
});
|
|
57132
57779
|
}
|
|
57133
57780
|
commonsSaveFilter(input) {
|
|
@@ -57148,13 +57795,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57148
57795
|
commonsClaimPublication(input) {
|
|
57149
57796
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57150
57797
|
return this.call("/commons/publications/claim", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57151
|
-
"Idempotency-Key": `commons-publication-claim-${(0,
|
|
57798
|
+
"Idempotency-Key": `commons-publication-claim-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57152
57799
|
});
|
|
57153
57800
|
}
|
|
57154
57801
|
commonsPublishEditorial(input) {
|
|
57155
57802
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57156
57803
|
return this.call("/commons/publications/publish", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57157
|
-
"Idempotency-Key": `commons-publication-publish-${(0,
|
|
57804
|
+
"Idempotency-Key": `commons-publication-publish-${(0, import_node_crypto37.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57158
57805
|
});
|
|
57159
57806
|
}
|
|
57160
57807
|
commonsGetPublication(input) {
|
|
@@ -57162,13 +57809,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57162
57809
|
return this.getJson(input.subdomain ? `/commons/publications/${encodeURIComponent(input.subdomain)}?${query}` : `/commons/publications/me?${query}`);
|
|
57163
57810
|
}
|
|
57164
57811
|
async captureSerpSnapshot(input) {
|
|
57165
|
-
const fingerprint2 = (0,
|
|
57812
|
+
const fingerprint2 = (0, import_node_crypto37.createHash)("sha256").update(JSON.stringify(input)).digest("hex");
|
|
57166
57813
|
const now = Date.now();
|
|
57167
57814
|
for (const [pendingFingerprint, pendingEntry] of this.pendingSerpCaptureBillingKeys) {
|
|
57168
57815
|
if (pendingEntry.expiresAt <= now) this.pendingSerpCaptureBillingKeys.delete(pendingFingerprint);
|
|
57169
57816
|
}
|
|
57170
57817
|
const pending = this.pendingSerpCaptureBillingKeys.get(fingerprint2);
|
|
57171
|
-
const idempotencyKey4 = pending && pending.expiresAt > now ? pending.key : (0,
|
|
57818
|
+
const idempotencyKey4 = pending && pending.expiresAt > now ? pending.key : (0, import_node_crypto37.randomUUID)();
|
|
57172
57819
|
this.pendingSerpCaptureBillingKeys.set(fingerprint2, {
|
|
57173
57820
|
key: idempotencyKey4,
|
|
57174
57821
|
expiresAt: now + 15 * 6e4
|
|
@@ -61645,7 +62292,7 @@ async function createImageSourceArtifact(args) {
|
|
|
61645
62292
|
if (args.content.length === 0 || args.content.length > IMAGE_SOURCE_MAX_BYTES) {
|
|
61646
62293
|
throw new Error("image_source_size_invalid");
|
|
61647
62294
|
}
|
|
61648
|
-
const id = (0,
|
|
62295
|
+
const id = (0, import_node_crypto38.randomUUID)().replaceAll("-", "");
|
|
61649
62296
|
return createPrivateArtifact({
|
|
61650
62297
|
policy: policy4(),
|
|
61651
62298
|
ownerId: args.ownerId,
|
|
@@ -61664,11 +62311,11 @@ async function readOwnedImageSourceArtifact(args) {
|
|
|
61664
62311
|
maxBytes: IMAGE_SOURCE_MAX_BYTES
|
|
61665
62312
|
});
|
|
61666
62313
|
}
|
|
61667
|
-
var
|
|
62314
|
+
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;
|
|
61668
62315
|
var init_image_source_artifacts = __esm({
|
|
61669
62316
|
"src/api/image-source-artifacts.ts"() {
|
|
61670
62317
|
"use strict";
|
|
61671
|
-
|
|
62318
|
+
import_node_crypto38 = require("crypto");
|
|
61672
62319
|
init_private_artifacts();
|
|
61673
62320
|
IMAGE_SOURCE_ARTIFACT_PREFIX = "image-sources/";
|
|
61674
62321
|
IMAGE_SOURCE_ARTIFACT_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -63282,7 +63929,7 @@ async function runBrowserAgentMigration() {
|
|
|
63282
63929
|
}
|
|
63283
63930
|
async function createExtensionRow(input) {
|
|
63284
63931
|
const db = getDb();
|
|
63285
|
-
const id = `bext_${(0,
|
|
63932
|
+
const id = `bext_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
63286
63933
|
await db.execute({
|
|
63287
63934
|
sql: `INSERT INTO browser_agent_extensions (id, user_id, name, backend_id, backend_name, source, source_url, size_bytes)
|
|
63288
63935
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
@@ -63317,7 +63964,7 @@ async function deleteExtensionRow(userId, name) {
|
|
|
63317
63964
|
}
|
|
63318
63965
|
async function createAuthConnectionRow(input) {
|
|
63319
63966
|
const db = getDb();
|
|
63320
|
-
const connectionId = `authc_${(0,
|
|
63967
|
+
const connectionId = `authc_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
63321
63968
|
await db.execute({
|
|
63322
63969
|
sql: `INSERT INTO browser_auth_connections (connection_id, domain, profile, account_email, note, status, browser_agent_session_id)
|
|
63323
63970
|
VALUES (?, ?, ?, ?, ?, 'NEEDS_AUTH', ?)`,
|
|
@@ -63402,7 +64049,7 @@ async function deleteProfileLabel(userId, profile) {
|
|
|
63402
64049
|
}
|
|
63403
64050
|
async function createSessionRow(input) {
|
|
63404
64051
|
const db = getDb();
|
|
63405
|
-
const id = `bas_${(0,
|
|
64052
|
+
const id = `bas_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
63406
64053
|
await db.execute({
|
|
63407
64054
|
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)
|
|
63408
64055
|
VALUES (?, ?, ?, ?, 'open', ?, ?, ?, datetime('now'))`,
|
|
@@ -63479,7 +64126,7 @@ async function recordAction(input) {
|
|
|
63479
64126
|
sql: `INSERT INTO browser_agent_actions (id, session_id, type, params_json, ok, error)
|
|
63480
64127
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
63481
64128
|
args: [
|
|
63482
|
-
`baa_${(0,
|
|
64129
|
+
`baa_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`,
|
|
63483
64130
|
input.sessionId,
|
|
63484
64131
|
input.type,
|
|
63485
64132
|
input.params == null ? null : JSON.stringify(input.params),
|
|
@@ -63519,11 +64166,11 @@ async function listReplayRows(sessionId) {
|
|
|
63519
64166
|
});
|
|
63520
64167
|
return res.rows;
|
|
63521
64168
|
}
|
|
63522
|
-
var
|
|
64169
|
+
var import_node_crypto39, _ready2, _migrationPromise2, ORPHANED_SESSION_STATUS;
|
|
63523
64170
|
var init_browser_agent_db = __esm({
|
|
63524
64171
|
"src/api/browser-agent-db.ts"() {
|
|
63525
64172
|
"use strict";
|
|
63526
|
-
|
|
64173
|
+
import_node_crypto39 = require("crypto");
|
|
63527
64174
|
init_db();
|
|
63528
64175
|
_ready2 = false;
|
|
63529
64176
|
_migrationPromise2 = null;
|
|
@@ -64670,8 +65317,8 @@ function kernelClient() {
|
|
|
64670
65317
|
return new import_sdk11.default({ apiKey });
|
|
64671
65318
|
}
|
|
64672
65319
|
function backendName(userId, name, resource) {
|
|
64673
|
-
const digest2 = (0,
|
|
64674
|
-
const nonce = (0,
|
|
65320
|
+
const digest2 = (0, import_node_crypto40.createHash)("sha256").update(`${userId}:${name}`).digest("hex").slice(0, 16);
|
|
65321
|
+
const nonce = (0, import_node_crypto40.randomUUID)().replace(/-/g, "").slice(0, 8);
|
|
64675
65322
|
return `mcp-serp-${resource}-${digest2}-${nonce}`;
|
|
64676
65323
|
}
|
|
64677
65324
|
function isNotFound2(error) {
|
|
@@ -64749,11 +65396,11 @@ async function deleteSerpIdentity(userId, name) {
|
|
|
64749
65396
|
throw error;
|
|
64750
65397
|
}
|
|
64751
65398
|
}
|
|
64752
|
-
var
|
|
65399
|
+
var import_node_crypto40, import_sdk11, MAX_SERP_IDENTITIES_PER_USER;
|
|
64753
65400
|
var init_serp_identity_service = __esm({
|
|
64754
65401
|
"src/api/serp-identity-service.ts"() {
|
|
64755
65402
|
"use strict";
|
|
64756
|
-
|
|
65403
|
+
import_node_crypto40 = require("crypto");
|
|
64757
65404
|
import_sdk11 = __toESM(require("@onkernel/sdk"), 1);
|
|
64758
65405
|
init_browser_service_env();
|
|
64759
65406
|
init_serp_identity_db();
|
|
@@ -65464,7 +66111,7 @@ function buildBrowserAgentRoutes() {
|
|
|
65464
66111
|
}
|
|
65465
66112
|
const existing = await getExtensionRow(user.id, name);
|
|
65466
66113
|
if (existing) return c.json({ error: `an extension named "${name}" already exists \u2014 delete it first or pick another name` }, 409);
|
|
65467
|
-
const backendName2 = `u${user.id}_${(0,
|
|
66114
|
+
const backendName2 = `u${user.id}_${(0, import_node_crypto41.randomUUID)().replace(/-/g, "")}`;
|
|
65468
66115
|
try {
|
|
65469
66116
|
const imported = await importExtensionFromStore(storeUrl, backendName2);
|
|
65470
66117
|
const row = await createExtensionRow({
|
|
@@ -65523,11 +66170,11 @@ function buildBrowserAgentRoutes() {
|
|
|
65523
66170
|
});
|
|
65524
66171
|
return app2;
|
|
65525
66172
|
}
|
|
65526
|
-
var
|
|
66173
|
+
var import_node_crypto41, import_hono24, auth, DEFAULT_BROWSER_SESSION_LOCK_TTL_SECONDS, EXTENSION_NAME_RE, SERP_IDENTITY_NAME_RE;
|
|
65527
66174
|
var init_browser_agent_routes = __esm({
|
|
65528
66175
|
"src/api/browser-agent-routes.ts"() {
|
|
65529
66176
|
"use strict";
|
|
65530
|
-
|
|
66177
|
+
import_node_crypto41 = require("crypto");
|
|
65531
66178
|
import_hono24 = require("hono");
|
|
65532
66179
|
init_api_auth();
|
|
65533
66180
|
init_errors();
|
|
@@ -66085,7 +66732,7 @@ async function getKeys() {
|
|
|
66085
66732
|
const privateKey = await (0, import_jose2.importPKCS8)(pem, "RS256", { extractable: true });
|
|
66086
66733
|
const full = await (0, import_jose2.exportJWK)(privateKey);
|
|
66087
66734
|
const publicJwk = { kty: full.kty, n: full.n, e: full.e };
|
|
66088
|
-
const kid = (0,
|
|
66735
|
+
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);
|
|
66089
66736
|
publicJwk.kid = kid;
|
|
66090
66737
|
publicJwk.alg = "RS256";
|
|
66091
66738
|
publicJwk.use = "sig";
|
|
@@ -66264,23 +66911,23 @@ async function validateAuthRequest(p) {
|
|
|
66264
66911
|
}
|
|
66265
66912
|
function pkceMatches(verifier, challenge) {
|
|
66266
66913
|
if (!verifier) return false;
|
|
66267
|
-
const computed = (0,
|
|
66914
|
+
const computed = (0, import_node_crypto42.createHash)("sha256").update(verifier).digest("base64url");
|
|
66268
66915
|
return computed === challenge;
|
|
66269
66916
|
}
|
|
66270
66917
|
async function mintAccessToken(identity, scope, plan, audience) {
|
|
66271
66918
|
const { privateKey, kid } = await getKeys();
|
|
66272
|
-
return new import_jose2.SignJWT({ scope, plan }).setProtectedHeader({ alg: "RS256", kid }).setIssuer(ISSUER).setSubject(identity).setAudience(audience).setIssuedAt().setJti((0,
|
|
66919
|
+
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);
|
|
66273
66920
|
}
|
|
66274
66921
|
function tokenErrorResponse(c, error, description, status) {
|
|
66275
66922
|
return c.json({ error, error_description: description }, status);
|
|
66276
66923
|
}
|
|
66277
|
-
var import_hono26, import_cookie,
|
|
66924
|
+
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;
|
|
66278
66925
|
var init_oauth_routes = __esm({
|
|
66279
66926
|
"src/api/oauth-routes.ts"() {
|
|
66280
66927
|
"use strict";
|
|
66281
66928
|
import_hono26 = require("hono");
|
|
66282
66929
|
import_cookie = require("hono/cookie");
|
|
66283
|
-
|
|
66930
|
+
import_node_crypto42 = require("crypto");
|
|
66284
66931
|
import_jose2 = require("jose");
|
|
66285
66932
|
init_session();
|
|
66286
66933
|
init_db();
|
|
@@ -66387,7 +67034,7 @@ var init_oauth_routes = __esm({
|
|
|
66387
67034
|
}
|
|
66388
67035
|
}
|
|
66389
67036
|
const clientName = typeof body.client_name === "string" ? body.client_name : null;
|
|
66390
|
-
const clientId = `client_${(0,
|
|
67037
|
+
const clientId = `client_${(0, import_node_crypto42.randomBytes)(16).toString("hex")}`;
|
|
66391
67038
|
await withOAuthDatabaseDeadline("register-client", registerClient(clientId, redirectUris, clientName));
|
|
66392
67039
|
console.log("[oauth-dcr] register OK client_id=%s redirect_uris=%s", clientId, JSON.stringify(redirectUris));
|
|
66393
67040
|
return c.json({
|
|
@@ -66440,7 +67087,7 @@ var init_oauth_routes = __esm({
|
|
|
66440
67087
|
if (action3 === "deny") return redirectWithError(p.redirect_uri, p.state, "access_denied");
|
|
66441
67088
|
if (action3 !== "approve") return c.text("unsupported action", 400);
|
|
66442
67089
|
const scope = negotiateScope(p.scope, user, p.resource);
|
|
66443
|
-
const code = `code_${(0,
|
|
67090
|
+
const code = `code_${(0, import_node_crypto42.randomBytes)(32).toString("base64url")}`;
|
|
66444
67091
|
const expiresAt = new Date(Date.now() + CODE_TTL_SECONDS * 1e3).toISOString();
|
|
66445
67092
|
await withOAuthDatabaseDeadline("put-authorization-code", putCode({
|
|
66446
67093
|
code,
|
|
@@ -66479,7 +67126,7 @@ var init_oauth_routes = __esm({
|
|
|
66479
67126
|
const plan = user ? resolvePlan(user) : "free";
|
|
66480
67127
|
const audience = record.resource ?? RESOURCE();
|
|
66481
67128
|
const accessToken = await mintAccessToken(record.identity, record.scope, plan, audience);
|
|
66482
|
-
const refreshToken = `rt_${(0,
|
|
67129
|
+
const refreshToken = `rt_${(0, import_node_crypto42.randomBytes)(40).toString("base64url")}`;
|
|
66483
67130
|
await withOAuthDatabaseDeadline("put-refresh-token", putRefresh({
|
|
66484
67131
|
refresh_token: refreshToken,
|
|
66485
67132
|
client_id: clientId,
|
|
@@ -66509,7 +67156,7 @@ var init_oauth_routes = __esm({
|
|
|
66509
67156
|
const plan = user ? resolvePlan(user) : "free";
|
|
66510
67157
|
const audience = record.resource ?? RESOURCE();
|
|
66511
67158
|
const accessToken = await mintAccessToken(record.identity, record.scope, plan, audience);
|
|
66512
|
-
const nextRefresh = `rt_${(0,
|
|
67159
|
+
const nextRefresh = `rt_${(0, import_node_crypto42.randomBytes)(40).toString("base64url")}`;
|
|
66513
67160
|
await withOAuthDatabaseDeadline("rotate-refresh-token", rotateRefresh(refreshToken, {
|
|
66514
67161
|
refresh_token: nextRefresh,
|
|
66515
67162
|
client_id: record.client_id,
|
|
@@ -67929,7 +68576,7 @@ function quoteUntrusted(value) {
|
|
|
67929
68576
|
return clean3.split("\n").map((line) => `> ${line}`).join("\n");
|
|
67930
68577
|
}
|
|
67931
68578
|
function shortHash(value, length = 24) {
|
|
67932
|
-
return (0,
|
|
68579
|
+
return (0, import_node_crypto43.createHash)("sha256").update(value).digest("hex").slice(0, length);
|
|
67933
68580
|
}
|
|
67934
68581
|
function safePathPart(value) {
|
|
67935
68582
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "contact";
|
|
@@ -68417,11 +69064,11 @@ async function captureSupportMessage(memoryKey, email, options) {
|
|
|
68417
69064
|
direction: options.direction
|
|
68418
69065
|
};
|
|
68419
69066
|
}
|
|
68420
|
-
var
|
|
69067
|
+
var import_node_crypto43, SUPPORT_TAGS, ISSUE_TAGS;
|
|
68421
69068
|
var init_resend_support_thread = __esm({
|
|
68422
69069
|
"src/api/resend-support-thread.ts"() {
|
|
68423
69070
|
"use strict";
|
|
68424
|
-
|
|
69071
|
+
import_node_crypto43 = require("crypto");
|
|
68425
69072
|
init_memory();
|
|
68426
69073
|
SUPPORT_TAGS = [
|
|
68427
69074
|
{
|
|
@@ -69006,7 +69653,7 @@ async function claimWorkshopRegistration(input) {
|
|
|
69006
69653
|
) < ?
|
|
69007
69654
|
`,
|
|
69008
69655
|
args: [
|
|
69009
|
-
(0,
|
|
69656
|
+
(0, import_node_crypto44.randomUUID)(),
|
|
69010
69657
|
input.eventSlug,
|
|
69011
69658
|
input.email,
|
|
69012
69659
|
input.firstName,
|
|
@@ -69023,7 +69670,7 @@ async function claimWorkshopRegistration(input) {
|
|
|
69023
69670
|
id, event_slug, email, first_name, last_name, status
|
|
69024
69671
|
) VALUES (?, ?, ?, ?, ?, 'waitlisted')
|
|
69025
69672
|
`,
|
|
69026
|
-
args: [(0,
|
|
69673
|
+
args: [(0, import_node_crypto44.randomUUID)(), input.eventSlug, input.email, input.firstName, input.lastName || null]
|
|
69027
69674
|
});
|
|
69028
69675
|
const waitlisted = await getWorkshopRegistration(input.eventSlug, input.email);
|
|
69029
69676
|
if (!waitlisted) throw new Error("workshop registration could not be claimed");
|
|
@@ -69038,7 +69685,7 @@ async function registerWorkshopInterest(input) {
|
|
|
69038
69685
|
id, event_slug, email, first_name, last_name, status
|
|
69039
69686
|
) VALUES (?, ?, ?, ?, ?, 'interested')
|
|
69040
69687
|
`,
|
|
69041
|
-
args: [(0,
|
|
69688
|
+
args: [(0, import_node_crypto44.randomUUID)(), input.eventSlug, input.email, input.firstName, input.lastName || null]
|
|
69042
69689
|
});
|
|
69043
69690
|
const registration = await getWorkshopRegistration(input.eventSlug, input.email);
|
|
69044
69691
|
if (!registration) throw new Error("workshop interest could not be recorded");
|
|
@@ -69068,11 +69715,11 @@ async function updateWorkshopRegistration(id, patch) {
|
|
|
69068
69715
|
args: [...entries.map(([, value]) => value), id]
|
|
69069
69716
|
});
|
|
69070
69717
|
}
|
|
69071
|
-
var
|
|
69718
|
+
var import_node_crypto44;
|
|
69072
69719
|
var init_workshop_registration_repository = __esm({
|
|
69073
69720
|
"src/api/workshop-registration-repository.ts"() {
|
|
69074
69721
|
"use strict";
|
|
69075
|
-
|
|
69722
|
+
import_node_crypto44 = require("crypto");
|
|
69076
69723
|
init_db();
|
|
69077
69724
|
}
|
|
69078
69725
|
});
|
|
@@ -69645,7 +70292,7 @@ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
|
|
|
69645
70292
|
articleCount: articles.length,
|
|
69646
70293
|
wordCount: totalWordCount,
|
|
69647
70294
|
bytes,
|
|
69648
|
-
sha256: (0,
|
|
70295
|
+
sha256: (0, import_node_crypto45.createHash)("sha256").update(html).digest("hex"),
|
|
69649
70296
|
warnings
|
|
69650
70297
|
};
|
|
69651
70298
|
}
|
|
@@ -69728,14 +70375,14 @@ ${provenance}`;
|
|
|
69728
70375
|
...rendered,
|
|
69729
70376
|
html,
|
|
69730
70377
|
bytes: Buffer.byteLength(html),
|
|
69731
|
-
sha256: (0,
|
|
70378
|
+
sha256: (0, import_node_crypto45.createHash)("sha256").update(html).digest("hex")
|
|
69732
70379
|
};
|
|
69733
70380
|
}
|
|
69734
|
-
var
|
|
70381
|
+
var import_node_crypto45, import_node_fs14, import_node_path21, import_marked, runtimeEntryDir, assetCache;
|
|
69735
70382
|
var init_render = __esm({
|
|
69736
70383
|
"src/editorial-reading-room/render.ts"() {
|
|
69737
70384
|
"use strict";
|
|
69738
|
-
|
|
70385
|
+
import_node_crypto45 = require("crypto");
|
|
69739
70386
|
import_node_fs14 = require("fs");
|
|
69740
70387
|
import_node_path21 = require("path");
|
|
69741
70388
|
import_marked = require("marked");
|
|
@@ -69999,7 +70646,7 @@ async function hostCommonsImage(input) {
|
|
|
69999
70646
|
415
|
|
70000
70647
|
);
|
|
70001
70648
|
}
|
|
70002
|
-
const digest2 = (0,
|
|
70649
|
+
const digest2 = (0, import_node_crypto46.createHash)("sha256").update(bytes).digest("hex");
|
|
70003
70650
|
const existing = await getDb().execute({
|
|
70004
70651
|
sql: "SELECT id, url, content_type, bytes, source_url FROM commons_images WHERE digest = ? LIMIT 1",
|
|
70005
70652
|
args: [digest2]
|
|
@@ -70087,11 +70734,11 @@ async function hostEntityImages(input) {
|
|
|
70087
70734
|
}
|
|
70088
70735
|
return rewrite;
|
|
70089
70736
|
}
|
|
70090
|
-
var
|
|
70737
|
+
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;
|
|
70091
70738
|
var init_commons_image_store = __esm({
|
|
70092
70739
|
"src/api/commons-image-store.ts"() {
|
|
70093
70740
|
"use strict";
|
|
70094
|
-
|
|
70741
|
+
import_node_crypto46 = require("crypto");
|
|
70095
70742
|
import_promises16 = require("dns/promises");
|
|
70096
70743
|
import_node_net2 = require("net");
|
|
70097
70744
|
init_blob_store();
|
|
@@ -70114,141 +70761,6 @@ var init_commons_image_store = __esm({
|
|
|
70114
70761
|
}
|
|
70115
70762
|
});
|
|
70116
70763
|
|
|
70117
|
-
// src/api/commons-embeddings.ts
|
|
70118
|
-
function commonsEmbedModel() {
|
|
70119
|
-
return (process.env.JINA_EMBED_MODEL ?? "jina-embeddings-v5-omni-small").trim();
|
|
70120
|
-
}
|
|
70121
|
-
function commonsEmbedDim() {
|
|
70122
|
-
return Number((process.env.JINA_EMBED_DIM ?? "1024").trim());
|
|
70123
|
-
}
|
|
70124
|
-
function commonsSemanticSearchConfigured() {
|
|
70125
|
-
return Boolean(process.env.JINA_API_KEY?.trim() && process.env.MEMORY_DATABASE_URL?.trim());
|
|
70126
|
-
}
|
|
70127
|
-
function vectorSql() {
|
|
70128
|
-
if (_vectorSql) return _vectorSql;
|
|
70129
|
-
const url = process.env.MEMORY_DATABASE_URL?.trim();
|
|
70130
|
-
if (!url) throw new Error("MEMORY_DATABASE_URL is not set; Commons semantic search needs the shared Postgres.");
|
|
70131
|
-
_vectorSql = (0, import_serverless.neon)(url);
|
|
70132
|
-
return _vectorSql;
|
|
70133
|
-
}
|
|
70134
|
-
async function ensureCommonsVectorSchema() {
|
|
70135
|
-
if (vectorSchemaReady) return;
|
|
70136
|
-
const dimension = commonsEmbedDim();
|
|
70137
|
-
await vectorSql().query("CREATE EXTENSION IF NOT EXISTS vector");
|
|
70138
|
-
await vectorSql().query(`
|
|
70139
|
-
CREATE TABLE IF NOT EXISTS commons_index_vectors (
|
|
70140
|
-
document_id TEXT PRIMARY KEY,
|
|
70141
|
-
entity_id TEXT NOT NULL,
|
|
70142
|
-
document_type TEXT NOT NULL,
|
|
70143
|
-
title TEXT NOT NULL,
|
|
70144
|
-
embedding vector(${dimension}) NOT NULL,
|
|
70145
|
-
model TEXT NOT NULL,
|
|
70146
|
-
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
70147
|
-
)
|
|
70148
|
-
`);
|
|
70149
|
-
await vectorSql().query("CREATE INDEX IF NOT EXISTS commons_index_vectors_entity ON commons_index_vectors(entity_id)");
|
|
70150
|
-
vectorSchemaReady = true;
|
|
70151
|
-
}
|
|
70152
|
-
async function embedCommonsTexts(texts) {
|
|
70153
|
-
const apiKey = process.env.JINA_API_KEY?.trim();
|
|
70154
|
-
if (!apiKey) throw new Error("JINA_API_KEY is not set; Commons semantic search cannot embed.");
|
|
70155
|
-
if (!texts.length) return [];
|
|
70156
|
-
const response = await fetch("https://api.jina.ai/v1/embeddings", {
|
|
70157
|
-
method: "POST",
|
|
70158
|
-
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
70159
|
-
body: JSON.stringify({
|
|
70160
|
-
model: commonsEmbedModel(),
|
|
70161
|
-
dimensions: commonsEmbedDim(),
|
|
70162
|
-
input: texts.map((text2) => ({ text: text2.slice(0, 8e3) }))
|
|
70163
|
-
}),
|
|
70164
|
-
signal: AbortSignal.timeout(6e4)
|
|
70165
|
-
});
|
|
70166
|
-
if (!response.ok) {
|
|
70167
|
-
throw new Error(`Jina embedding request failed with HTTP ${response.status}: ${(await response.text()).slice(0, 200)}`);
|
|
70168
|
-
}
|
|
70169
|
-
const payload = await response.json();
|
|
70170
|
-
const vectors = (payload.data ?? []).map((item) => item.embedding);
|
|
70171
|
-
if (vectors.length !== texts.length) {
|
|
70172
|
-
throw new Error(`Jina returned ${vectors.length} embeddings for ${texts.length} inputs.`);
|
|
70173
|
-
}
|
|
70174
|
-
return vectors;
|
|
70175
|
-
}
|
|
70176
|
-
async function embedQueuedCommonsDocuments(limit = 50) {
|
|
70177
|
-
if (!commonsSemanticSearchConfigured()) return { claimed: 0, embedded: 0, failed: 0, remaining: 0 };
|
|
70178
|
-
await ensureCommonsVectorSchema();
|
|
70179
|
-
const bounded2 = Math.max(1, Math.min(200, Math.floor(limit)));
|
|
70180
|
-
const queued = await getDb().execute({
|
|
70181
|
-
sql: `SELECT id, entity_id, document_type, title, text FROM commons_index_documents
|
|
70182
|
-
WHERE embedding_status IN ('queued', 'failed') ORDER BY updated_at ASC LIMIT ?`,
|
|
70183
|
-
args: [bounded2]
|
|
70184
|
-
});
|
|
70185
|
-
const rows = queued.rows;
|
|
70186
|
-
if (!rows.length) return { claimed: 0, embedded: 0, failed: 0, remaining: await queuedCommonsDocumentCount() };
|
|
70187
|
-
let embedded = 0;
|
|
70188
|
-
let failed = 0;
|
|
70189
|
-
const model = commonsEmbedModel();
|
|
70190
|
-
try {
|
|
70191
|
-
const vectors = await embedCommonsTexts(rows.map((row) => `${row.title}
|
|
70192
|
-
|
|
70193
|
-
${row.text}`));
|
|
70194
|
-
for (const [index, row] of rows.entries()) {
|
|
70195
|
-
const literal = `[${vectors[index].join(",")}]`;
|
|
70196
|
-
await vectorSql().query(
|
|
70197
|
-
`INSERT INTO commons_index_vectors (document_id, entity_id, document_type, title, embedding, model, updated_at)
|
|
70198
|
-
VALUES ($1, $2, $3, $4, $5::vector, $6, now())
|
|
70199
|
-
ON CONFLICT (document_id) DO UPDATE SET entity_id = EXCLUDED.entity_id, document_type = EXCLUDED.document_type,
|
|
70200
|
-
title = EXCLUDED.title, embedding = EXCLUDED.embedding, model = EXCLUDED.model, updated_at = now()`,
|
|
70201
|
-
[row.id, row.entity_id, row.document_type, row.title, literal, model]
|
|
70202
|
-
);
|
|
70203
|
-
await getDb().execute({
|
|
70204
|
-
sql: `UPDATE commons_index_documents SET embedding_status = 'indexed', embedding_provider = ?, embedding_model = ?,
|
|
70205
|
-
vector_ref = ?, indexed_at = ?, error = NULL WHERE id = ?`,
|
|
70206
|
-
args: [COMMONS_EMBED_PROVIDER, model, row.id, (/* @__PURE__ */ new Date()).toISOString(), row.id]
|
|
70207
|
-
});
|
|
70208
|
-
embedded += 1;
|
|
70209
|
-
}
|
|
70210
|
-
} catch (error) {
|
|
70211
|
-
failed = rows.length - embedded;
|
|
70212
|
-
const message = (error instanceof Error ? error.message : String(error)).slice(0, 500);
|
|
70213
|
-
for (const row of rows.slice(embedded)) {
|
|
70214
|
-
await getDb().execute({
|
|
70215
|
-
sql: `UPDATE commons_index_documents SET embedding_status = 'failed', error = ? WHERE id = ?`,
|
|
70216
|
-
args: [message, row.id]
|
|
70217
|
-
}).catch(() => void 0);
|
|
70218
|
-
}
|
|
70219
|
-
}
|
|
70220
|
-
return { claimed: rows.length, embedded, failed, remaining: await queuedCommonsDocumentCount() };
|
|
70221
|
-
}
|
|
70222
|
-
async function queuedCommonsDocumentCount() {
|
|
70223
|
-
const result = await getDb().execute(`SELECT COUNT(*) AS n FROM commons_index_documents WHERE embedding_status IN ('queued', 'failed')`);
|
|
70224
|
-
return Number(result.rows[0]?.n ?? 0);
|
|
70225
|
-
}
|
|
70226
|
-
async function semanticCommonsEntityScores(query, limit = 40) {
|
|
70227
|
-
const scores = /* @__PURE__ */ new Map();
|
|
70228
|
-
if (!commonsSemanticSearchConfigured() || !query.trim()) return scores;
|
|
70229
|
-
await ensureCommonsVectorSchema();
|
|
70230
|
-
const [vector] = await embedCommonsTexts([query]);
|
|
70231
|
-
if (!vector) return scores;
|
|
70232
|
-
const rows = await vectorSql().query(
|
|
70233
|
-
`SELECT entity_id, MAX(1 - (embedding <=> $1::vector)) AS score
|
|
70234
|
-
FROM commons_index_vectors GROUP BY entity_id ORDER BY score DESC LIMIT $2`,
|
|
70235
|
-
[`[${vector.join(",")}]`, Math.max(1, Math.min(100, limit))]
|
|
70236
|
-
);
|
|
70237
|
-
for (const row of rows) scores.set(String(row.entity_id), Number(row.score));
|
|
70238
|
-
return scores;
|
|
70239
|
-
}
|
|
70240
|
-
var import_serverless, COMMONS_EMBED_PROVIDER, _vectorSql, vectorSchemaReady;
|
|
70241
|
-
var init_commons_embeddings = __esm({
|
|
70242
|
-
"src/api/commons-embeddings.ts"() {
|
|
70243
|
-
"use strict";
|
|
70244
|
-
import_serverless = require("@neondatabase/serverless");
|
|
70245
|
-
init_db();
|
|
70246
|
-
COMMONS_EMBED_PROVIDER = "jina";
|
|
70247
|
-
_vectorSql = null;
|
|
70248
|
-
vectorSchemaReady = false;
|
|
70249
|
-
}
|
|
70250
|
-
});
|
|
70251
|
-
|
|
70252
70764
|
// src/api/schema-presence.ts
|
|
70253
70765
|
async function loadSchemaObjects() {
|
|
70254
70766
|
const res = await getDb().execute(
|
|
@@ -70351,7 +70863,7 @@ function buildCommonsLinkset(entity, claims) {
|
|
|
70351
70863
|
context[claim.predicate] = targets;
|
|
70352
70864
|
}
|
|
70353
70865
|
const document2 = { linkset: [context] };
|
|
70354
|
-
const etag = `"${(0,
|
|
70866
|
+
const etag = `"${(0, import_node_crypto47.createHash)("sha256").update(JSON.stringify(document2)).digest("hex")}"`;
|
|
70355
70867
|
return { document: document2, etag, publicUrl, linksetUrl, profile: COMMONS_RELATIONSHIP_PROFILE };
|
|
70356
70868
|
}
|
|
70357
70869
|
function commonsLinksetDiscoveryHeader(idOrSlug) {
|
|
@@ -70419,11 +70931,11 @@ function normalizeHreflang(value) {
|
|
|
70419
70931
|
const languages = [...new Set(value.map((item) => optionalText(item, 80)).filter((item) => Boolean(item)))];
|
|
70420
70932
|
return languages.length ? languages : void 0;
|
|
70421
70933
|
}
|
|
70422
|
-
var
|
|
70934
|
+
var import_node_crypto47, COMMONS_LINKSET_MEDIA_TYPE, COMMONS_RELATIONSHIP_PROFILE, REGISTERED_RELATIONS;
|
|
70423
70935
|
var init_commons_linksets = __esm({
|
|
70424
70936
|
"src/api/commons-linksets.ts"() {
|
|
70425
70937
|
"use strict";
|
|
70426
|
-
|
|
70938
|
+
import_node_crypto47 = require("crypto");
|
|
70427
70939
|
COMMONS_LINKSET_MEDIA_TYPE = "application/linkset+json";
|
|
70428
70940
|
COMMONS_RELATIONSHIP_PROFILE = "https://mcpscraper.dev/commons/profiles/relationships/v1";
|
|
70429
70941
|
REGISTERED_RELATIONS = /* @__PURE__ */ new Set([
|
|
@@ -71063,7 +71575,7 @@ async function submitCommonsEntity(input, user) {
|
|
|
71063
71575
|
const existingClaims = existing && normalized.claims !== void 0 ? await getCommonsClaimsByEntityId(existing.id) : [];
|
|
71064
71576
|
const safety = evaluatePublishSafety(normalized, existing);
|
|
71065
71577
|
const shouldApply = safety.safe && normalized.reviewPolicy !== "always_review";
|
|
71066
|
-
const proposalId = `commons-proposal-${(0,
|
|
71578
|
+
const proposalId = `commons-proposal-${(0, import_node_crypto48.randomUUID)()}`;
|
|
71067
71579
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
71068
71580
|
const entityId = existing?.id ?? normalized.entityId ?? allocateEntityId();
|
|
71069
71581
|
const proposalStatus = shouldApply ? "accepted" : "pending_review";
|
|
@@ -71118,7 +71630,7 @@ async function submitCommonsEntity(input, user) {
|
|
|
71118
71630
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
71119
71631
|
`,
|
|
71120
71632
|
args: [
|
|
71121
|
-
`commons-ledger-${(0,
|
|
71633
|
+
`commons-ledger-${(0, import_node_crypto48.randomUUID)()}`,
|
|
71122
71634
|
nextEntity.id,
|
|
71123
71635
|
proposalId,
|
|
71124
71636
|
user.id,
|
|
@@ -71224,7 +71736,7 @@ async function saveCommonsFilter(input, user) {
|
|
|
71224
71736
|
sql: "SELECT id FROM commons_saved_filters WHERE user_id = ? AND name = ? LIMIT 1",
|
|
71225
71737
|
args: [user.id, name]
|
|
71226
71738
|
});
|
|
71227
|
-
const id = existing.rows[0]?.id != null ? String(existing.rows[0].id) : `commons-filter-${(0,
|
|
71739
|
+
const id = existing.rows[0]?.id != null ? String(existing.rows[0].id) : `commons-filter-${(0, import_node_crypto48.randomUUID)()}`;
|
|
71228
71740
|
await getDb().execute({
|
|
71229
71741
|
sql: `
|
|
71230
71742
|
INSERT INTO commons_saved_filters (id, user_id, name, description, filter_json, created_at, updated_at)
|
|
@@ -72002,7 +72514,7 @@ function commonsIndexDocuments(entity, now) {
|
|
|
72002
72514
|
return documents;
|
|
72003
72515
|
}
|
|
72004
72516
|
function commonsIndexDocumentId(entityId, documentType, documentKey) {
|
|
72005
|
-
return `commons-index-${(0,
|
|
72517
|
+
return `commons-index-${(0, import_node_crypto48.createHash)("sha256").update(`${entityId}
|
|
72006
72518
|
${documentType}
|
|
72007
72519
|
${documentKey}`).digest("hex").slice(0, 32)}`;
|
|
72008
72520
|
}
|
|
@@ -72568,11 +73080,11 @@ function jsonLikeValue(value) {
|
|
|
72568
73080
|
function escapeLike(value) {
|
|
72569
73081
|
return value.replace(/[%_]/g, "");
|
|
72570
73082
|
}
|
|
72571
|
-
var
|
|
73083
|
+
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;
|
|
72572
73084
|
var init_commons_repository = __esm({
|
|
72573
73085
|
"src/api/commons-repository.ts"() {
|
|
72574
73086
|
"use strict";
|
|
72575
|
-
|
|
73087
|
+
import_node_crypto48 = require("crypto");
|
|
72576
73088
|
init_db();
|
|
72577
73089
|
init_commons_image_store();
|
|
72578
73090
|
init_commons_embeddings();
|
|
@@ -72951,7 +73463,7 @@ async function claimCommonsPublication(input, user) {
|
|
|
72951
73463
|
}
|
|
72952
73464
|
const existingName = await getCommonsPublicationBySubdomain(subdomain);
|
|
72953
73465
|
if (existingName) throw new CommonsPublicationError("publication_name_unavailable", "That publication name is already claimed.", 409);
|
|
72954
|
-
const id = `tcpub_${(0,
|
|
73466
|
+
const id = `tcpub_${(0, import_node_crypto49.randomUUID)()}`;
|
|
72955
73467
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
72956
73468
|
try {
|
|
72957
73469
|
await getDb().execute({
|
|
@@ -73003,7 +73515,7 @@ async function publishCommonsEditorial(input, user) {
|
|
|
73003
73515
|
const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
|
|
73004
73516
|
const rendered = renderEditorialReadingRoom(editionInput);
|
|
73005
73517
|
const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
|
|
73006
|
-
const editionId = `tced_${(0,
|
|
73518
|
+
const editionId = `tced_${(0, import_node_crypto49.randomUUID)()}`;
|
|
73007
73519
|
const revision = (latest?.revision ?? 0) + 1;
|
|
73008
73520
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
73009
73521
|
await getDb().batch([
|
|
@@ -73027,7 +73539,7 @@ async function publishCommonsEditorial(input, user) {
|
|
|
73027
73539
|
JSON.stringify(editionInput.articles),
|
|
73028
73540
|
html,
|
|
73029
73541
|
rendered.filename,
|
|
73030
|
-
(0,
|
|
73542
|
+
(0, import_node_crypto49.createHash)("sha256").update(html).digest("hex"),
|
|
73031
73543
|
rendered.articleCount,
|
|
73032
73544
|
rendered.wordCount,
|
|
73033
73545
|
Buffer.byteLength(html),
|
|
@@ -73085,7 +73597,7 @@ async function updateCommonsEditorialArticle(input, user) {
|
|
|
73085
73597
|
const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
|
|
73086
73598
|
const rendered = renderEditorialReadingRoom(editionInput);
|
|
73087
73599
|
const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
|
|
73088
|
-
const editionId = `tced_${(0,
|
|
73600
|
+
const editionId = `tced_${(0, import_node_crypto49.randomUUID)()}`;
|
|
73089
73601
|
const revision = latest.revision + 1;
|
|
73090
73602
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
73091
73603
|
await getDb().batch([
|
|
@@ -73109,7 +73621,7 @@ async function updateCommonsEditorialArticle(input, user) {
|
|
|
73109
73621
|
JSON.stringify(nextArticles),
|
|
73110
73622
|
html,
|
|
73111
73623
|
rendered.filename,
|
|
73112
|
-
(0,
|
|
73624
|
+
(0, import_node_crypto49.createHash)("sha256").update(html).digest("hex"),
|
|
73113
73625
|
rendered.articleCount,
|
|
73114
73626
|
rendered.wordCount,
|
|
73115
73627
|
Buffer.byteLength(html),
|
|
@@ -73314,11 +73826,11 @@ function addPublicMetadata(html, canonicalUrl, publicationTitle) {
|
|
|
73314
73826
|
"</head>"
|
|
73315
73827
|
].join("\n"));
|
|
73316
73828
|
}
|
|
73317
|
-
var
|
|
73829
|
+
var import_node_crypto49, PUBLICATION_ROOT_DOMAIN, RESERVED_SUBDOMAINS, CommonsPublicationError;
|
|
73318
73830
|
var init_commons_publication_repository = __esm({
|
|
73319
73831
|
"src/api/commons-publication-repository.ts"() {
|
|
73320
73832
|
"use strict";
|
|
73321
|
-
|
|
73833
|
+
import_node_crypto49 = require("crypto");
|
|
73322
73834
|
init_db();
|
|
73323
73835
|
init_commons_repository();
|
|
73324
73836
|
init_render();
|
|
@@ -74551,7 +75063,7 @@ async function migrateAnalytics() {
|
|
|
74551
75063
|
}
|
|
74552
75064
|
function normalizeSlug2(value) {
|
|
74553
75065
|
const slug4 = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
74554
|
-
return slug4 || `site-${(0,
|
|
75066
|
+
return slug4 || `site-${(0, import_node_crypto50.randomBytes)(4).toString("hex")}`;
|
|
74555
75067
|
}
|
|
74556
75068
|
function normalizeObservedHostname(origin) {
|
|
74557
75069
|
if (!origin || origin === "null") return null;
|
|
@@ -74564,7 +75076,7 @@ function normalizeObservedHostname(origin) {
|
|
|
74564
75076
|
}
|
|
74565
75077
|
}
|
|
74566
75078
|
function publicPixelId() {
|
|
74567
|
-
return `px_${(0,
|
|
75079
|
+
return `px_${(0, import_node_crypto50.randomBytes)(18).toString("base64url")}`;
|
|
74568
75080
|
}
|
|
74569
75081
|
function mapRows(rows) {
|
|
74570
75082
|
return rows;
|
|
@@ -74596,7 +75108,7 @@ async function requireEditor(client2, siteId, userId) {
|
|
|
74596
75108
|
async function createAnalyticsSite(input) {
|
|
74597
75109
|
const db = getAnalyticsPool();
|
|
74598
75110
|
const client2 = await db.connect();
|
|
74599
|
-
const id = (0,
|
|
75111
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
74600
75112
|
const baseSlug = normalizeSlug2(input.slug || input.name);
|
|
74601
75113
|
try {
|
|
74602
75114
|
await client2.query("BEGIN");
|
|
@@ -74612,7 +75124,7 @@ async function createAnalyticsSite(input) {
|
|
|
74612
75124
|
} catch (error) {
|
|
74613
75125
|
const code = error.code;
|
|
74614
75126
|
if (code !== "23505" || attempt === 2) throw error;
|
|
74615
|
-
slug4 = `${baseSlug}-${(0,
|
|
75127
|
+
slug4 = `${baseSlug}-${(0, import_node_crypto50.randomBytes)(2).toString("hex")}`;
|
|
74616
75128
|
}
|
|
74617
75129
|
}
|
|
74618
75130
|
await client2.query(
|
|
@@ -74827,7 +75339,7 @@ async function createAnalyticsPixel(input) {
|
|
|
74827
75339
|
VALUES ($1, $2, $3, $4, $5)
|
|
74828
75340
|
RETURNING id, site_id, public_id, name, environment, status, created_at::text, NULL::text AS last_event_at`,
|
|
74829
75341
|
[
|
|
74830
|
-
(0,
|
|
75342
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
74831
75343
|
input.siteId,
|
|
74832
75344
|
publicPixelId(),
|
|
74833
75345
|
input.name.trim(),
|
|
@@ -74904,7 +75416,7 @@ async function setAnalyticsPixelDomainState(input) {
|
|
|
74904
75416
|
SELECT $1, p.id, $4, $5 FROM analytics_pixels p WHERE p.id = $2 AND p.site_id = $3
|
|
74905
75417
|
ON CONFLICT(pixel_id, hostname) DO UPDATE SET state = EXCLUDED.state, updated_at = now()
|
|
74906
75418
|
RETURNING id`,
|
|
74907
|
-
[(0,
|
|
75419
|
+
[(0, import_node_crypto50.randomUUID)(), input.pixelId, input.siteId, hostname, input.state]
|
|
74908
75420
|
);
|
|
74909
75421
|
if (!result.rowCount)
|
|
74910
75422
|
throw new AnalyticsRepositoryError(
|
|
@@ -74954,7 +75466,7 @@ function sanitizeAnalyticsProperties(value) {
|
|
|
74954
75466
|
}
|
|
74955
75467
|
async function ingestAnalyticsEvents(input) {
|
|
74956
75468
|
const db = getAnalyticsPool();
|
|
74957
|
-
const requestId = `air_${(0,
|
|
75469
|
+
const requestId = `air_${(0, import_node_crypto50.randomUUID)()}`;
|
|
74958
75470
|
const hostname = normalizeObservedHostname(input.origin);
|
|
74959
75471
|
const pixelResult = await db.query(
|
|
74960
75472
|
`SELECT p.id, p.site_id, p.status,
|
|
@@ -74975,7 +75487,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
74975
75487
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
74976
75488
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
74977
75489
|
[
|
|
74978
|
-
(0,
|
|
75490
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
74979
75491
|
requestId,
|
|
74980
75492
|
pixel?.site_id ?? null,
|
|
74981
75493
|
pixel?.id ?? null,
|
|
@@ -75000,7 +75512,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75000
75512
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
75001
75513
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
75002
75514
|
[
|
|
75003
|
-
(0,
|
|
75515
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75004
75516
|
requestId,
|
|
75005
75517
|
pixel.site_id,
|
|
75006
75518
|
pixel.id,
|
|
@@ -75025,7 +75537,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75025
75537
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, rejected_count, reason_codes)
|
|
75026
75538
|
VALUES ($1, $2, $3, $4, $5, $6::jsonb)`,
|
|
75027
75539
|
[
|
|
75028
|
-
(0,
|
|
75540
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75029
75541
|
requestId,
|
|
75030
75542
|
pixel.site_id,
|
|
75031
75543
|
pixel.id,
|
|
@@ -75049,7 +75561,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75049
75561
|
ON CONFLICT(pixel_id, hostname) DO UPDATE
|
|
75050
75562
|
SET last_seen_at = now(), updated_at = now()
|
|
75051
75563
|
RETURNING state`,
|
|
75052
|
-
[(0,
|
|
75564
|
+
[(0, import_node_crypto50.randomUUID)(), pixel.id, hostname]
|
|
75053
75565
|
);
|
|
75054
75566
|
if (domainResult.rows[0]?.state !== "approved") {
|
|
75055
75567
|
await db.query(
|
|
@@ -75063,7 +75575,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75063
75575
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
75064
75576
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
75065
75577
|
[
|
|
75066
|
-
(0,
|
|
75578
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75067
75579
|
requestId,
|
|
75068
75580
|
pixel.site_id,
|
|
75069
75581
|
pixel.id,
|
|
@@ -75113,7 +75625,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75113
75625
|
$23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33
|
|
75114
75626
|
) ON CONFLICT(site_id, event_id) DO NOTHING`,
|
|
75115
75627
|
[
|
|
75116
|
-
(0,
|
|
75628
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75117
75629
|
event2.eventId,
|
|
75118
75630
|
pixel.site_id,
|
|
75119
75631
|
pixel.id,
|
|
@@ -75171,7 +75683,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
75171
75683
|
id, request_id, site_id, pixel_id, hostname, accepted_count, rejected_count, reason_codes
|
|
75172
75684
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb)`,
|
|
75173
75685
|
[
|
|
75174
|
-
(0,
|
|
75686
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
75175
75687
|
requestId,
|
|
75176
75688
|
pixel.site_id,
|
|
75177
75689
|
pixel.id,
|
|
@@ -75203,7 +75715,7 @@ function normalizeGeographyCode(value, max) {
|
|
|
75203
75715
|
return normalized && /^[A-Z0-9-]+$/.test(normalized) ? normalized.slice(0, max) : null;
|
|
75204
75716
|
}
|
|
75205
75717
|
function pageFingerprint(scope, siteId, filters) {
|
|
75206
|
-
return (0,
|
|
75718
|
+
return (0, import_node_crypto50.createHash)("sha256").update(JSON.stringify({ scope, siteId, filters })).digest("base64url").slice(0, 18);
|
|
75207
75719
|
}
|
|
75208
75720
|
function decodePageOffset(cursor, fingerprint2) {
|
|
75209
75721
|
if (!cursor) return 0;
|
|
@@ -75253,7 +75765,7 @@ async function createAnalyticsConversion(input) {
|
|
|
75253
75765
|
404
|
|
75254
75766
|
);
|
|
75255
75767
|
}
|
|
75256
|
-
const id = (0,
|
|
75768
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
75257
75769
|
const resolvedPerson = input.sessionId ? await db.query(
|
|
75258
75770
|
`SELECT e.person_id FROM analytics_identity_nodes n JOIN analytics_identity_edges e ON e.identity_node_id = n.id
|
|
75259
75771
|
WHERE n.site_id = $1 AND n.kind = 'session_id' AND n.value_hmac = $2 ORDER BY e.confidence DESC LIMIT 1`,
|
|
@@ -76002,7 +76514,7 @@ async function createAnalyticsCampaignLink(input) {
|
|
|
76002
76514
|
404
|
|
76003
76515
|
);
|
|
76004
76516
|
}
|
|
76005
|
-
const shortCode = (input.shortCode?.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "-") || (0,
|
|
76517
|
+
const shortCode = (input.shortCode?.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "-") || (0, import_node_crypto50.randomBytes)(5).toString("base64url").toLowerCase()).slice(0, 48);
|
|
76006
76518
|
try {
|
|
76007
76519
|
const result = await db.query(
|
|
76008
76520
|
`INSERT INTO analytics_campaign_links(
|
|
@@ -76011,7 +76523,7 @@ async function createAnalyticsCampaignLink(input) {
|
|
|
76011
76523
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
|
|
76012
76524
|
RETURNING *, 0::int AS click_count`,
|
|
76013
76525
|
[
|
|
76014
|
-
(0,
|
|
76526
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76015
76527
|
input.siteId,
|
|
76016
76528
|
input.pixelId ?? null,
|
|
76017
76529
|
input.name.trim(),
|
|
@@ -76082,7 +76594,7 @@ async function resolveAnalyticsCampaignLink(shortCode, referrer) {
|
|
|
76082
76594
|
if (!row) return null;
|
|
76083
76595
|
await db.query(
|
|
76084
76596
|
`INSERT INTO analytics_campaign_clicks(id, link_id, referrer) VALUES ($1, $2, $3)`,
|
|
76085
|
-
[(0,
|
|
76597
|
+
[(0, import_node_crypto50.randomUUID)(), row.id, normalizeAnalyticsUrl(referrer || void 0)]
|
|
76086
76598
|
);
|
|
76087
76599
|
return buildTaggedCampaignUrl(row);
|
|
76088
76600
|
}
|
|
@@ -76100,14 +76612,14 @@ async function createAnalyticsForm(input) {
|
|
|
76100
76612
|
404
|
|
76101
76613
|
);
|
|
76102
76614
|
const baseSlug = normalizeSlug2(input.name);
|
|
76103
|
-
const slug4 = `${baseSlug}-${(0,
|
|
76104
|
-
const publicId = `form_${(0,
|
|
76615
|
+
const slug4 = `${baseSlug}-${(0, import_node_crypto50.randomBytes)(3).toString("hex")}`;
|
|
76616
|
+
const publicId = `form_${(0, import_node_crypto50.randomBytes)(18).toString("base64url")}`;
|
|
76105
76617
|
const result = await db.query(
|
|
76106
76618
|
`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)
|
|
76107
76619
|
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb,$9,$10,$11,$12,$13,$14)
|
|
76108
76620
|
RETURNING *, 0::int AS submission_count`,
|
|
76109
76621
|
[
|
|
76110
|
-
(0,
|
|
76622
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76111
76623
|
publicId,
|
|
76112
76624
|
input.siteId,
|
|
76113
76625
|
input.pixelId,
|
|
@@ -76152,7 +76664,7 @@ async function getPublicAnalyticsForm(publicId) {
|
|
|
76152
76664
|
return result.rows[0] ?? null;
|
|
76153
76665
|
}
|
|
76154
76666
|
async function recordAnalyticsFormSubmission(input) {
|
|
76155
|
-
const id = (0,
|
|
76667
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76156
76668
|
await getAnalyticsPool().query(
|
|
76157
76669
|
`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)
|
|
76158
76670
|
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12::jsonb)`,
|
|
@@ -76183,7 +76695,7 @@ function sanitizeClickIds(value) {
|
|
|
76183
76695
|
return output;
|
|
76184
76696
|
}
|
|
76185
76697
|
function identityHmac(kind, value) {
|
|
76186
|
-
return (0,
|
|
76698
|
+
return (0, import_node_crypto50.createHmac)("sha256", getSessionSecret()).update(`${kind}:${value.trim().toLowerCase()}`).digest("hex");
|
|
76187
76699
|
}
|
|
76188
76700
|
async function linkAnalyticsFormIdentity(input) {
|
|
76189
76701
|
const client2 = await getAnalyticsPool().connect();
|
|
@@ -76192,7 +76704,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
76192
76704
|
const person = await client2.query(
|
|
76193
76705
|
`INSERT INTO analytics_people(id, site_id, crm_person_ref) VALUES ($1,$2,$3)
|
|
76194
76706
|
ON CONFLICT(site_id, crm_person_ref) DO UPDATE SET last_seen_at = now() RETURNING id`,
|
|
76195
|
-
[(0,
|
|
76707
|
+
[(0, import_node_crypto50.randomUUID)(), input.siteId, input.crmPersonRef]
|
|
76196
76708
|
);
|
|
76197
76709
|
const personId = person.rows[0].id;
|
|
76198
76710
|
const signals = [];
|
|
@@ -76239,7 +76751,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
76239
76751
|
`INSERT INTO analytics_identity_nodes(id, site_id, kind, value_hmac) VALUES ($1,$2,$3,$4)
|
|
76240
76752
|
ON CONFLICT(site_id, kind, value_hmac) DO UPDATE SET last_seen_at = now() RETURNING id`,
|
|
76241
76753
|
[
|
|
76242
|
-
(0,
|
|
76754
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76243
76755
|
input.siteId,
|
|
76244
76756
|
signal.kind,
|
|
76245
76757
|
identityHmac(signal.kind, signal.value)
|
|
@@ -76250,7 +76762,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
76250
76762
|
VALUES ($1,$2,$3,$4,$5,$6)
|
|
76251
76763
|
ON CONFLICT(person_id, identity_node_id, evidence_kind) DO UPDATE SET last_seen_at = now(), confidence = greatest(analytics_identity_edges.confidence, EXCLUDED.confidence)`,
|
|
76252
76764
|
[
|
|
76253
|
-
(0,
|
|
76765
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76254
76766
|
input.siteId,
|
|
76255
76767
|
personId,
|
|
76256
76768
|
node.rows[0].id,
|
|
@@ -76348,7 +76860,7 @@ async function createAnalyticsCrmImport(input) {
|
|
|
76348
76860
|
const db = getAnalyticsPool();
|
|
76349
76861
|
await requireEditor(db, input.siteId, input.userId);
|
|
76350
76862
|
const client2 = await db.connect();
|
|
76351
|
-
const id = (0,
|
|
76863
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76352
76864
|
try {
|
|
76353
76865
|
await client2.query("BEGIN");
|
|
76354
76866
|
await client2.query(
|
|
@@ -76368,7 +76880,7 @@ async function createAnalyticsCrmImport(input) {
|
|
|
76368
76880
|
await client2.query(
|
|
76369
76881
|
`INSERT INTO analytics_crm_import_rows(id, import_id, crm_person_ref, payload_ciphertext)
|
|
76370
76882
|
VALUES ($1,$2,$3,$4) ON CONFLICT(import_id, crm_person_ref) DO NOTHING`,
|
|
76371
|
-
[(0,
|
|
76883
|
+
[(0, import_node_crypto50.randomUUID)(), id, row.crmPersonRef, row.payloadCiphertext]
|
|
76372
76884
|
);
|
|
76373
76885
|
}
|
|
76374
76886
|
await client2.query("COMMIT");
|
|
@@ -76407,7 +76919,7 @@ async function createAnalyticsActivationDestination(input) {
|
|
|
76407
76919
|
`INSERT INTO analytics_activation_destinations(id, site_id, platform, name, connection_ref, external_dataset_id, event_mapping, created_by_user_id)
|
|
76408
76920
|
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8) RETURNING *`,
|
|
76409
76921
|
[
|
|
76410
|
-
(0,
|
|
76922
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76411
76923
|
input.siteId,
|
|
76412
76924
|
input.platform,
|
|
76413
76925
|
input.name.trim(),
|
|
@@ -76459,7 +76971,7 @@ async function queueAnalyticsActivation(input) {
|
|
|
76459
76971
|
`INSERT INTO analytics_activation_jobs(id, destination_id, conversion_id, person_id, payload_ciphertext)
|
|
76460
76972
|
VALUES ($1,$2,$3,$4,$5) ON CONFLICT(destination_id, conversion_id) DO NOTHING`,
|
|
76461
76973
|
[
|
|
76462
|
-
(0,
|
|
76974
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76463
76975
|
destination.id,
|
|
76464
76976
|
input.conversionId,
|
|
76465
76977
|
input.personId ?? null,
|
|
@@ -76471,7 +76983,7 @@ async function queueAnalyticsActivation(input) {
|
|
|
76471
76983
|
return queued;
|
|
76472
76984
|
}
|
|
76473
76985
|
async function queueAnalyticsFormDelivery(input) {
|
|
76474
|
-
const id = (0,
|
|
76986
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76475
76987
|
await getAnalyticsPool().query(
|
|
76476
76988
|
`INSERT INTO analytics_form_delivery_jobs(id, submission_id, owner_user_id, payload_ciphertext, last_error_code)
|
|
76477
76989
|
VALUES ($1,$2,$3,$4,$5)`,
|
|
@@ -76598,7 +77110,7 @@ async function analyticsHealth(siteId, userId) {
|
|
|
76598
77110
|
}
|
|
76599
77111
|
async function refreshAnalyticsDailyRollups(input) {
|
|
76600
77112
|
const db = getAnalyticsPool();
|
|
76601
|
-
const runId = (0,
|
|
77113
|
+
const runId = (0, import_node_crypto50.randomUUID)();
|
|
76602
77114
|
await db.query(
|
|
76603
77115
|
`INSERT INTO analytics_rollup_runs(id, window_start, window_end, status) VALUES ($1, $2, $3, 'running')`,
|
|
76604
77116
|
[runId, input.start, input.end]
|
|
@@ -76692,7 +77204,7 @@ async function refreshAnalyticsDailyRollupsIfDue(now = /* @__PURE__ */ new Date(
|
|
|
76692
77204
|
lockClient.release();
|
|
76693
77205
|
}
|
|
76694
77206
|
}
|
|
76695
|
-
function
|
|
77207
|
+
function csvCell3(value) {
|
|
76696
77208
|
const text2 = value == null ? "" : String(value);
|
|
76697
77209
|
return /[\n\r,\"]/.test(text2) ? `"${text2.replaceAll('"', '""')}"` : text2;
|
|
76698
77210
|
}
|
|
@@ -76702,7 +77214,7 @@ function rowsToCsv2(rows) {
|
|
|
76702
77214
|
return [
|
|
76703
77215
|
columns.join(","),
|
|
76704
77216
|
...rows.map(
|
|
76705
|
-
(row) => columns.map((column) =>
|
|
77217
|
+
(row) => columns.map((column) => csvCell3(row[column])).join(",")
|
|
76706
77218
|
)
|
|
76707
77219
|
].join("\n");
|
|
76708
77220
|
}
|
|
@@ -76795,7 +77307,7 @@ async function createAnalyticsExport(input) {
|
|
|
76795
77307
|
`Generated ${(/* @__PURE__ */ new Date()).toISOString()} from the governed ${input.report} report contract.`
|
|
76796
77308
|
].join("\n");
|
|
76797
77309
|
}
|
|
76798
|
-
const id = (0,
|
|
77310
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76799
77311
|
const inserted = await getAnalyticsPool().query(
|
|
76800
77312
|
`INSERT INTO analytics_exports(id, site_id, requested_by_user_id, idempotency_key, report, format, filters, content)
|
|
76801
77313
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8)
|
|
@@ -76828,11 +77340,11 @@ async function createAnalyticsExport(input) {
|
|
|
76828
77340
|
}
|
|
76829
77341
|
return describeArtifact(replay.rows[0]);
|
|
76830
77342
|
}
|
|
76831
|
-
var
|
|
77343
|
+
var import_node_crypto50, import_pg, AnalyticsRepositoryError, pool2, MAX_ENGAGED_MS, ENGAGED_SESSION_MS, blockedPropertyName, inferredFamilySql, ANALYTICS_CONTENT_SORTS, clickIdKeys;
|
|
76832
77344
|
var init_analytics_repository = __esm({
|
|
76833
77345
|
"src/api/analytics-repository.ts"() {
|
|
76834
77346
|
"use strict";
|
|
76835
|
-
|
|
77347
|
+
import_node_crypto50 = require("crypto");
|
|
76836
77348
|
import_pg = require("pg");
|
|
76837
77349
|
init_session();
|
|
76838
77350
|
init_analytics_attribution();
|
|
@@ -77071,8 +77583,8 @@ function dashboardCallbackUrl() {
|
|
|
77071
77583
|
}
|
|
77072
77584
|
async function createThorbitConnectUrl(userId) {
|
|
77073
77585
|
if (!bridgeConfigured()) throw new Error("Thorbit X-Ray account bridge is not configured");
|
|
77074
|
-
const state = (0,
|
|
77075
|
-
const stateHash = (0,
|
|
77586
|
+
const state = (0, import_node_crypto51.randomBytes)(32).toString("base64url");
|
|
77587
|
+
const stateHash = (0, import_node_crypto51.createHash)("sha256").update(state).digest("hex");
|
|
77076
77588
|
await getAnalyticsPool().query(
|
|
77077
77589
|
`INSERT INTO analytics_thorbit_connect_states(state_hash,user_id,expires_at)
|
|
77078
77590
|
VALUES ($1,$2,now()+interval '10 minutes')
|
|
@@ -77087,9 +77599,9 @@ async function createThorbitConnectUrl(userId) {
|
|
|
77087
77599
|
function verifyThorbitAssertion(token6) {
|
|
77088
77600
|
const [encoded, signature] = token6.split(".");
|
|
77089
77601
|
if (!encoded || !signature || !bridgeConfigured()) throw new Error("Invalid Thorbit assertion");
|
|
77090
|
-
const expected = (0,
|
|
77602
|
+
const expected = (0, import_node_crypto51.createHmac)("sha256", bridgeSecret()).update(encoded).digest();
|
|
77091
77603
|
const actual = Buffer.from(signature, "base64url");
|
|
77092
|
-
if (actual.length !== expected.length || !(0,
|
|
77604
|
+
if (actual.length !== expected.length || !(0, import_node_crypto51.timingSafeEqual)(actual, expected)) {
|
|
77093
77605
|
throw new Error("Invalid Thorbit assertion signature");
|
|
77094
77606
|
}
|
|
77095
77607
|
const parsed = AssertionSchema.safeParse(
|
|
@@ -77101,7 +77613,7 @@ function verifyThorbitAssertion(token6) {
|
|
|
77101
77613
|
return parsed.data.entitlement;
|
|
77102
77614
|
}
|
|
77103
77615
|
async function consumeThorbitConnectCallback(input) {
|
|
77104
|
-
const stateHash = (0,
|
|
77616
|
+
const stateHash = (0, import_node_crypto51.createHash)("sha256").update(input.state).digest("hex");
|
|
77105
77617
|
const client2 = await getAnalyticsPool().connect();
|
|
77106
77618
|
try {
|
|
77107
77619
|
await client2.query("BEGIN");
|
|
@@ -77141,11 +77653,11 @@ async function disconnectAnalyticsEntitlement(userId) {
|
|
|
77141
77653
|
[userId]
|
|
77142
77654
|
);
|
|
77143
77655
|
}
|
|
77144
|
-
var
|
|
77656
|
+
var import_node_crypto51, import_zod55, THORBIT_PRODUCT_URL, REFRESH_INTERVAL_MS, ELIGIBLE_GRACE_MS, TRIAL_LENGTH_MS, ThorbitEntitlementSchema, AssertionSchema;
|
|
77145
77657
|
var init_analytics_entitlement = __esm({
|
|
77146
77658
|
"src/api/analytics-entitlement.ts"() {
|
|
77147
77659
|
"use strict";
|
|
77148
|
-
|
|
77660
|
+
import_node_crypto51 = require("crypto");
|
|
77149
77661
|
import_zod55 = require("zod");
|
|
77150
77662
|
init_analytics_repository();
|
|
77151
77663
|
THORBIT_PRODUCT_URL = "https://thorbit.ai";
|
|
@@ -77285,14 +77797,14 @@ function renderPublicForm(form, placementUrl) {
|
|
|
77285
77797
|
const brand = form.brand;
|
|
77286
77798
|
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>`;
|
|
77287
77799
|
}
|
|
77288
|
-
var import_hono34, import_factory6, import_zod56,
|
|
77800
|
+
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;
|
|
77289
77801
|
var init_analytics_routes = __esm({
|
|
77290
77802
|
"src/api/analytics-routes.ts"() {
|
|
77291
77803
|
"use strict";
|
|
77292
77804
|
import_hono34 = require("hono");
|
|
77293
77805
|
import_factory6 = require("hono/factory");
|
|
77294
77806
|
import_zod56 = require("zod");
|
|
77295
|
-
|
|
77807
|
+
import_node_crypto52 = require("crypto");
|
|
77296
77808
|
import_papaparse6 = __toESM(require("papaparse"), 1);
|
|
77297
77809
|
init_api_auth();
|
|
77298
77810
|
init_db();
|
|
@@ -77623,7 +78135,7 @@ var init_analytics_routes = __esm({
|
|
|
77623
78135
|
const lastName = typeof data.last_name === "string" ? data.last_name.trim() : "";
|
|
77624
78136
|
const fullName = [firstName, lastName].filter(Boolean).join(" ") || (typeof data.name === "string" ? data.name.trim() : "") || email || "Website lead";
|
|
77625
78137
|
const identitySeed = email || `${fullName}:${Date.now()}`;
|
|
77626
|
-
const suffix2 = (0,
|
|
78138
|
+
const suffix2 = (0, import_node_crypto52.createHash)("sha256").update(identitySeed).digest("hex").slice(0, 12);
|
|
77627
78139
|
const path6 = `Leads/person-${suffix2}`;
|
|
77628
78140
|
const { key: memoryKey, error: memoryKeyError } = await getOrCreateUserMemoryKey(user);
|
|
77629
78141
|
const existing = memoryKey ? await memoryCall("getTool", { vault: "People", path: path6 }, memoryKey) : { ok: false, error: memoryKeyError || "memory_credential_unavailable" };
|
|
@@ -77722,9 +78234,9 @@ Submitted the published form.
|
|
|
77722
78234
|
occurredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
77723
78235
|
});
|
|
77724
78236
|
const match = {
|
|
77725
|
-
...email ? { emailSha256: (0,
|
|
78237
|
+
...email ? { emailSha256: (0, import_node_crypto52.createHash)("sha256").update(email).digest("hex") } : {},
|
|
77726
78238
|
...phone ? {
|
|
77727
|
-
phoneSha256: (0,
|
|
78239
|
+
phoneSha256: (0, import_node_crypto52.createHash)("sha256").update(phone.replace(/\D/g, "")).digest("hex")
|
|
77728
78240
|
} : {}
|
|
77729
78241
|
};
|
|
77730
78242
|
const activationQueued = await queueAnalyticsActivation({
|
|
@@ -78152,7 +78664,7 @@ Submitted the published form.
|
|
|
78152
78664
|
rejectedCount += 1;
|
|
78153
78665
|
continue;
|
|
78154
78666
|
}
|
|
78155
|
-
const digest2 = (0,
|
|
78667
|
+
const digest2 = (0, import_node_crypto52.createHash)("sha256").update(
|
|
78156
78668
|
`${parsed.data.sourceSystem}:${externalId || email || phone || `${fullName}:${index}`}`
|
|
78157
78669
|
).digest("hex").slice(0, 16);
|
|
78158
78670
|
const path6 = `Leads/person-${digest2}`;
|
|
@@ -78610,13 +79122,13 @@ var init_analytics_delivery = __esm({
|
|
|
78610
79122
|
|
|
78611
79123
|
// src/api/scheduled-artifact-owner.ts
|
|
78612
79124
|
function scheduledArtifactOwnerIdForApiKey(apiKey) {
|
|
78613
|
-
return (0,
|
|
79125
|
+
return (0, import_node_crypto53.createHash)("sha256").update(apiKey).digest("hex").slice(0, 24);
|
|
78614
79126
|
}
|
|
78615
|
-
var
|
|
79127
|
+
var import_node_crypto53;
|
|
78616
79128
|
var init_scheduled_artifact_owner = __esm({
|
|
78617
79129
|
"src/api/scheduled-artifact-owner.ts"() {
|
|
78618
79130
|
"use strict";
|
|
78619
|
-
|
|
79131
|
+
import_node_crypto53 = require("crypto");
|
|
78620
79132
|
}
|
|
78621
79133
|
});
|
|
78622
79134
|
|
|
@@ -78673,7 +79185,7 @@ async function ensureScheduledRunViewLinksSchema() {
|
|
|
78673
79185
|
schemaReady2 = true;
|
|
78674
79186
|
}
|
|
78675
79187
|
function tokenHash2(token6) {
|
|
78676
|
-
return (0,
|
|
79188
|
+
return (0, import_node_crypto54.createHash)("sha256").update(token6).digest("hex");
|
|
78677
79189
|
}
|
|
78678
79190
|
function mapRow(row) {
|
|
78679
79191
|
return {
|
|
@@ -78693,9 +79205,9 @@ function mapRow(row) {
|
|
|
78693
79205
|
async function createScheduledRunViewLink(input) {
|
|
78694
79206
|
await ensureScheduledRunViewLinksSchema();
|
|
78695
79207
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
78696
|
-
const token6 = (0,
|
|
79208
|
+
const token6 = (0, import_node_crypto54.randomBytes)(32).toString("base64url");
|
|
78697
79209
|
const record = {
|
|
78698
|
-
shareId: (0,
|
|
79210
|
+
shareId: (0, import_node_crypto54.randomUUID)(),
|
|
78699
79211
|
ownerId: input.ownerId,
|
|
78700
79212
|
runId: input.runId,
|
|
78701
79213
|
artifactId: input.artifactId,
|
|
@@ -78758,11 +79270,11 @@ async function revokeScheduledRunViewLink(ownerId2, runId, shareId, now = /* @__
|
|
|
78758
79270
|
});
|
|
78759
79271
|
return result.rowsAffected > 0;
|
|
78760
79272
|
}
|
|
78761
|
-
var
|
|
79273
|
+
var import_node_crypto54, schemaReady2;
|
|
78762
79274
|
var init_scheduled_run_view_links = __esm({
|
|
78763
79275
|
"src/api/scheduled-run-view-links.ts"() {
|
|
78764
79276
|
"use strict";
|
|
78765
|
-
|
|
79277
|
+
import_node_crypto54 = require("crypto");
|
|
78766
79278
|
init_db();
|
|
78767
79279
|
schemaReady2 = false;
|
|
78768
79280
|
}
|
|
@@ -78828,15 +79340,15 @@ ${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id=
|
|
|
78828
79340
|
html,
|
|
78829
79341
|
filename: `${input.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "personal-authority"}.html`,
|
|
78830
79342
|
bytes,
|
|
78831
|
-
sha256: (0,
|
|
79343
|
+
sha256: (0, import_node_crypto55.createHash)("sha256").update(html).digest("hex"),
|
|
78832
79344
|
generatedAt: generatedAtIso
|
|
78833
79345
|
};
|
|
78834
79346
|
}
|
|
78835
|
-
var
|
|
79347
|
+
var import_node_crypto55;
|
|
78836
79348
|
var init_render2 = __esm({
|
|
78837
79349
|
"src/personal-authority/render.ts"() {
|
|
78838
79350
|
"use strict";
|
|
78839
|
-
|
|
79351
|
+
import_node_crypto55 = require("crypto");
|
|
78840
79352
|
}
|
|
78841
79353
|
});
|
|
78842
79354
|
|
|
@@ -78939,15 +79451,15 @@ ${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id
|
|
|
78939
79451
|
html,
|
|
78940
79452
|
filename: `${input.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "personal-authority"}.html`,
|
|
78941
79453
|
bytes,
|
|
78942
|
-
sha256: (0,
|
|
79454
|
+
sha256: (0, import_node_crypto56.createHash)("sha256").update(html).digest("hex"),
|
|
78943
79455
|
generatedAt: generatedAtIso
|
|
78944
79456
|
};
|
|
78945
79457
|
}
|
|
78946
|
-
var
|
|
79458
|
+
var import_node_crypto56, FONT_STACKS;
|
|
78947
79459
|
var init_render_v2 = __esm({
|
|
78948
79460
|
"src/personal-authority/render-v2.ts"() {
|
|
78949
79461
|
"use strict";
|
|
78950
|
-
|
|
79462
|
+
import_node_crypto56 = require("crypto");
|
|
78951
79463
|
init_contracts();
|
|
78952
79464
|
FONT_STACKS = Object.freeze({
|
|
78953
79465
|
"editorial-serif": "Iowan Old Style, Baskerville, Times New Roman, serif",
|
|
@@ -79063,15 +79575,15 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
|
|
|
79063
79575
|
@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}}
|
|
79064
79576
|
</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>`;
|
|
79065
79577
|
const bytes = Buffer.byteLength(html);
|
|
79066
|
-
const sha2565 = (0,
|
|
79578
|
+
const sha2565 = (0, import_node_crypto57.createHash)("sha256").update(html).digest("hex");
|
|
79067
79579
|
const filename2 = `${brand.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "newsroom"}-news-site.html`;
|
|
79068
79580
|
return { html, filename: filename2, bytes, sha256: sha2565, generatedAt: generatedAtIso };
|
|
79069
79581
|
}
|
|
79070
|
-
var
|
|
79582
|
+
var import_node_crypto57;
|
|
79071
79583
|
var init_render3 = __esm({
|
|
79072
79584
|
"src/newsroom-publisher/render.ts"() {
|
|
79073
79585
|
"use strict";
|
|
79074
|
-
|
|
79586
|
+
import_node_crypto57 = require("crypto");
|
|
79075
79587
|
}
|
|
79076
79588
|
});
|
|
79077
79589
|
|
|
@@ -79163,7 +79675,7 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
79163
79675
|
: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}}
|
|
79164
79676
|
</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>`;
|
|
79165
79677
|
const bytes = Buffer.byteLength(html);
|
|
79166
|
-
const sha2565 = (0,
|
|
79678
|
+
const sha2565 = (0, import_node_crypto58.createHash)("sha256").update(html).digest("hex");
|
|
79167
79679
|
return {
|
|
79168
79680
|
html,
|
|
79169
79681
|
filename: "blog-article.html",
|
|
@@ -79173,11 +79685,11 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
79173
79685
|
generatedAt: generatedAtIso
|
|
79174
79686
|
};
|
|
79175
79687
|
}
|
|
79176
|
-
var
|
|
79688
|
+
var import_node_crypto58;
|
|
79177
79689
|
var init_render4 = __esm({
|
|
79178
79690
|
"src/blog-article/render.ts"() {
|
|
79179
79691
|
"use strict";
|
|
79180
|
-
|
|
79692
|
+
import_node_crypto58 = require("crypto");
|
|
79181
79693
|
}
|
|
79182
79694
|
});
|
|
79183
79695
|
|
|
@@ -79508,7 +80020,7 @@ function policy6() {
|
|
|
79508
80020
|
};
|
|
79509
80021
|
}
|
|
79510
80022
|
function runStorageSegment(runId) {
|
|
79511
|
-
return /^[a-zA-Z0-9_-]{1,160}$/.test(runId) ? runId : `run-${(0,
|
|
80023
|
+
return /^[a-zA-Z0-9_-]{1,160}$/.test(runId) ? runId : `run-${(0, import_node_crypto59.createHash)("sha256").update(runId).digest("hex").slice(0, 32)}`;
|
|
79512
80024
|
}
|
|
79513
80025
|
async function createScheduledRunArtifact(args) {
|
|
79514
80026
|
if (args.rendered.bytes > SCHEDULED_RUN_ARTIFACT_MAX_BYTES) {
|
|
@@ -79549,12 +80061,12 @@ async function readScheduledRunArtifact(args) {
|
|
|
79549
80061
|
if (!window2 || window2.nextOffset !== null || window2.totalBytes > SCHEDULED_RUN_ARTIFACT_MAX_BYTES) return null;
|
|
79550
80062
|
return window2.text;
|
|
79551
80063
|
}
|
|
79552
|
-
var
|
|
80064
|
+
var import_node_crypto59, SCHEDULED_RUN_ARTIFACT_PREFIX, SCHEDULED_RUN_ARTIFACT_DOWNLOAD_TTL_MS, SCHEDULED_RUN_ARTIFACT_MAX_BYTES;
|
|
79553
80065
|
var init_scheduled_run_artifact_store = __esm({
|
|
79554
80066
|
"src/scheduled-artifacts/scheduled-run-artifact-store.ts"() {
|
|
79555
80067
|
"use strict";
|
|
79556
80068
|
init_private_artifacts();
|
|
79557
|
-
|
|
80069
|
+
import_node_crypto59 = require("crypto");
|
|
79558
80070
|
SCHEDULED_RUN_ARTIFACT_PREFIX = "scheduled-run-artifacts/";
|
|
79559
80071
|
SCHEDULED_RUN_ARTIFACT_DOWNLOAD_TTL_MS = 15 * 60 * 1e3;
|
|
79560
80072
|
SCHEDULED_RUN_ARTIFACT_MAX_BYTES = 2e6;
|
|
@@ -79772,7 +80284,7 @@ async function reconcileDiscoveredNangoConnections(identity, discovered) {
|
|
|
79772
80284
|
updated_at = excluded.updated_at
|
|
79773
80285
|
`,
|
|
79774
80286
|
args: [
|
|
79775
|
-
(0,
|
|
80287
|
+
(0, import_node_crypto60.randomUUID)(),
|
|
79776
80288
|
userId,
|
|
79777
80289
|
connection.providerConfigKey,
|
|
79778
80290
|
connection.provider,
|
|
@@ -79843,7 +80355,7 @@ async function recordServiceConnectionHealth(args) {
|
|
|
79843
80355
|
});
|
|
79844
80356
|
await getDb().execute({
|
|
79845
80357
|
sql: `INSERT INTO service_connection_health_events (id, connection_id, operational_status, failure_code, retryable, evidence_source) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
79846
|
-
args: [(0,
|
|
80358
|
+
args: [(0, import_node_crypto60.randomUUID)(), args.connectionId, args.operationalStatus, args.failureCode ?? null, args.retryable == null ? null : args.retryable ? 1 : 0, args.evidenceSource]
|
|
79847
80359
|
});
|
|
79848
80360
|
}
|
|
79849
80361
|
async function setServiceConnectionActions(identity, connectionId, enabled) {
|
|
@@ -79883,7 +80395,7 @@ async function claimServiceConnectionAction(args) {
|
|
|
79883
80395
|
if (!connection) throw new Error("service_connection_not_found");
|
|
79884
80396
|
const inserted = await getDb().execute({
|
|
79885
80397
|
sql: `INSERT OR IGNORE INTO service_connection_action_audit (id, connection_id, user_id, tool, request_id, status, request_digest) VALUES (?, ?, ?, ?, ?, 'started', ?)`,
|
|
79886
|
-
args: [(0,
|
|
80398
|
+
args: [(0, import_node_crypto60.randomUUID)(), connection.id, connection.userId, args.tool, args.requestId, args.requestDigest]
|
|
79887
80399
|
});
|
|
79888
80400
|
if (Number(inserted.rowsAffected ?? 0) === 1) return { claimed: true };
|
|
79889
80401
|
const existing = await getDb().execute({
|
|
@@ -79908,11 +80420,11 @@ async function claimServiceConnectionAction(args) {
|
|
|
79908
80420
|
...result !== void 0 ? { result } : {}
|
|
79909
80421
|
};
|
|
79910
80422
|
}
|
|
79911
|
-
var
|
|
80423
|
+
var import_node_crypto60, schemaReady3, schemaDb6;
|
|
79912
80424
|
var init_service_connections = __esm({
|
|
79913
80425
|
"src/api/service-connections.ts"() {
|
|
79914
80426
|
"use strict";
|
|
79915
|
-
|
|
80427
|
+
import_node_crypto60 = require("crypto");
|
|
79916
80428
|
init_db();
|
|
79917
80429
|
schemaReady3 = null;
|
|
79918
80430
|
schemaDb6 = null;
|
|
@@ -79926,8 +80438,8 @@ function signingSecret() {
|
|
|
79926
80438
|
return secret2;
|
|
79927
80439
|
}
|
|
79928
80440
|
function schedulerIntegrationSignature(args) {
|
|
79929
|
-
const bodyHash = (0,
|
|
79930
|
-
return (0,
|
|
80441
|
+
const bodyHash = (0, import_node_crypto61.createHash)("sha256").update(args.body).digest("hex");
|
|
80442
|
+
return (0, import_node_crypto61.createHmac)("sha256", args.secret).update(`${args.method.toUpperCase()}
|
|
79931
80443
|
${args.path}
|
|
79932
80444
|
${args.timestamp}
|
|
79933
80445
|
${args.nonce}
|
|
@@ -79974,17 +80486,17 @@ async function verifySchedulerIntegrationRequest(request, rawBody) {
|
|
|
79974
80486
|
});
|
|
79975
80487
|
const suppliedBytes = Buffer.from(signature, "hex");
|
|
79976
80488
|
const expectedBytes = Buffer.from(expected, "hex");
|
|
79977
|
-
if (suppliedBytes.length !== expectedBytes.length || !(0,
|
|
80489
|
+
if (suppliedBytes.length !== expectedBytes.length || !(0, import_node_crypto61.timingSafeEqual)(suppliedBytes, expectedBytes)) {
|
|
79978
80490
|
throw new SchedulerIntegrationAuthError("invalid_signature");
|
|
79979
80491
|
}
|
|
79980
80492
|
await claimNonce(nonce, timestampMs);
|
|
79981
80493
|
return { requestId };
|
|
79982
80494
|
}
|
|
79983
|
-
var
|
|
80495
|
+
var import_node_crypto61, MAX_CLOCK_SKEW_MS, SchedulerIntegrationAuthError;
|
|
79984
80496
|
var init_scheduler_integration_auth = __esm({
|
|
79985
80497
|
"src/api/scheduler-integration-auth.ts"() {
|
|
79986
80498
|
"use strict";
|
|
79987
|
-
|
|
80499
|
+
import_node_crypto61 = require("crypto");
|
|
79988
80500
|
init_db();
|
|
79989
80501
|
init_service_connections();
|
|
79990
80502
|
MAX_CLOCK_SKEW_MS = 5 * 60 * 1e3;
|
|
@@ -80146,7 +80658,7 @@ function requestedSiteMaxPages(maxPages) {
|
|
|
80146
80658
|
return Math.min(ABSOLUTE_SITE_MAX_PAGES, Math.max(1, maxPages ?? DEFAULT_SITE_MAX_PAGES));
|
|
80147
80659
|
}
|
|
80148
80660
|
function shouldRunSiteExtractInBackground(input) {
|
|
80149
|
-
return input.background === true || input.downloadImages === true || input.preserveMedia === true || requestedSiteMaxPages(input.maxPages) > MAX_SYNCHRONOUS_SITE_PAGES;
|
|
80661
|
+
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;
|
|
80150
80662
|
}
|
|
80151
80663
|
var MAX_SYNCHRONOUS_SITE_PAGES, DEFAULT_SITE_MAX_PAGES, ABSOLUTE_SITE_MAX_PAGES;
|
|
80152
80664
|
var init_site_extract_policy = __esm({
|
|
@@ -80292,7 +80804,7 @@ async function fetchMedia(rawUrl, expectedType) {
|
|
|
80292
80804
|
finalUrl: checked.parsed.href,
|
|
80293
80805
|
width: dimensions?.width ?? null,
|
|
80294
80806
|
height: dimensions?.height ?? null,
|
|
80295
|
-
sha256: (0,
|
|
80807
|
+
sha256: (0, import_node_crypto62.createHash)("sha256").update(bytes).digest("hex")
|
|
80296
80808
|
};
|
|
80297
80809
|
}
|
|
80298
80810
|
throw new Error("media_redirect_rejected");
|
|
@@ -80406,7 +80918,7 @@ async function packagePageMedia(args) {
|
|
|
80406
80918
|
files.push({ path: "summary.json", content: Buffer.from(JSON.stringify(summary, null, 2)) });
|
|
80407
80919
|
files.push({ path: "media.jsonl", content: Buffer.from(cleanAssets.map((asset) => JSON.stringify(asset)).join("\n") + "\n") });
|
|
80408
80920
|
const archive = await zipBuffer2(files);
|
|
80409
|
-
const id = (0,
|
|
80921
|
+
const id = (0, import_node_crypto62.randomBytes)(6).toString("hex");
|
|
80410
80922
|
const pointer = await createPrivateArtifact({
|
|
80411
80923
|
policy: policy7(),
|
|
80412
80924
|
ownerId: args.ownerId,
|
|
@@ -80419,11 +80931,11 @@ async function packagePageMedia(args) {
|
|
|
80419
80931
|
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);
|
|
80420
80932
|
return { media: args.media, artifact: { ...pointer, localPath } };
|
|
80421
80933
|
}
|
|
80422
|
-
var
|
|
80934
|
+
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;
|
|
80423
80935
|
var init_page_media_artifacts = __esm({
|
|
80424
80936
|
"src/api/page-media-artifacts.ts"() {
|
|
80425
80937
|
"use strict";
|
|
80426
|
-
|
|
80938
|
+
import_node_crypto62 = require("crypto");
|
|
80427
80939
|
import_node_os15 = require("os");
|
|
80428
80940
|
import_node_path22 = require("path");
|
|
80429
80941
|
import_p_limit7 = __toESM(require("p-limit"), 1);
|
|
@@ -80532,7 +81044,7 @@ var init_site_extract_reconciliation = __esm({
|
|
|
80532
81044
|
|
|
80533
81045
|
// src/api/page-diff.ts
|
|
80534
81046
|
function sha256Hex(value) {
|
|
80535
|
-
return (0,
|
|
81047
|
+
return (0, import_node_crypto63.createHash)("sha256").update(value).digest("hex");
|
|
80536
81048
|
}
|
|
80537
81049
|
function truncateForStorage(value, maxChars = MAX_SNAPSHOT_CONTENT_CHARS) {
|
|
80538
81050
|
if (value.length <= maxChars) return { value, truncated: false };
|
|
@@ -80589,11 +81101,11 @@ function diffPageContent(oldContent, newContent) {
|
|
|
80589
81101
|
totalChangedLineCount
|
|
80590
81102
|
};
|
|
80591
81103
|
}
|
|
80592
|
-
var
|
|
81104
|
+
var import_node_crypto63, import_diff, MAX_SNAPSHOT_CONTENT_CHARS, MAX_DIFF_HUNKS, MAX_DIFF_LINES_PER_RESPONSE;
|
|
80593
81105
|
var init_page_diff = __esm({
|
|
80594
81106
|
"src/api/page-diff.ts"() {
|
|
80595
81107
|
"use strict";
|
|
80596
|
-
|
|
81108
|
+
import_node_crypto63 = require("crypto");
|
|
80597
81109
|
import_diff = require("diff");
|
|
80598
81110
|
MAX_SNAPSHOT_CONTENT_CHARS = 25e4;
|
|
80599
81111
|
MAX_DIFF_HUNKS = 200;
|
|
@@ -80667,7 +81179,7 @@ var init_scrape_vault_sink = __esm({
|
|
|
80667
81179
|
|
|
80668
81180
|
// src/api/scrape-image-sink.ts
|
|
80669
81181
|
function idempotencyKey3(userId, vault, input) {
|
|
80670
|
-
return `scrape-image-${(0,
|
|
81182
|
+
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")}`;
|
|
80671
81183
|
}
|
|
80672
81184
|
async function persistScrapeImagesToMemory(user, inputs, vault) {
|
|
80673
81185
|
const selected = inputs.slice(0, MAX_IMAGES_PER_SCRAPE);
|
|
@@ -80709,11 +81221,11 @@ async function persistScrapeImagesToMemory(user, inputs, vault) {
|
|
|
80709
81221
|
assets
|
|
80710
81222
|
};
|
|
80711
81223
|
}
|
|
80712
|
-
var
|
|
81224
|
+
var import_node_crypto64, MAX_IMAGES_PER_SCRAPE;
|
|
80713
81225
|
var init_scrape_image_sink = __esm({
|
|
80714
81226
|
"src/api/scrape-image-sink.ts"() {
|
|
80715
81227
|
"use strict";
|
|
80716
|
-
|
|
81228
|
+
import_node_crypto64 = require("crypto");
|
|
80717
81229
|
init_memory();
|
|
80718
81230
|
MAX_IMAGES_PER_SCRAPE = 25;
|
|
80719
81231
|
}
|
|
@@ -81166,7 +81678,7 @@ function canonicalJson(value) {
|
|
|
81166
81678
|
return JSON.stringify(value);
|
|
81167
81679
|
}
|
|
81168
81680
|
function sha2563(value) {
|
|
81169
|
-
return (0,
|
|
81681
|
+
return (0, import_node_crypto65.createHash)("sha256").update(value).digest("hex");
|
|
81170
81682
|
}
|
|
81171
81683
|
function sensitiveKey(key) {
|
|
81172
81684
|
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
@@ -81381,11 +81893,11 @@ async function importServiceConnectionToMemory(identity, input, dependencies) {
|
|
|
81381
81893
|
...!searchReady ? { warning: "The snapshot was stored, but no search chunks were indexed yet." } : {}
|
|
81382
81894
|
};
|
|
81383
81895
|
}
|
|
81384
|
-
var
|
|
81896
|
+
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;
|
|
81385
81897
|
var init_connection_memory_import = __esm({
|
|
81386
81898
|
"src/api/connection-memory-import.ts"() {
|
|
81387
81899
|
"use strict";
|
|
81388
|
-
|
|
81900
|
+
import_node_crypto65 = require("crypto");
|
|
81389
81901
|
init_slugify();
|
|
81390
81902
|
CONNECTION_MEMORY_IMPORT_MAX_ARGS_BYTES = 64 * 1024;
|
|
81391
81903
|
CONNECTION_MEMORY_IMPORT_MAX_RESULT_BYTES = 1e6;
|
|
@@ -81469,7 +81981,7 @@ var init_scrape_blob_cleanup = __esm({
|
|
|
81469
81981
|
|
|
81470
81982
|
// src/api/site-export-reader.ts
|
|
81471
81983
|
function sha2564(value) {
|
|
81472
|
-
return (0,
|
|
81984
|
+
return (0, import_node_crypto66.createHash)("sha256").update(value).digest("hex");
|
|
81473
81985
|
}
|
|
81474
81986
|
function publicPageRecord(page) {
|
|
81475
81987
|
const { bodyMarkdown: _body, contentRef: _contentRef, discoveryLinks: _discovery, ...metadata } = page;
|
|
@@ -81577,11 +82089,11 @@ async function readOwnedSiteExportImage(input) {
|
|
|
81577
82089
|
if (!bytes || artifact.sha256 && sha2564(bytes) !== artifact.sha256) return null;
|
|
81578
82090
|
return { bytes, artifact };
|
|
81579
82091
|
}
|
|
81580
|
-
var
|
|
82092
|
+
var import_node_crypto66, SiteExportFormatUnavailableError;
|
|
81581
82093
|
var init_site_export_reader = __esm({
|
|
81582
82094
|
"src/api/site-export-reader.ts"() {
|
|
81583
82095
|
"use strict";
|
|
81584
|
-
|
|
82096
|
+
import_node_crypto66 = require("crypto");
|
|
81585
82097
|
init_site_extract_repository();
|
|
81586
82098
|
init_site_extract_content_store();
|
|
81587
82099
|
init_site_extract_artifacts();
|
|
@@ -81732,7 +82244,7 @@ function finitePositive(value, fallback) {
|
|
|
81732
82244
|
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
81733
82245
|
}
|
|
81734
82246
|
async function collectConnectedDataExport(args) {
|
|
81735
|
-
const exportId = (0,
|
|
82247
|
+
const exportId = (0, import_node_crypto67.randomUUID)();
|
|
81736
82248
|
const now = args.now ?? Date.now;
|
|
81737
82249
|
const startedAt = now();
|
|
81738
82250
|
const budgetMs = finitePositive(CONNECTED_DATA_EXPORT_BUDGET_MS, 24e4);
|
|
@@ -81846,11 +82358,11 @@ ${lines.length ? `${lines.join("\n")}
|
|
|
81846
82358
|
untrustedContent: true
|
|
81847
82359
|
};
|
|
81848
82360
|
}
|
|
81849
|
-
var
|
|
82361
|
+
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;
|
|
81850
82362
|
var init_connected_data_export = __esm({
|
|
81851
82363
|
"src/api/connected-data-export.ts"() {
|
|
81852
82364
|
"use strict";
|
|
81853
|
-
|
|
82365
|
+
import_node_crypto67 = require("crypto");
|
|
81854
82366
|
CONNECTED_DATA_INLINE_BUDGET_BYTES = Number(
|
|
81855
82367
|
process.env.MCP_SCRAPER_CONNECTED_DATA_INLINE_BUDGET_BYTES ?? 5e4
|
|
81856
82368
|
);
|
|
@@ -81964,7 +82476,7 @@ async function exportSearchConsoleTableData(args) {
|
|
|
81964
82476
|
offset += rows.length;
|
|
81965
82477
|
if (stoppedForBytes || rows.length < limit || offset >= matchedRows) break;
|
|
81966
82478
|
}
|
|
81967
|
-
const exportId = (0,
|
|
82479
|
+
const exportId = (0, import_node_crypto68.randomUUID)();
|
|
81968
82480
|
const artifact = await args.writeArtifact({
|
|
81969
82481
|
ownerId: args.ownerId,
|
|
81970
82482
|
exportId,
|
|
@@ -81986,11 +82498,11 @@ async function exportSearchConsoleTableData(args) {
|
|
|
81986
82498
|
warnings
|
|
81987
82499
|
};
|
|
81988
82500
|
}
|
|
81989
|
-
var
|
|
82501
|
+
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;
|
|
81990
82502
|
var init_search_console_table_export = __esm({
|
|
81991
82503
|
"src/api/search-console-table-export.ts"() {
|
|
81992
82504
|
"use strict";
|
|
81993
|
-
|
|
82505
|
+
import_node_crypto68 = require("crypto");
|
|
81994
82506
|
SEARCH_CONSOLE_TABLE_EXPORT_MAX_ROWS = 5e4;
|
|
81995
82507
|
SEARCH_CONSOLE_TABLE_EXPORT_PAGE_SIZE = 2e3;
|
|
81996
82508
|
SEARCH_CONSOLE_TABLE_EXPORT_MAX_BYTES = 50 * 1024 * 1024;
|
|
@@ -83169,7 +83681,7 @@ async function listNangoToolsDirect(identity, connectionId) {
|
|
|
83169
83681
|
});
|
|
83170
83682
|
const readTools = [...policies.values()].filter((policy8) => policy8.classification === "read").map((policy8) => policy8.name);
|
|
83171
83683
|
const actionTools = [...policies.values()].filter((policy8) => policy8.classification === "action").map((policy8) => policy8.name);
|
|
83172
|
-
const revision = (0,
|
|
83684
|
+
const revision = (0, import_node_crypto69.createHash)("sha256").update(JSON.stringify(tools.map((tool) => ({ name: tool.name, inputSchema: tool.inputSchema })))).digest("hex");
|
|
83173
83685
|
await updateServiceConnectionTools(connection.id, readTools, actionTools, revision);
|
|
83174
83686
|
const refreshed = await getOwnedServiceConnection(identity, connection.id);
|
|
83175
83687
|
return { connection: refreshed ?? { ...connection, readTools, actionTools, toolRevision: revision }, tools };
|
|
@@ -83196,8 +83708,8 @@ async function callNangoToolDirect(args) {
|
|
|
83196
83708
|
identity: args.identity,
|
|
83197
83709
|
ratePolicyVersion: CONNECTED_USAGE_RATE_POLICY_VERSION
|
|
83198
83710
|
});
|
|
83199
|
-
const requestId = args.requestId?.trim() || (0,
|
|
83200
|
-
const idempotencyKey4 = `main-nango:${(0,
|
|
83711
|
+
const requestId = args.requestId?.trim() || (0, import_node_crypto69.randomUUID)();
|
|
83712
|
+
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")}`;
|
|
83201
83713
|
const startedAt = /* @__PURE__ */ new Date();
|
|
83202
83714
|
const started = performance.now();
|
|
83203
83715
|
let result;
|
|
@@ -83222,7 +83734,7 @@ async function callNangoToolDirect(args) {
|
|
|
83222
83734
|
toolName: args.tool,
|
|
83223
83735
|
operationKind: args.operationKind ?? args.classification,
|
|
83224
83736
|
outcome: providerError ? "error" : "partial",
|
|
83225
|
-
requestId: requestId.length <= 200 ? requestId : (0,
|
|
83737
|
+
requestId: requestId.length <= 200 ? requestId : (0, import_node_crypto69.createHash)("sha256").update(requestId).digest("hex"),
|
|
83226
83738
|
startedAt: startedAt.toISOString(),
|
|
83227
83739
|
completedAt: completedAt.toISOString()
|
|
83228
83740
|
}
|
|
@@ -83264,15 +83776,15 @@ async function describeNangoToolDirect(identity, connectionId, toolName) {
|
|
|
83264
83776
|
providerContractHash: MAIN_INTEGRATION_CONTRACT_HASH,
|
|
83265
83777
|
protocolVersion: null,
|
|
83266
83778
|
schemaSource: "live_tools_list",
|
|
83267
|
-
schemaHash: (0,
|
|
83779
|
+
schemaHash: (0, import_node_crypto69.createHash)("sha256").update(JSON.stringify(projected)).digest("hex"),
|
|
83268
83780
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
83269
83781
|
};
|
|
83270
83782
|
}
|
|
83271
|
-
var
|
|
83783
|
+
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;
|
|
83272
83784
|
var init_main_nango_transport = __esm({
|
|
83273
83785
|
"src/api/main-nango-transport.ts"() {
|
|
83274
83786
|
"use strict";
|
|
83275
|
-
|
|
83787
|
+
import_node_crypto69 = require("crypto");
|
|
83276
83788
|
import_client15 = require("@modelcontextprotocol/client");
|
|
83277
83789
|
init_service_connections();
|
|
83278
83790
|
init_connected_usage_billing();
|
|
@@ -83896,8 +84408,8 @@ async function setScheduleConnectionActionsEnabled(identity, connectionId, enabl
|
|
|
83896
84408
|
return data.connection.actionsEnabled === true;
|
|
83897
84409
|
}
|
|
83898
84410
|
async function callScheduleConnectionAction(identity, connectionId, input, tool, idempotencyKey4) {
|
|
83899
|
-
const requestId = `main-connected-action:${(0,
|
|
83900
|
-
const requestDigest = (0,
|
|
84411
|
+
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")}`;
|
|
84412
|
+
const requestDigest = (0, import_node_crypto70.createHash)("sha256").update(connectionId).update("\0").update(tool?.trim() ?? "").update("\0").update(canonicalJson2(input)).digest("hex");
|
|
83901
84413
|
if (mainOwnsIntegrations()) {
|
|
83902
84414
|
const selectedTool = tool?.trim();
|
|
83903
84415
|
if (!selectedTool) throw new NangoControlError("An action tool is required.", 400, "invalid_request", false);
|
|
@@ -84048,7 +84560,7 @@ function canonicalJson2(value) {
|
|
|
84048
84560
|
return JSON.stringify(value);
|
|
84049
84561
|
}
|
|
84050
84562
|
function projectedToolSchemaHash(tool) {
|
|
84051
|
-
return (0,
|
|
84563
|
+
return (0, import_node_crypto70.createHash)("sha256").update(canonicalJson2(tool)).digest("hex");
|
|
84052
84564
|
}
|
|
84053
84565
|
async function describeNangoTool(identity, connectionId, tool, fresh) {
|
|
84054
84566
|
if (mainOwnsIntegrations()) {
|
|
@@ -84325,11 +84837,11 @@ async function callMainOwnedExportPage(identity, input) {
|
|
|
84325
84837
|
untrustedContent: true
|
|
84326
84838
|
};
|
|
84327
84839
|
}
|
|
84328
|
-
var
|
|
84840
|
+
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;
|
|
84329
84841
|
var init_nango_control = __esm({
|
|
84330
84842
|
"src/api/nango-control.ts"() {
|
|
84331
84843
|
"use strict";
|
|
84332
|
-
|
|
84844
|
+
import_node_crypto70 = require("crypto");
|
|
84333
84845
|
init_connected_data_export();
|
|
84334
84846
|
init_slack_connected_data_export();
|
|
84335
84847
|
init_main_nango_transport();
|
|
@@ -84685,7 +85197,7 @@ async function callResendRead(identity, connectionId, tool, args) {
|
|
|
84685
85197
|
return isRecord5(data) ? data.result ?? data : data;
|
|
84686
85198
|
}
|
|
84687
85199
|
async function callResendAction(identity, connectionId, tool, input, idempotencyKey4) {
|
|
84688
|
-
const requestId = `main-resend-action:${(0,
|
|
85200
|
+
const requestId = `main-resend-action:${(0, import_node_crypto71.createHash)("sha256").update(identity).update("\0").update(idempotencyKey4.trim()).digest("hex")}`;
|
|
84689
85201
|
const body = await controlRequest2("/api/internal/resend/actions/call", {
|
|
84690
85202
|
method: "POST",
|
|
84691
85203
|
headers: { "x-request-id": requestId },
|
|
@@ -84750,12 +85262,12 @@ async function callResendExportPage(identity, input) {
|
|
|
84750
85262
|
untrustedContent: true
|
|
84751
85263
|
};
|
|
84752
85264
|
}
|
|
84753
|
-
var
|
|
85265
|
+
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;
|
|
84754
85266
|
var init_resend_control = __esm({
|
|
84755
85267
|
"src/api/resend-control.ts"() {
|
|
84756
85268
|
"use strict";
|
|
84757
85269
|
init_connected_data_export();
|
|
84758
|
-
|
|
85270
|
+
import_node_crypto71 = require("crypto");
|
|
84759
85271
|
DEFAULT_CONNECTION_CONTROL_URL = "https://mcp-scraper-scheduler.vercel.app";
|
|
84760
85272
|
RESEND_PROVIDER_CONFIG_KEY = "resend";
|
|
84761
85273
|
RESEND_LOGO_URL = "https://cdn.resend.com/brand/resend-icon-black.svg";
|
|
@@ -85362,7 +85874,7 @@ function settleWithinTickBudget(label, unfinished, work, onDeadlineOrError) {
|
|
|
85362
85874
|
);
|
|
85363
85875
|
});
|
|
85364
85876
|
}
|
|
85365
|
-
var import_resend3,
|
|
85877
|
+
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;
|
|
85366
85878
|
var init_server = __esm({
|
|
85367
85879
|
"src/api/server.ts"() {
|
|
85368
85880
|
"use strict";
|
|
@@ -85375,7 +85887,7 @@ var init_server = __esm({
|
|
|
85375
85887
|
init_og();
|
|
85376
85888
|
import_resend3 = require("resend");
|
|
85377
85889
|
init_url_utils();
|
|
85378
|
-
|
|
85890
|
+
import_node_crypto72 = require("crypto");
|
|
85379
85891
|
init_kpo_extractor();
|
|
85380
85892
|
init_screenshot();
|
|
85381
85893
|
init_media_extractor();
|
|
@@ -86936,7 +87448,7 @@ var init_server = __esm({
|
|
|
86936
87448
|
if (!harvestOk) return c.json(insufficientBalanceResponse(harvestBal, harvestCost), 402);
|
|
86937
87449
|
jobId2 = await createJob(user.id, options.query, { ...options, billingHoldMc: harvestCost }, body.callback_url);
|
|
86938
87450
|
} else {
|
|
86939
|
-
jobId2 = (0,
|
|
87451
|
+
jobId2 = (0, import_node_crypto72.randomUUID)();
|
|
86940
87452
|
const billingDebitKey = `paa-harvest:${jobId2}:hold`;
|
|
86941
87453
|
const description = `PAA harvest: ${options.query}`.slice(0, 500);
|
|
86942
87454
|
const hold = await debitMcIdempotent(
|
|
@@ -87771,6 +88283,13 @@ var init_server = __esm({
|
|
|
87771
88283
|
const bodyResult = ExtractSiteBodySchema.safeParse(raw);
|
|
87772
88284
|
if (!bodyResult.success) return c.json({ error: bodyResult.error.issues[0]?.message ?? "Invalid request" }, 400);
|
|
87773
88285
|
const body = bodyResult.data;
|
|
88286
|
+
if (body.semanticSimilarity && !process.env.JINA_API_KEY?.trim()) {
|
|
88287
|
+
return c.json({
|
|
88288
|
+
error: "Semantic site similarity is not configured on this deployment.",
|
|
88289
|
+
errorCode: "semantic_similarity_unconfigured",
|
|
88290
|
+
retryable: false
|
|
88291
|
+
}, 503);
|
|
88292
|
+
}
|
|
87774
88293
|
if (body.preserveMedia !== void 0 && body.downloadImages !== void 0 && body.preserveMedia !== body.downloadImages) {
|
|
87775
88294
|
return c.json({ error: "preserveMedia conflicts with deprecated downloadImages." }, 400);
|
|
87776
88295
|
}
|
|
@@ -87824,7 +88343,12 @@ var init_server = __esm({
|
|
|
87824
88343
|
maxPages: requestedMaxPages,
|
|
87825
88344
|
rotateProxyEvery: body.rotateProxyEvery ?? 10,
|
|
87826
88345
|
formats: [...body.formats ?? []].sort(),
|
|
87827
|
-
downloadImages
|
|
88346
|
+
downloadImages,
|
|
88347
|
+
renderJavaScript: body.renderJavaScript === true,
|
|
88348
|
+
captureRenderedDom: body.captureRenderedDom === true,
|
|
88349
|
+
semanticSimilarity: body.semanticSimilarity === true,
|
|
88350
|
+
similarityThreshold: body.similarityThreshold ?? null,
|
|
88351
|
+
similarityMaxPairs: body.similarityMaxPairs ?? null
|
|
87828
88352
|
}));
|
|
87829
88353
|
const prepared = await prepareSiteExtractStart({
|
|
87830
88354
|
jobId: jobId2,
|
|
@@ -87838,6 +88362,11 @@ var init_server = __esm({
|
|
|
87838
88362
|
urlsPerBrowser: body.rotateProxyEvery ?? 10,
|
|
87839
88363
|
formats: body.formats,
|
|
87840
88364
|
downloadImages,
|
|
88365
|
+
renderJavaScript: body.renderJavaScript === true,
|
|
88366
|
+
captureRenderedDom: body.captureRenderedDom === true,
|
|
88367
|
+
semanticSimilarity: body.semanticSimilarity === true,
|
|
88368
|
+
similarityThreshold: body.similarityThreshold,
|
|
88369
|
+
similarityMaxPairs: body.similarityMaxPairs,
|
|
87841
88370
|
debitKey: `site-extract:${user.id}:${jobId2}:hold`,
|
|
87842
88371
|
waybackReplay: waybackReplay && !body.wayback ? {
|
|
87843
88372
|
timestamp: waybackReplay.timestamp,
|
|
@@ -87931,8 +88460,10 @@ var init_server = __esm({
|
|
|
87931
88460
|
startUrl: crawlStartUrl,
|
|
87932
88461
|
maxPages: siteMaxPages,
|
|
87933
88462
|
seedUrls: waybackCaptures?.map((capture) => capture.rawReplayUrl),
|
|
87934
|
-
kernelApiKey: rotateProxies || wantsBranding || body.browserFallback || body.kernelFallback ? browserServiceApiKey() : void 0,
|
|
88463
|
+
kernelApiKey: rotateProxies || wantsBranding || body.browserFallback || body.kernelFallback || body.renderJavaScript || body.captureRenderedDom || body.semanticSimilarity ? browserServiceApiKey() : void 0,
|
|
87935
88464
|
formats: body.formats,
|
|
88465
|
+
forceBrowserRender: body.renderJavaScript || body.captureRenderedDom || body.semanticSimilarity,
|
|
88466
|
+
captureRenderedDom: body.captureRenderedDom,
|
|
87936
88467
|
...rotateProxies ? {
|
|
87937
88468
|
rotateProxyEvery: body.rotateProxyEvery ?? 30,
|
|
87938
88469
|
parallelism: concurrencyLimitForUser(user)
|