mcp-scraper 0.81.0 → 0.83.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.
- package/CHANGELOG.md +37 -0
- package/README.md +2 -2
- package/dist/{analytics-repository-YOY5KMOD.js → analytics-repository-GA6P5S5J.js} +1 -1
- package/dist/bin/api-server.js +3 -3
- package/dist/bin/mcp-scraper-cli.js +61 -46
- package/dist/bin/mcp-scraper-core.js +6 -6
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.js +6 -6
- package/dist/{chunk-PMONKQGJ.js → chunk-4NZ6JFK5.js} +2 -2
- package/dist/{chunk-VEQPA65D.js → chunk-ACDNW7TG.js} +1 -1
- package/dist/{chunk-Z63DQAO7.js → chunk-AIVNZZO3.js} +4 -3
- package/dist/{chunk-VXLU74YZ.js → chunk-BGD7U3AE.js} +207 -1
- package/dist/{chunk-HEUMDX4I.js → chunk-CNAJWRJT.js} +131 -1
- package/dist/{chunk-RSXDHQBA.js → chunk-FUG2IRKP.js} +1 -1
- package/dist/{chunk-XBEUZJHS.js → chunk-HGJJQY24.js} +49 -5
- package/dist/{chunk-XWXCLKXF.js → chunk-QSZXAA5F.js} +3107 -2210
- package/dist/{chunk-M2A7YSJV.js → chunk-UXVT7FWW.js} +2 -2
- package/dist/{chunk-VWC7XATD.js → chunk-ZHPGPVJJ.js} +1 -1
- package/dist/{extract-bundle-232SA7MI.js → extract-bundle-HTWWJD6N.js} +2 -2
- package/dist/{gmail-service-2A3ZZT3M.js → gmail-service-VXE7OYNA.js} +2 -2
- package/dist/{server-QRYEMF4H.js → server-ICMRDYI4.js} +2111 -791
- package/dist/{site-extract-repository-VDONDDMR.js → site-extract-repository-Y5WQFSQW.js} +6 -2
- package/dist/{worker-2MY77WYY.js → worker-FM3ZRDY4.js} +1 -1
- package/package.json +6 -2
- package/public/.well-known/xray-install.json +178 -0
- package/public/agent-install.md +194 -0
|
@@ -3263,9 +3263,139 @@ async function migrateAnalytics() {
|
|
|
3263
3263
|
await client.query(
|
|
3264
3264
|
"CREATE INDEX IF NOT EXISTS analytics_spend_facts_hierarchy ON analytics_ad_spend_facts(site_id, platform, account_id, campaign_id, ad_set_id, ad_id, bucket DESC)"
|
|
3265
3265
|
);
|
|
3266
|
+
await client.query(`
|
|
3267
|
+
CREATE TABLE IF NOT EXISTS analytics_runtime_manifests (
|
|
3268
|
+
manifest_id uuid PRIMARY KEY,
|
|
3269
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3270
|
+
revision integer NOT NULL CHECK (revision > 0),
|
|
3271
|
+
digest text NOT NULL CHECK (digest ~ '^[a-f0-9]{64}$'),
|
|
3272
|
+
manifest jsonb NOT NULL,
|
|
3273
|
+
is_current boolean NOT NULL DEFAULT false,
|
|
3274
|
+
created_by_user_id bigint NOT NULL,
|
|
3275
|
+
expires_at timestamptz NOT NULL,
|
|
3276
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3277
|
+
UNIQUE(site_id, revision)
|
|
3278
|
+
)
|
|
3279
|
+
`);
|
|
3280
|
+
await client.query("CREATE UNIQUE INDEX IF NOT EXISTS analytics_runtime_manifests_one_current ON analytics_runtime_manifests(site_id) WHERE is_current");
|
|
3281
|
+
await client.query("CREATE INDEX IF NOT EXISTS analytics_runtime_manifests_site_created ON analytics_runtime_manifests(site_id, created_at DESC)");
|
|
3282
|
+
await client.query(`
|
|
3283
|
+
CREATE TABLE IF NOT EXISTS analytics_runtime_manifest_publications (
|
|
3284
|
+
publication_id uuid PRIMARY KEY,
|
|
3285
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3286
|
+
manifest_id uuid NOT NULL REFERENCES analytics_runtime_manifests(manifest_id) ON DELETE CASCADE,
|
|
3287
|
+
setup_id uuid,
|
|
3288
|
+
setup_revision integer,
|
|
3289
|
+
idempotency_key text NOT NULL,
|
|
3290
|
+
request_fingerprint text NOT NULL CHECK (request_fingerprint ~ '^[a-f0-9]{64}$'),
|
|
3291
|
+
manifest jsonb NOT NULL,
|
|
3292
|
+
published_at timestamptz NOT NULL DEFAULT now(),
|
|
3293
|
+
UNIQUE(site_id, idempotency_key)
|
|
3294
|
+
)
|
|
3295
|
+
`);
|
|
3296
|
+
await client.query(`
|
|
3297
|
+
CREATE TABLE IF NOT EXISTS analytics_runtime_rule_health (
|
|
3298
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3299
|
+
manifest_id uuid NOT NULL REFERENCES analytics_runtime_manifests(manifest_id) ON DELETE CASCADE,
|
|
3300
|
+
rule_id uuid NOT NULL,
|
|
3301
|
+
rule_version integer NOT NULL,
|
|
3302
|
+
route_path text NOT NULL,
|
|
3303
|
+
selector_quality text NOT NULL CHECK (selector_quality IN ('portable','stable','fragile')),
|
|
3304
|
+
match_count integer NOT NULL CHECK (match_count BETWEEN 0 AND 100),
|
|
3305
|
+
structural_fingerprint text NOT NULL CHECK (structural_fingerprint ~ '^[a-f0-9]{64}$'),
|
|
3306
|
+
observed_at timestamptz NOT NULL,
|
|
3307
|
+
PRIMARY KEY(manifest_id, rule_id, route_path)
|
|
3308
|
+
)
|
|
3309
|
+
`);
|
|
3310
|
+
await client.query(`
|
|
3311
|
+
CREATE TABLE IF NOT EXISTS analytics_experiments (
|
|
3312
|
+
experiment_id uuid PRIMARY KEY,
|
|
3313
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3314
|
+
current_revision integer NOT NULL CHECK (current_revision > 0),
|
|
3315
|
+
state text NOT NULL CHECK (state IN ('draft','approved','canary','active','paused','killed','archived')),
|
|
3316
|
+
created_by_user_id bigint NOT NULL,
|
|
3317
|
+
create_idempotency_key text,
|
|
3318
|
+
create_request_fingerprint text,
|
|
3319
|
+
started_at timestamptz,
|
|
3320
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3321
|
+
updated_at timestamptz NOT NULL DEFAULT now()
|
|
3322
|
+
)
|
|
3323
|
+
`);
|
|
3324
|
+
await client.query("ALTER TABLE analytics_experiments ADD COLUMN IF NOT EXISTS create_idempotency_key text");
|
|
3325
|
+
await client.query("ALTER TABLE analytics_experiments ADD COLUMN IF NOT EXISTS create_request_fingerprint text");
|
|
3326
|
+
await client.query("ALTER TABLE analytics_experiments ADD COLUMN IF NOT EXISTS started_at timestamptz");
|
|
3327
|
+
await client.query("CREATE UNIQUE INDEX IF NOT EXISTS analytics_experiments_site_create_idempotency ON analytics_experiments(site_id, create_idempotency_key) WHERE create_idempotency_key IS NOT NULL");
|
|
3328
|
+
await client.query(`
|
|
3329
|
+
CREATE TABLE IF NOT EXISTS analytics_experiment_revisions (
|
|
3330
|
+
experiment_id uuid NOT NULL REFERENCES analytics_experiments(experiment_id) ON DELETE CASCADE,
|
|
3331
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3332
|
+
revision integer NOT NULL CHECK (revision > 0),
|
|
3333
|
+
plan jsonb NOT NULL,
|
|
3334
|
+
approved_by_user_id bigint,
|
|
3335
|
+
approved_at timestamptz,
|
|
3336
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3337
|
+
PRIMARY KEY(experiment_id, revision)
|
|
3338
|
+
)
|
|
3339
|
+
`);
|
|
3340
|
+
await client.query(`
|
|
3341
|
+
CREATE TABLE IF NOT EXISTS analytics_experiment_receipts (
|
|
3342
|
+
receipt_id uuid PRIMARY KEY,
|
|
3343
|
+
experiment_id uuid NOT NULL REFERENCES analytics_experiments(experiment_id) ON DELETE CASCADE,
|
|
3344
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3345
|
+
revision integer NOT NULL,
|
|
3346
|
+
operation text NOT NULL,
|
|
3347
|
+
idempotency_key text,
|
|
3348
|
+
receipt jsonb NOT NULL,
|
|
3349
|
+
occurred_at timestamptz NOT NULL DEFAULT now(),
|
|
3350
|
+
UNIQUE(experiment_id, idempotency_key)
|
|
3351
|
+
)
|
|
3352
|
+
`);
|
|
3353
|
+
await client.query("CREATE INDEX IF NOT EXISTS analytics_experiments_site_updated ON analytics_experiments(site_id, updated_at DESC)");
|
|
3354
|
+
await client.query(`
|
|
3355
|
+
CREATE TABLE IF NOT EXISTS analytics_site_setups (
|
|
3356
|
+
setup_id uuid PRIMARY KEY,
|
|
3357
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3358
|
+
owner_user_id bigint NOT NULL,
|
|
3359
|
+
revision integer NOT NULL CHECK (revision > 0),
|
|
3360
|
+
status text NOT NULL,
|
|
3361
|
+
start_url text NOT NULL,
|
|
3362
|
+
state jsonb NOT NULL,
|
|
3363
|
+
expires_at timestamptz NOT NULL,
|
|
3364
|
+
created_at timestamptz NOT NULL,
|
|
3365
|
+
updated_at timestamptz NOT NULL
|
|
3366
|
+
)
|
|
3367
|
+
`);
|
|
3368
|
+
await client.query(`
|
|
3369
|
+
CREATE TABLE IF NOT EXISTS analytics_site_setup_revisions (
|
|
3370
|
+
setup_id uuid NOT NULL REFERENCES analytics_site_setups(setup_id) ON DELETE CASCADE,
|
|
3371
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3372
|
+
owner_user_id bigint NOT NULL,
|
|
3373
|
+
revision integer NOT NULL CHECK (revision > 0),
|
|
3374
|
+
status text NOT NULL,
|
|
3375
|
+
state jsonb NOT NULL,
|
|
3376
|
+
created_at timestamptz NOT NULL,
|
|
3377
|
+
PRIMARY KEY(setup_id, revision)
|
|
3378
|
+
)
|
|
3379
|
+
`);
|
|
3380
|
+
await client.query(`
|
|
3381
|
+
CREATE TABLE IF NOT EXISTS analytics_site_setup_receipts (
|
|
3382
|
+
receipt_id uuid PRIMARY KEY,
|
|
3383
|
+
setup_id uuid NOT NULL REFERENCES analytics_site_setups(setup_id) ON DELETE CASCADE,
|
|
3384
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3385
|
+
owner_user_id bigint NOT NULL,
|
|
3386
|
+
revision integer NOT NULL,
|
|
3387
|
+
operation text NOT NULL,
|
|
3388
|
+
status text NOT NULL,
|
|
3389
|
+
receipt jsonb NOT NULL,
|
|
3390
|
+
occurred_at timestamptz NOT NULL
|
|
3391
|
+
)
|
|
3392
|
+
`);
|
|
3393
|
+
await client.query("CREATE INDEX IF NOT EXISTS analytics_site_setups_owner_updated ON analytics_site_setups(owner_user_id, updated_at DESC)");
|
|
3394
|
+
await client.query("CREATE INDEX IF NOT EXISTS analytics_site_setups_site_updated ON analytics_site_setups(site_id, updated_at DESC)");
|
|
3395
|
+
await client.query("CREATE INDEX IF NOT EXISTS analytics_site_setup_receipts_setup_revision ON analytics_site_setup_receipts(setup_id, revision, occurred_at)");
|
|
3266
3396
|
await client.query(`
|
|
3267
3397
|
INSERT INTO analytics_schema_migrations(version)
|
|
3268
|
-
VALUES ('2026-08-05.1'), ('2026-08-05.2'), ('2026-08-05.3'), ('2026-08-05.4'), ('2026-08-05.5'), ('2026-08-05.6'), ('2026-08-05.7'), ('2026-08-05.8'), ('2026-08-05.9'), ('2026-08-05.10'), ('2026-08-05.11'), ('2026-08-05.12'), ('2026-08-05.13'), ('2026-08-05.14'), ('2026-08-26.1'), ('2026-08-26.2'), ('2026-08-26.3'), ('2026-08-26.4'), ('2026-08-27.1'), ('2026-08-28.1'), ('2026-08-28.2'), ('2026-08-28.3'), ('2026-08-28.4')
|
|
3398
|
+
VALUES ('2026-08-05.1'), ('2026-08-05.2'), ('2026-08-05.3'), ('2026-08-05.4'), ('2026-08-05.5'), ('2026-08-05.6'), ('2026-08-05.7'), ('2026-08-05.8'), ('2026-08-05.9'), ('2026-08-05.10'), ('2026-08-05.11'), ('2026-08-05.12'), ('2026-08-05.13'), ('2026-08-05.14'), ('2026-08-26.1'), ('2026-08-26.2'), ('2026-08-26.3'), ('2026-08-26.4'), ('2026-08-27.1'), ('2026-08-28.1'), ('2026-08-28.2'), ('2026-08-28.3'), ('2026-08-28.4'), ('2026-08-31.1'), ('2026-09-01.1')
|
|
3269
3399
|
ON CONFLICT (version) DO NOTHING
|
|
3270
3400
|
`);
|
|
3271
3401
|
} catch (error) {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-DNM65UCK.js";
|
|
8
8
|
import {
|
|
9
9
|
LedgerOperation
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-4NZ6JFK5.js";
|
|
11
11
|
import {
|
|
12
12
|
CREDIT_LOT_TTL,
|
|
13
13
|
getDb,
|
|
@@ -255,6 +255,7 @@ function createSiteExtractContentReader(ownerId) {
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
// src/api/site-extract-repository.ts
|
|
258
|
+
var XRAY_ENTITLED_EXTRACT_BILLING_CLASS = "xray_entitlement";
|
|
258
259
|
function extractJobLimitInfo(job) {
|
|
259
260
|
const effectiveMaxPages = Math.max(1, Number(job.options.effectiveMaxPages ?? job.options.maxPages ?? 1));
|
|
260
261
|
const requestedMaxPages = Math.max(effectiveMaxPages, Number(job.options.requestedMaxPages ?? effectiveMaxPages));
|
|
@@ -366,16 +367,31 @@ async function listFundedPendingExtractJobs(limit = 25, staleMinutes = 2) {
|
|
|
366
367
|
const safeStaleMinutes = Math.max(1, Math.min(60, Math.round(staleMinutes)));
|
|
367
368
|
const res = await db.execute({
|
|
368
369
|
sql: `SELECT j.* FROM site_extract_jobs j
|
|
369
|
-
JOIN billing_debits d
|
|
370
|
+
LEFT JOIN billing_debits d
|
|
370
371
|
ON d.idempotency_key = json_extract(j.options, '$.debitKey')
|
|
371
372
|
AND d.user_id = j.user_id
|
|
372
373
|
AND d.status = 'applied'
|
|
373
374
|
WHERE j.status = 'pending'
|
|
374
375
|
AND j.billed_mc IS NULL
|
|
376
|
+
AND (
|
|
377
|
+
d.idempotency_key IS NOT NULL
|
|
378
|
+
OR (
|
|
379
|
+
json_extract(j.options, '$.billingClass') = ?
|
|
380
|
+
AND json_extract(j.options, '$.heldMc') = 0
|
|
381
|
+
AND json_extract(j.options, '$.debitKey') IS NULL
|
|
382
|
+
AND json_extract(j.options, '$.xraySetupReceipt.billingClass') = ?
|
|
383
|
+
AND json_extract(j.options, '$.xraySetupReceipt.consumesMcpScraperCredits') = 0
|
|
384
|
+
)
|
|
385
|
+
)
|
|
375
386
|
AND (j.next_dispatch_at IS NULL OR j.next_dispatch_at <= datetime('now'))
|
|
376
387
|
AND j.updated_at <= datetime('now', ?)
|
|
377
388
|
ORDER BY j.updated_at ASC LIMIT ?`,
|
|
378
|
-
args: [
|
|
389
|
+
args: [
|
|
390
|
+
XRAY_ENTITLED_EXTRACT_BILLING_CLASS,
|
|
391
|
+
XRAY_ENTITLED_EXTRACT_BILLING_CLASS,
|
|
392
|
+
`-${safeStaleMinutes} minutes`,
|
|
393
|
+
Math.max(1, Math.min(100, Math.round(limit)))
|
|
394
|
+
]
|
|
379
395
|
});
|
|
380
396
|
return res.rows.map((row) => rowToJob(row));
|
|
381
397
|
}
|
|
@@ -687,16 +703,24 @@ async function failUnfundedExtractJob(jobId, error, publicError) {
|
|
|
687
703
|
});
|
|
688
704
|
}
|
|
689
705
|
async function setExtractJobPublicError(jobId, publicError) {
|
|
706
|
+
const job = await getExtractJob(jobId);
|
|
707
|
+
const normalized = job?.options.billingClass === XRAY_ENTITLED_EXTRACT_BILLING_CLASS && publicError ? { ...publicError, charge_status: "not_charged" } : publicError;
|
|
690
708
|
await getDb().execute({
|
|
691
709
|
sql: `UPDATE site_extract_jobs SET public_error_json = ?, updated_at = datetime('now')
|
|
692
710
|
WHERE id = ? AND status IN ('complete', 'partial', 'failed')`,
|
|
693
|
-
args: [serializePublicErrorEnvelope(
|
|
711
|
+
args: [serializePublicErrorEnvelope(normalized), jobId]
|
|
694
712
|
});
|
|
695
713
|
}
|
|
696
714
|
async function settleExtractJob(jobId, userId, refundMc, netChargeMc, reference) {
|
|
697
715
|
const db = getDb();
|
|
698
716
|
const job = await getExtractJob(jobId);
|
|
699
717
|
if (!job || job.billedMc != null) return;
|
|
718
|
+
if (job.options.billingClass === XRAY_ENTITLED_EXTRACT_BILLING_CLASS) {
|
|
719
|
+
if (!await finalizeXRayEntitledExtractJobCharge(jobId)) {
|
|
720
|
+
throw new Error("xray_extract_zero_charge_finalization_rejected");
|
|
721
|
+
}
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
700
724
|
const debitKey = typeof job.options.debitKey === "string" ? job.options.debitKey : null;
|
|
701
725
|
if (debitKey) {
|
|
702
726
|
const settlement = await settleDebitMcIdempotent(
|
|
@@ -757,6 +781,24 @@ async function settleExtractJob(jobId, userId, refundMc, netChargeMc, reference)
|
|
|
757
781
|
}
|
|
758
782
|
], "write");
|
|
759
783
|
}
|
|
784
|
+
async function finalizeXRayEntitledExtractJobCharge(jobId) {
|
|
785
|
+
const db = getDb();
|
|
786
|
+
const result = await db.execute({
|
|
787
|
+
sql: `UPDATE site_extract_jobs
|
|
788
|
+
SET billed_mc = 0, updated_at = datetime('now')
|
|
789
|
+
WHERE id = ?
|
|
790
|
+
AND billed_mc IS NULL
|
|
791
|
+
AND json_extract(options, '$.billingClass') = ?
|
|
792
|
+
AND json_extract(options, '$.heldMc') = 0
|
|
793
|
+
AND json_extract(options, '$.debitKey') IS NULL
|
|
794
|
+
AND json_extract(options, '$.xraySetupReceipt.billingClass') = ?
|
|
795
|
+
AND json_extract(options, '$.xraySetupReceipt.consumesMcpScraperCredits') = 0
|
|
796
|
+
AND json_extract(options, '$.xraySetupReceipt.heldMc') = 0
|
|
797
|
+
AND json_extract(options, '$.xraySetupReceipt.billedMc') = 0`,
|
|
798
|
+
args: [jobId, XRAY_ENTITLED_EXTRACT_BILLING_CLASS, XRAY_ENTITLED_EXTRACT_BILLING_CLASS]
|
|
799
|
+
});
|
|
800
|
+
return result.rowsAffected === 1;
|
|
801
|
+
}
|
|
760
802
|
|
|
761
803
|
export {
|
|
762
804
|
SITE_EXTRACT_ARTIFACT_PREFIX,
|
|
@@ -767,6 +809,7 @@ export {
|
|
|
767
809
|
readOwnedSiteExtractImageArtifact,
|
|
768
810
|
cleanupExpiredSiteExtractArtifacts,
|
|
769
811
|
createSiteExtractContentReader,
|
|
812
|
+
XRAY_ENTITLED_EXTRACT_BILLING_CLASS,
|
|
770
813
|
extractJobLimitInfo,
|
|
771
814
|
terminalExtractJobStatus,
|
|
772
815
|
createExtractJob,
|
|
@@ -795,5 +838,6 @@ export {
|
|
|
795
838
|
failExtractJob,
|
|
796
839
|
failUnfundedExtractJob,
|
|
797
840
|
setExtractJobPublicError,
|
|
798
|
-
settleExtractJob
|
|
841
|
+
settleExtractJob,
|
|
842
|
+
finalizeXRayEntitledExtractJobCharge
|
|
799
843
|
};
|