mcp-scraper 0.34.0 → 0.35.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 +6 -5
- package/dist/bin/api-server.cjs +3788 -2742
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- 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 +2 -2
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.cjs +2129 -1932
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +5 -5
- package/dist/bin/paa-harvest.js +2 -2
- package/dist/{chunk-V36LS5YV.js → chunk-4ZB3X6BQ.js} +4 -3
- package/dist/chunk-4ZB3X6BQ.js.map +1 -0
- package/dist/{chunk-JBSGBSGT.js → chunk-BWXLTWF7.js} +21 -16
- package/dist/chunk-BWXLTWF7.js.map +1 -0
- package/dist/{chunk-J32XSMJI.js → chunk-NPMW5HUS.js} +2350 -2151
- package/dist/chunk-NPMW5HUS.js.map +1 -0
- package/dist/{chunk-SUOHUXQS.js → chunk-U44TPRST.js} +3 -3
- package/dist/chunk-U44TPRST.js.map +1 -0
- package/dist/{chunk-4KQVIYIH.js → chunk-XVVNKASZ.js} +2 -2
- package/dist/chunk-YR4LJ6AQ.js +7 -0
- package/dist/chunk-YR4LJ6AQ.js.map +1 -0
- package/dist/{chunk-2EDFOQD7.js → chunk-YRGSEY5L.js} +2 -2
- package/dist/{chunk-2EDFOQD7.js.map → chunk-YRGSEY5L.js.map} +1 -1
- package/dist/chunk-YV2FUEBX.js +851 -0
- package/dist/chunk-YV2FUEBX.js.map +1 -0
- package/dist/{extract-bundle-GPZRLBVY.js → extract-bundle-ONWZVV55.js} +59 -8
- package/dist/extract-bundle-ONWZVV55.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/{server-LKVPEQFE.js → server-GKUTC73B.js} +278 -52
- package/dist/server-GKUTC73B.js.map +1 -0
- package/dist/{site-extract-repository-JHMVHENZ.js → site-extract-repository-L6BHWVDU.js} +3 -3
- package/dist/{worker-ZZHSYI3Y.js → worker-645BZPEK.js} +4 -4
- package/docs/mcp-tool-craft-lint.generated.md +171 -49
- package/docs/mcp-tool-manifest.generated.json +508 -10
- package/docs/specs/query-fanout-transport-contract-fix.md +45 -0
- package/package.json +1 -1
- package/dist/chunk-J32XSMJI.js.map +0 -1
- package/dist/chunk-JBSGBSGT.js.map +0 -1
- package/dist/chunk-JWIE5NCR.js +0 -284
- package/dist/chunk-JWIE5NCR.js.map +0 -1
- package/dist/chunk-NFMIHEYE.js +0 -7
- package/dist/chunk-NFMIHEYE.js.map +0 -1
- package/dist/chunk-SUOHUXQS.js.map +0 -1
- package/dist/chunk-V36LS5YV.js.map +0 -1
- package/dist/extract-bundle-GPZRLBVY.js.map +0 -1
- package/dist/server-LKVPEQFE.js.map +0 -1
- /package/dist/{chunk-4KQVIYIH.js.map → chunk-XVVNKASZ.js.map} +0 -0
- /package/dist/{site-extract-repository-JHMVHENZ.js.map → site-extract-repository-L6BHWVDU.js.map} +0 -0
- /package/dist/{worker-ZZHSYI3Y.js.map → worker-645BZPEK.js.map} +0 -0
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
expandWaybackMonths,
|
|
3
|
+
harvestPageMedia,
|
|
4
|
+
inventoryWaybackSnapshots,
|
|
5
|
+
parseWaybackReplayUrl,
|
|
6
|
+
resolveFeaturedImage,
|
|
7
|
+
resolveWaybackSiteCaptures,
|
|
8
|
+
resolveWaybackTimelineCaptures
|
|
9
|
+
} from "./chunk-YV2FUEBX.js";
|
|
4
10
|
import {
|
|
5
11
|
classifyHarvestProblem,
|
|
6
12
|
createHarvestAttemptRecorder,
|
|
@@ -20,9 +26,11 @@ import {
|
|
|
20
26
|
resolveBackupKernelProxyId,
|
|
21
27
|
resolveKernelProxyId,
|
|
22
28
|
serpArrivalUrl
|
|
23
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-XVVNKASZ.js";
|
|
24
30
|
import {
|
|
25
31
|
HttpMcpToolExecutor,
|
|
32
|
+
WaybackInventoryOptionsSchema,
|
|
33
|
+
WaybackTimelineSchema,
|
|
26
34
|
assessTranscriptSignal,
|
|
27
35
|
buildLinkGraph,
|
|
28
36
|
buildPaaExtractorMcpServer,
|
|
@@ -40,7 +48,7 @@ import {
|
|
|
40
48
|
sanitizeAttempts,
|
|
41
49
|
sanitizeHarvestResult,
|
|
42
50
|
transcribeMediaUrl
|
|
43
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-NPMW5HUS.js";
|
|
44
52
|
import {
|
|
45
53
|
auditImages,
|
|
46
54
|
buildLinkReport,
|
|
@@ -53,11 +61,10 @@ import {
|
|
|
53
61
|
browserServiceProfileSaveChanges,
|
|
54
62
|
browserServiceProxyId,
|
|
55
63
|
currentCostContext,
|
|
56
|
-
kernelCostUsd,
|
|
57
64
|
recordKernelSession,
|
|
58
65
|
recordVendorUsage,
|
|
59
66
|
runWithCostContext
|
|
60
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-4ZB3X6BQ.js";
|
|
61
68
|
import {
|
|
62
69
|
csvRecords,
|
|
63
70
|
listWorkflowDefinitions,
|
|
@@ -81,7 +88,7 @@ import {
|
|
|
81
88
|
RawMapsOverviewSchema,
|
|
82
89
|
RawMapsReviewStatsSchema
|
|
83
90
|
} from "./chunk-CB5C3BPB.js";
|
|
84
|
-
import "./chunk-
|
|
91
|
+
import "./chunk-YR4LJ6AQ.js";
|
|
85
92
|
import {
|
|
86
93
|
completeExtractJob,
|
|
87
94
|
countSuccessfulPages,
|
|
@@ -92,7 +99,7 @@ import {
|
|
|
92
99
|
saveExtractPages,
|
|
93
100
|
setExtractJobTotal,
|
|
94
101
|
settleExtractJob
|
|
95
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-U44TPRST.js";
|
|
96
103
|
import {
|
|
97
104
|
BROWSER_OPEN_MIN_BALANCE_MC,
|
|
98
105
|
CONCURRENCY_PRICE_ID,
|
|
@@ -110,7 +117,6 @@ import {
|
|
|
110
117
|
MC_PER_CREDIT,
|
|
111
118
|
MC_PER_USD,
|
|
112
119
|
MEDIA_TRANSCRIBE_HOLD_MC,
|
|
113
|
-
MEDIA_TRANSCRIBE_MARGIN_MULTIPLE,
|
|
114
120
|
MEMORY_AI_MARGIN_MULTIPLE,
|
|
115
121
|
MEMORY_PLANS,
|
|
116
122
|
MEMORY_PLAN_QUOTA,
|
|
@@ -131,13 +137,14 @@ import {
|
|
|
131
137
|
getPublicRatesPayload,
|
|
132
138
|
insufficientBalanceResponse,
|
|
133
139
|
mcToCredits,
|
|
140
|
+
mediaTranscribeChargeMc,
|
|
134
141
|
offerClaimPathForTier,
|
|
135
142
|
serpActualCostMc,
|
|
136
143
|
tierAmountChargedUsd,
|
|
137
144
|
tierBillingInterval,
|
|
138
145
|
tierCreditsPerInterval,
|
|
139
146
|
vendorCostUsdToMc
|
|
140
|
-
} from "./chunk-
|
|
147
|
+
} from "./chunk-BWXLTWF7.js";
|
|
141
148
|
import {
|
|
142
149
|
CaptchaError,
|
|
143
150
|
ExtractionError,
|
|
@@ -7319,13 +7326,41 @@ var siteExtractFn = inngest.createFunction(
|
|
|
7319
7326
|
const maxPages = Number(job.options.maxPages ?? 1e4);
|
|
7320
7327
|
const concurrency = Number(job.options.concurrency ?? 1);
|
|
7321
7328
|
const urlsPerBrowser = Number(job.options.urlsPerBrowser ?? job.options.rotateProxyEvery ?? 10);
|
|
7329
|
+
const waybackReplay = parseWaybackReplayUrl(job.startUrl);
|
|
7330
|
+
const waybackTimeline = job.options.waybackTimeline;
|
|
7331
|
+
const disableLinkDiscovery = Boolean(waybackReplay) || Boolean(waybackTimeline);
|
|
7322
7332
|
const seedRaw = await step.run("discover", async () => {
|
|
7333
|
+
if (waybackTimeline) {
|
|
7334
|
+
const plan = await resolveWaybackTimelineCaptures({
|
|
7335
|
+
rootUrl: waybackTimeline.rootUrl,
|
|
7336
|
+
timeline: waybackTimeline.timeline,
|
|
7337
|
+
maxPagesPerSnapshot: waybackTimeline.maxPagesPerSnapshot,
|
|
7338
|
+
maxCaptures: maxPages
|
|
7339
|
+
});
|
|
7340
|
+
const urls2 = plan.captures.map((capture) => capture.rawReplayUrl);
|
|
7341
|
+
const requestedCells = plan.requestedUrls ? plan.months.length * plan.requestedUrls.length : urls2.length + plan.missing.length;
|
|
7342
|
+
await setExtractJobTotal(jobId, Math.max(urls2.length, requestedCells));
|
|
7343
|
+
return {
|
|
7344
|
+
urls: urls2,
|
|
7345
|
+
sitemapUrls: [],
|
|
7346
|
+
waybackMonthsByUrl: Object.fromEntries(
|
|
7347
|
+
plan.captures.map((capture) => [capture.rawReplayUrl, capture.requestedMonth ?? ""])
|
|
7348
|
+
)
|
|
7349
|
+
};
|
|
7350
|
+
}
|
|
7351
|
+
if (waybackReplay) {
|
|
7352
|
+
const captures = await resolveWaybackSiteCaptures(waybackReplay, maxPages);
|
|
7353
|
+
const urls2 = captures.map((capture) => capture.rawReplayUrl);
|
|
7354
|
+
await setExtractJobTotal(jobId, urls2.length);
|
|
7355
|
+
return { urls: urls2, sitemapUrls: [] };
|
|
7356
|
+
}
|
|
7323
7357
|
const discovered = await discoverUrlsWithSitemap(job.startUrl, maxPages, key);
|
|
7324
7358
|
const urls = discovered.urls.length ? discovered.urls : [job.startUrl];
|
|
7325
7359
|
await setExtractJobTotal(jobId, urls.length);
|
|
7326
7360
|
return { urls, sitemapUrls: discovered.sitemapUrls };
|
|
7327
7361
|
});
|
|
7328
|
-
const seed = Array.isArray(seedRaw) ? { urls: seedRaw, sitemapUrls: [] } : seedRaw;
|
|
7362
|
+
const seed = Array.isArray(seedRaw) ? { urls: seedRaw, sitemapUrls: [], waybackMonthsByUrl: void 0 } : seedRaw;
|
|
7363
|
+
const waybackMonthsByUrl = seed.waybackMonthsByUrl ?? {};
|
|
7329
7364
|
const siteHost = (() => {
|
|
7330
7365
|
try {
|
|
7331
7366
|
return new URL(job.startUrl).hostname.replace(/^www\./, "");
|
|
@@ -7359,7 +7394,20 @@ var siteExtractFn = inngest.createFunction(
|
|
|
7359
7394
|
if (!batch.length) break;
|
|
7360
7395
|
const newLinks = await step.run(`crawl-batch-${i}`, async () => {
|
|
7361
7396
|
const pages = await extractPagesRotating(batch, { kernelApiKey: key, concurrency, urlsPerBrowser });
|
|
7362
|
-
await saveExtractPages(jobId, pages.map((p) =>
|
|
7397
|
+
await saveExtractPages(jobId, pages.map((p) => {
|
|
7398
|
+
const replay = parseWaybackReplayUrl(p.url);
|
|
7399
|
+
return {
|
|
7400
|
+
...p,
|
|
7401
|
+
inSitemap: sitemapSet ? sitemapSet.has(norm(p.url)) : null,
|
|
7402
|
+
...replay ? {
|
|
7403
|
+
archivedUrl: p.url,
|
|
7404
|
+
archiveTimestamp: replay.timestamp,
|
|
7405
|
+
originalUrl: replay.originalUrl,
|
|
7406
|
+
requestedMonth: waybackMonthsByUrl[p.url] || void 0
|
|
7407
|
+
} : {}
|
|
7408
|
+
};
|
|
7409
|
+
}));
|
|
7410
|
+
if (disableLinkDiscovery) return [];
|
|
7363
7411
|
const found = [];
|
|
7364
7412
|
for (const p of pages) for (const l of p.outlinks ?? []) {
|
|
7365
7413
|
if (l.internal && l.href && sameSite(l.href)) found.push(l.href);
|
|
@@ -7388,7 +7436,7 @@ var siteExtractFn = inngest.createFunction(
|
|
|
7388
7436
|
return buildSeoAudit(pages, job.startUrl);
|
|
7389
7437
|
}) : null;
|
|
7390
7438
|
const artifacts = await step.run("finalize", async () => {
|
|
7391
|
-
const { assembleExtractArtifacts } = await import("./extract-bundle-
|
|
7439
|
+
const { assembleExtractArtifacts } = await import("./extract-bundle-ONWZVV55.js");
|
|
7392
7440
|
const stored = await assembleExtractArtifacts(job, { branding, imageAudit, seoAudit });
|
|
7393
7441
|
await completeExtractJob(jobId, stored);
|
|
7394
7442
|
return stored;
|
|
@@ -10375,6 +10423,7 @@ var ExtractUrlBodySchema = z14.object({
|
|
|
10375
10423
|
screenshot: z14.boolean().optional(),
|
|
10376
10424
|
screenshotDevice: z14.enum(["desktop", "mobile"]).optional(),
|
|
10377
10425
|
extractBranding: z14.boolean().optional(),
|
|
10426
|
+
includeFeaturedImage: z14.boolean().optional(),
|
|
10378
10427
|
downloadMedia: z14.boolean().optional(),
|
|
10379
10428
|
mediaTypes: z14.array(z14.enum(["image", "video", "audio"])).optional(),
|
|
10380
10429
|
allowLocal: z14.boolean().optional(),
|
|
@@ -10393,9 +10442,14 @@ var MapUrlsBodySchema = z14.object({
|
|
|
10393
10442
|
browserFallback: z14.boolean().optional(),
|
|
10394
10443
|
kernelFallback: z14.boolean().optional()
|
|
10395
10444
|
});
|
|
10445
|
+
var WaybackInventoryBodySchema = z14.object({
|
|
10446
|
+
url: z14.string().min(1, "url is required"),
|
|
10447
|
+
...WaybackInventoryOptionsSchema
|
|
10448
|
+
});
|
|
10396
10449
|
var ExtractSiteBodySchema = z14.object({
|
|
10397
10450
|
url: z14.string().min(1, "url is required"),
|
|
10398
10451
|
maxPages: z14.number().int().min(1).max(1e4).optional(),
|
|
10452
|
+
wayback: WaybackTimelineSchema.optional(),
|
|
10399
10453
|
browserFallback: z14.boolean().optional(),
|
|
10400
10454
|
kernelFallback: z14.boolean().optional(),
|
|
10401
10455
|
rotateProxies: z14.boolean().optional(),
|
|
@@ -10654,8 +10708,7 @@ youtubeApp.post("/transcribe", createApiKeyAuth(), async (c) => {
|
|
|
10654
10708
|
const { videoId } = parsed.data;
|
|
10655
10709
|
const id = videoId.trim();
|
|
10656
10710
|
const user = c.get("user");
|
|
10657
|
-
const
|
|
10658
|
-
const holdMc = MC_COSTS.yt_transcription * holdMins;
|
|
10711
|
+
const holdMc = MEDIA_TRANSCRIBE_HOLD_MC;
|
|
10659
10712
|
const gate = await acquireConcurrencyGate(user, "youtube_transcribe", {
|
|
10660
10713
|
reuseLockId: c.req.header("x-mcp-scraper-concurrency-lock"),
|
|
10661
10714
|
metadata: { videoId: id }
|
|
@@ -10671,8 +10724,7 @@ youtubeApp.post("/transcribe", createApiKeyAuth(), async (c) => {
|
|
|
10671
10724
|
const chunkSecs = lastChunk && Number.isFinite(lastChunk.timestamp[1]) ? lastChunk.timestamp[1] : 0;
|
|
10672
10725
|
const durationSecs = Number.isFinite(result.durationMs) ? result.durationMs / 1e3 : 0;
|
|
10673
10726
|
const videoSecs = Math.max(chunkSecs, durationSecs) || 60;
|
|
10674
|
-
const
|
|
10675
|
-
const actualMc = MC_COSTS.yt_transcription * actualMins;
|
|
10727
|
+
const actualMc = mediaTranscribeChargeMc(videoSecs);
|
|
10676
10728
|
const diff = holdMc - actualMc;
|
|
10677
10729
|
if (diff > 0) await creditMc(user.id, diff, LedgerOperation.TRANSCRIPTION_REFUND, "overestimate refund");
|
|
10678
10730
|
else if (diff < 0) await debitMc(user.id, -diff, LedgerOperation.TRANSCRIPTION, id);
|
|
@@ -11941,7 +11993,7 @@ facebookAdApp.post("/transcribe", createApiKeyAuth(), async (c) => {
|
|
|
11941
11993
|
if (!ok) return c.json(insufficientBalanceResponse(balance_mc, holdMc), 402);
|
|
11942
11994
|
debited = true;
|
|
11943
11995
|
const transcript = await transcribeFacebookVideoUrl(videoUrl, "# Facebook Ad Transcript");
|
|
11944
|
-
const settleMc =
|
|
11996
|
+
const settleMc = mediaTranscribeChargeMc(transcript.durationMs / 1e3);
|
|
11945
11997
|
const diff = holdMc - settleMc;
|
|
11946
11998
|
if (diff > 0) await creditMc(fbUser.id, diff, LedgerOperation.FB_TRANSCRIBE_REFUND, "real-cost reconcile");
|
|
11947
11999
|
else if (diff < 0) await debitMc(fbUser.id, -diff, LedgerOperation.FB_TRANSCRIBE, videoUrl);
|
|
@@ -11992,7 +12044,7 @@ facebookAdApp.post("/video-transcribe", createApiKeyAuth(), async (c) => {
|
|
|
11992
12044
|
const video = await extractFacebookOrganicVideoFromPage(page, sourceUrl.href, body.quality);
|
|
11993
12045
|
const kernelMs = Date.now() - kernelStartMs;
|
|
11994
12046
|
const transcript = await transcribeFacebookVideoUrl(video.videoUrl, "# Facebook Organic Video Transcript");
|
|
11995
|
-
const settleMc =
|
|
12047
|
+
const settleMc = mediaTranscribeChargeMc(transcript.durationMs / 1e3);
|
|
11996
12048
|
const diff = holdMc - settleMc;
|
|
11997
12049
|
if (diff > 0) await creditMc(fbUser.id, diff, LedgerOperation.FB_TRANSCRIBE_REFUND, "real-cost reconcile");
|
|
11998
12050
|
else if (diff < 0) await debitMc(fbUser.id, -diff, LedgerOperation.FB_TRANSCRIBE, sourceUrl.href);
|
|
@@ -12475,7 +12527,7 @@ googleAdsApp.post("/transcribe", createApiKeyAuth(), async (c) => {
|
|
|
12475
12527
|
if (!ok) return c.json(insufficientBalanceResponse(balance_mc, holdMc), 402);
|
|
12476
12528
|
debited = true;
|
|
12477
12529
|
const transcript = await runWithCostContext({ ...currentCostContext(), op: "google_ads_transcribe", userId: user.id }, () => transcribeMediaUrl(videoUrl, "# Google Ad Transcript"));
|
|
12478
|
-
const settleMc =
|
|
12530
|
+
const settleMc = mediaTranscribeChargeMc(transcript.durationMs / 1e3);
|
|
12479
12531
|
const diff = holdMc - settleMc;
|
|
12480
12532
|
if (diff > 0) await creditMc(user.id, diff, LedgerOperation.GOOGLE_ADS_TRANSCRIBE_REFUND, "real-cost reconcile");
|
|
12481
12533
|
else if (diff < 0) await debitMc(user.id, -diff, LedgerOperation.GOOGLE_ADS_TRANSCRIBE, videoUrl);
|
|
@@ -13130,7 +13182,7 @@ instagramApp.post("/media-download", createApiKeyAuth(), async (c) => {
|
|
|
13130
13182
|
if (!tx.ok) return c.json(insufficientBalanceResponse(tx.balance_mc, holdMc), 402);
|
|
13131
13183
|
transcriptDebited = true;
|
|
13132
13184
|
transcript = await transcribeMediaUrl(audioUrl, "# Instagram Media Transcript");
|
|
13133
|
-
const settleMc =
|
|
13185
|
+
const settleMc = mediaTranscribeChargeMc(transcript.durationMs / 1e3);
|
|
13134
13186
|
const diff = holdMc - settleMc;
|
|
13135
13187
|
if (diff > 0) await creditMc(user.id, diff, LedgerOperation.INSTAGRAM_TRANSCRIBE_REFUND, "real-cost reconcile");
|
|
13136
13188
|
else if (diff < 0) await debitMc(user.id, -diff, LedgerOperation.INSTAGRAM_TRANSCRIBE, sourceUrl.href);
|
|
@@ -20544,6 +20596,19 @@ if (state.key) { refreshSessions(); if (state.current) selectSession(state.curre
|
|
|
20544
20596
|
import Stripe from "stripe";
|
|
20545
20597
|
import { Hono as Hono20 } from "hono";
|
|
20546
20598
|
var stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: "2026-02-25.clover" });
|
|
20599
|
+
async function cancelStandaloneMemorySub(memSubId, baseSubId) {
|
|
20600
|
+
if (!memSubId || memSubId === baseSubId) return;
|
|
20601
|
+
try {
|
|
20602
|
+
const memSub = await stripe.subscriptions.retrieve(memSubId);
|
|
20603
|
+
const priceId = memSub.items.data[0]?.price?.id;
|
|
20604
|
+
const stillOpen = memSub.status !== "canceled" && !memSub.cancel_at_period_end;
|
|
20605
|
+
if (priceId && priceId in MEMORY_PLANS && stillOpen) {
|
|
20606
|
+
await stripe.subscriptions.update(memSubId, { cancel_at_period_end: true });
|
|
20607
|
+
}
|
|
20608
|
+
} catch (err) {
|
|
20609
|
+
console.error("[stripe] could not wind down standalone memory subscription", memSubId, err instanceof Error ? err.message : err);
|
|
20610
|
+
}
|
|
20611
|
+
}
|
|
20547
20612
|
var stripeApp = new Hono20();
|
|
20548
20613
|
stripeApp.post("/webhooks", async (c) => {
|
|
20549
20614
|
const sig = c.req.header("stripe-signature");
|
|
@@ -20575,14 +20640,7 @@ stripeApp.post("/webhooks", async (c) => {
|
|
|
20575
20640
|
await creditMc(user.id, tier.credits_mc, LedgerOperation.SUBSCRIPTION, `${tier.label} subscription credits`, invoice.id, { neverExpires: tier.credits_never_expire });
|
|
20576
20641
|
await setSubscriptionTier(user.id, tier.tier, tier.concurrency, subId ?? user.subscription_id);
|
|
20577
20642
|
if (tier.includes_memory) {
|
|
20578
|
-
|
|
20579
|
-
if (standaloneMemorySub) {
|
|
20580
|
-
try {
|
|
20581
|
-
await stripe.subscriptions.update(standaloneMemorySub, { cancel_at_period_end: true });
|
|
20582
|
-
} catch (err) {
|
|
20583
|
-
console.error("[stripe] could not wind down standalone memory subscription", standaloneMemorySub, err instanceof Error ? err.message : err);
|
|
20584
|
-
}
|
|
20585
|
-
}
|
|
20643
|
+
await cancelStandaloneMemorySub(user.memory_subscription_id, subId ?? user.subscription_id);
|
|
20586
20644
|
await setMemoryPlan(user.id, "pro", null);
|
|
20587
20645
|
await syncMemoryKeyPlan(user, resolveEffectiveMemoryPlan({ ...user, memory_plan: "pro", subscription_tier: tier.tier }));
|
|
20588
20646
|
}
|
|
@@ -20634,6 +20692,7 @@ stripeApp.post("/webhooks", async (c) => {
|
|
|
20634
20692
|
await setSubscriptionTier(user.id, newTier, live ? tier.concurrency : 0, live ? sub.id : null);
|
|
20635
20693
|
if (tier.includes_memory) {
|
|
20636
20694
|
const newMemoryPlan = live ? "pro" : "free";
|
|
20695
|
+
if (live) await cancelStandaloneMemorySub(user.memory_subscription_id, sub.id);
|
|
20637
20696
|
await setMemoryPlan(user.id, newMemoryPlan, live ? sub.id : null);
|
|
20638
20697
|
await syncMemoryKeyPlan(user, resolveEffectiveMemoryPlan({ ...user, memory_plan: newMemoryPlan }));
|
|
20639
20698
|
} else if (user.memory_subscription_id === sub.id) {
|
|
@@ -26595,6 +26654,7 @@ function opForCostPath(p) {
|
|
|
26595
26654
|
if (p === "/extract-url") return "page_scrape";
|
|
26596
26655
|
if (p === "/extract-site") return "extract_site";
|
|
26597
26656
|
if (p === "/map-urls") return "url_map";
|
|
26657
|
+
if (p === "/wayback/snapshots") return "url_map";
|
|
26598
26658
|
if (p === "/youtube/harvest") return "yt_channel";
|
|
26599
26659
|
if (p === "/youtube/transcribe") return "yt_transcription";
|
|
26600
26660
|
if (p === "/maps/search") return "maps_search";
|
|
@@ -28309,7 +28369,7 @@ app.post("/extract-url", auth2, async (c) => {
|
|
|
28309
28369
|
const raw = await c.req.json().catch(() => ({}));
|
|
28310
28370
|
const bodyResult = ExtractUrlBodySchema.safeParse(raw);
|
|
28311
28371
|
if (!bodyResult.success) return c.json({ error: bodyResult.error.issues[0]?.message ?? "Invalid request" }, 400);
|
|
28312
|
-
const { url, screenshot: screenshot2, screenshotDevice, extractBranding: extractBranding2, downloadMedia, mediaTypes, allowLocal } = bodyResult.data;
|
|
28372
|
+
const { url, screenshot: screenshot2, screenshotDevice, extractBranding: extractBranding2, includeFeaturedImage, downloadMedia, mediaTypes, allowLocal } = bodyResult.data;
|
|
28313
28373
|
if (!allowLocal) {
|
|
28314
28374
|
const checked = await validatePublicHttpUrl(url, { field: "URL" });
|
|
28315
28375
|
if (checked.error || !checked.parsed) return c.json({ error: checked.error ?? "Invalid URL" }, 400);
|
|
@@ -28327,6 +28387,8 @@ app.post("/extract-url", auth2, async (c) => {
|
|
|
28327
28387
|
return url;
|
|
28328
28388
|
}
|
|
28329
28389
|
})();
|
|
28390
|
+
const waybackReplay = parseWaybackReplayUrl(canonicalUrl);
|
|
28391
|
+
const extractionUrl = waybackReplay?.rawReplayUrl ?? canonicalUrl;
|
|
28330
28392
|
const user = c.get("user");
|
|
28331
28393
|
const gate = await acquireConcurrencyGate(user, "extract_url", {
|
|
28332
28394
|
reuseLockId: c.req.header("x-mcp-scraper-concurrency-lock"),
|
|
@@ -28341,7 +28403,7 @@ app.post("/extract-url", auth2, async (c) => {
|
|
|
28341
28403
|
const kernelApiKey = browserServiceApiKey();
|
|
28342
28404
|
const device = screenshotDevice === "mobile" ? "mobile" : "desktop";
|
|
28343
28405
|
const [result, pageData] = await Promise.all([
|
|
28344
|
-
extractKpo({ url:
|
|
28406
|
+
extractKpo({ url: extractionUrl, kernelApiKey }),
|
|
28345
28407
|
screenshot2 || extractBranding2 ? capturePageData(canonicalUrl, { kernelApiKey, device, screenshot: !!screenshot2, branding: !!extractBranding2 }).catch((err) => {
|
|
28346
28408
|
console.error("[extract-url] capturePageData failed:", err instanceof Error ? err.message : err);
|
|
28347
28409
|
return null;
|
|
@@ -28353,15 +28415,36 @@ app.post("/extract-url", auth2, async (c) => {
|
|
|
28353
28415
|
if (screenshotBuf) {
|
|
28354
28416
|
screenshotMeta = { base64: screenshotBuf.toString("base64"), sizeBytes: screenshotBuf.length, device };
|
|
28355
28417
|
}
|
|
28356
|
-
const mediaMeta = downloadMedia ? await harvestPageMedia(result.bodyHtml, canonicalUrl, { types: mediaTypes ?? ["image", "video", "audio"], outputDir: null }) : null;
|
|
28418
|
+
const mediaMeta = downloadMedia ? await harvestPageMedia(result.bodyHtml, waybackReplay?.originalUrl ?? canonicalUrl, { types: mediaTypes ?? ["image", "video", "audio"], outputDir: null }) : null;
|
|
28419
|
+
const featuredImage = includeFeaturedImage ? resolveFeaturedImage({
|
|
28420
|
+
html: result.bodyHtml,
|
|
28421
|
+
meta: result.meta,
|
|
28422
|
+
schema: result.schema,
|
|
28423
|
+
pageUrl: waybackReplay?.rawReplayUrl ?? canonicalUrl
|
|
28424
|
+
}) : null;
|
|
28357
28425
|
const memory = bodyResult.data.depositToVault ? await persistScrapeBody(user, {
|
|
28358
28426
|
title: result.title ?? canonicalUrl,
|
|
28359
28427
|
content: result.bodyMarkdown ?? "",
|
|
28360
28428
|
source: canonicalUrl,
|
|
28361
28429
|
vault: bodyResult.data.vaultName
|
|
28362
28430
|
}) : void 0;
|
|
28431
|
+
const archive = waybackReplay ? {
|
|
28432
|
+
timestamp: waybackReplay.timestamp,
|
|
28433
|
+
originalUrl: waybackReplay.originalUrl,
|
|
28434
|
+
replayUrl: waybackReplay.replayUrl,
|
|
28435
|
+
rawReplayUrl: waybackReplay.rawReplayUrl
|
|
28436
|
+
} : null;
|
|
28363
28437
|
await logRequestEvent({ userId: user.id, source: "extract_url", status: "done", query: canonicalUrl, resultCount: result.headings.length, result });
|
|
28364
|
-
return c.json({
|
|
28438
|
+
return c.json({
|
|
28439
|
+
...result,
|
|
28440
|
+
url: canonicalUrl,
|
|
28441
|
+
archive,
|
|
28442
|
+
featuredImage,
|
|
28443
|
+
screenshot: screenshotMeta,
|
|
28444
|
+
branding: brandingData,
|
|
28445
|
+
media: mediaMeta,
|
|
28446
|
+
memory
|
|
28447
|
+
});
|
|
28365
28448
|
} catch (err) {
|
|
28366
28449
|
const msg = err instanceof Error ? err.message : String(err);
|
|
28367
28450
|
if (debited) await creditMc(user.id, MC_COSTS.page_scrape, LedgerOperation.EXTRACT_URL, "failed call");
|
|
@@ -28505,6 +28588,76 @@ app.post("/map-urls", auth2, async (c) => {
|
|
|
28505
28588
|
await releaseConcurrencyGate(gate.lockId);
|
|
28506
28589
|
}
|
|
28507
28590
|
});
|
|
28591
|
+
app.post("/wayback/snapshots", auth2, async (c) => {
|
|
28592
|
+
const raw = await c.req.json().catch(() => ({}));
|
|
28593
|
+
const bodyResult = WaybackInventoryBodySchema.safeParse(raw);
|
|
28594
|
+
if (!bodyResult.success) return c.json({ error: bodyResult.error.issues[0]?.message ?? "Invalid request" }, 400);
|
|
28595
|
+
const body = bodyResult.data;
|
|
28596
|
+
const checked = await validatePublicHttpUrl(body.url, { field: "URL" });
|
|
28597
|
+
if (checked.error || !checked.parsed) return c.json({ error: checked.error ?? "Invalid URL" }, 400);
|
|
28598
|
+
for (const selectedUrl of body.urls ?? []) {
|
|
28599
|
+
const selected = await validatePublicHttpUrl(selectedUrl, { field: "Wayback selected URL" });
|
|
28600
|
+
if (selected.error || !selected.parsed) return c.json({ error: selected.error ?? "Invalid Wayback selected URL" }, 400);
|
|
28601
|
+
}
|
|
28602
|
+
const user = c.get("user");
|
|
28603
|
+
const gate = await acquireConcurrencyGate(user, "wayback_inventory", {
|
|
28604
|
+
reuseLockId: c.req.header("x-mcp-scraper-concurrency-lock"),
|
|
28605
|
+
metadata: { url: checked.parsed.href }
|
|
28606
|
+
});
|
|
28607
|
+
if (!gate.ok) return c.json(concurrencyLimitExceededResponse(gate), 429, { "Retry-After": String(gate.retryAfterSeconds) });
|
|
28608
|
+
let debited = false;
|
|
28609
|
+
try {
|
|
28610
|
+
const { ok, balance_mc: balanceMc } = await debitMc(
|
|
28611
|
+
user.id,
|
|
28612
|
+
MC_COSTS.url_map,
|
|
28613
|
+
LedgerOperation.URL_MAP,
|
|
28614
|
+
checked.parsed.hostname
|
|
28615
|
+
);
|
|
28616
|
+
if (!ok) return c.json(insufficientBalanceResponse(balanceMc, MC_COSTS.url_map), 402);
|
|
28617
|
+
debited = true;
|
|
28618
|
+
const result = await inventoryWaybackSnapshots({
|
|
28619
|
+
url: checked.parsed.href,
|
|
28620
|
+
scope: body.scope,
|
|
28621
|
+
urls: body.urls,
|
|
28622
|
+
from: body.from,
|
|
28623
|
+
to: body.to,
|
|
28624
|
+
successfulHtmlOnly: body.successfulHtmlOnly,
|
|
28625
|
+
maxCaptures: body.maxCaptures,
|
|
28626
|
+
includeCaptures: body.includeCaptures,
|
|
28627
|
+
maxCaptureRows: body.maxCaptureRows
|
|
28628
|
+
});
|
|
28629
|
+
await logRequestEvent({
|
|
28630
|
+
userId: user.id,
|
|
28631
|
+
source: "wayback_inventory",
|
|
28632
|
+
status: "done",
|
|
28633
|
+
query: result.url,
|
|
28634
|
+
resultCount: result.totalCaptures,
|
|
28635
|
+
result: {
|
|
28636
|
+
scope: result.scope,
|
|
28637
|
+
from: result.from,
|
|
28638
|
+
to: result.to,
|
|
28639
|
+
totalCaptures: result.totalCaptures,
|
|
28640
|
+
countType: result.countType,
|
|
28641
|
+
uniqueUrls: result.uniqueUrls,
|
|
28642
|
+
uniqueDigests: result.uniqueDigests
|
|
28643
|
+
}
|
|
28644
|
+
});
|
|
28645
|
+
return c.json(result);
|
|
28646
|
+
} catch (error) {
|
|
28647
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
28648
|
+
if (debited) await creditMc(user.id, MC_COSTS.url_map, LedgerOperation.URL_MAP_REFUND, "failed call");
|
|
28649
|
+
await logRequestEvent({
|
|
28650
|
+
userId: user.id,
|
|
28651
|
+
source: "wayback_inventory",
|
|
28652
|
+
status: "failed",
|
|
28653
|
+
query: checked.parsed.href,
|
|
28654
|
+
error: message
|
|
28655
|
+
});
|
|
28656
|
+
return c.json({ error: message }, 500);
|
|
28657
|
+
} finally {
|
|
28658
|
+
await releaseConcurrencyGate(gate.lockId);
|
|
28659
|
+
}
|
|
28660
|
+
});
|
|
28508
28661
|
app.post("/extract-site", auth2, async (c) => {
|
|
28509
28662
|
const raw = await c.req.json().catch(() => ({}));
|
|
28510
28663
|
const bodyResult = ExtractSiteBodySchema.safeParse(raw);
|
|
@@ -28514,24 +28667,58 @@ app.post("/extract-site", auth2, async (c) => {
|
|
|
28514
28667
|
if (checked.error || !checked.parsed) return c.json({ error: checked.error ?? "Invalid URL" }, 400);
|
|
28515
28668
|
const parsed = checked.parsed;
|
|
28516
28669
|
const user = c.get("user");
|
|
28670
|
+
const waybackReplay = parseWaybackReplayUrl(parsed.href);
|
|
28671
|
+
const waybackMonths = body.wayback ? expandWaybackMonths(body.wayback) : [];
|
|
28672
|
+
const waybackRootUrl = waybackReplay?.originalUrl ?? parsed.href;
|
|
28673
|
+
if (body.wayback?.urls) {
|
|
28674
|
+
const rootHost = new URL(waybackRootUrl).hostname.replace(/^www\./, "").toLowerCase();
|
|
28675
|
+
for (const selectedUrl of body.wayback.urls) {
|
|
28676
|
+
const selected = await validatePublicHttpUrl(selectedUrl, { field: "Wayback selected URL" });
|
|
28677
|
+
if (selected.error || !selected.parsed) return c.json({ error: selected.error ?? "Invalid Wayback selected URL" }, 400);
|
|
28678
|
+
if (selected.parsed.hostname.replace(/^www\./, "").toLowerCase() !== rootHost) {
|
|
28679
|
+
return c.json({ error: "Every selected Wayback URL must belong to the same site as url." }, 400);
|
|
28680
|
+
}
|
|
28681
|
+
}
|
|
28682
|
+
}
|
|
28683
|
+
const maxPagesPerSnapshot = Math.min(500, Math.max(1, body.maxPages ?? 100));
|
|
28684
|
+
const requestedMaxPages = body.wayback ? Math.min(
|
|
28685
|
+
1e4,
|
|
28686
|
+
waybackMonths.length * Math.min(maxPagesPerSnapshot, body.wayback.urls?.length ?? maxPagesPerSnapshot)
|
|
28687
|
+
) : Math.min(1e4, Math.max(1, body.maxPages ?? 1e4));
|
|
28688
|
+
const crawlStartUrl = body.wayback ? waybackRootUrl : waybackReplay?.rawReplayUrl ?? parsed.href;
|
|
28517
28689
|
const downloadImages = body.downloadImages === true;
|
|
28518
|
-
if (body.background === true || downloadImages) {
|
|
28690
|
+
if (body.background === true || downloadImages || Boolean(body.wayback)) {
|
|
28519
28691
|
const affordablePages = Math.floor(user.balance_mc / MC_COSTS.page_scrape);
|
|
28520
28692
|
if (affordablePages < 1) return c.json(insufficientBalanceResponse(user.balance_mc, MC_COSTS.page_scrape), 402);
|
|
28521
|
-
const maxPages = Math.min(
|
|
28693
|
+
const maxPages = Math.min(requestedMaxPages, affordablePages);
|
|
28522
28694
|
const heldMc = maxPages * MC_COSTS.page_scrape;
|
|
28523
28695
|
const { ok: holdOk, balance_mc: holdBal } = await debitMc(user.id, heldMc, LedgerOperation.EXTRACT_SITE_HOLD, parsed.hostname);
|
|
28524
28696
|
if (!holdOk) return c.json(insufficientBalanceResponse(holdBal, heldMc), 402);
|
|
28525
28697
|
const jobId = `ext_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
|
28526
28698
|
let jobCreated = false;
|
|
28527
28699
|
try {
|
|
28528
|
-
await createExtractJob(jobId, user.id,
|
|
28700
|
+
await createExtractJob(jobId, user.id, crawlStartUrl, {
|
|
28529
28701
|
maxPages,
|
|
28530
28702
|
concurrency: concurrencyLimitForUser(user),
|
|
28531
28703
|
urlsPerBrowser: body.rotateProxyEvery ?? 10,
|
|
28532
28704
|
formats: body.formats,
|
|
28533
28705
|
downloadImages,
|
|
28534
|
-
heldMc
|
|
28706
|
+
heldMc,
|
|
28707
|
+
...waybackReplay && !body.wayback ? {
|
|
28708
|
+
waybackReplay: {
|
|
28709
|
+
timestamp: waybackReplay.timestamp,
|
|
28710
|
+
originalUrl: waybackReplay.originalUrl,
|
|
28711
|
+
replayUrl: waybackReplay.replayUrl,
|
|
28712
|
+
rawReplayUrl: waybackReplay.rawReplayUrl
|
|
28713
|
+
}
|
|
28714
|
+
} : {},
|
|
28715
|
+
...body.wayback ? {
|
|
28716
|
+
waybackTimeline: {
|
|
28717
|
+
rootUrl: waybackRootUrl,
|
|
28718
|
+
timeline: body.wayback,
|
|
28719
|
+
maxPagesPerSnapshot
|
|
28720
|
+
}
|
|
28721
|
+
} : {}
|
|
28535
28722
|
});
|
|
28536
28723
|
jobCreated = true;
|
|
28537
28724
|
await inngest.send({ name: "mcp-scraper/extract.requested", data: { jobId } });
|
|
@@ -28565,9 +28752,11 @@ app.post("/extract-site", auth2, async (c) => {
|
|
|
28565
28752
|
debited = true;
|
|
28566
28753
|
const rotateProxies = body.rotateProxies === true;
|
|
28567
28754
|
const wantsBranding = body.formats?.includes("branding") === true;
|
|
28755
|
+
const waybackCaptures = waybackReplay ? await resolveWaybackSiteCaptures(waybackReplay, siteMaxPages) : null;
|
|
28568
28756
|
const result = await extractSite({
|
|
28569
|
-
startUrl:
|
|
28757
|
+
startUrl: crawlStartUrl,
|
|
28570
28758
|
maxPages: siteMaxPages,
|
|
28759
|
+
seedUrls: waybackCaptures?.map((capture) => capture.rawReplayUrl),
|
|
28571
28760
|
kernelApiKey: rotateProxies || wantsBranding || body.browserFallback || body.kernelFallback ? browserServiceApiKey() : void 0,
|
|
28572
28761
|
formats: body.formats,
|
|
28573
28762
|
...rotateProxies ? {
|
|
@@ -28575,8 +28764,25 @@ app.post("/extract-site", auth2, async (c) => {
|
|
|
28575
28764
|
parallelism: concurrencyLimitForUser(user)
|
|
28576
28765
|
} : {}
|
|
28577
28766
|
});
|
|
28767
|
+
if (waybackReplay) {
|
|
28768
|
+
result.startUrl = waybackReplay.originalUrl;
|
|
28769
|
+
result.pages = result.pages.map((page) => {
|
|
28770
|
+
const replay = parseWaybackReplayUrl(page.url);
|
|
28771
|
+
return replay ? {
|
|
28772
|
+
...page,
|
|
28773
|
+
archivedUrl: page.url,
|
|
28774
|
+
archiveTimestamp: replay.timestamp,
|
|
28775
|
+
originalUrl: replay.originalUrl,
|
|
28776
|
+
url: replay.originalUrl,
|
|
28777
|
+
finalUrl: replay.originalUrl
|
|
28778
|
+
} : page;
|
|
28779
|
+
});
|
|
28780
|
+
}
|
|
28578
28781
|
const pageCount = result.pages?.length ?? 1;
|
|
28579
|
-
const
|
|
28782
|
+
const successfulPageCount = result.pages.filter(
|
|
28783
|
+
(page) => page.status != null && page.status >= 200 && page.status < 300 && page.wordCount > 0
|
|
28784
|
+
).length;
|
|
28785
|
+
const actualSiteMc = successfulPageCount * MC_COSTS.page_scrape;
|
|
28580
28786
|
const siteDiff = siteHoldMc - actualSiteMc;
|
|
28581
28787
|
if (siteDiff > 0) await creditMc(user.id, siteDiff, LedgerOperation.EXTRACT_SITE_REFUND, "overestimate refund");
|
|
28582
28788
|
else if (siteDiff < 0) await debitMc(user.id, -siteDiff, LedgerOperation.EXTRACT_SITE, parsed.hostname);
|
|
@@ -28689,15 +28895,25 @@ app.post("/billing/subscribe", requireAllowedOrigin, sessionAuth, async (c) => {
|
|
|
28689
28895
|
customerId = customer.id;
|
|
28690
28896
|
await setStripeCustomerId(user.id, customerId);
|
|
28691
28897
|
}
|
|
28692
|
-
|
|
28693
|
-
|
|
28898
|
+
let existingSubId = user.subscription_id;
|
|
28899
|
+
if (!existingSubId) {
|
|
28900
|
+
try {
|
|
28901
|
+
const active = await stripeClient.subscriptions.list({ customer: customerId, status: "active", limit: 20 });
|
|
28902
|
+
const baseSub = active.data.find((s) => findBasePlanItem(s));
|
|
28903
|
+
if (baseSub) existingSubId = baseSub.id;
|
|
28904
|
+
} catch (err) {
|
|
28905
|
+
console.warn("[billing/subscribe] could not check for existing subscription", err instanceof Error ? err.message : err);
|
|
28906
|
+
}
|
|
28907
|
+
}
|
|
28908
|
+
if (existingSubId) {
|
|
28909
|
+
const sub = await stripeClient.subscriptions.retrieve(existingSubId);
|
|
28694
28910
|
const itemId = findBasePlanItem(sub)?.id;
|
|
28695
28911
|
if (itemId) {
|
|
28696
|
-
await stripeClient.subscriptions.update(
|
|
28912
|
+
await stripeClient.subscriptions.update(existingSubId, {
|
|
28697
28913
|
items: [{ id: itemId, price: tier.price_id }],
|
|
28698
28914
|
proration_behavior: "create_prorations"
|
|
28699
28915
|
});
|
|
28700
|
-
const billed = await chargeTierChangeNow(stripeClient,
|
|
28916
|
+
const billed = await chargeTierChangeNow(stripeClient, existingSubId, customerId);
|
|
28701
28917
|
if (!billed.ok) {
|
|
28702
28918
|
return c.json({
|
|
28703
28919
|
updated: true,
|
|
@@ -28815,15 +29031,25 @@ app.post("/billing/subscribe/terminal-checkout", auth2, async (c) => {
|
|
|
28815
29031
|
customerId = customer.id;
|
|
28816
29032
|
await setStripeCustomerId(user.id, customerId);
|
|
28817
29033
|
}
|
|
28818
|
-
|
|
28819
|
-
|
|
29034
|
+
let existingSubId = user.subscription_id;
|
|
29035
|
+
if (!existingSubId) {
|
|
29036
|
+
try {
|
|
29037
|
+
const active = await stripeClient.subscriptions.list({ customer: customerId, status: "active", limit: 20 });
|
|
29038
|
+
const baseSub = active.data.find((s) => findBasePlanItem(s));
|
|
29039
|
+
if (baseSub) existingSubId = baseSub.id;
|
|
29040
|
+
} catch (err) {
|
|
29041
|
+
console.warn("[billing/subscribe] could not check for existing subscription", err instanceof Error ? err.message : err);
|
|
29042
|
+
}
|
|
29043
|
+
}
|
|
29044
|
+
if (existingSubId) {
|
|
29045
|
+
const sub = await stripeClient.subscriptions.retrieve(existingSubId);
|
|
28820
29046
|
const itemId = findBasePlanItem(sub)?.id;
|
|
28821
29047
|
if (itemId) {
|
|
28822
|
-
await stripeClient.subscriptions.update(
|
|
29048
|
+
await stripeClient.subscriptions.update(existingSubId, {
|
|
28823
29049
|
items: [{ id: itemId, price: tier.price_id }],
|
|
28824
29050
|
proration_behavior: "create_prorations"
|
|
28825
29051
|
});
|
|
28826
|
-
const billed = await chargeTierChangeNow(stripeClient,
|
|
29052
|
+
const billed = await chargeTierChangeNow(stripeClient, existingSubId, customerId);
|
|
28827
29053
|
if (!billed.ok) {
|
|
28828
29054
|
return c.json({
|
|
28829
29055
|
updated: true,
|
|
@@ -28937,7 +29163,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
28937
29163
|
if (!process.env.CRON_SECRET || secret2 !== `Bearer ${process.env.CRON_SECRET}`) {
|
|
28938
29164
|
return c.json({ error: "Unauthorized" }, 401);
|
|
28939
29165
|
}
|
|
28940
|
-
const { drainQueue } = await import("./worker-
|
|
29166
|
+
const { drainQueue } = await import("./worker-645BZPEK.js");
|
|
28941
29167
|
const budget = { maxJobs: 10, deadlineMs: Date.now() + 28e4 };
|
|
28942
29168
|
const workflowDispatchResult = await dispatchDueWorkflowSchedules(`${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`);
|
|
28943
29169
|
const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup] = await Promise.all([
|
|
@@ -28965,15 +29191,15 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
|
|
|
28965
29191
|
return c.json({ error: "Unauthorized" }, 401);
|
|
28966
29192
|
}
|
|
28967
29193
|
const jobId = c.req.param("id");
|
|
28968
|
-
const { getExtractJob: getExtractJob2, completeExtractJob: completeExtractJob2 } = await import("./site-extract-repository-
|
|
28969
|
-
const { assembleExtractArtifacts } = await import("./extract-bundle-
|
|
29194
|
+
const { getExtractJob: getExtractJob2, completeExtractJob: completeExtractJob2 } = await import("./site-extract-repository-L6BHWVDU.js");
|
|
29195
|
+
const { assembleExtractArtifacts } = await import("./extract-bundle-ONWZVV55.js");
|
|
28970
29196
|
const job = await getExtractJob2(jobId);
|
|
28971
29197
|
if (!job) return c.json({ error: "job not found" }, 404);
|
|
28972
29198
|
const stored = await assembleExtractArtifacts(job, {});
|
|
28973
29199
|
await completeExtractJob2(jobId, stored);
|
|
28974
29200
|
let settlement = "already_settled_or_refunded";
|
|
28975
29201
|
if (job.billedMc == null && job.userId != null) {
|
|
28976
|
-
const { settleExtractJob: settleExtractJob2, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-
|
|
29202
|
+
const { settleExtractJob: settleExtractJob2, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-L6BHWVDU.js");
|
|
28977
29203
|
const heldMc = Number(job.options.heldMc ?? 0);
|
|
28978
29204
|
const successful = await countSuccessfulPages2(jobId);
|
|
28979
29205
|
const usedMc = Math.min(successful * MC_COSTS.page_scrape, heldMc);
|
|
@@ -29142,4 +29368,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
29142
29368
|
export {
|
|
29143
29369
|
app
|
|
29144
29370
|
};
|
|
29145
|
-
//# sourceMappingURL=server-
|
|
29371
|
+
//# sourceMappingURL=server-GKUTC73B.js.map
|