@layer-ai/core 0.5.12 → 0.7.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 +17 -1
- package/dist/lib/db/postgres.d.ts.map +1 -1
- package/dist/lib/db/postgres.js +43 -2
- 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/lib/encryption.d.ts +9 -0
- package/dist/lib/encryption.d.ts.map +1 -0
- package/dist/lib/encryption.js +39 -0
- package/dist/routes/v2/complete.d.ts.map +1 -1
- package/dist/routes/v2/complete.js +32 -16
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import pg from 'pg';
|
|
2
|
-
import type { User, ApiKey, Gate } from '@layer-ai/sdk';
|
|
2
|
+
import type { User, ApiKey, Gate, ProviderKey } from '@layer-ai/sdk';
|
|
3
3
|
declare function getPool(): pg.Pool;
|
|
4
4
|
export declare const db: {
|
|
5
5
|
query(text: string, params?: any[]): Promise<pg.QueryResult<any>>;
|
|
@@ -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>;
|
|
@@ -24,6 +25,21 @@ export declare const db: {
|
|
|
24
25
|
} | null>;
|
|
25
26
|
createSessionKey(userId: string): Promise<string>;
|
|
26
27
|
deleteSessionKeysForUser(userId: string): Promise<void>;
|
|
28
|
+
getProviderKey(userId: string, provider: string): Promise<ProviderKey | null>;
|
|
29
|
+
getProviderKeys(userId: string): Promise<ProviderKey[]>;
|
|
30
|
+
createProviderKey(userId: string, provider: string, encryptedKey: {
|
|
31
|
+
encrypted: string;
|
|
32
|
+
iv: string;
|
|
33
|
+
authTag: string;
|
|
34
|
+
}, keyPrefix: string): Promise<ProviderKey>;
|
|
35
|
+
updateProviderKey(userId: string, provider: string, encryptedKey: {
|
|
36
|
+
encrypted: string;
|
|
37
|
+
iv: string;
|
|
38
|
+
authTag: string;
|
|
39
|
+
}, keyPrefix: string): Promise<ProviderKey | null>;
|
|
40
|
+
deleteProviderKey(userId: string, provider: string): Promise<boolean>;
|
|
41
|
+
hardDeleteProviderKey(userId: string, provider: string): Promise<boolean>;
|
|
42
|
+
getDeletedProviderKeys(daysOld?: number): Promise<ProviderKey[]>;
|
|
27
43
|
};
|
|
28
44
|
export default getPool;
|
|
29
45
|
//# 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,MAAM,eAAe,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,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"}
|
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);
|
|
@@ -192,6 +196,43 @@ export const db = {
|
|
|
192
196
|
},
|
|
193
197
|
async deleteSessionKeysForUser(userId) {
|
|
194
198
|
await getPool().query('DELETE FROM session_keys WHERE user_id = $1', [userId]);
|
|
195
|
-
}
|
|
199
|
+
},
|
|
200
|
+
// Provider Keys (BYOK)
|
|
201
|
+
async getProviderKey(userId, provider) {
|
|
202
|
+
const result = await getPool().query('SELECT * FROM provider_keys WHERE user_id = $1 AND provider = $2 AND deleted_at IS NULL', [userId, provider]);
|
|
203
|
+
return result.rows[0] ? toCamelCase(result.rows[0]) : null;
|
|
204
|
+
},
|
|
205
|
+
async getProviderKeys(userId) {
|
|
206
|
+
const result = await getPool().query('SELECT * FROM provider_keys WHERE user_id = $1 AND deleted_at IS NULL ORDER BY created_at DESC', [userId]);
|
|
207
|
+
return result.rows.map(toCamelCase);
|
|
208
|
+
},
|
|
209
|
+
async createProviderKey(userId, provider, encryptedKey, keyPrefix) {
|
|
210
|
+
const result = await getPool().query(`INSERT INTO provider_keys (user_id, provider, encrypted_key, key_prefix)
|
|
211
|
+
VALUES ($1, $2, $3, $4)
|
|
212
|
+
RETURNING *`, [userId, provider, JSON.stringify(encryptedKey), keyPrefix]);
|
|
213
|
+
return toCamelCase(result.rows[0]);
|
|
214
|
+
},
|
|
215
|
+
async updateProviderKey(userId, provider, encryptedKey, keyPrefix) {
|
|
216
|
+
const result = await getPool().query(`UPDATE provider_keys
|
|
217
|
+
SET encrypted_key = $3, key_prefix = $4, deleted_at = NULL, updated_at = NOW()
|
|
218
|
+
WHERE user_id = $1 AND provider = $2
|
|
219
|
+
RETURNING *`, [userId, provider, JSON.stringify(encryptedKey), keyPrefix]);
|
|
220
|
+
return result.rows[0] ? toCamelCase(result.rows[0]) : null;
|
|
221
|
+
},
|
|
222
|
+
async deleteProviderKey(userId, provider) {
|
|
223
|
+
const result = await getPool().query('UPDATE provider_keys SET deleted_at = NOW() WHERE user_id = $1 AND provider = $2 AND deleted_at IS NULL', [userId, provider]);
|
|
224
|
+
return (result.rowCount ?? 0) > 0;
|
|
225
|
+
},
|
|
226
|
+
async hardDeleteProviderKey(userId, provider) {
|
|
227
|
+
const result = await getPool().query('DELETE FROM provider_keys WHERE user_id = $1 AND provider = $2', [userId, provider]);
|
|
228
|
+
return (result.rowCount ?? 0) > 0;
|
|
229
|
+
},
|
|
230
|
+
async getDeletedProviderKeys(daysOld = 90) {
|
|
231
|
+
const result = await getPool().query(`SELECT * FROM provider_keys
|
|
232
|
+
WHERE deleted_at IS NOT NULL
|
|
233
|
+
AND deleted_at < NOW() - INTERVAL '1 day' * $1
|
|
234
|
+
ORDER BY deleted_at ASC`, [daysOld]);
|
|
235
|
+
return result.rows.map(toCamelCase);
|
|
236
|
+
},
|
|
196
237
|
};
|
|
197
238
|
export default getPool;
|
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);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface EncryptedData {
|
|
2
|
+
encrypted: string;
|
|
3
|
+
iv: string;
|
|
4
|
+
authTag: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function encrypt(plaintext: string, masterKey: string): EncryptedData;
|
|
7
|
+
export declare function decrypt(encryptedData: EncryptedData, masterKey: string): string;
|
|
8
|
+
export declare function generateEncryptionKey(): string;
|
|
9
|
+
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/lib/encryption.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,CAqB3E;AAED,wBAAgB,OAAO,CAAC,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAmB/E;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
2
|
+
export function encrypt(plaintext, masterKey) {
|
|
3
|
+
if (!plaintext) {
|
|
4
|
+
throw new Error("Plaintext is required");
|
|
5
|
+
}
|
|
6
|
+
if (!masterKey || masterKey.length !== 64) {
|
|
7
|
+
throw new Error("Master key must be a 64-character hex string (32 bytes)");
|
|
8
|
+
}
|
|
9
|
+
const iv = randomBytes(12);
|
|
10
|
+
const keyBuffer = Buffer.from(masterKey, "hex");
|
|
11
|
+
const cipher = createCipheriv("aes-256-gcm", keyBuffer, iv);
|
|
12
|
+
let encrypted = cipher.update(plaintext, "utf-8", "hex");
|
|
13
|
+
encrypted += cipher.final("hex");
|
|
14
|
+
const authTag = cipher.getAuthTag();
|
|
15
|
+
return {
|
|
16
|
+
encrypted,
|
|
17
|
+
iv: iv.toString("hex"),
|
|
18
|
+
authTag: authTag.toString("hex"),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function decrypt(encryptedData, masterKey) {
|
|
22
|
+
if (!encryptedData || !encryptedData.encrypted || !encryptedData.iv || !encryptedData.authTag) {
|
|
23
|
+
throw new Error("Invalid encrypted data structure");
|
|
24
|
+
}
|
|
25
|
+
if (!masterKey || masterKey.length !== 64) {
|
|
26
|
+
throw new Error("Master key must be a 64-character hex string (32 bytes)");
|
|
27
|
+
}
|
|
28
|
+
const keyBuffer = Buffer.from(masterKey, "hex");
|
|
29
|
+
const ivBuffer = Buffer.from(encryptedData.iv, "hex");
|
|
30
|
+
const authTagBuffer = Buffer.from(encryptedData.authTag, "hex");
|
|
31
|
+
const decipher = createDecipheriv("aes-256-gcm", keyBuffer, ivBuffer);
|
|
32
|
+
decipher.setAuthTag(authTagBuffer);
|
|
33
|
+
let decrypted = decipher.update(encryptedData.encrypted, "hex", "utf8");
|
|
34
|
+
decrypted += decipher.final("utf8");
|
|
35
|
+
return decrypted;
|
|
36
|
+
}
|
|
37
|
+
export function generateEncryptionKey() {
|
|
38
|
+
return randomBytes(32).toString("hex");
|
|
39
|
+
}
|
|
@@ -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.7.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.7.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/bcryptjs": "^2.4.6",
|