@layer-ai/core 2.0.53 → 2.0.54
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/lib/db/migrations/010_add_alert_threshold_tracking.sql +1 -0
- package/dist/lib/db/postgres.d.ts +2 -1
- package/dist/lib/db/postgres.d.ts.map +1 -1
- package/dist/lib/db/postgres.js +5 -3
- package/dist/lib/spending-tracker.d.ts +2 -0
- package/dist/lib/spending-tracker.d.ts.map +1 -1
- package/dist/lib/spending-tracker.js +22 -2
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE users ADD COLUMN IF NOT EXISTS last_spending_alert_threshold INTEGER DEFAULT NULL;
|
|
@@ -13,6 +13,7 @@ export declare const db: {
|
|
|
13
13
|
periodStart: Date;
|
|
14
14
|
status: string;
|
|
15
15
|
limitEnforcementType: string;
|
|
16
|
+
lastAlertThreshold: number | null;
|
|
16
17
|
} | null>;
|
|
17
18
|
updateUserSpending(userId: string, newSpending: number): Promise<void>;
|
|
18
19
|
incrementUserSpending(userId: string, cost: number): Promise<{
|
|
@@ -27,7 +28,7 @@ export declare const db: {
|
|
|
27
28
|
getUsersToResetSpending(): Promise<string[]>;
|
|
28
29
|
resetDailyUsage(): Promise<void>;
|
|
29
30
|
resetMonthlyUsage(): Promise<void>;
|
|
30
|
-
recordSpendingAlert(userId: string): Promise<void>;
|
|
31
|
+
recordSpendingAlert(userId: string, threshold: number): Promise<void>;
|
|
31
32
|
getApiKeyByHash(keyHash: string): Promise<ApiKey | null>;
|
|
32
33
|
createApiKey(userId: string, keyHash: string, keyPrefix: string, name: string): Promise<ApiKey>;
|
|
33
34
|
updateApiKeyLastUsed(keyHash: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../../src/lib/db/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAyB,WAAW,EAAE,MAAM,eAAe,CAAC;AAO5F,iBAAS,OAAO,IAAI,EAAE,CAAC,IAAI,CAqB1B;AA0BD,eAAO,MAAM,EAAE;gBAEK,MAAM,WAAW,GAAG,EAAE;0BASZ,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;oBAQnC,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;sBAQ3B,MAAM,gBAAgB,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;0BAQxC,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;4BAU7B,MAAM,GAAG,OAAO,CAAC;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,WAAW,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,oBAAoB,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;+
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../../src/lib/db/postgres.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/db/postgres.js
CHANGED
|
@@ -70,7 +70,7 @@ export const db = {
|
|
|
70
70
|
},
|
|
71
71
|
// ===== SPENDING MANAGEMENT =====
|
|
72
72
|
async getUserSpending(userId) {
|
|
73
|
-
const result = await getPool().query('SELECT current_month_spending, monthly_spending_limit, spending_period_start, status, limit_enforcement_type FROM users WHERE id = $1', [userId]);
|
|
73
|
+
const result = await getPool().query('SELECT current_month_spending, monthly_spending_limit, spending_period_start, status, limit_enforcement_type, last_spending_alert_threshold FROM users WHERE id = $1', [userId]);
|
|
74
74
|
if (!result.rows[0])
|
|
75
75
|
return null;
|
|
76
76
|
return {
|
|
@@ -79,6 +79,7 @@ export const db = {
|
|
|
79
79
|
periodStart: result.rows[0].spending_period_start,
|
|
80
80
|
status: result.rows[0].status,
|
|
81
81
|
limitEnforcementType: result.rows[0].limit_enforcement_type,
|
|
82
|
+
lastAlertThreshold: result.rows[0].last_spending_alert_threshold ? parseInt(result.rows[0].last_spending_alert_threshold) : null,
|
|
82
83
|
};
|
|
83
84
|
},
|
|
84
85
|
async updateUserSpending(userId, newSpending) {
|
|
@@ -109,6 +110,7 @@ export const db = {
|
|
|
109
110
|
SET current_month_spending = 0,
|
|
110
111
|
spending_period_start = NOW(),
|
|
111
112
|
status = CASE WHEN status = 'over_limit' THEN 'active' ELSE status END,
|
|
113
|
+
last_spending_alert_threshold = NULL,
|
|
112
114
|
updated_at = NOW()
|
|
113
115
|
WHERE id = $1`, [userId]);
|
|
114
116
|
},
|
|
@@ -165,8 +167,8 @@ export const db = {
|
|
|
165
167
|
AND billing_cycle_start < (NOW() AT TIME ZONE 'America/Los_Angeles')::date - INTERVAL '28 days'
|
|
166
168
|
)`);
|
|
167
169
|
},
|
|
168
|
-
async recordSpendingAlert(userId) {
|
|
169
|
-
await getPool().query('UPDATE users SET last_spending_alert_sent_at = NOW(), updated_at = NOW() WHERE id = $1', [userId]);
|
|
170
|
+
async recordSpendingAlert(userId, threshold) {
|
|
171
|
+
await getPool().query('UPDATE users SET last_spending_alert_sent_at = NOW(), last_spending_alert_threshold = $2, updated_at = NOW() WHERE id = $1', [userId, threshold]);
|
|
170
172
|
},
|
|
171
173
|
// API Keys
|
|
172
174
|
async getApiKeyByHash(keyHash) {
|
|
@@ -4,7 +4,9 @@ interface SpendingUpdate {
|
|
|
4
4
|
exceeded?: boolean;
|
|
5
5
|
newSpending?: number;
|
|
6
6
|
}
|
|
7
|
+
type AlertCallback = (userId: string, threshold: number, currentSpending: number, limit: number) => Promise<void>;
|
|
7
8
|
export declare const spendingTracker: {
|
|
9
|
+
setAlertCallback(callback: AlertCallback): void;
|
|
8
10
|
trackSpending(userId: string, cost: number): Promise<SpendingUpdate>;
|
|
9
11
|
trackSpendingDB(userId: string, cost: number): Promise<SpendingUpdate>;
|
|
10
12
|
checkAlertThresholds(userId: string, currentSpending: number, limit: number | null): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spending-tracker.d.ts","sourceRoot":"","sources":["../../src/lib/spending-tracker.ts"],"names":[],"mappings":"AAGA,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,eAAe;
|
|
1
|
+
{"version":3,"file":"spending-tracker.d.ts","sourceRoot":"","sources":["../../src/lib/spending-tracker.ts"],"names":[],"mappings":"AAGA,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAIlH,eAAO,MAAM,eAAe;+BACC,aAAa,GAAG,IAAI;0BAInB,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;4BA0B5C,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;iCAkBzC,MAAM,mBAAmB,MAAM,SAAS,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;8BAcxE,MAAM,aAAa,MAAM,mBAAmB,MAAM,SAAS,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;6BAqBlF,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;uBAY5B,OAAO,CAAC,IAAI,CAAC;sBAad,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAU/C,CAAC"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { db } from './db/postgres.js';
|
|
2
2
|
import { cache } from './db/redis.js';
|
|
3
|
+
let onAlertCallback = null;
|
|
3
4
|
export const spendingTracker = {
|
|
5
|
+
setAlertCallback(callback) {
|
|
6
|
+
onAlertCallback = callback;
|
|
7
|
+
},
|
|
4
8
|
async trackSpending(userId, cost) {
|
|
5
9
|
try {
|
|
6
10
|
const newSpending = await cache.incrementUserSpending(userId, cost);
|
|
@@ -40,7 +44,7 @@ export const spendingTracker = {
|
|
|
40
44
|
if (!limit || limit === 0)
|
|
41
45
|
return;
|
|
42
46
|
const percentage = (currentSpending / limit) * 100;
|
|
43
|
-
const thresholds = [
|
|
47
|
+
const thresholds = [100, 95, 80, 50];
|
|
44
48
|
for (const threshold of thresholds) {
|
|
45
49
|
if (percentage >= threshold) {
|
|
46
50
|
await this.sendAlertIfNeeded(userId, threshold, currentSpending, limit);
|
|
@@ -49,8 +53,24 @@ export const spendingTracker = {
|
|
|
49
53
|
}
|
|
50
54
|
},
|
|
51
55
|
async sendAlertIfNeeded(userId, threshold, currentSpending, limit) {
|
|
56
|
+
const spendingInfo = await db.getUserSpending(userId);
|
|
57
|
+
if (!spendingInfo)
|
|
58
|
+
return;
|
|
59
|
+
if (spendingInfo.limitEnforcementType !== 'alert_only')
|
|
60
|
+
return;
|
|
61
|
+
const lastThreshold = spendingInfo.lastAlertThreshold;
|
|
62
|
+
if (lastThreshold !== null && threshold <= lastThreshold)
|
|
63
|
+
return;
|
|
52
64
|
console.log(`[Spending] Alert: User ${userId} at ${threshold}% of limit ($${currentSpending}/$${limit})`);
|
|
53
|
-
await db.recordSpendingAlert(userId);
|
|
65
|
+
await db.recordSpendingAlert(userId, threshold);
|
|
66
|
+
if (onAlertCallback) {
|
|
67
|
+
try {
|
|
68
|
+
await onAlertCallback(userId, threshold, currentSpending, limit);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error(`[Spending] Alert callback error for user ${userId}:`, error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
54
74
|
},
|
|
55
75
|
async syncSpendingToDB(userId) {
|
|
56
76
|
try {
|