mcp-scraper 0.76.0 → 0.78.0

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 (40) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/dist/{analytics-repository-AUTJK4HK.js → analytics-repository-D5LEGQG3.js} +3 -3
  4. package/dist/bin/api-server.js +4 -4
  5. package/dist/bin/mcp-scraper-cli.js +3 -3
  6. package/dist/bin/mcp-scraper-core.js +7 -7
  7. package/dist/bin/mcp-scraper-install.js +2 -2
  8. package/dist/bin/mcp-stdio-server.js +7 -7
  9. package/dist/bin/paa-harvest.js +4 -4
  10. package/dist/{chunk-BOGRXBH2.js → chunk-2P2ZVRPK.js} +189 -57
  11. package/dist/{chunk-E6Y3VCOJ.js → chunk-3PUMNEOC.js} +3 -3
  12. package/dist/{chunk-KIPIBPUB.js → chunk-47ZCUBM5.js} +1 -1
  13. package/dist/{chunk-IBQNOZ7E.js → chunk-74CCAY6T.js} +1 -1
  14. package/dist/{chunk-7RQULQF3.js → chunk-B6L73AO4.js} +1 -1
  15. package/dist/{chunk-WFQ2E4WE.js → chunk-BTQ23KCT.js} +1 -1
  16. package/dist/{chunk-SDX6TRJ6.js → chunk-FODYEDZK.js} +3 -3
  17. package/dist/{chunk-PJEEKOUM.js → chunk-FUMG43EN.js} +1 -1
  18. package/dist/{chunk-XSYEDC25.js → chunk-IYYRSVRQ.js} +1 -1
  19. package/dist/{chunk-A66DGFOU.js → chunk-KAGHJQFO.js} +1 -1
  20. package/dist/{chunk-CXY5WV45.js → chunk-NGLZ6UJR.js} +1 -1
  21. package/dist/{chunk-WEFPBAAG.js → chunk-OU4FV2RP.js} +140 -4
  22. package/dist/{chunk-F5TK4KMT.js → chunk-OUBH6XMY.js} +1 -1
  23. package/dist/{chunk-77LQV73B.js → chunk-OWF2JJKN.js} +13 -1
  24. package/dist/{chunk-F6MUGMRN.js → chunk-UFJJGXVO.js} +702 -165
  25. package/dist/{chunk-KBTUPRTF.js → chunk-VEQPA65D.js} +1 -1
  26. package/dist/{chunk-D2O7V2CT.js → chunk-VMWSXKUQ.js} +1 -1
  27. package/dist/{chunk-JNFOBQVH.js → chunk-ZUCU2A6V.js} +1 -1
  28. package/dist/{db-566MOHHD.js → db-TA567JLA.js} +17 -1
  29. package/dist/{extract-bundle-OO74L67T.js → extract-bundle-P2DTUVY3.js} +3 -3
  30. package/dist/{gmail-service-TIU4V5JA.js → gmail-service-HN57R2GS.js} +4 -4
  31. package/dist/index.cjs +714 -165
  32. package/dist/index.d.cts +83 -1
  33. package/dist/index.d.ts +83 -1
  34. package/dist/index.js +4 -4
  35. package/dist/{lead-list-enrichment-repository-WWEMJ7EN.js → lead-list-enrichment-repository-5LEWW4X7.js} +2 -2
  36. package/dist/{location-data-repository-H4B2BWGY.js → location-data-repository-AHKDXTEQ.js} +2 -2
  37. package/dist/{server-IAGYCPN6.js → server-6B2OG3NN.js} +1434 -983
  38. package/dist/{site-extract-repository-B47JB62U.js → site-extract-repository-XKSVXSSY.js} +2 -2
  39. package/dist/{worker-DR6R7J46.js → worker-2BYACLNF.js} +6 -6
  40. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  publicErrorMessage,
3
3
  sanitizeVendorName
4
- } from "./chunk-WEFPBAAG.js";
4
+ } from "./chunk-OU4FV2RP.js";
5
5
 
6
6
  // src/api/outbound-sanitize.ts
7
7
  var KEY_RENAMES = {
@@ -8,7 +8,7 @@ import {
8
8
  import {
9
9
  buildPublicErrorEnvelope,
10
10
  getDb
11
- } from "./chunk-WEFPBAAG.js";
11
+ } from "./chunk-OU4FV2RP.js";
12
12
 
13
13
  // src/lib/media-extractor.ts
14
14
  import { createWriteStream, mkdirSync, rmSync } from "fs";
@@ -12,13 +12,13 @@ import {
12
12
  registerScheduledResultsMcpTools,
13
13
  registerSerpIntelligenceCaptureTools,
14
14
  resolveDeploymentProfile
15
- } from "./chunk-BOGRXBH2.js";
15
+ } from "./chunk-2P2ZVRPK.js";
16
16
  import {
17
17
  renderInstallTerminal
18
- } from "./chunk-XSYEDC25.js";
18
+ } from "./chunk-IYYRSVRQ.js";
19
19
  import {
20
20
  PACKAGE_VERSION
21
- } from "./chunk-JNFOBQVH.js";
21
+ } from "./chunk-ZUCU2A6V.js";
22
22
 
23
23
  // src/mcp/stdio-runtime.ts
24
24
  import { readFileSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getDb,
3
3
  getUserByEmail
4
- } from "./chunk-WEFPBAAG.js";
4
+ } from "./chunk-OU4FV2RP.js";
5
5
 
6
6
  // src/api/session.ts
7
7
  import { createHmac, timingSafeEqual } from "crypto";
@@ -1,6 +1,6 @@
1
1
  // release-message.json
2
2
  var release_message_default = {
3
- message: "MCP Scraper now ships a fail-closed 34-tool restricted entrypoint for Thorbit while the normal package and Desktop extension remain full-surface."
3
+ message: "PAA harvests now distinguish a proven end of the question frontier from an interrupted browser, automatically resume the same durable job, and preserve captured questions, answers, AI Overview citations, and ranked SERP links."
4
4
  };
5
5
 
6
6
  // src/install-terminal.ts
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDb
3
- } from "./chunk-WEFPBAAG.js";
3
+ } from "./chunk-OU4FV2RP.js";
4
4
 
5
5
  // src/api/lead-list-enrichment-repository.ts
6
6
  import { createHash, randomUUID } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDb
3
- } from "./chunk-WEFPBAAG.js";
3
+ } from "./chunk-OU4FV2RP.js";
4
4
 
5
5
  // src/api/cost-context.ts
6
6
  import { AsyncLocalStorage } from "async_hooks";
@@ -367,6 +367,9 @@ var RequestAbortedError = class extends Error {
367
367
  super(message);
368
368
  }
369
369
  };
370
+ var PaaInteractionInterruptedError = class extends Error {
371
+ name = "PaaInteractionInterruptedError";
372
+ };
370
373
  var LocationMismatchError = class extends Error {
371
374
  name = "LocationMismatchError";
372
375
  constructor(message = "Google returned results for a different location than requested") {
@@ -2595,22 +2598,40 @@ async function claimPendingJob() {
2595
2598
  });
2596
2599
  return upd.rowsAffected === 0 ? void 0 : { ...job, status: "running" };
2597
2600
  }
2601
+ var DURABLE_PAA_LEASE_MS = 45e3;
2598
2602
  async function claimDurablePaaJob(id) {
2599
2603
  const db = getDb();
2600
2604
  const current = await getJob(id);
2601
2605
  if (!current || current.options.executionOwner !== "direct" || current.options.serpOnly === true) return void 0;
2606
+ const recoveryCount = Math.max(0, Number(current.options.paaRecoveryCount ?? 0));
2602
2607
  if (current.status === "running") return void 0;
2603
2608
  if (current.status === "pending") {
2609
+ const leaseToken = randomUUID();
2610
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2611
+ const leaseExpiresAt = new Date(Date.now() + DURABLE_PAA_LEASE_MS).toISOString();
2604
2612
  const updated = await db.execute({
2605
2613
  sql: `UPDATE jobs
2606
- SET status = 'running', started_at = COALESCE(started_at, datetime('now')), error = NULL
2614
+ SET status = 'running', started_at = datetime('now'), error = NULL,
2615
+ options = json_set(options,
2616
+ '$.paaLeaseToken', ?,
2617
+ '$.paaLeaseExpiresAt', ?,
2618
+ '$.paaLastDispatchAt', ?)
2607
2619
  WHERE id = ? AND status = 'pending'`,
2608
- args: [id]
2620
+ args: [leaseToken, leaseExpiresAt, now, id]
2609
2621
  });
2610
2622
  if (updated.rowsAffected === 0) return void 0;
2611
- return { ...current, status: "running", started_at: current.started_at ?? (/* @__PURE__ */ new Date()).toISOString() };
2623
+ return {
2624
+ job: {
2625
+ ...current,
2626
+ status: "running",
2627
+ started_at: now,
2628
+ options: { ...current.options, paaLeaseToken: leaseToken, paaLeaseExpiresAt: leaseExpiresAt, paaLastDispatchAt: now }
2629
+ },
2630
+ leaseToken,
2631
+ recoveryCount
2632
+ };
2612
2633
  }
2613
- return current;
2634
+ return { job: current, leaseToken: null, recoveryCount };
2614
2635
  }
2615
2636
  async function checkpointJob(id, result) {
2616
2637
  const updated = await getDb().execute({
@@ -2619,6 +2640,91 @@ async function checkpointJob(id, result) {
2619
2640
  });
2620
2641
  return updated.rowsAffected === 1;
2621
2642
  }
2643
+ async function checkpointDurablePaaJob(id, leaseToken, result) {
2644
+ const leaseExpiresAt = new Date(Date.now() + DURABLE_PAA_LEASE_MS).toISOString();
2645
+ const updated = await getDb().execute({
2646
+ sql: `UPDATE jobs SET result = ?, options = json_set(options, '$.paaLeaseExpiresAt', ?)
2647
+ WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,
2648
+ args: [JSON.stringify(result), leaseExpiresAt, id, leaseToken]
2649
+ });
2650
+ return updated.rowsAffected === 1;
2651
+ }
2652
+ async function renewDurablePaaLease(id, leaseToken) {
2653
+ const leaseExpiresAt = new Date(Date.now() + DURABLE_PAA_LEASE_MS).toISOString();
2654
+ const updated = await getDb().execute({
2655
+ sql: `UPDATE jobs SET options = json_set(options, '$.paaLeaseExpiresAt', ?)
2656
+ WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,
2657
+ args: [leaseExpiresAt, id, leaseToken]
2658
+ });
2659
+ return updated.rowsAffected === 1;
2660
+ }
2661
+ async function completeDurablePaaJob(id, leaseToken, result) {
2662
+ const updated = await getDb().execute({
2663
+ sql: `UPDATE jobs SET status = 'done', result = ?, error = NULL, public_error_json = NULL,
2664
+ completed_at = datetime('now'),
2665
+ options = json_set(options, '$.paaLeaseExpiresAt', NULL)
2666
+ WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,
2667
+ args: [JSON.stringify(result), id, leaseToken]
2668
+ });
2669
+ return updated.rowsAffected === 1;
2670
+ }
2671
+ async function failDurablePaaJob(id, leaseToken, error, publicError) {
2672
+ const updated = await getDb().execute({
2673
+ sql: `UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now'),
2674
+ options = json_set(options, '$.paaLeaseExpiresAt', NULL)
2675
+ WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,
2676
+ args: [error, serializePublicErrorEnvelope(publicError), id, leaseToken]
2677
+ });
2678
+ return updated.rowsAffected === 1;
2679
+ }
2680
+ async function requeueExpiredDurablePaaJob(id, maxRecoveries) {
2681
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2682
+ const updated = await getDb().execute({
2683
+ sql: `UPDATE jobs SET status = 'pending', started_at = NULL,
2684
+ result = CASE WHEN json_valid(result) THEN json_set(result,
2685
+ '$.progress.lifecycle.discoveryStatus', 'interrupted',
2686
+ '$.progress.lifecycle.completionReason', 'The previous worker lease expired; the same job is recovering automatically.',
2687
+ '$.progress.lifecycle.automaticRetries', COALESCE(json_extract(options, '$.paaRecoveryCount'), 0) + 1)
2688
+ ELSE result END,
2689
+ options = json_set(options,
2690
+ '$.paaRecoveryCount', COALESCE(json_extract(options, '$.paaRecoveryCount'), 0) + 1,
2691
+ '$.paaLeaseToken', NULL,
2692
+ '$.paaLeaseExpiresAt', NULL,
2693
+ '$.paaRecoveryQueuedAt', ?)
2694
+ WHERE id = ? AND status = 'running'
2695
+ AND (
2696
+ datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
2697
+ OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
2698
+ )
2699
+ AND COALESCE(json_extract(options, '$.paaRecoveryCount'), 0) < ?`,
2700
+ args: [now, id, Math.max(0, Math.trunc(maxRecoveries))]
2701
+ });
2702
+ return updated.rowsAffected === 1;
2703
+ }
2704
+ async function completeExpiredDurablePaaJob(id, result) {
2705
+ const updated = await getDb().execute({
2706
+ sql: `UPDATE jobs SET status = 'done', result = ?, error = NULL, public_error_json = NULL, completed_at = datetime('now')
2707
+ WHERE id = ? AND status = 'running'
2708
+ AND (
2709
+ datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
2710
+ OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
2711
+ )`,
2712
+ args: [JSON.stringify(result), id]
2713
+ });
2714
+ return updated.rowsAffected === 1;
2715
+ }
2716
+ async function failExpiredDurablePaaJob(id, error, publicError) {
2717
+ const updated = await getDb().execute({
2718
+ sql: `UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now')
2719
+ WHERE id = ? AND status = 'running'
2720
+ AND (
2721
+ datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
2722
+ OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
2723
+ )`,
2724
+ args: [error, serializePublicErrorEnvelope(publicError), id]
2725
+ });
2726
+ return updated.rowsAffected === 1;
2727
+ }
2622
2728
  async function listRecentTerminalDurablePaaJobs(limit = 25) {
2623
2729
  const safeLimit = Math.max(1, Math.min(100, Math.floor(limit)));
2624
2730
  const rows = await getDb().execute({
@@ -2646,6 +2752,27 @@ async function listStaleRunningDurablePaaJobs(limit = 25) {
2646
2752
  });
2647
2753
  return rows.rows.map((row) => deserialize(rowToRawJob(row)));
2648
2754
  }
2755
+ async function listRecoverableDurablePaaJobs(limit = 25) {
2756
+ const safeLimit = Math.max(1, Math.min(100, Math.floor(limit)));
2757
+ const rows = await getDb().execute({
2758
+ sql: `SELECT * FROM jobs
2759
+ WHERE json_extract(options, '$.executionOwner') = 'direct'
2760
+ AND json_extract(options, '$.serpOnly') IS NOT 1
2761
+ AND (
2762
+ (status = 'running' AND (
2763
+ datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
2764
+ OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
2765
+ ))
2766
+ OR
2767
+ (status = 'pending' AND COALESCE(json_extract(options, '$.paaRecoveryCount'), 0) > 0
2768
+ AND datetime(COALESCE(json_extract(options, '$.paaLastDispatchAt'), '1970-01-01')) <= datetime('now', '-30 seconds'))
2769
+ )
2770
+ ORDER BY COALESCE(started_at, created_at)
2771
+ LIMIT ?`,
2772
+ args: [safeLimit]
2773
+ });
2774
+ return rows.rows.map((row) => deserialize(rowToRawJob(row)));
2775
+ }
2649
2776
  async function markJobBillingSettled(id, billedMc, settledAt = (/* @__PURE__ */ new Date()).toISOString()) {
2650
2777
  if (!Number.isSafeInteger(billedMc) || billedMc < 0) throw new Error("job billed amount must be a non-negative integer");
2651
2778
  const updated = await getDb().execute({
@@ -3699,6 +3826,7 @@ export {
3699
3826
  ExtractionError,
3700
3827
  MapsSearchIncompletePageError,
3701
3828
  RequestAbortedError,
3829
+ PaaInteractionInterruptedError,
3702
3830
  LocationMismatchError,
3703
3831
  CREDIT_LOTS_EPOCH,
3704
3832
  CORE_SCHEMA_VERSION,
@@ -3777,8 +3905,16 @@ export {
3777
3905
  claimPendingJob,
3778
3906
  claimDurablePaaJob,
3779
3907
  checkpointJob,
3908
+ checkpointDurablePaaJob,
3909
+ renewDurablePaaLease,
3910
+ completeDurablePaaJob,
3911
+ failDurablePaaJob,
3912
+ requeueExpiredDurablePaaJob,
3913
+ completeExpiredDurablePaaJob,
3914
+ failExpiredDurablePaaJob,
3780
3915
  listRecentTerminalDurablePaaJobs,
3781
3916
  listStaleRunningDurablePaaJobs,
3917
+ listRecoverableDurablePaaJobs,
3782
3918
  markJobBillingSettled,
3783
3919
  completeJob,
3784
3920
  completeRunningJob,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-RJ7JVYKU.js";
4
4
  import {
5
5
  getDb
6
- } from "./chunk-WEFPBAAG.js";
6
+ } from "./chunk-OU4FV2RP.js";
7
7
 
8
8
  // src/api/location-data-repository.ts
9
9
  import { createHash, randomUUID } from "crypto";
@@ -90,11 +90,23 @@ var MapsSearchOptionsSchema = z.object({
90
90
  headless: z.boolean().default(true)
91
91
  });
92
92
  var RawPAAItemSchema = z.object({
93
+ questionId: z.string().min(1),
94
+ googleLinkId: z.string().nullable(),
95
+ googleEvidenceId: z.string().nullable(),
93
96
  question: z.string().min(1),
94
97
  answer: z.string().optional(),
95
98
  sourceTitle: z.string().optional(),
96
99
  sourceSite: z.string().optional(),
97
- sourceCite: z.string().optional()
100
+ sourceCite: z.string().optional(),
101
+ sources: z.array(z.object({
102
+ title: z.string().nullable(),
103
+ site: z.string().nullable(),
104
+ url: z.string().min(1),
105
+ rawUrl: z.string().min(1),
106
+ resolvedUrl: z.string().nullable(),
107
+ linkType: z.enum(["plain", "google_url_redirect", "google_goto_redirect"]),
108
+ resolutionStatus: z.enum(["not_needed", "resolved", "unresolved", "rejected"])
109
+ })).default([])
98
110
  });
99
111
  var RawMapsOverviewSchema = z.object({
100
112
  name: z.string().nullable(),