mcp-scraper 0.3.18 → 0.3.20

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.
Files changed (33) hide show
  1. package/dist/bin/api-server.cjs +169 -18
  2. package/dist/bin/api-server.cjs.map +1 -1
  3. package/dist/bin/api-server.js +3 -3
  4. package/dist/bin/mcp-scraper-cli.cjs +1 -1
  5. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  6. package/dist/bin/mcp-scraper-cli.js +1 -1
  7. package/dist/bin/mcp-scraper-install.cjs +1 -1
  8. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  9. package/dist/bin/mcp-scraper-install.js +1 -1
  10. package/dist/bin/mcp-stdio-server.cjs +1 -1
  11. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  12. package/dist/bin/mcp-stdio-server.js +2 -2
  13. package/dist/{chunk-2XCNU22L.js → chunk-6N6USFMH.js} +2 -2
  14. package/dist/{chunk-5H22TOXQ.js → chunk-IORA5BFI.js} +107 -6
  15. package/dist/chunk-IORA5BFI.js.map +1 -0
  16. package/dist/chunk-XLHBBA3U.js +7 -0
  17. package/dist/chunk-XLHBBA3U.js.map +1 -0
  18. package/dist/{chunk-HDPWLYK7.js → chunk-YZAYOFJV.js} +4 -4
  19. package/dist/chunk-YZAYOFJV.js.map +1 -0
  20. package/dist/{db-P76GVIFN.js → db-ZWV4Y43C.js} +10 -2
  21. package/dist/{server-3M3XCVOT.js → server-NKZW2SEV.js} +64 -15
  22. package/dist/server-NKZW2SEV.js.map +1 -0
  23. package/dist/{worker-J6I5XP2F.js → worker-PR7GODIV.js} +3 -3
  24. package/docs/mcp-tool-manifest.generated.json +1 -1
  25. package/package.json +1 -1
  26. package/dist/chunk-5H22TOXQ.js.map +0 -1
  27. package/dist/chunk-C7ZNIXOA.js +0 -7
  28. package/dist/chunk-C7ZNIXOA.js.map +0 -1
  29. package/dist/chunk-HDPWLYK7.js.map +0 -1
  30. package/dist/server-3M3XCVOT.js.map +0 -1
  31. /package/dist/{chunk-2XCNU22L.js.map → chunk-6N6USFMH.js.map} +0 -0
  32. /package/dist/{db-P76GVIFN.js.map → db-ZWV4Y43C.js.map} +0 -0
  33. /package/dist/{worker-J6I5XP2F.js.map → worker-PR7GODIV.js.map} +0 -0
@@ -21,7 +21,7 @@ import {
21
21
  renderLinkReport,
22
22
  sanitizeAttempts,
23
23
  sanitizeHarvestResult
24
- } from "./chunk-2XCNU22L.js";
24
+ } from "./chunk-6N6USFMH.js";
25
25
  import {
26
26
  csvRecords,
27
27
  listWorkflowDefinitions,
@@ -33,7 +33,7 @@ import {
33
33
  workflowStepCount,
34
34
  workflowSupportsSteps
35
35
  } from "./chunk-H2R232HK.js";
36
- import "./chunk-C7ZNIXOA.js";
36
+ import "./chunk-XLHBBA3U.js";
37
37
  import {
38
38
  BALANCE_PACK_LABELS,
39
39
  BALANCE_PRICE_IDS,
@@ -52,7 +52,7 @@ import {
52
52
  harvestProblemResponse,
53
53
  insufficientBalanceResponse,
54
54
  serializeHarvestProblem
55
- } from "./chunk-HDPWLYK7.js";
55
+ } from "./chunk-YZAYOFJV.js";
56
56
  import {
57
57
  BrowserDriver,
58
58
  MapsSelectors,
@@ -101,6 +101,7 @@ import {
101
101
  deactivateUser,
102
102
  debitMc,
103
103
  deleteWorkflowSchedule,
104
+ expireOldLots,
104
105
  failJob,
105
106
  failWorkflowRunRecord,
106
107
  getDb,
@@ -140,7 +141,7 @@ import {
140
141
  setPassword,
141
142
  setStripeCustomerId,
142
143
  verifyPassword
143
- } from "./chunk-5H22TOXQ.js";
144
+ } from "./chunk-IORA5BFI.js";
144
145
 
145
146
  // src/blog/registry.ts
146
147
  var posts = [
@@ -9410,7 +9411,11 @@ screenshotApp.post("/", async (c) => {
9410
9411
  metadata: { url: targetUrl, device }
9411
9412
  });
9412
9413
  if (!gate.ok) return c.json(concurrencyLimitExceededResponse(gate), 429, { "Retry-After": String(gate.retryAfterSeconds) });
9414
+ let debited = false;
9413
9415
  try {
9416
+ const { ok, balance_mc } = await debitMc(user.id, MC_COSTS.page_scrape, LedgerOperation.EXTRACT_URL, targetUrl);
9417
+ if (!ok) return c.json(insufficientBalanceResponse(balance_mc, MC_COSTS.page_scrape), 402);
9418
+ debited = true;
9414
9419
  const buf = await captureScreenshot(targetUrl, browserServiceApiKey(), device);
9415
9420
  return new Response(new Uint8Array(buf), {
9416
9421
  status: 200,
@@ -9421,6 +9426,7 @@ screenshotApp.post("/", async (c) => {
9421
9426
  }
9422
9427
  });
9423
9428
  } catch (err) {
9429
+ if (debited) await creditMc(user.id, MC_COSTS.page_scrape, LedgerOperation.EXTRACT_URL, "failed screenshot refund");
9424
9430
  const msg = err instanceof Error ? err.message : String(err);
9425
9431
  return c.json({ error: msg }, 502);
9426
9432
  } finally {
@@ -14444,6 +14450,14 @@ async function listSessionRows(userId, includeClosed = false) {
14444
14450
  });
14445
14451
  return res.rows;
14446
14452
  }
14453
+ async function listIdleOpenSessionRows(idleSeconds) {
14454
+ const db = getDb();
14455
+ const res = await db.execute({
14456
+ sql: `SELECT * FROM browser_agent_sessions WHERE status = 'open' AND COALESCE(last_action_at, created_at) <= datetime('now', ?) ORDER BY created_at LIMIT 200`,
14457
+ args: [`-${Math.max(1, Math.round(idleSeconds))} seconds`]
14458
+ });
14459
+ return res.rows;
14460
+ }
14447
14461
  async function addActiveMs(id, deltaMs) {
14448
14462
  const db = getDb();
14449
14463
  await db.execute({
@@ -15632,16 +15646,42 @@ function browserSessionLockTtlSeconds(timeoutSeconds) {
15632
15646
  }
15633
15647
  return DEFAULT_BROWSER_SESSION_LOCK_TTL_SECONDS;
15634
15648
  }
15635
- async function charge(sessionId, userId, startedAtMs) {
15636
- const elapsedMs = Date.now() - startedAtMs;
15637
- const { active_ms, billed_mc } = await addActiveMs(sessionId, elapsedMs);
15638
- const owed = browserActiveCostMc(active_ms);
15639
- const delta = owed - billed_mc;
15649
+ async function charge(sessionId, userId, _startedAtMs) {
15650
+ const row = await getSessionRow(sessionId);
15651
+ if (!row) return;
15652
+ const createdMs = parseAgentDate(row.created_at);
15653
+ if (createdMs == null) return;
15654
+ const uptimeMs = Math.max(0, Date.now() - createdMs);
15655
+ const owed = browserActiveCostMc(uptimeMs);
15656
+ await addActiveMs(sessionId, 0);
15657
+ const delta = owed - Number(row.billed_mc ?? 0);
15640
15658
  if (delta > 0) {
15641
15659
  const res = await debitMc(userId, delta, LedgerOperation.BROWSER_SESSION, sessionId);
15642
15660
  if (res.ok) await setBilledMc(sessionId, owed);
15643
15661
  }
15644
15662
  }
15663
+ async function reapIdleBrowserSessions(idleSeconds = 120) {
15664
+ const rows = await listIdleOpenSessionRows(idleSeconds);
15665
+ let reaped = 0;
15666
+ for (const row of rows) {
15667
+ if (row.user_id != null) {
15668
+ try {
15669
+ await charge(row.id, row.user_id);
15670
+ } catch {
15671
+ }
15672
+ }
15673
+ try {
15674
+ await closeSession(row.runtime_session_id);
15675
+ } catch {
15676
+ }
15677
+ await markSessionClosed(row.id).catch(() => {
15678
+ });
15679
+ if (row.concurrency_lock_id) await releaseConcurrencyGate(row.concurrency_lock_id).catch(() => {
15680
+ });
15681
+ reaped++;
15682
+ }
15683
+ return { reaped };
15684
+ }
15645
15685
  function publicSession(row) {
15646
15686
  return {
15647
15687
  session_id: row.id,
@@ -15651,10 +15691,16 @@ function publicSession(row) {
15651
15691
  created_at: row.created_at,
15652
15692
  last_action_at: row.last_action_at,
15653
15693
  closed_at: row.closed_at,
15654
- active_seconds: Math.round((row.active_ms ?? 0) / 1e3),
15694
+ uptime_seconds: uptimeSeconds(row),
15655
15695
  credits_used: Math.round((row.billed_mc ?? 0) / 10) / 100
15656
15696
  };
15657
15697
  }
15698
+ function uptimeSeconds(row) {
15699
+ const createdMs = parseAgentDate(row.created_at);
15700
+ const endMs = row.closed_at ? parseAgentDate(row.closed_at) : Date.now();
15701
+ if (createdMs == null || endMs == null) return 0;
15702
+ return Math.max(0, Math.round((endMs - createdMs) / 1e3));
15703
+ }
15658
15704
  function failure(err) {
15659
15705
  const msg = err instanceof Error ? err.message : String(err);
15660
15706
  return { error: sanitizeVendorName(msg) };
@@ -15866,6 +15912,7 @@ function buildBrowserAgentRoutes() {
15866
15912
  const user = c.get("user");
15867
15913
  const row = await loadOpenSession(c.req.param("id"), user.id);
15868
15914
  if (!row) return c.json({ error: "not found" }, 404);
15915
+ await charge(row.id, user.id);
15869
15916
  try {
15870
15917
  await closeSession(row.runtime_session_id);
15871
15918
  } catch {
@@ -17530,14 +17577,16 @@ app.get("/cron/tick", async (c) => {
17530
17577
  if (!process.env.CRON_SECRET || secret2 !== `Bearer ${process.env.CRON_SECRET}`) {
17531
17578
  return c.json({ error: "Unauthorized" }, 401);
17532
17579
  }
17533
- const { drainQueue } = await import("./worker-J6I5XP2F.js");
17580
+ const { drainQueue } = await import("./worker-PR7GODIV.js");
17534
17581
  const budget = { maxJobs: 10, deadlineMs: Date.now() + 28e4 };
17535
17582
  const workflowDispatchResult = await dispatchDueWorkflowSchedules(`${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`);
17536
- const [results, sweepResult] = await Promise.all([
17583
+ const [results, sweepResult, reapResult, expiredResult] = await Promise.all([
17537
17584
  drainQueue(budget),
17538
- runMonthlyRefreshSweep()
17585
+ runMonthlyRefreshSweep(),
17586
+ reapIdleBrowserSessions(120).catch(() => ({ reaped: 0 })),
17587
+ expireOldLots().catch(() => ({ expired_lots: 0, expired_mc: 0 }))
17539
17588
  ]);
17540
- return c.json({ drained: results.length, results, sweepResult, workflowDispatch: workflowDispatchResult });
17589
+ return c.json({ drained: results.length, results, sweepResult, reaped: reapResult, expired: expiredResult, workflowDispatch: workflowDispatchResult });
17541
17590
  });
17542
17591
  app.on(["GET", "POST", "PUT"], "/api/inngest", serveInngest({ client: inngest, functions: [siteAuditFn, siteExtractFn] }));
17543
17592
  app.route("/api/internal/site-architecture-auditor", siteAuditApp);
@@ -17673,4 +17722,4 @@ app.get("/blog/:slug/", (c) => {
17673
17722
  export {
17674
17723
  app
17675
17724
  };
17676
- //# sourceMappingURL=server-3M3XCVOT.js.map
17725
+ //# sourceMappingURL=server-NKZW2SEV.js.map