mcp-scraper 0.3.19 → 0.3.21
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/dist/bin/api-server.cjs +219 -164
- 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 +2 -2
- package/dist/{chunk-5H22TOXQ.js → chunk-3KYRG7O7.js} +130 -7
- package/dist/chunk-3KYRG7O7.js.map +1 -0
- package/dist/{chunk-T337IGVE.js → chunk-7PQFU7TV.js} +13 -20
- package/dist/chunk-7PQFU7TV.js.map +1 -0
- package/dist/chunk-J4PSMJNZ.js +7 -0
- package/dist/chunk-J4PSMJNZ.js.map +1 -0
- package/dist/{chunk-A46NKAAM.js → chunk-UO252634.js} +2 -2
- package/dist/{db-P76GVIFN.js → db-EG5ETPTY.js} +12 -2
- package/dist/{server-EYNMXWUJ.js → server-K4UIE2R3.js} +88 -144
- package/dist/server-K4UIE2R3.js.map +1 -0
- package/dist/{worker-YZ2ZJE4F.js → worker-AITQTXHM.js} +3 -3
- package/docs/mcp-tool-manifest.generated.json +1 -1
- package/package.json +1 -1
- package/dist/chunk-5H22TOXQ.js.map +0 -1
- package/dist/chunk-AUKOY2IV.js +0 -7
- package/dist/chunk-AUKOY2IV.js.map +0 -1
- package/dist/chunk-T337IGVE.js.map +0 -1
- package/dist/server-EYNMXWUJ.js.map +0 -1
- /package/dist/{chunk-A46NKAAM.js.map → chunk-UO252634.js.map} +0 -0
- /package/dist/{db-P76GVIFN.js.map → db-EG5ETPTY.js.map} +0 -0
- /package/dist/{worker-YZ2ZJE4F.js.map → worker-AITQTXHM.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
CREDIT_LOT_TTL,
|
|
2
3
|
SiteAuditJobRowSchema,
|
|
3
4
|
SiteAuditPhaseLogRowSchema,
|
|
4
5
|
advanceWorkflowRunStep,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
deactivateUser,
|
|
26
27
|
debitMc,
|
|
27
28
|
deleteWorkflowSchedule,
|
|
29
|
+
expireOldLots,
|
|
28
30
|
failJob,
|
|
29
31
|
failKpoJob,
|
|
30
32
|
failWorkflowRunRecord,
|
|
@@ -62,6 +64,7 @@ import {
|
|
|
62
64
|
markWorkflowRunRunning,
|
|
63
65
|
markWorkflowScheduleRan,
|
|
64
66
|
migrate,
|
|
67
|
+
migrateExistingBalancesToLots,
|
|
65
68
|
patchWorkflowSchedule,
|
|
66
69
|
reconcileBalanceMc,
|
|
67
70
|
recordStripeEvent,
|
|
@@ -70,15 +73,18 @@ import {
|
|
|
70
73
|
revokeApiKey,
|
|
71
74
|
rotateApiKey,
|
|
72
75
|
setConcurrencySubId,
|
|
76
|
+
setDbForTesting,
|
|
73
77
|
setExtraConcurrencySlots,
|
|
74
78
|
setPassword,
|
|
75
79
|
setStripeCustomerId,
|
|
80
|
+
setSubscriptionTier,
|
|
76
81
|
startHarvestAttempt,
|
|
77
82
|
stripeEventAlreadyProcessed,
|
|
78
83
|
updateKpoJobState,
|
|
79
84
|
verifyPassword
|
|
80
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-3KYRG7O7.js";
|
|
81
86
|
export {
|
|
87
|
+
CREDIT_LOT_TTL,
|
|
82
88
|
SiteAuditJobRowSchema,
|
|
83
89
|
SiteAuditPhaseLogRowSchema,
|
|
84
90
|
advanceWorkflowRunStep,
|
|
@@ -105,6 +111,7 @@ export {
|
|
|
105
111
|
deactivateUser,
|
|
106
112
|
debitMc,
|
|
107
113
|
deleteWorkflowSchedule,
|
|
114
|
+
expireOldLots,
|
|
108
115
|
failJob,
|
|
109
116
|
failKpoJob,
|
|
110
117
|
failWorkflowRunRecord,
|
|
@@ -142,6 +149,7 @@ export {
|
|
|
142
149
|
markWorkflowRunRunning,
|
|
143
150
|
markWorkflowScheduleRan,
|
|
144
151
|
migrate,
|
|
152
|
+
migrateExistingBalancesToLots,
|
|
145
153
|
patchWorkflowSchedule,
|
|
146
154
|
reconcileBalanceMc,
|
|
147
155
|
recordStripeEvent,
|
|
@@ -150,12 +158,14 @@ export {
|
|
|
150
158
|
revokeApiKey,
|
|
151
159
|
rotateApiKey,
|
|
152
160
|
setConcurrencySubId,
|
|
161
|
+
setDbForTesting,
|
|
153
162
|
setExtraConcurrencySlots,
|
|
154
163
|
setPassword,
|
|
155
164
|
setStripeCustomerId,
|
|
165
|
+
setSubscriptionTier,
|
|
156
166
|
startHarvestAttempt,
|
|
157
167
|
stripeEventAlreadyProcessed,
|
|
158
168
|
updateKpoJobState,
|
|
159
169
|
verifyPassword
|
|
160
170
|
};
|
|
161
|
-
//# sourceMappingURL=db-
|
|
171
|
+
//# sourceMappingURL=db-EG5ETPTY.js.map
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
renderLinkReport,
|
|
22
22
|
sanitizeAttempts,
|
|
23
23
|
sanitizeHarvestResult
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-UO252634.js";
|
|
25
25
|
import {
|
|
26
26
|
csvRecords,
|
|
27
27
|
listWorkflowDefinitions,
|
|
@@ -33,18 +33,16 @@ import {
|
|
|
33
33
|
workflowStepCount,
|
|
34
34
|
workflowSupportsSteps
|
|
35
35
|
} from "./chunk-H2R232HK.js";
|
|
36
|
-
import "./chunk-
|
|
36
|
+
import "./chunk-J4PSMJNZ.js";
|
|
37
37
|
import {
|
|
38
|
-
BALANCE_PACK_LABELS,
|
|
39
|
-
BALANCE_PRICE_IDS,
|
|
40
38
|
BROWSER_OPEN_MIN_BALANCE_MC,
|
|
41
39
|
CONCURRENCY_PRICE_ID,
|
|
42
40
|
CREDIT_COST_CATALOG,
|
|
43
|
-
FREE_MONTHLY_REFRESH_MC,
|
|
44
|
-
FREE_SIGNUP_MC,
|
|
45
41
|
LedgerOperation,
|
|
46
42
|
MC_COSTS,
|
|
47
43
|
MC_PER_CREDIT,
|
|
44
|
+
SUBSCRIPTION_TIERS,
|
|
45
|
+
SUBSCRIPTION_TIER_BY_KEY,
|
|
48
46
|
browserActiveCostMc,
|
|
49
47
|
classifyHarvestProblem,
|
|
50
48
|
concurrencySlotBillingInfo,
|
|
@@ -52,7 +50,7 @@ import {
|
|
|
52
50
|
harvestProblemResponse,
|
|
53
51
|
insufficientBalanceResponse,
|
|
54
52
|
serializeHarvestProblem
|
|
55
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-7PQFU7TV.js";
|
|
56
54
|
import {
|
|
57
55
|
BrowserDriver,
|
|
58
56
|
MapsSelectors,
|
|
@@ -86,7 +84,6 @@ import {
|
|
|
86
84
|
appendWorkflowArtifacts,
|
|
87
85
|
cancelJob,
|
|
88
86
|
checkRateLimit,
|
|
89
|
-
claimMonthlyFreeRefresh,
|
|
90
87
|
completeJob,
|
|
91
88
|
completeWorkflowRunRecord,
|
|
92
89
|
consumePasswordResetToken,
|
|
@@ -101,6 +98,7 @@ import {
|
|
|
101
98
|
deactivateUser,
|
|
102
99
|
debitMc,
|
|
103
100
|
deleteWorkflowSchedule,
|
|
101
|
+
expireOldLots,
|
|
104
102
|
failJob,
|
|
105
103
|
failWorkflowRunRecord,
|
|
106
104
|
getDb,
|
|
@@ -139,8 +137,9 @@ import {
|
|
|
139
137
|
setExtraConcurrencySlots,
|
|
140
138
|
setPassword,
|
|
141
139
|
setStripeCustomerId,
|
|
140
|
+
setSubscriptionTier,
|
|
142
141
|
verifyPassword
|
|
143
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-3KYRG7O7.js";
|
|
144
143
|
|
|
145
144
|
// src/blog/registry.ts
|
|
146
145
|
var posts = [
|
|
@@ -9044,7 +9043,8 @@ var DEFAULT_RETRY_AFTER_SECONDS = 30;
|
|
|
9044
9043
|
var MAX_LOCK_TTL_SECONDS = 24 * 60 * 60;
|
|
9045
9044
|
var schemaReady = null;
|
|
9046
9045
|
function concurrencyLimitForUser(user) {
|
|
9047
|
-
|
|
9046
|
+
const tier = Math.max(0, Number(user.subscription_concurrency ?? 0));
|
|
9047
|
+
return Math.max(1, tier) + Math.max(0, Number(user.extra_concurrency_slots ?? 0));
|
|
9048
9048
|
}
|
|
9049
9049
|
function concurrencyLimitExceededResponse(gate) {
|
|
9050
9050
|
const upgrade = concurrencySlotBillingInfo();
|
|
@@ -16457,49 +16457,58 @@ stripeApp.post("/webhooks", async (c) => {
|
|
|
16457
16457
|
}
|
|
16458
16458
|
const isNew = await recordStripeEvent(event.id);
|
|
16459
16459
|
if (!isNew) return c.json({ received: true });
|
|
16460
|
-
if (event.type === "
|
|
16461
|
-
const
|
|
16462
|
-
|
|
16463
|
-
|
|
16464
|
-
|
|
16465
|
-
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
const label = BALANCE_PACK_LABELS[priceId] ?? "unknown";
|
|
16470
|
-
let user = await getUserByStripeCustomerId(customerId);
|
|
16471
|
-
if (!user) {
|
|
16472
|
-
const email = session.customer_details?.email;
|
|
16473
|
-
if (!email) return c.json({ received: true });
|
|
16474
|
-
user = await getUserByEmail(email);
|
|
16475
|
-
if (!user) return c.json({ received: true });
|
|
16476
|
-
await setStripeCustomerId(user.id, customerId);
|
|
16460
|
+
if (event.type === "invoice.paid" || event.type === "invoice.payment_succeeded") {
|
|
16461
|
+
const invoice = event.data.object;
|
|
16462
|
+
const lineTierId = invoice.lines.data.map(linePriceId).find((id) => id && id in SUBSCRIPTION_TIERS);
|
|
16463
|
+
if (lineTierId) {
|
|
16464
|
+
const tier = SUBSCRIPTION_TIERS[lineTierId];
|
|
16465
|
+
const user = await resolveUser(invoice.customer, invoice.customer_email ?? void 0);
|
|
16466
|
+
if (user && invoice.id && !await ledgerExistsForStripePI(invoice.id)) {
|
|
16467
|
+
await creditMc(user.id, tier.credits_mc, LedgerOperation.SUBSCRIPTION, `${tier.label} subscription credits`, invoice.id);
|
|
16468
|
+
await setSubscriptionTier(user.id, tier.tier, tier.concurrency, invoice.subscription ?? user.subscription_id);
|
|
16477
16469
|
}
|
|
16478
|
-
const pi = session.payment_intent;
|
|
16479
|
-
if (await ledgerExistsForStripePI(pi)) return c.json({ received: true });
|
|
16480
|
-
await creditMc(user.id, mc, LedgerOperation.TOPUP, `${label} balance top-up`, pi);
|
|
16481
16470
|
}
|
|
16482
16471
|
}
|
|
16483
|
-
if (event.type === "customer.subscription.created") {
|
|
16472
|
+
if (event.type === "customer.subscription.created" || event.type === "customer.subscription.updated") {
|
|
16484
16473
|
const sub = event.data.object;
|
|
16485
16474
|
const priceId = sub.items.data[0]?.price?.id;
|
|
16486
|
-
if (priceId !== CONCURRENCY_PRICE_ID) return c.json({ received: true });
|
|
16487
16475
|
const user = await getUserByStripeCustomerId(sub.customer);
|
|
16488
16476
|
if (!user) return c.json({ received: true });
|
|
16489
|
-
|
|
16490
|
-
|
|
16477
|
+
if (priceId && priceId in SUBSCRIPTION_TIERS) {
|
|
16478
|
+
const tier = SUBSCRIPTION_TIERS[priceId];
|
|
16479
|
+
const live = sub.status === "active" || sub.status === "trialing";
|
|
16480
|
+
await setSubscriptionTier(user.id, live ? tier.tier : null, live ? tier.concurrency : 0, live ? sub.id : null);
|
|
16481
|
+
} else if (priceId === CONCURRENCY_PRICE_ID && event.type === "customer.subscription.created") {
|
|
16482
|
+
await setExtraConcurrencySlots(user.id, user.extra_concurrency_slots + 1);
|
|
16483
|
+
await setConcurrencySubId(user.id, sub.id);
|
|
16484
|
+
}
|
|
16491
16485
|
}
|
|
16492
16486
|
if (event.type === "customer.subscription.deleted") {
|
|
16493
16487
|
const sub = event.data.object;
|
|
16494
16488
|
const priceId = sub.items.data[0]?.price?.id;
|
|
16495
|
-
if (priceId !== CONCURRENCY_PRICE_ID) return c.json({ received: true });
|
|
16496
16489
|
const user = await getUserByStripeCustomerId(sub.customer);
|
|
16497
16490
|
if (!user) return c.json({ received: true });
|
|
16498
|
-
|
|
16499
|
-
|
|
16491
|
+
if (priceId && priceId in SUBSCRIPTION_TIERS) {
|
|
16492
|
+
await setSubscriptionTier(user.id, null, 0, null);
|
|
16493
|
+
} else if (priceId === CONCURRENCY_PRICE_ID) {
|
|
16494
|
+
await setExtraConcurrencySlots(user.id, Math.max(0, user.extra_concurrency_slots - 1));
|
|
16495
|
+
await setConcurrencySubId(user.id, null);
|
|
16496
|
+
}
|
|
16500
16497
|
}
|
|
16501
16498
|
return c.json({ received: true });
|
|
16502
16499
|
});
|
|
16500
|
+
function linePriceId(line) {
|
|
16501
|
+
const l = line;
|
|
16502
|
+
return l?.price?.id ?? l?.pricing?.price_details?.price ?? l?.plan?.id;
|
|
16503
|
+
}
|
|
16504
|
+
async function resolveUser(customerId, emailFallback) {
|
|
16505
|
+
let user = await getUserByStripeCustomerId(customerId);
|
|
16506
|
+
if (user) return user;
|
|
16507
|
+
if (!emailFallback) return void 0;
|
|
16508
|
+
user = await getUserByEmail(emailFallback);
|
|
16509
|
+
if (user) await setStripeCustomerId(user.id, customerId);
|
|
16510
|
+
return user;
|
|
16511
|
+
}
|
|
16503
16512
|
|
|
16504
16513
|
// src/api/site-audit-worker.ts
|
|
16505
16514
|
var MAX_CONCURRENT_SITE_AUDIT = 1;
|
|
@@ -16539,96 +16548,15 @@ import { createMiddleware as createMiddleware3 } from "hono/factory";
|
|
|
16539
16548
|
import { getCookie, setCookie, deleteCookie } from "hono/cookie";
|
|
16540
16549
|
import Stripe2 from "stripe";
|
|
16541
16550
|
|
|
16542
|
-
// src/api/billing-schemas.ts
|
|
16543
|
-
import { z as z19 } from "zod";
|
|
16544
|
-
var BillingCheckoutBodySchema = z19.object({
|
|
16545
|
-
priceId: z19.string().min(1)
|
|
16546
|
-
});
|
|
16547
|
-
var FreeCreditBreakdownSchema = z19.object({
|
|
16548
|
-
signup_grant_mc: z19.number().int().nonnegative(),
|
|
16549
|
-
monthly_refresh_mc: z19.number().int().nonnegative(),
|
|
16550
|
-
total_free_mc: z19.number().int().nonnegative(),
|
|
16551
|
-
signup_grant_credits: z19.number().nonnegative(),
|
|
16552
|
-
monthly_refresh_credits: z19.number().nonnegative(),
|
|
16553
|
-
total_free_credits: z19.number().nonnegative()
|
|
16554
|
-
});
|
|
16555
|
-
var BillingBalanceResponseSchema = z19.object({
|
|
16556
|
-
balance_mc: z19.number().int().nonnegative(),
|
|
16557
|
-
balance_credits: z19.number().nonnegative(),
|
|
16558
|
-
free_credits: FreeCreditBreakdownSchema,
|
|
16559
|
-
ledger: z19.array(z19.any())
|
|
16560
|
-
});
|
|
16561
|
-
var MonthlyRefreshSweepResultSchema = z19.object({
|
|
16562
|
-
usersRefreshed: z19.number().int().nonnegative(),
|
|
16563
|
-
totalMcGranted: z19.number().int().nonnegative()
|
|
16564
|
-
});
|
|
16565
|
-
|
|
16566
16551
|
// src/api/credit-operations.ts
|
|
16567
|
-
function
|
|
16568
|
-
return
|
|
16569
|
-
}
|
|
16570
|
-
function userCreatedBeforeThisMonth(user) {
|
|
16571
|
-
return user.created_at.slice(0, 7) < monthKey();
|
|
16572
|
-
}
|
|
16573
|
-
async function grantSignupCredit(userId) {
|
|
16574
|
-
if (await ledgerExistsForOperation(userId, LedgerOperation.SIGNUP_GRANT)) return;
|
|
16575
|
-
await creditMc(userId, FREE_SIGNUP_MC, LedgerOperation.SIGNUP_GRANT, "Welcome to MCP Scraper");
|
|
16552
|
+
async function grantSignupCredit(_userId) {
|
|
16553
|
+
return;
|
|
16576
16554
|
}
|
|
16577
16555
|
async function applyMonthlyFreeRefresh(user) {
|
|
16578
|
-
|
|
16579
|
-
const claimed = await claimMonthlyFreeRefresh(user.id, monthKey());
|
|
16580
|
-
if (!claimed) return user;
|
|
16581
|
-
const balance = await creditMc(
|
|
16582
|
-
user.id,
|
|
16583
|
-
FREE_MONTHLY_REFRESH_MC,
|
|
16584
|
-
LedgerOperation.MONTHLY_REFRESH,
|
|
16585
|
-
"Monthly free credits"
|
|
16586
|
-
);
|
|
16587
|
-
return { ...user, balance_mc: balance };
|
|
16556
|
+
return user;
|
|
16588
16557
|
}
|
|
16589
16558
|
async function runMonthlyRefreshSweep() {
|
|
16590
|
-
|
|
16591
|
-
const monthStart = /* @__PURE__ */ new Date();
|
|
16592
|
-
monthStart.setUTCDate(1);
|
|
16593
|
-
monthStart.setUTCHours(0, 0, 0, 0);
|
|
16594
|
-
const monthStartIso = monthStart.toISOString();
|
|
16595
|
-
const currentMonth = monthKey();
|
|
16596
|
-
const res = await db.execute({
|
|
16597
|
-
sql: `
|
|
16598
|
-
SELECT * FROM users
|
|
16599
|
-
WHERE created_at < ?
|
|
16600
|
-
AND active = 1
|
|
16601
|
-
AND id NOT IN (
|
|
16602
|
-
SELECT user_id FROM free_credit_refreshes WHERE month = ?
|
|
16603
|
-
)
|
|
16604
|
-
`,
|
|
16605
|
-
args: [monthStartIso, currentMonth]
|
|
16606
|
-
});
|
|
16607
|
-
const users = res.rows.map((r) => ({
|
|
16608
|
-
id: Number(r.id),
|
|
16609
|
-
email: String(r.email),
|
|
16610
|
-
name: r.name != null ? String(r.name) : null,
|
|
16611
|
-
api_key: String(r.api_key ?? ""),
|
|
16612
|
-
key_active: Number(r.key_active ?? 1),
|
|
16613
|
-
password_hash: r.password_hash != null ? String(r.password_hash) : null,
|
|
16614
|
-
created_at: String(r.created_at),
|
|
16615
|
-
active: Number(r.active),
|
|
16616
|
-
stripe_customer_id: r.stripe_customer_id != null ? String(r.stripe_customer_id) : null,
|
|
16617
|
-
balance_mc: Number(r.balance_mc ?? 0),
|
|
16618
|
-
extra_concurrency_slots: Number(r.extra_concurrency_slots ?? 0),
|
|
16619
|
-
concurrency_stripe_sub_id: r.concurrency_stripe_sub_id != null ? String(r.concurrency_stripe_sub_id) : null
|
|
16620
|
-
}));
|
|
16621
|
-
let usersRefreshed = 0;
|
|
16622
|
-
let totalMcGranted = 0;
|
|
16623
|
-
for (const user of users) {
|
|
16624
|
-
const before = user.balance_mc;
|
|
16625
|
-
const after = await applyMonthlyFreeRefresh(user);
|
|
16626
|
-
if (after.balance_mc !== before) {
|
|
16627
|
-
usersRefreshed++;
|
|
16628
|
-
totalMcGranted += FREE_MONTHLY_REFRESH_MC;
|
|
16629
|
-
}
|
|
16630
|
-
}
|
|
16631
|
-
return { usersRefreshed, totalMcGranted };
|
|
16559
|
+
return { usersRefreshed: 0, totalMcGranted: 0 };
|
|
16632
16560
|
}
|
|
16633
16561
|
async function getFreeCreditBreakdown(userId) {
|
|
16634
16562
|
const res = await getDb().execute({
|
|
@@ -16932,8 +16860,10 @@ app.get("/me", async (c) => {
|
|
|
16932
16860
|
balance_mc: user.balance_mc,
|
|
16933
16861
|
balance_credits: user.balance_mc / 1e3,
|
|
16934
16862
|
extra_concurrency_slots: user.extra_concurrency_slots,
|
|
16935
|
-
concurrency_limit:
|
|
16863
|
+
concurrency_limit: concurrencyLimitForUser(user),
|
|
16936
16864
|
has_concurrency_sub: !!user.concurrency_stripe_sub_id,
|
|
16865
|
+
subscription_tier: user.subscription_tier,
|
|
16866
|
+
subscription_concurrency: user.subscription_concurrency,
|
|
16937
16867
|
...stats
|
|
16938
16868
|
});
|
|
16939
16869
|
});
|
|
@@ -17398,13 +17328,12 @@ app.get("/extract-site/status/:id", auth2, async (c) => {
|
|
|
17398
17328
|
});
|
|
17399
17329
|
});
|
|
17400
17330
|
app.post("/billing/checkout", requireAllowedOrigin, sessionAuth, async (c) => {
|
|
17331
|
+
return c.json({ error: "One-time credit packs are no longer available. Subscribe to a plan instead \u2014 use /billing/subscribe.", error_code: "packs_removed" }, 410);
|
|
17332
|
+
});
|
|
17333
|
+
app.post("/billing/concurrency/checkout", requireAllowedOrigin, sessionAuth, async (c) => {
|
|
17401
17334
|
try {
|
|
17402
17335
|
const user = c.get("sessionUser");
|
|
17403
|
-
|
|
17404
|
-
const parsed = BillingCheckoutBodySchema.safeParse(raw);
|
|
17405
|
-
if (!parsed.success) return c.json({ error: "Invalid request" }, 400);
|
|
17406
|
-
const { priceId } = parsed.data;
|
|
17407
|
-
if (!(priceId in BALANCE_PRICE_IDS)) return c.json({ error: "Invalid price" }, 400);
|
|
17336
|
+
if (user.concurrency_stripe_sub_id) return c.json({ error: "Already subscribed \u2014 cancel existing slot first to change." }, 409);
|
|
17408
17337
|
const secret2 = process.env.STRIPE_SECRET_KEY?.trim();
|
|
17409
17338
|
if (!secret2) return c.json({ error: "Stripe is not configured." }, 503);
|
|
17410
17339
|
const stripeClient = new Stripe2(secret2, { apiVersion: STRIPE_API_VERSION });
|
|
@@ -17416,26 +17345,28 @@ app.post("/billing/checkout", requireAllowedOrigin, sessionAuth, async (c) => {
|
|
|
17416
17345
|
}
|
|
17417
17346
|
const session = await stripeClient.checkout.sessions.create({
|
|
17418
17347
|
customer: customerId,
|
|
17419
|
-
mode: "
|
|
17420
|
-
line_items: [{ price:
|
|
17348
|
+
mode: "subscription",
|
|
17349
|
+
line_items: [{ price: CONCURRENCY_PRICE_ID, quantity: 1 }],
|
|
17421
17350
|
ui_mode: "embedded",
|
|
17422
17351
|
automatic_tax: { enabled: true },
|
|
17423
17352
|
billing_address_collection: "required",
|
|
17424
17353
|
customer_update: { address: "auto", name: "auto" },
|
|
17425
17354
|
tax_id_collection: { enabled: true },
|
|
17426
|
-
return_url: `${appOrigin()}/billing?
|
|
17355
|
+
return_url: `${appOrigin()}/billing?slot_added=1`
|
|
17427
17356
|
});
|
|
17428
17357
|
return c.json({ clientSecret: session.client_secret });
|
|
17429
17358
|
} catch (err) {
|
|
17430
17359
|
const message = err instanceof Error ? err.message : "Unable to start checkout.";
|
|
17431
|
-
console.error("[billing/checkout]", message);
|
|
17360
|
+
console.error("[billing/concurrency/checkout]", message);
|
|
17432
17361
|
return c.json({ error: message }, 500);
|
|
17433
17362
|
}
|
|
17434
17363
|
});
|
|
17435
|
-
app.post("/billing/
|
|
17364
|
+
app.post("/billing/subscribe", requireAllowedOrigin, sessionAuth, async (c) => {
|
|
17436
17365
|
try {
|
|
17437
17366
|
const user = c.get("sessionUser");
|
|
17438
|
-
|
|
17367
|
+
const raw = await c.req.json().catch(() => ({}));
|
|
17368
|
+
const tier = SUBSCRIPTION_TIER_BY_KEY[String(raw.tier ?? "")];
|
|
17369
|
+
if (!tier) return c.json({ error: "Invalid tier. Choose starter, growth, or scale." }, 400);
|
|
17439
17370
|
const secret2 = process.env.STRIPE_SECRET_KEY?.trim();
|
|
17440
17371
|
if (!secret2) return c.json({ error: "Stripe is not configured." }, 503);
|
|
17441
17372
|
const stripeClient = new Stripe2(secret2, { apiVersion: STRIPE_API_VERSION });
|
|
@@ -17445,21 +17376,33 @@ app.post("/billing/concurrency/checkout", requireAllowedOrigin, sessionAuth, asy
|
|
|
17445
17376
|
customerId = customer.id;
|
|
17446
17377
|
await setStripeCustomerId(user.id, customerId);
|
|
17447
17378
|
}
|
|
17379
|
+
if (user.subscription_id) {
|
|
17380
|
+
const sub = await stripeClient.subscriptions.retrieve(user.subscription_id);
|
|
17381
|
+
const itemId = sub.items.data[0]?.id;
|
|
17382
|
+
if (itemId) {
|
|
17383
|
+
await stripeClient.subscriptions.update(user.subscription_id, {
|
|
17384
|
+
items: [{ id: itemId, price: tier.price_id }],
|
|
17385
|
+
proration_behavior: "create_prorations"
|
|
17386
|
+
});
|
|
17387
|
+
return c.json({ updated: true, tier: tier.tier });
|
|
17388
|
+
}
|
|
17389
|
+
}
|
|
17448
17390
|
const session = await stripeClient.checkout.sessions.create({
|
|
17449
17391
|
customer: customerId,
|
|
17450
17392
|
mode: "subscription",
|
|
17451
|
-
line_items: [{ price:
|
|
17393
|
+
line_items: [{ price: tier.price_id, quantity: 1 }],
|
|
17394
|
+
...tier.intro_coupon ? { discounts: [{ coupon: tier.intro_coupon }] } : {},
|
|
17452
17395
|
ui_mode: "embedded",
|
|
17453
17396
|
automatic_tax: { enabled: true },
|
|
17454
17397
|
billing_address_collection: "required",
|
|
17455
17398
|
customer_update: { address: "auto", name: "auto" },
|
|
17456
17399
|
tax_id_collection: { enabled: true },
|
|
17457
|
-
return_url: `${appOrigin()}/billing?
|
|
17400
|
+
return_url: `${appOrigin()}/billing?subscribed=${tier.tier}`
|
|
17458
17401
|
});
|
|
17459
17402
|
return c.json({ clientSecret: session.client_secret });
|
|
17460
17403
|
} catch (err) {
|
|
17461
|
-
const message = err instanceof Error ? err.message : "Unable to start
|
|
17462
|
-
console.error("[billing/
|
|
17404
|
+
const message = err instanceof Error ? err.message : "Unable to start subscription.";
|
|
17405
|
+
console.error("[billing/subscribe]", message);
|
|
17463
17406
|
return c.json({ error: message }, 500);
|
|
17464
17407
|
}
|
|
17465
17408
|
});
|
|
@@ -17507,7 +17450,7 @@ app.post("/billing/concurrency/terminal-checkout", auth2, async (c) => {
|
|
|
17507
17450
|
current_extra_slots: user.extra_concurrency_slots,
|
|
17508
17451
|
current_limit: concurrencyLimitForUser(user),
|
|
17509
17452
|
after_checkout_extra_slots: user.extra_concurrency_slots + 1,
|
|
17510
|
-
after_checkout_limit: concurrencyLimitForUser({ extra_concurrency_slots: user.extra_concurrency_slots + 1 })
|
|
17453
|
+
after_checkout_limit: concurrencyLimitForUser({ extra_concurrency_slots: user.extra_concurrency_slots + 1, subscription_concurrency: user.subscription_concurrency })
|
|
17511
17454
|
},
|
|
17512
17455
|
next_step: "Open checkout_url in a browser, complete checkout, then restart or retry the MCP request."
|
|
17513
17456
|
});
|
|
@@ -17576,15 +17519,16 @@ app.get("/cron/tick", async (c) => {
|
|
|
17576
17519
|
if (!process.env.CRON_SECRET || secret2 !== `Bearer ${process.env.CRON_SECRET}`) {
|
|
17577
17520
|
return c.json({ error: "Unauthorized" }, 401);
|
|
17578
17521
|
}
|
|
17579
|
-
const { drainQueue } = await import("./worker-
|
|
17522
|
+
const { drainQueue } = await import("./worker-AITQTXHM.js");
|
|
17580
17523
|
const budget = { maxJobs: 10, deadlineMs: Date.now() + 28e4 };
|
|
17581
17524
|
const workflowDispatchResult = await dispatchDueWorkflowSchedules(`${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`);
|
|
17582
|
-
const [results, sweepResult, reapResult] = await Promise.all([
|
|
17525
|
+
const [results, sweepResult, reapResult, expiredResult] = await Promise.all([
|
|
17583
17526
|
drainQueue(budget),
|
|
17584
17527
|
runMonthlyRefreshSweep(),
|
|
17585
|
-
reapIdleBrowserSessions(120).catch(() => ({ reaped: 0 }))
|
|
17528
|
+
reapIdleBrowserSessions(120).catch(() => ({ reaped: 0 })),
|
|
17529
|
+
expireOldLots().catch(() => ({ expired_lots: 0, expired_mc: 0 }))
|
|
17586
17530
|
]);
|
|
17587
|
-
return c.json({ drained: results.length, results, sweepResult, reaped: reapResult, workflowDispatch: workflowDispatchResult });
|
|
17531
|
+
return c.json({ drained: results.length, results, sweepResult, reaped: reapResult, expired: expiredResult, workflowDispatch: workflowDispatchResult });
|
|
17588
17532
|
});
|
|
17589
17533
|
app.on(["GET", "POST", "PUT"], "/api/inngest", serveInngest({ client: inngest, functions: [siteAuditFn, siteExtractFn] }));
|
|
17590
17534
|
app.route("/api/internal/site-architecture-auditor", siteAuditApp);
|
|
@@ -17720,4 +17664,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
17720
17664
|
export {
|
|
17721
17665
|
app
|
|
17722
17666
|
};
|
|
17723
|
-
//# sourceMappingURL=server-
|
|
17667
|
+
//# sourceMappingURL=server-K4UIE2R3.js.map
|