@layer-ai/core 0.8.0 → 0.8.2

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
@@ -1,5 +1,6 @@
1
1
  export { default as authRouter } from './routes/v1/auth.js';
2
2
  export { default as gatesRouter } from './routes/v1/gates.js';
3
+ export { default as gateHistoryRouter } from './routes/v1/gate-history.js';
3
4
  export { default as keysRouter } from './routes/v1/keys.js';
4
5
  export { default as logsRouter } from './routes/v1/logs.js';
5
6
  export { default as completeRouter } from './routes/v2/complete.js';
@@ -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,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,YAAY,EAAE,MAAM,sBAAsB,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,QAAQ,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,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,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,YAAY,EAAE,MAAM,sBAAsB,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,QAAQ,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // Routes
2
2
  export { default as authRouter } from './routes/v1/auth.js';
3
3
  export { default as gatesRouter } from './routes/v1/gates.js';
4
+ export { default as gateHistoryRouter } from './routes/v1/gate-history.js';
4
5
  export { default as keysRouter } from './routes/v1/keys.js';
5
6
  export { default as logsRouter } from './routes/v1/logs.js';
6
7
  export { default as completeRouter } from './routes/v2/complete.js';
@@ -40,6 +40,11 @@ export declare const db: {
40
40
  deleteProviderKey(userId: string, provider: string): Promise<boolean>;
41
41
  hardDeleteProviderKey(userId: string, provider: string): Promise<boolean>;
42
42
  getDeletedProviderKeys(daysOld?: number): Promise<ProviderKey[]>;
43
+ createGateHistory(gateId: string, gate: Partial<Gate>, appliedBy: "user" | "auto", changedFields?: string[]): Promise<void>;
44
+ getGateHistory(gateId: string, limit?: number): Promise<any[]>;
45
+ getGateHistoryById(id: string): Promise<any | null>;
46
+ createActivityLog(gateId: string, userId: string | null, action: "manual_update" | "auto_update" | "reanalysis" | "rollback", details: any): Promise<void>;
47
+ getActivityLog(gateId: string, limit?: number): Promise<any[]>;
43
48
  };
44
49
  export default getPool;
45
50
  //# sourceMappingURL=postgres.d.ts.map
@@ -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;6BASrC,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;oBA4BpC,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;mBAQ9B,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;mBA4CxC,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;qBASvB,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;iCAgBP,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;kCAQvC,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;qCAQzC,MAAM,GAAQ,OAAO,CAAC,WAAW,EAAE,CAAC;CAU3E,CAAC;AAEF,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../../src/lib/db/postgres.ts"],"names":[],"mappings":"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"}
@@ -234,5 +234,67 @@ export const db = {
234
234
  ORDER BY deleted_at ASC`, [daysOld]);
235
235
  return result.rows.map(toCamelCase);
236
236
  },
237
+ // Gate History
238
+ async createGateHistory(gateId, gate, appliedBy, changedFields) {
239
+ await getPool().query(`INSERT INTO gate_history (
240
+ gate_id, name, description, model, fallback_models, routing_strategy,
241
+ temperature, max_tokens, top_p, cost_weight, latency_weight, quality_weight,
242
+ analysis_method, task_type, task_analysis, system_prompt,
243
+ reanalysis_period, auto_apply_recommendations, applied_by, applied_at, changed_fields
244
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, NOW(), $20)`, [
245
+ gateId,
246
+ gate.name,
247
+ gate.description,
248
+ gate.model,
249
+ JSON.stringify(gate.fallbackModels || []),
250
+ gate.routingStrategy,
251
+ gate.temperature,
252
+ gate.maxTokens,
253
+ gate.topP,
254
+ gate.costWeight ?? 0.33,
255
+ gate.latencyWeight ?? 0.33,
256
+ gate.qualityWeight ?? 0.34,
257
+ gate.analysisMethod ?? 'balanced',
258
+ gate.taskType,
259
+ gate.taskAnalysis ? JSON.stringify(gate.taskAnalysis) : null,
260
+ gate.systemPrompt,
261
+ gate.reanalysisPeriod ?? 'never',
262
+ gate.autoApplyRecommendations ?? false,
263
+ appliedBy,
264
+ changedFields ? JSON.stringify(changedFields) : null
265
+ ]);
266
+ // Prune old history entries, keeping only the last 20
267
+ await getPool().query(`DELETE FROM gate_history
268
+ WHERE gate_id = $1
269
+ AND id NOT IN (
270
+ SELECT id FROM gate_history
271
+ WHERE gate_id = $1
272
+ ORDER BY created_at DESC
273
+ LIMIT 20
274
+ )`, [gateId]);
275
+ },
276
+ async getGateHistory(gateId, limit = 20) {
277
+ const result = await getPool().query(`SELECT * FROM gate_history
278
+ WHERE gate_id = $1
279
+ ORDER BY created_at DESC
280
+ LIMIT $2`, [gateId, limit]);
281
+ return result.rows.map(toCamelCase);
282
+ },
283
+ async getGateHistoryById(id) {
284
+ const result = await getPool().query('SELECT * FROM gate_history WHERE id = $1', [id]);
285
+ return result.rows[0] ? toCamelCase(result.rows[0]) : null;
286
+ },
287
+ // Activity Log
288
+ async createActivityLog(gateId, userId, action, details) {
289
+ await getPool().query(`INSERT INTO gate_activity_log (gate_id, user_id, action, details)
290
+ VALUES ($1, $2, $3, $4)`, [gateId, userId, action, details ? JSON.stringify(details) : null]);
291
+ },
292
+ async getActivityLog(gateId, limit = 50) {
293
+ const result = await getPool().query(`SELECT * FROM gate_activity_log
294
+ WHERE gate_id = $1
295
+ ORDER BY timestamp DESC
296
+ LIMIT $2`, [gateId, limit]);
297
+ return result.rows.map(toCamelCase);
298
+ },
237
299
  };
238
300
  export default getPool;
@@ -0,0 +1,4 @@
1
+ import { Router } from 'express';
2
+ declare const router: Router;
3
+ export default router;
4
+ //# sourceMappingURL=gate-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-history.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/gate-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,QAAA,MAAM,MAAM,EAAE,MAAiB,CAAC;AA6HhC,eAAe,MAAM,CAAC"}
@@ -0,0 +1,108 @@
1
+ import { Router } from 'express';
2
+ import { db } from '../../lib/db/postgres.js';
3
+ const router = Router();
4
+ /**
5
+ * GET /v1/gates/:gateId/history
6
+ * Get history for a gate
7
+ */
8
+ router.get('/:gateId/history', async (req, res) => {
9
+ try {
10
+ const { gateId } = req.params;
11
+ const limit = req.query.limit ? parseInt(req.query.limit, 10) : 20;
12
+ const gate = await db.getGateById(gateId);
13
+ if (!gate) {
14
+ return res.status(404).json({ error: 'Gate not found' });
15
+ }
16
+ if (gate.userId !== req.userId) {
17
+ return res.status(403).json({ error: 'Forbidden' });
18
+ }
19
+ const history = await db.getGateHistory(gateId, limit);
20
+ res.json(history);
21
+ }
22
+ catch (error) {
23
+ console.error('Error fetching gate history:', error);
24
+ res.status(500).json({ error: 'Failed to fetch history' });
25
+ }
26
+ });
27
+ /**
28
+ * GET /v1/gates/:gateId/activity
29
+ * Get activity log for a gate
30
+ */
31
+ router.get('/:gateId/activity', async (req, res) => {
32
+ try {
33
+ const { gateId } = req.params;
34
+ const limit = req.query.limit ? parseInt(req.query.limit, 10) : 50;
35
+ const gate = await db.getGateById(gateId);
36
+ if (!gate) {
37
+ return res.status(404).json({ error: 'Gate not found' });
38
+ }
39
+ if (gate.userId !== req.userId) {
40
+ return res.status(403).json({ error: 'Forbidden' });
41
+ }
42
+ const activity = await db.getActivityLog(gateId, limit);
43
+ res.json(activity);
44
+ }
45
+ catch (error) {
46
+ console.error('Error fetching gate activity:', error);
47
+ res.status(500).json({ error: 'Failed to fetch activity' });
48
+ }
49
+ });
50
+ /**
51
+ * POST /v1/gates/:gateId/rollback/:historyId
52
+ * Rollback gate to a previous configuration
53
+ */
54
+ router.post('/:gateId/rollback/:historyId', async (req, res) => {
55
+ try {
56
+ const { gateId, historyId } = req.params;
57
+ const gate = await db.getGateById(gateId);
58
+ if (!gate) {
59
+ return res.status(404).json({ error: 'Gate not found' });
60
+ }
61
+ if (gate.userId !== req.userId) {
62
+ return res.status(403).json({ error: 'Forbidden' });
63
+ }
64
+ // Get the history entry to rollback to
65
+ const historyEntry = await db.getGateHistoryById(historyId);
66
+ if (!historyEntry) {
67
+ return res.status(404).json({ error: 'History entry not found' });
68
+ }
69
+ if (historyEntry.gateId !== gateId) {
70
+ return res.status(400).json({ error: 'History entry does not belong to this gate' });
71
+ }
72
+ // Create a snapshot of current state before rollback
73
+ await db.createGateHistory(gateId, gate, 'user');
74
+ // Update gate with historical configuration
75
+ const updatedGate = await db.updateGate(gateId, {
76
+ name: historyEntry.name,
77
+ description: historyEntry.description,
78
+ model: historyEntry.model,
79
+ fallbackModels: historyEntry.fallbackModels,
80
+ routingStrategy: historyEntry.routingStrategy,
81
+ temperature: historyEntry.temperature,
82
+ maxTokens: historyEntry.maxTokens,
83
+ topP: historyEntry.topP,
84
+ costWeight: historyEntry.costWeight,
85
+ latencyWeight: historyEntry.latencyWeight,
86
+ qualityWeight: historyEntry.qualityWeight,
87
+ analysisMethod: historyEntry.analysisMethod,
88
+ taskType: historyEntry.taskType,
89
+ taskAnalysis: historyEntry.taskAnalysis,
90
+ systemPrompt: historyEntry.systemPrompt,
91
+ reanalysisPeriod: historyEntry.reanalysisPeriod,
92
+ autoApplyRecommendations: historyEntry.autoApplyRecommendations,
93
+ });
94
+ // Log the rollback activity
95
+ await db.createActivityLog(gateId, req.userId, 'rollback', {
96
+ historyId,
97
+ previousModel: gate.model,
98
+ rolledBackToModel: historyEntry.model,
99
+ appliedAt: historyEntry.appliedAt,
100
+ });
101
+ res.json(updatedGate);
102
+ }
103
+ catch (error) {
104
+ console.error('Error rolling back gate:', error);
105
+ res.status(500).json({ error: 'Failed to rollback gate' });
106
+ }
107
+ });
108
+ export default router;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layer-ai/core",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Core API routes and services for Layer AI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",