mcp-scraper 0.2.14 → 0.2.16
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/README.md +6 -5
- package/dist/bin/api-server.cjs +321 -29
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/browser-agent-stdio-server.cjs +1 -1
- package/dist/bin/browser-agent-stdio-server.cjs.map +1 -1
- package/dist/bin/browser-agent-stdio-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-combined-stdio-server.cjs +95 -6
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.js +3 -3
- package/dist/bin/mcp-scraper-install.cjs +4 -4
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +4 -4
- package/dist/bin/mcp-scraper-install.js.map +1 -1
- package/dist/bin/mcp-stdio-server.cjs +95 -6
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/{chunk-ZV2XXYR7.js → chunk-ATJAINML.js} +2 -2
- package/dist/{chunk-IWQTNY2E.js → chunk-FMC3V54I.js} +96 -7
- package/dist/chunk-FMC3V54I.js.map +1 -0
- package/dist/chunk-KE4JZDLV.js +7 -0
- package/dist/chunk-KE4JZDLV.js.map +1 -0
- package/dist/{server-7QP6HQJJ.js → server-KSEQLZNP.js} +221 -24
- package/dist/server-KSEQLZNP.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-IWQTNY2E.js.map +0 -1
- package/dist/chunk-ROCXJOVY.js +0 -7
- package/dist/chunk-ROCXJOVY.js.map +0 -1
- package/dist/server-7QP6HQJJ.js.map +0 -1
- /package/dist/{chunk-ZV2XXYR7.js.map → chunk-ATJAINML.js.map} +0 -0
|
@@ -100,7 +100,7 @@ import {
|
|
|
100
100
|
harvestTimeoutBudget,
|
|
101
101
|
liveWebToolAnnotations,
|
|
102
102
|
outputBaseDir
|
|
103
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-FMC3V54I.js";
|
|
104
104
|
import {
|
|
105
105
|
CaptchaError,
|
|
106
106
|
RECAPTCHA_INSTRUCTIONS,
|
|
@@ -114,7 +114,7 @@ import {
|
|
|
114
114
|
workflowDefinition,
|
|
115
115
|
workflowOutputBaseDir
|
|
116
116
|
} from "./chunk-F44RBOJ5.js";
|
|
117
|
-
import "./chunk-
|
|
117
|
+
import "./chunk-KE4JZDLV.js";
|
|
118
118
|
|
|
119
119
|
// src/api/outbound-sanitize.ts
|
|
120
120
|
var KEY_RENAMES = {
|
|
@@ -9189,6 +9189,127 @@ function advertisersFromResults(results, maxResults) {
|
|
|
9189
9189
|
return [...byPage.values()].map((e) => ({ pageName: e.pageName, pageId: e.pageId, sampleLibraryId: e.sampleLibraryId, adCount: Math.max(e.maxCollation, e.resultCount) })).sort((a, b) => b.adCount - a.adCount).slice(0, maxResults);
|
|
9190
9190
|
}
|
|
9191
9191
|
|
|
9192
|
+
// src/extractor/FacebookOrganicVideoExtractor.ts
|
|
9193
|
+
function htmlDecode(value) {
|
|
9194
|
+
return value.replace(/&/g, "&").replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
9195
|
+
}
|
|
9196
|
+
function decodeEscapedValue(raw) {
|
|
9197
|
+
let out = raw;
|
|
9198
|
+
try {
|
|
9199
|
+
out = JSON.parse(`"${raw.replace(/"/g, '\\"')}"`);
|
|
9200
|
+
} catch {
|
|
9201
|
+
out = raw.replace(/\\u0025/g, "%").replace(/\\u0026/g, "&").replace(/\\u003D/g, "=").replace(/\\u003d/g, "=").replace(/\\"/g, '"').replace(/\\\//g, "/");
|
|
9202
|
+
}
|
|
9203
|
+
return htmlDecode(out);
|
|
9204
|
+
}
|
|
9205
|
+
function facebookVideoIdFromUrl(url) {
|
|
9206
|
+
try {
|
|
9207
|
+
const parsed = new URL(url);
|
|
9208
|
+
const path5 = parsed.pathname;
|
|
9209
|
+
const direct = path5.match(/\/(?:reel|videos|watch)\/(?:[^/]+\/)?(\d{8,})/i);
|
|
9210
|
+
if (direct) return direct[1];
|
|
9211
|
+
const queryVideoId = parsed.searchParams.get("v") ?? parsed.searchParams.get("video_id");
|
|
9212
|
+
if (queryVideoId && /^\d{8,}$/.test(queryVideoId)) return queryVideoId;
|
|
9213
|
+
const numericTail = path5.match(/\/(\d{8,})\/?$/);
|
|
9214
|
+
if (numericTail) return numericTail[1];
|
|
9215
|
+
} catch {
|
|
9216
|
+
}
|
|
9217
|
+
return null;
|
|
9218
|
+
}
|
|
9219
|
+
function parseEfg(url) {
|
|
9220
|
+
try {
|
|
9221
|
+
const efg = new URL(url).searchParams.get("efg");
|
|
9222
|
+
if (!efg) return null;
|
|
9223
|
+
return JSON.parse(Buffer.from(efg, "base64").toString("utf8"));
|
|
9224
|
+
} catch {
|
|
9225
|
+
return null;
|
|
9226
|
+
}
|
|
9227
|
+
}
|
|
9228
|
+
function manifestDurationSec(htmlWindow) {
|
|
9229
|
+
const decoded = decodeEscapedValue(htmlWindow);
|
|
9230
|
+
const match = decoded.match(/mediaPresentationDuration="PT([\d.]+)S"/);
|
|
9231
|
+
return match ? Number(match[1]) : null;
|
|
9232
|
+
}
|
|
9233
|
+
function metadataContent(html, key) {
|
|
9234
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9235
|
+
const re = new RegExp(`<meta\\s+[^>]*(?:property|name)=["']${escaped}["'][^>]*content=["']([^"']+)["'][^>]*>`, "i");
|
|
9236
|
+
const m = html.match(re);
|
|
9237
|
+
return m ? htmlDecode(m[1]).trim() : null;
|
|
9238
|
+
}
|
|
9239
|
+
function ownerNameFromHtml(html) {
|
|
9240
|
+
const ogTitle = metadataContent(html, "og:title");
|
|
9241
|
+
const pipe = ogTitle?.split("|").map((s) => s.trim()).filter(Boolean);
|
|
9242
|
+
if (pipe && pipe.length > 1) return pipe[pipe.length - 1] ?? null;
|
|
9243
|
+
return null;
|
|
9244
|
+
}
|
|
9245
|
+
function extractFacebookOrganicVideo(html, pageUrl, sourceUrl = pageUrl, quality = "best") {
|
|
9246
|
+
const videoId = facebookVideoIdFromUrl(pageUrl) ?? facebookVideoIdFromUrl(sourceUrl);
|
|
9247
|
+
const manifestIndex = videoId ? html.indexOf(`dash_mpd_debug.mpd?v=${videoId}`) : -1;
|
|
9248
|
+
const searchWindow = manifestIndex >= 0 ? html.slice(Math.max(0, manifestIndex - 5e4), Math.min(html.length, manifestIndex + 5e4)) : html;
|
|
9249
|
+
const targetDuration = manifestDurationSec(searchWindow);
|
|
9250
|
+
const candidates = [];
|
|
9251
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9252
|
+
const re = /browser_native_(sd|hd)_url\\?"\s*:\s*\\?"([^"<]+?)\\?"/g;
|
|
9253
|
+
let match;
|
|
9254
|
+
while ((match = re.exec(searchWindow)) !== null) {
|
|
9255
|
+
const url = decodeEscapedValue(match[2]);
|
|
9256
|
+
if (!url || seen.has(url)) continue;
|
|
9257
|
+
seen.add(url);
|
|
9258
|
+
const parsed = parseEfg(url);
|
|
9259
|
+
let bitrate = null;
|
|
9260
|
+
try {
|
|
9261
|
+
const value = new URL(url).searchParams.get("bitrate");
|
|
9262
|
+
bitrate = value ? Number(value) : null;
|
|
9263
|
+
} catch {
|
|
9264
|
+
}
|
|
9265
|
+
candidates.push({
|
|
9266
|
+
url,
|
|
9267
|
+
quality: match[1],
|
|
9268
|
+
bitrate: Number.isFinite(bitrate) ? bitrate : null,
|
|
9269
|
+
durationSec: typeof parsed?.duration_s === "number" ? parsed.duration_s : null,
|
|
9270
|
+
assetId: typeof parsed?.xpv_asset_id === "number" ? parsed.xpv_asset_id : null,
|
|
9271
|
+
vencodeTag: typeof parsed?.vencode_tag === "string" ? parsed.vencode_tag : null
|
|
9272
|
+
});
|
|
9273
|
+
}
|
|
9274
|
+
const targetCandidates = candidates.filter((candidate) => {
|
|
9275
|
+
if (!targetDuration || candidate.durationSec == null) return true;
|
|
9276
|
+
return Math.abs(candidate.durationSec - targetDuration) <= 2;
|
|
9277
|
+
});
|
|
9278
|
+
const selectable = targetCandidates.length ? targetCandidates : candidates;
|
|
9279
|
+
const selected = [...selectable].filter((candidate) => quality === "best" || candidate.quality === quality).sort((a, b) => {
|
|
9280
|
+
const aq = a.quality === "hd" ? 1 : 0;
|
|
9281
|
+
const bq = b.quality === "hd" ? 1 : 0;
|
|
9282
|
+
if (quality === "best" && aq !== bq) return bq - aq;
|
|
9283
|
+
return (b.bitrate ?? 0) - (a.bitrate ?? 0);
|
|
9284
|
+
})[0];
|
|
9285
|
+
if (!selected) {
|
|
9286
|
+
throw new Error("No progressive Facebook video URL was found in the rendered page state");
|
|
9287
|
+
}
|
|
9288
|
+
return {
|
|
9289
|
+
sourceUrl,
|
|
9290
|
+
pageUrl,
|
|
9291
|
+
videoId,
|
|
9292
|
+
title: metadataContent(html, "og:title") ?? metadataContent(html, "twitter:title"),
|
|
9293
|
+
description: metadataContent(html, "og:description") ?? metadataContent(html, "description") ?? metadataContent(html, "twitter:description"),
|
|
9294
|
+
ownerName: ownerNameFromHtml(html),
|
|
9295
|
+
videoUrl: selected.url,
|
|
9296
|
+
selectedQuality: selected.quality,
|
|
9297
|
+
bitrate: selected.bitrate,
|
|
9298
|
+
durationSec: targetDuration ?? selected.durationSec,
|
|
9299
|
+
assetId: selected.assetId,
|
|
9300
|
+
vencodeTag: selected.vencodeTag,
|
|
9301
|
+
candidates: selectable,
|
|
9302
|
+
extractedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9303
|
+
};
|
|
9304
|
+
}
|
|
9305
|
+
async function extractFacebookOrganicVideoFromPage(page, sourceUrl, quality = "best") {
|
|
9306
|
+
await page.waitForLoadState("domcontentloaded", { timeout: 15e3 }).catch(() => {
|
|
9307
|
+
});
|
|
9308
|
+
await page.waitForTimeout(1500);
|
|
9309
|
+
const html = await page.content();
|
|
9310
|
+
return extractFacebookOrganicVideo(html, page.url(), sourceUrl, quality);
|
|
9311
|
+
}
|
|
9312
|
+
|
|
9192
9313
|
// src/api/facebook-ad-routes.ts
|
|
9193
9314
|
import { fal as fal2 } from "@fal-ai/client";
|
|
9194
9315
|
var FacebookAdBodySchema = z13.object({
|
|
@@ -9208,6 +9329,10 @@ var FacebookPageIntelBodySchema = z13.object({
|
|
|
9208
9329
|
var FacebookTranscribeBodySchema = z13.object({
|
|
9209
9330
|
videoUrl: z13.string().trim().min(1, "videoUrl is required")
|
|
9210
9331
|
});
|
|
9332
|
+
var FacebookVideoTranscribeBodySchema = z13.object({
|
|
9333
|
+
url: z13.string().trim().min(1, "url is required"),
|
|
9334
|
+
quality: z13.enum(["best", "hd", "sd"]).default("best")
|
|
9335
|
+
});
|
|
9211
9336
|
var FacebookSearchBodySchema = z13.object({
|
|
9212
9337
|
query: z13.string().trim().min(1, "query is required"),
|
|
9213
9338
|
country: z13.string().trim().toUpperCase().optional(),
|
|
@@ -9220,6 +9345,39 @@ var FacebookMediaBodySchema = z13.object({
|
|
|
9220
9345
|
function invalidRequest(message) {
|
|
9221
9346
|
return { error_code: "invalid_request", message };
|
|
9222
9347
|
}
|
|
9348
|
+
function isAllowedFacebookOrganicUrl(url) {
|
|
9349
|
+
const hostname = url.hostname.toLowerCase().replace(/^www\./, "").replace(/^m\./, "");
|
|
9350
|
+
return hostname === "facebook.com" || hostname === "fb.watch";
|
|
9351
|
+
}
|
|
9352
|
+
function facebookTranscriptMarkdown(title, text, chunks, durationMs) {
|
|
9353
|
+
const fmtTs2 = (s) => `${Math.floor(s / 60)}:${String(Math.floor(s % 60)).padStart(2, "0")}`;
|
|
9354
|
+
const lines = [title, "", `*Transcribed in ${(durationMs / 1e3).toFixed(1)}s*`, "", "## Full Text", "", text, ""];
|
|
9355
|
+
if (chunks.length) {
|
|
9356
|
+
lines.push("## Timestamped Segments", "");
|
|
9357
|
+
for (const ch of chunks) {
|
|
9358
|
+
lines.push(`**[${fmtTs2(ch.timestamp[0])} -> ${fmtTs2(ch.timestamp[1])}]** ${ch.text.trim()}`, "");
|
|
9359
|
+
}
|
|
9360
|
+
}
|
|
9361
|
+
return lines.join("\n");
|
|
9362
|
+
}
|
|
9363
|
+
async function transcribeFacebookVideoUrl(videoUrl, markdownTitle = "# Facebook Video Transcript") {
|
|
9364
|
+
const startMs = Date.now();
|
|
9365
|
+
const result = await fal2.subscribe("fal-ai/wizper", {
|
|
9366
|
+
input: { audio_url: videoUrl, task: "transcribe", language: "en" },
|
|
9367
|
+
logs: false,
|
|
9368
|
+
pollInterval: 3e3
|
|
9369
|
+
});
|
|
9370
|
+
const data = result.data;
|
|
9371
|
+
const text = data.text ?? "";
|
|
9372
|
+
const chunks = data.chunks ?? [];
|
|
9373
|
+
const durationMs = Date.now() - startMs;
|
|
9374
|
+
return {
|
|
9375
|
+
text,
|
|
9376
|
+
chunks,
|
|
9377
|
+
durationMs,
|
|
9378
|
+
markdown: facebookTranscriptMarkdown(markdownTitle, text, chunks, durationMs)
|
|
9379
|
+
};
|
|
9380
|
+
}
|
|
9223
9381
|
async function detectSoftBlock(driver) {
|
|
9224
9382
|
const page = driver.getPage();
|
|
9225
9383
|
const bodyText = await page.evaluate(() => document.body?.innerText ?? "").catch(() => "");
|
|
@@ -9363,26 +9521,9 @@ facebookAdApp.post("/transcribe", createApiKeyAuth(), async (c) => {
|
|
|
9363
9521
|
const { ok, balance_mc } = await debitMc(fbUser.id, MC_COSTS.fb_transcribe, LedgerOperation.FB_TRANSCRIBE, videoUrl);
|
|
9364
9522
|
if (!ok) return c.json(insufficientBalanceResponse(balance_mc, MC_COSTS.fb_transcribe), 402);
|
|
9365
9523
|
debited = true;
|
|
9366
|
-
const
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
logs: false,
|
|
9370
|
-
pollInterval: 3e3
|
|
9371
|
-
});
|
|
9372
|
-
const data = result.data;
|
|
9373
|
-
const text = data.text ?? "";
|
|
9374
|
-
const chunks = data.chunks ?? [];
|
|
9375
|
-
const durationMs = Date.now() - startMs;
|
|
9376
|
-
const fmtTs2 = (s) => `${Math.floor(s / 60)}:${String(Math.floor(s % 60)).padStart(2, "0")}`;
|
|
9377
|
-
const lines = ["# Facebook Ad Transcript", "", `*Transcribed in ${(durationMs / 1e3).toFixed(1)}s*`, "", "## Full Text", "", text, ""];
|
|
9378
|
-
if (chunks.length) {
|
|
9379
|
-
lines.push("## Timestamped Segments", "");
|
|
9380
|
-
for (const ch of chunks) {
|
|
9381
|
-
lines.push(`**[${fmtTs2(ch.timestamp[0])} \u2192 ${fmtTs2(ch.timestamp[1])}]** ${ch.text.trim()}`, "");
|
|
9382
|
-
}
|
|
9383
|
-
}
|
|
9384
|
-
await logRequestEvent({ userId: fbUser.id, source: "facebook_transcribe", status: "done", query: videoUrl, resultCount: chunks.length, result: { text, chunks, durationMs } });
|
|
9385
|
-
return c.json({ text, chunks, durationMs, markdown: lines.join("\n") });
|
|
9524
|
+
const transcript = await transcribeFacebookVideoUrl(videoUrl, "# Facebook Ad Transcript");
|
|
9525
|
+
await logRequestEvent({ userId: fbUser.id, source: "facebook_transcribe", status: "done", query: videoUrl, resultCount: transcript.chunks.length, result: { text: transcript.text, chunks: transcript.chunks, durationMs: transcript.durationMs } });
|
|
9526
|
+
return c.json(transcript);
|
|
9386
9527
|
} catch (err) {
|
|
9387
9528
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9388
9529
|
if (debited) await creditMc(fbUser.id, MC_COSTS.fb_transcribe, LedgerOperation.FB_TRANSCRIBE_REFUND, "failed call");
|
|
@@ -9392,6 +9533,62 @@ facebookAdApp.post("/transcribe", createApiKeyAuth(), async (c) => {
|
|
|
9392
9533
|
await releaseConcurrencyGate(gate.lockId);
|
|
9393
9534
|
}
|
|
9394
9535
|
});
|
|
9536
|
+
facebookAdApp.post("/video-transcribe", createApiKeyAuth(), async (c) => {
|
|
9537
|
+
const raw = await c.req.json().catch(() => ({}));
|
|
9538
|
+
const parsed = FacebookVideoTranscribeBodySchema.safeParse(raw);
|
|
9539
|
+
if (!parsed.success) {
|
|
9540
|
+
return c.json(invalidRequest(parsed.error.issues[0]?.message ?? "Invalid request"), 400);
|
|
9541
|
+
}
|
|
9542
|
+
const body = parsed.data;
|
|
9543
|
+
const urlCheck = await validatePublicHttpUrl(body.url, { field: "url", requireHttps: false });
|
|
9544
|
+
if (urlCheck.error) {
|
|
9545
|
+
return c.json(invalidRequest(urlCheck.error), 400);
|
|
9546
|
+
}
|
|
9547
|
+
const sourceUrl = urlCheck.parsed;
|
|
9548
|
+
if (!isAllowedFacebookOrganicUrl(sourceUrl)) {
|
|
9549
|
+
return c.json(invalidRequest("url must be a Facebook organic video, reel, or share URL"), 400);
|
|
9550
|
+
}
|
|
9551
|
+
const fbUser = c.get("user");
|
|
9552
|
+
const gate = await acquireConcurrencyGate(fbUser, "facebook_video_transcribe", {
|
|
9553
|
+
reuseLockId: c.req.header("x-mcp-scraper-concurrency-lock"),
|
|
9554
|
+
metadata: { url: sourceUrl.href }
|
|
9555
|
+
});
|
|
9556
|
+
if (!gate.ok) return c.json(concurrencyLimitExceededResponse(gate), 429, { "Retry-After": String(gate.retryAfterSeconds) });
|
|
9557
|
+
fal2.config({ credentials: process.env.FAL_KEY });
|
|
9558
|
+
const driver = new BrowserDriver();
|
|
9559
|
+
let debited = false;
|
|
9560
|
+
try {
|
|
9561
|
+
const { ok, balance_mc } = await debitMc(fbUser.id, MC_COSTS.fb_transcribe, LedgerOperation.FB_TRANSCRIBE, sourceUrl.href);
|
|
9562
|
+
if (!ok) return c.json(insufficientBalanceResponse(balance_mc, MC_COSTS.fb_transcribe), 402);
|
|
9563
|
+
debited = true;
|
|
9564
|
+
await driver.launch(await kernelLaunchOptsResidential());
|
|
9565
|
+
await driver.navigateTo(sourceUrl.href);
|
|
9566
|
+
const page = driver.getPage();
|
|
9567
|
+
const video = await extractFacebookOrganicVideoFromPage(page, sourceUrl.href, body.quality);
|
|
9568
|
+
const transcript = await transcribeFacebookVideoUrl(video.videoUrl, "# Facebook Organic Video Transcript");
|
|
9569
|
+
const result = {
|
|
9570
|
+
...video,
|
|
9571
|
+
videoDurationSec: video.durationSec,
|
|
9572
|
+
text: transcript.text,
|
|
9573
|
+
chunks: transcript.chunks,
|
|
9574
|
+
durationMs: transcript.durationMs,
|
|
9575
|
+
markdown: transcript.markdown
|
|
9576
|
+
};
|
|
9577
|
+
await logRequestEvent({ userId: fbUser.id, source: "facebook_video_transcribe", status: "done", query: sourceUrl.href, resultCount: transcript.chunks.length, result });
|
|
9578
|
+
return c.json(result);
|
|
9579
|
+
} catch (err) {
|
|
9580
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9581
|
+
if (debited) await creditMc(fbUser.id, MC_COSTS.fb_transcribe, LedgerOperation.FB_TRANSCRIBE_REFUND, "failed call");
|
|
9582
|
+
await logRequestEvent({ userId: fbUser.id, source: "facebook_video_transcribe", status: "failed", query: sourceUrl.href, error: msg });
|
|
9583
|
+
if (msg.toLowerCase().includes("blocked") || msg.toLowerCase().includes("captcha")) {
|
|
9584
|
+
return c.json({ error: msg }, 503);
|
|
9585
|
+
}
|
|
9586
|
+
return c.json({ error: msg }, 500);
|
|
9587
|
+
} finally {
|
|
9588
|
+
await driver.close();
|
|
9589
|
+
await releaseConcurrencyGate(gate.lockId);
|
|
9590
|
+
}
|
|
9591
|
+
});
|
|
9395
9592
|
facebookAdApp.post("/search", createApiKeyAuth(), async (c) => {
|
|
9396
9593
|
const raw = await c.req.json().catch(() => ({}));
|
|
9397
9594
|
const parsed = FacebookSearchBodySchema.safeParse(raw);
|
|
@@ -13602,7 +13799,7 @@ var sessionCookieOptions = {
|
|
|
13602
13799
|
sameSite: "Strict"
|
|
13603
13800
|
};
|
|
13604
13801
|
function configuredOrigins() {
|
|
13605
|
-
const origins = /* @__PURE__ */ new Set(["https://mcpscraper.dev"]);
|
|
13802
|
+
const origins = /* @__PURE__ */ new Set(["https://mcpscraper.dev", "https://www.mcpscraper.dev"]);
|
|
13606
13803
|
for (const raw of (process.env.ALLOWED_ORIGINS ?? process.env.APP_ORIGIN ?? "").split(",")) {
|
|
13607
13804
|
const trimmed = raw.trim();
|
|
13608
13805
|
if (trimmed) origins.add(trimmed);
|
|
@@ -14536,4 +14733,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
14536
14733
|
export {
|
|
14537
14734
|
app
|
|
14538
14735
|
};
|
|
14539
|
-
//# sourceMappingURL=server-
|
|
14736
|
+
//# sourceMappingURL=server-KSEQLZNP.js.map
|