mcp-scraper 0.4.4 → 0.4.5
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 +265 -35
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +109 -3
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/chunk-UGQC2FOX.js +7 -0
- package/dist/chunk-UGQC2FOX.js.map +1 -0
- package/dist/{chunk-Z34NGK64.js → chunk-WI4A3KFQ.js} +110 -4
- package/dist/chunk-WI4A3KFQ.js.map +1 -0
- package/dist/{server-IKT3QVFB.js → server-XCDFHHLE.js} +149 -25
- package/dist/{server-IKT3QVFB.js.map → server-XCDFHHLE.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-TZRPP45I.js +0 -7
- package/dist/chunk-TZRPP45I.js.map +0 -1
- package/dist/chunk-Z34NGK64.js.map +0 -1
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
registerSerpIntelligenceCaptureTools,
|
|
32
32
|
sanitizeAttempts,
|
|
33
33
|
sanitizeHarvestResult
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-WI4A3KFQ.js";
|
|
35
35
|
import {
|
|
36
36
|
auditImages,
|
|
37
37
|
getBlobStore
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
RawMapsOverviewSchema,
|
|
66
66
|
RawMapsReviewStatsSchema
|
|
67
67
|
} from "./chunk-XGIPATLV.js";
|
|
68
|
-
import "./chunk-
|
|
68
|
+
import "./chunk-UGQC2FOX.js";
|
|
69
69
|
import {
|
|
70
70
|
completeExtractJob,
|
|
71
71
|
countSuccessfulPages,
|
|
@@ -11935,23 +11935,8 @@ async function provisionMemoryForUser(user) {
|
|
|
11935
11935
|
} catch {
|
|
11936
11936
|
}
|
|
11937
11937
|
}
|
|
11938
|
-
function memoryPlanForUser(user) {
|
|
11939
|
-
switch (user.subscription_tier) {
|
|
11940
|
-
case "starter":
|
|
11941
|
-
return "pro";
|
|
11942
|
-
case "growth":
|
|
11943
|
-
return "team";
|
|
11944
|
-
case "scale":
|
|
11945
|
-
return "enterprise";
|
|
11946
|
-
default:
|
|
11947
|
-
return "free";
|
|
11948
|
-
}
|
|
11949
|
-
}
|
|
11950
|
-
var MEMORY_PLAN_RANK = { free: 0, pro: 1, team: 2, enterprise: 3 };
|
|
11951
11938
|
function resolveEffectiveMemoryPlan(user) {
|
|
11952
|
-
|
|
11953
|
-
const memoryProPlan = user.memory_plan === "pro" || user.memory_plan === "team" ? user.memory_plan : "free";
|
|
11954
|
-
return MEMORY_PLAN_RANK[tierPlan] >= MEMORY_PLAN_RANK[memoryProPlan] ? tierPlan : memoryProPlan;
|
|
11939
|
+
return user.memory_plan === "pro" || user.memory_plan === "team" ? user.memory_plan : "free";
|
|
11955
11940
|
}
|
|
11956
11941
|
async function getOrCreateUserMemoryKey(user) {
|
|
11957
11942
|
const creds = await getUserMemoryCreds(user.id);
|
|
@@ -15958,6 +15943,7 @@ mcpApp.all("/", async (c) => {
|
|
|
15958
15943
|
});
|
|
15959
15944
|
|
|
15960
15945
|
// src/api/browser-agent-routes.ts
|
|
15946
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
15961
15947
|
import { Hono as Hono17 } from "hono";
|
|
15962
15948
|
|
|
15963
15949
|
// src/api/browser-agent-db.ts
|
|
@@ -16046,8 +16032,58 @@ async function migrateBrowserAgent() {
|
|
|
16046
16032
|
} catch {
|
|
16047
16033
|
}
|
|
16048
16034
|
await db.execute(`CREATE INDEX IF NOT EXISTS browser_auth_connections_profile ON browser_auth_connections(profile)`);
|
|
16035
|
+
await db.execute(`
|
|
16036
|
+
CREATE TABLE IF NOT EXISTS browser_agent_extensions (
|
|
16037
|
+
id TEXT PRIMARY KEY,
|
|
16038
|
+
user_id INTEGER NOT NULL,
|
|
16039
|
+
name TEXT NOT NULL,
|
|
16040
|
+
backend_id TEXT NOT NULL,
|
|
16041
|
+
backend_name TEXT NOT NULL,
|
|
16042
|
+
source TEXT NOT NULL DEFAULT 'store',
|
|
16043
|
+
source_url TEXT,
|
|
16044
|
+
size_bytes INTEGER,
|
|
16045
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
16046
|
+
)
|
|
16047
|
+
`);
|
|
16048
|
+
await db.execute(`CREATE UNIQUE INDEX IF NOT EXISTS browser_agent_extensions_user_name ON browser_agent_extensions(user_id, name)`);
|
|
16049
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS browser_agent_extensions_user ON browser_agent_extensions(user_id)`);
|
|
16049
16050
|
_ready = true;
|
|
16050
16051
|
}
|
|
16052
|
+
async function createExtensionRow(input) {
|
|
16053
|
+
const db = getDb();
|
|
16054
|
+
const id = `bext_${randomUUID2().replace(/-/g, "").slice(0, 20)}`;
|
|
16055
|
+
await db.execute({
|
|
16056
|
+
sql: `INSERT INTO browser_agent_extensions (id, user_id, name, backend_id, backend_name, source, source_url, size_bytes)
|
|
16057
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
16058
|
+
args: [id, input.userId, input.name, input.backendId, input.backendName, input.source, input.sourceUrl, input.sizeBytes]
|
|
16059
|
+
});
|
|
16060
|
+
const row = await getExtensionRow(input.userId, input.name);
|
|
16061
|
+
if (!row) throw new Error("extension insert failed");
|
|
16062
|
+
return row;
|
|
16063
|
+
}
|
|
16064
|
+
async function getExtensionRow(userId, name) {
|
|
16065
|
+
const db = getDb();
|
|
16066
|
+
const res = await db.execute({
|
|
16067
|
+
sql: `SELECT * FROM browser_agent_extensions WHERE user_id = ? AND name = ?`,
|
|
16068
|
+
args: [userId, name]
|
|
16069
|
+
});
|
|
16070
|
+
return res.rows[0] ?? null;
|
|
16071
|
+
}
|
|
16072
|
+
async function listExtensionRows(userId) {
|
|
16073
|
+
const db = getDb();
|
|
16074
|
+
const res = await db.execute({
|
|
16075
|
+
sql: `SELECT * FROM browser_agent_extensions WHERE user_id = ? ORDER BY created_at DESC`,
|
|
16076
|
+
args: [userId]
|
|
16077
|
+
});
|
|
16078
|
+
return res.rows;
|
|
16079
|
+
}
|
|
16080
|
+
async function deleteExtensionRow(userId, name) {
|
|
16081
|
+
const db = getDb();
|
|
16082
|
+
await db.execute({
|
|
16083
|
+
sql: `DELETE FROM browser_agent_extensions WHERE user_id = ? AND name = ?`,
|
|
16084
|
+
args: [userId, name]
|
|
16085
|
+
});
|
|
16086
|
+
}
|
|
16051
16087
|
async function createAuthConnectionRow(input) {
|
|
16052
16088
|
const db = getDb();
|
|
16053
16089
|
const connectionId = `authc_${randomUUID2().replace(/-/g, "").slice(0, 20)}`;
|
|
@@ -16904,6 +16940,28 @@ function isProfileConflict(err) {
|
|
|
16904
16940
|
const message = err instanceof Error ? err.message : String(err);
|
|
16905
16941
|
return /\b409\b|conflict|already exists/i.test(message);
|
|
16906
16942
|
}
|
|
16943
|
+
function isNotFound(err) {
|
|
16944
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16945
|
+
return /\b404\b|not found/i.test(message);
|
|
16946
|
+
}
|
|
16947
|
+
async function importExtensionFromStore(storeUrl, backendName) {
|
|
16948
|
+
const k = client();
|
|
16949
|
+
const archive = await k.extensions.downloadFromChromeStore({ url: storeUrl });
|
|
16950
|
+
const uploaded = await k.extensions.upload({ file: archive, name: backendName });
|
|
16951
|
+
return {
|
|
16952
|
+
backendId: uploaded.id,
|
|
16953
|
+
backendName: uploaded.name ?? backendName,
|
|
16954
|
+
sizeBytes: typeof uploaded.size_bytes === "number" ? uploaded.size_bytes : null
|
|
16955
|
+
};
|
|
16956
|
+
}
|
|
16957
|
+
async function deleteExtensionBackend(backendName) {
|
|
16958
|
+
const k = client();
|
|
16959
|
+
try {
|
|
16960
|
+
await k.extensions.delete(backendName);
|
|
16961
|
+
} catch (err) {
|
|
16962
|
+
if (!isNotFound(err)) throw err;
|
|
16963
|
+
}
|
|
16964
|
+
}
|
|
16907
16965
|
async function ensureProfile(k, name) {
|
|
16908
16966
|
try {
|
|
16909
16967
|
await k.profiles.create({ name });
|
|
@@ -16922,6 +16980,7 @@ async function createSession(opts = {}) {
|
|
|
16922
16980
|
const resolvedSaveProfileChanges = opts.saveProfileChanges ?? browserServiceProfileSaveChanges();
|
|
16923
16981
|
const disableDefaultProxy = opts.disableDefaultProxy ?? !resolvedProxyId;
|
|
16924
16982
|
const startUrl = opts.startUrl?.trim();
|
|
16983
|
+
const extensionNames = (opts.extensionNames ?? []).map((name) => name.trim()).filter(Boolean);
|
|
16925
16984
|
if (resolvedProfileName && resolvedSaveProfileChanges === true) {
|
|
16926
16985
|
await ensureProfile(k, resolvedProfileName);
|
|
16927
16986
|
}
|
|
@@ -16935,7 +16994,8 @@ async function createSession(opts = {}) {
|
|
|
16935
16994
|
name: resolvedProfileName,
|
|
16936
16995
|
...typeof resolvedSaveProfileChanges === "boolean" ? { save_changes: resolvedSaveProfileChanges } : {}
|
|
16937
16996
|
}
|
|
16938
|
-
} : {}
|
|
16997
|
+
} : {},
|
|
16998
|
+
...extensionNames.length ? { extensions: extensionNames.map((name) => ({ name })) } : {}
|
|
16939
16999
|
};
|
|
16940
17000
|
const browser = await k.browsers.create(createPayload);
|
|
16941
17001
|
const runtimeSessionId = browser.session_id;
|
|
@@ -17323,6 +17383,16 @@ function parseAgentDate(value) {
|
|
|
17323
17383
|
const legacyParsed = Date.parse(`${value.replace(" ", "T")}Z`);
|
|
17324
17384
|
return Number.isFinite(legacyParsed) ? legacyParsed : null;
|
|
17325
17385
|
}
|
|
17386
|
+
var EXTENSION_NAME_RE = /^[\w .-]{1,64}$/;
|
|
17387
|
+
function publicExtension(row) {
|
|
17388
|
+
return {
|
|
17389
|
+
name: row.name,
|
|
17390
|
+
source: row.source,
|
|
17391
|
+
source_url: row.source_url,
|
|
17392
|
+
size_bytes: row.size_bytes,
|
|
17393
|
+
created_at: row.created_at
|
|
17394
|
+
};
|
|
17395
|
+
}
|
|
17326
17396
|
function replayClock(row) {
|
|
17327
17397
|
if (!row) return null;
|
|
17328
17398
|
const startedAtMs = parseAgentDate(row.started_at);
|
|
@@ -17469,6 +17539,15 @@ function buildBrowserAgentRoutes() {
|
|
|
17469
17539
|
const body = await c.req.json().catch(() => ({}));
|
|
17470
17540
|
const timeoutSeconds = typeof body.timeout_seconds === "number" ? body.timeout_seconds : void 0;
|
|
17471
17541
|
const startUrl = typeof body.url === "string" ? body.url : void 0;
|
|
17542
|
+
const extensionNames = Array.isArray(body.extension_names) ? body.extension_names.filter((v) => typeof v === "string") : void 0;
|
|
17543
|
+
let resolvedExtensionBackendNames;
|
|
17544
|
+
if (extensionNames && extensionNames.length) {
|
|
17545
|
+
const names = extensionNames;
|
|
17546
|
+
const rows = await Promise.all(names.map((name) => getExtensionRow(user.id, name)));
|
|
17547
|
+
const missing = names.filter((_, i) => !rows[i]);
|
|
17548
|
+
if (missing.length) return c.json({ error: `extension(s) not found: ${missing.join(", ")}` }, 400);
|
|
17549
|
+
resolvedExtensionBackendNames = rows.map((row) => row.backend_name);
|
|
17550
|
+
}
|
|
17472
17551
|
const gate = await acquireConcurrencyGate(user, "browser_agent_session", {
|
|
17473
17552
|
ttlSeconds: browserSessionLockTtlSeconds(timeoutSeconds),
|
|
17474
17553
|
metadata: { label: typeof body.label === "string" ? body.label : null }
|
|
@@ -17483,7 +17562,8 @@ function buildBrowserAgentRoutes() {
|
|
|
17483
17562
|
saveProfileChanges: typeof body.save_profile_changes === "boolean" ? body.save_profile_changes : void 0,
|
|
17484
17563
|
startUrl,
|
|
17485
17564
|
disableDefaultProxy: typeof body.disable_default_proxy === "boolean" ? body.disable_default_proxy : void 0,
|
|
17486
|
-
viewport: body.viewport && typeof body.viewport === "object" ? body.viewport : void 0
|
|
17565
|
+
viewport: body.viewport && typeof body.viewport === "object" ? body.viewport : void 0,
|
|
17566
|
+
extensionNames: resolvedExtensionBackendNames
|
|
17487
17567
|
});
|
|
17488
17568
|
runtimeSessionId = created.runtimeSessionId;
|
|
17489
17569
|
const row = await createSessionRow({
|
|
@@ -17786,6 +17866,52 @@ function buildBrowserAgentRoutes() {
|
|
|
17786
17866
|
}))
|
|
17787
17867
|
});
|
|
17788
17868
|
});
|
|
17869
|
+
app2.post("/extensions/import", async (c) => {
|
|
17870
|
+
const user = c.get("user");
|
|
17871
|
+
const body = await c.req.json().catch(() => ({}));
|
|
17872
|
+
const storeUrl = typeof body.store_url === "string" ? body.store_url.trim() : "";
|
|
17873
|
+
const name = typeof body.name === "string" ? body.name.trim() : "";
|
|
17874
|
+
if (!storeUrl) return c.json({ error: "store_url is required" }, 400);
|
|
17875
|
+
if (!name || !EXTENSION_NAME_RE.test(name)) {
|
|
17876
|
+
return c.json({ error: "name is required (1-64 characters: letters, numbers, spaces, dots, underscores, hyphens)" }, 400);
|
|
17877
|
+
}
|
|
17878
|
+
const existing = await getExtensionRow(user.id, name);
|
|
17879
|
+
if (existing) return c.json({ error: `an extension named "${name}" already exists \u2014 delete it first or pick another name` }, 409);
|
|
17880
|
+
const backendName = `u${user.id}_${randomUUID3().replace(/-/g, "")}`;
|
|
17881
|
+
try {
|
|
17882
|
+
const imported = await importExtensionFromStore(storeUrl, backendName);
|
|
17883
|
+
const row = await createExtensionRow({
|
|
17884
|
+
userId: user.id,
|
|
17885
|
+
name,
|
|
17886
|
+
backendId: imported.backendId,
|
|
17887
|
+
backendName: imported.backendName,
|
|
17888
|
+
source: "store",
|
|
17889
|
+
sourceUrl: storeUrl,
|
|
17890
|
+
sizeBytes: imported.sizeBytes
|
|
17891
|
+
});
|
|
17892
|
+
return c.json(publicExtension(row));
|
|
17893
|
+
} catch (err) {
|
|
17894
|
+
return c.json(failure(err), 502);
|
|
17895
|
+
}
|
|
17896
|
+
});
|
|
17897
|
+
app2.get("/extensions", async (c) => {
|
|
17898
|
+
const user = c.get("user");
|
|
17899
|
+
const rows = await listExtensionRows(user.id);
|
|
17900
|
+
return c.json({ extensions: rows.map(publicExtension) });
|
|
17901
|
+
});
|
|
17902
|
+
app2.delete("/extensions/:name", async (c) => {
|
|
17903
|
+
const user = c.get("user");
|
|
17904
|
+
const name = c.req.param("name");
|
|
17905
|
+
const row = await getExtensionRow(user.id, name);
|
|
17906
|
+
if (!row) return c.json({ error: "not found" }, 404);
|
|
17907
|
+
try {
|
|
17908
|
+
await deleteExtensionBackend(row.backend_name);
|
|
17909
|
+
} catch (err) {
|
|
17910
|
+
return c.json(failure(err), 502);
|
|
17911
|
+
}
|
|
17912
|
+
await deleteExtensionRow(user.id, name);
|
|
17913
|
+
return c.json({ ok: true });
|
|
17914
|
+
});
|
|
17789
17915
|
app2.get("/sessions/:id/replays/:replayId/download", async (c) => {
|
|
17790
17916
|
const user = c.get("user");
|
|
17791
17917
|
const row = await loadOpenSession(c.req.param("id"), user.id);
|
|
@@ -18141,7 +18267,6 @@ stripeApp.post("/webhooks", async (c) => {
|
|
|
18141
18267
|
const live = sub.status === "active" || sub.status === "trialing";
|
|
18142
18268
|
const newTier = live ? tier.tier : null;
|
|
18143
18269
|
await setSubscriptionTier(user.id, newTier, live ? tier.concurrency : 0, live ? sub.id : null);
|
|
18144
|
-
await syncMemoryKeyPlan(user, resolveEffectiveMemoryPlan({ ...user, subscription_tier: newTier }));
|
|
18145
18270
|
} else if (priceId === CONCURRENCY_PRICE_ID && event.type === "customer.subscription.created") {
|
|
18146
18271
|
await setExtraConcurrencySlots(user.id, user.extra_concurrency_slots + 1);
|
|
18147
18272
|
await setConcurrencySubId(user.id, sub.id);
|
|
@@ -18167,7 +18292,6 @@ stripeApp.post("/webhooks", async (c) => {
|
|
|
18167
18292
|
if (!user) return c.json({ received: true });
|
|
18168
18293
|
if (priceId && priceId in SUBSCRIPTION_TIERS) {
|
|
18169
18294
|
await setSubscriptionTier(user.id, null, 0, null);
|
|
18170
|
-
await syncMemoryKeyPlan(user, resolveEffectiveMemoryPlan({ ...user, subscription_tier: null }));
|
|
18171
18295
|
} else if (priceId === CONCURRENCY_PRICE_ID) {
|
|
18172
18296
|
await setExtraConcurrencySlots(user.id, Math.max(0, user.extra_concurrency_slots - 1));
|
|
18173
18297
|
await setConcurrencySubId(user.id, null);
|
|
@@ -18191,7 +18315,7 @@ async function resolveUser(customerId, emailFallback) {
|
|
|
18191
18315
|
// src/api/oauth-routes.ts
|
|
18192
18316
|
import { Hono as Hono19 } from "hono";
|
|
18193
18317
|
import { getCookie, setCookie } from "hono/cookie";
|
|
18194
|
-
import { createHash as createHash3, randomBytes as randomBytes2, randomUUID as
|
|
18318
|
+
import { createHash as createHash3, randomBytes as randomBytes2, randomUUID as randomUUID4 } from "crypto";
|
|
18195
18319
|
import { importPKCS8, exportJWK, SignJWT } from "jose";
|
|
18196
18320
|
var ISSUER = "https://mcpscraper.dev";
|
|
18197
18321
|
var RESOURCE = () => process.env.MCP_MEMORY_RESOURCE_URL ?? "https://memory.mcpscraper.dev/mcp";
|
|
@@ -18539,7 +18663,7 @@ function pkceMatches(verifier, challenge) {
|
|
|
18539
18663
|
}
|
|
18540
18664
|
async function mintAccessToken(identity, scope, plan, audience) {
|
|
18541
18665
|
const { privateKey, kid } = await getKeys();
|
|
18542
|
-
return new SignJWT({ scope, plan }).setProtectedHeader({ alg: "RS256", kid }).setIssuer(ISSUER).setSubject(identity).setAudience(audience).setIssuedAt().setJti(
|
|
18666
|
+
return new SignJWT({ scope, plan }).setProtectedHeader({ alg: "RS256", kid }).setIssuer(ISSUER).setSubject(identity).setAudience(audience).setIssuedAt().setJti(randomUUID4()).setExpirationTime(`${ACCESS_TTL_SECONDS}s`).sign(privateKey);
|
|
18543
18667
|
}
|
|
18544
18668
|
function tokenErrorResponse(c, error, description, status) {
|
|
18545
18669
|
return c.json({ error, error_description: description }, status);
|
|
@@ -21590,4 +21714,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
21590
21714
|
export {
|
|
21591
21715
|
app
|
|
21592
21716
|
};
|
|
21593
|
-
//# sourceMappingURL=server-
|
|
21717
|
+
//# sourceMappingURL=server-XCDFHHLE.js.map
|