mcp-scraper 0.38.0 → 0.38.1
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/README.md +1 -1
- package/dist/bin/api-server.cjs +98 -65
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +3 -3
- 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 +1 -1
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +4 -4
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +3 -3
- package/dist/{chunk-Q35WZJJK.js → chunk-4YAFJWFG.js} +2 -2
- package/dist/{chunk-LOPKN3YL.js → chunk-BSD2Z5A6.js} +2 -2
- package/dist/{chunk-MA5JBAUZ.js → chunk-C5UGV7RM.js} +2 -2
- package/dist/chunk-FFBPWVWC.js +7 -0
- package/dist/chunk-FFBPWVWC.js.map +1 -0
- package/dist/{chunk-FSAXLDB3.js → chunk-OLRRIA4H.js} +2 -2
- package/dist/{chunk-PUJFYJXB.js → chunk-WS2E7HA5.js} +2 -2
- package/dist/{chunk-CSCD2HNS.js → chunk-XKCZOPZN.js} +79 -63
- package/dist/chunk-XKCZOPZN.js.map +1 -0
- package/dist/{chunk-P64PZUCA.js → chunk-YAW3AUTP.js} +3 -3
- package/dist/{db-N3YECFWR.js → db-JRFMBTRD.js} +4 -2
- package/dist/{extract-bundle-346R6MXD.js → extract-bundle-DSFOHMAT.js} +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/{location-data-repository-O2VII3ON.js → location-data-repository-OBJYZEGE.js} +3 -3
- package/dist/{server-3Q6XIJPF.js → server-2UDB6PTC.js} +24 -17
- package/dist/server-2UDB6PTC.js.map +1 -0
- package/dist/{site-extract-repository-I3VM6WXN.js → site-extract-repository-2YJ33J5C.js} +3 -3
- package/dist/{worker-TTFXPPDK.js → worker-ESF3HCNJ.js} +5 -5
- package/docs/mcp-tool-manifest.generated.json +2 -2
- package/package.json +4 -2
- package/dist/chunk-CSCD2HNS.js.map +0 -1
- package/dist/chunk-H3M3O457.js +0 -7
- package/dist/chunk-H3M3O457.js.map +0 -1
- package/dist/server-3Q6XIJPF.js.map +0 -1
- /package/dist/{chunk-Q35WZJJK.js.map → chunk-4YAFJWFG.js.map} +0 -0
- /package/dist/{chunk-LOPKN3YL.js.map → chunk-BSD2Z5A6.js.map} +0 -0
- /package/dist/{chunk-MA5JBAUZ.js.map → chunk-C5UGV7RM.js.map} +0 -0
- /package/dist/{chunk-FSAXLDB3.js.map → chunk-OLRRIA4H.js.map} +0 -0
- /package/dist/{chunk-PUJFYJXB.js.map → chunk-WS2E7HA5.js.map} +0 -0
- /package/dist/{chunk-P64PZUCA.js.map → chunk-YAW3AUTP.js.map} +0 -0
- /package/dist/{db-N3YECFWR.js.map → db-JRFMBTRD.js.map} +0 -0
- /package/dist/{extract-bundle-346R6MXD.js.map → extract-bundle-DSFOHMAT.js.map} +0 -0
- /package/dist/{location-data-repository-O2VII3ON.js.map → location-data-repository-OBJYZEGE.js.map} +0 -0
- /package/dist/{site-extract-repository-I3VM6WXN.js.map → site-extract-repository-2YJ33J5C.js.map} +0 -0
- /package/dist/{worker-TTFXPPDK.js.map → worker-ESF3HCNJ.js.map} +0 -0
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ Build the branded one-click bundle:
|
|
|
90
90
|
npm run build:mcpb
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.38.
|
|
93
|
+
The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.38.1`, SHA-256 `7b368db1bb9facbf2f7e1ec7d52128b8c49c682a02405a373ae613eba618aeae`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
|
|
94
94
|
|
|
95
95
|
The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
|
|
96
96
|
|
package/dist/bin/api-server.cjs
CHANGED
|
@@ -3598,10 +3598,20 @@ var init_url_utils = __esm({
|
|
|
3598
3598
|
}
|
|
3599
3599
|
});
|
|
3600
3600
|
|
|
3601
|
+
// src/api/credit-lot-integrity.ts
|
|
3602
|
+
var CREDIT_LOTS_EPOCH;
|
|
3603
|
+
var init_credit_lot_integrity = __esm({
|
|
3604
|
+
"src/api/credit-lot-integrity.ts"() {
|
|
3605
|
+
"use strict";
|
|
3606
|
+
CREDIT_LOTS_EPOCH = "2026-06-26 21:58:03";
|
|
3607
|
+
}
|
|
3608
|
+
});
|
|
3609
|
+
|
|
3601
3610
|
// src/api/db.ts
|
|
3602
3611
|
var db_exports = {};
|
|
3603
3612
|
__export(db_exports, {
|
|
3604
3613
|
CORE_SCHEMA_VERSION: () => CORE_SCHEMA_VERSION,
|
|
3614
|
+
CREDIT_LOTS_EPOCH: () => CREDIT_LOTS_EPOCH,
|
|
3605
3615
|
CREDIT_LOT_TTL: () => CREDIT_LOT_TTL,
|
|
3606
3616
|
SiteAuditJobRowSchema: () => SiteAuditJobRowSchema,
|
|
3607
3617
|
SiteAuditPhaseLogRowSchema: () => SiteAuditPhaseLogRowSchema,
|
|
@@ -3998,6 +4008,21 @@ async function migrate() {
|
|
|
3998
4008
|
} catch {
|
|
3999
4009
|
}
|
|
4000
4010
|
await db.execute(`CREATE INDEX IF NOT EXISTS credit_lots_user_active ON credit_lots(user_id, expires_at, remaining_mc)`);
|
|
4011
|
+
await db.execute(`
|
|
4012
|
+
CREATE TABLE IF NOT EXISTS credit_lot_repairs (
|
|
4013
|
+
repair_id TEXT PRIMARY KEY,
|
|
4014
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
4015
|
+
report_sha256 TEXT NOT NULL,
|
|
4016
|
+
classification TEXT NOT NULL,
|
|
4017
|
+
before_json TEXT NOT NULL,
|
|
4018
|
+
plan_json TEXT NOT NULL,
|
|
4019
|
+
after_json TEXT,
|
|
4020
|
+
status TEXT NOT NULL DEFAULT 'claimed',
|
|
4021
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
4022
|
+
applied_at TEXT
|
|
4023
|
+
)
|
|
4024
|
+
`);
|
|
4025
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS credit_lot_repairs_user_applied ON credit_lot_repairs(user_id, applied_at)`);
|
|
4001
4026
|
await db.execute(`
|
|
4002
4027
|
CREATE TABLE IF NOT EXISTS free_credit_refreshes (
|
|
4003
4028
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
@@ -5530,32 +5555,25 @@ async function resolveUserByMemorySubscription(subscriptionId) {
|
|
|
5530
5555
|
}
|
|
5531
5556
|
async function ensureMigrated(userId) {
|
|
5532
5557
|
const db = getDb();
|
|
5533
|
-
const
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5558
|
+
const inserted = await db.execute({
|
|
5559
|
+
sql: `INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, expires_at)
|
|
5560
|
+
SELECT ?, legacy.balance_mc, legacy.balance_mc, 'migration', datetime('now', ?)
|
|
5561
|
+
FROM (
|
|
5562
|
+
SELECT COALESCE(SUM(amount_mc), 0) AS balance_mc
|
|
5563
|
+
FROM ledger
|
|
5564
|
+
WHERE user_id = ?
|
|
5565
|
+
) AS legacy
|
|
5566
|
+
WHERE legacy.balance_mc > 0
|
|
5567
|
+
AND EXISTS (
|
|
5568
|
+
SELECT 1 FROM ledger
|
|
5569
|
+
WHERE user_id = ? AND created_at < ?
|
|
5570
|
+
)
|
|
5571
|
+
AND NOT EXISTS (
|
|
5572
|
+
SELECT 1 FROM credit_lots WHERE user_id = ?
|
|
5573
|
+
)`,
|
|
5574
|
+
args: [userId, CREDIT_LOT_TTL, userId, userId, CREDIT_LOTS_EPOCH, userId]
|
|
5549
5575
|
});
|
|
5550
|
-
|
|
5551
|
-
const updates = [];
|
|
5552
|
-
for (const lot of lots.rows) {
|
|
5553
|
-
if (need <= 0) break;
|
|
5554
|
-
const take = Math.min(Number(lot.remaining_mc), need);
|
|
5555
|
-
updates.push({ sql: "UPDATE credit_lots SET remaining_mc = remaining_mc - ? WHERE id = ?", args: [take, Number(lot.id)] });
|
|
5556
|
-
need -= take;
|
|
5557
|
-
}
|
|
5558
|
-
if (updates.length) await db.batch(updates, "write");
|
|
5576
|
+
return inserted.rowsAffected;
|
|
5559
5577
|
}
|
|
5560
5578
|
async function expireOldLots() {
|
|
5561
5579
|
const db = getDb();
|
|
@@ -5581,23 +5599,29 @@ async function expireOldLots() {
|
|
|
5581
5599
|
async function migrateExistingBalancesToLots() {
|
|
5582
5600
|
const db = getDb();
|
|
5583
5601
|
const res = await db.execute({
|
|
5584
|
-
sql: `SELECT u.id AS user_id
|
|
5585
|
-
FROM users u
|
|
5586
|
-
|
|
5587
|
-
|
|
5602
|
+
sql: `SELECT DISTINCT u.id AS user_id
|
|
5603
|
+
FROM users u
|
|
5604
|
+
JOIN ledger l ON l.user_id = u.id
|
|
5605
|
+
WHERE l.created_at < ?
|
|
5606
|
+
AND NOT EXISTS (SELECT 1 FROM credit_lots WHERE user_id = u.id)`,
|
|
5607
|
+
args: [CREDIT_LOTS_EPOCH]
|
|
5588
5608
|
});
|
|
5589
5609
|
let migrated = 0;
|
|
5590
5610
|
let totalMc = 0;
|
|
5591
5611
|
for (const row of res.rows) {
|
|
5592
5612
|
const uid = Number(row.user_id);
|
|
5593
|
-
const
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5613
|
+
const inserted = await ensureMigrated(uid);
|
|
5614
|
+
if (inserted === 0) continue;
|
|
5615
|
+
const lot = await db.execute({
|
|
5616
|
+
sql: `SELECT amount_mc FROM credit_lots
|
|
5617
|
+
WHERE user_id = ? AND source = 'migration'
|
|
5618
|
+
ORDER BY id DESC LIMIT 1`,
|
|
5619
|
+
args: [uid]
|
|
5620
|
+
});
|
|
5621
|
+
const amountMc = Number(lot.rows[0]?.amount_mc ?? 0);
|
|
5598
5622
|
await reconcileBalanceMc(uid);
|
|
5599
|
-
migrated
|
|
5600
|
-
totalMc +=
|
|
5623
|
+
migrated += 1;
|
|
5624
|
+
totalMc += amountMc;
|
|
5601
5625
|
}
|
|
5602
5626
|
return { migrated, total_mc: totalMc };
|
|
5603
5627
|
}
|
|
@@ -5611,19 +5635,22 @@ async function creditMc(userId, mc, operation, description, stripePaymentIntent,
|
|
|
5611
5635
|
}
|
|
5612
5636
|
const expiry = neverExpires ? "9999-12-31 23:59:59" : null;
|
|
5613
5637
|
if (stripePaymentIntent) {
|
|
5614
|
-
const
|
|
5638
|
+
const stmts2 = [{
|
|
5615
5639
|
sql: "INSERT OR IGNORE INTO ledger (user_id, amount_mc, operation, description, stripe_pi) VALUES (?, ?, ?, ?, ?)",
|
|
5616
5640
|
args: [userId, mc, operation, description ?? null, stripePaymentIntent]
|
|
5617
|
-
}
|
|
5618
|
-
if (ledgerInsert.rowsAffected === 0) {
|
|
5619
|
-
const res3 = await db.execute({ sql: "SELECT balance_mc FROM users WHERE id = ?", args: [userId] });
|
|
5620
|
-
return Number(res3.rows[0]?.balance_mc ?? 0);
|
|
5621
|
-
}
|
|
5622
|
-
const stmts2 = [];
|
|
5641
|
+
}];
|
|
5623
5642
|
if (mc > 0) {
|
|
5624
|
-
stmts2.push({
|
|
5643
|
+
stmts2.push({
|
|
5644
|
+
sql: `INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, stripe_pi, expires_at, never_expires)
|
|
5645
|
+
SELECT ?, ?, ?, ?, ?, COALESCE(?, datetime('now', ?)), ?
|
|
5646
|
+
WHERE changes() = 1`,
|
|
5647
|
+
args: [userId, mc, mc, operation, stripePaymentIntent, expiry, CREDIT_LOT_TTL, neverExpires ? 1 : 0]
|
|
5648
|
+
});
|
|
5625
5649
|
}
|
|
5626
|
-
stmts2.push({
|
|
5650
|
+
stmts2.push({
|
|
5651
|
+
sql: "UPDATE users SET balance_mc = balance_mc + ? WHERE id = ? AND changes() = 1",
|
|
5652
|
+
args: [mc, userId]
|
|
5653
|
+
});
|
|
5627
5654
|
await db.batch(stmts2, "write");
|
|
5628
5655
|
const res2 = await db.execute({ sql: "SELECT balance_mc FROM users WHERE id = ?", args: [userId] });
|
|
5629
5656
|
return Number(res2.rows[0]?.balance_mc ?? 0);
|
|
@@ -5731,23 +5758,14 @@ async function claimMonthlyFreeRefresh(userId, month) {
|
|
|
5731
5758
|
return res.rowsAffected > 0;
|
|
5732
5759
|
}
|
|
5733
5760
|
async function debitMc(userId, mc, operation, description) {
|
|
5734
|
-
const
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
return { ok: false, balance_mc: Number(res2.rows[0]?.balance_mc ?? 0) };
|
|
5743
|
-
}
|
|
5744
|
-
await drainLots(userId, mc);
|
|
5745
|
-
await db.execute({
|
|
5746
|
-
sql: "INSERT INTO ledger (user_id, amount_mc, operation, description) VALUES (?, ?, ?, ?)",
|
|
5747
|
-
args: [userId, -mc, operation, description ?? null]
|
|
5748
|
-
});
|
|
5749
|
-
const res = await db.execute({ sql: "SELECT balance_mc FROM users WHERE id = ?", args: [userId] });
|
|
5750
|
-
return { ok: true, balance_mc: Number(res.rows[0]?.balance_mc ?? 0) };
|
|
5761
|
+
const debit = await debitMcIdempotent(
|
|
5762
|
+
userId,
|
|
5763
|
+
mc,
|
|
5764
|
+
operation,
|
|
5765
|
+
description ?? "",
|
|
5766
|
+
`debit:${(0, import_node_crypto.randomUUID)()}`
|
|
5767
|
+
);
|
|
5768
|
+
return { ok: debit.ok, balance_mc: debit.balance_mc };
|
|
5751
5769
|
}
|
|
5752
5770
|
async function debitMcIdempotent(userId, mc, operation, description, idempotencyKey2) {
|
|
5753
5771
|
if (!Number.isSafeInteger(mc) || mc <= 0) throw new Error("idempotent debit amount must be a positive integer");
|
|
@@ -6258,11 +6276,13 @@ var init_db = __esm({
|
|
|
6258
6276
|
import_http = require("@libsql/client/http");
|
|
6259
6277
|
import_node_crypto = require("crypto");
|
|
6260
6278
|
import_zod = require("zod");
|
|
6279
|
+
init_credit_lot_integrity();
|
|
6280
|
+
init_credit_lot_integrity();
|
|
6261
6281
|
DB_URL = process.env.TURSO_DATABASE_URL ?? "file:./paa-api.db";
|
|
6262
6282
|
DB_TOKEN = process.env.TURSO_AUTH_TOKEN;
|
|
6263
6283
|
_db = null;
|
|
6264
6284
|
_rateLimitSchemaReady = false;
|
|
6265
|
-
CORE_SCHEMA_VERSION = "2026-07-28.
|
|
6285
|
+
CORE_SCHEMA_VERSION = "2026-07-28.2";
|
|
6266
6286
|
CORE_SCHEMA_TABLES = [
|
|
6267
6287
|
"admin_credit_adjustment_events",
|
|
6268
6288
|
"admin_credit_adjustments",
|
|
@@ -6275,6 +6295,7 @@ var init_db = __esm({
|
|
|
6275
6295
|
"connected_account_billing",
|
|
6276
6296
|
"concurrency_locks",
|
|
6277
6297
|
"credit_lots",
|
|
6298
|
+
"credit_lot_repairs",
|
|
6278
6299
|
"free_credit_refreshes",
|
|
6279
6300
|
"harvest_attempts",
|
|
6280
6301
|
"inbox_messages",
|
|
@@ -6311,6 +6332,7 @@ var init_db = __esm({
|
|
|
6311
6332
|
"concurrency_locks_operation",
|
|
6312
6333
|
"concurrency_locks_user_status",
|
|
6313
6334
|
"credit_lots_user_active",
|
|
6335
|
+
"credit_lot_repairs_user_applied",
|
|
6314
6336
|
"harvest_attempts_job_id",
|
|
6315
6337
|
"harvest_attempts_user_created_at",
|
|
6316
6338
|
"inbox_messages_user_sent_at",
|
|
@@ -37478,7 +37500,7 @@ var PACKAGE_VERSION;
|
|
|
37478
37500
|
var init_version = __esm({
|
|
37479
37501
|
"src/version.ts"() {
|
|
37480
37502
|
"use strict";
|
|
37481
|
-
PACKAGE_VERSION = "0.38.
|
|
37503
|
+
PACKAGE_VERSION = "0.38.1";
|
|
37482
37504
|
}
|
|
37483
37505
|
});
|
|
37484
37506
|
|
|
@@ -48348,6 +48370,16 @@ var init_browser_agent_console = __esm({
|
|
|
48348
48370
|
}
|
|
48349
48371
|
});
|
|
48350
48372
|
|
|
48373
|
+
// src/api/stripe-credit-policy.ts
|
|
48374
|
+
function shouldGrantScraperSubscriptionCredits(invoiceHasTierLine, invoiceTotal) {
|
|
48375
|
+
return invoiceHasTierLine && (invoiceTotal ?? 0) > 0;
|
|
48376
|
+
}
|
|
48377
|
+
var init_stripe_credit_policy = __esm({
|
|
48378
|
+
"src/api/stripe-credit-policy.ts"() {
|
|
48379
|
+
"use strict";
|
|
48380
|
+
}
|
|
48381
|
+
});
|
|
48382
|
+
|
|
48351
48383
|
// src/api/stripe-routes.ts
|
|
48352
48384
|
async function cancelStandaloneMemorySub(memSubId, baseSubId) {
|
|
48353
48385
|
if (!memSubId || memSubId === baseSubId) return;
|
|
@@ -48384,6 +48416,7 @@ var init_stripe_routes = __esm({
|
|
|
48384
48416
|
init_rates();
|
|
48385
48417
|
init_memory();
|
|
48386
48418
|
init_connected_account_billing();
|
|
48419
|
+
init_stripe_credit_policy();
|
|
48387
48420
|
stripe = new import_stripe.default(process.env.STRIPE_SECRET_KEY, { apiVersion: "2026-02-25.clover" });
|
|
48388
48421
|
stripeApp = new import_hono22.Hono();
|
|
48389
48422
|
stripeApp.post("/webhooks", async (c) => {
|
|
@@ -48405,7 +48438,7 @@ var init_stripe_routes = __esm({
|
|
|
48405
48438
|
const id = linePriceId(l);
|
|
48406
48439
|
return id && id in SUBSCRIPTION_TIERS;
|
|
48407
48440
|
});
|
|
48408
|
-
if (invoiceHasTierLine) {
|
|
48441
|
+
if (shouldGrantScraperSubscriptionCredits(invoiceHasTierLine, invoice.total)) {
|
|
48409
48442
|
const subId = invoice.subscription;
|
|
48410
48443
|
const liveBasePlanPriceId = subId ? findBasePlanItem(await stripe.subscriptions.retrieve(subId))?.price?.id : void 0;
|
|
48411
48444
|
const tierPriceId = liveBasePlanPriceId ?? invoice.lines.data.map(linePriceId).find((id) => id && id in SUBSCRIPTION_TIERS);
|