mcp-scraper 0.34.1 → 0.36.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 (91) hide show
  1. package/README.md +10 -9
  2. package/dist/bin/api-server.cjs +24342 -17931
  3. package/dist/bin/api-server.cjs.map +1 -1
  4. package/dist/bin/api-server.js +3 -3
  5. package/dist/bin/mcp-scraper-cli.cjs +51 -7
  6. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  7. package/dist/bin/mcp-scraper-cli.js +48 -5
  8. package/dist/bin/mcp-scraper-cli.js.map +1 -1
  9. package/dist/bin/mcp-scraper-install.cjs +2 -2
  10. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  11. package/dist/bin/mcp-scraper-install.js +2 -2
  12. package/dist/bin/mcp-stdio-server.cjs +2997 -2070
  13. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  14. package/dist/bin/mcp-stdio-server.js +8 -8
  15. package/dist/bin/paa-harvest.cjs +125 -70
  16. package/dist/bin/paa-harvest.cjs.map +1 -1
  17. package/dist/bin/paa-harvest.js +4 -4
  18. package/dist/chunk-345BQXZH.js +712 -0
  19. package/dist/chunk-345BQXZH.js.map +1 -0
  20. package/dist/{chunk-M2S27J6Z.js → chunk-44HZLHDV.js} +10 -1
  21. package/dist/chunk-44HZLHDV.js.map +1 -0
  22. package/dist/chunk-4HO66323.js +7 -0
  23. package/dist/chunk-4HO66323.js.map +1 -0
  24. package/dist/{chunk-BWXLTWF7.js → chunk-4ZIJ3BKZ.js} +6 -4
  25. package/dist/chunk-4ZIJ3BKZ.js.map +1 -0
  26. package/dist/{chunk-6OPHG76G.js → chunk-5RULXBJ7.js} +3166 -2322
  27. package/dist/chunk-5RULXBJ7.js.map +1 -0
  28. package/dist/chunk-AN3VQARU.js +684 -0
  29. package/dist/chunk-AN3VQARU.js.map +1 -0
  30. package/dist/{chunk-XVVNKASZ.js → chunk-ANCGXUQJ.js} +118 -73
  31. package/dist/chunk-ANCGXUQJ.js.map +1 -0
  32. package/dist/{chunk-3HBPKR5G.js → chunk-D7LM5QZN.js} +3 -3
  33. package/dist/{chunk-4ZB3X6BQ.js → chunk-E5UEELA7.js} +16 -2
  34. package/dist/{chunk-4ZB3X6BQ.js.map → chunk-E5UEELA7.js.map} +1 -1
  35. package/dist/{chunk-ZID3WQID.js → chunk-FQI5PFE7.js} +9 -71
  36. package/dist/chunk-FQI5PFE7.js.map +1 -0
  37. package/dist/chunk-G3P3ZDB4.js +69 -0
  38. package/dist/chunk-G3P3ZDB4.js.map +1 -0
  39. package/dist/{chunk-7AYRWAEK.js → chunk-G7KAVJ3F.js} +2 -2
  40. package/dist/{chunk-7AYRWAEK.js.map → chunk-G7KAVJ3F.js.map} +1 -1
  41. package/dist/{chunk-62DQAWPF.js → chunk-IFYER7O4.js} +367 -42
  42. package/dist/chunk-IFYER7O4.js.map +1 -0
  43. package/dist/chunk-O2MCWFXQ.js +499 -0
  44. package/dist/chunk-O2MCWFXQ.js.map +1 -0
  45. package/dist/{chunk-JWIE5NCR.js → chunk-QZXKQB7Y.js} +140 -10
  46. package/dist/chunk-QZXKQB7Y.js.map +1 -0
  47. package/dist/{db-YAI5AQOI.js → db-N6MPVMEF.js} +8 -2
  48. package/dist/extract-bundle-M4SDJG3V.js +568 -0
  49. package/dist/extract-bundle-M4SDJG3V.js.map +1 -0
  50. package/dist/index.cjs +129 -70
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +11 -0
  53. package/dist/index.d.ts +11 -0
  54. package/dist/index.js +4 -4
  55. package/dist/location-data-repository-Z4NQOU5Y.js +35 -0
  56. package/dist/{server-IWDHTES2.js → server-ZIGAFKOL.js} +10844 -7480
  57. package/dist/server-ZIGAFKOL.js.map +1 -0
  58. package/dist/site-extract-repository-PGQZNW6V.js +62 -0
  59. package/dist/site-extract-repository-PGQZNW6V.js.map +1 -0
  60. package/dist/{worker-645BZPEK.js → worker-EBB6CTGW.js} +7 -7
  61. package/docs/hosted-location-data.md +108 -0
  62. package/docs/mcp-tool-craft-lint.generated.md +6 -3
  63. package/docs/mcp-tool-manifest.generated.json +2073 -551
  64. package/docs/mcp-tool-quality-spec.md +1 -1
  65. package/docs/specs/connected-services-control-plane-decoupling-spec.md +1044 -0
  66. package/docs/specs/kernel-stealth-captcha-test-matrix.md +278 -0
  67. package/docs/specs/multimodal-image-memory-architecture-spec.md +1022 -0
  68. package/docs/specs/query-fanout-transport-contract-fix.md +9 -1
  69. package/docs/specs/unified-credit-and-scheduled-execution-billing-spec.md +36 -27
  70. package/package.json +6 -5
  71. package/dist/chunk-5PZ6N2QM.js +0 -130
  72. package/dist/chunk-5PZ6N2QM.js.map +0 -1
  73. package/dist/chunk-62DQAWPF.js.map +0 -1
  74. package/dist/chunk-6OPHG76G.js.map +0 -1
  75. package/dist/chunk-7N2KYL4U.js +0 -7
  76. package/dist/chunk-7N2KYL4U.js.map +0 -1
  77. package/dist/chunk-BWXLTWF7.js.map +0 -1
  78. package/dist/chunk-JWIE5NCR.js.map +0 -1
  79. package/dist/chunk-M2S27J6Z.js.map +0 -1
  80. package/dist/chunk-R7EETU7Z.js +0 -419
  81. package/dist/chunk-R7EETU7Z.js.map +0 -1
  82. package/dist/chunk-XVVNKASZ.js.map +0 -1
  83. package/dist/chunk-ZID3WQID.js.map +0 -1
  84. package/dist/extract-bundle-GPZRLBVY.js +0 -331
  85. package/dist/extract-bundle-GPZRLBVY.js.map +0 -1
  86. package/dist/server-IWDHTES2.js.map +0 -1
  87. package/dist/site-extract-repository-OLVWMOU2.js +0 -30
  88. /package/dist/{chunk-3HBPKR5G.js.map → chunk-D7LM5QZN.js.map} +0 -0
  89. /package/dist/{db-YAI5AQOI.js.map → db-N6MPVMEF.js.map} +0 -0
  90. /package/dist/{site-extract-repository-OLVWMOU2.js.map → location-data-repository-Z4NQOU5Y.js.map} +0 -0
  91. /package/dist/{worker-645BZPEK.js.map → worker-EBB6CTGW.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  # Query fan-out transport contract fix
2
2
 
3
- - **Status:** Implemented; pending deployed live proof
3
+ - **Status:** Released and verified in production
4
4
  - **Baseline:** `origin/main` at `e2c90f8db7c22fa2aa48fc62cef10e2e0c799e15` (2026-07-25)
5
5
  - **Decision:** [Keep hosted fan-out results inline](../decisions/2026-07-25-hosted-fanout-results-stay-inline.md)
6
6
  - **Owner:** MCP Scraper browser-agent surface
@@ -32,6 +32,14 @@ Focused tests must prove hosted calls force upstream `export: false` and return
32
32
 
33
33
  Live release acceptance requires an explicitly authorized new web-search prompt: hosted OAuth with `export: true` must return a populated inline result with `exports: null`; stdio with the same option must additionally produce readable local exports.
34
34
 
35
+ ## Release evidence
36
+
37
+ - PR [#64](https://github.com/VilovietaSEO/mcp-scraper/pull/64) merged as `34a5eefa69b1fcaa2dec1dd645ac0dfc55cf4035`.
38
+ - npm, annotated tag, and GitHub/MCPB release published as `0.34.1` / `v0.34.1`.
39
+ - Vercel production deployment `dpl_CFCSkpAywT6PyqRe8LPDaKvicGrp` reached `READY` and serves `mcpscraper.dev`.
40
+ - Hosted Streamable HTTP with OAuth exposed 167 tools and returned a successful fan-out with 21 researched sources, complete inline data, `exports: null`, and no export error.
41
+ - The exact published npm `0.34.1` stdio package exposed 167 tools, returned a successful fan-out with 30 researched sources, and produced nine readable local export files with no export error.
42
+
35
43
  ## Out of scope
36
44
 
37
45
  Public/shared download URLs, capture-parser changes, profile authentication, billing, timeout changes, and recovery of fan-out from pre-capture prompts.
@@ -1,36 +1,39 @@
1
1
  # Unified Credits, Integrations, and Scheduled Execution Billing
2
2
 
3
- - Status: Released v1 contract plus explicitly deferred hardening roadmap
4
- - Spec date: 2026-07-14
3
+ - Status: Released scheduled-execution contract plus approved connected-account v2 contract
4
+ - Spec date: 2026-07-15
5
5
  - Primary repos: mcp-scraper, mcp-scraper-scheduler, mcpscraper-web, mcpscraper-sdk
6
6
  - Commercial decision: Scheduled Actions is a product capability, not a separate subscription
7
+ - Connected-account decision: each active Nango connection is a $3/month add-on; usage is metered in Credits
7
8
  - Accounting decision: MCP Scraper's main credit ledger is the only debit authority
8
9
 
9
10
  ## Executive decision
10
11
 
11
12
  MCP Scraper will use one visible usage currency: Credits.
12
13
 
13
- Scheduled Actions uses the same Credit wallet as the rest of MCP Scraper. It is no longer sold as a separate $10-per-month product with a 1,000-run quota. Integrations themselves are included with paid plans: connecting, reconnecting, direct reads, enabled actions, supported exports, and connection-to-Memory snapshots do not currently create a separate integration-operation debit.
14
+ Scheduled Actions uses the same Credit wallet as the rest of MCP Scraper. It is no longer sold as a separate $10-per-month product with a 1,000-run quota. Connected accounts are commercial add-ons: each active Nango connection costs $3 per month, and provider usage is settled from the shared Credit wallet using authoritative receipts.
14
15
 
15
16
  The replacement contract is:
16
17
 
17
- 1. Every paid MCP Scraper plan includes access to integrations and scheduling.
18
- 2. OAuth connect and reconnect cost 0 Credits and there is no per-connection subscription or active-connection minimum.
18
+ 1. Every paid MCP Scraper plan includes access to scheduling and the ability to add connected accounts.
19
+ 2. OAuth connect and reconnect cost 0 Credits. Each active Nango connection is a separate $3-per-month recurring add-on, prorated by the subscription system.
19
20
  3. Each scheduled occurrence that passes the balance check and begins execution costs 75 Credits exactly once.
20
21
  4. A deterministic `connection_sync` occurrence has no model charge beyond that 75-Credit base.
21
22
  5. An agent-mode occurrence additionally settles OpenRouter's actual reported model cost, multiplied by 1.5, then converted to Credits.
22
23
  6. Token prices may be shown as current per-million-token estimates in Credits, but OpenRouter's reported cost is the settlement truth.
23
24
  7. Separately metered scraper, browser, transcription, video-analysis, and similar tools keep their published rate-card prices when a schedule calls them.
24
- 8. The proposed 5/10/15/25-Credit connected-operation tariff, per-record/byte tariff, and 20,000-Credit active-connection minimum are deferred and are not enabled.
25
+ 8. Connected usage costs 2 Credits per Nango function run, 2 Credits per Nango Proxy request, and 5 Credits per compute second, prorated from aggregate milliseconds and rounded once up to integer mc.
26
+ 9. The older 5/10/15/25-Credit semantic read/write tariff, per-record/byte tariff, and 20,000-Credit active-connection minimum remain retired and are not enabled.
25
27
 
26
- This design encourages usage: paid users can immediately connect and use accounts without per-operation friction, while recurring automation and model work draw from the shared Credit balance. There is no artificial 1,000-run cliff or add-on product to understand.
28
+ This design separates the predictable credential-carrying cost from variable work. The $3 recurring line item pays for keeping a Nango connection active; function, Proxy, and compute activity draw from the shared Credit balance. There is no artificial 1,000-run cliff or separate scheduler product.
27
29
 
28
30
  ### Released v1 implementation boundary
29
31
 
30
32
  - Authorization currently performs an idempotent wallet balance check, not a hard balance reservation.
31
33
  - The server-side default maximum is 5,000 Credits per run and is environment-configurable; it is not yet editable in the customer UI.
32
34
  - A missing authoritative model cost moves the schedule to `cost_pending` and pauses it. Automated recovery/reconciliation is still a hardening item.
33
- - Connected-operation receipts, user-editable monthly caps, auto-refill, and active-connection minimums remain future work unless a later commercial decision explicitly enables them.
35
+ - The main API accepts idempotent connected-usage receipts and is the settlement authority. The scheduler must preflight at least the fixed 2-Credit function unit, and a prior `cost_pending` connected receipt blocks new work until recovered.
36
+ - User-editable monthly caps, auto-refill, hard reservations, and automated Nango-to-ledger reconciliation remain hardening work.
34
37
 
35
38
  ## What was found before the v1 cutover
36
39
 
@@ -66,25 +69,25 @@ Do not assume existing scheduled-agent charges equal a clean 1.5 markup. Before
66
69
 
67
70
  ## Canonical Build Spec
68
71
 
69
- - **Request:** Replace separate Scheduled Actions billing with the shared Credit wallet; charge one 75-Credit occurrence base and correctly settle all-step OpenRouter cost at 1.5; keep direct integration use included.
72
+ - **Request:** Keep Scheduled Actions on the shared Credit wallet; charge one 75-Credit occurrence base and correctly settle all-step OpenRouter cost at 1.5; add a $3 active-Nango-connection recurring line item plus receipt-based function, Proxy, and millisecond compute usage.
70
73
  - **Lane:** Mastra Agentic Development plus MCP/API product billing.
71
74
  - **Capability:** Unified Metered Execution.
72
75
  - **Audience:** MCP Scraper customers, scheduled-agent users, MCP clients, SDK users, operators, finance, and support.
73
- - **User-Facing Outcome:** A user connects a service, uses it directly without a separate operation fee, optionally moves a bounded result into Memory, and pays 75 Credits plus applicable model/tool usage when recurring work executes.
76
+ - **User-Facing Outcome:** A user pays $3/month for each active Nango account, sees connected usage itemized in Credits, optionally schedules work, and receives idempotent receipts without duplicate debits on retries.
74
77
  - **Target Runtime:** Main MCP Scraper API and credit ledger; Vercel-hosted Mastra scheduler; Inngest workers; Nango connections and Proxy/functions; private Blob artifacts; public MCP; npm/SDK clients.
75
78
  - **Inputs:** Authenticated identity, connection ID, tool or sync request, scheduled occurrence, model selection, per-run and monthly Credit limits, actual provider results, OpenRouter usage metadata, bytes and records delivered.
76
79
  - **Agents:** Existing Scheduled Action Agent for interpretive work. Deterministic connection_sync workers remain non-agentic. Both use the same billing context.
77
80
  - **Workflows:** Connect; direct read/write; bulk export; memory import; schedule estimate; occurrence claim; Credit authorization; execution; incremental settlement; final settlement; receipt; retry/reconciliation.
78
81
  - **Tools:** Existing generic connected-service tools, provider-native tools, schedule tools, bulk export/import tools, credits_info, a new schedule estimator, and a shared internal billing adapter.
79
82
  - **MCP:** Credit behavior is transport-independent. Tool descriptions state charge categories and estimates, results include receipt summaries, and exact provider tools remain protected by tenant ownership, action switches, and grants.
80
- - **Signals:** Billing authorization created; low balance; budget threshold; cost pending; settlement complete; and insufficient Credits. Auto-refill and connection-minimum signals belong only to the deferred roadmap.
83
+ - **Signals:** Billing authorization created; connected-use preflight; low balance; budget threshold; cost pending; settlement complete; and insufficient Credits.
81
84
  - **Background Tasks:** Usage aggregation, connection-minimum settlement, pending-cost reconciliation, low-balance notifications, automatic refill, legacy subscription migration, receipt retention, and rate-snapshot refresh.
82
85
  - **Guardrails:** Integer microcredit arithmetic, idempotent charges, one debit authority, no model-visible billing credentials, fail closed before externally costly work, action approval independent of price, no prompt or provider credential in billing events.
83
86
  - **Observability:** Itemized receipt per run; raw vendor cost; multiplier; model/provider; tokens; bytes; changed records; connection and schedule IDs; idempotency keys; authorization, settlement, and refund state.
84
87
  - **Enforcement:** A call cannot bypass the billing adapter by using Mastra, the generic MCP bridge, direct REST, SDK, Nango, or a background job. Duplicate occurrence or HTTP retry cannot debit twice.
85
88
  - **Persistence:** The main MCP Scraper/Turso credit ledger owns balances and debits. Scheduler Postgres owns schedule state, occurrence state, and a mirrored receipt reference, not the authoritative wallet.
86
89
  - **Deployment:** Main API/ledger first, then scheduler and connection adapters, then public MCP, frontend, SDK/npm/MCPB, generated docs, Stripe migration, and Vercel production.
87
- - **Done Contract:** A production scheduled run performs one balance authorization, charges its 75-Credit base once, aggregates every OpenRouter model step once, and exposes the same pricing contract through the UI, MCP, API, and SDK. Hard reservations and full receipt UX remain the next hardening phase.
90
+ - **Done Contract:** A production scheduled run charges its 75-Credit base once and aggregates every OpenRouter model step once. Every Nango call is preflighted, reports function/Proxy/compute usage under the active rate revision, and settles once in the main ledger. The UI, MCP, API, SDK, and recurring connection quantity publish the same contract.
88
91
  - **Receipt Requirements:** Code and deployment SHAs; rate-table revision; Stripe migration result; test output; production Vercel IDs; npm/MCPB versions; sample agent and deterministic-sync billing receipts; reconciliation report; public pricing and tool-description parity.
89
92
 
90
93
  ## Product contract in plain language
@@ -106,7 +109,7 @@ A scheduled occurrence pays:
106
109
  + any separately metered scraper, browser, transcription,
107
110
  video-analysis, or other published rate-card tools it calls
108
111
 
109
- Direct connected-service reads, enabled actions, supported exports, and bounded Memory snapshots do not add a separate integration-operation line item today.
112
+ Direct connected-service reads, enabled actions, supported exports, and bounded Memory snapshots report the Nango resources they actually consume: function runs, Proxy requests, and function compute milliseconds. The tool's semantic label does not change those infrastructure rates.
110
113
 
111
114
  Internal pagination, retries, leases, and orchestration steps are not separate “runs.” A retry of the same occurrence cannot pay the fixed charge again.
112
115
 
@@ -182,21 +185,26 @@ Released v1 rates:
182
185
  | Billing class | Charge |
183
186
  |---|---:|
184
187
  | OAuth connect, reconnect, or consent callback | Free |
185
- | Direct approved read | Included |
186
- | Direct enabled action | Included |
187
- | Supported connected-service export | Included |
188
- | Bounded connection-to-Memory snapshot | Included |
189
- | Active connection minimum | None |
188
+ | Active Nango connection | $3 per month, recurring and prorated |
189
+ | Nango function run | 2 Credits per run |
190
+ | Nango Proxy request | 2 Credits per request |
191
+ | Nango function compute | 5 Credits per second, prorated from aggregate milliseconds |
190
192
 
191
193
  Action safety remains independent of price: ownership, live inventory, source-controlled policy, the account action switch, and exact scheduled grants still apply.
192
194
 
195
+ The active rate revision is `2026-07-15.connected-usage-v1`. Compute settlement uses:
196
+
197
+ compute mc = ceil(computeMilliseconds * 500 mc / 1000)
198
+
199
+ The scheduler aggregates raw milliseconds for one receipt before applying that ceiling. It does not round each span or function up to a whole second. Function, Proxy, and compute line items are additive; the recurring $3 connection charge is not converted into Credits.
200
+
193
201
  ### Deferred connected-operation pricing options (not enabled)
194
202
 
195
203
  Earlier design work proposed 5/10/15/25-Credit read/write classes, a 25-Credit bulk base, per-record charges, and per-MiB charges. Those values are retained only as research for a later commercial decision. They are not present in the production registry and must not appear as current pricing in UI, MCP descriptions, SDKs, or support answers.
196
204
 
197
- ### Deferred active connection minimum (not enabled)
205
+ ### Retired active connection minimum proposal
198
206
 
199
- An earlier proposal described a 20,000-Credit minimum per active connection per 30-day billing period. The released product has no active-connection minimum, no first-connection waiver clock, and no connection billing-pause flow. Enabling any such minimum requires a new explicit commercial decision, customer notice, and a separate release.
207
+ An earlier proposal described a 20,000-Credit wallet minimum per active connection per 30-day billing period. It is superseded by the flat $3/month recurring add-on and must not be presented as current pricing.
200
208
 
201
209
  The remainder of this subsection records the deferred proposal for future evaluation only:
202
210
 
@@ -698,7 +706,7 @@ The deterministic worker:
698
706
  - claims the same occurrence key;
699
707
  - authorizes its budget;
700
708
  - charges the 75-Credit occurrence base once;
701
- - does not add record, byte, or connected-operation charges in released v1;
709
+ - settles observed Nango function runs, Proxy requests, and aggregate compute milliseconds under the active connected-usage rate revision;
702
710
  - checkpoints before settlement so retry behavior is deterministic.
703
711
 
704
712
  The worker never invokes a model merely to paginate or transfer content.
@@ -711,9 +719,9 @@ Remove the Scheduled Actions add-on card.
711
719
 
712
720
  Under every paid plan:
713
721
 
714
- > Integrations and scheduled work included. Usage draws from your shared Credit balance.
722
+ > Integration access and scheduled work included. Each active Nango account is $3/month; connected usage draws from your shared Credit balance.
715
723
 
716
- Show the 75-Credit scheduled occurrence, the “actual OpenRouter cost plus 50%” disclosure, and the fact that direct integration use is included. Do not show the deferred active-connection minimum or per-operation tariff as current pricing.
724
+ Show the 75-Credit scheduled occurrence, the “actual OpenRouter cost plus 50%” disclosure, the $3 active-account recurring fee, and the 2/2/5 connected-usage rates. Do not show the retired semantic read/write tariff or active-connection Credit minimum as current pricing.
717
725
 
718
726
  ### Integrations page
719
727
 
@@ -940,7 +948,7 @@ Receipts must be sanitized. Do not include prompts, connection tokens, API keys,
940
948
  - Separate scheduling entitlement or 1,000-run quota still enforced on any surface.
941
949
  - Frontend, hosted MCP, SDK/npm, MCPB, or public docs showing different rates.
942
950
  - A fixed token rate described as authoritative rather than an estimate.
943
- - Any connected-operation tariff or active-connection minimum exposed without a new approved commercial release.
951
+ - Any surface that omits or contradicts the approved $3 plus 2/2/5 connected-account contract.
944
952
  - Commercial migration without a reconciliation and compensating-credit policy.
945
953
 
946
954
  ## Decisions locked by this spec
@@ -951,7 +959,8 @@ Receipts must be sanitized. Do not include prompts, connection tokens, API keys,
951
959
  - scheduled_agent_llm uses a 1.5 multiplier.
952
960
  - Model token tables are estimates.
953
961
  - The fixed scheduled-occurrence charge is 75 Credits.
954
- - Direct integration use is included; the proposed 5/10/15/25 tariffs and 20,000-Credit active-connection minimum are not enabled.
962
+ - Active Nango connections cost $3/month; usage costs 2 Credits/function execution, 2 Credits/Proxy request, and 5 Credits/compute-second measured from milliseconds.
963
+ - The proposed 5/10/15/25 semantic tariffs and 20,000-Credit active-connection minimum are not enabled.
955
964
  - OAuth is free.
956
965
  - Main MCP Scraper owns the only mutable Credit ledger.
957
966
  - Every product and execution surface publishes the same price contract; shared itemized receipt UX remains hardening work.
@@ -959,8 +968,8 @@ Receipts must be sanitized. Do not include prompts, connection tokens, API keys,
959
968
 
960
969
  ## Decisions that may change only through a rate revision
961
970
 
962
- - Exact per-read, per-write, per-record, and per-MiB rates.
963
- - Connection-minimum amount and waiver duration.
971
+ - Exact semantic per-read, per-write, per-record, and per-MiB rates beyond the current Nango resource meter.
972
+ - Connected-account monthly price and function, Proxy, or compute rates.
964
973
  - Pay-as-you-go Credit grant per dollar.
965
974
  - Default per-run and monthly caps.
966
975
  - Existing non-scheduler AI multipliers.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-scraper",
3
- "version": "0.34.1",
3
+ "version": "0.36.0",
4
4
  "description": "MCP server for MCP Scraper web intelligence tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -35,7 +35,7 @@
35
35
  "build:og-pages": "node scripts/build-og-pages.mjs",
36
36
  "build:md": "node scripts/build-md-mirror.mjs",
37
37
  "build:mcpb": "npm run build && node scripts/build-mcpb.mjs",
38
- "build:rates": "tsx scripts/gen-rates.ts",
38
+ "build:rates": "node --import tsx scripts/gen-rates.ts",
39
39
  "build:ui": "npm run build:rates && esbuild public/app.jsx --bundle --loader:.jsx=jsx --outfile=public/app.js --target=es2020",
40
40
  "build:blog": "node scripts/run-ts-sandbox-safe.mjs scripts/build-blog.ts",
41
41
  "mcp:manifest": "node scripts/run-ts-sandbox-safe.mjs scripts/generate-mcp-tool-manifest.ts",
@@ -52,6 +52,8 @@
52
52
  "test:kernel": "vitest run tests/integration/kernel.smoke.test.ts",
53
53
  "sync:env": "bash scripts/push-env.sh",
54
54
  "sync:env:apply": "bash scripts/push-env.sh --apply",
55
+ "locations:publish-geonames": "node --import tsx scripts/publish-geonames-location-data.ts",
56
+ "locations:sync": "node --import tsx scripts/sync-hosted-location-data.ts",
55
57
  "integrations:migrate-scheduler": "node --import tsx scripts/migrate-scheduler-integrations.ts",
56
58
  "test:webhook": "node scripts/test-webhook.mjs",
57
59
  "test:e2e": "playwright test",
@@ -76,6 +78,7 @@
76
78
  "diff": "^9.0.0",
77
79
  "hono": "^4.12.18",
78
80
  "inngest": "^4.4.0",
81
+ "ipaddr.js": "^1.9.1",
79
82
  "jose": "^6.2.3",
80
83
  "mcpscraper-memory-tools": "^1.9.0",
81
84
  "p-limit": "^7.3.0",
@@ -91,9 +94,6 @@
91
94
  "youtube-transcript": "^1.3.1",
92
95
  "zod": "^3.23.0"
93
96
  },
94
- "optionalDependencies": {
95
- "@resvg/resvg-js-linux-arm64-gnu": "2.6.2"
96
- },
97
97
  "devDependencies": {
98
98
  "@onkernel/cli": "^0.19.2",
99
99
  "@playwright/test": "^1.60.0",
@@ -105,6 +105,7 @@
105
105
  "better-sqlite3": "^12.9.0",
106
106
  "bgutils-js": "^3.2.0",
107
107
  "dotenv": "^17.4.2",
108
+ "fflate": "^0.7.4",
108
109
  "jsdom": "^29.1.1",
109
110
  "tsup": "^8.0.0",
110
111
  "tsx": "^4.0.0",
@@ -1,130 +0,0 @@
1
- import {
2
- LedgerOperation
3
- } from "./chunk-BWXLTWF7.js";
4
- import {
5
- sanitizeVendorName
6
- } from "./chunk-M2S27J6Z.js";
7
- import {
8
- getDb
9
- } from "./chunk-62DQAWPF.js";
10
-
11
- // src/api/site-extract-repository.ts
12
- function rowToJob(r) {
13
- return {
14
- id: String(r.id),
15
- userId: r.user_id != null ? Number(r.user_id) : null,
16
- status: r.status != null ? String(r.status) : "pending",
17
- startUrl: String(r.start_url ?? ""),
18
- options: r.options ? JSON.parse(String(r.options)) : {},
19
- totalUrls: Number(r.total_urls ?? 0),
20
- doneUrls: Number(r.done_urls ?? 0),
21
- artifacts: r.artifacts ? JSON.parse(String(r.artifacts)) : null,
22
- error: r.error != null ? String(r.error) : null,
23
- billedMc: r.billed_mc != null ? Number(r.billed_mc) : null,
24
- createdAt: String(r.created_at ?? ""),
25
- updatedAt: String(r.updated_at ?? "")
26
- };
27
- }
28
- async function createExtractJob(jobId, userId, startUrl, options) {
29
- const db = getDb();
30
- await db.execute({
31
- sql: `INSERT INTO site_extract_jobs (id, user_id, status, start_url, options, created_at, updated_at)
32
- VALUES (?, ?, 'pending', ?, ?, datetime('now'), datetime('now'))`,
33
- args: [jobId, userId, startUrl, JSON.stringify(options)]
34
- });
35
- }
36
- async function getExtractJob(jobId) {
37
- const db = getDb();
38
- const res = await db.execute({ sql: `SELECT * FROM site_extract_jobs WHERE id = ?`, args: [jobId] });
39
- return res.rows[0] ? rowToJob(res.rows[0]) : null;
40
- }
41
- async function listExtractJobs(userId) {
42
- const db = getDb();
43
- const res = await db.execute({ sql: `SELECT * FROM site_extract_jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50`, args: [userId] });
44
- return res.rows.map((r) => rowToJob(r));
45
- }
46
- async function setExtractJobTotal(jobId, totalUrls) {
47
- const db = getDb();
48
- await db.execute({
49
- sql: `UPDATE site_extract_jobs SET status = 'running', total_urls = ?, updated_at = datetime('now') WHERE id = ?`,
50
- args: [totalUrls, jobId]
51
- });
52
- }
53
- async function saveExtractPages(jobId, pages) {
54
- if (pages.length === 0) return;
55
- const db = getDb();
56
- await db.batch(
57
- pages.map((p) => ({
58
- sql: `INSERT OR REPLACE INTO site_extract_pages (job_id, url, page) VALUES (?, ?, ?)`,
59
- args: [jobId, p.url, JSON.stringify({ ...p, bodyMarkdown: "", schema: [] })]
60
- }))
61
- );
62
- await db.execute({
63
- sql: `UPDATE site_extract_jobs
64
- SET done_urls = (SELECT COUNT(*) FROM site_extract_pages WHERE job_id = ?), updated_at = datetime('now')
65
- WHERE id = ?`,
66
- args: [jobId, jobId]
67
- });
68
- }
69
- async function getExtractedPages(jobId) {
70
- const db = getDb();
71
- const res = await db.execute({ sql: `SELECT page FROM site_extract_pages WHERE job_id = ?`, args: [jobId] });
72
- return res.rows.map((r) => JSON.parse(String(r.page)));
73
- }
74
- async function countSuccessfulPages(jobId) {
75
- const db = getDb();
76
- const res = await db.execute({
77
- sql: `SELECT COUNT(*) AS n FROM site_extract_pages
78
- WHERE job_id = ? AND json_extract(page, '$.status') = 200 AND json_extract(page, '$.wordCount') > 0`,
79
- args: [jobId]
80
- });
81
- return Number(res.rows[0]?.n ?? 0);
82
- }
83
- async function getExtractedUrls(jobId) {
84
- const db = getDb();
85
- const res = await db.execute({ sql: `SELECT url FROM site_extract_pages WHERE job_id = ?`, args: [jobId] });
86
- return new Set(res.rows.map((r) => String(r.url)));
87
- }
88
- async function completeExtractJob(jobId, artifacts) {
89
- const db = getDb();
90
- await db.execute({
91
- sql: `UPDATE site_extract_jobs SET status = 'complete', artifacts = ?, updated_at = datetime('now') WHERE id = ?`,
92
- args: [JSON.stringify(artifacts ?? []), jobId]
93
- });
94
- }
95
- async function failExtractJob(jobId, error) {
96
- const db = getDb();
97
- await db.execute({
98
- sql: `UPDATE site_extract_jobs SET status = 'failed', error = ?, updated_at = datetime('now') WHERE id = ?`,
99
- args: [sanitizeVendorName(error).slice(0, 2e3), jobId]
100
- });
101
- }
102
- async function settleExtractJob(jobId, userId, refundMc, netChargeMc, reference) {
103
- const db = getDb();
104
- const job = await getExtractJob(jobId);
105
- if (!job || job.billedMc != null) return;
106
- if (refundMc <= 0) {
107
- await db.execute({ sql: `UPDATE site_extract_jobs SET billed_mc = ?, updated_at = datetime('now') WHERE id = ? AND billed_mc IS NULL`, args: [Math.max(0, netChargeMc), jobId] });
108
- return;
109
- }
110
- await db.batch([
111
- { sql: "UPDATE users SET balance_mc = balance_mc + ? WHERE id = ?", args: [refundMc, userId] },
112
- { sql: "INSERT INTO ledger (user_id, amount_mc, operation, description) VALUES (?, ?, ?, ?)", args: [userId, refundMc, LedgerOperation.EXTRACT_SITE_REFUND, reference] },
113
- { sql: `UPDATE site_extract_jobs SET billed_mc = ?, updated_at = datetime('now') WHERE id = ? AND billed_mc IS NULL`, args: [Math.max(0, netChargeMc), jobId] }
114
- ]);
115
- }
116
-
117
- export {
118
- createExtractJob,
119
- getExtractJob,
120
- listExtractJobs,
121
- setExtractJobTotal,
122
- saveExtractPages,
123
- getExtractedPages,
124
- countSuccessfulPages,
125
- getExtractedUrls,
126
- completeExtractJob,
127
- failExtractJob,
128
- settleExtractJob
129
- };
130
- //# sourceMappingURL=chunk-5PZ6N2QM.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/site-extract-repository.ts"],"sourcesContent":["import { getDb } from './db.js'\nimport { sanitizeVendorName } from '../errors.js'\nimport { LedgerOperation } from './rates.js'\nimport type { PageData } from './site-extractor.js'\n\nexport type ExtractJobStatus = 'pending' | 'running' | 'complete' | 'failed'\n\nexport interface ExtractJobRow {\n id: string\n userId: number | null\n status: ExtractJobStatus\n startUrl: string\n options: Record<string, unknown>\n totalUrls: number\n doneUrls: number\n artifacts: Array<{ key: string; url: string; bytes: number; contentType: string }> | null\n error: string | null\n billedMc: number | null\n createdAt: string\n updatedAt: string\n}\n\nfunction rowToJob(r: Record<string, unknown>): ExtractJobRow {\n return {\n id: String(r.id),\n userId: r.user_id != null ? Number(r.user_id) : null,\n status: (r.status != null ? String(r.status) : 'pending') as ExtractJobStatus,\n startUrl: String(r.start_url ?? ''),\n options: r.options ? JSON.parse(String(r.options)) : {},\n totalUrls: Number(r.total_urls ?? 0),\n doneUrls: Number(r.done_urls ?? 0),\n artifacts: r.artifacts ? JSON.parse(String(r.artifacts)) : null,\n error: r.error != null ? String(r.error) : null,\n billedMc: r.billed_mc != null ? Number(r.billed_mc) : null,\n createdAt: String(r.created_at ?? ''),\n updatedAt: String(r.updated_at ?? ''),\n }\n}\n\nexport async function createExtractJob(jobId: string, userId: number, startUrl: string, options: Record<string, unknown>): Promise<void> {\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO site_extract_jobs (id, user_id, status, start_url, options, created_at, updated_at)\n VALUES (?, ?, 'pending', ?, ?, datetime('now'), datetime('now'))`,\n args: [jobId, userId, startUrl, JSON.stringify(options)],\n })\n}\n\nexport async function getExtractJob(jobId: string): Promise<ExtractJobRow | null> {\n const db = getDb()\n const res = await db.execute({ sql: `SELECT * FROM site_extract_jobs WHERE id = ?`, args: [jobId] })\n return res.rows[0] ? rowToJob(res.rows[0] as unknown as Record<string, unknown>) : null\n}\n\nexport async function listExtractJobs(userId: number): Promise<ExtractJobRow[]> {\n const db = getDb()\n const res = await db.execute({ sql: `SELECT * FROM site_extract_jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50`, args: [userId] })\n return res.rows.map(r => rowToJob(r as unknown as Record<string, unknown>))\n}\n\nexport async function setExtractJobTotal(jobId: string, totalUrls: number): Promise<void> {\n const db = getDb()\n await db.execute({\n sql: `UPDATE site_extract_jobs SET status = 'running', total_urls = ?, updated_at = datetime('now') WHERE id = ?`,\n args: [totalUrls, jobId],\n })\n}\n\nexport async function saveExtractPages(jobId: string, pages: PageData[]): Promise<void> {\n if (pages.length === 0) return\n const db = getDb()\n await db.batch(\n pages.map(p => ({\n sql: `INSERT OR REPLACE INTO site_extract_pages (job_id, url, page) VALUES (?, ?, ?)`,\n args: [jobId, p.url, JSON.stringify({ ...p, bodyMarkdown: '', schema: [] })],\n })),\n )\n await db.execute({\n sql: `UPDATE site_extract_jobs\n SET done_urls = (SELECT COUNT(*) FROM site_extract_pages WHERE job_id = ?), updated_at = datetime('now')\n WHERE id = ?`,\n args: [jobId, jobId],\n })\n}\n\nexport async function getExtractedPages(jobId: string): Promise<PageData[]> {\n const db = getDb()\n const res = await db.execute({ sql: `SELECT page FROM site_extract_pages WHERE job_id = ?`, args: [jobId] })\n return res.rows.map(r => JSON.parse(String((r as unknown as Record<string, unknown>).page)) as PageData)\n}\n\nexport async function countSuccessfulPages(jobId: string): Promise<number> {\n const db = getDb()\n const res = await db.execute({\n sql: `SELECT COUNT(*) AS n FROM site_extract_pages\n WHERE job_id = ? AND json_extract(page, '$.status') = 200 AND json_extract(page, '$.wordCount') > 0`,\n args: [jobId],\n })\n return Number((res.rows[0] as unknown as Record<string, unknown>)?.n ?? 0)\n}\n\nexport async function getExtractedUrls(jobId: string): Promise<Set<string>> {\n const db = getDb()\n const res = await db.execute({ sql: `SELECT url FROM site_extract_pages WHERE job_id = ?`, args: [jobId] })\n return new Set(res.rows.map(r => String((r as unknown as Record<string, unknown>).url)))\n}\n\nexport async function completeExtractJob(jobId: string, artifacts: ExtractJobRow['artifacts']): Promise<void> {\n const db = getDb()\n await db.execute({\n sql: `UPDATE site_extract_jobs SET status = 'complete', artifacts = ?, updated_at = datetime('now') WHERE id = ?`,\n args: [JSON.stringify(artifacts ?? []), jobId],\n })\n}\n\nexport async function failExtractJob(jobId: string, error: string): Promise<void> {\n const db = getDb()\n await db.execute({\n sql: `UPDATE site_extract_jobs SET status = 'failed', error = ?, updated_at = datetime('now') WHERE id = ?`,\n args: [sanitizeVendorName(error).slice(0, 2000), jobId],\n })\n}\n\nexport async function settleExtractJob(jobId: string, userId: number, refundMc: number, netChargeMc: number, reference: string): Promise<void> {\n const db = getDb()\n const job = await getExtractJob(jobId)\n if (!job || job.billedMc != null) return\n if (refundMc <= 0) {\n await db.execute({ sql: `UPDATE site_extract_jobs SET billed_mc = ?, updated_at = datetime('now') WHERE id = ? AND billed_mc IS NULL`, args: [Math.max(0, netChargeMc), jobId] })\n return\n }\n await db.batch([\n { sql: 'UPDATE users SET balance_mc = balance_mc + ? WHERE id = ?', args: [refundMc, userId] },\n { sql: 'INSERT INTO ledger (user_id, amount_mc, operation, description) VALUES (?, ?, ?, ?)', args: [userId, refundMc, LedgerOperation.EXTRACT_SITE_REFUND, reference] },\n { sql: `UPDATE site_extract_jobs SET billed_mc = ?, updated_at = datetime('now') WHERE id = ? AND billed_mc IS NULL`, args: [Math.max(0, netChargeMc), jobId] },\n ])\n}\n"],"mappings":"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","names":[]}