mcp-scraper 0.4.1 → 0.4.2
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 +917 -221
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +2 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +3 -3
- 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 +64 -21
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +3 -3
- package/dist/bin/paa-harvest.cjs +1 -0
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +2 -2
- package/dist/{chunk-6TDUY7CA.js → chunk-4MFYMUIF.js} +25 -3
- package/dist/chunk-4MFYMUIF.js.map +1 -0
- package/dist/chunk-7HICT4GY.js +7 -0
- package/dist/chunk-7HICT4GY.js.map +1 -0
- package/dist/{chunk-NNEIXK5L.js → chunk-FUWZWKGO.js} +2 -2
- package/dist/{chunk-QUOZ3LZG.js → chunk-GFY6XHZS.js} +63 -21
- package/dist/chunk-GFY6XHZS.js.map +1 -0
- package/dist/{chunk-HBC4C75S.js → chunk-NJK5BTUK.js} +2 -2
- package/dist/{chunk-JOEZJL4I.js → chunk-NVUBFCJK.js} +2 -2
- package/dist/{chunk-BP27CZ5Q.js → chunk-XGIPATLV.js} +2 -1
- package/dist/chunk-XGIPATLV.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{server-U7V6DUSY.js → server-6IYQQK6X.js} +793 -210
- package/dist/server-6IYQQK6X.js.map +1 -0
- package/dist/{site-extract-repository-2MQBAOX5.js → site-extract-repository-4NVO5KQA.js} +3 -3
- package/dist/{worker-RVZXIALX.js → worker-7XRZNLKB.js} +4 -4
- package/package.json +2 -1
- package/dist/chunk-2ULBZRQQ.js +0 -7
- package/dist/chunk-2ULBZRQQ.js.map +0 -1
- package/dist/chunk-6TDUY7CA.js.map +0 -1
- package/dist/chunk-BP27CZ5Q.js.map +0 -1
- package/dist/chunk-QUOZ3LZG.js.map +0 -1
- package/dist/server-U7V6DUSY.js.map +0 -1
- /package/dist/{chunk-NNEIXK5L.js.map → chunk-FUWZWKGO.js.map} +0 -0
- /package/dist/{chunk-HBC4C75S.js.map → chunk-NJK5BTUK.js.map} +0 -0
- /package/dist/{chunk-JOEZJL4I.js.map → chunk-NVUBFCJK.js.map} +0 -0
- /package/dist/{site-extract-repository-2MQBAOX5.js.map → site-extract-repository-4NVO5KQA.js.map} +0 -0
- /package/dist/{worker-RVZXIALX.js.map → worker-7XRZNLKB.js.map} +0 -0
package/dist/bin/api-server.cjs
CHANGED
|
@@ -10042,7 +10042,9 @@ var init_rates = __esm({
|
|
|
10042
10042
|
instagram_transcribe: 50,
|
|
10043
10043
|
browser_minute: 12e3,
|
|
10044
10044
|
reddit_thread: 2e3,
|
|
10045
|
-
video_analysis: 666667
|
|
10045
|
+
video_analysis: 666667,
|
|
10046
|
+
trustpilot_reviews: 500,
|
|
10047
|
+
trustpilot_review: 100
|
|
10046
10048
|
};
|
|
10047
10049
|
MC_PER_BROWSER_MS = MC_COSTS.browser_minute / 6e4;
|
|
10048
10050
|
BROWSER_OPEN_MIN_BALANCE_MC = 1e3;
|
|
@@ -10213,6 +10215,22 @@ var init_rates = __esm({
|
|
|
10213
10215
|
credits: mcToCredits(MC_COSTS.video_analysis),
|
|
10214
10216
|
unit: "per 120 frames (max 480)",
|
|
10215
10217
|
notes: "Full multi-lens video breakdown: samples frames across a video (up to 30 minutes), analyzes each with vision AI, transcribes the audio, then produces summary, pacing/energy, words-per-minute, topic outline, key points, hook analysis, visual style, and a how-to-replicate recipe with a quality-control pass. $1 per 120 frames requested (max 480 = $4); billed down automatically if the video cannot use the requested frames, and refunded fully if the run fails."
|
|
10218
|
+
},
|
|
10219
|
+
{
|
|
10220
|
+
key: "trustpilot_reviews",
|
|
10221
|
+
label: "Trustpilot review harvest",
|
|
10222
|
+
aliases: ["trustpilot_reviews", "trustpilot", "trustpilot reviews"],
|
|
10223
|
+
credits: mcToCredits(MC_COSTS.trustpilot_reviews),
|
|
10224
|
+
unit: "per call",
|
|
10225
|
+
notes: "Base lookup. Reviews billed separately per card at trustpilot_review rate. Refunded if no reviews are found."
|
|
10226
|
+
},
|
|
10227
|
+
{
|
|
10228
|
+
key: "trustpilot_review",
|
|
10229
|
+
label: "Trustpilot review card",
|
|
10230
|
+
aliases: ["trustpilot_review", "trustpilot card"],
|
|
10231
|
+
credits: mcToCredits(MC_COSTS.trustpilot_review),
|
|
10232
|
+
unit: "per review card",
|
|
10233
|
+
notes: "Charged per review actually extracted, billed down automatically if the balance runs out mid-page."
|
|
10216
10234
|
}
|
|
10217
10235
|
];
|
|
10218
10236
|
CONCURRENCY_PRICE_ID = "price_1Ta1NRS8aAcsk3TGwsRnYbix";
|
|
@@ -10290,7 +10308,11 @@ var init_rates = __esm({
|
|
|
10290
10308
|
VIDEO_ANALYSIS_REFUND: "video_analysis_refund",
|
|
10291
10309
|
VIDEO_ANALYSIS_ADJUST: "video_analysis_adjust",
|
|
10292
10310
|
MEMORY_AI: "memory_ai",
|
|
10293
|
-
MEMORY_AI_REFUND: "memory_ai_refund"
|
|
10311
|
+
MEMORY_AI_REFUND: "memory_ai_refund",
|
|
10312
|
+
TRUSTPILOT_REVIEWS: "trustpilot_reviews",
|
|
10313
|
+
TRUSTPILOT_REVIEWS_REFUND: "trustpilot_reviews_refund",
|
|
10314
|
+
TRUSTPILOT_REVIEW: "trustpilot_review",
|
|
10315
|
+
TRUSTPILOT_REVIEW_REFUND: "trustpilot_review_refund"
|
|
10294
10316
|
};
|
|
10295
10317
|
MEMORY_AI_MARGIN_MULTIPLE = 3;
|
|
10296
10318
|
MC_PER_USD = SUBSCRIPTION_TIERS["price_1TmiHRS8aAcsk3TGwmSNfNIa"].credits_mc / SUBSCRIPTION_TIERS["price_1TmiHRS8aAcsk3TGwmSNfNIa"].monthly_usd;
|
|
@@ -15063,6 +15085,7 @@ var init_schemas3 = __esm({
|
|
|
15063
15085
|
hl: import_zod15.z.string().length(2).default("en"),
|
|
15064
15086
|
includeReviews: import_zod15.z.boolean().default(false),
|
|
15065
15087
|
maxReviews: import_zod15.z.number().int().min(1).max(500).default(50),
|
|
15088
|
+
includeServices: import_zod15.z.boolean().default(false),
|
|
15066
15089
|
kernelApiKey: import_zod15.z.string().optional(),
|
|
15067
15090
|
kernelProxyId: import_zod15.z.string().optional(),
|
|
15068
15091
|
headless: import_zod15.z.boolean().default(true)
|
|
@@ -16889,6 +16912,23 @@ async function provisionMemoryForUser(user) {
|
|
|
16889
16912
|
} catch {
|
|
16890
16913
|
}
|
|
16891
16914
|
}
|
|
16915
|
+
function memoryPlanForUser(user) {
|
|
16916
|
+
switch (user.subscription_tier) {
|
|
16917
|
+
case "starter":
|
|
16918
|
+
return "pro";
|
|
16919
|
+
case "growth":
|
|
16920
|
+
return "team";
|
|
16921
|
+
case "scale":
|
|
16922
|
+
return "enterprise";
|
|
16923
|
+
default:
|
|
16924
|
+
return "free";
|
|
16925
|
+
}
|
|
16926
|
+
}
|
|
16927
|
+
function resolveEffectiveMemoryPlan(user) {
|
|
16928
|
+
const tierPlan = memoryPlanForUser(user);
|
|
16929
|
+
const memoryProPlan = user.memory_plan === "pro" || user.memory_plan === "team" ? user.memory_plan : "free";
|
|
16930
|
+
return MEMORY_PLAN_RANK[tierPlan] >= MEMORY_PLAN_RANK[memoryProPlan] ? tierPlan : memoryProPlan;
|
|
16931
|
+
}
|
|
16892
16932
|
async function getOrCreateUserMemoryKey(user) {
|
|
16893
16933
|
const creds = await getUserMemoryCreds(user.id);
|
|
16894
16934
|
if (creds.memory_key) {
|
|
@@ -16899,10 +16939,9 @@ async function getOrCreateUserMemoryKey(user) {
|
|
|
16899
16939
|
if (!admin) return { key: null, error: "memory not configured (MCP_MEMORY_ADMIN_KEY missing)" };
|
|
16900
16940
|
const identity = memoryIdentity(user);
|
|
16901
16941
|
const plan = isMemoryOperator(user.email) ? "unlimited" : (await getMemoryPlan(user.id)).plan;
|
|
16902
|
-
const provisioned = await
|
|
16903
|
-
|
|
16904
|
-
{
|
|
16905
|
-
admin
|
|
16942
|
+
const provisioned = await import_provision_defaults.provisionDefaultsTool.execute(
|
|
16943
|
+
{ apiKey: admin, granteeIdentity: identity, issueKey: true, plan },
|
|
16944
|
+
{}
|
|
16906
16945
|
);
|
|
16907
16946
|
if (!provisioned.ok || !provisioned.secret) {
|
|
16908
16947
|
return { key: null, error: provisioned.error ?? "failed to provision default vaults" };
|
|
@@ -16929,23 +16968,27 @@ async function syncScheduleEntitlement(user, enabled, quotaPerPeriod) {
|
|
|
16929
16968
|
const admin = ADMIN_KEY();
|
|
16930
16969
|
if (!admin) return { ok: false, error: "memory not configured (MCP_MEMORY_ADMIN_KEY missing)" };
|
|
16931
16970
|
const identity = resolveMemoryIdentity(user);
|
|
16932
|
-
const res = await
|
|
16971
|
+
const res = await import_set_schedule_entitlement.setScheduleEntitlementTool.execute({
|
|
16972
|
+
apiKey: admin,
|
|
16933
16973
|
granteeIdentity: identity,
|
|
16934
16974
|
enabled,
|
|
16935
16975
|
quotaPerPeriod,
|
|
16936
16976
|
mcpScraperApiKey: user.api_key
|
|
16937
|
-
},
|
|
16977
|
+
}, {});
|
|
16938
16978
|
return { ok: res.ok, error: res.error };
|
|
16939
16979
|
}
|
|
16940
|
-
var import_node_crypto6, MEMORY_BASE_URL, ADMIN_KEY;
|
|
16980
|
+
var import_node_crypto6, import_provision_defaults, import_set_schedule_entitlement, MEMORY_BASE_URL, ADMIN_KEY, MEMORY_PLAN_RANK;
|
|
16941
16981
|
var init_memory = __esm({
|
|
16942
16982
|
"src/api/memory.ts"() {
|
|
16943
16983
|
"use strict";
|
|
16944
16984
|
import_node_crypto6 = require("crypto");
|
|
16945
16985
|
init_session();
|
|
16946
16986
|
init_db();
|
|
16987
|
+
import_provision_defaults = require("mcpscraper-memory-tools/tools/vaults/provision-defaults");
|
|
16988
|
+
import_set_schedule_entitlement = require("mcpscraper-memory-tools/tools/schedule/set-schedule-entitlement");
|
|
16947
16989
|
MEMORY_BASE_URL = () => (process.env.MCP_MEMORY_BASE_URL ?? "https://memory.mcpscraper.dev").replace(/\/$/, "");
|
|
16948
16990
|
ADMIN_KEY = () => process.env.MCP_MEMORY_ADMIN_KEY?.trim() ?? "";
|
|
16991
|
+
MEMORY_PLAN_RANK = { free: 0, pro: 1, team: 2, enterprise: 3 };
|
|
16949
16992
|
}
|
|
16950
16993
|
});
|
|
16951
16994
|
|
|
@@ -17119,6 +17162,33 @@ var init_MapsNavigator = __esm({
|
|
|
17119
17162
|
await this.page.waitForSelector('[role="main"] h2', { timeout: 5e3 }).catch(() => {
|
|
17120
17163
|
});
|
|
17121
17164
|
}
|
|
17165
|
+
async navigateToSerpBusinessPanel(businessName, location2) {
|
|
17166
|
+
const query = `${businessName} ${location2}`;
|
|
17167
|
+
const searchUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}&udm=1`;
|
|
17168
|
+
await this.page.goto(searchUrl, { waitUntil: "domcontentloaded", timeout: 45e3 }).catch(() => {
|
|
17169
|
+
});
|
|
17170
|
+
await this.page.waitForTimeout(2e3);
|
|
17171
|
+
const clicked = await this.page.evaluate((name) => {
|
|
17172
|
+
const trimmedName = name.trim();
|
|
17173
|
+
const words = trimmedName.split(/\s+/);
|
|
17174
|
+
const prefix = words.slice(0, Math.min(2, words.length)).join(" ");
|
|
17175
|
+
const headings = Array.from(document.querySelectorAll('h3, div[role="heading"]'));
|
|
17176
|
+
const heading = headings.find((el2) => el2.innerText?.trim() === trimmedName) ?? headings.find((el2) => el2.innerText?.trim().startsWith(prefix));
|
|
17177
|
+
const clickable = heading?.closest('a, div[role="link"], div[jsaction]');
|
|
17178
|
+
if (clickable) {
|
|
17179
|
+
clickable.click();
|
|
17180
|
+
return true;
|
|
17181
|
+
}
|
|
17182
|
+
if (heading) {
|
|
17183
|
+
heading.click();
|
|
17184
|
+
return true;
|
|
17185
|
+
}
|
|
17186
|
+
return false;
|
|
17187
|
+
}, businessName);
|
|
17188
|
+
if (!clicked) return false;
|
|
17189
|
+
await this.page.waitForTimeout(2e3);
|
|
17190
|
+
return true;
|
|
17191
|
+
}
|
|
17122
17192
|
buildReviewsUrl(placeUrl) {
|
|
17123
17193
|
const fid = placeUrl.match(/!1s(0x[0-9a-f]+:0x[0-9a-f]+)/i);
|
|
17124
17194
|
const pin = placeUrl.match(/!3d(-?\d+\.\d+)!4d(-?\d+\.\d+)/);
|
|
@@ -17305,6 +17375,25 @@ var init_MapsExtractor = __esm({
|
|
|
17305
17375
|
}
|
|
17306
17376
|
await navigator.navigateToAboutTab();
|
|
17307
17377
|
const aboutAttributes = await this.extractAbout(page);
|
|
17378
|
+
let services = [];
|
|
17379
|
+
let areasServed = [];
|
|
17380
|
+
let servicesStatus = "not_requested";
|
|
17381
|
+
if (options.includeServices) {
|
|
17382
|
+
try {
|
|
17383
|
+
const opened = await navigator.navigateToSerpBusinessPanel(options.businessName, options.location);
|
|
17384
|
+
if (opened) {
|
|
17385
|
+
const result = await this.extractServicesAndAreasServed(page);
|
|
17386
|
+
services = result.services;
|
|
17387
|
+
areasServed = result.areasServed;
|
|
17388
|
+
servicesStatus = services.length > 0 || areasServed.length > 0 ? "collected" : "none_exist";
|
|
17389
|
+
} else {
|
|
17390
|
+
servicesStatus = "unavailable";
|
|
17391
|
+
}
|
|
17392
|
+
} catch (err) {
|
|
17393
|
+
console.warn("[MapsExtractor] services/areas-served extraction failed:", err instanceof Error ? err.message : String(err));
|
|
17394
|
+
servicesStatus = "unavailable";
|
|
17395
|
+
}
|
|
17396
|
+
}
|
|
17308
17397
|
const reviewCountFinal = overview.reviewCount ?? (reviewStats.reviewHistogram.length > 0 ? reviewStats.reviewHistogram.reduce((s, r) => s + parseInt(r.count, 10), 0).toString() : null);
|
|
17309
17398
|
return {
|
|
17310
17399
|
businessName: options.businessName,
|
|
@@ -17320,6 +17409,9 @@ var init_MapsExtractor = __esm({
|
|
|
17320
17409
|
aboutAttributes,
|
|
17321
17410
|
reviews,
|
|
17322
17411
|
reviewsStatus,
|
|
17412
|
+
services,
|
|
17413
|
+
areasServed,
|
|
17414
|
+
servicesStatus,
|
|
17323
17415
|
durationMs: Date.now() - startMs
|
|
17324
17416
|
};
|
|
17325
17417
|
} finally {
|
|
@@ -17508,6 +17600,81 @@ var init_MapsExtractor = __esm({
|
|
|
17508
17600
|
}
|
|
17509
17601
|
return result.data;
|
|
17510
17602
|
}
|
|
17603
|
+
async extractServicesAndAreasServed(page) {
|
|
17604
|
+
await page.waitForTimeout(1500);
|
|
17605
|
+
let services = [];
|
|
17606
|
+
if (await this.clickRowStartingWithRetry(page, "Services:")) {
|
|
17607
|
+
await page.waitForSelector('[role="dialog"]', { timeout: 5e3 }).catch(() => {
|
|
17608
|
+
});
|
|
17609
|
+
await page.waitForTimeout(800);
|
|
17610
|
+
services = await this.extractOpenDialogItems(page, "Services");
|
|
17611
|
+
await this.closeOpenDialog(page, "Services");
|
|
17612
|
+
await page.waitForTimeout(500);
|
|
17613
|
+
}
|
|
17614
|
+
let areasServed = [];
|
|
17615
|
+
if (await this.clickRowStartingWithRetry(page, "Serves ")) {
|
|
17616
|
+
await page.waitForSelector('[role="dialog"]', { timeout: 5e3 }).catch(() => {
|
|
17617
|
+
});
|
|
17618
|
+
await page.waitForTimeout(800);
|
|
17619
|
+
areasServed = await this.extractOpenDialogItems(page, "Areas Served");
|
|
17620
|
+
await this.closeOpenDialog(page, "Areas Served");
|
|
17621
|
+
}
|
|
17622
|
+
return { services, areasServed };
|
|
17623
|
+
}
|
|
17624
|
+
async clickRowStartingWithRetry(page, prefix) {
|
|
17625
|
+
if (await this.clickRowStartingWith(page, prefix)) return true;
|
|
17626
|
+
await page.waitForTimeout(2e3);
|
|
17627
|
+
return this.clickRowStartingWith(page, prefix);
|
|
17628
|
+
}
|
|
17629
|
+
async clickRowStartingWith(page, prefix) {
|
|
17630
|
+
return page.evaluate((p) => {
|
|
17631
|
+
const el2 = Array.from(document.querySelectorAll('button, a, div[role="button"]')).find(
|
|
17632
|
+
(e) => (e.innerText ?? "").trim().startsWith(p)
|
|
17633
|
+
);
|
|
17634
|
+
if (!el2) return false;
|
|
17635
|
+
el2.click();
|
|
17636
|
+
return true;
|
|
17637
|
+
}, prefix);
|
|
17638
|
+
}
|
|
17639
|
+
async extractOpenDialogItems(page, expectedHeading) {
|
|
17640
|
+
return page.evaluate((expected) => {
|
|
17641
|
+
const dialogs = Array.from(document.querySelectorAll('[role="dialog"]'));
|
|
17642
|
+
const withHeading = dialogs.find((d) => {
|
|
17643
|
+
const h = d.querySelector('h1, h2, [role="heading"]');
|
|
17644
|
+
const headingText = h?.innerText?.trim() ?? "";
|
|
17645
|
+
return headingText.startsWith(expected);
|
|
17646
|
+
});
|
|
17647
|
+
if (!withHeading) return [];
|
|
17648
|
+
const headingEl = withHeading.querySelector('h1, h2, [role="heading"]');
|
|
17649
|
+
const headingLines = new Set(
|
|
17650
|
+
(headingEl?.innerText ?? "").split("\n").map((s) => s.trim()).filter(Boolean)
|
|
17651
|
+
);
|
|
17652
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17653
|
+
const items = [];
|
|
17654
|
+
withHeading.querySelectorAll("*").forEach((el2) => {
|
|
17655
|
+
if (el2.children.length > 0) return;
|
|
17656
|
+
const text = el2.innerText?.trim() ?? el2.textContent?.trim() ?? "";
|
|
17657
|
+
if (!text || headingLines.has(text)) return;
|
|
17658
|
+
if (/^(back|close|done|thanks)$/i.test(text)) return;
|
|
17659
|
+
if (/^serves\s.*following/i.test(text)) return;
|
|
17660
|
+
if (seen.has(text)) return;
|
|
17661
|
+
seen.add(text);
|
|
17662
|
+
items.push(text);
|
|
17663
|
+
});
|
|
17664
|
+
return items;
|
|
17665
|
+
}, expectedHeading);
|
|
17666
|
+
}
|
|
17667
|
+
async closeOpenDialog(page, expectedHeading) {
|
|
17668
|
+
await page.evaluate((expected) => {
|
|
17669
|
+
const dialog = Array.from(document.querySelectorAll('[role="dialog"]')).find((d) => {
|
|
17670
|
+
const h = d.querySelector('h1, h2, [role="heading"]');
|
|
17671
|
+
const headingText = h?.innerText?.trim() ?? "";
|
|
17672
|
+
return headingText.startsWith(expected);
|
|
17673
|
+
});
|
|
17674
|
+
const closeBtn = dialog?.querySelector('[aria-label*="Close" i], button[aria-label*="close" i]');
|
|
17675
|
+
closeBtn?.click();
|
|
17676
|
+
}, expectedHeading);
|
|
17677
|
+
}
|
|
17511
17678
|
};
|
|
17512
17679
|
}
|
|
17513
17680
|
});
|
|
@@ -18168,6 +18335,17 @@ var init_workflow_catalog = __esm({
|
|
|
18168
18335
|
produces: ["content gaps", "page comparison CSV", "PAA questions CSV", "section map", "writer brief"],
|
|
18169
18336
|
runHint: "Use workflow_run with workflowId serp-comparison for competitor gaps or paa-expansion-brief when the user mainly wants a section map from PAA data."
|
|
18170
18337
|
},
|
|
18338
|
+
{
|
|
18339
|
+
id: "recurring_tracking_and_memory",
|
|
18340
|
+
title: "Recurring Tracking & Memory",
|
|
18341
|
+
description: "Run a check on a daily, weekly, or custom cadence with no external cron needed, and save each result somewhere searchable so you can compare against past runs later - rankings, prices, competitor changes, anything you would otherwise check by hand and forget to log.",
|
|
18342
|
+
primaryWorkflowId: null,
|
|
18343
|
+
recommendedTools: ["create-scheduled-action", "search_serp", "table-create", "table-insert-rows", "table-query", "memory-put", "memory-search", "list-scheduled-actions"],
|
|
18344
|
+
requiredInputs: ["plain-language description of what to check and how often"],
|
|
18345
|
+
optionalInputs: ["vault to save into", "timeOfDay", "timezone"],
|
|
18346
|
+
produces: ["a live scheduled action that runs automatically on cadence", "a table row or note per run for structured history", "a searchable trend you can compare run-over-run"],
|
|
18347
|
+
runHint: "Use create-scheduled-action with a plain description and cadence; the run itself checks list-vaults, uses table-insert-rows for repeating structured data (e.g. a keyword rank check) or memory-put for a one-off note, and reads prior runs with table-query or memory-search before writing the new one. For a one-time blueprint to build your own external cron/DB instead of a live scheduled action, use rank_tracker_workflow."
|
|
18348
|
+
},
|
|
18171
18349
|
{
|
|
18172
18350
|
id: "ai_search_visibility_audit",
|
|
18173
18351
|
title: "AI Search Visibility Audit",
|
|
@@ -19883,6 +20061,9 @@ function formatMapsPlaceIntel(raw, input) {
|
|
|
19883
20061
|
const about = d.aboutAttributes ?? [];
|
|
19884
20062
|
const reviews = d.reviews ?? [];
|
|
19885
20063
|
const reviewsStatus = d.reviewsStatus ?? "not_requested";
|
|
20064
|
+
const services = d.services ?? [];
|
|
20065
|
+
const areasServed = d.areasServed ?? [];
|
|
20066
|
+
const servicesStatus = d.servicesStatus ?? "not_requested";
|
|
19886
20067
|
const hoursTable = d.hoursTable ?? [];
|
|
19887
20068
|
const ratingLine = [rating, reviewCount ? `(${reviewCount} reviews)` : null].filter(Boolean).join(" ");
|
|
19888
20069
|
const basicLines = [
|
|
@@ -19937,6 +20118,20 @@ ${reviews.map((r, i) => {
|
|
|
19937
20118
|
${r.text ?? ""}`;
|
|
19938
20119
|
}).join("\n\n")}`;
|
|
19939
20120
|
})();
|
|
20121
|
+
const servicesSection = (() => {
|
|
20122
|
+
if (servicesStatus === "not_requested") return "";
|
|
20123
|
+
if (servicesStatus === "unavailable") return "\n## Services & Areas Served\n> Could not be retrieved this run \u2014 retry with `includeServices: true`.";
|
|
20124
|
+
if (servicesStatus === "none_exist") return "\n## Services & Areas Served\n*Not listed on this business's profile.*";
|
|
20125
|
+
const parts = [
|
|
20126
|
+
services.length ? `**Services**
|
|
20127
|
+
${services.map((s) => `- ${s}`).join("\n")}` : null,
|
|
20128
|
+
areasServed.length ? `**Areas Served**
|
|
20129
|
+
${areasServed.map((a) => `- ${a}`).join("\n")}` : null
|
|
20130
|
+
].filter(Boolean);
|
|
20131
|
+
return parts.length ? `
|
|
20132
|
+
## Services & Areas Served
|
|
20133
|
+
${parts.join("\n\n")}` : "";
|
|
20134
|
+
})();
|
|
19940
20135
|
const full = [
|
|
19941
20136
|
`# ${name}`,
|
|
19942
20137
|
category ? `*${category}*` : null,
|
|
@@ -19952,6 +20147,7 @@ ${basicLines}` : null,
|
|
|
19952
20147
|
## Entity IDs
|
|
19953
20148
|
${entitySection}` : null,
|
|
19954
20149
|
reviewsSection,
|
|
20150
|
+
servicesSection,
|
|
19955
20151
|
durationMs != null ? `
|
|
19956
20152
|
---
|
|
19957
20153
|
*Extracted in ${(durationMs / 1e3).toFixed(1)}s*` : null
|
|
@@ -19975,7 +20171,10 @@ ${entitySection}` : null,
|
|
|
19975
20171
|
lng: lng ?? null,
|
|
19976
20172
|
reviewsStatus,
|
|
19977
20173
|
reviewsCollected: reviews.length,
|
|
19978
|
-
reviewTopics: topics.map((t) => ({ label: String(t.label ?? ""), count: String(t.count ?? "") }))
|
|
20174
|
+
reviewTopics: topics.map((t) => ({ label: String(t.label ?? ""), count: String(t.count ?? "") })),
|
|
20175
|
+
services,
|
|
20176
|
+
areasServed,
|
|
20177
|
+
servicesStatus
|
|
19979
20178
|
}
|
|
19980
20179
|
};
|
|
19981
20180
|
}
|
|
@@ -26325,7 +26524,7 @@ var PACKAGE_VERSION;
|
|
|
26325
26524
|
var init_version = __esm({
|
|
26326
26525
|
"src/version.ts"() {
|
|
26327
26526
|
"use strict";
|
|
26328
|
-
PACKAGE_VERSION = "0.4.
|
|
26527
|
+
PACKAGE_VERSION = "0.4.2";
|
|
26329
26528
|
}
|
|
26330
26529
|
});
|
|
26331
26530
|
|
|
@@ -26592,7 +26791,8 @@ var init_mcp_tool_schemas = __esm({
|
|
|
26592
26791
|
gl: import_zod31.z.string().length(2).default("us").describe("Google country code inferred from location."),
|
|
26593
26792
|
hl: import_zod31.z.string().length(2).default("en").describe("Language inferred from user request."),
|
|
26594
26793
|
includeReviews: import_zod31.z.boolean().default(false).describe("Fetch individual review cards \u2014 for reviews, customer pain, complaints, or praise themes."),
|
|
26595
|
-
maxReviews: import_zod31.z.number().int().min(1).max(500).default(50).describe("Max review cards when includeReviews is true. Default 50, maximum 500.")
|
|
26794
|
+
maxReviews: import_zod31.z.number().int().min(1).max(500).default(50).describe("Max review cards when includeReviews is true. Default 50, maximum 500."),
|
|
26795
|
+
includeServices: import_zod31.z.boolean().default(false).describe("Fetch the business's configured services list and areas-served list, when the profile has them. Adds one extra page visit; not present for every business.")
|
|
26596
26796
|
};
|
|
26597
26797
|
MapsSearchInputSchema = {
|
|
26598
26798
|
query: import_zod31.z.string().min(1).describe('Business category, niche, or search term, e.g. "roofers". Do not include location here \u2014 use location instead.'),
|
|
@@ -26905,7 +27105,10 @@ var init_mcp_tool_schemas = __esm({
|
|
|
26905
27105
|
reviewTopics: import_zod31.z.array(import_zod31.z.object({
|
|
26906
27106
|
label: import_zod31.z.string(),
|
|
26907
27107
|
count: import_zod31.z.string()
|
|
26908
|
-
}))
|
|
27108
|
+
})),
|
|
27109
|
+
services: import_zod31.z.array(import_zod31.z.string()),
|
|
27110
|
+
areasServed: import_zod31.z.array(import_zod31.z.string()),
|
|
27111
|
+
servicesStatus: import_zod31.z.string()
|
|
26909
27112
|
};
|
|
26910
27113
|
CreditsInfoOutputSchema = {
|
|
26911
27114
|
balanceCredits: import_zod31.z.number().nullable(),
|
|
@@ -28731,7 +28934,7 @@ var init_browser_agent_tool_schemas = __esm({
|
|
|
28731
28934
|
BrowserProfileConnectOutputSchema = {
|
|
28732
28935
|
ok: import_zod32.z.boolean(),
|
|
28733
28936
|
tool: import_zod32.z.literal("browser_profile_connect"),
|
|
28734
|
-
session_id: NullableString2,
|
|
28937
|
+
session_id: NullableString2.describe("The underlying live browser session id backing this sign-in."),
|
|
28735
28938
|
auth_connection_id: import_zod32.z.string(),
|
|
28736
28939
|
watch_url: import_zod32.z.string().describe("mcpscraper.dev sign-in link to give the user so they can complete this login."),
|
|
28737
28940
|
live_view_url: NullableString2.describe("Deprecated; always null. Open watch_url to view the sign-in."),
|
|
@@ -28741,10 +28944,10 @@ var init_browser_agent_tool_schemas = __esm({
|
|
|
28741
28944
|
account_email: NullableString2,
|
|
28742
28945
|
note: NullableString2,
|
|
28743
28946
|
status: import_zod32.z.string(),
|
|
28744
|
-
flow_status: NullableString2,
|
|
28745
|
-
flow_step: NullableString2,
|
|
28746
|
-
flow_expires_at: NullableString2,
|
|
28747
|
-
post_login_url: NullableString2,
|
|
28947
|
+
flow_status: NullableString2.describe("Deprecated; always null."),
|
|
28948
|
+
flow_step: NullableString2.describe("Deprecated; always null."),
|
|
28949
|
+
flow_expires_at: NullableString2.describe("Deprecated; always null."),
|
|
28950
|
+
post_login_url: NullableString2.describe("Deprecated; always null."),
|
|
28748
28951
|
connected_logins: import_zod32.z.array(BrowserProfileLogin).describe("Every login currently saved in this profile, so you can see what else is connected."),
|
|
28749
28952
|
next_steps: import_zod32.z.array(import_zod32.z.string()),
|
|
28750
28953
|
raw: BrowserRawObject.optional()
|
|
@@ -29177,6 +29380,11 @@ function slugPart(value) {
|
|
|
29177
29380
|
if (!trimmed) return null;
|
|
29178
29381
|
return trimmed.replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/.*$/, "").replace(/[^a-z0-9._-]+/g, "-").replace(/[._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
29179
29382
|
}
|
|
29383
|
+
function normalizeDomain4(value) {
|
|
29384
|
+
const trimmed = value?.trim().toLowerCase();
|
|
29385
|
+
if (!trimmed) return null;
|
|
29386
|
+
return trimmed.replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/.*$/, "").replace(/[^a-z0-9.-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
29387
|
+
}
|
|
29180
29388
|
function savedProfileNameFromEmail(email) {
|
|
29181
29389
|
const value = slugPart(email);
|
|
29182
29390
|
if (!value) return null;
|
|
@@ -29286,13 +29494,13 @@ function registerBrowserAgentMcpTools(server, opts) {
|
|
|
29286
29494
|
"browser_profile_connect",
|
|
29287
29495
|
{
|
|
29288
29496
|
title: "Save a Site Login to a Profile",
|
|
29289
|
-
description:
|
|
29497
|
+
description: 'Open a live hosted browser session so the user can sign into a site (ChatGPT, Claude, Reddit, any account-gated site) directly in their own browser tab, then save the login to a named profile. Returns a watch_url \u2014 give it to the user; they sign in fresh on the real site (existing browser cookies are NOT imported), then click "Done" on that page to save the session and close it. ONE profile holds MANY logins \u2014 call again with the same profile and a different domain to stack another account. NOT for one-off scraping (use extract_url) or driving the browser (use browser_open). Billed at the standard live-browser rate while the sign-in session stays open. After the user clicks Done, poll browser_profile_list until AUTHENTICATED, then browser_open with the profile.',
|
|
29290
29498
|
inputSchema: BrowserProfileConnectInputSchema,
|
|
29291
29499
|
outputSchema: recordOutputSchema("browser_profile_connect", BrowserProfileConnectOutputSchema),
|
|
29292
29500
|
annotations: annotations("Save a Site Login to a Profile")
|
|
29293
29501
|
},
|
|
29294
29502
|
async (input) => {
|
|
29295
|
-
const domain =
|
|
29503
|
+
const domain = normalizeDomain4(input.domain) || "chatgpt.com";
|
|
29296
29504
|
const setupUrl = input.login_url ?? input.url ?? (domain === "chatgpt.com" ? "https://chatgpt.com/" : `https://${domain}/`);
|
|
29297
29505
|
const profile = input.profile?.trim() || savedProfileNameFromEmail(input.email) || browserServiceProfileName();
|
|
29298
29506
|
if (!profile) {
|
|
@@ -29308,14 +29516,15 @@ function registerBrowserAgentMcpTools(server, opts) {
|
|
|
29308
29516
|
domain,
|
|
29309
29517
|
login_url: setupUrl,
|
|
29310
29518
|
...accountEmail ? { account_email: accountEmail } : {},
|
|
29311
|
-
...note ? { note } : {}
|
|
29519
|
+
...note ? { note } : {},
|
|
29520
|
+
...typeof input.timeout_seconds === "number" ? { timeout_seconds: input.timeout_seconds } : {}
|
|
29312
29521
|
});
|
|
29313
29522
|
if (!open.ok) return errorResult("browser_profile_connect", open.data);
|
|
29314
29523
|
const connectedLogins = await fetchConnectedLogins(profile).catch(() => []);
|
|
29315
29524
|
return structuredResult({
|
|
29316
29525
|
ok: true,
|
|
29317
29526
|
tool: "browser_profile_connect",
|
|
29318
|
-
session_id: null,
|
|
29527
|
+
session_id: open.data.browser_session_id ?? null,
|
|
29319
29528
|
auth_connection_id: open.data.connection_id,
|
|
29320
29529
|
watch_url: `${consoleBase}/console/auth/${open.data.connection_id}`,
|
|
29321
29530
|
live_view_url: null,
|
|
@@ -29325,13 +29534,13 @@ function registerBrowserAgentMcpTools(server, opts) {
|
|
|
29325
29534
|
account_email: accountEmail,
|
|
29326
29535
|
note,
|
|
29327
29536
|
status: open.data.status ?? null,
|
|
29328
|
-
flow_status:
|
|
29329
|
-
flow_step:
|
|
29330
|
-
flow_expires_at:
|
|
29331
|
-
post_login_url:
|
|
29537
|
+
flow_status: null,
|
|
29538
|
+
flow_step: null,
|
|
29539
|
+
flow_expires_at: null,
|
|
29540
|
+
post_login_url: null,
|
|
29332
29541
|
connected_logins: connectedLogins,
|
|
29333
29542
|
next_steps: [
|
|
29334
|
-
`Give the user watch_url so they can sign in to ${domain}.`,
|
|
29543
|
+
`Give the user watch_url so they can sign in to ${domain} directly in that page, then click "Done \u2014 I'm signed in".`,
|
|
29335
29544
|
"Poll browser_profile_list (with this profile) until the login reads AUTHENTICATED.",
|
|
29336
29545
|
"To add another account to this same profile, call browser_profile_connect again with the same profile and a different domain.",
|
|
29337
29546
|
"When authenticated, call browser_open with this profile to drive the logged-in session."
|
|
@@ -29356,7 +29565,7 @@ function registerBrowserAgentMcpTools(server, opts) {
|
|
|
29356
29565
|
error: "profile or email is required when BROWSER_AGENT_PROFILE_NAME is not available"
|
|
29357
29566
|
});
|
|
29358
29567
|
}
|
|
29359
|
-
const domain =
|
|
29568
|
+
const domain = normalizeDomain4(input.domain) || void 0;
|
|
29360
29569
|
const res = await req("POST", "/agent/profiles/list", {
|
|
29361
29570
|
profile,
|
|
29362
29571
|
...domain ? { domain } : {},
|
|
@@ -31957,6 +32166,486 @@ var init_memory_mcp_tool_executor = __esm({
|
|
|
31957
32166
|
}
|
|
31958
32167
|
});
|
|
31959
32168
|
|
|
32169
|
+
// src/mcp/memory-inprocess-executor.ts
|
|
32170
|
+
function registerCutover(upstreamName, handler) {
|
|
32171
|
+
CUTOVER.set(upstreamName, handler);
|
|
32172
|
+
}
|
|
32173
|
+
var CUTOVER, HybridMemoryToolExecutor;
|
|
32174
|
+
var init_memory_inprocess_executor = __esm({
|
|
32175
|
+
"src/mcp/memory-inprocess-executor.ts"() {
|
|
32176
|
+
"use strict";
|
|
32177
|
+
init_memory();
|
|
32178
|
+
CUTOVER = /* @__PURE__ */ new Map();
|
|
32179
|
+
HybridMemoryToolExecutor = class {
|
|
32180
|
+
constructor(httpExecutor, user) {
|
|
32181
|
+
this.httpExecutor = httpExecutor;
|
|
32182
|
+
this.user = user;
|
|
32183
|
+
}
|
|
32184
|
+
httpExecutor;
|
|
32185
|
+
user;
|
|
32186
|
+
mkKeyPromise = null;
|
|
32187
|
+
async resolveMkKey() {
|
|
32188
|
+
if (!this.mkKeyPromise) {
|
|
32189
|
+
this.mkKeyPromise = getOrCreateUserMemoryKey(this.user).then((r) => r.key);
|
|
32190
|
+
}
|
|
32191
|
+
return this.mkKeyPromise;
|
|
32192
|
+
}
|
|
32193
|
+
async callMemoryTool(upstreamName, args) {
|
|
32194
|
+
const handler = CUTOVER.get(upstreamName);
|
|
32195
|
+
if (!handler) return this.httpExecutor.callMemoryTool(upstreamName, args);
|
|
32196
|
+
const mkKey = await this.resolveMkKey();
|
|
32197
|
+
if (!mkKey) return { content: [{ type: "text", text: "memory unavailable" }], isError: true };
|
|
32198
|
+
try {
|
|
32199
|
+
return await handler(args, mkKey);
|
|
32200
|
+
} catch (err) {
|
|
32201
|
+
const message = err instanceof Error ? err.message : `memory ${upstreamName} failed in-process`;
|
|
32202
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
32203
|
+
}
|
|
32204
|
+
}
|
|
32205
|
+
};
|
|
32206
|
+
}
|
|
32207
|
+
});
|
|
32208
|
+
|
|
32209
|
+
// src/mcp/memory-cutover/reads.ts
|
|
32210
|
+
function registerReadCutovers() {
|
|
32211
|
+
if (registered) return;
|
|
32212
|
+
registered = true;
|
|
32213
|
+
registerCutover("listApprovedSendersTool", async (input, apiKey) => {
|
|
32214
|
+
const result = await import_list_approved_senders.listApprovedSendersTool.execute({ ...input, apiKey }, {});
|
|
32215
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32216
|
+
});
|
|
32217
|
+
registerCutover("noteInboxTool", async (input, apiKey) => {
|
|
32218
|
+
const result = await import_note_inbox.noteInboxTool.execute({ ...input, apiKey }, {});
|
|
32219
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32220
|
+
});
|
|
32221
|
+
registerCutover("getMessageNoteTool", async (input, apiKey) => {
|
|
32222
|
+
const result = await import_get_message_note.getMessageNoteTool.execute({ ...input, apiKey }, {});
|
|
32223
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32224
|
+
});
|
|
32225
|
+
registerCutover("listChannelMembersTool", async (input, apiKey) => {
|
|
32226
|
+
const result = await import_list_channel_members.listChannelMembersTool.execute({ ...input, apiKey }, {});
|
|
32227
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32228
|
+
});
|
|
32229
|
+
registerCutover("myMentionsTool", async (input, apiKey) => {
|
|
32230
|
+
const result = await import_my_mentions.myMentionsTool.execute({ ...input, apiKey }, {});
|
|
32231
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32232
|
+
});
|
|
32233
|
+
registerCutover("factHistoryTool", async (input, apiKey) => {
|
|
32234
|
+
const result = await import_fact_history.factHistoryTool.execute({ ...input, apiKey }, {});
|
|
32235
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32236
|
+
});
|
|
32237
|
+
registerCutover("exportTool", async (input, apiKey) => {
|
|
32238
|
+
const result = await import_export2.exportTool.execute({ ...input, apiKey }, {});
|
|
32239
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32240
|
+
});
|
|
32241
|
+
registerCutover("getTool", async (input, apiKey) => {
|
|
32242
|
+
const result = await import_get.getTool.execute({ ...input, apiKey }, {});
|
|
32243
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32244
|
+
});
|
|
32245
|
+
registerCutover("listTool", async (input, apiKey) => {
|
|
32246
|
+
const result = await import_list.listTool.execute({ ...input, apiKey }, {});
|
|
32247
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32248
|
+
});
|
|
32249
|
+
registerCutover("searchTool", async (input, apiKey) => {
|
|
32250
|
+
const result = await import_search.searchTool.execute({ ...input, apiKey }, {});
|
|
32251
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32252
|
+
});
|
|
32253
|
+
registerCutover("suggestTool", async (input, apiKey) => {
|
|
32254
|
+
const result = await import_suggest.suggestTool.execute({ ...input, apiKey }, {});
|
|
32255
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32256
|
+
});
|
|
32257
|
+
registerCutover("temporalRecallTool", async (input, apiKey) => {
|
|
32258
|
+
const result = await import_temporal_recall.temporalRecallTool.execute({ ...input, apiKey }, {});
|
|
32259
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32260
|
+
});
|
|
32261
|
+
registerCutover("listScheduledActionsTool", async (input, apiKey) => {
|
|
32262
|
+
const result = await import_list_scheduled_actions.listScheduledActionsTool.execute({ ...input, apiKey }, {});
|
|
32263
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32264
|
+
});
|
|
32265
|
+
registerCutover("costUsageTool", async (input, apiKey) => {
|
|
32266
|
+
const result = await import_cost_usage.costUsageTool.execute({ ...input, apiKey }, {});
|
|
32267
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32268
|
+
});
|
|
32269
|
+
registerCutover("storageUsageTool", async (input, apiKey) => {
|
|
32270
|
+
const result = await import_storage_usage.storageUsageTool.execute({ ...input, apiKey }, {});
|
|
32271
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32272
|
+
});
|
|
32273
|
+
registerCutover("describeTableTool", async (input, apiKey) => {
|
|
32274
|
+
const result = await import_table_describe.describeTableTool.execute({ ...input, apiKey }, {});
|
|
32275
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32276
|
+
});
|
|
32277
|
+
registerCutover("listTablesTool", async (input, apiKey) => {
|
|
32278
|
+
const result = await import_table_list.listTablesTool.execute({ ...input, apiKey }, {});
|
|
32279
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32280
|
+
});
|
|
32281
|
+
registerCutover("queryTableTool", async (input, apiKey) => {
|
|
32282
|
+
const result = await import_table_query.queryTableTool.execute({ ...input, apiKey }, {});
|
|
32283
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32284
|
+
});
|
|
32285
|
+
registerCutover("listSharedWithMeTool", async (input, apiKey) => {
|
|
32286
|
+
const result = await import_list_shared_with_me.listSharedWithMeTool.execute({ ...input, apiKey }, {});
|
|
32287
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32288
|
+
});
|
|
32289
|
+
registerCutover("listVaultsTool", async (input, apiKey) => {
|
|
32290
|
+
const result = await import_list_vaults.listVaultsTool.execute({ ...input, apiKey }, {});
|
|
32291
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32292
|
+
});
|
|
32293
|
+
registerCutover("videoAnalyzeStatusTool", async (input, apiKey) => {
|
|
32294
|
+
const result = await import_status.videoAnalyzeStatusTool.execute({ ...input, apiKey }, {});
|
|
32295
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32296
|
+
});
|
|
32297
|
+
registerCutover("listWebhooksTool", async (input, apiKey) => {
|
|
32298
|
+
const result = await import_list_webhooks.listWebhooksTool.execute({ ...input, apiKey }, {});
|
|
32299
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32300
|
+
});
|
|
32301
|
+
}
|
|
32302
|
+
var import_list_approved_senders, import_note_inbox, import_get_message_note, import_list_channel_members, import_my_mentions, import_fact_history, import_export2, import_get, import_list, import_search, import_suggest, import_temporal_recall, import_list_scheduled_actions, import_cost_usage, import_storage_usage, import_table_describe, import_table_list, import_table_query, import_list_shared_with_me, import_list_vaults, import_status, import_list_webhooks, registered;
|
|
32303
|
+
var init_reads = __esm({
|
|
32304
|
+
"src/mcp/memory-cutover/reads.ts"() {
|
|
32305
|
+
"use strict";
|
|
32306
|
+
init_memory_inprocess_executor();
|
|
32307
|
+
import_list_approved_senders = require("mcpscraper-memory-tools/tools/access/list-approved-senders");
|
|
32308
|
+
import_note_inbox = require("mcpscraper-memory-tools/tools/access/note-inbox");
|
|
32309
|
+
import_get_message_note = require("mcpscraper-memory-tools/tools/channels/get-message-note");
|
|
32310
|
+
import_list_channel_members = require("mcpscraper-memory-tools/tools/channels/list-channel-members");
|
|
32311
|
+
import_my_mentions = require("mcpscraper-memory-tools/tools/channels/my-mentions");
|
|
32312
|
+
import_fact_history = require("mcpscraper-memory-tools/tools/facts/fact-history");
|
|
32313
|
+
import_export2 = require("mcpscraper-memory-tools/tools/memory/export");
|
|
32314
|
+
import_get = require("mcpscraper-memory-tools/tools/memory/get");
|
|
32315
|
+
import_list = require("mcpscraper-memory-tools/tools/memory/list");
|
|
32316
|
+
import_search = require("mcpscraper-memory-tools/tools/memory/search");
|
|
32317
|
+
import_suggest = require("mcpscraper-memory-tools/tools/memory/suggest");
|
|
32318
|
+
import_temporal_recall = require("mcpscraper-memory-tools/tools/recall/temporal-recall");
|
|
32319
|
+
import_list_scheduled_actions = require("mcpscraper-memory-tools/tools/schedule/list-scheduled-actions");
|
|
32320
|
+
import_cost_usage = require("mcpscraper-memory-tools/tools/storage/cost-usage");
|
|
32321
|
+
import_storage_usage = require("mcpscraper-memory-tools/tools/storage/storage-usage");
|
|
32322
|
+
import_table_describe = require("mcpscraper-memory-tools/tools/tables/table-describe");
|
|
32323
|
+
import_table_list = require("mcpscraper-memory-tools/tools/tables/table-list");
|
|
32324
|
+
import_table_query = require("mcpscraper-memory-tools/tools/tables/table-query");
|
|
32325
|
+
import_list_shared_with_me = require("mcpscraper-memory-tools/tools/vaults/list-shared-with-me");
|
|
32326
|
+
import_list_vaults = require("mcpscraper-memory-tools/tools/vaults/list-vaults");
|
|
32327
|
+
import_status = require("mcpscraper-memory-tools/tools/video/status");
|
|
32328
|
+
import_list_webhooks = require("mcpscraper-memory-tools/tools/webhooks/list-webhooks");
|
|
32329
|
+
registered = false;
|
|
32330
|
+
}
|
|
32331
|
+
});
|
|
32332
|
+
|
|
32333
|
+
// src/mcp/memory-cutover/writes.ts
|
|
32334
|
+
function registerWriteCutovers() {
|
|
32335
|
+
if (registered2) return;
|
|
32336
|
+
registered2 = true;
|
|
32337
|
+
registerCutover("acceptShareTool", async (input, apiKey) => {
|
|
32338
|
+
const result = await import_accept_share.acceptShareTool.execute({ ...input, apiKey }, {});
|
|
32339
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32340
|
+
});
|
|
32341
|
+
registerCutover("approveSenderTool", async (input, apiKey) => {
|
|
32342
|
+
const result = await import_approve_sender.approveSenderTool.execute({ ...input, apiKey }, {});
|
|
32343
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32344
|
+
});
|
|
32345
|
+
registerCutover("declineShareTool", async (input, apiKey) => {
|
|
32346
|
+
const result = await import_decline_share.declineShareTool.execute({ ...input, apiKey }, {});
|
|
32347
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32348
|
+
});
|
|
32349
|
+
registerCutover("inboxSettingsTool", async (input, apiKey) => {
|
|
32350
|
+
const result = await import_inbox_settings.inboxSettingsTool.execute({ ...input, apiKey }, {});
|
|
32351
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32352
|
+
});
|
|
32353
|
+
registerCutover("removeApprovedSenderTool", async (input, apiKey) => {
|
|
32354
|
+
const result = await import_remove_approved_sender.removeApprovedSenderTool.execute({ ...input, apiKey }, {});
|
|
32355
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32356
|
+
});
|
|
32357
|
+
registerCutover("revokeShareTool", async (input, apiKey) => {
|
|
32358
|
+
const result = await import_revoke_share.revokeShareTool.execute({ ...input, apiKey }, {});
|
|
32359
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32360
|
+
});
|
|
32361
|
+
registerCutover("setAgentIdentityTool", async (input, apiKey) => {
|
|
32362
|
+
const result = await import_set_agent_identity.setAgentIdentityTool.execute({ ...input, apiKey }, {});
|
|
32363
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32364
|
+
});
|
|
32365
|
+
registerCutover("shareNoteTool", async (input, apiKey) => {
|
|
32366
|
+
const result = await import_share_note.shareNoteTool.execute({ ...input, apiKey }, {});
|
|
32367
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32368
|
+
});
|
|
32369
|
+
registerCutover("shareVaultTool", async (input, apiKey) => {
|
|
32370
|
+
const result = await import_share_vault.shareVaultTool.execute({ ...input, apiKey }, {});
|
|
32371
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32372
|
+
});
|
|
32373
|
+
registerCutover("swapVaultTool", async (input, apiKey) => {
|
|
32374
|
+
const result = await import_swap_vault.swapVaultTool.execute({ ...input, apiKey }, {});
|
|
32375
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32376
|
+
});
|
|
32377
|
+
registerCutover("switchAccountTool", async (input, apiKey) => {
|
|
32378
|
+
const result = await import_switch_account.switchAccountTool.execute({ ...input, apiKey }, {});
|
|
32379
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32380
|
+
});
|
|
32381
|
+
registerCutover("unlinkShareTool", async (input, apiKey) => {
|
|
32382
|
+
const result = await import_unlink_share.unlinkShareTool.execute({ ...input, apiKey }, {});
|
|
32383
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32384
|
+
});
|
|
32385
|
+
registerCutover("memoryQuestionsTool", async (input, apiKey) => {
|
|
32386
|
+
const result = await import_memory_questions.memoryQuestionsTool.execute({ ...input, apiKey }, {});
|
|
32387
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32388
|
+
});
|
|
32389
|
+
registerCutover("createChannelTool", async (input, apiKey) => {
|
|
32390
|
+
const result = await import_create_channel.createChannelTool.execute({ ...input, apiKey }, {});
|
|
32391
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32392
|
+
});
|
|
32393
|
+
registerCutover("listChannelMessagesTool", async (input, apiKey) => {
|
|
32394
|
+
const result = await import_list_channel_messages.listChannelMessagesTool.execute({ ...input, apiKey }, {});
|
|
32395
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32396
|
+
});
|
|
32397
|
+
registerCutover("pollChannelTool", async (input, apiKey) => {
|
|
32398
|
+
const result = await import_poll_channel.pollChannelTool.execute({ ...input, apiKey }, {});
|
|
32399
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32400
|
+
});
|
|
32401
|
+
registerCutover("postMessageTool", async (input, apiKey) => {
|
|
32402
|
+
const result = await import_post_message.postMessageTool.execute({ ...input, apiKey }, {});
|
|
32403
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32404
|
+
});
|
|
32405
|
+
registerCutover("reactMessageTool", async (input, apiKey) => {
|
|
32406
|
+
const result = await import_react_message.reactMessageTool.execute({ ...input, apiKey }, {});
|
|
32407
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32408
|
+
});
|
|
32409
|
+
registerCutover("removeChannelMemberTool", async (input, apiKey) => {
|
|
32410
|
+
const result = await import_remove_channel_member.removeChannelMemberTool.execute({ ...input, apiKey }, {});
|
|
32411
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32412
|
+
});
|
|
32413
|
+
registerCutover("replyMessageTool", async (input, apiKey) => {
|
|
32414
|
+
const result = await import_reply_message.replyMessageTool.execute({ ...input, apiKey }, {});
|
|
32415
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32416
|
+
});
|
|
32417
|
+
registerCutover("recordFactTool", async (input, apiKey) => {
|
|
32418
|
+
const result = await import_record_fact.recordFactTool.execute({ ...input, apiKey }, {});
|
|
32419
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32420
|
+
});
|
|
32421
|
+
registerCutover("libraryIngestTool", async (input, apiKey) => {
|
|
32422
|
+
const result = await import_library_ingest.libraryIngestTool.execute({ ...input, apiKey }, {});
|
|
32423
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32424
|
+
});
|
|
32425
|
+
registerCutover("deleteNoteTool", async (input, apiKey) => {
|
|
32426
|
+
const result = await import_delete_note.deleteNoteTool.execute({ ...input, apiKey }, {});
|
|
32427
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32428
|
+
});
|
|
32429
|
+
registerCutover("putTool", async (input, apiKey) => {
|
|
32430
|
+
const result = await import_put.putTool.execute({ ...input, apiKey }, {});
|
|
32431
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32432
|
+
});
|
|
32433
|
+
registerCutover("uploadTool", async (input, apiKey) => {
|
|
32434
|
+
const result = await import_upload.uploadTool.execute({ ...input, apiKey }, {});
|
|
32435
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32436
|
+
});
|
|
32437
|
+
registerCutover("deleteScheduledActionTool", async (input, apiKey) => {
|
|
32438
|
+
const result = await import_delete_scheduled_action.deleteScheduledActionTool.execute({ ...input, apiKey }, {});
|
|
32439
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32440
|
+
});
|
|
32441
|
+
registerCutover("pauseScheduledActionTool", async (input, apiKey) => {
|
|
32442
|
+
const result = await import_pause_scheduled_action.pauseScheduledActionTool.execute({ ...input, apiKey }, {});
|
|
32443
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32444
|
+
});
|
|
32445
|
+
registerCutover("resumeScheduledActionTool", async (input, apiKey) => {
|
|
32446
|
+
const result = await import_resume_scheduled_action.resumeScheduledActionTool.execute({ ...input, apiKey }, {});
|
|
32447
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32448
|
+
});
|
|
32449
|
+
registerCutover("createTableTool", async (input, apiKey) => {
|
|
32450
|
+
const result = await import_table_create.createTableTool.execute({ ...input, apiKey }, {});
|
|
32451
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32452
|
+
});
|
|
32453
|
+
registerCutover("deleteTableRowsTool", async (input, apiKey) => {
|
|
32454
|
+
const result = await import_table_delete_rows.deleteTableRowsTool.execute({ ...input, apiKey }, {});
|
|
32455
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32456
|
+
});
|
|
32457
|
+
registerCutover("dropTableTool", async (input, apiKey) => {
|
|
32458
|
+
const result = await import_table_drop.dropTableTool.execute({ ...input, apiKey }, {});
|
|
32459
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32460
|
+
});
|
|
32461
|
+
registerCutover("insertTableRowsTool", async (input, apiKey) => {
|
|
32462
|
+
const result = await import_table_insert_rows.insertTableRowsTool.execute({ ...input, apiKey }, {});
|
|
32463
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32464
|
+
});
|
|
32465
|
+
registerCutover("addVaultTool", async (input, apiKey) => {
|
|
32466
|
+
const result = await import_add_vault.addVaultTool.execute({ ...input, apiKey }, {});
|
|
32467
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32468
|
+
});
|
|
32469
|
+
registerCutover("deleteVaultTool", async (input, apiKey) => {
|
|
32470
|
+
const result = await import_delete_vault.deleteVaultTool.execute({ ...input, apiKey }, {});
|
|
32471
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32472
|
+
});
|
|
32473
|
+
}
|
|
32474
|
+
var import_accept_share, import_approve_sender, import_decline_share, import_inbox_settings, import_remove_approved_sender, import_revoke_share, import_set_agent_identity, import_share_note, import_share_vault, import_swap_vault, import_switch_account, import_unlink_share, import_memory_questions, import_create_channel, import_list_channel_messages, import_poll_channel, import_post_message, import_react_message, import_remove_channel_member, import_reply_message, import_record_fact, import_library_ingest, import_delete_note, import_put, import_upload, import_delete_scheduled_action, import_pause_scheduled_action, import_resume_scheduled_action, import_table_create, import_table_delete_rows, import_table_drop, import_table_insert_rows, import_add_vault, import_delete_vault, registered2;
|
|
32475
|
+
var init_writes = __esm({
|
|
32476
|
+
"src/mcp/memory-cutover/writes.ts"() {
|
|
32477
|
+
"use strict";
|
|
32478
|
+
init_memory_inprocess_executor();
|
|
32479
|
+
import_accept_share = require("mcpscraper-memory-tools/tools/access/accept-share");
|
|
32480
|
+
import_approve_sender = require("mcpscraper-memory-tools/tools/access/approve-sender");
|
|
32481
|
+
import_decline_share = require("mcpscraper-memory-tools/tools/access/decline-share");
|
|
32482
|
+
import_inbox_settings = require("mcpscraper-memory-tools/tools/access/inbox-settings");
|
|
32483
|
+
import_remove_approved_sender = require("mcpscraper-memory-tools/tools/access/remove-approved-sender");
|
|
32484
|
+
import_revoke_share = require("mcpscraper-memory-tools/tools/access/revoke-share");
|
|
32485
|
+
import_set_agent_identity = require("mcpscraper-memory-tools/tools/access/set-agent-identity");
|
|
32486
|
+
import_share_note = require("mcpscraper-memory-tools/tools/access/share-note");
|
|
32487
|
+
import_share_vault = require("mcpscraper-memory-tools/tools/access/share-vault");
|
|
32488
|
+
import_swap_vault = require("mcpscraper-memory-tools/tools/access/swap-vault");
|
|
32489
|
+
import_switch_account = require("mcpscraper-memory-tools/tools/access/switch-account");
|
|
32490
|
+
import_unlink_share = require("mcpscraper-memory-tools/tools/access/unlink-share");
|
|
32491
|
+
import_memory_questions = require("mcpscraper-memory-tools/tools/capture/memory-questions");
|
|
32492
|
+
import_create_channel = require("mcpscraper-memory-tools/tools/channels/create-channel");
|
|
32493
|
+
import_list_channel_messages = require("mcpscraper-memory-tools/tools/channels/list-channel-messages");
|
|
32494
|
+
import_poll_channel = require("mcpscraper-memory-tools/tools/channels/poll-channel");
|
|
32495
|
+
import_post_message = require("mcpscraper-memory-tools/tools/channels/post-message");
|
|
32496
|
+
import_react_message = require("mcpscraper-memory-tools/tools/channels/react-message");
|
|
32497
|
+
import_remove_channel_member = require("mcpscraper-memory-tools/tools/channels/remove-channel-member");
|
|
32498
|
+
import_reply_message = require("mcpscraper-memory-tools/tools/channels/reply-message");
|
|
32499
|
+
import_record_fact = require("mcpscraper-memory-tools/tools/facts/record-fact");
|
|
32500
|
+
import_library_ingest = require("mcpscraper-memory-tools/tools/library/library-ingest");
|
|
32501
|
+
import_delete_note = require("mcpscraper-memory-tools/tools/memory/delete-note");
|
|
32502
|
+
import_put = require("mcpscraper-memory-tools/tools/memory/put");
|
|
32503
|
+
import_upload = require("mcpscraper-memory-tools/tools/memory/upload");
|
|
32504
|
+
import_delete_scheduled_action = require("mcpscraper-memory-tools/tools/schedule/delete-scheduled-action");
|
|
32505
|
+
import_pause_scheduled_action = require("mcpscraper-memory-tools/tools/schedule/pause-scheduled-action");
|
|
32506
|
+
import_resume_scheduled_action = require("mcpscraper-memory-tools/tools/schedule/resume-scheduled-action");
|
|
32507
|
+
import_table_create = require("mcpscraper-memory-tools/tools/tables/table-create");
|
|
32508
|
+
import_table_delete_rows = require("mcpscraper-memory-tools/tools/tables/table-delete-rows");
|
|
32509
|
+
import_table_drop = require("mcpscraper-memory-tools/tools/tables/table-drop");
|
|
32510
|
+
import_table_insert_rows = require("mcpscraper-memory-tools/tools/tables/table-insert-rows");
|
|
32511
|
+
import_add_vault = require("mcpscraper-memory-tools/tools/vaults/add-vault");
|
|
32512
|
+
import_delete_vault = require("mcpscraper-memory-tools/tools/vaults/delete-vault");
|
|
32513
|
+
registered2 = false;
|
|
32514
|
+
}
|
|
32515
|
+
});
|
|
32516
|
+
|
|
32517
|
+
// src/mcp/memory-cutover/billing.ts
|
|
32518
|
+
function registerBillingCutovers() {
|
|
32519
|
+
if (registered3) return;
|
|
32520
|
+
registered3 = true;
|
|
32521
|
+
registerCutover("issueKeyTool", async (input, apiKey) => {
|
|
32522
|
+
const result = await import_issue_key.issueKeyTool.execute({ ...input, apiKey }, {});
|
|
32523
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32524
|
+
});
|
|
32525
|
+
registerCutover("listKeysTool", async (input, apiKey) => {
|
|
32526
|
+
const result = await import_list_keys.listKeysTool.execute({ ...input, apiKey }, {});
|
|
32527
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32528
|
+
});
|
|
32529
|
+
registerCutover("revokeKeyTool", async (input, apiKey) => {
|
|
32530
|
+
const result = await import_revoke_key.revokeKeyTool.execute({ ...input, apiKey }, {});
|
|
32531
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32532
|
+
});
|
|
32533
|
+
registerCutover("setScopeTool", async (input, apiKey) => {
|
|
32534
|
+
const result = await import_set_scope.setScopeTool.execute({ ...input, apiKey }, {});
|
|
32535
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32536
|
+
});
|
|
32537
|
+
registerCutover("inviteAccountTool", async (input, apiKey) => {
|
|
32538
|
+
const result = await import_invite_account.inviteAccountTool.execute({ ...input, apiKey }, {});
|
|
32539
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32540
|
+
});
|
|
32541
|
+
registerCutover("getChatLinkTool", async (input, apiKey) => {
|
|
32542
|
+
const result = await import_get_chat_link.getChatLinkTool.execute({ ...input, apiKey }, {});
|
|
32543
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32544
|
+
});
|
|
32545
|
+
registerCutover("revokeChatLinkTool", async (input, apiKey) => {
|
|
32546
|
+
const result = await import_revoke_chat_link.revokeChatLinkTool.execute({ ...input, apiKey }, {});
|
|
32547
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32548
|
+
});
|
|
32549
|
+
registerCutover("provisionDefaultsTool", async (input, apiKey) => {
|
|
32550
|
+
const result = await import_provision_defaults2.provisionDefaultsTool.execute({ ...input, apiKey }, {});
|
|
32551
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32552
|
+
});
|
|
32553
|
+
registerCutover("createSecureVaultTool", async (input, apiKey) => {
|
|
32554
|
+
const result = await import_create_secure_vault.createSecureVaultTool.execute({ ...input, apiKey }, {});
|
|
32555
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32556
|
+
});
|
|
32557
|
+
registerCutover("createScheduledActionTool", async (input, apiKey) => {
|
|
32558
|
+
const result = await import_create_scheduled_action.createScheduledActionTool.execute({ ...input, apiKey }, {});
|
|
32559
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32560
|
+
});
|
|
32561
|
+
registerCutover("getScheduleStatusTool", async (input, apiKey) => {
|
|
32562
|
+
const result = await import_get_schedule_status.getScheduleStatusTool.execute({ ...input, apiKey }, {});
|
|
32563
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32564
|
+
});
|
|
32565
|
+
registerCutover("getScheduleLinkTool", async (input, apiKey) => {
|
|
32566
|
+
const result = await import_get_schedule_link.getScheduleLinkTool.execute({ ...input, apiKey }, {});
|
|
32567
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32568
|
+
});
|
|
32569
|
+
registerCutover("revokeScheduleLinkTool", async (input, apiKey) => {
|
|
32570
|
+
const result = await import_revoke_schedule_link.revokeScheduleLinkTool.execute({ ...input, apiKey }, {});
|
|
32571
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32572
|
+
});
|
|
32573
|
+
registerCutover("setScheduleEntitlementTool", async (input, apiKey) => {
|
|
32574
|
+
const result = await import_set_schedule_entitlement2.setScheduleEntitlementTool.execute({ ...input, apiKey }, {});
|
|
32575
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32576
|
+
});
|
|
32577
|
+
registerCutover("createWebhookTool", async (input, apiKey) => {
|
|
32578
|
+
const result = await import_create_webhook.createWebhookTool.execute({ ...input, apiKey }, {});
|
|
32579
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32580
|
+
});
|
|
32581
|
+
registerCutover("revokeWebhookTool", async (input, apiKey) => {
|
|
32582
|
+
const result = await import_revoke_webhook.revokeWebhookTool.execute({ ...input, apiKey }, {});
|
|
32583
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32584
|
+
});
|
|
32585
|
+
}
|
|
32586
|
+
var import_issue_key, import_list_keys, import_revoke_key, import_set_scope, import_invite_account, import_get_chat_link, import_revoke_chat_link, import_provision_defaults2, import_create_secure_vault, import_create_scheduled_action, import_get_schedule_status, import_get_schedule_link, import_revoke_schedule_link, import_set_schedule_entitlement2, import_create_webhook, import_revoke_webhook, registered3;
|
|
32587
|
+
var init_billing = __esm({
|
|
32588
|
+
"src/mcp/memory-cutover/billing.ts"() {
|
|
32589
|
+
"use strict";
|
|
32590
|
+
init_memory_inprocess_executor();
|
|
32591
|
+
import_issue_key = require("mcpscraper-memory-tools/tools/access/issue-key");
|
|
32592
|
+
import_list_keys = require("mcpscraper-memory-tools/tools/access/list-keys");
|
|
32593
|
+
import_revoke_key = require("mcpscraper-memory-tools/tools/access/revoke-key");
|
|
32594
|
+
import_set_scope = require("mcpscraper-memory-tools/tools/access/set-scope");
|
|
32595
|
+
import_invite_account = require("mcpscraper-memory-tools/tools/access/invite-account");
|
|
32596
|
+
import_get_chat_link = require("mcpscraper-memory-tools/tools/access/get-chat-link");
|
|
32597
|
+
import_revoke_chat_link = require("mcpscraper-memory-tools/tools/access/revoke-chat-link");
|
|
32598
|
+
import_provision_defaults2 = require("mcpscraper-memory-tools/tools/vaults/provision-defaults");
|
|
32599
|
+
import_create_secure_vault = require("mcpscraper-memory-tools/tools/vaults/create-secure-vault");
|
|
32600
|
+
import_create_scheduled_action = require("mcpscraper-memory-tools/tools/schedule/create-scheduled-action");
|
|
32601
|
+
import_get_schedule_status = require("mcpscraper-memory-tools/tools/schedule/get-schedule-status");
|
|
32602
|
+
import_get_schedule_link = require("mcpscraper-memory-tools/tools/schedule/get-schedule-link");
|
|
32603
|
+
import_revoke_schedule_link = require("mcpscraper-memory-tools/tools/schedule/revoke-schedule-link");
|
|
32604
|
+
import_set_schedule_entitlement2 = require("mcpscraper-memory-tools/tools/schedule/set-schedule-entitlement");
|
|
32605
|
+
import_create_webhook = require("mcpscraper-memory-tools/tools/webhooks/create-webhook");
|
|
32606
|
+
import_revoke_webhook = require("mcpscraper-memory-tools/tools/webhooks/revoke-webhook");
|
|
32607
|
+
registered3 = false;
|
|
32608
|
+
}
|
|
32609
|
+
});
|
|
32610
|
+
|
|
32611
|
+
// src/mcp/memory-cutover/cross-service.ts
|
|
32612
|
+
function registerCrossServiceCutovers() {
|
|
32613
|
+
if (registered4) return;
|
|
32614
|
+
registered4 = true;
|
|
32615
|
+
registerCutover("proposeScheduledActionTool", async (input, apiKey) => {
|
|
32616
|
+
const result = await import_propose_scheduled_action.proposeScheduledActionTool.execute({ ...input, apiKey }, {});
|
|
32617
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32618
|
+
});
|
|
32619
|
+
}
|
|
32620
|
+
var import_propose_scheduled_action, registered4;
|
|
32621
|
+
var init_cross_service = __esm({
|
|
32622
|
+
"src/mcp/memory-cutover/cross-service.ts"() {
|
|
32623
|
+
"use strict";
|
|
32624
|
+
init_memory_inprocess_executor();
|
|
32625
|
+
import_propose_scheduled_action = require("mcpscraper-memory-tools/tools/schedule/propose-scheduled-action");
|
|
32626
|
+
registered4 = false;
|
|
32627
|
+
}
|
|
32628
|
+
});
|
|
32629
|
+
|
|
32630
|
+
// src/mcp/memory-cutover/video.ts
|
|
32631
|
+
function registerVideoCutovers() {
|
|
32632
|
+
if (registered5) return;
|
|
32633
|
+
registered5 = true;
|
|
32634
|
+
registerCutover("videoAnalyzeStartTool", async (input, apiKey) => {
|
|
32635
|
+
const result = await import_start.videoAnalyzeStartTool.execute({ ...input, apiKey }, {});
|
|
32636
|
+
return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
|
|
32637
|
+
});
|
|
32638
|
+
}
|
|
32639
|
+
var import_start, registered5;
|
|
32640
|
+
var init_video = __esm({
|
|
32641
|
+
"src/mcp/memory-cutover/video.ts"() {
|
|
32642
|
+
"use strict";
|
|
32643
|
+
init_memory_inprocess_executor();
|
|
32644
|
+
import_start = require("mcpscraper-memory-tools/tools/video/start");
|
|
32645
|
+
registered5 = false;
|
|
32646
|
+
}
|
|
32647
|
+
});
|
|
32648
|
+
|
|
31960
32649
|
// src/mcp/mcp-oauth.ts
|
|
31961
32650
|
function oauthIssuer() {
|
|
31962
32651
|
return (process.env.OAUTH_ISSUER ?? "https://mcpscraper.dev").replace(/\/$/, "");
|
|
@@ -32035,13 +32724,13 @@ async function requireMcpCallerKey(c) {
|
|
|
32035
32724
|
if (!identity) return mcpAuthError("Bearer token has no subject");
|
|
32036
32725
|
const user2 = await getUserByEmail(identity);
|
|
32037
32726
|
if (!user2 || !user2.api_key || user2.key_active !== 1) return mcpAuthError("No active MCP Scraper account for this identity");
|
|
32038
|
-
return user2.api_key;
|
|
32727
|
+
return { key: user2.api_key, user: user2 };
|
|
32039
32728
|
}
|
|
32040
32729
|
const callerKey = xApiKey ?? bearerToken;
|
|
32041
32730
|
if (!callerKey) return mcpAuthError();
|
|
32042
32731
|
const user = await getUserByApiKey(callerKey);
|
|
32043
32732
|
if (!user) return mcpAuthError();
|
|
32044
|
-
return callerKey;
|
|
32733
|
+
return { key: callerKey, user };
|
|
32045
32734
|
}
|
|
32046
32735
|
var import_hono14, import_webStandardStreamableHttp, mcpApp;
|
|
32047
32736
|
var init_mcp_routes = __esm({
|
|
@@ -32054,16 +32743,27 @@ var init_mcp_routes = __esm({
|
|
|
32054
32743
|
init_browser_agent_mcp_server();
|
|
32055
32744
|
init_memory_mcp_server();
|
|
32056
32745
|
init_memory_mcp_tool_executor();
|
|
32746
|
+
init_memory_inprocess_executor();
|
|
32747
|
+
init_reads();
|
|
32748
|
+
init_writes();
|
|
32749
|
+
init_billing();
|
|
32750
|
+
init_cross_service();
|
|
32751
|
+
init_video();
|
|
32057
32752
|
init_mcp_response_formatter();
|
|
32058
32753
|
init_db();
|
|
32059
32754
|
init_mcp_oauth();
|
|
32755
|
+
registerReadCutovers();
|
|
32756
|
+
registerWriteCutovers();
|
|
32757
|
+
registerBillingCutovers();
|
|
32758
|
+
registerCrossServiceCutovers();
|
|
32759
|
+
registerVideoCutovers();
|
|
32060
32760
|
configureReportSaving(false);
|
|
32061
32761
|
mcpApp = new import_hono14.Hono();
|
|
32062
32762
|
mcpApp.all("/", async (c) => {
|
|
32063
32763
|
try {
|
|
32064
32764
|
const keyOrError = await requireMcpCallerKey(c);
|
|
32065
32765
|
if (keyOrError instanceof Response) return keyOrError;
|
|
32066
|
-
const callerKey = keyOrError;
|
|
32766
|
+
const { key: callerKey, user } = keyOrError;
|
|
32067
32767
|
const baseUrl = process.env.MCP_SCRAPER_BASE_URL?.trim() ?? process.env.MCP_BASE_URL?.trim() ?? "https://mcpscraper.dev";
|
|
32068
32768
|
const executor = new HttpMcpToolExecutor(baseUrl, callerKey);
|
|
32069
32769
|
const transport = new import_webStandardStreamableHttp.WebStandardStreamableHTTPServerTransport({
|
|
@@ -32074,7 +32774,8 @@ var init_mcp_routes = __esm({
|
|
|
32074
32774
|
const server = buildPaaExtractorMcpServer(executor, { savesReportsLocally: false, ownerId: hashOwnerId(callerKey) });
|
|
32075
32775
|
registerSerpIntelligenceCaptureTools(server, executor);
|
|
32076
32776
|
registerBrowserAgentMcpTools(server, { baseUrl, apiKey: callerKey, consoleBaseUrl, savesReportsLocally: false });
|
|
32077
|
-
|
|
32777
|
+
const memoryExecutor = new HybridMemoryToolExecutor(new MemoryMcpToolExecutor(baseUrl, callerKey), user);
|
|
32778
|
+
registerMemoryMcpTools(server, memoryExecutor);
|
|
32078
32779
|
await server.connect(transport);
|
|
32079
32780
|
return transport.handleRequest(c.req.raw);
|
|
32080
32781
|
} catch {
|
|
@@ -32159,23 +32860,34 @@ async function migrateBrowserAgent() {
|
|
|
32159
32860
|
await db.execute(`ALTER TABLE browser_auth_connections ADD COLUMN updated_at TEXT`);
|
|
32160
32861
|
} catch {
|
|
32161
32862
|
}
|
|
32863
|
+
try {
|
|
32864
|
+
await db.execute(`ALTER TABLE browser_auth_connections ADD COLUMN status TEXT NOT NULL DEFAULT 'NEEDS_AUTH'`);
|
|
32865
|
+
} catch {
|
|
32866
|
+
}
|
|
32867
|
+
try {
|
|
32868
|
+
await db.execute(`ALTER TABLE browser_auth_connections ADD COLUMN browser_agent_session_id TEXT`);
|
|
32869
|
+
} catch {
|
|
32870
|
+
}
|
|
32162
32871
|
await db.execute(`CREATE INDEX IF NOT EXISTS browser_auth_connections_profile ON browser_auth_connections(profile)`);
|
|
32163
32872
|
_ready2 = true;
|
|
32164
32873
|
}
|
|
32165
|
-
async function
|
|
32166
|
-
|
|
32874
|
+
async function createAuthConnectionRow(input) {
|
|
32875
|
+
const db = getDb();
|
|
32876
|
+
const connectionId = `authc_${(0, import_node_crypto11.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
32877
|
+
await db.execute({
|
|
32878
|
+
sql: `INSERT INTO browser_auth_connections (connection_id, domain, profile, account_email, note, status, browser_agent_session_id)
|
|
32879
|
+
VALUES (?, ?, ?, ?, ?, 'NEEDS_AUTH', ?)`,
|
|
32880
|
+
args: [connectionId, input.domain, input.profile, input.accountEmail, input.note, input.browserAgentSessionId]
|
|
32881
|
+
});
|
|
32882
|
+
const row = await getAuthConnectionRow(connectionId);
|
|
32883
|
+
if (!row) throw new Error("auth connection insert failed");
|
|
32884
|
+
return row;
|
|
32885
|
+
}
|
|
32886
|
+
async function markAuthConnectionAuthenticated(connectionId) {
|
|
32167
32887
|
const db = getDb();
|
|
32168
32888
|
await db.execute({
|
|
32169
|
-
sql: `
|
|
32170
|
-
|
|
32171
|
-
ON CONFLICT(connection_id) DO UPDATE SET
|
|
32172
|
-
hosted_url = COALESCE(excluded.hosted_url, browser_auth_connections.hosted_url),
|
|
32173
|
-
domain = COALESCE(excluded.domain, browser_auth_connections.domain),
|
|
32174
|
-
profile = COALESCE(excluded.profile, browser_auth_connections.profile),
|
|
32175
|
-
account_email = COALESCE(excluded.account_email, browser_auth_connections.account_email),
|
|
32176
|
-
note = COALESCE(excluded.note, browser_auth_connections.note),
|
|
32177
|
-
updated_at = datetime('now')`,
|
|
32178
|
-
args: [input.connectionId, input.hostedUrl, input.domain, input.profile, input.accountEmail ?? null, input.note ?? null]
|
|
32889
|
+
sql: `UPDATE browser_auth_connections SET status = 'AUTHENTICATED', updated_at = datetime('now') WHERE connection_id = ?`,
|
|
32890
|
+
args: [connectionId]
|
|
32179
32891
|
});
|
|
32180
32892
|
}
|
|
32181
32893
|
async function getAuthConnectionRow(connectionId) {
|
|
@@ -33082,79 +33794,10 @@ async function ensureProfile(k, name) {
|
|
|
33082
33794
|
if (!isProfileConflict(err)) throw err;
|
|
33083
33795
|
}
|
|
33084
33796
|
}
|
|
33085
|
-
function profileConnectionMatches(connection, profileName, domain) {
|
|
33086
|
-
if (!connection || typeof connection !== "object") return false;
|
|
33087
|
-
const data = connection;
|
|
33088
|
-
return data.profile_name === profileName && data.domain === domain;
|
|
33089
|
-
}
|
|
33090
|
-
async function findProfileConnection(k, profileName, domain) {
|
|
33091
|
-
for await (const connection of k.auth.connections.list({ profile_name: profileName, domain })) {
|
|
33092
|
-
if (profileConnectionMatches(connection, profileName, domain)) return connection;
|
|
33093
|
-
}
|
|
33094
|
-
return null;
|
|
33095
|
-
}
|
|
33096
|
-
async function listProfileConnections(profileName) {
|
|
33097
|
-
if (!profileName) return [];
|
|
33098
|
-
const k = client();
|
|
33099
|
-
const out = [];
|
|
33100
|
-
for await (const connection of k.auth.connections.list({ profile_name: profileName })) {
|
|
33101
|
-
const data = connection;
|
|
33102
|
-
if (data.profile_name && data.profile_name !== profileName) continue;
|
|
33103
|
-
out.push(profileOnboardResult(connection));
|
|
33104
|
-
}
|
|
33105
|
-
return out;
|
|
33106
|
-
}
|
|
33107
|
-
async function findOrCreateProfileConnection(k, opts) {
|
|
33108
|
-
try {
|
|
33109
|
-
return await k.auth.connections.create({
|
|
33110
|
-
domain: opts.domain,
|
|
33111
|
-
profile_name: opts.profileName,
|
|
33112
|
-
...opts.loginUrl ? { login_url: opts.loginUrl } : {}
|
|
33113
|
-
});
|
|
33114
|
-
} catch (err) {
|
|
33115
|
-
if (!isProfileConflict(err)) throw err;
|
|
33116
|
-
const existing = await findProfileConnection(k, opts.profileName, opts.domain);
|
|
33117
|
-
if (existing) return existing;
|
|
33118
|
-
throw err;
|
|
33119
|
-
}
|
|
33120
|
-
}
|
|
33121
|
-
function profileOnboardResult(connection, hostedUrl = null, liveViewUrl = null) {
|
|
33122
|
-
return {
|
|
33123
|
-
connectionId: String(connection.id),
|
|
33124
|
-
profileName: String(connection.profile_name),
|
|
33125
|
-
domain: String(connection.domain),
|
|
33126
|
-
status: String(connection.status),
|
|
33127
|
-
flowStatus: typeof connection.flow_status === "string" ? connection.flow_status : null,
|
|
33128
|
-
flowStep: typeof connection.flow_step === "string" ? connection.flow_step : null,
|
|
33129
|
-
flowExpiresAt: typeof connection.flow_expires_at === "string" ? connection.flow_expires_at : null,
|
|
33130
|
-
hostedUrl: hostedUrl ?? (typeof connection.hosted_url === "string" ? connection.hosted_url : null),
|
|
33131
|
-
liveViewUrl: liveViewUrl ?? (typeof connection.live_view_url === "string" ? connection.live_view_url : null),
|
|
33132
|
-
browserSessionId: typeof connection.browser_session_id === "string" ? connection.browser_session_id : null,
|
|
33133
|
-
postLoginUrl: typeof connection.post_login_url === "string" ? connection.post_login_url : null
|
|
33134
|
-
};
|
|
33135
|
-
}
|
|
33136
33797
|
function explicitProxyId(value) {
|
|
33137
33798
|
const trimmed = value?.trim();
|
|
33138
33799
|
return trimmed || void 0;
|
|
33139
33800
|
}
|
|
33140
|
-
async function startProfileOnboarding(opts) {
|
|
33141
|
-
const k = client();
|
|
33142
|
-
const connection = await findOrCreateProfileConnection(k, opts);
|
|
33143
|
-
const login = await k.auth.connections.login(connection.id);
|
|
33144
|
-
const state = await k.auth.connections.retrieve(connection.id);
|
|
33145
|
-
return profileOnboardResult(state, login.hosted_url ?? null, login.live_view_url ?? null);
|
|
33146
|
-
}
|
|
33147
|
-
async function getProfileOnboardingStatus(input) {
|
|
33148
|
-
const k = client();
|
|
33149
|
-
let connection = null;
|
|
33150
|
-
if (input.connectionId) {
|
|
33151
|
-
connection = await k.auth.connections.retrieve(input.connectionId);
|
|
33152
|
-
} else if (input.profileName && input.domain) {
|
|
33153
|
-
connection = await findProfileConnection(k, input.profileName, input.domain);
|
|
33154
|
-
}
|
|
33155
|
-
if (!connection) throw new Error("profile auth connection not found");
|
|
33156
|
-
return profileOnboardResult(connection);
|
|
33157
|
-
}
|
|
33158
33801
|
async function createSession(opts = {}) {
|
|
33159
33802
|
const k = client();
|
|
33160
33803
|
const resolvedProxyId = explicitProxyId(opts.proxyId);
|
|
@@ -33505,24 +34148,39 @@ async function charge(sessionId, userId, _startedAtMs) {
|
|
|
33505
34148
|
if (res.ok) await setBilledMc(sessionId, owed);
|
|
33506
34149
|
}
|
|
33507
34150
|
}
|
|
34151
|
+
async function closeAndSettleSession(row) {
|
|
34152
|
+
if (row.user_id != null) {
|
|
34153
|
+
try {
|
|
34154
|
+
await charge(row.id, row.user_id);
|
|
34155
|
+
} catch {
|
|
34156
|
+
}
|
|
34157
|
+
}
|
|
34158
|
+
try {
|
|
34159
|
+
await closeSession(row.runtime_session_id);
|
|
34160
|
+
} catch {
|
|
34161
|
+
}
|
|
34162
|
+
await markSessionClosed(row.id).catch(() => {
|
|
34163
|
+
});
|
|
34164
|
+
await releaseConcurrencyGate(row.concurrency_lock_id).catch(() => {
|
|
34165
|
+
});
|
|
34166
|
+
}
|
|
34167
|
+
async function completeAuthConnection(connectionId) {
|
|
34168
|
+
const connection = await getAuthConnectionRow(connectionId);
|
|
34169
|
+
if (!connection) return { ok: false, error: "not found" };
|
|
34170
|
+
if (connection.browser_agent_session_id) {
|
|
34171
|
+
const sessionRow = await getSessionRow(connection.browser_agent_session_id);
|
|
34172
|
+
if (sessionRow && sessionRow.status === "open") {
|
|
34173
|
+
await closeAndSettleSession(sessionRow);
|
|
34174
|
+
}
|
|
34175
|
+
}
|
|
34176
|
+
await markAuthConnectionAuthenticated(connectionId);
|
|
34177
|
+
return { ok: true };
|
|
34178
|
+
}
|
|
33508
34179
|
async function reapIdleBrowserSessions(idleSeconds = 120) {
|
|
33509
34180
|
const rows = await listIdleOpenSessionRows(idleSeconds);
|
|
33510
34181
|
let reaped = 0;
|
|
33511
34182
|
for (const row of rows) {
|
|
33512
|
-
|
|
33513
|
-
try {
|
|
33514
|
-
await charge(row.id, row.user_id);
|
|
33515
|
-
} catch {
|
|
33516
|
-
}
|
|
33517
|
-
}
|
|
33518
|
-
try {
|
|
33519
|
-
await closeSession(row.runtime_session_id);
|
|
33520
|
-
} catch {
|
|
33521
|
-
}
|
|
33522
|
-
await markSessionClosed(row.id).catch(() => {
|
|
33523
|
-
});
|
|
33524
|
-
if (row.concurrency_lock_id) await releaseConcurrencyGate(row.concurrency_lock_id).catch(() => {
|
|
33525
|
-
});
|
|
34183
|
+
await closeAndSettleSession(row);
|
|
33526
34184
|
reaped++;
|
|
33527
34185
|
}
|
|
33528
34186
|
return { reaped };
|
|
@@ -33590,74 +34248,87 @@ function buildBrowserAgentRoutes() {
|
|
|
33590
34248
|
});
|
|
33591
34249
|
app2.use("*", auth);
|
|
33592
34250
|
app2.post("/profiles/onboard", async (c) => {
|
|
34251
|
+
const user = c.get("user");
|
|
34252
|
+
if (Number(user.balance_mc ?? 0) < BROWSER_OPEN_MIN_BALANCE_MC) {
|
|
34253
|
+
return c.json(insufficientBalanceResponse(Number(user.balance_mc ?? 0), BROWSER_OPEN_MIN_BALANCE_MC), 402);
|
|
34254
|
+
}
|
|
33593
34255
|
const body = await c.req.json().catch(() => ({}));
|
|
33594
34256
|
const profileName = typeof body.profile === "string" ? body.profile.trim() : "";
|
|
33595
34257
|
const domain = typeof body.domain === "string" ? body.domain.trim().replace(/^https?:\/\//, "").replace(/\/.*$/, "") : "chatgpt.com";
|
|
33596
34258
|
const loginUrl = typeof body.login_url === "string" ? body.login_url.trim() : void 0;
|
|
33597
34259
|
const accountEmail = typeof body.account_email === "string" ? body.account_email.trim() || null : null;
|
|
33598
34260
|
const note = typeof body.note === "string" ? body.note.trim() || null : null;
|
|
34261
|
+
const timeoutSeconds = typeof body.timeout_seconds === "number" ? body.timeout_seconds : void 0;
|
|
33599
34262
|
if (!profileName) return c.json({ error: "profile is required" }, 400);
|
|
33600
34263
|
if (!domain) return c.json({ error: "domain is required" }, 400);
|
|
34264
|
+
const gate = await acquireConcurrencyGate(user, "browser_agent_session", {
|
|
34265
|
+
ttlSeconds: browserSessionLockTtlSeconds(timeoutSeconds),
|
|
34266
|
+
metadata: { label: typeof body.label === "string" ? body.label : null }
|
|
34267
|
+
});
|
|
34268
|
+
if (!gate.ok) return c.json(concurrencyLimitExceededResponse(gate), 429, { "Retry-After": String(gate.retryAfterSeconds) });
|
|
34269
|
+
let runtimeSessionId = null;
|
|
33601
34270
|
try {
|
|
33602
|
-
const
|
|
33603
|
-
|
|
33604
|
-
|
|
33605
|
-
|
|
33606
|
-
|
|
33607
|
-
|
|
33608
|
-
|
|
33609
|
-
|
|
33610
|
-
|
|
33611
|
-
|
|
33612
|
-
|
|
33613
|
-
|
|
34271
|
+
const created = await createSession({
|
|
34272
|
+
timeoutSeconds,
|
|
34273
|
+
profileName,
|
|
34274
|
+
saveProfileChanges: true,
|
|
34275
|
+
startUrl: loginUrl || `https://${domain}/`,
|
|
34276
|
+
disableDefaultProxy: true
|
|
34277
|
+
});
|
|
34278
|
+
runtimeSessionId = created.runtimeSessionId;
|
|
34279
|
+
const sessionRow = await createSessionRow({
|
|
34280
|
+
runtimeSessionId: created.runtimeSessionId,
|
|
34281
|
+
liveViewUrl: created.liveViewUrl,
|
|
34282
|
+
cdpWsUrl: created.cdpWsUrl,
|
|
34283
|
+
label: typeof body.label === "string" ? body.label : `Login setup: ${domain} \u2192 ${profileName}`,
|
|
34284
|
+
userId: user.id,
|
|
34285
|
+
concurrencyLockId: gate.lockId
|
|
34286
|
+
});
|
|
34287
|
+
const connection = await createAuthConnectionRow({
|
|
34288
|
+
domain,
|
|
34289
|
+
profile: profileName,
|
|
34290
|
+
accountEmail,
|
|
34291
|
+
note,
|
|
34292
|
+
browserAgentSessionId: sessionRow.id
|
|
34293
|
+
});
|
|
33614
34294
|
return c.json({
|
|
33615
|
-
connection_id:
|
|
33616
|
-
profile:
|
|
33617
|
-
domain
|
|
33618
|
-
status:
|
|
33619
|
-
|
|
33620
|
-
flow_step: result.flowStep,
|
|
33621
|
-
flow_expires_at: result.flowExpiresAt,
|
|
33622
|
-
browser_session_id: result.browserSessionId,
|
|
33623
|
-
post_login_url: result.postLoginUrl
|
|
34295
|
+
connection_id: connection.connection_id,
|
|
34296
|
+
profile: profileName,
|
|
34297
|
+
domain,
|
|
34298
|
+
status: connection.status,
|
|
34299
|
+
browser_session_id: sessionRow.id
|
|
33624
34300
|
});
|
|
33625
34301
|
} catch (err) {
|
|
34302
|
+
if (runtimeSessionId) {
|
|
34303
|
+
try {
|
|
34304
|
+
await closeSession(runtimeSessionId);
|
|
34305
|
+
} catch {
|
|
34306
|
+
}
|
|
34307
|
+
}
|
|
34308
|
+
await releaseConcurrencyGate(gate.lockId);
|
|
33626
34309
|
return c.json(failure(err), 502);
|
|
33627
34310
|
}
|
|
33628
34311
|
});
|
|
33629
34312
|
app2.post("/profiles/status", async (c) => {
|
|
33630
34313
|
const body = await c.req.json().catch(() => ({}));
|
|
33631
|
-
const connectionId = typeof body.connection_id === "string" ? body.connection_id.trim() :
|
|
33632
|
-
const profileName = typeof body.profile === "string" ? body.profile.trim() :
|
|
34314
|
+
const connectionId = typeof body.connection_id === "string" ? body.connection_id.trim() : "";
|
|
34315
|
+
const profileName = typeof body.profile === "string" ? body.profile.trim() : "";
|
|
33633
34316
|
const domain = typeof body.domain === "string" ? body.domain.trim().replace(/^https?:\/\//, "").replace(/\/.*$/, "") : void 0;
|
|
33634
|
-
|
|
33635
|
-
|
|
33636
|
-
|
|
33637
|
-
|
|
33638
|
-
|
|
33639
|
-
|
|
33640
|
-
|
|
33641
|
-
|
|
33642
|
-
|
|
33643
|
-
|
|
33644
|
-
|
|
33645
|
-
|
|
33646
|
-
|
|
33647
|
-
|
|
33648
|
-
|
|
33649
|
-
profile: result.profileName,
|
|
33650
|
-
domain: result.domain,
|
|
33651
|
-
status: result.status,
|
|
33652
|
-
flow_status: result.flowStatus,
|
|
33653
|
-
flow_step: result.flowStep,
|
|
33654
|
-
flow_expires_at: result.flowExpiresAt,
|
|
33655
|
-
browser_session_id: result.browserSessionId,
|
|
33656
|
-
post_login_url: result.postLoginUrl
|
|
33657
|
-
});
|
|
33658
|
-
} catch (err) {
|
|
33659
|
-
return c.json(failure(err), 404);
|
|
33660
|
-
}
|
|
34317
|
+
let row = null;
|
|
34318
|
+
if (connectionId) {
|
|
34319
|
+
row = await getAuthConnectionRow(connectionId);
|
|
34320
|
+
} else if (profileName && domain) {
|
|
34321
|
+
const rows = await listAuthConnectionsByProfile(profileName);
|
|
34322
|
+
row = rows.find((r) => r.domain === domain) ?? null;
|
|
34323
|
+
}
|
|
34324
|
+
if (!row) return c.json({ error: "auth connection not found" }, 404);
|
|
34325
|
+
return c.json({
|
|
34326
|
+
connection_id: row.connection_id,
|
|
34327
|
+
profile: row.profile,
|
|
34328
|
+
domain: row.domain,
|
|
34329
|
+
status: row.status,
|
|
34330
|
+
browser_session_id: row.browser_agent_session_id
|
|
34331
|
+
});
|
|
33661
34332
|
});
|
|
33662
34333
|
app2.post("/profiles/list", async (c) => {
|
|
33663
34334
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -33666,23 +34337,15 @@ function buildBrowserAgentRoutes() {
|
|
|
33666
34337
|
const domainFilter = typeof body.domain === "string" ? body.domain.trim().replace(/^https?:\/\//, "").replace(/\/.*$/, "") : void 0;
|
|
33667
34338
|
const connectionIdFilter = typeof body.connection_id === "string" ? body.connection_id.trim() : void 0;
|
|
33668
34339
|
try {
|
|
33669
|
-
const
|
|
33670
|
-
|
|
33671
|
-
|
|
33672
|
-
|
|
33673
|
-
|
|
33674
|
-
|
|
33675
|
-
|
|
33676
|
-
|
|
33677
|
-
|
|
33678
|
-
connection_id: conn.connectionId,
|
|
33679
|
-
domain: conn.domain,
|
|
33680
|
-
status: conn.status,
|
|
33681
|
-
account_email: record?.account_email ?? null,
|
|
33682
|
-
note: record?.note ?? null,
|
|
33683
|
-
last_connected_at: record?.updated_at ?? record?.created_at ?? null
|
|
33684
|
-
};
|
|
33685
|
-
});
|
|
34340
|
+
const stored = await listAuthConnectionsByProfile(profileName);
|
|
34341
|
+
let connections = stored.map((row) => ({
|
|
34342
|
+
connection_id: row.connection_id,
|
|
34343
|
+
domain: row.domain,
|
|
34344
|
+
status: row.status,
|
|
34345
|
+
account_email: row.account_email,
|
|
34346
|
+
note: row.note,
|
|
34347
|
+
last_connected_at: row.updated_at ?? row.created_at
|
|
34348
|
+
}));
|
|
33686
34349
|
if (connectionIdFilter) connections = connections.filter((c2) => c2.connection_id === connectionIdFilter);
|
|
33687
34350
|
if (domainFilter) connections = connections.filter((c2) => c2.domain === domainFilter);
|
|
33688
34351
|
return c.json({ profile: profileName, connections });
|
|
@@ -33757,13 +34420,7 @@ function buildBrowserAgentRoutes() {
|
|
|
33757
34420
|
const user = c.get("user");
|
|
33758
34421
|
const row = await loadOpenSession(c.req.param("id"), user.id);
|
|
33759
34422
|
if (!row) return c.json({ error: "not found" }, 404);
|
|
33760
|
-
await
|
|
33761
|
-
try {
|
|
33762
|
-
await closeSession(row.runtime_session_id);
|
|
33763
|
-
} catch {
|
|
33764
|
-
}
|
|
33765
|
-
await markSessionClosed(row.id);
|
|
33766
|
-
await releaseConcurrencyGate(row.concurrency_lock_id);
|
|
34423
|
+
await closeAndSettleSession(row);
|
|
33767
34424
|
return c.json({ ok: true });
|
|
33768
34425
|
});
|
|
33769
34426
|
app2.post("/sessions/:id/goto", async (c) => {
|
|
@@ -34063,17 +34720,30 @@ var init_browser_agent_routes = __esm({
|
|
|
34063
34720
|
});
|
|
34064
34721
|
|
|
34065
34722
|
// src/api/browser-agent-console.ts
|
|
34066
|
-
function renderAuthConsoleHtml(connectionId,
|
|
34067
|
-
const
|
|
34068
|
-
const
|
|
34069
|
-
const
|
|
34070
|
-
|
|
34071
|
-
|
|
34072
|
-
|
|
34073
|
-
|
|
34723
|
+
function renderAuthConsoleHtml(connectionId, info) {
|
|
34724
|
+
const esc2 = (s) => String(s == null ? "" : s).replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]);
|
|
34725
|
+
const safeId = esc2(connectionId);
|
|
34726
|
+
const domainLabel = info.domain ? esc2(info.domain) : "this site";
|
|
34727
|
+
let body;
|
|
34728
|
+
if (info.status === "AUTHENTICATED") {
|
|
34729
|
+
body = `<div class="empty">
|
|
34730
|
+
<div class="check">\u2713</div>
|
|
34731
|
+
<div>You're signed in to ${domainLabel}.</div>
|
|
34732
|
+
<div class="muted">This login is saved. You can close this tab.</div>
|
|
34733
|
+
</div>`;
|
|
34734
|
+
} else if (info.sessionOpen && info.liveViewUrl) {
|
|
34735
|
+
body = `<iframe class="stage" allow="clipboard-read; clipboard-write" src="${esc2(info.liveViewUrl)}"></iframe>
|
|
34736
|
+
<div class="footer">
|
|
34737
|
+
<span class="muted">Log into ${domainLabel} directly in the window above, then confirm below.</span>
|
|
34738
|
+
<span class="spacer"></span>
|
|
34739
|
+
<button class="btn" id="done">Done \u2014 I'm signed in</button>
|
|
34740
|
+
</div>`;
|
|
34741
|
+
} else {
|
|
34742
|
+
body = `<div class="empty">
|
|
34074
34743
|
<div>This sign-in link is no longer active.</div>
|
|
34075
34744
|
<div class="muted">Ask the assistant to reconnect the profile, then open the new link.</div>
|
|
34076
34745
|
</div>`;
|
|
34746
|
+
}
|
|
34077
34747
|
return `<!DOCTYPE html>
|
|
34078
34748
|
<html lang="en">
|
|
34079
34749
|
<head>
|
|
@@ -34089,9 +34759,11 @@ function renderAuthConsoleHtml(connectionId, hostedUrl) {
|
|
|
34089
34759
|
header .muted { color: #6b7689; font-size: 12px; }
|
|
34090
34760
|
.spacer { flex: 1; }
|
|
34091
34761
|
.stage { flex: 1; width: 100%; border: 0; display: block; background: #05070b; }
|
|
34092
|
-
.
|
|
34093
|
-
.btn { background: #2b6cff; color: #fff; border-radius: 7px; padding:
|
|
34762
|
+
.footer { display: flex; align-items: center; gap: 12px; padding: 10px 18px; border-top: 1px solid #1c2230; background: #0f131c; font-size: 13px; color: #8893a7; }
|
|
34763
|
+
.btn { background: #2b6cff; color: #fff; border: 0; border-radius: 7px; padding: 8px 14px; text-decoration: none; font-weight: 500; font: inherit; cursor: pointer; }
|
|
34764
|
+
.btn:disabled { opacity: .6; cursor: default; }
|
|
34094
34765
|
.empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; color: #8893a7; }
|
|
34766
|
+
.check { font-size: 32px; color: #36d399; }
|
|
34095
34767
|
.muted { color: #6b7689; font-size: 12px; }
|
|
34096
34768
|
</style>
|
|
34097
34769
|
${ATTRIBUTION_PIXEL_SCRIPT}
|
|
@@ -34101,9 +34773,23 @@ ${ATTRIBUTION_PIXEL_SCRIPT}
|
|
|
34101
34773
|
<h1>MCP Scraper</h1>
|
|
34102
34774
|
<span class="muted">Secure sign-in \xB7 ${safeId}</span>
|
|
34103
34775
|
<span class="spacer"></span>
|
|
34104
|
-
<span class="muted">
|
|
34776
|
+
<span class="muted">Log in directly to the real site above \u2014 your session is saved to your profile.</span>
|
|
34105
34777
|
</header>
|
|
34106
34778
|
${body}
|
|
34779
|
+
<script>
|
|
34780
|
+
(function(){
|
|
34781
|
+
var doneBtn = document.getElementById('done');
|
|
34782
|
+
if (!doneBtn) return;
|
|
34783
|
+
doneBtn.onclick = function() {
|
|
34784
|
+
doneBtn.disabled = true;
|
|
34785
|
+
doneBtn.textContent = 'Saving\u2026';
|
|
34786
|
+
fetch('/console/auth/${encodeURIComponent(connectionId)}/complete', { method: 'POST' })
|
|
34787
|
+
.then(function(r){ return r.json().catch(function(){ return {}; }); })
|
|
34788
|
+
.then(function(){ location.reload(); })
|
|
34789
|
+
.catch(function(){ doneBtn.disabled = false; doneBtn.textContent = "Done \u2014 I'm signed in"; });
|
|
34790
|
+
};
|
|
34791
|
+
})();
|
|
34792
|
+
</script>
|
|
34107
34793
|
</body>
|
|
34108
34794
|
</html>`;
|
|
34109
34795
|
}
|
|
@@ -34366,8 +35052,9 @@ var init_stripe_routes = __esm({
|
|
|
34366
35052
|
const user2 = await resolveUser(sub.customer, sub.customer_email);
|
|
34367
35053
|
if (user2) {
|
|
34368
35054
|
const live = sub.status === "active" || sub.status === "trialing";
|
|
34369
|
-
|
|
34370
|
-
await
|
|
35055
|
+
const newMemoryPlan = live ? mem.plan : "free";
|
|
35056
|
+
await setMemoryPlan(user2.id, newMemoryPlan, live ? sub.id : null);
|
|
35057
|
+
await syncMemoryKeyPlan(user2, resolveEffectiveMemoryPlan({ ...user2, memory_plan: newMemoryPlan }));
|
|
34371
35058
|
}
|
|
34372
35059
|
return c.json({ received: true });
|
|
34373
35060
|
}
|
|
@@ -34385,7 +35072,9 @@ var init_stripe_routes = __esm({
|
|
|
34385
35072
|
if (priceId && priceId in SUBSCRIPTION_TIERS) {
|
|
34386
35073
|
const tier = SUBSCRIPTION_TIERS[priceId];
|
|
34387
35074
|
const live = sub.status === "active" || sub.status === "trialing";
|
|
34388
|
-
|
|
35075
|
+
const newTier = live ? tier.tier : null;
|
|
35076
|
+
await setSubscriptionTier(user.id, newTier, live ? tier.concurrency : 0, live ? sub.id : null);
|
|
35077
|
+
await syncMemoryKeyPlan(user, resolveEffectiveMemoryPlan({ ...user, subscription_tier: newTier }));
|
|
34389
35078
|
} else if (priceId === CONCURRENCY_PRICE_ID && event.type === "customer.subscription.created") {
|
|
34390
35079
|
await setExtraConcurrencySlots(user.id, user.extra_concurrency_slots + 1);
|
|
34391
35080
|
await setConcurrencySubId(user.id, sub.id);
|
|
@@ -34398,7 +35087,7 @@ var init_stripe_routes = __esm({
|
|
|
34398
35087
|
const user2 = await resolveUserByMemorySubscription(sub.id) ?? await getUserByStripeCustomerId(sub.customer);
|
|
34399
35088
|
if (user2) {
|
|
34400
35089
|
await setMemoryPlan(user2.id, "free", null);
|
|
34401
|
-
await syncMemoryKeyPlan(user2, "free");
|
|
35090
|
+
await syncMemoryKeyPlan(user2, resolveEffectiveMemoryPlan({ ...user2, memory_plan: "free" }));
|
|
34402
35091
|
}
|
|
34403
35092
|
return c.json({ received: true });
|
|
34404
35093
|
}
|
|
@@ -34411,6 +35100,7 @@ var init_stripe_routes = __esm({
|
|
|
34411
35100
|
if (!user) return c.json({ received: true });
|
|
34412
35101
|
if (priceId && priceId in SUBSCRIPTION_TIERS) {
|
|
34413
35102
|
await setSubscriptionTier(user.id, null, 0, null);
|
|
35103
|
+
await syncMemoryKeyPlan(user, resolveEffectiveMemoryPlan({ ...user, subscription_tier: null }));
|
|
34414
35104
|
} else if (priceId === CONCURRENCY_PRICE_ID) {
|
|
34415
35105
|
await setExtraConcurrencySlots(user.id, Math.max(0, user.extra_concurrency_slots - 1));
|
|
34416
35106
|
await setConcurrencySubId(user.id, null);
|
|
@@ -37990,14 +38680,20 @@ var init_server = __esm({
|
|
|
37990
38680
|
const id = c.req.param("id");
|
|
37991
38681
|
await migrateBrowserAgent();
|
|
37992
38682
|
const row = await getAuthConnectionRow(id);
|
|
37993
|
-
|
|
38683
|
+
const sessionRow = row?.browser_agent_session_id ? await getSessionRow(row.browser_agent_session_id) : null;
|
|
38684
|
+
return c.html(renderAuthConsoleHtml(id, {
|
|
38685
|
+
domain: row?.domain ?? null,
|
|
38686
|
+
status: row?.status ?? null,
|
|
38687
|
+
liveViewUrl: sessionRow?.live_view_url ?? null,
|
|
38688
|
+
sessionOpen: sessionRow?.status === "open"
|
|
38689
|
+
}));
|
|
37994
38690
|
});
|
|
37995
|
-
app.
|
|
38691
|
+
app.post("/console/auth/:id/complete", async (c) => {
|
|
37996
38692
|
const id = c.req.param("id");
|
|
37997
38693
|
await migrateBrowserAgent();
|
|
37998
|
-
const
|
|
37999
|
-
if (!
|
|
38000
|
-
return c.
|
|
38694
|
+
const result = await completeAuthConnection(id);
|
|
38695
|
+
if (!result.ok) return c.json({ error: result.error }, 404);
|
|
38696
|
+
return c.json({ ok: true });
|
|
38001
38697
|
});
|
|
38002
38698
|
app.get("/console/:id", (c) => c.html(renderConsoleHtml(c.req.param("id"))));
|
|
38003
38699
|
app.route("/stripe", stripeApp);
|