mcp-scraper 0.19.0 → 0.20.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/dist/bin/api-server.cjs +189 -37
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +3 -3
- 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 +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +100 -14
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +4 -4
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +3 -3
- package/dist/{chunk-GL4BW4CP.js → chunk-22VEGGTW.js} +21 -9
- package/dist/{chunk-GL4BW4CP.js.map → chunk-22VEGGTW.js.map} +1 -1
- package/dist/{chunk-RUGJE5EB.js → chunk-EJK25QOW.js} +2 -2
- package/dist/chunk-JWIE5NCR.js +284 -0
- package/dist/chunk-JWIE5NCR.js.map +1 -0
- package/dist/{chunk-O2S5TOCG.js → chunk-KE7KE2Q2.js} +102 -16
- package/dist/chunk-KE7KE2Q2.js.map +1 -0
- package/dist/chunk-PZB3TJWK.js +7 -0
- package/dist/chunk-PZB3TJWK.js.map +1 -0
- package/dist/{chunk-D7ZT27HY.js → chunk-UN7VMHZL.js} +2 -2
- package/dist/{chunk-2HDMYW4B.js → chunk-XDFSLSSH.js} +2 -2
- package/dist/{chunk-HE2LQPJ2.js → chunk-ZRKFW5FB.js} +2 -2
- package/dist/{db-LIOTIWVN.js → db-YHZYG7D2.js} +2 -2
- package/dist/{extract-bundle-U4D5LW5W.js → extract-bundle-OSUPAHCE.js} +58 -5
- package/dist/extract-bundle-OSUPAHCE.js.map +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/{server-VWXDE64Y.js → server-VDWIPV7F.js} +37 -310
- package/dist/server-VDWIPV7F.js.map +1 -0
- package/dist/{site-extract-repository-NVSZH35Y.js → site-extract-repository-GWKGK46Z.js} +3 -3
- package/dist/{worker-AM2DHUWG.js → worker-O5PZTTPY.js} +5 -5
- package/docs/mcp-tool-manifest.generated.json +166 -23
- package/docs/specs/meta-ad-creative-media-resolution-spec.md +3 -3
- package/docs/specs/unified-credit-and-scheduled-execution-billing-spec.md +1007 -0
- package/package.json +1 -1
- package/dist/chunk-O2S5TOCG.js.map +0 -1
- package/dist/chunk-OQHYDW4Q.js +0 -7
- package/dist/chunk-OQHYDW4Q.js.map +0 -1
- package/dist/extract-bundle-U4D5LW5W.js.map +0 -1
- package/dist/server-VWXDE64Y.js.map +0 -1
- /package/dist/{chunk-RUGJE5EB.js.map → chunk-EJK25QOW.js.map} +0 -0
- /package/dist/{chunk-D7ZT27HY.js.map → chunk-UN7VMHZL.js.map} +0 -0
- /package/dist/{chunk-2HDMYW4B.js.map → chunk-XDFSLSSH.js.map} +0 -0
- /package/dist/{chunk-HE2LQPJ2.js.map → chunk-ZRKFW5FB.js.map} +0 -0
- /package/dist/{db-LIOTIWVN.js.map → db-YHZYG7D2.js.map} +0 -0
- /package/dist/{site-extract-repository-NVSZH35Y.js.map → site-extract-repository-GWKGK46Z.js.map} +0 -0
- /package/dist/{worker-AM2DHUWG.js.map → worker-O5PZTTPY.js.map} +0 -0
package/dist/bin/api-server.cjs
CHANGED
|
@@ -5271,18 +5271,30 @@ async function ledgerExistsForStripePI(stripePI) {
|
|
|
5271
5271
|
});
|
|
5272
5272
|
return res.rows.length > 0;
|
|
5273
5273
|
}
|
|
5274
|
-
async function reconcileBalanceMc(userId) {
|
|
5274
|
+
async function reconcileBalanceMc(userId, knownBalanceMc) {
|
|
5275
5275
|
const db = getDb();
|
|
5276
|
-
await ensureMigrated(Number(userId));
|
|
5277
5276
|
const res = await db.execute({
|
|
5278
|
-
sql: `SELECT
|
|
5277
|
+
sql: `SELECT
|
|
5278
|
+
COUNT(*) AS lot_count,
|
|
5279
|
+
COALESCE(SUM(CASE WHEN remaining_mc > 0 AND expires_at > datetime('now') THEN remaining_mc ELSE 0 END), 0) AS balance_mc
|
|
5280
|
+
FROM credit_lots WHERE user_id = ?`,
|
|
5279
5281
|
args: [userId]
|
|
5280
5282
|
});
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5283
|
+
let balanceMc = Number(res.rows[0]?.balance_mc ?? 0);
|
|
5284
|
+
if (Number(res.rows[0]?.lot_count ?? 0) === 0) {
|
|
5285
|
+
await ensureMigrated(Number(userId));
|
|
5286
|
+
const migrated = await db.execute({
|
|
5287
|
+
sql: `SELECT COALESCE(SUM(remaining_mc), 0) AS balance_mc FROM credit_lots WHERE user_id = ? AND remaining_mc > 0 AND expires_at > datetime('now')`,
|
|
5288
|
+
args: [userId]
|
|
5289
|
+
});
|
|
5290
|
+
balanceMc = Number(migrated.rows[0]?.balance_mc ?? 0);
|
|
5291
|
+
}
|
|
5292
|
+
if (knownBalanceMc !== balanceMc) {
|
|
5293
|
+
await db.execute({
|
|
5294
|
+
sql: "UPDATE users SET balance_mc = ? WHERE id = ? AND balance_mc != ?",
|
|
5295
|
+
args: [balanceMc, userId, balanceMc]
|
|
5296
|
+
});
|
|
5297
|
+
}
|
|
5286
5298
|
return balanceMc;
|
|
5287
5299
|
}
|
|
5288
5300
|
var import_http, import_node_crypto, import_zod, DB_URL, DB_TOKEN, _db, _rateLimitSchemaReady, CREDIT_LOT_TTL, SiteAuditJobRowSchema, SiteAuditPhaseLogRowSchema;
|
|
@@ -6372,8 +6384,8 @@ async function downloadAsset(url, destDir, filename) {
|
|
|
6372
6384
|
}
|
|
6373
6385
|
const writer = (0, import_node_fs.createWriteStream)(dest);
|
|
6374
6386
|
await (0, import_promises2.pipeline)(import_node_stream.Readable.fromWeb(res.body), writer);
|
|
6375
|
-
const { statSync:
|
|
6376
|
-
const sizeBytes =
|
|
6387
|
+
const { statSync: statSync3 } = await import("fs");
|
|
6388
|
+
const sizeBytes = statSync3(dest).size;
|
|
6377
6389
|
return { savedPath: dest, sizeBytes, mimeType };
|
|
6378
6390
|
}
|
|
6379
6391
|
async function harvestPageMedia(html, pageUrl, options = {}) {
|
|
@@ -10746,6 +10758,15 @@ function registrableDomain2(host) {
|
|
|
10746
10758
|
const parts = h.split(".");
|
|
10747
10759
|
return parts.length <= 2 ? h : parts.slice(-2).join(".");
|
|
10748
10760
|
}
|
|
10761
|
+
function safeImageFilename(url, index) {
|
|
10762
|
+
try {
|
|
10763
|
+
const u = new URL(url);
|
|
10764
|
+
const base = (0, import_node_path3.basename)(u.pathname).replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
10765
|
+
return base || `image-${index}`;
|
|
10766
|
+
} catch {
|
|
10767
|
+
return `image-${index}`;
|
|
10768
|
+
}
|
|
10769
|
+
}
|
|
10749
10770
|
function slugFactory() {
|
|
10750
10771
|
const counts = /* @__PURE__ */ new Map();
|
|
10751
10772
|
return (url) => {
|
|
@@ -10768,7 +10789,9 @@ async function* pageChunks(jobId) {
|
|
|
10768
10789
|
}
|
|
10769
10790
|
async function assembleExtractArtifacts(job, extras = {}) {
|
|
10770
10791
|
const dir = (0, import_node_path3.join)((0, import_node_os3.tmpdir)(), `extract-bundle-${job.id}-${Date.now()}`);
|
|
10792
|
+
const downloadImages = job.options.downloadImages === true;
|
|
10771
10793
|
(0, import_node_fs3.mkdirSync)((0, import_node_path3.join)(dir, "pages"), { recursive: true });
|
|
10794
|
+
if (downloadImages) (0, import_node_fs3.mkdirSync)((0, import_node_path3.join)(dir, "images"), { recursive: true });
|
|
10772
10795
|
try {
|
|
10773
10796
|
const metas = [];
|
|
10774
10797
|
const statusByUrl = /* @__PURE__ */ new Map();
|
|
@@ -10802,6 +10825,10 @@ async function assembleExtractArtifacts(job, extras = {}) {
|
|
|
10802
10825
|
} catch {
|
|
10803
10826
|
siteReg = "";
|
|
10804
10827
|
}
|
|
10828
|
+
const imageLimit = (0, import_p_limit3.default)(IMAGE_DOWNLOAD_CONCURRENCY);
|
|
10829
|
+
const imageDownloads = [];
|
|
10830
|
+
let imagesQueued = 0;
|
|
10831
|
+
let imagesFailed = 0;
|
|
10805
10832
|
for await (const chunk of pageChunks(job.id)) {
|
|
10806
10833
|
for (const p of chunk) {
|
|
10807
10834
|
if (p.bodyMarkdown) {
|
|
@@ -10819,6 +10846,20 @@ ${p.bodyMarkdown}
|
|
|
10819
10846
|
`
|
|
10820
10847
|
);
|
|
10821
10848
|
}
|
|
10849
|
+
if (downloadImages && p.imageLinks?.length && imagesQueued < MAX_IMAGES_PER_SITE) {
|
|
10850
|
+
const pageDir = (0, import_node_path3.join)(dir, "images", slug(p.url));
|
|
10851
|
+
(0, import_node_fs3.mkdirSync)(pageDir, { recursive: true });
|
|
10852
|
+
for (const [idx, imgUrl] of p.imageLinks.slice(0, MAX_IMAGES_PER_PAGE).entries()) {
|
|
10853
|
+
if (imagesQueued >= MAX_IMAGES_PER_SITE) break;
|
|
10854
|
+
imagesQueued++;
|
|
10855
|
+
const filename = safeImageFilename(imgUrl, idx);
|
|
10856
|
+
imageDownloads.push(
|
|
10857
|
+
imageLimit(() => downloadAsset(imgUrl, pageDir, filename)).then(() => void 0, () => {
|
|
10858
|
+
imagesFailed++;
|
|
10859
|
+
})
|
|
10860
|
+
);
|
|
10861
|
+
}
|
|
10862
|
+
}
|
|
10822
10863
|
const from = normalize2(p.url);
|
|
10823
10864
|
const oc = { int: 0, ext: 0 };
|
|
10824
10865
|
for (const l of p.outlinks ?? []) {
|
|
@@ -10866,6 +10907,7 @@ ${p.bodyMarkdown}
|
|
|
10866
10907
|
}
|
|
10867
10908
|
gz.end();
|
|
10868
10909
|
await (0, import_node_events.once)(linksOut, "finish");
|
|
10910
|
+
await Promise.all(imageDownloads);
|
|
10869
10911
|
const depth = /* @__PURE__ */ new Map();
|
|
10870
10912
|
const start = normalize2(job.startUrl);
|
|
10871
10913
|
depth.set(start, 0);
|
|
@@ -10957,6 +10999,15 @@ ${renderImageSection(extras.imageAudit)}`;
|
|
|
10957
10999
|
}
|
|
10958
11000
|
if (extras.seoAudit) (0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "seo-audit.json"), JSON.stringify(extras.seoAudit, null, 2));
|
|
10959
11001
|
if (extras.branding) (0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "branding.json"), JSON.stringify(extras.branding, null, 2));
|
|
11002
|
+
if (downloadImages) {
|
|
11003
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(dir, "images-download-summary.json"), JSON.stringify({
|
|
11004
|
+
queued: imagesQueued,
|
|
11005
|
+
downloaded: imagesQueued - imagesFailed,
|
|
11006
|
+
failed: imagesFailed,
|
|
11007
|
+
perPageCap: MAX_IMAGES_PER_PAGE,
|
|
11008
|
+
perSiteCap: MAX_IMAGES_PER_SITE
|
|
11009
|
+
}, null, 2));
|
|
11010
|
+
}
|
|
10960
11011
|
const artifactFiles = [
|
|
10961
11012
|
{ name: "report.md", type: "text/markdown" },
|
|
10962
11013
|
{ name: "issues.json", type: "application/json" },
|
|
@@ -10973,13 +11024,20 @@ ${renderImageSection(extras.imageAudit)}`;
|
|
|
10973
11024
|
}
|
|
10974
11025
|
if (extras.seoAudit) artifactFiles.push({ name: "seo-audit.json", type: "application/json" });
|
|
10975
11026
|
if (extras.branding) artifactFiles.push({ name: "branding.json", type: "application/json" });
|
|
11027
|
+
if (downloadImages) artifactFiles.push({ name: "images-download-summary.json", type: "application/json" });
|
|
10976
11028
|
const zip = new import_yazl.ZipFile();
|
|
10977
11029
|
const zipOut = (0, import_node_fs3.createWriteStream)((0, import_node_path3.join)(dir, "bundle.zip"));
|
|
10978
11030
|
zip.outputStream.pipe(zipOut);
|
|
10979
11031
|
for (const f of artifactFiles) zip.addFile((0, import_node_path3.join)(dir, f.name), f.name);
|
|
10980
11032
|
if (pagesWithBody > 0) {
|
|
10981
|
-
const
|
|
10982
|
-
|
|
11033
|
+
for (const f of (0, import_node_fs3.readdirSync)((0, import_node_path3.join)(dir, "pages"))) zip.addFile((0, import_node_path3.join)(dir, "pages", f), `pages/${f}`);
|
|
11034
|
+
}
|
|
11035
|
+
if (downloadImages && imagesQueued > imagesFailed) {
|
|
11036
|
+
const imagesDir = (0, import_node_path3.join)(dir, "images");
|
|
11037
|
+
for (const rel of (0, import_node_fs3.readdirSync)(imagesDir, { recursive: true })) {
|
|
11038
|
+
const full = (0, import_node_path3.join)(imagesDir, rel);
|
|
11039
|
+
if ((0, import_node_fs3.statSync)(full).isFile()) zip.addFile(full, `images/${rel.split("\\").join("/")}`);
|
|
11040
|
+
}
|
|
10983
11041
|
}
|
|
10984
11042
|
zip.end();
|
|
10985
11043
|
await (0, import_node_events.once)(zipOut, "finish");
|
|
@@ -10993,7 +11051,7 @@ ${renderImageSection(extras.imageAudit)}`;
|
|
|
10993
11051
|
(0, import_node_fs3.rmSync)(dir, { recursive: true, force: true });
|
|
10994
11052
|
}
|
|
10995
11053
|
}
|
|
10996
|
-
var import_node_fs3, import_node_path3, import_node_os3, import_node_zlib, import_node_events, import_yazl, CHUNK;
|
|
11054
|
+
var import_node_fs3, import_node_path3, import_node_os3, import_node_zlib, import_node_events, import_yazl, import_p_limit3, CHUNK, MAX_IMAGES_PER_PAGE, MAX_IMAGES_PER_SITE, IMAGE_DOWNLOAD_CONCURRENCY;
|
|
10997
11055
|
var init_extract_bundle = __esm({
|
|
10998
11056
|
"src/api/extract-bundle.ts"() {
|
|
10999
11057
|
"use strict";
|
|
@@ -11003,12 +11061,17 @@ var init_extract_bundle = __esm({
|
|
|
11003
11061
|
import_node_zlib = require("zlib");
|
|
11004
11062
|
import_node_events = require("events");
|
|
11005
11063
|
import_yazl = require("yazl");
|
|
11064
|
+
import_p_limit3 = __toESM(require("p-limit"), 1);
|
|
11006
11065
|
init_db();
|
|
11007
11066
|
init_blob_store();
|
|
11008
11067
|
init_seo_issues();
|
|
11009
11068
|
init_seo_link_report();
|
|
11010
11069
|
init_image_audit();
|
|
11070
|
+
init_media_extractor();
|
|
11011
11071
|
CHUNK = 400;
|
|
11072
|
+
MAX_IMAGES_PER_PAGE = 20;
|
|
11073
|
+
MAX_IMAGES_PER_SITE = 500;
|
|
11074
|
+
IMAGE_DOWNLOAD_CONCURRENCY = 8;
|
|
11012
11075
|
}
|
|
11013
11076
|
});
|
|
11014
11077
|
|
|
@@ -14049,6 +14112,7 @@ var init_server_schemas = __esm({
|
|
|
14049
14112
|
rotateProxies: import_zod13.z.boolean().optional(),
|
|
14050
14113
|
rotateProxyEvery: import_zod13.z.number().int().min(1).max(100).optional(),
|
|
14051
14114
|
background: import_zod13.z.boolean().optional(),
|
|
14115
|
+
downloadImages: import_zod13.z.boolean().optional(),
|
|
14052
14116
|
formats: import_zod13.z.array(import_zod13.z.enum(["markdown", "links", "json", "images", "branding", "issues"])).optional()
|
|
14053
14117
|
});
|
|
14054
14118
|
YoutubeHarvestBodySchema = import_zod13.z.object({
|
|
@@ -20035,9 +20099,24 @@ function buildSeoExport(siteUrl, pages, branding) {
|
|
|
20035
20099
|
branding: branding ?? void 0
|
|
20036
20100
|
};
|
|
20037
20101
|
}
|
|
20102
|
+
function formatBackgroundJobStarted(toolLabel, data) {
|
|
20103
|
+
if (data.status !== "pending" || typeof data.jobId !== "string") return null;
|
|
20104
|
+
const jobId = data.jobId;
|
|
20105
|
+
const full = [
|
|
20106
|
+
`# ${toolLabel} \u2014 export started`,
|
|
20107
|
+
`**Job ID:** \`${jobId}\``,
|
|
20108
|
+
`
|
|
20109
|
+
Running in the background \u2014 this can take a while for large sites.`,
|
|
20110
|
+
`
|
|
20111
|
+
Poll \`check_site_export\` with this jobId to get the download link once it's ready.`
|
|
20112
|
+
].join("\n");
|
|
20113
|
+
return { content: [{ type: "text", text: full }], structuredContent: { jobId, status: "pending" } };
|
|
20114
|
+
}
|
|
20038
20115
|
async function formatExtractSite(raw, input, ctx) {
|
|
20039
20116
|
const parsed = parseData(raw);
|
|
20040
20117
|
if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
|
|
20118
|
+
const started = formatBackgroundJobStarted("Multi-Page Site Content Crawl", parsed.data);
|
|
20119
|
+
if (started) return started;
|
|
20041
20120
|
const d = parsed.data;
|
|
20042
20121
|
const pages = d.pages ?? [];
|
|
20043
20122
|
const schemaTypesOf = (p) => p.kpo?.type ?? (Array.isArray(p.schema) && p.schema.length ? [`${p.schema.length} block(s)`] : []);
|
|
@@ -20155,6 +20234,8 @@ ${pageDetails}${tips}`;
|
|
|
20155
20234
|
async function formatAuditSite(raw, input, ctx) {
|
|
20156
20235
|
const parsed = parseData(raw);
|
|
20157
20236
|
if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
|
|
20237
|
+
const started = formatBackgroundJobStarted("Technical SEO Audit", parsed.data);
|
|
20238
|
+
if (started) return started;
|
|
20158
20239
|
const d = parsed.data;
|
|
20159
20240
|
const pages = d.pages ?? [];
|
|
20160
20241
|
const schemaTypesOf = (p) => p.kpo?.type ?? (Array.isArray(p.schema) && p.schema.length ? [`${p.schema.length} block(s)`] : []);
|
|
@@ -20226,6 +20307,42 @@ ${imgLine}`
|
|
|
20226
20307
|
].join("\n");
|
|
20227
20308
|
return { content: [{ type: "text", text: full }], structuredContent };
|
|
20228
20309
|
}
|
|
20310
|
+
function formatCheckSiteExport(raw, input) {
|
|
20311
|
+
const parsed = parseData(raw);
|
|
20312
|
+
if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
|
|
20313
|
+
const d = parsed.data;
|
|
20314
|
+
const bundle = (d.artifacts ?? []).find((a) => a.key.endsWith("bundle.zip")) ?? null;
|
|
20315
|
+
const progress = d.totalUrls ? `${d.doneUrls ?? 0}/${d.totalUrls} pages` : "starting";
|
|
20316
|
+
const body = d.status === "complete" && bundle ? `
|
|
20317
|
+
## \u2705 Ready
|
|
20318
|
+
**Download:** ${bundle.url}
|
|
20319
|
+
**Size:** ${(bundle.bytes / 1e6).toFixed(1)} MB` : d.status === "complete" ? `
|
|
20320
|
+
## \u26A0\uFE0F Complete, but no bundle was produced
|
|
20321
|
+
Check the job's artifacts \u2014 nothing matched \`bundle.zip\`.` : d.status === "failed" ? `
|
|
20322
|
+
## \u274C Failed
|
|
20323
|
+
${d.error ?? "no error message recorded"}` : `
|
|
20324
|
+
## \u23F3 Not ready yet
|
|
20325
|
+
Status: ${d.status} (${progress}). Poll again shortly.`;
|
|
20326
|
+
const full = [
|
|
20327
|
+
`# Site Export: ${d.startUrl ?? input.jobId}`,
|
|
20328
|
+
`**Job ID:** \`${d.jobId}\``,
|
|
20329
|
+
`**Status:** ${d.status}`,
|
|
20330
|
+
body
|
|
20331
|
+
].join("\n");
|
|
20332
|
+
return {
|
|
20333
|
+
...oneBlock(full),
|
|
20334
|
+
structuredContent: {
|
|
20335
|
+
jobId: d.jobId,
|
|
20336
|
+
status: d.status,
|
|
20337
|
+
startUrl: d.startUrl,
|
|
20338
|
+
totalUrls: d.totalUrls,
|
|
20339
|
+
doneUrls: d.doneUrls,
|
|
20340
|
+
bundleUrl: bundle?.url ?? null,
|
|
20341
|
+
bundleBytes: bundle?.bytes ?? null,
|
|
20342
|
+
error: d.error ?? null
|
|
20343
|
+
}
|
|
20344
|
+
};
|
|
20345
|
+
}
|
|
20229
20346
|
function formatYoutubeHarvest(raw, input) {
|
|
20230
20347
|
const parsed = parseData(raw);
|
|
20231
20348
|
if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
|
|
@@ -25043,7 +25160,7 @@ async function capturePageSnapshot(target, options = {}) {
|
|
|
25043
25160
|
async function capturePageSnapshots(targets, options = {}) {
|
|
25044
25161
|
const timeoutMs = normalizeTimeoutMs(options.timeoutMs);
|
|
25045
25162
|
const maxConcurrency = normalizeMaxConcurrency(options.maxConcurrency);
|
|
25046
|
-
const limit = (0,
|
|
25163
|
+
const limit = (0, import_p_limit4.default)(maxConcurrency);
|
|
25047
25164
|
const pageSnapshotArtifacts = await Promise.all(
|
|
25048
25165
|
targets.map((target) => limit(() => capturePageSnapshot(target, { ...options, timeoutMs })))
|
|
25049
25166
|
);
|
|
@@ -25068,12 +25185,12 @@ async function capturePageSnapshots(targets, options = {}) {
|
|
|
25068
25185
|
}
|
|
25069
25186
|
};
|
|
25070
25187
|
}
|
|
25071
|
-
var import_node_crypto10,
|
|
25188
|
+
var import_node_crypto10, import_p_limit4, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_CONTENT_CHARS;
|
|
25072
25189
|
var init_page_snapshot_extractor = __esm({
|
|
25073
25190
|
"src/serp-intelligence/page-snapshot-extractor.ts"() {
|
|
25074
25191
|
"use strict";
|
|
25075
25192
|
import_node_crypto10 = require("crypto");
|
|
25076
|
-
|
|
25193
|
+
import_p_limit4 = __toESM(require("p-limit"), 1);
|
|
25077
25194
|
init_kpo_extractor();
|
|
25078
25195
|
init_url_utils();
|
|
25079
25196
|
DEFAULT_TIMEOUT_MS = 15e3;
|
|
@@ -27740,7 +27857,7 @@ var PACKAGE_VERSION;
|
|
|
27740
27857
|
var init_version = __esm({
|
|
27741
27858
|
"src/version.ts"() {
|
|
27742
27859
|
"use strict";
|
|
27743
|
-
PACKAGE_VERSION = "0.
|
|
27860
|
+
PACKAGE_VERSION = "0.20.0";
|
|
27744
27861
|
}
|
|
27745
27862
|
});
|
|
27746
27863
|
|
|
@@ -28127,7 +28244,7 @@ var init_meta_ad_creative_media = __esm({
|
|
|
28127
28244
|
});
|
|
28128
28245
|
|
|
28129
28246
|
// src/mcp/mcp-tool-schemas.ts
|
|
28130
|
-
var import_zod33, HarvestPaaInputSchema, ExtractUrlInputSchema, DiffPageInputSchema, MapSiteUrlsInputSchema, ExtractSiteInputSchema, AuditSiteInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, ArtifactPointerOutputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryWorkflowOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, 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, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
|
|
28247
|
+
var import_zod33, HarvestPaaInputSchema, ExtractUrlInputSchema, DiffPageInputSchema, MapSiteUrlsInputSchema, ExtractSiteInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, ArtifactPointerOutputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryWorkflowOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, 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, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
|
|
28131
28248
|
var init_mcp_tool_schemas = __esm({
|
|
28132
28249
|
"src/mcp/mcp-tool-schemas.ts"() {
|
|
28133
28250
|
"use strict";
|
|
@@ -28169,13 +28286,20 @@ var init_mcp_tool_schemas = __esm({
|
|
|
28169
28286
|
maxPages: import_zod33.z.number().int().min(1).max(1e4).optional().describe("Maximum pages to extract. Bulk crawls (over 25 pages) switch to folder mode: each page saved as its own Markdown file, with a summary plus folder path returned instead of inlining content."),
|
|
28170
28287
|
rotateProxies: import_zod33.z.boolean().optional().describe("Route page fetches through rotating residential proxies to defeat rate-limiting and bot blocks (403/429). Slower and pricier \u2014 use only when a site blocks normal crawling."),
|
|
28171
28288
|
rotateProxyEvery: import_zod33.z.number().int().min(1).max(100).optional().describe("When rotateProxies is on, pages fetched per proxy before rotating. Default 30."),
|
|
28172
|
-
formats: import_zod33.z.array(import_zod33.z.enum(["markdown", "links", "json", "images", "branding"])).optional().describe("Per-page output formats: markdown, links, json, images are captured cheaply from HTML; branding (site-level logo/colors/fonts) requires a browser and adds time. Defaults to markdown+links.")
|
|
28289
|
+
formats: import_zod33.z.array(import_zod33.z.enum(["markdown", "links", "json", "images", "branding"])).optional().describe("Per-page output formats: markdown, links, json, images are captured cheaply from HTML; branding (site-level logo/colors/fonts) requires a browser and adds time. Defaults to markdown+links."),
|
|
28290
|
+
background: import_zod33.z.boolean().default(false).describe("Run the crawl as a background job instead of blocking this call, returning a jobId immediately \u2014 poll it with check_site_export to get a downloadable zip (all page content, plus real image files if downloadImages is set) once ready. Use for large sites where a synchronous call would be slow."),
|
|
28291
|
+
downloadImages: import_zod33.z.boolean().default(false).describe("Download every discovered image as a real file into the export bundle (not just image URLs/stats). OFF by default \u2014 must be explicitly set true. Implies background regardless of the background flag, since downloading a whole site's images is too slow to run synchronously. Capped at 20 images/page and 500 images/site.")
|
|
28173
28292
|
};
|
|
28174
28293
|
AuditSiteInputSchema = {
|
|
28175
28294
|
url: import_zod33.z.string().url().describe("Public website URL or domain for a full technical SEO audit (issues, link graph, indexability, headings, images). For plain content use extract_site instead."),
|
|
28176
28295
|
maxPages: import_zod33.z.number().int().min(1).max(1e4).optional().describe("Maximum pages to crawl and audit. Always writes a folder of analysis files plus per-page content, returning a summary plus the folder path."),
|
|
28177
28296
|
rotateProxies: import_zod33.z.boolean().optional().describe("Route page fetches through rotating residential proxies to defeat rate-limiting and bot blocks. Slower/pricier \u2014 use only when a site blocks normal crawling."),
|
|
28178
|
-
rotateProxyEvery: import_zod33.z.number().int().min(1).max(100).optional().describe("When rotateProxies is on, pages fetched per proxy before rotating. Default 30.")
|
|
28297
|
+
rotateProxyEvery: import_zod33.z.number().int().min(1).max(100).optional().describe("When rotateProxies is on, pages fetched per proxy before rotating. Default 30."),
|
|
28298
|
+
background: import_zod33.z.boolean().default(false).describe("Run the audit as a background job instead of blocking this call, returning a jobId immediately \u2014 poll it with check_site_export to get a downloadable zip (full audit report, all page content, plus real image files if downloadImages is set) once ready. Use for large sites where a synchronous call would be slow."),
|
|
28299
|
+
downloadImages: import_zod33.z.boolean().default(false).describe("Download every discovered image as a real file into the export bundle (not just image URLs/stats). OFF by default \u2014 must be explicitly set true. Implies background regardless of the background flag, since downloading a whole site's images is too slow to run synchronously. Capped at 20 images/page and 500 images/site.")
|
|
28300
|
+
};
|
|
28301
|
+
CheckSiteExportInputSchema = {
|
|
28302
|
+
jobId: import_zod33.z.string().min(1).describe('The jobId returned by extract_site or audit_site when called with background (or downloadImages) set \u2014 poll this until status is "complete" (or "failed").')
|
|
28179
28303
|
};
|
|
28180
28304
|
YoutubeHarvestInputSchema = {
|
|
28181
28305
|
mode: import_zod33.z.enum(["search", "channel"]).describe("Use search for topic/keyword requests. Use channel when the user provides @handle, channel ID, or channel URL."),
|
|
@@ -28578,36 +28702,52 @@ var init_mcp_tool_schemas = __esm({
|
|
|
28578
28702
|
};
|
|
28579
28703
|
ExtractSiteOutputSchema = {
|
|
28580
28704
|
url: import_zod33.z.string(),
|
|
28581
|
-
pageCount: import_zod33.z.number().int().min(0),
|
|
28705
|
+
pageCount: import_zod33.z.number().int().min(0).optional().describe("Absent when background is true \u2014 the crawl has not finished yet."),
|
|
28582
28706
|
pages: import_zod33.z.array(import_zod33.z.object({
|
|
28583
28707
|
url: import_zod33.z.string(),
|
|
28584
28708
|
title: NullableString,
|
|
28585
28709
|
schemaTypes: import_zod33.z.array(import_zod33.z.string())
|
|
28586
|
-
})),
|
|
28587
|
-
durationMs: import_zod33.z.number().min(0),
|
|
28710
|
+
})).optional().describe("Absent when background is true \u2014 the crawl has not finished yet."),
|
|
28711
|
+
durationMs: import_zod33.z.number().min(0).optional().describe("Absent when background is true \u2014 the crawl has not finished yet."),
|
|
28588
28712
|
truncatedCount: import_zod33.z.number().int().min(0).optional(),
|
|
28589
|
-
artifact: ArtifactPointerOutputSchema.optional()
|
|
28713
|
+
artifact: ArtifactPointerOutputSchema.optional(),
|
|
28714
|
+
jobId: import_zod33.z.string().optional().describe("Present when background (or downloadImages) was set \u2014 poll with check_site_export."),
|
|
28715
|
+
status: import_zod33.z.enum(["pending"]).optional().describe("Present when background (or downloadImages) was set."),
|
|
28716
|
+
statusUrl: import_zod33.z.string().optional().describe("Present when background (or downloadImages) was set \u2014 informational; use check_site_export with jobId, not this URL directly.")
|
|
28590
28717
|
};
|
|
28591
28718
|
AuditSiteOutputSchema = {
|
|
28592
28719
|
url: import_zod33.z.string(),
|
|
28593
|
-
pageCount: import_zod33.z.number().int().min(0),
|
|
28594
|
-
durationMs: import_zod33.z.number().min(0),
|
|
28595
|
-
bulkFolder: import_zod33.z.string().nullable(),
|
|
28596
|
-
issues: import_zod33.z.record(import_zod33.z.string(), import_zod33.z.number()),
|
|
28720
|
+
pageCount: import_zod33.z.number().int().min(0).optional().describe("Absent when background is true \u2014 the audit has not finished yet."),
|
|
28721
|
+
durationMs: import_zod33.z.number().min(0).optional().describe("Absent when background is true \u2014 the audit has not finished yet."),
|
|
28722
|
+
bulkFolder: import_zod33.z.string().nullable().optional().describe("Absent when background is true \u2014 the audit has not finished yet."),
|
|
28723
|
+
issues: import_zod33.z.record(import_zod33.z.string(), import_zod33.z.number()).optional().describe("Absent when background is true \u2014 the audit has not finished yet."),
|
|
28597
28724
|
images: import_zod33.z.object({
|
|
28598
28725
|
unique: import_zod33.z.number().int().min(0),
|
|
28599
28726
|
totalBytes: import_zod33.z.number().min(0),
|
|
28600
28727
|
over100kb: import_zod33.z.number().int().min(0),
|
|
28601
28728
|
legacyFormat: import_zod33.z.number().int().min(0)
|
|
28602
|
-
}),
|
|
28729
|
+
}).optional().describe("Absent when background is true \u2014 the audit has not finished yet."),
|
|
28603
28730
|
links: import_zod33.z.object({
|
|
28604
28731
|
internal: import_zod33.z.number().int().min(0),
|
|
28605
28732
|
external: import_zod33.z.number().int().min(0),
|
|
28606
28733
|
orphans: import_zod33.z.number().int().min(0),
|
|
28607
28734
|
brokenInternal: import_zod33.z.number().int().min(0),
|
|
28608
28735
|
externalDomains: import_zod33.z.number().int().min(0)
|
|
28609
|
-
}),
|
|
28610
|
-
artifact: ArtifactPointerOutputSchema.optional()
|
|
28736
|
+
}).optional().describe("Absent when background is true \u2014 the audit has not finished yet."),
|
|
28737
|
+
artifact: ArtifactPointerOutputSchema.optional(),
|
|
28738
|
+
jobId: import_zod33.z.string().optional().describe("Present when background (or downloadImages) was set \u2014 poll with check_site_export."),
|
|
28739
|
+
status: import_zod33.z.enum(["pending"]).optional().describe("Present when background (or downloadImages) was set."),
|
|
28740
|
+
statusUrl: import_zod33.z.string().optional().describe("Present when background (or downloadImages) was set \u2014 informational; use check_site_export with jobId, not this URL directly.")
|
|
28741
|
+
};
|
|
28742
|
+
CheckSiteExportOutputSchema = {
|
|
28743
|
+
jobId: import_zod33.z.string(),
|
|
28744
|
+
status: import_zod33.z.enum(["pending", "running", "complete", "failed"]),
|
|
28745
|
+
startUrl: import_zod33.z.string().optional(),
|
|
28746
|
+
totalUrls: import_zod33.z.number().int().min(0).optional(),
|
|
28747
|
+
doneUrls: import_zod33.z.number().int().min(0).optional(),
|
|
28748
|
+
bundleUrl: import_zod33.z.string().nullable().describe("Downloadable zip URL once status is complete; null otherwise."),
|
|
28749
|
+
bundleBytes: import_zod33.z.number().int().min(0).nullable().describe("Zip size in bytes once status is complete; null otherwise."),
|
|
28750
|
+
error: import_zod33.z.string().nullable().optional().describe("Present with a message when status is failed.")
|
|
28611
28751
|
};
|
|
28612
28752
|
MapsPlaceIntelOutputSchema = {
|
|
28613
28753
|
name: import_zod33.z.string(),
|
|
@@ -29919,6 +30059,13 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
29919
30059
|
outputSchema: recordOutputSchema("audit_site", AuditSiteOutputSchema),
|
|
29920
30060
|
annotations: liveWebToolAnnotations("Technical SEO Audit")
|
|
29921
30061
|
}, async (input) => formatAuditSite(await executor.auditSite(input), input, ctx));
|
|
30062
|
+
server.registerTool("check_site_export", {
|
|
30063
|
+
title: "Check Site Export",
|
|
30064
|
+
description: "Poll the status of a background extract_site or audit_site job (one started with background or downloadImages set). Returns a downloadable zip URL (all page content, plus real image files if downloadImages was set) once status is complete.",
|
|
30065
|
+
inputSchema: CheckSiteExportInputSchema,
|
|
30066
|
+
outputSchema: recordOutputSchema("check_site_export", CheckSiteExportOutputSchema),
|
|
30067
|
+
annotations: liveWebToolAnnotations("Check Site Export")
|
|
30068
|
+
}, async (input) => formatCheckSiteExport(await executor.checkSiteExport(input), input));
|
|
29922
30069
|
server.registerTool("youtube_harvest", {
|
|
29923
30070
|
title: "YouTube Video Harvest",
|
|
29924
30071
|
description: 'Harvest YouTube video metadata by topic search or channel library. Use mode "search" for keyword/topic requests, mode "channel" for @handles/channel IDs/URLs. Returns titles, views, durations, and videoIds.',
|
|
@@ -30436,6 +30583,9 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
30436
30583
|
auditSite(input) {
|
|
30437
30584
|
return this.call("/extract-site", input);
|
|
30438
30585
|
}
|
|
30586
|
+
checkSiteExport(input) {
|
|
30587
|
+
return this.getJson(`/extract-site/status/${encodeURIComponent(input.jobId)}`);
|
|
30588
|
+
}
|
|
30439
30589
|
youtubeHarvest(input) {
|
|
30440
30590
|
return this.call("/youtube/harvest", input);
|
|
30441
30591
|
}
|
|
@@ -41906,7 +42056,7 @@ var init_server = __esm({
|
|
|
41906
42056
|
const user = await getUserByApiKey(key);
|
|
41907
42057
|
if (!user) return c.json({ error: "Invalid or inactive API key" }, 401);
|
|
41908
42058
|
const refreshed = await applyMonthlyFreeRefresh(user);
|
|
41909
|
-
const balanceMc = await reconcileBalanceMc(refreshed.id);
|
|
42059
|
+
const balanceMc = await reconcileBalanceMc(refreshed.id, refreshed.balance_mc);
|
|
41910
42060
|
c.set("user", { ...refreshed, balance_mc: balanceMc });
|
|
41911
42061
|
return next();
|
|
41912
42062
|
});
|
|
@@ -41925,7 +42075,7 @@ var init_server = __esm({
|
|
|
41925
42075
|
const user = await getUserById(userId);
|
|
41926
42076
|
if (!user) return c.json({ error: "User not found" }, 401);
|
|
41927
42077
|
const refreshed = await applyMonthlyFreeRefresh(user);
|
|
41928
|
-
const balanceMc = await reconcileBalanceMc(refreshed.id);
|
|
42078
|
+
const balanceMc = await reconcileBalanceMc(refreshed.id, refreshed.balance_mc);
|
|
41929
42079
|
c.set("sessionUser", { ...refreshed, balance_mc: balanceMc });
|
|
41930
42080
|
return next();
|
|
41931
42081
|
});
|
|
@@ -42115,7 +42265,7 @@ var init_server = __esm({
|
|
|
42115
42265
|
}
|
|
42116
42266
|
const refreshed = await applyMonthlyFreeRefresh(foundUser);
|
|
42117
42267
|
const [balanceMc, stats] = await Promise.all([
|
|
42118
|
-
reconcileBalanceMc(refreshed.id),
|
|
42268
|
+
reconcileBalanceMc(refreshed.id, refreshed.balance_mc),
|
|
42119
42269
|
getUserStats(refreshed.id)
|
|
42120
42270
|
]);
|
|
42121
42271
|
const user = { ...refreshed, balance_mc: balanceMc };
|
|
@@ -43383,7 +43533,8 @@ var init_server = __esm({
|
|
|
43383
43533
|
if (checked.error || !checked.parsed) return c.json({ error: checked.error ?? "Invalid URL" }, 400);
|
|
43384
43534
|
const parsed = checked.parsed;
|
|
43385
43535
|
const user = c.get("user");
|
|
43386
|
-
|
|
43536
|
+
const downloadImages = body.downloadImages === true;
|
|
43537
|
+
if (body.background === true || downloadImages) {
|
|
43387
43538
|
const affordablePages = Math.floor(user.balance_mc / MC_COSTS.page_scrape);
|
|
43388
43539
|
if (affordablePages < 1) return c.json(insufficientBalanceResponse(user.balance_mc, MC_COSTS.page_scrape), 402);
|
|
43389
43540
|
const maxPages = Math.min(Math.min(1e4, Math.max(1, body.maxPages ?? 1e4)), affordablePages);
|
|
@@ -43398,6 +43549,7 @@ var init_server = __esm({
|
|
|
43398
43549
|
concurrency: concurrencyLimitForUser(user),
|
|
43399
43550
|
urlsPerBrowser: body.rotateProxyEvery ?? 10,
|
|
43400
43551
|
formats: body.formats,
|
|
43552
|
+
downloadImages,
|
|
43401
43553
|
heldMc
|
|
43402
43554
|
});
|
|
43403
43555
|
jobCreated = true;
|
|
@@ -43706,7 +43858,7 @@ var init_server = __esm({
|
|
|
43706
43858
|
});
|
|
43707
43859
|
app.get("/billing/balance", auth2, async (c) => {
|
|
43708
43860
|
const user = c.get("user");
|
|
43709
|
-
const balanceMc =
|
|
43861
|
+
const balanceMc = user.balance_mc;
|
|
43710
43862
|
const ledger = await getLedger(user.id, 20);
|
|
43711
43863
|
const freeCredits = await getFreeCreditBreakdown(user.id);
|
|
43712
43864
|
return c.json({
|
|
@@ -43718,7 +43870,7 @@ var init_server = __esm({
|
|
|
43718
43870
|
});
|
|
43719
43871
|
app.post("/billing/credits", auth2, async (c) => {
|
|
43720
43872
|
const user = c.get("user");
|
|
43721
|
-
const balanceMc =
|
|
43873
|
+
const balanceMc = user.balance_mc;
|
|
43722
43874
|
const body = await c.req.json().catch(() => ({}));
|
|
43723
43875
|
const query = body.item?.trim().toLowerCase();
|
|
43724
43876
|
const costs = CREDIT_COST_CATALOG.map(({ aliases, ...cost }) => cost);
|