@layer-ai/core 2.0.49 → 2.0.50

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/index.d.ts CHANGED
@@ -23,6 +23,6 @@ export * from './services/task-analysis.js';
23
23
  export { initializeRegistry, getRegistry, getModel, hasModel, getModelEntries } from './lib/registry.js';
24
24
  export { PROVIDER, PROVIDERS, type Provider, callAdapter, normalizeModelId, getProviderForModel } from './lib/provider-factory.js';
25
25
  export { spendingTracker } from './lib/spending-tracker.js';
26
- export { spendingJobs } from './lib/spending-jobs.js';
26
+ export { spendingWorker } from './lib/spending-jobs.js';
27
27
  export { gateSpendingTracker } from './lib/gate-spending-tracker.js';
28
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAC;AAC1C,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,eAAO,MAAM,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,MAAM,CAGrE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAG3E,CAAC;AAGF,cAAc,6BAA6B,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGnI,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAC;AAC1C,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,eAAO,MAAM,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,MAAM,CAGrE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAG3E,CAAC;AAGF,cAAc,6BAA6B,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGnI,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC"}
package/dist/index.js CHANGED
@@ -39,5 +39,5 @@ export { initializeRegistry, getRegistry, getModel, hasModel, getModelEntries }
39
39
  export { PROVIDER, PROVIDERS, callAdapter, normalizeModelId, getProviderForModel } from './lib/provider-factory.js';
40
40
  // Spending Management
41
41
  export { spendingTracker } from './lib/spending-tracker.js';
42
- export { spendingJobs } from './lib/spending-jobs.js';
42
+ export { spendingWorker } from './lib/spending-jobs.js';
43
43
  export { gateSpendingTracker } from './lib/gate-spending-tracker.js';
@@ -1,8 +1,14 @@
1
- export declare const spendingJobs: {
2
- syncSpendingJob(): Promise<void>;
3
- resetSpendingPeriodsJob(): Promise<void>;
4
- resetGateSpendingPeriodsJob(): Promise<void>;
5
- resetUsageCountersJob(): Promise<void>;
6
- startScheduledJobs(): void;
7
- };
1
+ declare class SpendingWorker {
2
+ private isRunning;
3
+ private syncTask;
4
+ private resetTask;
5
+ start(): void;
6
+ stop(): void;
7
+ private syncSpendingJob;
8
+ private resetSpendingPeriodsJob;
9
+ private resetGateSpendingPeriodsJob;
10
+ private resetUsageCountersJob;
11
+ }
12
+ export declare const spendingWorker: SpendingWorker;
13
+ export {};
8
14
  //# sourceMappingURL=spending-jobs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spending-jobs.d.ts","sourceRoot":"","sources":["../../src/lib/spending-jobs.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,YAAY;uBACE,OAAO,CAAC,IAAI,CAAC;+BASL,OAAO,CAAC,IAAI,CAAC;mCAwBT,OAAO,CAAC,IAAI,CAAC;6BAuBnB,OAAO,CAAC,IAAI,CAAC;0BAWtB,IAAI;CAqC3B,CAAC"}
1
+ {"version":3,"file":"spending-jobs.d.ts","sourceRoot":"","sources":["../../src/lib/spending-jobs.ts"],"names":[],"mappings":"AAKA,cAAM,cAAc;IAClB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,SAAS,CAAmC;IAEpD,KAAK;IAkBL,IAAI;YAUU,eAAe;YAiBf,uBAAuB;YAwBvB,2BAA2B;YAuB3B,qBAAqB;CAUpC;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
@@ -1,98 +1,102 @@
1
+ import * as cron from 'node-cron';
1
2
  import { db } from './db/postgres.js';
2
3
  import { cache } from './db/redis.js';
3
4
  import { spendingTracker } from './spending-tracker.js';
4
- export const spendingJobs = {
5
+ class SpendingWorker {
6
+ constructor() {
7
+ this.isRunning = false;
8
+ this.syncTask = null;
9
+ this.resetTask = null;
10
+ }
11
+ start() {
12
+ console.log('[Spending Worker] Starting scheduled jobs');
13
+ // Sync Redis to DB every 5 minutes
14
+ this.syncTask = cron.schedule('*/5 * * * *', async () => {
15
+ await this.syncSpendingJob();
16
+ });
17
+ // Check for billing period resets every hour at :15
18
+ this.resetTask = cron.schedule('15 * * * *', async () => {
19
+ await this.resetSpendingPeriodsJob();
20
+ await this.resetGateSpendingPeriodsJob();
21
+ await this.resetUsageCountersJob();
22
+ });
23
+ console.log('[Spending Worker] Cron schedules activated');
24
+ }
25
+ stop() {
26
+ if (this.syncTask) {
27
+ this.syncTask.stop();
28
+ }
29
+ if (this.resetTask) {
30
+ this.resetTask.stop();
31
+ }
32
+ console.log('[Spending Worker] Stopped');
33
+ }
5
34
  async syncSpendingJob() {
6
- console.log('[Spending Job] Starting periodic sync...');
35
+ if (this.isRunning) {
36
+ console.log('[Spending Worker] Sync already in progress, skipping');
37
+ return;
38
+ }
39
+ this.isRunning = true;
7
40
  try {
41
+ console.log('[Spending Worker] Starting periodic sync...');
8
42
  await spendingTracker.syncAllSpending();
9
43
  }
10
44
  catch (error) {
11
- console.error('[Spending Job] Sync failed:', error);
45
+ console.error('[Spending Worker] Sync failed:', error);
12
46
  }
13
- },
47
+ finally {
48
+ this.isRunning = false;
49
+ }
50
+ }
14
51
  async resetSpendingPeriodsJob() {
15
- console.log('[Spending Job] Checking for billing periods to reset...');
52
+ console.log('[Spending Worker] Checking for billing periods to reset...');
16
53
  try {
17
54
  const usersToReset = await db.getUsersToResetSpending();
18
55
  if (usersToReset.length === 0) {
19
- console.log('[Spending Job] No users need reset');
56
+ console.log('[Spending Worker] No users need reset');
20
57
  return;
21
58
  }
22
- console.log(`[Spending Job] Resetting ${usersToReset.length} users`);
59
+ console.log(`[Spending Worker] Resetting ${usersToReset.length} users`);
23
60
  for (const userId of usersToReset) {
24
61
  await db.resetUserSpending(userId);
25
62
  await cache.invalidateUserSpending(userId);
26
- console.log(`[Spending Job] Reset user ${userId}`);
63
+ console.log(`[Spending Worker] Reset user ${userId}`);
27
64
  }
28
- console.log('[Spending Job] Reset complete');
65
+ console.log('[Spending Worker] Reset complete');
29
66
  }
30
67
  catch (error) {
31
- console.error('[Spending Job] Reset failed:', error);
68
+ console.error('[Spending Worker] Reset failed:', error);
32
69
  }
33
- },
70
+ }
34
71
  async resetGateSpendingPeriodsJob() {
35
- console.log('[Spending Job] Checking for gate spending periods to reset...');
72
+ console.log('[Spending Worker] Checking for gate spending periods to reset...');
36
73
  try {
37
74
  const gatesToReset = await db.getGatesToResetSpending();
38
75
  if (gatesToReset.length === 0) {
39
- console.log('[Spending Job] No gates need reset');
76
+ console.log('[Spending Worker] No gates need reset');
40
77
  return;
41
78
  }
42
- console.log(`[Spending Job] Resetting ${gatesToReset.length} gates`);
79
+ console.log(`[Spending Worker] Resetting ${gatesToReset.length} gates`);
43
80
  for (const gateId of gatesToReset) {
44
81
  await db.resetGateSpending(gateId);
45
- console.log(`[Spending Job] Reset gate ${gateId}`);
82
+ console.log(`[Spending Worker] Reset gate ${gateId}`);
46
83
  }
47
- console.log('[Spending Job] Gate reset complete');
84
+ console.log('[Spending Worker] Gate reset complete');
48
85
  }
49
86
  catch (error) {
50
- console.error('[Spending Job] Gate reset failed:', error);
87
+ console.error('[Spending Worker] Gate reset failed:', error);
51
88
  }
52
- },
89
+ }
53
90
  async resetUsageCountersJob() {
54
- console.log('[Spending Job] Checking for usage counters to reset...');
91
+ console.log('[Spending Worker] Checking for usage counters to reset...');
55
92
  try {
56
93
  await db.resetDailyUsage();
57
94
  await db.resetMonthlyUsage();
58
- console.log('[Spending Job] Usage counters reset complete');
95
+ console.log('[Spending Worker] Usage counters reset complete');
59
96
  }
60
97
  catch (error) {
61
- console.error('[Spending Job] Usage counter reset failed:', error);
98
+ console.error('[Spending Worker] Usage counter reset failed:', error);
62
99
  }
63
- },
64
- startScheduledJobs() {
65
- // Sync Redis to DB every 5 minutes
66
- setInterval(() => {
67
- this.syncSpendingJob().catch(err => {
68
- console.error('[Spending Job] Sync interval error:', err);
69
- });
70
- }, 5 * 60 * 1000);
71
- // Check for billing period resets every hour
72
- setInterval(() => {
73
- this.resetSpendingPeriodsJob().catch(err => {
74
- console.error('[Spending Job] Reset interval error:', err);
75
- });
76
- this.resetGateSpendingPeriodsJob().catch(err => {
77
- console.error('[Spending Job] Gate reset interval error:', err);
78
- });
79
- this.resetUsageCountersJob().catch(err => {
80
- console.error('[Spending Job] Usage counter reset interval error:', err);
81
- });
82
- }, 60 * 60 * 1000);
83
- // Run once on startup
84
- this.syncSpendingJob().catch(err => {
85
- console.error('[Spending Job] Initial sync error:', err);
86
- });
87
- this.resetSpendingPeriodsJob().catch(err => {
88
- console.error('[Spending Job] Initial reset error:', err);
89
- });
90
- this.resetGateSpendingPeriodsJob().catch(err => {
91
- console.error('[Spending Job] Initial gate reset error:', err);
92
- });
93
- this.resetUsageCountersJob().catch(err => {
94
- console.error('[Spending Job] Initial usage counter reset error:', err);
95
- });
96
- console.log('[Spending Job] Scheduled jobs started');
97
- },
98
- };
100
+ }
101
+ }
102
+ export const spendingWorker = new SpendingWorker();
@@ -9,7 +9,7 @@ function getAnthropicClient(apiKey) {
9
9
  }
10
10
  if (!anthropic) {
11
11
  anthropic = new Anthropic({
12
- apiKey: process.env.ANTHROPIC_API_KEY,
12
+ apiKey: process.env.LAYER_PLATFORM_ANTHROPIC_API_KEY,
13
13
  });
14
14
  }
15
15
  return anthropic;
@@ -52,7 +52,7 @@ export class AnthropicAdapter extends BaseProviderAdapter {
52
52
  return super.mapToolChoice(choice);
53
53
  }
54
54
  async call(request, userId) {
55
- const resolved = await resolveApiKey(this.provider, userId, process.env.ANTHROPIC_API_KEY);
55
+ const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_ANTHROPIC_API_KEY);
56
56
  switch (request.type) {
57
57
  case 'chat':
58
58
  return this.handleChat(request, resolved.key, resolved.usedPlatformKey);
@@ -69,7 +69,7 @@ export class AnthropicAdapter extends BaseProviderAdapter {
69
69
  }
70
70
  }
71
71
  async *callStream(request, userId) {
72
- const resolved = await resolveApiKey(this.provider, userId, process.env.ANTHROPIC_API_KEY);
72
+ const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_ANTHROPIC_API_KEY);
73
73
  switch (request.type) {
74
74
  case 'chat':
75
75
  yield* this.handleChatStream(request, resolved.key, resolved.usedPlatformKey);
@@ -9,7 +9,7 @@ function getGoogleClient(apiKey) {
9
9
  return new GoogleGenAI({ apiKey });
10
10
  }
11
11
  if (!client) {
12
- client = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY || '' });
12
+ client = new GoogleGenAI({ apiKey: process.env.LAYER_PLATFORM_GOOGLE_API_KEY || '' });
13
13
  }
14
14
  return client;
15
15
  }
@@ -56,7 +56,7 @@ export class GoogleAdapter extends BaseProviderAdapter {
56
56
  };
57
57
  }
58
58
  async call(request, userId) {
59
- const resolved = await resolveApiKey(this.provider, userId, process.env.GOOGLE_API_KEY);
59
+ const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_GOOGLE_API_KEY);
60
60
  switch (request.type) {
61
61
  case 'chat':
62
62
  return this.handleChat(request, resolved.key, resolved.usedPlatformKey);
@@ -73,7 +73,7 @@ export class GoogleAdapter extends BaseProviderAdapter {
73
73
  }
74
74
  }
75
75
  async *callStream(request, userId) {
76
- const resolved = await resolveApiKey(this.provider, userId, process.env.GOOGLE_API_KEY);
76
+ const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_GOOGLE_API_KEY);
77
77
  switch (request.type) {
78
78
  case 'chat':
79
79
  yield* this.handleChatStream(request, resolved.key, resolved.usedPlatformKey);
@@ -12,7 +12,7 @@ function getMistralClient(apiKey) {
12
12
  // Otherwise use singleton with platform key
13
13
  if (!client) {
14
14
  client = new Mistral({
15
- apiKey: process.env.MISTRAL_API_KEY || '',
15
+ apiKey: process.env.LAYER_PLATFORM_MISTRAL_API_KEY || '',
16
16
  });
17
17
  }
18
18
  return client;
@@ -46,7 +46,7 @@ export class MistralAdapter extends BaseProviderAdapter {
46
46
  }
47
47
  async call(request, userId) {
48
48
  // Resolve API key (BYOK → Platform key)
49
- const resolved = await resolveApiKey(this.provider, userId, process.env.MISTRAL_API_KEY);
49
+ const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_MISTRAL_API_KEY);
50
50
  switch (request.type) {
51
51
  case 'chat':
52
52
  return this.handleChat(request, resolved.key, resolved.usedPlatformKey);
@@ -65,7 +65,7 @@ export class MistralAdapter extends BaseProviderAdapter {
65
65
  }
66
66
  }
67
67
  async *callStream(request, userId) {
68
- const resolved = await resolveApiKey(this.provider, userId, process.env.MISTRAL_API_KEY);
68
+ const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_MISTRAL_API_KEY);
69
69
  switch (request.type) {
70
70
  case 'chat':
71
71
  yield* this.handleChatStream(request, resolved.key, resolved.usedPlatformKey);
@@ -9,7 +9,7 @@ function getOpenAIClient(apiKey) {
9
9
  }
10
10
  if (!openai) {
11
11
  openai = new OpenAI({
12
- apiKey: process.env.OPENAI_API_KEY,
12
+ apiKey: process.env.LAYER_PLATFORM_OPENAI_API_KEY,
13
13
  });
14
14
  }
15
15
  return openai;
@@ -71,7 +71,7 @@ export class OpenAIAdapter extends BaseProviderAdapter {
71
71
  };
72
72
  }
73
73
  async call(request, userId) {
74
- const resolved = await resolveApiKey(this.provider, userId, process.env.OPENAI_API_KEY);
74
+ const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_OPENAI_API_KEY);
75
75
  switch (request.type) {
76
76
  case 'chat':
77
77
  return this.handleChat(request, resolved.key, resolved.usedPlatformKey);
@@ -88,7 +88,7 @@ export class OpenAIAdapter extends BaseProviderAdapter {
88
88
  }
89
89
  }
90
90
  async *callStream(request, userId) {
91
- const resolved = await resolveApiKey(this.provider, userId, process.env.OPENAI_API_KEY);
91
+ const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_OPENAI_API_KEY);
92
92
  switch (request.type) {
93
93
  case 'chat':
94
94
  yield* this.handleChatStream(request, resolved.key, resolved.usedPlatformKey);
@@ -53,7 +53,7 @@ Return ONLY the task type as a single word, nothing else.`;
53
53
  }
54
54
  export async function analyzeTask(description, userPreferences) {
55
55
  const anthropic = new Anthropic({
56
- apiKey: process.env.ANTHROPIC_API_KEY
56
+ apiKey: process.env.LAYER_PLATFORM_ANTHROPIC_API_KEY
57
57
  });
58
58
  const costWeight = userPreferences?.costWeight ?? 0.33;
59
59
  const latencyWeight = userPreferences?.latencyWeight ?? 0.33;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layer-ai/core",
3
- "version": "2.0.49",
3
+ "version": "2.0.50",
4
4
  "description": "Core API routes and services for Layer AI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -34,6 +34,7 @@
34
34
  "ioredis": "^5.3.2",
35
35
  "jsonwebtoken": "^9.0.2",
36
36
  "nanoid": "^5.0.4",
37
+ "node-cron": "^4.2.1",
37
38
  "openai": "^4.24.0",
38
39
  "pg": "^8.11.3",
39
40
  "@layer-ai/sdk": "^2.5.14"
@@ -43,6 +44,7 @@
43
44
  "@types/express": "^4.17.21",
44
45
  "@types/jsonwebtoken": "^9.0.5",
45
46
  "@types/node": "^20.10.4",
47
+ "@types/node-cron": "^3.0.11",
46
48
  "@types/pg": "^8.10.9",
47
49
  "typescript": "^5.3.3"
48
50
  },