mcp-scraper 0.3.16 → 0.3.18
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 +26 -58
- package/dist/bin/api-server.cjs +418 -53
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +4 -4
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +5 -5
- package/dist/bin/mcp-scraper-cli.js.map +1 -1
- package/dist/bin/mcp-scraper-install.cjs +12 -12
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +3 -3
- package/dist/bin/mcp-scraper-install.js.map +1 -1
- package/dist/bin/mcp-stdio-server.cjs +2554 -781
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +1377 -9
- package/dist/bin/mcp-stdio-server.js.map +1 -1
- package/dist/bin/paa-harvest.js +2 -3
- package/dist/bin/paa-harvest.js.map +1 -1
- package/dist/{chunk-7XARJHS6.js → chunk-2XCNU22L.js} +332 -13
- package/dist/chunk-2XCNU22L.js.map +1 -0
- package/dist/chunk-C7ZNIXOA.js +7 -0
- package/dist/chunk-C7ZNIXOA.js.map +1 -0
- package/dist/{chunk-ACIUCZ27.js → chunk-DE7WP4UU.js} +11 -11
- package/dist/chunk-DE7WP4UU.js.map +1 -0
- package/dist/{chunk-ZAUMSBV3.js → chunk-HDPWLYK7.js} +6 -6
- package/dist/{chunk-4OPKIDON.js → chunk-IGOEAKC7.js} +4 -6
- package/dist/{chunk-4OPKIDON.js.map → chunk-IGOEAKC7.js.map} +1 -1
- package/dist/{chunk-M2S27J6Z.js → chunk-ZAP7MYVO.js} +26 -1
- package/dist/chunk-ZAP7MYVO.js.map +1 -0
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/{server-LPVBSE2E.js → server-3M3XCVOT.js} +328 -157
- package/dist/server-3M3XCVOT.js.map +1 -0
- package/dist/{worker-2WVKKCC7.js → worker-J6I5XP2F.js} +9 -10
- package/dist/{worker-2WVKKCC7.js.map → worker-J6I5XP2F.js.map} +1 -1
- package/docs/mcp-tool-manifest.generated.json +28 -27
- package/package.json +3 -3
- package/dist/bin/browser-agent-stdio-server.cjs +0 -1523
- package/dist/bin/browser-agent-stdio-server.cjs.map +0 -1
- package/dist/bin/browser-agent-stdio-server.d.cts +0 -1
- package/dist/bin/browser-agent-stdio-server.d.ts +0 -1
- package/dist/bin/browser-agent-stdio-server.js +0 -43
- package/dist/bin/browser-agent-stdio-server.js.map +0 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs +0 -5601
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs.map +0 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.d.cts +0 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.d.ts +0 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.js +0 -70
- package/dist/bin/mcp-scraper-combined-stdio-server.js.map +0 -1
- package/dist/chunk-3YGKXXUG.js +0 -133
- package/dist/chunk-3YGKXXUG.js.map +0 -1
- package/dist/chunk-7XARJHS6.js.map +0 -1
- package/dist/chunk-ACIUCZ27.js.map +0 -1
- package/dist/chunk-ISZWGIWL.js +0 -1332
- package/dist/chunk-ISZWGIWL.js.map +0 -1
- package/dist/chunk-M2S27J6Z.js.map +0 -1
- package/dist/chunk-SOMBZK3V.js +0 -7
- package/dist/chunk-SOMBZK3V.js.map +0 -1
- package/dist/chunk-WN7PBKMV.js +0 -28
- package/dist/chunk-WN7PBKMV.js.map +0 -1
- package/dist/server-LPVBSE2E.js.map +0 -1
- /package/dist/{chunk-ZAUMSBV3.js.map → chunk-HDPWLYK7.js.map} +0 -0
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CaptureSerpPageSnapshotsInputSchema,
|
|
3
|
+
CaptureSerpPageSnapshotsOutputSchema,
|
|
4
|
+
CaptureSerpSnapshotInputSchema,
|
|
5
|
+
CaptureSerpSnapshotOutputSchema,
|
|
6
|
+
HttpMcpToolExecutor,
|
|
7
|
+
auditImages,
|
|
8
|
+
buildLinkGraph,
|
|
9
|
+
buildLinkReport,
|
|
10
|
+
buildPaaExtractorMcpServer,
|
|
11
|
+
computeIssues,
|
|
12
|
+
configureReportSaving,
|
|
13
|
+
exportFanout,
|
|
14
|
+
formatCaptureSerpPageSnapshots,
|
|
15
|
+
formatCaptureSerpSnapshot,
|
|
16
|
+
harvestTimeoutBudget,
|
|
17
|
+
liveWebToolAnnotations,
|
|
18
|
+
outputBaseDir,
|
|
19
|
+
renderImageSection,
|
|
20
|
+
renderIssueReport,
|
|
21
|
+
renderLinkReport,
|
|
22
|
+
sanitizeAttempts,
|
|
23
|
+
sanitizeHarvestResult
|
|
24
|
+
} from "./chunk-2XCNU22L.js";
|
|
25
|
+
import {
|
|
26
|
+
csvRecords,
|
|
27
|
+
listWorkflowDefinitions,
|
|
28
|
+
rowsToCsv,
|
|
29
|
+
runWorkflow,
|
|
30
|
+
runWorkflowStep,
|
|
31
|
+
workflowDefinition,
|
|
32
|
+
workflowOutputBaseDir,
|
|
33
|
+
workflowStepCount,
|
|
34
|
+
workflowSupportsSteps
|
|
35
|
+
} from "./chunk-H2R232HK.js";
|
|
36
|
+
import "./chunk-C7ZNIXOA.js";
|
|
1
37
|
import {
|
|
2
38
|
BALANCE_PACK_LABELS,
|
|
3
39
|
BALANCE_PRICE_IDS,
|
|
@@ -16,7 +52,34 @@ import {
|
|
|
16
52
|
harvestProblemResponse,
|
|
17
53
|
insufficientBalanceResponse,
|
|
18
54
|
serializeHarvestProblem
|
|
19
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-HDPWLYK7.js";
|
|
56
|
+
import {
|
|
57
|
+
BrowserDriver,
|
|
58
|
+
MapsSelectors,
|
|
59
|
+
buildYouTubeChannelVideosUrl,
|
|
60
|
+
deleteKernelProxyId,
|
|
61
|
+
harvest,
|
|
62
|
+
resolveKernelProxyId
|
|
63
|
+
} from "./chunk-IGOEAKC7.js";
|
|
64
|
+
import {
|
|
65
|
+
CaptchaError,
|
|
66
|
+
RECAPTCHA_INSTRUCTIONS,
|
|
67
|
+
browserServiceApiKey,
|
|
68
|
+
browserServiceProfileName,
|
|
69
|
+
browserServiceProfileSaveChanges,
|
|
70
|
+
browserServiceProxyId,
|
|
71
|
+
sanitizeVendorName
|
|
72
|
+
} from "./chunk-ZAP7MYVO.js";
|
|
73
|
+
import {
|
|
74
|
+
DEFAULT_MAPS_PROXY_MODE,
|
|
75
|
+
DEFAULT_PROXY_MODE,
|
|
76
|
+
MapsPlaceOptionsSchema,
|
|
77
|
+
MapsSearchOptionsSchema,
|
|
78
|
+
RawMapsAboutAttributeSchema,
|
|
79
|
+
RawMapsHoursRowSchema,
|
|
80
|
+
RawMapsOverviewSchema,
|
|
81
|
+
RawMapsReviewStatsSchema
|
|
82
|
+
} from "./chunk-LFATOGDF.js";
|
|
20
83
|
import {
|
|
21
84
|
SiteAuditJobRowSchema,
|
|
22
85
|
advanceWorkflowRunStep,
|
|
@@ -78,116 +141,6 @@ import {
|
|
|
78
141
|
setStripeCustomerId,
|
|
79
142
|
verifyPassword
|
|
80
143
|
} from "./chunk-5H22TOXQ.js";
|
|
81
|
-
import {
|
|
82
|
-
BrowserDriver,
|
|
83
|
-
MapsSelectors,
|
|
84
|
-
buildYouTubeChannelVideosUrl,
|
|
85
|
-
deleteKernelProxyId,
|
|
86
|
-
harvest,
|
|
87
|
-
resolveKernelProxyId
|
|
88
|
-
} from "./chunk-4OPKIDON.js";
|
|
89
|
-
import {
|
|
90
|
-
CaptureSerpPageSnapshotsInputSchema,
|
|
91
|
-
CaptureSerpPageSnapshotsOutputSchema,
|
|
92
|
-
CaptureSerpSnapshotInputSchema,
|
|
93
|
-
CaptureSerpSnapshotOutputSchema,
|
|
94
|
-
HttpMcpToolExecutor,
|
|
95
|
-
auditImages,
|
|
96
|
-
buildLinkGraph,
|
|
97
|
-
buildPaaExtractorMcpServer,
|
|
98
|
-
computeIssues,
|
|
99
|
-
configureReportSaving,
|
|
100
|
-
formatCaptureSerpPageSnapshots,
|
|
101
|
-
formatCaptureSerpSnapshot,
|
|
102
|
-
harvestTimeoutBudget,
|
|
103
|
-
liveWebToolAnnotations,
|
|
104
|
-
outputBaseDir,
|
|
105
|
-
renderImageSection,
|
|
106
|
-
renderIssueReport
|
|
107
|
-
} from "./chunk-7XARJHS6.js";
|
|
108
|
-
import {
|
|
109
|
-
CaptchaError,
|
|
110
|
-
RECAPTCHA_INSTRUCTIONS,
|
|
111
|
-
sanitizeVendorName
|
|
112
|
-
} from "./chunk-M2S27J6Z.js";
|
|
113
|
-
import {
|
|
114
|
-
exportFanout
|
|
115
|
-
} from "./chunk-3YGKXXUG.js";
|
|
116
|
-
import {
|
|
117
|
-
browserServiceApiKey,
|
|
118
|
-
browserServiceProfileName,
|
|
119
|
-
browserServiceProfileSaveChanges,
|
|
120
|
-
browserServiceProxyId
|
|
121
|
-
} from "./chunk-WN7PBKMV.js";
|
|
122
|
-
import {
|
|
123
|
-
csvRecords,
|
|
124
|
-
listWorkflowDefinitions,
|
|
125
|
-
rowsToCsv,
|
|
126
|
-
runWorkflow,
|
|
127
|
-
runWorkflowStep,
|
|
128
|
-
workflowDefinition,
|
|
129
|
-
workflowOutputBaseDir,
|
|
130
|
-
workflowStepCount,
|
|
131
|
-
workflowSupportsSteps
|
|
132
|
-
} from "./chunk-H2R232HK.js";
|
|
133
|
-
import {
|
|
134
|
-
DEFAULT_MAPS_PROXY_MODE,
|
|
135
|
-
DEFAULT_PROXY_MODE,
|
|
136
|
-
MapsPlaceOptionsSchema,
|
|
137
|
-
MapsSearchOptionsSchema,
|
|
138
|
-
RawMapsAboutAttributeSchema,
|
|
139
|
-
RawMapsHoursRowSchema,
|
|
140
|
-
RawMapsOverviewSchema,
|
|
141
|
-
RawMapsReviewStatsSchema
|
|
142
|
-
} from "./chunk-LFATOGDF.js";
|
|
143
|
-
import "./chunk-SOMBZK3V.js";
|
|
144
|
-
|
|
145
|
-
// src/api/outbound-sanitize.ts
|
|
146
|
-
var KEY_RENAMES = {
|
|
147
|
-
kernel: "browserRuntime",
|
|
148
|
-
kernel_session_id: "browser_session_id",
|
|
149
|
-
kernel_delete_started: "session_cleanup_started",
|
|
150
|
-
kernel_delete_succeeded: "session_cleanup_succeeded",
|
|
151
|
-
kernel_delete_error: "session_cleanup_error",
|
|
152
|
-
kernelSessionId: "browserSessionId",
|
|
153
|
-
kernelDeleteStarted: "sessionCleanupStarted",
|
|
154
|
-
kernelDeleteSucceeded: "sessionCleanupSucceeded",
|
|
155
|
-
kernelDeleteError: "sessionCleanupError",
|
|
156
|
-
kernelProxyId: "proxyId"
|
|
157
|
-
};
|
|
158
|
-
var SANITIZED_VALUE_KEYS = /error|message/i;
|
|
159
|
-
function sanitizeOutboundDiagnostics(value, parentKey = "") {
|
|
160
|
-
if (typeof value === "string") {
|
|
161
|
-
if (SANITIZED_VALUE_KEYS.test(parentKey) && /kernel/i.test(value)) {
|
|
162
|
-
return sanitizeVendorName(value);
|
|
163
|
-
}
|
|
164
|
-
return value;
|
|
165
|
-
}
|
|
166
|
-
if (Array.isArray(value)) return value.map((v) => sanitizeOutboundDiagnostics(v, parentKey));
|
|
167
|
-
if (value !== null && typeof value === "object") {
|
|
168
|
-
const out = {};
|
|
169
|
-
for (const [key, val] of Object.entries(value)) {
|
|
170
|
-
const renamed = KEY_RENAMES[key] ?? key;
|
|
171
|
-
out[renamed] = sanitizeOutboundDiagnostics(val, key);
|
|
172
|
-
}
|
|
173
|
-
return out;
|
|
174
|
-
}
|
|
175
|
-
return value;
|
|
176
|
-
}
|
|
177
|
-
function sanitizeAttempts(attempts) {
|
|
178
|
-
return attempts.map((a) => sanitizeOutboundDiagnostics(a));
|
|
179
|
-
}
|
|
180
|
-
function sanitizeHarvestResult(result) {
|
|
181
|
-
const diagnostics = result?.diagnostics;
|
|
182
|
-
if (!diagnostics?.debug) return result;
|
|
183
|
-
return {
|
|
184
|
-
...result,
|
|
185
|
-
diagnostics: {
|
|
186
|
-
...diagnostics,
|
|
187
|
-
debug: sanitizeOutboundDiagnostics(diagnostics.debug)
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
144
|
|
|
192
145
|
// src/blog/registry.ts
|
|
193
146
|
var posts = [
|
|
@@ -7584,14 +7537,10 @@ async function settleExtractJob(jobId, userId, refundMc, netChargeMc, reference)
|
|
|
7584
7537
|
|
|
7585
7538
|
// src/inngest/functions/site-extract.ts
|
|
7586
7539
|
var BATCH = 30;
|
|
7587
|
-
function chunk(items, size) {
|
|
7588
|
-
const out = [];
|
|
7589
|
-
for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
|
|
7590
|
-
return out;
|
|
7591
|
-
}
|
|
7592
7540
|
function buildArtifacts(job, pages, branding, imageAudit) {
|
|
7593
7541
|
const { edges, metrics } = buildLinkGraph(pages, job.startUrl);
|
|
7594
7542
|
const issues = computeIssues(pages, metrics);
|
|
7543
|
+
const linkReport = buildLinkReport(edges, [...metrics.values()], job.startUrl);
|
|
7595
7544
|
let reportMd = renderIssueReport(job.startUrl, pages, issues, metrics);
|
|
7596
7545
|
if (imageAudit) reportMd += `
|
|
7597
7546
|
|
|
@@ -7607,7 +7556,10 @@ ${renderImageSection(imageAudit)}`;
|
|
|
7607
7556
|
{ name: "issues.json", body: JSON.stringify(issues, null, 2), type: "application/json" },
|
|
7608
7557
|
{ name: "pages.jsonl", body: jsonl(pageRows), type: "application/x-ndjson" },
|
|
7609
7558
|
{ name: "links.jsonl", body: jsonl(edges), type: "application/x-ndjson" },
|
|
7610
|
-
{ name: "link-metrics.jsonl", body: jsonl([...metrics.values()]), type: "application/x-ndjson" }
|
|
7559
|
+
{ name: "link-metrics.jsonl", body: jsonl([...metrics.values()]), type: "application/x-ndjson" },
|
|
7560
|
+
{ name: "link-report.md", body: renderLinkReport(linkReport), type: "text/markdown" },
|
|
7561
|
+
{ name: "links-summary.json", body: JSON.stringify(linkReport.summary, null, 2), type: "application/json" },
|
|
7562
|
+
{ name: "external-domains.json", body: JSON.stringify(linkReport.externalDomains, null, 2), type: "application/json" }
|
|
7611
7563
|
];
|
|
7612
7564
|
if (imageAudit) {
|
|
7613
7565
|
files.push({ name: "images.jsonl", body: jsonl(imageAudit.rows), type: "application/x-ndjson" });
|
|
@@ -7643,18 +7595,62 @@ var siteExtractFn = inngest.createFunction(
|
|
|
7643
7595
|
const maxPages = Number(job.options.maxPages ?? 1e4);
|
|
7644
7596
|
const concurrency = Number(job.options.concurrency ?? 1);
|
|
7645
7597
|
const urlsPerBrowser = Number(job.options.urlsPerBrowser ?? job.options.rotateProxyEvery ?? 10);
|
|
7646
|
-
const
|
|
7598
|
+
const seed = await step.run("discover", async () => {
|
|
7647
7599
|
const discovered = await discoverUrls(job.startUrl, maxPages, key);
|
|
7648
|
-
|
|
7649
|
-
|
|
7600
|
+
const out = discovered.length ? discovered : [job.startUrl];
|
|
7601
|
+
await setExtractJobTotal(jobId, out.length);
|
|
7602
|
+
return out;
|
|
7650
7603
|
});
|
|
7651
|
-
const
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7604
|
+
const siteHost = (() => {
|
|
7605
|
+
try {
|
|
7606
|
+
return new URL(job.startUrl).hostname.replace(/^www\./, "");
|
|
7607
|
+
} catch {
|
|
7608
|
+
return "";
|
|
7609
|
+
}
|
|
7610
|
+
})();
|
|
7611
|
+
const norm = (u) => {
|
|
7612
|
+
try {
|
|
7613
|
+
const x = new URL(u);
|
|
7614
|
+
x.hash = "";
|
|
7615
|
+
return (x.origin + x.pathname).replace(/\/+$/, "") + x.search;
|
|
7616
|
+
} catch {
|
|
7617
|
+
return u;
|
|
7618
|
+
}
|
|
7619
|
+
};
|
|
7620
|
+
const sameSite = (u) => {
|
|
7621
|
+
try {
|
|
7622
|
+
return new URL(u).hostname.replace(/^www\./, "") === siteHost;
|
|
7623
|
+
} catch {
|
|
7624
|
+
return false;
|
|
7625
|
+
}
|
|
7626
|
+
};
|
|
7627
|
+
const queue = [...seed];
|
|
7628
|
+
const seen = new Set(seed.map(norm));
|
|
7629
|
+
let crawled = 0;
|
|
7630
|
+
const MAX_BATCHES = Math.ceil(maxPages / BATCH) + 30;
|
|
7631
|
+
for (let i = 0; i < MAX_BATCHES && crawled < maxPages && crawled < queue.length; i++) {
|
|
7632
|
+
const batch = queue.slice(crawled, Math.min(crawled + BATCH, maxPages));
|
|
7633
|
+
if (!batch.length) break;
|
|
7634
|
+
const newLinks = await step.run(`crawl-batch-${i}`, async () => {
|
|
7635
|
+
const pages = await extractPagesRotating(batch, { kernelApiKey: key, concurrency, urlsPerBrowser });
|
|
7655
7636
|
await saveExtractPages(jobId, pages);
|
|
7656
|
-
|
|
7637
|
+
const found = [];
|
|
7638
|
+
for (const p of pages) for (const l of p.outlinks ?? []) {
|
|
7639
|
+
if (l.internal && l.href && sameSite(l.href)) found.push(l.href);
|
|
7640
|
+
}
|
|
7641
|
+
return [...new Set(found)];
|
|
7657
7642
|
});
|
|
7643
|
+
crawled += batch.length;
|
|
7644
|
+
let added = false;
|
|
7645
|
+
for (const href of newLinks) {
|
|
7646
|
+
const n = norm(href);
|
|
7647
|
+
if (!seen.has(n) && seen.size < maxPages) {
|
|
7648
|
+
seen.add(n);
|
|
7649
|
+
queue.push(href);
|
|
7650
|
+
added = true;
|
|
7651
|
+
}
|
|
7652
|
+
}
|
|
7653
|
+
if (added) await setExtractJobTotal(jobId, Math.min(seen.size, maxPages));
|
|
7658
7654
|
}
|
|
7659
7655
|
const branding = Array.isArray(job.options.formats) && job.options.formats.includes("branding") ? await step.run("branding", () => extractBranding(job.startUrl, key).catch(() => null)) : null;
|
|
7660
7656
|
const imageAudit = Array.isArray(job.options.formats) && job.options.formats.includes("images") ? await step.run("image-audit", async () => {
|
|
@@ -9337,10 +9333,10 @@ function buildTranscriptMarkdown(result) {
|
|
|
9337
9333
|
if (result.chunks?.length) {
|
|
9338
9334
|
lines.push("## Timestamped Segments");
|
|
9339
9335
|
lines.push("");
|
|
9340
|
-
for (const
|
|
9341
|
-
const start = fmtTs(
|
|
9342
|
-
const end = fmtTs(
|
|
9343
|
-
lines.push(`**[${start} \u2192 ${end}]** ${
|
|
9336
|
+
for (const chunk of result.chunks) {
|
|
9337
|
+
const start = fmtTs(chunk.timestamp[0]);
|
|
9338
|
+
const end = fmtTs(chunk.timestamp[1]);
|
|
9339
|
+
lines.push(`**[${start} \u2192 ${end}]** ${chunk.text.trim()}`);
|
|
9344
9340
|
lines.push("");
|
|
9345
9341
|
}
|
|
9346
9342
|
}
|
|
@@ -9841,20 +9837,20 @@ var FacebookAdExtractor = class {
|
|
|
9841
9837
|
if (splitRe.lastIndex === m.index) splitRe.lastIndex++;
|
|
9842
9838
|
}
|
|
9843
9839
|
if (last < bodyText.length) adChunks.push(bodyText.slice(last));
|
|
9844
|
-
const ads = adChunks.filter((c) => /Library ID[:\s]+\d{10,20}/i.test(c)).slice(0, maxAds).map((
|
|
9845
|
-
const lidM =
|
|
9840
|
+
const ads = adChunks.filter((c) => /Library ID[:\s]+\d{10,20}/i.test(c)).slice(0, maxAds).map((chunk) => {
|
|
9841
|
+
const lidM = chunk.match(/Library ID[:\s]+([0-9]{10,20})/i);
|
|
9846
9842
|
const libraryId = lidM ? lidM[1] : null;
|
|
9847
|
-
const statusM =
|
|
9843
|
+
const statusM = chunk.match(/^(Active|Inactive)/i);
|
|
9848
9844
|
const status = statusM ? statusM[1] : null;
|
|
9849
|
-
const startM =
|
|
9845
|
+
const startM = chunk.match(/Started running on\s+([A-Za-z]+\.?\s+\d{1,2},?\s*\d{4})/i);
|
|
9850
9846
|
const started = startM ? startM[1].replace(/\s+/g, " ").trim() : null;
|
|
9851
9847
|
const visual = adVisuals[libraryId ?? ""] ?? { imageSrc: null, videoSrc: null, videoPoster: null };
|
|
9852
|
-
const hasVideoText = /0:00\s*\/\s*0:00|\d+:\d+\s*\/\s*\d+:\d+/.test(
|
|
9848
|
+
const hasVideoText = /0:00\s*\/\s*0:00|\d+:\d+\s*\/\s*\d+:\d+/.test(chunk);
|
|
9853
9849
|
const creativeType = visual.videoSrc || hasVideoText ? "video" : visual.imageSrc ? "image" : "unknown";
|
|
9854
9850
|
let domain = null;
|
|
9855
9851
|
const domainRe = /\b([A-Z0-9]{2,}(?:\.[A-Z]{2,})+)\b/g;
|
|
9856
9852
|
let dm;
|
|
9857
|
-
while ((dm = domainRe.exec(
|
|
9853
|
+
while ((dm = domainRe.exec(chunk)) !== null) {
|
|
9858
9854
|
const c = dm[1];
|
|
9859
9855
|
if (c.length >= 6 && c !== "LIBRARY") {
|
|
9860
9856
|
domain = c;
|
|
@@ -9863,9 +9859,9 @@ var FacebookAdExtractor = class {
|
|
|
9863
9859
|
}
|
|
9864
9860
|
let primaryText = null;
|
|
9865
9861
|
let headline = null;
|
|
9866
|
-
const sponsoredIdx =
|
|
9862
|
+
const sponsoredIdx = chunk.search(/\bSponsored\b/i);
|
|
9867
9863
|
if (sponsoredIdx >= 0) {
|
|
9868
|
-
let afterSponsored =
|
|
9864
|
+
let afterSponsored = chunk.slice(sponsoredIdx + "Sponsored".length).trim();
|
|
9869
9865
|
afterSponsored = afterSponsored.replace(/\s*\d*:?\d+\s*\/\s*\d*:?\d+.*$/, "");
|
|
9870
9866
|
if (domain) {
|
|
9871
9867
|
const di = afterSponsored.indexOf(domain);
|
|
@@ -9876,18 +9872,18 @@ var FacebookAdExtractor = class {
|
|
|
9876
9872
|
}
|
|
9877
9873
|
const ctaRe2 = new RegExp("\\b(" + CTA_LABELS.map((l) => l.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|") + ")\\b", "i");
|
|
9878
9874
|
if (domain) {
|
|
9879
|
-
const di =
|
|
9875
|
+
const di = chunk.indexOf(domain);
|
|
9880
9876
|
if (di >= 0) {
|
|
9881
|
-
let afterDomain =
|
|
9877
|
+
let afterDomain = chunk.slice(di + domain.length).trim();
|
|
9882
9878
|
const ctaMatch = afterDomain.search(ctaRe2);
|
|
9883
9879
|
if (ctaMatch >= 0) afterDomain = afterDomain.slice(0, ctaMatch).trim();
|
|
9884
9880
|
if (afterDomain.length > 3 && afterDomain.length < 120) headline = afterDomain;
|
|
9885
9881
|
}
|
|
9886
9882
|
}
|
|
9887
9883
|
if (!headline) {
|
|
9888
|
-
const ctaIdx =
|
|
9884
|
+
const ctaIdx = chunk.search(ctaRe2);
|
|
9889
9885
|
if (ctaIdx > 0) {
|
|
9890
|
-
const beforeCta =
|
|
9886
|
+
const beforeCta = chunk.slice(0, ctaIdx).trimEnd();
|
|
9891
9887
|
const sentenceEnd = Math.max(beforeCta.lastIndexOf(". "), beforeCta.lastIndexOf("! "), beforeCta.lastIndexOf("? "));
|
|
9892
9888
|
if (sentenceEnd >= 0) {
|
|
9893
9889
|
const candidate = beforeCta.slice(sentenceEnd + 2).trim();
|
|
@@ -9899,12 +9895,12 @@ var FacebookAdExtractor = class {
|
|
|
9899
9895
|
}
|
|
9900
9896
|
let cta = null;
|
|
9901
9897
|
for (const lbl of CTA_LABELS) {
|
|
9902
|
-
if (
|
|
9898
|
+
if (chunk.toLowerCase().includes(lbl.toLowerCase())) {
|
|
9903
9899
|
cta = lbl;
|
|
9904
9900
|
break;
|
|
9905
9901
|
}
|
|
9906
9902
|
}
|
|
9907
|
-
const multiM =
|
|
9903
|
+
const multiM = chunk.match(/(\d+)\s+ad[s]?\s+use[s]?\s+this/i);
|
|
9908
9904
|
const clusterCount = multiM ? parseInt(multiM[1]) : null;
|
|
9909
9905
|
return {
|
|
9910
9906
|
libraryId,
|
|
@@ -9927,8 +9923,8 @@ var FacebookAdExtractor = class {
|
|
|
9927
9923
|
const unknownCreativeCount = ads.filter((a) => a.creativeType === "unknown").length;
|
|
9928
9924
|
const advertiserPageId = new URL(page.url()).searchParams.get("view_all_page_id") ?? null;
|
|
9929
9925
|
const nameFreq = /* @__PURE__ */ new Map();
|
|
9930
|
-
for (const
|
|
9931
|
-
const detailsParts =
|
|
9926
|
+
for (const chunk of adChunks) {
|
|
9927
|
+
const detailsParts = chunk.split("See ad details ");
|
|
9932
9928
|
if (detailsParts.length < 2) continue;
|
|
9933
9929
|
const sponsoredIdx = detailsParts[1].indexOf(" Sponsored");
|
|
9934
9930
|
if (sponsoredIdx < 0) continue;
|
|
@@ -10668,11 +10664,11 @@ facebookAdApp.post("/search", createApiKeyAuth(), async (c) => {
|
|
|
10668
10664
|
}
|
|
10669
10665
|
if (last < bodyText.length) adChunks.push(bodyText.slice(last));
|
|
10670
10666
|
const advertiserMap = /* @__PURE__ */ new Map();
|
|
10671
|
-
for (const
|
|
10672
|
-
const lidM =
|
|
10667
|
+
for (const chunk of adChunks) {
|
|
10668
|
+
const lidM = chunk.match(/Library ID[:\s]+([0-9]{10,20})/i);
|
|
10673
10669
|
if (!lidM) continue;
|
|
10674
10670
|
const libraryId = lidM[1];
|
|
10675
|
-
const detailsParts =
|
|
10671
|
+
const detailsParts = chunk.split("See ad details ");
|
|
10676
10672
|
if (detailsParts.length < 2) continue;
|
|
10677
10673
|
const afterDetails = detailsParts[1];
|
|
10678
10674
|
const sponsoredIdx = afterDetails.indexOf(" Sponsored");
|
|
@@ -11224,8 +11220,8 @@ function runFfmpegMux(videoPath, audioPath, outPath) {
|
|
|
11224
11220
|
stdio: ["ignore", "ignore", "pipe"]
|
|
11225
11221
|
});
|
|
11226
11222
|
let stderr = "";
|
|
11227
|
-
child.stderr.on("data", (
|
|
11228
|
-
stderr += String(
|
|
11223
|
+
child.stderr.on("data", (chunk) => {
|
|
11224
|
+
stderr += String(chunk);
|
|
11229
11225
|
});
|
|
11230
11226
|
child.on("error", (err) => resolve({ ok: false, error: err.message }));
|
|
11231
11227
|
child.on("close", (code) => resolve({ ok: code === 0, error: code === 0 ? null : stderr.trim() || `ffmpeg exited ${code}` }));
|
|
@@ -14357,8 +14353,64 @@ async function migrateBrowserAgent() {
|
|
|
14357
14353
|
)
|
|
14358
14354
|
`);
|
|
14359
14355
|
await db.execute(`CREATE INDEX IF NOT EXISTS browser_agent_replays_session ON browser_agent_replays(session_id)`);
|
|
14356
|
+
await db.execute(`
|
|
14357
|
+
CREATE TABLE IF NOT EXISTS browser_auth_connections (
|
|
14358
|
+
connection_id TEXT PRIMARY KEY,
|
|
14359
|
+
hosted_url TEXT,
|
|
14360
|
+
domain TEXT,
|
|
14361
|
+
profile TEXT,
|
|
14362
|
+
account_email TEXT,
|
|
14363
|
+
note TEXT,
|
|
14364
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
14365
|
+
updated_at TEXT
|
|
14366
|
+
)
|
|
14367
|
+
`);
|
|
14368
|
+
try {
|
|
14369
|
+
await db.execute(`ALTER TABLE browser_auth_connections ADD COLUMN account_email TEXT`);
|
|
14370
|
+
} catch {
|
|
14371
|
+
}
|
|
14372
|
+
try {
|
|
14373
|
+
await db.execute(`ALTER TABLE browser_auth_connections ADD COLUMN note TEXT`);
|
|
14374
|
+
} catch {
|
|
14375
|
+
}
|
|
14376
|
+
try {
|
|
14377
|
+
await db.execute(`ALTER TABLE browser_auth_connections ADD COLUMN updated_at TEXT`);
|
|
14378
|
+
} catch {
|
|
14379
|
+
}
|
|
14380
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS browser_auth_connections_profile ON browser_auth_connections(profile)`);
|
|
14360
14381
|
_ready = true;
|
|
14361
14382
|
}
|
|
14383
|
+
async function saveAuthConnection(input) {
|
|
14384
|
+
if (!input.connectionId) return;
|
|
14385
|
+
const db = getDb();
|
|
14386
|
+
await db.execute({
|
|
14387
|
+
sql: `INSERT INTO browser_auth_connections (connection_id, hosted_url, domain, profile, account_email, note, updated_at)
|
|
14388
|
+
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
|
|
14389
|
+
ON CONFLICT(connection_id) DO UPDATE SET
|
|
14390
|
+
hosted_url = COALESCE(excluded.hosted_url, browser_auth_connections.hosted_url),
|
|
14391
|
+
domain = COALESCE(excluded.domain, browser_auth_connections.domain),
|
|
14392
|
+
profile = COALESCE(excluded.profile, browser_auth_connections.profile),
|
|
14393
|
+
account_email = COALESCE(excluded.account_email, browser_auth_connections.account_email),
|
|
14394
|
+
note = COALESCE(excluded.note, browser_auth_connections.note),
|
|
14395
|
+
updated_at = datetime('now')`,
|
|
14396
|
+
args: [input.connectionId, input.hostedUrl, input.domain, input.profile, input.accountEmail ?? null, input.note ?? null]
|
|
14397
|
+
});
|
|
14398
|
+
}
|
|
14399
|
+
async function getAuthConnectionRow(connectionId) {
|
|
14400
|
+
if (!connectionId) return null;
|
|
14401
|
+
const db = getDb();
|
|
14402
|
+
const res = await db.execute({ sql: `SELECT * FROM browser_auth_connections WHERE connection_id = ?`, args: [connectionId] });
|
|
14403
|
+
return res.rows[0] ?? null;
|
|
14404
|
+
}
|
|
14405
|
+
async function listAuthConnectionsByProfile(profile) {
|
|
14406
|
+
if (!profile) return [];
|
|
14407
|
+
const db = getDb();
|
|
14408
|
+
const res = await db.execute({
|
|
14409
|
+
sql: `SELECT * FROM browser_auth_connections WHERE profile = ? ORDER BY COALESCE(updated_at, created_at) DESC`,
|
|
14410
|
+
args: [profile]
|
|
14411
|
+
});
|
|
14412
|
+
return res.rows;
|
|
14413
|
+
}
|
|
14362
14414
|
async function createSessionRow(input) {
|
|
14363
14415
|
const db = getDb();
|
|
14364
14416
|
const id = `bas_${randomUUID2().replace(/-/g, "").slice(0, 20)}`;
|
|
@@ -15191,6 +15243,17 @@ async function findProfileConnection(k, profileName, domain) {
|
|
|
15191
15243
|
}
|
|
15192
15244
|
return null;
|
|
15193
15245
|
}
|
|
15246
|
+
async function listProfileConnections(profileName) {
|
|
15247
|
+
if (!profileName) return [];
|
|
15248
|
+
const k = client();
|
|
15249
|
+
const out = [];
|
|
15250
|
+
for await (const connection of k.auth.connections.list({ profile_name: profileName })) {
|
|
15251
|
+
const data = connection;
|
|
15252
|
+
if (data.profile_name && data.profile_name !== profileName) continue;
|
|
15253
|
+
out.push(profileOnboardResult(connection));
|
|
15254
|
+
}
|
|
15255
|
+
return out;
|
|
15256
|
+
}
|
|
15194
15257
|
async function findOrCreateProfileConnection(k, opts) {
|
|
15195
15258
|
try {
|
|
15196
15259
|
return await k.auth.connections.create({
|
|
@@ -15584,7 +15647,7 @@ function publicSession(row) {
|
|
|
15584
15647
|
session_id: row.id,
|
|
15585
15648
|
status: row.status,
|
|
15586
15649
|
label: row.label,
|
|
15587
|
-
|
|
15650
|
+
watch_url: `/console/${row.id}`,
|
|
15588
15651
|
created_at: row.created_at,
|
|
15589
15652
|
last_action_at: row.last_action_at,
|
|
15590
15653
|
closed_at: row.closed_at,
|
|
@@ -15640,10 +15703,23 @@ function buildBrowserAgentRoutes() {
|
|
|
15640
15703
|
const profileName = typeof body.profile === "string" ? body.profile.trim() : "";
|
|
15641
15704
|
const domain = typeof body.domain === "string" ? body.domain.trim().replace(/^https?:\/\//, "").replace(/\/.*$/, "") : "chatgpt.com";
|
|
15642
15705
|
const loginUrl = typeof body.login_url === "string" ? body.login_url.trim() : void 0;
|
|
15706
|
+
const accountEmail = typeof body.account_email === "string" ? body.account_email.trim() || null : null;
|
|
15707
|
+
const note = typeof body.note === "string" ? body.note.trim() || null : null;
|
|
15643
15708
|
if (!profileName) return c.json({ error: "profile is required" }, 400);
|
|
15644
15709
|
if (!domain) return c.json({ error: "domain is required" }, 400);
|
|
15645
15710
|
try {
|
|
15646
15711
|
const result = await startProfileOnboarding({ profileName, domain, loginUrl });
|
|
15712
|
+
try {
|
|
15713
|
+
await saveAuthConnection({
|
|
15714
|
+
connectionId: result.connectionId,
|
|
15715
|
+
hostedUrl: result.hostedUrl,
|
|
15716
|
+
domain: result.domain,
|
|
15717
|
+
profile: result.profileName,
|
|
15718
|
+
accountEmail,
|
|
15719
|
+
note
|
|
15720
|
+
});
|
|
15721
|
+
} catch {
|
|
15722
|
+
}
|
|
15647
15723
|
return c.json({
|
|
15648
15724
|
connection_id: result.connectionId,
|
|
15649
15725
|
profile: result.profileName,
|
|
@@ -15652,8 +15728,6 @@ function buildBrowserAgentRoutes() {
|
|
|
15652
15728
|
flow_status: result.flowStatus,
|
|
15653
15729
|
flow_step: result.flowStep,
|
|
15654
15730
|
flow_expires_at: result.flowExpiresAt,
|
|
15655
|
-
hosted_url: result.hostedUrl,
|
|
15656
|
-
live_view_url: result.liveViewUrl,
|
|
15657
15731
|
browser_session_id: result.browserSessionId,
|
|
15658
15732
|
post_login_url: result.postLoginUrl
|
|
15659
15733
|
});
|
|
@@ -15668,6 +15742,17 @@ function buildBrowserAgentRoutes() {
|
|
|
15668
15742
|
const domain = typeof body.domain === "string" ? body.domain.trim().replace(/^https?:\/\//, "").replace(/\/.*$/, "") : void 0;
|
|
15669
15743
|
try {
|
|
15670
15744
|
const result = await getProfileOnboardingStatus({ connectionId, profileName, domain });
|
|
15745
|
+
if (result.hostedUrl) {
|
|
15746
|
+
try {
|
|
15747
|
+
await saveAuthConnection({
|
|
15748
|
+
connectionId: result.connectionId,
|
|
15749
|
+
hostedUrl: result.hostedUrl,
|
|
15750
|
+
domain: result.domain,
|
|
15751
|
+
profile: result.profileName
|
|
15752
|
+
});
|
|
15753
|
+
} catch {
|
|
15754
|
+
}
|
|
15755
|
+
}
|
|
15671
15756
|
return c.json({
|
|
15672
15757
|
connection_id: result.connectionId,
|
|
15673
15758
|
profile: result.profileName,
|
|
@@ -15676,8 +15761,6 @@ function buildBrowserAgentRoutes() {
|
|
|
15676
15761
|
flow_status: result.flowStatus,
|
|
15677
15762
|
flow_step: result.flowStep,
|
|
15678
15763
|
flow_expires_at: result.flowExpiresAt,
|
|
15679
|
-
hosted_url: result.hostedUrl,
|
|
15680
|
-
live_view_url: result.liveViewUrl,
|
|
15681
15764
|
browser_session_id: result.browserSessionId,
|
|
15682
15765
|
post_login_url: result.postLoginUrl
|
|
15683
15766
|
});
|
|
@@ -15685,6 +15768,37 @@ function buildBrowserAgentRoutes() {
|
|
|
15685
15768
|
return c.json(failure(err), 404);
|
|
15686
15769
|
}
|
|
15687
15770
|
});
|
|
15771
|
+
app2.post("/profiles/list", async (c) => {
|
|
15772
|
+
const body = await c.req.json().catch(() => ({}));
|
|
15773
|
+
const profileName = typeof body.profile === "string" ? body.profile.trim() : "";
|
|
15774
|
+
if (!profileName) return c.json({ error: "profile is required" }, 400);
|
|
15775
|
+
const domainFilter = typeof body.domain === "string" ? body.domain.trim().replace(/^https?:\/\//, "").replace(/\/.*$/, "") : void 0;
|
|
15776
|
+
const connectionIdFilter = typeof body.connection_id === "string" ? body.connection_id.trim() : void 0;
|
|
15777
|
+
try {
|
|
15778
|
+
const [live, stored] = await Promise.all([
|
|
15779
|
+
listProfileConnections(profileName),
|
|
15780
|
+
listAuthConnectionsByProfile(profileName).catch(() => [])
|
|
15781
|
+
]);
|
|
15782
|
+
const notesByDomain = new Map(stored.map((row) => [row.domain ?? "", row]));
|
|
15783
|
+
const notesByConnection = new Map(stored.map((row) => [row.connection_id, row]));
|
|
15784
|
+
let connections = live.map((conn) => {
|
|
15785
|
+
const record = notesByConnection.get(conn.connectionId) ?? notesByDomain.get(conn.domain);
|
|
15786
|
+
return {
|
|
15787
|
+
connection_id: conn.connectionId,
|
|
15788
|
+
domain: conn.domain,
|
|
15789
|
+
status: conn.status,
|
|
15790
|
+
account_email: record?.account_email ?? null,
|
|
15791
|
+
note: record?.note ?? null,
|
|
15792
|
+
last_connected_at: record?.updated_at ?? record?.created_at ?? null
|
|
15793
|
+
};
|
|
15794
|
+
});
|
|
15795
|
+
if (connectionIdFilter) connections = connections.filter((c2) => c2.connection_id === connectionIdFilter);
|
|
15796
|
+
if (domainFilter) connections = connections.filter((c2) => c2.domain === domainFilter);
|
|
15797
|
+
return c.json({ profile: profileName, connections });
|
|
15798
|
+
} catch (err) {
|
|
15799
|
+
return c.json(failure(err), 502);
|
|
15800
|
+
}
|
|
15801
|
+
});
|
|
15688
15802
|
app2.post("/sessions", async (c) => {
|
|
15689
15803
|
const user = c.get("user");
|
|
15690
15804
|
if (Number(user.balance_mc ?? 0) < BROWSER_OPEN_MIN_BALANCE_MC) {
|
|
@@ -16041,6 +16155,50 @@ function buildBrowserAgentRoutes() {
|
|
|
16041
16155
|
}
|
|
16042
16156
|
|
|
16043
16157
|
// src/api/browser-agent-console.ts
|
|
16158
|
+
function renderAuthConsoleHtml(connectionId, hostedUrl) {
|
|
16159
|
+
const safeId = String(connectionId).replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]);
|
|
16160
|
+
const goUrl = `/console/auth/${encodeURIComponent(connectionId)}/go`;
|
|
16161
|
+
const body = hostedUrl ? `<iframe class="stage" allow="clipboard-read; clipboard-write" src="${goUrl}"></iframe>
|
|
16162
|
+
<div class="fallback">
|
|
16163
|
+
<span>Sign-in window not showing?</span>
|
|
16164
|
+
<a class="btn" href="${goUrl}" target="_blank" rel="noopener">Open sign-in in a new tab</a>
|
|
16165
|
+
</div>` : `<div class="empty">
|
|
16166
|
+
<div>This sign-in link is no longer active.</div>
|
|
16167
|
+
<div class="muted">Ask the assistant to reconnect the profile, then open the new link.</div>
|
|
16168
|
+
</div>`;
|
|
16169
|
+
return `<!DOCTYPE html>
|
|
16170
|
+
<html lang="en">
|
|
16171
|
+
<head>
|
|
16172
|
+
<meta charset="UTF-8" />
|
|
16173
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
16174
|
+
<title>MCP Scraper \u2014 Secure Sign-in</title>
|
|
16175
|
+
<style>
|
|
16176
|
+
:root { color-scheme: dark; }
|
|
16177
|
+
:where(*) { box-sizing: border-box; }
|
|
16178
|
+
body { margin: 0; height: 100vh; display: flex; flex-direction: column; font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, sans-serif; background: #0b0e14; color: #d7dce5; }
|
|
16179
|
+
header { display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-bottom: 1px solid #1c2230; background: #0f131c; }
|
|
16180
|
+
header h1 { font-size: 14px; margin: 0; font-weight: 600; color: #fff; }
|
|
16181
|
+
header .muted { color: #6b7689; font-size: 12px; }
|
|
16182
|
+
.spacer { flex: 1; }
|
|
16183
|
+
.stage { flex: 1; width: 100%; border: 0; display: block; background: #05070b; }
|
|
16184
|
+
.fallback { display: flex; align-items: center; gap: 12px; padding: 10px 18px; border-top: 1px solid #1c2230; background: #0f131c; font-size: 13px; color: #8893a7; }
|
|
16185
|
+
.btn { background: #2b6cff; color: #fff; border-radius: 7px; padding: 7px 12px; text-decoration: none; font-weight: 500; }
|
|
16186
|
+
.empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; color: #8893a7; }
|
|
16187
|
+
.muted { color: #6b7689; font-size: 12px; }
|
|
16188
|
+
</style>
|
|
16189
|
+
${ATTRIBUTION_PIXEL_SCRIPT}
|
|
16190
|
+
</head>
|
|
16191
|
+
<body>
|
|
16192
|
+
<header>
|
|
16193
|
+
<h1>MCP Scraper</h1>
|
|
16194
|
+
<span class="muted">Secure sign-in \xB7 ${safeId}</span>
|
|
16195
|
+
<span class="spacer"></span>
|
|
16196
|
+
<span class="muted">Complete the login below \u2014 your session is saved to your profile.</span>
|
|
16197
|
+
</header>
|
|
16198
|
+
${body}
|
|
16199
|
+
</body>
|
|
16200
|
+
</html>`;
|
|
16201
|
+
}
|
|
16044
16202
|
function renderConsoleHtml(initialSessionId) {
|
|
16045
16203
|
const initial = JSON.stringify(initialSessionId ?? "");
|
|
16046
16204
|
return `<!DOCTYPE html>
|
|
@@ -17372,7 +17530,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
17372
17530
|
if (!process.env.CRON_SECRET || secret2 !== `Bearer ${process.env.CRON_SECRET}`) {
|
|
17373
17531
|
return c.json({ error: "Unauthorized" }, 401);
|
|
17374
17532
|
}
|
|
17375
|
-
const { drainQueue } = await import("./worker-
|
|
17533
|
+
const { drainQueue } = await import("./worker-J6I5XP2F.js");
|
|
17376
17534
|
const budget = { maxJobs: 10, deadlineMs: Date.now() + 28e4 };
|
|
17377
17535
|
const workflowDispatchResult = await dispatchDueWorkflowSchedules(`${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`);
|
|
17378
17536
|
const [results, sweepResult] = await Promise.all([
|
|
@@ -17394,6 +17552,19 @@ app.route("/serp-intelligence", serpIntelligenceApp);
|
|
|
17394
17552
|
app.route("/mcp", mcpApp);
|
|
17395
17553
|
app.route("/agent", buildBrowserAgentRoutes());
|
|
17396
17554
|
app.get("/console", (c) => c.html(renderConsoleHtml()));
|
|
17555
|
+
app.get("/console/auth/:id", async (c) => {
|
|
17556
|
+
const id = c.req.param("id");
|
|
17557
|
+
await migrateBrowserAgent();
|
|
17558
|
+
const row = await getAuthConnectionRow(id);
|
|
17559
|
+
return c.html(renderAuthConsoleHtml(id, row?.hosted_url ?? null));
|
|
17560
|
+
});
|
|
17561
|
+
app.get("/console/auth/:id/go", async (c) => {
|
|
17562
|
+
const id = c.req.param("id");
|
|
17563
|
+
await migrateBrowserAgent();
|
|
17564
|
+
const row = await getAuthConnectionRow(id);
|
|
17565
|
+
if (!row?.hosted_url) return c.text("This sign-in link is no longer active.", 404);
|
|
17566
|
+
return c.redirect(row.hosted_url, 302);
|
|
17567
|
+
});
|
|
17397
17568
|
app.get("/console/:id", (c) => c.html(renderConsoleHtml(c.req.param("id"))));
|
|
17398
17569
|
app.route("/stripe", stripeApp);
|
|
17399
17570
|
if (!process.env.INNGEST_EVENT_KEY) {
|
|
@@ -17502,4 +17673,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
17502
17673
|
export {
|
|
17503
17674
|
app
|
|
17504
17675
|
};
|
|
17505
|
-
//# sourceMappingURL=server-
|
|
17676
|
+
//# sourceMappingURL=server-3M3XCVOT.js.map
|