@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.
@@ -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;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;4BAQpD,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"}
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"}
@@ -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;
@@ -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;AAmBH,eAAO,MAAM,KAAK;oBAEM,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;oBAqB/C,MAAM,YAAY,MAAM,QAAQ,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;2BAW7C,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"}
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"}
@@ -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;AAgPpC,eAAe,MAAM,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, gateName) {
17
- let gateConfig = await cache.getGate(userId, gateName);
18
- if (!gateConfig) {
19
- gateConfig = await db.getGateByUserAndName(userId, gateName);
20
- if (gateConfig) {
21
- await cache.setGate(userId, gateName, gateConfig);
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 request = req.body;
129
- if (!request.gate) {
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
- if (!request.type) {
134
- res.status(400).json({ error: 'bad_request', message: 'Missing required field: type' });
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
- // Validate chat-specific requirements
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.5.12",
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.5.2"
39
+ "@layer-ai/sdk": "^0.7.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/bcryptjs": "^2.4.6",