codebuff 1.0.224 → 1.0.225
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/client.d.ts +5 -5
- package/dist/client.js +5 -0
- package/dist/client.js.map +1 -1
- package/dist/code-map/tsconfig.tsbuildinfo +1 -1
- package/dist/common/actions.d.ts +134 -134
- package/dist/common/advanced-analyzer.d.ts +19 -0
- package/dist/common/advanced-analyzer.js +140 -0
- package/dist/common/advanced-analyzer.js.map +1 -0
- package/dist/common/billing/balance-calculator.d.ts +1 -1
- package/dist/common/billing/check-auto-topup.d.ts +12 -0
- package/dist/common/billing/check-auto-topup.js +50 -0
- package/dist/common/billing/check-auto-topup.js.map +1 -0
- package/dist/common/billing/credit-check.d.ts +8 -0
- package/dist/common/billing/credit-check.js +45 -0
- package/dist/common/billing/credit-check.js.map +1 -0
- package/dist/common/billing/rollover-logic.d.ts +13 -0
- package/dist/common/billing/rollover-logic.js +174 -0
- package/dist/common/billing/rollover-logic.js.map +1 -0
- package/dist/common/billing/stripe-api.d.ts +31 -0
- package/dist/common/billing/stripe-api.js +104 -0
- package/dist/common/billing/stripe-api.js.map +1 -0
- package/dist/common/message-image-handling.d.ts +41 -0
- package/dist/common/message-image-handling.js +57 -0
- package/dist/common/message-image-handling.js.map +1 -0
- package/dist/common/types/billing.d.ts +16 -0
- package/dist/common/types/billing.js +3 -0
- package/dist/common/types/billing.js.map +1 -0
- package/dist/common/types/usage.d.ts +2 -2
- package/dist/common/util/process-stream.d.ts +8 -0
- package/dist/common/util/process-stream.js +102 -0
- package/dist/common/util/process-stream.js.map +1 -0
- package/dist/common/util/referral-credits.d.ts +1 -0
- package/dist/common/util/referral-credits.js +48 -0
- package/dist/common/util/referral-credits.js.map +1 -0
- package/dist/common/websockets/websocket-schema.d.ts +258 -258
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/common/logger.d.ts +0 -1
- package/dist/common/logger.js +0 -7
- package/dist/common/logger.js.map +0 -1
- package/dist/common/util/constants.d.ts +0 -1
- package/dist/common/util/constants.js +0 -7
- package/dist/common/util/constants.js.map +0 -1
- package/dist/common/util/helpers.d.ts +0 -1
- package/dist/common/util/helpers.js +0 -6
- package/dist/common/util/helpers.js.map +0 -1
- package/dist/common/util/token-counter.d.ts +0 -3
- package/dist/common/util/token-counter.js +0 -27
- package/dist/common/util/token-counter.js.map +0 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BrowserResponse } from './browser-actions';
|
|
2
|
+
/**
|
|
3
|
+
* Each detected issue includes a type, severity, detection reason,
|
|
4
|
+
* and an optional recommendation for the user.
|
|
5
|
+
*/
|
|
6
|
+
export interface AnalysisIssue {
|
|
7
|
+
type: string;
|
|
8
|
+
severity: 'low' | 'medium' | 'high';
|
|
9
|
+
message: string;
|
|
10
|
+
recommendation?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AnalysisResult {
|
|
13
|
+
issues: AnalysisIssue[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Entrypoint function to run a suite of heuristic checks over
|
|
17
|
+
* logs, network events, performance metrics, etc.
|
|
18
|
+
*/
|
|
19
|
+
export declare function analyzeBrowserData(response: BrowserResponse): AnalysisResult;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.analyzeBrowserData = analyzeBrowserData;
|
|
4
|
+
/**
|
|
5
|
+
* Entrypoint function to run a suite of heuristic checks over
|
|
6
|
+
* logs, network events, performance metrics, etc.
|
|
7
|
+
*/
|
|
8
|
+
function analyzeBrowserData(response) {
|
|
9
|
+
const issues = [];
|
|
10
|
+
// 1. Check logs for known error patterns or repeated errors
|
|
11
|
+
issues.push(...analyzeLogs(response));
|
|
12
|
+
// 2. Check network events for 4xx, 5xx, or suspicious patterns
|
|
13
|
+
issues.push(...analyzeNetwork(response));
|
|
14
|
+
// 3. Check performance metrics (TTFB, LCP, memory usage, etc.)
|
|
15
|
+
if (response.metrics) {
|
|
16
|
+
issues.push(...analyzePerformance(response.metrics));
|
|
17
|
+
}
|
|
18
|
+
// Return combined issues
|
|
19
|
+
return { issues };
|
|
20
|
+
}
|
|
21
|
+
function analyzeLogs(response) {
|
|
22
|
+
const issues = [];
|
|
23
|
+
const logs = response.logs || [];
|
|
24
|
+
// Check for high number of JavaScript errors
|
|
25
|
+
const jsErrors = logs.filter((log) => log.type === 'error');
|
|
26
|
+
if (jsErrors.length > 5) {
|
|
27
|
+
issues.push({
|
|
28
|
+
type: 'JS_ERROR_OVERFLOW',
|
|
29
|
+
severity: 'medium',
|
|
30
|
+
message: `Detected ${jsErrors.length} JavaScript errors in logs.`,
|
|
31
|
+
recommendation: 'Review the console logs for repeated error patterns. Fix the root cause or handle errors in code.'
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
// Pattern-based error detection
|
|
35
|
+
const errorPatterns = {
|
|
36
|
+
'not defined': {
|
|
37
|
+
severity: 'medium',
|
|
38
|
+
recommendation: 'Check for missing script dependencies or undefined variables'
|
|
39
|
+
},
|
|
40
|
+
'Failed to fetch': {
|
|
41
|
+
severity: 'medium',
|
|
42
|
+
recommendation: 'Verify endpoint URLs and network connectivity'
|
|
43
|
+
},
|
|
44
|
+
'SSL': {
|
|
45
|
+
severity: 'high',
|
|
46
|
+
recommendation: 'SSL certificate error - check HTTPS configuration'
|
|
47
|
+
},
|
|
48
|
+
'ERR_NAME_NOT_RESOLVED': {
|
|
49
|
+
severity: 'medium',
|
|
50
|
+
recommendation: 'DNS resolution failed - check domain name'
|
|
51
|
+
},
|
|
52
|
+
'ERR_CONNECTION_TIMED_OUT': {
|
|
53
|
+
severity: 'medium',
|
|
54
|
+
recommendation: 'Connection timeout - check network or firewall'
|
|
55
|
+
},
|
|
56
|
+
'Navigation timeout': {
|
|
57
|
+
severity: 'medium',
|
|
58
|
+
recommendation: 'Page took too long to load - check performance or timeouts'
|
|
59
|
+
},
|
|
60
|
+
'Frame detached': {
|
|
61
|
+
severity: 'low',
|
|
62
|
+
recommendation: 'Target frame or element no longer exists'
|
|
63
|
+
},
|
|
64
|
+
'Node is detached': {
|
|
65
|
+
severity: 'low',
|
|
66
|
+
recommendation: 'Element was removed from DOM'
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
for (const log of jsErrors) {
|
|
70
|
+
for (const [pattern, { severity, recommendation }] of Object.entries(errorPatterns)) {
|
|
71
|
+
if (log.message.includes(pattern)) {
|
|
72
|
+
issues.push({
|
|
73
|
+
type: 'JS_ERROR',
|
|
74
|
+
severity,
|
|
75
|
+
message: `Error detected: ${log.message}`,
|
|
76
|
+
recommendation
|
|
77
|
+
});
|
|
78
|
+
break; // Stop after first matching pattern
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return issues;
|
|
83
|
+
}
|
|
84
|
+
function analyzeNetwork(response) {
|
|
85
|
+
const issues = [];
|
|
86
|
+
const netEvents = response.networkEvents || [];
|
|
87
|
+
// Count 4xx / 5xx
|
|
88
|
+
const errorEvents = netEvents.filter((evt) => (evt.status && evt.status >= 400) || evt.errorText);
|
|
89
|
+
if (errorEvents.length > 0) {
|
|
90
|
+
issues.push({
|
|
91
|
+
type: 'NETWORK_ERRORS',
|
|
92
|
+
severity: 'medium',
|
|
93
|
+
message: `${errorEvents.length} network request(s) failed with 4xx/5xx error(s).`,
|
|
94
|
+
recommendation: 'Check your API endpoints and resource URLs. Verify server logs for possible configuration or routing issues.'
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
// Detect repeated 404s
|
|
98
|
+
const fourOhFours = netEvents.filter((e) => e.status === 404);
|
|
99
|
+
if (fourOhFours.length > 2) {
|
|
100
|
+
issues.push({
|
|
101
|
+
type: 'MISSING_RESOURCES',
|
|
102
|
+
severity: 'low',
|
|
103
|
+
message: `${fourOhFours.length} resources returned 404 Not Found.`,
|
|
104
|
+
recommendation: 'Ensure static assets or pages exist at the requested path.'
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return issues;
|
|
108
|
+
}
|
|
109
|
+
function analyzePerformance(metrics) {
|
|
110
|
+
const issues = [];
|
|
111
|
+
// Check Time to First Byte
|
|
112
|
+
if ((metrics.ttfb ?? 0) > 1000) {
|
|
113
|
+
issues.push({
|
|
114
|
+
type: 'HIGH_TTFB',
|
|
115
|
+
severity: 'medium',
|
|
116
|
+
message: `Time to First Byte is ${metrics.ttfb}ms, which is high.`,
|
|
117
|
+
recommendation: 'Optimize server response times or check network constraints. Look for server-side bottlenecks.'
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Check memory usage
|
|
121
|
+
if (metrics.memoryUsage > 100_000_000) { // ~100MB in JS heap
|
|
122
|
+
issues.push({
|
|
123
|
+
type: 'HIGH_MEMORY_USAGE',
|
|
124
|
+
severity: 'medium',
|
|
125
|
+
message: `Memory usage reached ${metrics.memoryUsage} bytes in JS heap.`,
|
|
126
|
+
recommendation: 'Investigate potential memory leaks, unbounded data structures, or large on-page assets.'
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// Check Largest Contentful Paint
|
|
130
|
+
if ((metrics.lcp ?? 0) > 4000) {
|
|
131
|
+
issues.push({
|
|
132
|
+
type: 'PERFORMANCE_LCP',
|
|
133
|
+
severity: 'medium',
|
|
134
|
+
message: `Largest Contentful Paint is ${metrics.lcp}ms (over 4s).`,
|
|
135
|
+
recommendation: 'Consider optimizing images, breaking up large bundle files, or deferring non-critical scripts.'
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return issues;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=advanced-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advanced-analyzer.js","sourceRoot":"","sources":["../src/advanced-analyzer.ts"],"names":[],"mappings":";;AAqBA,gDAgBC;AApBD;;;GAGG;AACH,SAAgB,kBAAkB,CAAC,QAAyB;IAC1D,MAAM,MAAM,GAAoB,EAAE,CAAA;IAElC,4DAA4D;IAC5D,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAA;IAErC,+DAA+D;IAC/D,MAAM,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAA;IAExC,+DAA+D;IAC/D,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;IACtD,CAAC;IAED,yBAAyB;IACzB,OAAO,EAAE,MAAM,EAAE,CAAA;AACnB,CAAC;AAED,SAAS,WAAW,CAAC,QAAyB;IAC5C,MAAM,MAAM,GAAoB,EAAE,CAAA;IAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAA;IAEhC,6CAA6C;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAA;IAC3D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,YAAY,QAAQ,CAAC,MAAM,6BAA6B;YACjE,cAAc,EACZ,mGAAmG;SACtG,CAAC,CAAA;IACJ,CAAC;IAED,gCAAgC;IAChC,MAAM,aAAa,GAAoF;QACrG,aAAa,EAAE;YACb,QAAQ,EAAE,QAAQ;YAClB,cAAc,EAAE,8DAA8D;SAC/E;QACD,iBAAiB,EAAE;YACjB,QAAQ,EAAE,QAAQ;YAClB,cAAc,EAAE,+CAA+C;SAChE;QACD,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM;YAChB,cAAc,EAAE,mDAAmD;SACpE;QACD,uBAAuB,EAAE;YACvB,QAAQ,EAAE,QAAQ;YAClB,cAAc,EAAE,2CAA2C;SAC5D;QACD,0BAA0B,EAAE;YAC1B,QAAQ,EAAE,QAAQ;YAClB,cAAc,EAAE,gDAAgD;SACjE;QACD,oBAAoB,EAAE;YACpB,QAAQ,EAAE,QAAQ;YAClB,cAAc,EAAE,4DAA4D;SAC7E;QACD,gBAAgB,EAAE;YAChB,QAAQ,EAAE,KAAK;YACf,cAAc,EAAE,0CAA0C;SAC3D;QACD,kBAAkB,EAAE;YAClB,QAAQ,EAAE,KAAK;YACf,cAAc,EAAE,8BAA8B;SAC/C;KACF,CAAA;IAED,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YACpF,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,UAAU;oBAChB,QAAQ;oBACR,OAAO,EAAE,mBAAmB,GAAG,CAAC,OAAO,EAAE;oBACzC,cAAc;iBACf,CAAC,CAAA;gBACF,MAAK,CAAC,oCAAoC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,cAAc,CAAC,QAAyB;IAC/C,MAAM,MAAM,GAAoB,EAAE,CAAA;IAClC,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,IAAI,EAAE,CAAA;IAE9C,kBAAkB;IAClB,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAClC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,SAAS,CAC5D,CAAA;IACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,gBAAgB;YACtB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,GAAG,WAAW,CAAC,MAAM,mDAAmD;YACjF,cAAc,EACZ,8GAA8G;SACjH,CAAC,CAAA;IACJ,CAAC;IAED,uBAAuB;IACvB,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAA;IAC7D,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,GAAG,WAAW,CAAC,MAAM,oCAAoC;YAClE,cAAc,EAAE,4DAA4D;SAC7E,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,kBAAkB,CAAC,OAA6C;IACvE,MAAM,MAAM,GAAoB,EAAE,CAAA;IAElC,2BAA2B;IAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,yBAAyB,OAAO,CAAC,IAAI,oBAAoB;YAClE,cAAc,EACZ,gGAAgG;SACnG,CAAC,CAAA;IACJ,CAAC;IAED,qBAAqB;IACrB,IAAI,OAAO,CAAC,WAAW,GAAG,WAAW,EAAE,CAAC,CAAC,oBAAoB;QAC3D,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,wBAAwB,OAAO,CAAC,WAAW,oBAAoB;YACxE,cAAc,EACZ,yFAAyF;SAC5F,CAAC,CAAA;IACJ,CAAC;IAED,iCAAiC;IACjC,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,iBAAiB;YACvB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,+BAA+B,OAAO,CAAC,GAAG,eAAe;YAClE,cAAc,EACZ,gGAAgG;SACnG,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -21,8 +21,8 @@ type DbConn = Pick<typeof db, 'select' | 'update'>;
|
|
|
21
21
|
* Added optional `conn` param so callers inside a transaction can supply their TX object.
|
|
22
22
|
*/
|
|
23
23
|
export declare function getOrderedActiveGrants(userId: string, now: Date, conn?: DbConn): Promise<{
|
|
24
|
-
type: import("../types/grant").GrantType;
|
|
25
24
|
created_at: Date;
|
|
25
|
+
type: import("../types/grant").GrantType;
|
|
26
26
|
expires_at: Date | null;
|
|
27
27
|
operation_id: string;
|
|
28
28
|
user_id: string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type Stripe from 'stripe';
|
|
2
|
+
export interface AutoTopupCheckResult {
|
|
3
|
+
blockedReason: string | null;
|
|
4
|
+
validPaymentMethod: Stripe.PaymentMethod | null;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Checks if auto top-up is allowed for a user by verifying their payment methods.
|
|
8
|
+
* @param userId The ID of the user for logging context
|
|
9
|
+
* @param stripeCustomerId The user's Stripe customer ID
|
|
10
|
+
* @returns Promise<AutoTopupCheckResult>
|
|
11
|
+
*/
|
|
12
|
+
export declare function checkAutoTopupAllowed(userId: string, stripeCustomerId: string | null): Promise<AutoTopupCheckResult>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkAutoTopupAllowed = checkAutoTopupAllowed;
|
|
4
|
+
const stripe_1 = require("../util/stripe");
|
|
5
|
+
const logger_1 = require("../util/logger");
|
|
6
|
+
const env_mjs_1 = require("src/env.mjs");
|
|
7
|
+
/**
|
|
8
|
+
* Checks if auto top-up is allowed for a user by verifying their payment methods.
|
|
9
|
+
* @param userId The ID of the user for logging context
|
|
10
|
+
* @param stripeCustomerId The user's Stripe customer ID
|
|
11
|
+
* @returns Promise<AutoTopupCheckResult>
|
|
12
|
+
*/
|
|
13
|
+
async function checkAutoTopupAllowed(userId, stripeCustomerId) {
|
|
14
|
+
const logContext = { userId };
|
|
15
|
+
if (!stripeCustomerId) {
|
|
16
|
+
return {
|
|
17
|
+
blockedReason: `You don\'t have a valid account with us. Please log in at ${env_mjs_1.env.NEXT_PUBLIC_APP_URL}/login`,
|
|
18
|
+
validPaymentMethod: null,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const paymentMethods = await stripe_1.stripeServer.paymentMethods.list({
|
|
23
|
+
customer: stripeCustomerId,
|
|
24
|
+
type: 'card',
|
|
25
|
+
});
|
|
26
|
+
// Find a valid, non-expired card
|
|
27
|
+
const validPaymentMethod = paymentMethods.data.find((pm) => pm.card?.exp_year &&
|
|
28
|
+
pm.card.exp_month &&
|
|
29
|
+
new Date(pm.card.exp_year, pm.card.exp_month - 1) > new Date());
|
|
30
|
+
if (!validPaymentMethod) {
|
|
31
|
+
logger_1.logger.warn({ ...logContext }, 'No valid payment methods found for auto top-up');
|
|
32
|
+
return {
|
|
33
|
+
blockedReason: 'You need a valid payment method to enable auto top-up. You can add one by manually purchasing credits.',
|
|
34
|
+
validPaymentMethod: null,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
blockedReason: null,
|
|
39
|
+
validPaymentMethod,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
logger_1.logger.error({ ...logContext, error }, 'Failed to fetch payment methods');
|
|
44
|
+
return {
|
|
45
|
+
blockedReason: 'Unable to verify payment method status.',
|
|
46
|
+
validPaymentMethod: null,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=check-auto-topup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-auto-topup.js","sourceRoot":"","sources":["../../src/billing/check-auto-topup.ts"],"names":[],"mappings":";;AAgBA,sDAkDC;AAlED,2CAA6C;AAC7C,2CAAuC;AAEvC,yCAAiC;AAOjC;;;;;GAKG;AACI,KAAK,UAAU,qBAAqB,CACzC,MAAc,EACd,gBAA+B;IAE/B,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,CAAA;IAE7B,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO;YACL,aAAa,EAAE,6DAA6D,aAAG,CAAC,mBAAmB,QAAQ;YAC3G,kBAAkB,EAAE,IAAI;SACzB,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,MAAM,qBAAY,CAAC,cAAc,CAAC,IAAI,CAAC;YAC5D,QAAQ,EAAE,gBAAgB;YAC1B,IAAI,EAAE,MAAM;SACb,CAAC,CAAA;QAEF,iCAAiC;QACjC,MAAM,kBAAkB,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CACjD,CAAC,EAAE,EAAE,EAAE,CACL,EAAE,CAAC,IAAI,EAAE,QAAQ;YACjB,EAAE,CAAC,IAAI,CAAC,SAAS;YACjB,IAAI,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,CACjE,CAAA;QAED,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACxB,eAAM,CAAC,IAAI,CACT,EAAE,GAAG,UAAU,EAAE,EACjB,gDAAgD,CACjD,CAAA;YACD,OAAO;gBACL,aAAa,EACX,wGAAwG;gBAC1G,kBAAkB,EAAE,IAAI;aACzB,CAAA;QACH,CAAC;QAED,OAAO;YACL,aAAa,EAAE,IAAI;YACnB,kBAAkB;SACnB,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,eAAM,CAAC,KAAK,CAAC,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE,EAAE,iCAAiC,CAAC,CAAA;QACzE,OAAO;YACL,aAAa,EAAE,yCAAyC;YACxD,kBAAkB,EAAE,IAAI;SACzB,CAAA;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CreditBalance } from './balance-calculator';
|
|
2
|
+
/**
|
|
3
|
+
* Gets the current detailed credit balance for a user.
|
|
4
|
+
* Returns a zero balance for anonymous users.
|
|
5
|
+
* @param userId The ID of the user, or undefined for anonymous.
|
|
6
|
+
* @returns A Promise resolving to the user's CreditBalance.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getCurrentBalanceDetails(userId: string | undefined): Promise<CreditBalance>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCurrentBalanceDetails = getCurrentBalanceDetails;
|
|
4
|
+
const balance_calculator_1 = require("./balance-calculator");
|
|
5
|
+
const logger_1 = require("../util/logger");
|
|
6
|
+
/**
|
|
7
|
+
* Gets the current detailed credit balance for a user.
|
|
8
|
+
* Returns a zero balance for anonymous users.
|
|
9
|
+
* @param userId The ID of the user, or undefined for anonymous.
|
|
10
|
+
* @returns A Promise resolving to the user's CreditBalance.
|
|
11
|
+
*/
|
|
12
|
+
async function getCurrentBalanceDetails(userId) {
|
|
13
|
+
if (!userId) {
|
|
14
|
+
// Return zero/default balance for anonymous users
|
|
15
|
+
return {
|
|
16
|
+
totalRemaining: 0,
|
|
17
|
+
breakdown: {
|
|
18
|
+
free: 0,
|
|
19
|
+
referral: 0,
|
|
20
|
+
purchase: 0,
|
|
21
|
+
admin: 0,
|
|
22
|
+
rollover: 0,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
// Use the new balance calculation logic
|
|
28
|
+
return await (0, balance_calculator_1.calculateCurrentBalance)(userId);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
logger_1.logger.error({ userId, error }, 'Error fetching balance details');
|
|
32
|
+
// Return a zero balance on error
|
|
33
|
+
return {
|
|
34
|
+
totalRemaining: 0,
|
|
35
|
+
breakdown: {
|
|
36
|
+
free: 0,
|
|
37
|
+
referral: 0,
|
|
38
|
+
purchase: 0,
|
|
39
|
+
admin: 0,
|
|
40
|
+
rollover: 0,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=credit-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credit-check.js","sourceRoot":"","sources":["../../src/billing/credit-check.ts"],"names":[],"mappings":";;AASA,4DAkCC;AA3CD,6DAA6E;AAC7E,2CAAuC;AAEvC;;;;;GAKG;AACI,KAAK,UAAU,wBAAwB,CAC5C,MAA0B;IAE1B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,kDAAkD;QAClD,OAAO;YACL,cAAc,EAAE,CAAC;YACjB,SAAS,EAAE;gBACT,IAAI,EAAE,CAAC;gBACP,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE,CAAC;gBACX,KAAK,EAAE,CAAC;gBACR,QAAQ,EAAE,CAAC;aACZ;SACF,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,wCAAwC;QACxC,OAAO,MAAM,IAAA,4CAAuB,EAAC,MAAM,CAAC,CAAA;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,eAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,gCAAgC,CAAC,CAAA;QACjE,iCAAiC;QACjC,OAAO;YACL,cAAc,EAAE,CAAC;YACjB,SAAS,EAAE;gBACT,IAAI,EAAE,CAAC;gBACP,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE,CAAC;gBACX,KAAK,EAAE,CAAC;gBACR,QAAQ,EAAE,CAAC;aACZ;SACF,CAAA;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates the rollover amount for a user at the end of their billing cycle
|
|
3
|
+
* and applies the necessary database updates (creates rollover grant, resets usage, updates reset date).
|
|
4
|
+
*
|
|
5
|
+
* NOTE: This function performs database writes and should be called within a transaction
|
|
6
|
+
* if invoked alongside other database operations. It also depends on the `credit_grants`
|
|
7
|
+
* table and the modified `user` table schema being in place.
|
|
8
|
+
*
|
|
9
|
+
* @param userId The ID of the user whose cycle is ending.
|
|
10
|
+
* @param cycleEndDate The exact date and time the billing cycle ended.
|
|
11
|
+
* @returns A Promise resolving when the process is complete.
|
|
12
|
+
*/
|
|
13
|
+
export declare function calculateAndApplyRollover(userId: string, cycleEndDate: Date): Promise<void>;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.calculateAndApplyRollover = calculateAndApplyRollover;
|
|
30
|
+
const db_1 = __importDefault(require("../db"));
|
|
31
|
+
const schema = __importStar(require("../db/schema"));
|
|
32
|
+
const drizzle_orm_1 = require("drizzle-orm");
|
|
33
|
+
const balance_calculator_1 = require("./balance-calculator");
|
|
34
|
+
const logger_1 = require("../util/logger");
|
|
35
|
+
const dates_1 = require("../util/dates"); // Assuming this utility exists/is created
|
|
36
|
+
// Define which grant types contribute to rollover
|
|
37
|
+
const ROLLOVER_GRANT_TYPES = ['purchase', 'rollover'];
|
|
38
|
+
/**
|
|
39
|
+
* Calculates the rollover amount for a user at the end of their billing cycle
|
|
40
|
+
* and applies the necessary database updates (creates rollover grant, resets usage, updates reset date).
|
|
41
|
+
*
|
|
42
|
+
* NOTE: This function performs database writes and should be called within a transaction
|
|
43
|
+
* if invoked alongside other database operations. It also depends on the `credit_grants`
|
|
44
|
+
* table and the modified `user` table schema being in place.
|
|
45
|
+
*
|
|
46
|
+
* @param userId The ID of the user whose cycle is ending.
|
|
47
|
+
* @param cycleEndDate The exact date and time the billing cycle ended.
|
|
48
|
+
* @returns A Promise resolving when the process is complete.
|
|
49
|
+
*/
|
|
50
|
+
async function calculateAndApplyRollover(userId, cycleEndDate) {
|
|
51
|
+
logger_1.logger.info({ userId, cycleEndDate }, 'Starting end-of-cycle rollover process');
|
|
52
|
+
try {
|
|
53
|
+
// 1. Fetch the user's usage for the cycle that just ended
|
|
54
|
+
// We need the user record to get the usage *before* resetting it.
|
|
55
|
+
const user = await db_1.default.query.user.findFirst({
|
|
56
|
+
where: (0, drizzle_orm_1.eq)(schema.user.id, userId),
|
|
57
|
+
columns: { usage: true, next_quota_reset: true }, // Also get current reset date
|
|
58
|
+
});
|
|
59
|
+
if (!user) {
|
|
60
|
+
logger_1.logger.error({ userId }, 'User not found during rollover calculation.');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Ensure we don't run rollover multiple times for the same cycle
|
|
64
|
+
if (user.next_quota_reset && user.next_quota_reset > cycleEndDate) {
|
|
65
|
+
logger_1.logger.warn({ userId, cycleEndDate, nextReset: user.next_quota_reset }, 'Rollover attempted for a cycle that has not yet ended or already processed. Skipping.');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const endedCycleUsage = user.usage;
|
|
69
|
+
// Calculate the start date of the ended cycle (approximate)
|
|
70
|
+
const cycleStartDate = new Date(cycleEndDate);
|
|
71
|
+
cycleStartDate.setMonth(cycleStartDate.getMonth() - 1); // Approximation
|
|
72
|
+
// 2. Fetch all grants that were active *during* the ended cycle
|
|
73
|
+
// Active during cycle: created_at < cycleEndDate AND (expires_at IS NULL OR expires_at > cycleStartDate)
|
|
74
|
+
const grantsActiveDuringCycle = await db_1.default
|
|
75
|
+
.select()
|
|
76
|
+
.from(schema.creditGrants)
|
|
77
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(schema.creditGrants.user_id, userId), (0, drizzle_orm_1.lte)(schema.creditGrants.created_at, cycleEndDate), // Created before or exactly at cycle end
|
|
78
|
+
(0, drizzle_orm_1.or)((0, drizzle_orm_1.isNull)(schema.creditGrants.expires_at), // Never expires
|
|
79
|
+
(0, drizzle_orm_1.gt)(schema.creditGrants.expires_at, cycleStartDate) // Expired after cycle start
|
|
80
|
+
)))
|
|
81
|
+
// 3. Order grants by priority ASC, then created_at ASC
|
|
82
|
+
.orderBy((0, drizzle_orm_1.asc)(schema.creditGrants.priority), (0, drizzle_orm_1.asc)(schema.creditGrants.created_at));
|
|
83
|
+
// 4. Initialize rollover amount
|
|
84
|
+
let rolloverAmount = 0;
|
|
85
|
+
// 5. Initialize usage to account for from the ended cycle
|
|
86
|
+
let usageToAccountFor = endedCycleUsage;
|
|
87
|
+
logger_1.logger.debug({ userId, endedCycleUsage, grantsCount: grantsActiveDuringCycle.length }, 'Simulating consumption for ended cycle');
|
|
88
|
+
// 6. Simulate Cycle Consumption
|
|
89
|
+
for (const grant of grantsActiveDuringCycle) {
|
|
90
|
+
const consumedFromThisGrant = Math.min(grant.amount, usageToAccountFor);
|
|
91
|
+
const remainingInThisGrant = grant.amount - consumedFromThisGrant;
|
|
92
|
+
usageToAccountFor -= consumedFromThisGrant;
|
|
93
|
+
logger_1.logger.trace({
|
|
94
|
+
userId,
|
|
95
|
+
grantId: grant.operation_id,
|
|
96
|
+
grantType: grant.type,
|
|
97
|
+
grantAmount: grant.amount,
|
|
98
|
+
consumed: consumedFromThisGrant,
|
|
99
|
+
remainingInGrant: remainingInThisGrant,
|
|
100
|
+
usageLeftToAccount: usageToAccountFor,
|
|
101
|
+
}, 'Processing grant during rollover simulation');
|
|
102
|
+
// 7. Check for Rollover Contribution
|
|
103
|
+
if (remainingInThisGrant > 0 &&
|
|
104
|
+
ROLLOVER_GRANT_TYPES.includes(grant.type)) {
|
|
105
|
+
rolloverAmount += remainingInThisGrant;
|
|
106
|
+
logger_1.logger.trace({
|
|
107
|
+
userId,
|
|
108
|
+
grantId: grant.operation_id,
|
|
109
|
+
addedToRollover: remainingInThisGrant,
|
|
110
|
+
newTotalRollover: rolloverAmount,
|
|
111
|
+
}, 'Grant contributed to rollover amount');
|
|
112
|
+
}
|
|
113
|
+
if (usageToAccountFor <= 0) {
|
|
114
|
+
// If usage is covered, check remaining grants for rollover contributions
|
|
115
|
+
const remainingGrants = grantsActiveDuringCycle.slice(grantsActiveDuringCycle.indexOf(grant) + 1);
|
|
116
|
+
for (const remainingGrant of remainingGrants) {
|
|
117
|
+
if (ROLLOVER_GRANT_TYPES.includes(remainingGrant.type)) {
|
|
118
|
+
rolloverAmount += remainingGrant.amount;
|
|
119
|
+
logger_1.logger.trace({
|
|
120
|
+
userId,
|
|
121
|
+
grantId: remainingGrant.operation_id,
|
|
122
|
+
addedToRollover: remainingGrant.amount,
|
|
123
|
+
newTotalRollover: rolloverAmount,
|
|
124
|
+
}, 'Untouched grant contributed to rollover amount');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
break; // All usage accounted for
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
logger_1.logger.info({ userId, endedCycleUsage, calculatedRollover: rolloverAmount }, 'Rollover calculation complete');
|
|
131
|
+
// 8. Database Updates (Perform as a transaction)
|
|
132
|
+
await db_1.default.transaction(async (tx) => {
|
|
133
|
+
// Insert new 'rollover' grant if amount > 0
|
|
134
|
+
if (rolloverAmount > 0) {
|
|
135
|
+
const rolloverGrantId = `rollover-${userId}-${cycleEndDate.toISOString()}`;
|
|
136
|
+
await tx
|
|
137
|
+
.insert(schema.creditGrants)
|
|
138
|
+
.values({
|
|
139
|
+
operation_id: rolloverGrantId,
|
|
140
|
+
user_id: userId,
|
|
141
|
+
amount: rolloverAmount,
|
|
142
|
+
amount_remaining: rolloverAmount, // Initialize amount_remaining to the full amount
|
|
143
|
+
type: 'rollover', // Use string literal directly
|
|
144
|
+
priority: balance_calculator_1.GRANT_PRIORITIES.rollover, // Use defined priority
|
|
145
|
+
expires_at: null, // Rollover credits don't expire
|
|
146
|
+
description: `Rollover from cycle ending ${cycleEndDate.toLocaleDateString()}`,
|
|
147
|
+
// stripe_grant_id is NULL for local grants
|
|
148
|
+
})
|
|
149
|
+
.onConflictDoNothing(); // Avoid duplicate rollovers if run concurrently
|
|
150
|
+
logger_1.logger.debug({ userId, rolloverAmount }, 'Inserted rollover grant');
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
logger_1.logger.debug({ userId }, 'No rollover amount to grant.');
|
|
154
|
+
}
|
|
155
|
+
// Update the user: reset usage and set next reset date
|
|
156
|
+
const nextResetDate = (0, dates_1.getNextQuotaReset)(cycleEndDate); // Calculate the next reset date based on the cycle end
|
|
157
|
+
await tx
|
|
158
|
+
.update(schema.user)
|
|
159
|
+
.set({
|
|
160
|
+
usage: 0,
|
|
161
|
+
next_quota_reset: nextResetDate,
|
|
162
|
+
})
|
|
163
|
+
.where((0, drizzle_orm_1.eq)(schema.user.id, userId));
|
|
164
|
+
logger_1.logger.info({ userId, nextResetDate: nextResetDate.toISOString() }, 'User usage reset and next reset date updated');
|
|
165
|
+
});
|
|
166
|
+
logger_1.logger.info({ userId }, 'Rollover process completed successfully.');
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
logger_1.logger.error({ userId, cycleEndDate, error }, 'Error during rollover process');
|
|
170
|
+
// Depending on trigger mechanism, might need error handling/retry logic here
|
|
171
|
+
throw error; // Re-throw to indicate failure if called from a job
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=rollover-logic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rollover-logic.js","sourceRoot":"","sources":["../../src/billing/rollover-logic.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,8DAsLC;AA7MD,+CAAsB;AACtB,qDAAsC;AACtC,6CAAoE;AACpE,6DAAuD;AACvD,2CAAuC;AACvC,yCAAiD,CAAC,0CAA0C;AAG5F,kDAAkD;AAClD,MAAM,oBAAoB,GAAgB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA;AAElE;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,yBAAyB,CAC7C,MAAc,EACd,YAAkB;IAElB,eAAM,CAAC,IAAI,CACT,EAAE,MAAM,EAAE,YAAY,EAAE,EACxB,wCAAwC,CACzC,CAAA;IAED,IAAI,CAAC;QACH,0DAA0D;QAC1D,kEAAkE;QAClE,MAAM,IAAI,GAAG,MAAM,YAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YACzC,KAAK,EAAE,IAAA,gBAAE,EAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC;YACjC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,EAAE,8BAA8B;SACjF,CAAC,CAAA;QAEF,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,eAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,6CAA6C,CAAC,CAAA;YACvE,OAAM;QACR,CAAC;QAED,iEAAiE;QACjE,IAAI,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,gBAAgB,GAAG,YAAY,EAAE,CAAC;YAClE,eAAM,CAAC,IAAI,CACT,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,CAAC,gBAAgB,EAAE,EAC1D,uFAAuF,CACxF,CAAA;YACD,OAAM;QACR,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAA;QAElC,4DAA4D;QAC5D,MAAM,cAAc,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,CAAA;QAC7C,cAAc,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAA,CAAC,gBAAgB;QAEvE,gEAAgE;QAChE,yGAAyG;QACzG,MAAM,uBAAuB,GAAG,MAAM,YAAE;aACrC,MAAM,EAAE;aACR,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;aACzB,KAAK,CACJ,IAAA,iBAAG,EACD,IAAA,gBAAE,EAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,EACvC,IAAA,iBAAG,EAAC,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,yCAAyC;QAC5F,IAAA,gBAAE,EACA,IAAA,oBAAM,EAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,gBAAgB;QACxD,IAAA,gBAAE,EAAC,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,4BAA4B;SAChF,CACF,CACF;YACD,uDAAuD;aACtD,OAAO,CACN,IAAA,iBAAG,EAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,EACjC,IAAA,iBAAG,EAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CACpC,CAAA;QAEH,gCAAgC;QAChC,IAAI,cAAc,GAAG,CAAC,CAAA;QAEtB,0DAA0D;QAC1D,IAAI,iBAAiB,GAAG,eAAe,CAAA;QAEvC,eAAM,CAAC,KAAK,CACV,EAAE,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,uBAAuB,CAAC,MAAM,EAAE,EACxE,wCAAwC,CACzC,CAAA;QAED,gCAAgC;QAChC,KAAK,MAAM,KAAK,IAAI,uBAAuB,EAAE,CAAC;YAC5C,MAAM,qBAAqB,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;YACvE,MAAM,oBAAoB,GAAG,KAAK,CAAC,MAAM,GAAG,qBAAqB,CAAA;YACjE,iBAAiB,IAAI,qBAAqB,CAAA;YAE1C,eAAM,CAAC,KAAK,CACV;gBACE,MAAM;gBACN,OAAO,EAAE,KAAK,CAAC,YAAY;gBAC3B,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,WAAW,EAAE,KAAK,CAAC,MAAM;gBACzB,QAAQ,EAAE,qBAAqB;gBAC/B,gBAAgB,EAAE,oBAAoB;gBACtC,kBAAkB,EAAE,iBAAiB;aACtC,EACD,6CAA6C,CAC9C,CAAA;YAED,qCAAqC;YACrC,IACE,oBAAoB,GAAG,CAAC;gBACxB,oBAAoB,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EACzC,CAAC;gBACD,cAAc,IAAI,oBAAoB,CAAA;gBACtC,eAAM,CAAC,KAAK,CACV;oBACE,MAAM;oBACN,OAAO,EAAE,KAAK,CAAC,YAAY;oBAC3B,eAAe,EAAE,oBAAoB;oBACrC,gBAAgB,EAAE,cAAc;iBACjC,EACD,sCAAsC,CACvC,CAAA;YACH,CAAC;YAED,IAAI,iBAAiB,IAAI,CAAC,EAAE,CAAC;gBAC3B,yEAAyE;gBACzE,MAAM,eAAe,GAAG,uBAAuB,CAAC,KAAK,CACnD,uBAAuB,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAC3C,CAAA;gBACD,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;oBAC7C,IAAI,oBAAoB,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvD,cAAc,IAAI,cAAc,CAAC,MAAM,CAAA;wBACvC,eAAM,CAAC,KAAK,CACV;4BACE,MAAM;4BACN,OAAO,EAAE,cAAc,CAAC,YAAY;4BACpC,eAAe,EAAE,cAAc,CAAC,MAAM;4BACtC,gBAAgB,EAAE,cAAc;yBACjC,EACD,gDAAgD,CACjD,CAAA;oBACH,CAAC;gBACH,CAAC;gBACD,MAAK,CAAC,0BAA0B;YAClC,CAAC;QACH,CAAC;QAED,eAAM,CAAC,IAAI,CACT,EAAE,MAAM,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,EAC/D,+BAA+B,CAChC,CAAA;QAED,iDAAiD;QACjD,MAAM,YAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAChC,4CAA4C;YAC5C,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,eAAe,GAAG,YAAY,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,EAAE,CAAA;gBAC1E,MAAM,EAAE;qBACL,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;qBAC3B,MAAM,CAAC;oBACN,YAAY,EAAE,eAAe;oBAC7B,OAAO,EAAE,MAAM;oBACf,MAAM,EAAE,cAAc;oBACtB,gBAAgB,EAAE,cAAc,EAAE,iDAAiD;oBACnF,IAAI,EAAE,UAAU,EAAE,8BAA8B;oBAChD,QAAQ,EAAE,qCAAgB,CAAC,QAAQ,EAAE,uBAAuB;oBAC5D,UAAU,EAAE,IAAI,EAAE,gCAAgC;oBAClD,WAAW,EAAE,8BAA8B,YAAY,CAAC,kBAAkB,EAAE,EAAE;oBAC9E,2CAA2C;iBAC5C,CAAC;qBACD,mBAAmB,EAAE,CAAA,CAAC,gDAAgD;gBACzE,eAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,yBAAyB,CAAC,CAAA;YACrE,CAAC;iBAAM,CAAC;gBACN,eAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,8BAA8B,CAAC,CAAA;YAC1D,CAAC;YAED,uDAAuD;YACvD,MAAM,aAAa,GAAG,IAAA,yBAAiB,EAAC,YAAY,CAAC,CAAA,CAAC,uDAAuD;YAC7G,MAAM,EAAE;iBACL,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;iBACnB,GAAG,CAAC;gBACH,KAAK,EAAE,CAAC;gBACR,gBAAgB,EAAE,aAAa;aAChC,CAAC;iBACD,KAAK,CAAC,IAAA,gBAAE,EAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAA;YAEpC,eAAM,CAAC,IAAI,CACT,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,CAAC,WAAW,EAAE,EAAE,EACtD,8CAA8C,CAC/C,CAAA;QACH,CAAC,CAAC,CAAA;QAEF,eAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,0CAA0C,CAAC,CAAA;IACrE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,eAAM,CAAC,KAAK,CACV,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,EAC/B,+BAA+B,CAChC,CAAA;QACD,6EAA6E;QAC7E,MAAM,KAAK,CAAA,CAAC,oDAAoD;IAClE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { CreditType } from './balance-calculator';
|
|
2
|
+
import Stripe from 'stripe';
|
|
3
|
+
export declare const stripeApi: {
|
|
4
|
+
credits: {
|
|
5
|
+
/**
|
|
6
|
+
* Creates a customer balance transaction in Stripe to grant credits.
|
|
7
|
+
* NOTE: Database insertion for a local 'creditGrant' record is commented out
|
|
8
|
+
* as the 'creditGrant' table doesn't exist in the current schema.
|
|
9
|
+
*/
|
|
10
|
+
create({ userId, amount, type, expiresAt, description, metadata }: {
|
|
11
|
+
userId: string;
|
|
12
|
+
amount: number;
|
|
13
|
+
type: CreditType;
|
|
14
|
+
expiresAt?: Date;
|
|
15
|
+
description?: string;
|
|
16
|
+
metadata?: Record<string, string | number | null>;
|
|
17
|
+
}): Promise<Stripe.CustomerBalanceTransaction>;
|
|
18
|
+
/**
|
|
19
|
+
* Retrieves the customer's cash balance from Stripe.
|
|
20
|
+
* Note: This is the overall cash balance, typically negative if credits have been granted.
|
|
21
|
+
* It does NOT represent the sum of specific "credit grants".
|
|
22
|
+
*/
|
|
23
|
+
getBalance(userId: string): Promise<number>;
|
|
24
|
+
};
|
|
25
|
+
usage: {
|
|
26
|
+
/**
|
|
27
|
+
* Reports usage to a Stripe meter.
|
|
28
|
+
*/
|
|
29
|
+
report(userId: string, amount: number, metadata?: Record<string, any>): Promise<Stripe.Response<Stripe.Billing.MeterEvent>>;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.stripeApi = void 0;
|
|
30
|
+
const db_1 = __importDefault(require("../db"));
|
|
31
|
+
const schema = __importStar(require("../db/schema"));
|
|
32
|
+
const drizzle_orm_1 = require("drizzle-orm");
|
|
33
|
+
const stripe_1 = require("../util/stripe");
|
|
34
|
+
const balance_calculator_1 = require("./balance-calculator");
|
|
35
|
+
// Helper to get Stripe Customer ID
|
|
36
|
+
async function getCustomerId(userId) {
|
|
37
|
+
const user = await db_1.default.query.user.findFirst({
|
|
38
|
+
where: (0, drizzle_orm_1.eq)(schema.user.id, userId),
|
|
39
|
+
columns: { stripe_customer_id: true }
|
|
40
|
+
});
|
|
41
|
+
if (!user?.stripe_customer_id) {
|
|
42
|
+
throw new Error(`Stripe customer ID not found for user ${userId}`);
|
|
43
|
+
}
|
|
44
|
+
return user.stripe_customer_id;
|
|
45
|
+
}
|
|
46
|
+
exports.stripeApi = {
|
|
47
|
+
credits: {
|
|
48
|
+
/**
|
|
49
|
+
* Creates a customer balance transaction in Stripe to grant credits.
|
|
50
|
+
* NOTE: Database insertion for a local 'creditGrant' record is commented out
|
|
51
|
+
* as the 'creditGrant' table doesn't exist in the current schema.
|
|
52
|
+
*/
|
|
53
|
+
async create({ userId, amount, type, expiresAt, description, metadata = {} }) {
|
|
54
|
+
const customerId = await getCustomerId(userId);
|
|
55
|
+
const priority = balance_calculator_1.CREDIT_PRIORITIES[type];
|
|
56
|
+
const amountInCents = -Math.abs(amount);
|
|
57
|
+
const transaction = await stripe_1.stripeServer.customers.createBalanceTransaction(customerId, {
|
|
58
|
+
amount: amountInCents,
|
|
59
|
+
currency: 'usd',
|
|
60
|
+
description: description ?? `${type} credits granted`,
|
|
61
|
+
metadata: {
|
|
62
|
+
...metadata,
|
|
63
|
+
type: type,
|
|
64
|
+
priority: priority.toString(),
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
return transaction;
|
|
68
|
+
},
|
|
69
|
+
/**
|
|
70
|
+
* Retrieves the customer's cash balance from Stripe.
|
|
71
|
+
* Note: This is the overall cash balance, typically negative if credits have been granted.
|
|
72
|
+
* It does NOT represent the sum of specific "credit grants".
|
|
73
|
+
*/
|
|
74
|
+
async getBalance(userId) {
|
|
75
|
+
const customerId = await getCustomerId(userId);
|
|
76
|
+
const customer = await stripe_1.stripeServer.customers.retrieve(customerId);
|
|
77
|
+
if (customer.deleted) {
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
80
|
+
return customer.balance ?? 0;
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
usage: {
|
|
84
|
+
/**
|
|
85
|
+
* Reports usage to a Stripe meter.
|
|
86
|
+
*/
|
|
87
|
+
async report(userId, amount, metadata = {}) {
|
|
88
|
+
const customerId = await getCustomerId(userId);
|
|
89
|
+
const eventName = 'codebuff_credits_used';
|
|
90
|
+
return stripe_1.stripeServer.billing.meterEvents.create({
|
|
91
|
+
event_name: eventName,
|
|
92
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
93
|
+
payload: {
|
|
94
|
+
stripe_customer_id: customerId,
|
|
95
|
+
value: amount.toString(),
|
|
96
|
+
...metadata
|
|
97
|
+
}
|
|
98
|
+
}).catch((err) => {
|
|
99
|
+
throw err;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=stripe-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-api.js","sourceRoot":"","sources":["../../src/billing/stripe-api.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAsB;AACtB,qDAAsC;AACtC,6CAAgC;AAChC,2CAA6C;AAC7C,6DAAoE;AAGpE,mCAAmC;AACnC,KAAK,UAAU,aAAa,CAAC,MAAc;IACvC,MAAM,IAAI,GAAG,MAAM,YAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;QACvC,KAAK,EAAE,IAAA,gBAAE,EAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC;QACjC,OAAO,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE;KACxC,CAAC,CAAC;IACH,IAAI,CAAC,IAAI,EAAE,kBAAkB,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,yCAAyC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,IAAI,CAAC,kBAAkB,CAAC;AACnC,CAAC;AAEY,QAAA,SAAS,GAAG;IACvB,OAAO,EAAE;QACP;;;;WAIG;QACH,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,GAAG,EAAE,EAOzE;YACC,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;YAC9C,MAAM,QAAQ,GAAG,sCAAiB,CAAC,IAAI,CAAC,CAAA;YAExC,MAAM,aAAa,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAExC,MAAM,WAAW,GAAG,MAAM,qBAAY,CAAC,SAAS,CAAC,wBAAwB,CACrE,UAAU,EACV;gBACI,MAAM,EAAE,aAAa;gBACrB,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,WAAW,IAAI,GAAG,IAAI,kBAAkB;gBACrD,QAAQ,EAAE;oBACN,GAAG,QAAQ;oBACX,IAAI,EAAE,IAAI;oBACV,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE;iBAChC;aACJ,CACJ,CAAC;YAEF,OAAO,WAAW,CAAA;QACpB,CAAC;QAED;;;;WAIG;QACH,KAAK,CAAC,UAAU,CAAC,MAAc;YAC3B,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,qBAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YAEnE,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO,CAAC,CAAC;YACb,CAAC;YAED,OAAO,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;QACjC,CAAC;KACF;IACD,KAAK,EAAE;QACL;;WAEG;QACH,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,MAAc,EAAE,WAAgC,EAAE;YAC7E,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;YAC9C,MAAM,SAAS,GAAG,uBAAuB,CAAC;YAE1C,OAAO,qBAAY,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC;gBAC7C,UAAU,EAAE,SAAS;gBACrB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;gBACxC,OAAO,EAAE;oBACP,kBAAkB,EAAE,UAAU;oBAC9B,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE;oBACxB,GAAG,QAAQ;iBACZ;aACF,CAAC,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;gBACpB,MAAM,GAAG,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC;KACF;CACF,CAAA"}
|