@layer-ai/core 0.5.12 → 0.6.0
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/postgres.d.ts +1 -0
- package/dist/lib/db/postgres.d.ts.map +1 -1
- package/dist/lib/db/postgres.js +5 -1
- package/dist/lib/db/redis.d.ts +1 -0
- package/dist/lib/db/redis.d.ts.map +1 -1
- package/dist/lib/db/redis.js +25 -1
- package/dist/routes/v2/complete.d.ts.map +1 -1
- package/dist/routes/v2/complete.js +32 -16
- package/package.json +2 -2
|
@@ -12,6 +12,7 @@ export declare const db: {
|
|
|
12
12
|
getApiKeysForUser(userId: string): Promise<ApiKey[]>;
|
|
13
13
|
deleteApiKey(id: string, userId: string): Promise<boolean>;
|
|
14
14
|
getGateByUserAndName(userId: string, gateName: string): Promise<Gate | null>;
|
|
15
|
+
getGateByUserAndId(userId: string, gateId: string): Promise<Gate | null>;
|
|
15
16
|
getGatesForUser(userId: string): Promise<Gate[]>;
|
|
16
17
|
createGate(userId: string, data: any): Promise<Gate>;
|
|
17
18
|
getGateById(id: string): Promise<Gate | null>;
|
|
@@ -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,MAAM,eAAe,CAAC;AAO/E,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;
|
|
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,MAAM,eAAe,CAAC;AAO/E,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;CAM9D,CAAC;AAEF,eAAe,OAAO,CAAC"}
|
package/dist/lib/db/postgres.js
CHANGED
|
@@ -84,11 +84,15 @@ export const db = {
|
|
|
84
84
|
const result = await getPool().query('UPDATE api_keys SET is_active = false WHERE id = $1 AND user_id = $2', [id, userId]);
|
|
85
85
|
return (result.rowCount ?? 0) > 0;
|
|
86
86
|
},
|
|
87
|
-
// Gates
|
|
87
|
+
// Gates
|
|
88
88
|
async getGateByUserAndName(userId, gateName) {
|
|
89
89
|
const result = await getPool().query('SELECT * FROM gates WHERE user_id = $1 AND name = $2', [userId, gateName]);
|
|
90
90
|
return result.rows[0] ? toCamelCase(result.rows[0]) : null;
|
|
91
91
|
},
|
|
92
|
+
async getGateByUserAndId(userId, gateId) {
|
|
93
|
+
const result = await getPool().query('SELECT * FROM gates WHERE user_id = $1 AND id = $2', [userId, gateId]);
|
|
94
|
+
return result.rows[0] ? toCamelCase(result.rows[0]) : null;
|
|
95
|
+
},
|
|
92
96
|
async getGatesForUser(userId) {
|
|
93
97
|
const result = await getPool().query('SELECT * FROM gates WHERE user_id = $1 ORDER BY created_at DESC', [userId]);
|
|
94
98
|
return result.rows.map(toCamelCase);
|
package/dist/lib/db/redis.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Gate } from '@layer-ai/sdk';
|
|
|
3
3
|
declare const redis: Redis;
|
|
4
4
|
export declare const cache: {
|
|
5
5
|
getGate(userId: string, gateName: string): Promise<Gate | null>;
|
|
6
|
+
getGateById(userId: string, gateId: string): Promise<Gate | null>;
|
|
6
7
|
setGate(userId: string, gateName: string, gate: Gate): Promise<void>;
|
|
7
8
|
invalidateGate(userId: string, gateName: string): Promise<void>;
|
|
8
9
|
invalidateUserGates(userId: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../../src/lib/db/redis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAG1C,QAAA,MAAM,KAAK,OAcT,CAAC;
|
|
1
|
+
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../../src/lib/db/redis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAG1C,QAAA,MAAM,KAAK,OAcT,CAAC;AAuBH,eAAO,MAAM,KAAK;oBAEM,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;wBAqB3C,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;oBAqBjD,MAAM,YAAY,MAAM,QAAQ,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;2BAe7C,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;gCAUnC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAc1C,OAAO,CAAC,OAAO,CAAC;CAQ/B,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
package/dist/lib/db/redis.js
CHANGED
|
@@ -25,7 +25,10 @@ redis.on('error', (err) => {
|
|
|
25
25
|
// Cache key builders
|
|
26
26
|
const CACHE_TTL = 300;
|
|
27
27
|
function getGateCacheKey(userId, gateName) {
|
|
28
|
-
return `gate:${userId}:${gateName}`;
|
|
28
|
+
return `gate:${userId}:name:${gateName}`;
|
|
29
|
+
}
|
|
30
|
+
function getGateCacheKeyById(userId, gateId) {
|
|
31
|
+
return `gate:${userId}:id:${gateId}`;
|
|
29
32
|
}
|
|
30
33
|
// Cache operations
|
|
31
34
|
export const cache = {
|
|
@@ -47,11 +50,32 @@ export const cache = {
|
|
|
47
50
|
return null; // if we fail, then we fetch from the db
|
|
48
51
|
}
|
|
49
52
|
},
|
|
53
|
+
// get the gate by ID
|
|
54
|
+
async getGateById(userId, gateId) {
|
|
55
|
+
try {
|
|
56
|
+
const key = getGateCacheKeyById(userId, gateId);
|
|
57
|
+
const cached = await redis.get(key);
|
|
58
|
+
if (!cached) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const gate = JSON.parse(cached);
|
|
62
|
+
gate.createdAt = new Date(gate.createdAt);
|
|
63
|
+
gate.updatedAt = new Date(gate.updatedAt);
|
|
64
|
+
return gate;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.error('Redis get error:', error);
|
|
68
|
+
return null; // if we fail, then we fetch from the db
|
|
69
|
+
}
|
|
70
|
+
},
|
|
50
71
|
// Set gate in cache
|
|
51
72
|
async setGate(userId, gateName, gate) {
|
|
52
73
|
try {
|
|
53
74
|
const key = getGateCacheKey(userId, gateName);
|
|
54
75
|
await redis.setex(key, CACHE_TTL, JSON.stringify(gate));
|
|
76
|
+
// Also cache by ID for lookups by gate ID
|
|
77
|
+
const keyById = getGateCacheKeyById(userId, gate.id);
|
|
78
|
+
await redis.setex(keyById, CACHE_TTL, JSON.stringify(gate));
|
|
55
79
|
}
|
|
56
80
|
catch (error) {
|
|
57
81
|
console.error('Redis set error:', error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/complete.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AASpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/complete.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AASpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAkQpC,eAAe,MAAM,CAAC"}
|
|
@@ -13,12 +13,25 @@ function isOverrideAllowed(allowOverrides, field) {
|
|
|
13
13
|
return false;
|
|
14
14
|
return allowOverrides[field] ?? false;
|
|
15
15
|
}
|
|
16
|
-
async function getGateConfig(userId,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
async function getGateConfig(userId, gateIdentifier) {
|
|
17
|
+
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(gateIdentifier);
|
|
18
|
+
let gateConfig = null;
|
|
19
|
+
if (isUUID) {
|
|
20
|
+
gateConfig = await cache.getGateById(userId, gateIdentifier);
|
|
21
|
+
if (!gateConfig) {
|
|
22
|
+
gateConfig = await db.getGateByUserAndId(userId, gateIdentifier);
|
|
23
|
+
if (gateConfig) {
|
|
24
|
+
await cache.setGate(userId, gateConfig.name, gateConfig);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
gateConfig = await cache.getGate(userId, gateIdentifier);
|
|
30
|
+
if (!gateConfig) {
|
|
31
|
+
gateConfig = await db.getGateByUserAndName(userId, gateIdentifier);
|
|
32
|
+
if (gateConfig) {
|
|
33
|
+
await cache.setGate(userId, gateIdentifier, gateConfig);
|
|
34
|
+
}
|
|
22
35
|
}
|
|
23
36
|
}
|
|
24
37
|
return gateConfig;
|
|
@@ -125,27 +138,30 @@ router.post('/', authenticate, async (req, res) => {
|
|
|
125
138
|
}
|
|
126
139
|
const userId = req.userId;
|
|
127
140
|
try {
|
|
128
|
-
const
|
|
129
|
-
if (!
|
|
141
|
+
const rawRequest = req.body;
|
|
142
|
+
if (!rawRequest.gate) {
|
|
130
143
|
res.status(400).json({ error: 'bad_request', message: 'Missing required field: gate' });
|
|
131
144
|
return;
|
|
132
145
|
}
|
|
133
|
-
|
|
134
|
-
|
|
146
|
+
const gateConfig = await getGateConfig(userId, rawRequest.gate);
|
|
147
|
+
if (!gateConfig) {
|
|
148
|
+
res.status(404).json({ error: 'not_found', message: `Gate "${rawRequest.gate}" not found` });
|
|
135
149
|
return;
|
|
136
150
|
}
|
|
137
|
-
|
|
151
|
+
const requestType = rawRequest.type || gateConfig.taskType || 'chat';
|
|
152
|
+
const request = {
|
|
153
|
+
gate: rawRequest.gate,
|
|
154
|
+
type: requestType,
|
|
155
|
+
data: rawRequest.data,
|
|
156
|
+
model: rawRequest.model,
|
|
157
|
+
metadata: rawRequest.metadata
|
|
158
|
+
};
|
|
138
159
|
if (request.type === 'chat') {
|
|
139
160
|
if (!request.data.messages || !Array.isArray(request.data.messages) || request.data.messages.length === 0) {
|
|
140
161
|
res.status(400).json({ error: 'bad_request', message: 'Missing required field: data.messages' });
|
|
141
162
|
return;
|
|
142
163
|
}
|
|
143
164
|
}
|
|
144
|
-
const gateConfig = await getGateConfig(userId, request.gate);
|
|
145
|
-
if (!gateConfig) {
|
|
146
|
-
res.status(404).json({ error: 'not_found', message: `Gate "${request.gate}" not found` });
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
165
|
const finalRequest = resolveFinalRequest(gateConfig, request);
|
|
150
166
|
const { result, modelUsed } = await executeWithRouting(gateConfig, finalRequest);
|
|
151
167
|
const latencyMs = Date.now() - startTime;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layer-ai/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Core API routes and services for Layer AI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"nanoid": "^5.0.4",
|
|
37
37
|
"openai": "^4.24.0",
|
|
38
38
|
"pg": "^8.11.3",
|
|
39
|
-
"@layer-ai/sdk": "^0.
|
|
39
|
+
"@layer-ai/sdk": "^0.6.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/bcryptjs": "^2.4.6",
|