@layer-ai/core 2.0.53 → 2.0.55

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.
@@ -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":"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"}
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,CAAC;QAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;+BAgB3K,MAAM,eAAe,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;kCAOxC,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;0BAexG,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;iCAO/B,MAAM,SAAS,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;mCAO1C,MAAM,mBAAmB,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;8BAOpD,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;+BAarB,OAAO,CAAC,MAAM,EAAE,CAAC;uBASzB,OAAO,CAAC,IAAI,CAAC;yBAmBX,OAAO,CAAC,IAAI,CAAC;gCAkCN,MAAM,aAAa,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;6BAQ5C,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;yBAQnC,MAAM,WAAW,MAAM,aAAa,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;kCAQjE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;8BAO1B,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;qBAQnC,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;iCAS7B,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;+BAQjD,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;4BAQhD,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;uBAQ7B,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;oBAqCpC,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;mBAQ9B,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;mBAgExC,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;qBAUvB,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;2BAkBhC,MAAM,YACJ;QACR,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,OAAO,CAAC,EAAE,IAAI,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,OAAO,CAAC,GAAG,EAAE,CAAC;iCAuCkB,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;6BAQhE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;qCAehB,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;2BAQhC,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;4BAQrD,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;8BASnD,MAAM,YACJ,MAAM,gBACF;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,aACrD,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC;8BAWb,MAAM,YACJ,MAAM,gBACF;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,aACrD,MAAM,GAChB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;8BAWE,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;oCAQrC,MAAM,YAAY,MAAM,YAAY,OAAO,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;kCAW3E,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;qCAQzC,MAAM,GAAQ,OAAO,CAAC,WAAW,EAAE,CAAC;8BAahE,MAAM,QACR,OAAO,CAAC,IAAI,CAAC,aACR,MAAM,GAAG,MAAM,kBACV,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC;2BA8Ca,MAAM,UAAS,MAAM,GAAQ,OAAO,CAAC,GAAG,EAAE,CAAC;2BAW3C,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;+BAQxB,MAAM,UAAS,MAAM,GAAS,OAAO,CAAC,GAAG,EAAE,CAAC;8BAcnE,MAAM,UACN,MAAM,GAAG,IAAI,UACb,eAAe,GAAG,aAAa,GAAG,YAAY,GAAG,UAAU,WAC1D,GAAG,GACX,OAAO,CAAC,IAAI,CAAC;2BAQa,MAAM,UAAS,MAAM,GAAQ,OAAO,CAAC,GAAG,EAAE,CAAC;gCAWtC,MAAM,UAAS,MAAM,GAAS,OAAO,CAAC,GAAG,EAAE,CAAC;4BAchD,MAAM,UAAS,MAAM,GAAS,OAAO,CAAC,GAAG,EAAE,CAAC;yBAa/C,MAAM,aAAa,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;4BAiF7D,MAAM,GAAG,OAAO,CAAC;QAC7C,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,mBAAmB,EAAE,SAAS,GAAG,OAAO,CAAC;QACzC,eAAe,EAAE,MAAM,CAAC;QACxB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,mBAAmB,EAAE,YAAY,GAAG,OAAO,CAAC;QAC5C,cAAc,EAAE,QAAQ,GAAG,WAAW,CAAC;QACvC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,GAAG,IAAI,CAAC;iCAkC0B,MAAM,SAAS,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;uCAStC,MAAM,eAAe,YAAY,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;kCAShE,MAAM,UAAU,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;8BASvD,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;8BASpC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;+BASrB,OAAO,CAAC,MAAM,EAAE,CAAC;mCAab,MAAM,GAAG,OAAO,CAAC;QACpD,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,eAAe,EAAE,MAAM,CAAC;QACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,WAAW,EAAE,YAAY,GAAG,OAAO,CAAC;KACrC,CAAC;CAgDH,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -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;0BACE,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;6BAKlF,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;uBAY5B,OAAO,CAAC,IAAI,CAAC;sBAad,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAU/C,CAAC"}
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 = [50, 80, 95, 100];
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 {
@@ -1 +1 @@
1
- {"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/embeddings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAiRpC,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/embeddings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAqRpC,eAAe,MAAM,CAAC"}
@@ -2,6 +2,7 @@ import { Router } from 'express';
2
2
  import { db } from '../../lib/db/postgres.js';
3
3
  import { callAdapter, normalizeModelId } from '../../lib/provider-factory.js';
4
4
  import { OverrideField } from '@layer-ai/sdk';
5
+ import { spendingTracker } from '../../lib/spending-tracker.js';
5
6
  const router = Router();
6
7
  // MARK:- Helper Functions
7
8
  function isOverrideAllowed(allowOverrides, field) {
@@ -188,6 +189,9 @@ router.post('/', async (req, res) => {
188
189
  cost: result.cost,
189
190
  },
190
191
  }).catch(err => console.error('Failed to log request:', err));
192
+ spendingTracker.trackSpending(userId, result.cost || 0).catch(err => {
193
+ console.error('Failed to track spending:', err);
194
+ });
191
195
  // Return LayerResponse with additional metadata
192
196
  const response = {
193
197
  ...result,
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/image.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAoQpC,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/image.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAwQpC,eAAe,MAAM,CAAC"}
@@ -2,6 +2,7 @@ import { Router } from 'express';
2
2
  import { db } from '../../lib/db/postgres.js';
3
3
  import { callAdapter, normalizeModelId } from '../../lib/provider-factory.js';
4
4
  import { OverrideField } from '@layer-ai/sdk';
5
+ import { spendingTracker } from '../../lib/spending-tracker.js';
5
6
  const router = Router();
6
7
  // MARK:- Helper Functions
7
8
  function isOverrideAllowed(allowOverrides, field) {
@@ -176,6 +177,9 @@ router.post('/', async (req, res) => {
176
177
  cost: result.cost,
177
178
  },
178
179
  }).catch(err => console.error('Failed to log request:', err));
180
+ spendingTracker.trackSpending(userId, result.cost || 0).catch(err => {
181
+ console.error('Failed to track spending:', err);
182
+ });
179
183
  // Return LayerResponse with additional metadata
180
184
  const response = {
181
185
  ...result,
@@ -1 +1 @@
1
- {"version":3,"file":"ocr.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/ocr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AA6PpC,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"ocr.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/ocr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAiQpC,eAAe,MAAM,CAAC"}
@@ -2,6 +2,7 @@ import { Router } from 'express';
2
2
  import { db } from '../../lib/db/postgres.js';
3
3
  import { callAdapter, normalizeModelId } from '../../lib/provider-factory.js';
4
4
  import { OverrideField } from '@layer-ai/sdk';
5
+ import { spendingTracker } from '../../lib/spending-tracker.js';
5
6
  const router = Router();
6
7
  // MARK:- Helper Functions
7
8
  function isOverrideAllowed(allowOverrides, field) {
@@ -170,6 +171,9 @@ router.post('/', async (req, res) => {
170
171
  cost: result.cost,
171
172
  },
172
173
  }).catch(err => console.error('Failed to log request:', err));
174
+ spendingTracker.trackSpending(userId, result.cost || 0).catch(err => {
175
+ console.error('Failed to track spending:', err);
176
+ });
173
177
  // Return LayerResponse with additional metadata
174
178
  const response = {
175
179
  ...result,
@@ -1 +1 @@
1
- {"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/tts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAyPpC,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/tts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AA6PpC,eAAe,MAAM,CAAC"}
@@ -2,6 +2,7 @@ import { Router } from 'express';
2
2
  import { db } from '../../lib/db/postgres.js';
3
3
  import { callAdapter, normalizeModelId } from '../../lib/provider-factory.js';
4
4
  import { OverrideField } from '@layer-ai/sdk';
5
+ import { spendingTracker } from '../../lib/spending-tracker.js';
5
6
  const router = Router();
6
7
  // MARK:- Helper Functions
7
8
  function isOverrideAllowed(allowOverrides, field) {
@@ -166,6 +167,9 @@ router.post('/', async (req, res) => {
166
167
  cost: result.cost,
167
168
  },
168
169
  }).catch(err => console.error('Failed to log request:', err));
170
+ spendingTracker.trackSpending(userId, result.cost || 0).catch(err => {
171
+ console.error('Failed to track spending:', err);
172
+ });
169
173
  // Return LayerResponse with additional metadata
170
174
  const response = {
171
175
  ...result,
@@ -1 +1 @@
1
- {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/video.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAoQpC,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/video.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAwQpC,eAAe,MAAM,CAAC"}
@@ -2,6 +2,7 @@ import { Router } from 'express';
2
2
  import { db } from '../../lib/db/postgres.js';
3
3
  import { callAdapter, normalizeModelId } from '../../lib/provider-factory.js';
4
4
  import { OverrideField } from '@layer-ai/sdk';
5
+ import { spendingTracker } from '../../lib/spending-tracker.js';
5
6
  const router = Router();
6
7
  // MARK:- Helper Functions
7
8
  function isOverrideAllowed(allowOverrides, field) {
@@ -176,6 +177,9 @@ router.post('/', async (req, res) => {
176
177
  cost: result.cost,
177
178
  },
178
179
  }).catch(err => console.error('Failed to log request:', err));
180
+ spendingTracker.trackSpending(userId, result.cost || 0).catch(err => {
181
+ console.error('Failed to track spending:', err);
182
+ });
179
183
  // Return LayerResponse with additional metadata
180
184
  const response = {
181
185
  ...result,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layer-ai/core",
3
- "version": "2.0.53",
3
+ "version": "2.0.55",
4
4
  "description": "Core API routes and services for Layer AI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",