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.
@@ -31,7 +31,7 @@ import {
31
31
  registerSerpIntelligenceCaptureTools,
32
32
  sanitizeAttempts,
33
33
  sanitizeHarvestResult
34
- } from "./chunk-Z34NGK64.js";
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-TZRPP45I.js";
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
- const tierPlan = memoryPlanForUser(user);
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 randomUUID3 } from "crypto";
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(randomUUID3()).setExpirationTime(`${ACCESS_TTL_SECONDS}s`).sign(privateKey);
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-IKT3QVFB.js.map
21717
+ //# sourceMappingURL=server-XCDFHHLE.js.map