billing-http.mjs
87 lines 3.9 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * GET /api/v1/billing/summary
3 */
4 import {
5 billingEnforced,
6 COST_BREAKDOWN,
7 INDEXING_TOKENS_POLICY,
8 MONTHLY_INCLUDED_CENTS_BY_TIER,
9 NOTE_CAP_BY_TIER,
10 } from './billing-constants.mjs';
11 import {
12 defaultUserRecord,
13 effectiveMonthlyIndexingTokensIncluded,
14 effectiveMonthlySearchesIncluded,
15 effectiveMonthlyIndexJobsIncluded,
16 effectiveMonthlyConsolidationPassesIncluded,
17 inferPackConsolidationPassesFromIndexingTokenBalance,
18 normalizeBillingUser,
19 } from './billing-logic.mjs';
20 import { loadBillingDb, resetMonthlyTokensIfNeeded, mutateBillingDb } from './billing-store.mjs';
21
22 function effectiveMonthlyIncludedCents(u) {
23 if (u.tier === 'free') return MONTHLY_INCLUDED_CENTS_BY_TIER.free ?? 0;
24 return Math.max(0, Math.floor(Number(u.monthly_included_cents) || 0));
25 }
26
27 export async function handleBillingSummary(req, res, getUserId) {
28 const uid = getUserId(req);
29 if (!uid) return res.status(401).json({ error: 'Unauthorized', code: 'UNAUTHORIZED' });
30
31 await resetMonthlyTokensIfNeeded(uid);
32
33 // One-time backfill: purchases before pack consolidation passes were stored in the ledger
34 // left pack_indexing_tokens_balance > 0 with pack_consolidation_passes_balance === 0.
35 await mutateBillingDb((dbMut) => {
36 const user = dbMut.users[uid] || defaultUserRecord(uid);
37 normalizeBillingUser(user);
38 dbMut.users[uid] = user;
39 if (user.pack_consolidation_legacy_inferred === true) return;
40 const packTok = Math.max(0, Math.floor(Number(user.pack_indexing_tokens_balance) || 0));
41 const packPass = Math.max(0, Math.floor(Number(user.pack_consolidation_passes_balance) || 0));
42 if (packPass > 0 || packTok <= 0) return;
43 const inferred = inferPackConsolidationPassesFromIndexingTokenBalance(packTok);
44 if (inferred > 0) {
45 user.pack_consolidation_passes_balance = inferred;
46 user.pack_consolidation_legacy_inferred = true;
47 }
48 });
49
50 const db = await loadBillingDb();
51 const u = normalizeBillingUser(db.users[uid] || defaultUserRecord(uid));
52
53 const tier = u.tier || 'beta';
54 const noteCapRaw = NOTE_CAP_BY_TIER[tier];
55 const noteCap = noteCapRaw === undefined ? null : noteCapRaw;
56
57 return res.json({
58 tier,
59 period_start: u.period_start,
60 period_end: u.period_end,
61 monthly_included_cents: u.monthly_included_cents,
62 monthly_included_effective_cents: effectiveMonthlyIncludedCents(u),
63 monthly_used_cents: u.monthly_used_cents,
64 addon_cents: u.addon_cents,
65 billing_enforced: billingEnforced(),
66 stripe_configured: Boolean(process.env.STRIPE_SECRET_KEY),
67 has_active_subscription: Boolean(u.stripe_subscription_id),
68 credit_policy:
69 '1 credit = $1 of platform metered usage. Credits are prepaid balance for Knowtation hosted only; not tradable, not a security.',
70 monthly_indexing_tokens_included: effectiveMonthlyIndexingTokensIncluded(u),
71 monthly_indexing_tokens_used: Math.max(0, Math.floor(Number(u.monthly_indexing_tokens_used) || 0)),
72 pack_indexing_tokens_balance: Math.max(0, Math.floor(Number(u.pack_indexing_tokens_balance) || 0)),
73 pack_consolidation_passes_balance: Math.max(0, Math.floor(Number(u.pack_consolidation_passes_balance) || 0)),
74 monthly_searches_used: Math.max(0, Math.floor(Number(u.monthly_searches_used) || 0)),
75 monthly_searches_included: effectiveMonthlySearchesIncluded(u),
76 monthly_index_jobs_used: Math.max(0, Math.floor(Number(u.monthly_index_jobs_used) || 0)),
77 monthly_index_jobs_included: effectiveMonthlyIndexJobsIncluded(u),
78 monthly_consolidation_jobs_used: Math.max(0, Math.floor(Number(u.monthly_consolidation_jobs_used) || 0)),
79 monthly_consolidation_jobs_included: effectiveMonthlyConsolidationPassesIncluded(u),
80 consolidation_last_pass_at: u.consolidation_last_pass_at ?? null,
81 note_cap: noteCap,
82 indexing_tokens_policy: INDEXING_TOKENS_POLICY,
83 cost_breakdown: COST_BREAKDOWN,
84 usage_chart_status:
85 'planned: time-series usage + chart in Hub (not required for launch); shadow logs via BILLING_SHADOW_LOG for research.',
86 });
87 }
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago