streamby-core 0.29.12 → 0.32.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,87 +1,31 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.dbConnectionRouter = dbConnectionRouter;
37
4
  const express_1 = require("express");
38
5
  const mongodb_1 = require("mongodb");
39
6
  const manager_1 = require("../../models/manager");
40
7
  const auth_1 = require("../../utils/auth");
41
- const connectionManager_1 = require("../../adapters/database/connectionManager");
42
- const builtinAccess_1 = require("../../utils/builtinAccess");
43
- const userIntegration_1 = require("../../services/userIntegration");
8
+ const sanitize_1 = require("../../utils/sanitize");
9
+ const encryption_1 = require("../../utils/encryption");
10
+ const connectionResolver_1 = require("../../services/connectionResolver");
44
11
  const dbConnection_1 = require("../../services/dbConnection");
45
12
  const VALID_DB_TYPES = ['postgresql', 'mongodb'];
46
- // `builtinId` is config.databases[].id (e.g. 'mongo'), NOT the DbConnection row's own id —
47
- // those are different values since TCORE-69's backfill gives each row its own UUID.
48
- function resolveBuiltinConnection(builtinId, config) {
49
- const db = (config.databases ?? []).find(d => d.id === builtinId);
50
- if (!db)
51
- return { error: `Database '${builtinId}' not found in config`, status: 404 };
52
- try {
53
- const { client, type } = (0, connectionManager_1.getConnection)(builtinId);
54
- return { client: client, dbType: type };
13
+ // Resolves the client for `connId`, runs `fn`, and writes the response — releasing
14
+ // ephemeral (non-builtin) clients afterward. Builtin clients are pooled and owned by
15
+ // connectionManager, never closed here. Responds with the resolve error directly if
16
+ // resolution fails, so callers never have to distinguish an error shape from fn's result.
17
+ async function withResolvedDbClient(project, connId, config, auth, res, fn) {
18
+ const resolved = await (0, connectionResolver_1.resolveDbConnectionClient)(project, connId, config, auth);
19
+ if ('error' in resolved) {
20
+ res.status(resolved.status).json({ message: resolved.error });
21
+ return;
55
22
  }
56
- catch (e) {
57
- return { error: e.message, status: 503 };
23
+ try {
24
+ await fn(resolved);
58
25
  }
59
- }
60
- // Finds the connection row + classifies it. A row is builtin iff conn.source === 'builtin'
61
- // (persisted at creation/backfill time) — NOT by comparing the row's own id against
62
- // config.databases, which no longer holds since builtin rows get their own generated id.
63
- function findDbConnection(project, connId) {
64
- return project.dbConnections?.find((c) => c.id === connId);
65
- }
66
- async function getDecryptedConnectionString(project, connId) {
67
- const conn = project.dbConnections?.find((c) => c.id === connId);
68
- if (!conn)
69
- return { error: 'DB connection not found', status: 404 };
70
- if (conn.source === 'integration') {
71
- if (!conn.integrationId)
72
- return { error: 'Connection is missing its integrationId', status: 500 };
73
- const credential = await (0, userIntegration_1.getDecryptedIntegrationCredentialById)(conn.integrationId);
74
- if (!credential)
75
- return { error: 'Integration not found', status: 400 };
76
- return { connectionString: credential, conn };
26
+ finally {
27
+ await (0, connectionResolver_1.releaseDbClient)(resolved);
77
28
  }
78
- const { decrypt, isEncryptionKeySet } = await Promise.resolve().then(() => __importStar(require('../../utils/encryption')));
79
- if (!isEncryptionKeySet())
80
- return { error: 'Encryption key is not set', status: 500 };
81
- const credential = project.credentials?.find((c) => c.id === conn.credentialId);
82
- if (!credential)
83
- return { error: 'Credential not found in project', status: 400 };
84
- return { connectionString: decrypt(credential.encryptedValue), conn };
85
29
  }
86
30
  function dbConnectionRouter(config) {
87
31
  const router = (0, express_1.Router)();
@@ -95,7 +39,7 @@ function dbConnectionRouter(config) {
95
39
  return res.status(404).json({ message: 'Project not found' });
96
40
  if (!(0, auth_1.isProjectMember)(project, auth.userId))
97
41
  return res.status(403).json({ message: 'Unauthorized project access' });
98
- return res.status(200).json({ data: project.dbConnections || [] });
42
+ return res.status(200).json({ data: (0, sanitize_1.sanitizeConnections)(project.dbConnections) });
99
43
  }
100
44
  catch (err) {
101
45
  res.status(500).json({ message: 'Failed to fetch DB connections', details: err.message });
@@ -108,15 +52,15 @@ function dbConnectionRouter(config) {
108
52
  if (auth.role !== 'admin' && auth.role !== 'editor') {
109
53
  return res.status(403).json({ message: 'Permission denied' });
110
54
  }
111
- const { name, dbType, credentialId, integrationId, description } = req.body;
55
+ const { name, dbType, credential, integrationId, description } = req.body;
112
56
  if (!name || !dbType) {
113
57
  return res.status(400).json({ message: 'name and dbType are required' });
114
58
  }
115
- if (!credentialId && !integrationId) {
116
- return res.status(400).json({ message: 'Either credentialId or integrationId is required' });
59
+ if (!credential && !integrationId) {
60
+ return res.status(400).json({ message: 'Either credential or integrationId is required' });
117
61
  }
118
- if (credentialId && integrationId) {
119
- return res.status(400).json({ message: 'Provide only one of credentialId or integrationId' });
62
+ if (credential && integrationId) {
63
+ return res.status(400).json({ message: 'Provide only one of credential or integrationId' });
120
64
  }
121
65
  if (!VALID_DB_TYPES.includes(dbType)) {
122
66
  return res.status(400).json({ message: `dbType must be one of: ${VALID_DB_TYPES.join(', ')}` });
@@ -126,6 +70,7 @@ function dbConnectionRouter(config) {
126
70
  return res.status(404).json({ message: 'Project not found' });
127
71
  if (!(0, auth_1.isProjectMember)(project, auth.userId))
128
72
  return res.status(403).json({ message: 'Unauthorized project access' });
73
+ let encryptedCredential;
129
74
  if (integrationId) {
130
75
  const UserIntegrationModel = (0, manager_1.getModel)('user_integrations');
131
76
  const integration = await UserIntegrationModel.findOne({ id: integrationId, userId: auth.userId });
@@ -135,23 +80,23 @@ function dbConnectionRouter(config) {
135
80
  return res.status(400).json({ message: 'Integration is not a database integration' });
136
81
  }
137
82
  else {
138
- const credExists = project.credentials?.some((c) => c.id === credentialId);
139
- if (!credExists)
140
- return res.status(400).json({ message: 'Credential not found in project' });
83
+ if (!(0, encryption_1.isEncryptionKeySet)())
84
+ return res.status(500).json({ message: 'Encryption key is not set' });
85
+ encryptedCredential = (0, encryption_1.encrypt)(credential);
141
86
  }
142
87
  const connection = {
143
88
  id: new mongodb_1.ObjectId().toHexString(),
144
89
  name,
145
90
  dbType,
146
- credentialId: credentialId ?? '',
147
91
  projectId: req.params.id,
148
92
  createdAt: new Date(),
149
93
  source: integrationId ? 'integration' : 'manual',
150
94
  ...(integrationId && { integrationId }),
95
+ ...(encryptedCredential !== undefined && { encryptedCredential }),
151
96
  ...(description !== undefined && { description }),
152
97
  };
153
98
  await Project.update({ _id: req.params.id }, { $push: { dbConnections: connection } });
154
- return res.status(201).json({ data: connection });
99
+ return res.status(201).json({ data: (0, sanitize_1.sanitizeConnection)(connection) });
155
100
  }
156
101
  catch (err) {
157
102
  res.status(500).json({ message: 'Failed to add DB connection', details: err.message });
@@ -169,7 +114,7 @@ function dbConnectionRouter(config) {
169
114
  return res.status(404).json({ message: 'Project not found' });
170
115
  if (!(0, auth_1.isProjectMember)(project, auth.userId))
171
116
  return res.status(403).json({ message: 'Unauthorized project access' });
172
- const conn = findDbConnection(project, req.params.connId);
117
+ const conn = (0, connectionResolver_1.findDbConnection)(project, req.params.connId);
173
118
  if (!conn)
174
119
  return res.status(404).json({ message: 'DB connection not found' });
175
120
  if (conn.source === 'builtin') {
@@ -191,25 +136,10 @@ function dbConnectionRouter(config) {
191
136
  return res.status(404).json({ message: 'Project not found' });
192
137
  if (!(0, auth_1.isProjectMember)(project, auth.userId))
193
138
  return res.status(403).json({ message: 'Unauthorized project access' });
194
- const conn = findDbConnection(project, req.params.connId);
195
- if (!conn)
196
- return res.status(404).json({ message: 'DB connection not found' });
197
- if (conn.source === 'builtin') {
198
- const builtinId = conn.integrationId;
199
- if (!(await (0, builtinAccess_1.assertBuiltinAccess)(auth, builtinId, config, 'database'))) {
200
- return res.status(403).json({ message: 'Access to this built-in database is not permitted' });
201
- }
202
- const internal = resolveBuiltinConnection(builtinId, config);
203
- if ('error' in internal)
204
- return res.status(internal.status).json({ message: internal.error });
205
- const tables = await (0, dbConnection_1.listTablesInternal)(internal.client, internal.dbType, req.params.id);
206
- return res.status(200).json({ data: tables });
207
- }
208
- const resolved = await getDecryptedConnectionString(project, req.params.connId);
209
- if ('error' in resolved)
210
- return res.status(resolved.status).json({ message: resolved.error });
211
- const tables = await (0, dbConnection_1.listTablesOrCollections)(resolved.connectionString, resolved.conn.dbType);
212
- return res.status(200).json({ data: tables });
139
+ await withResolvedDbClient(project, req.params.connId, config, auth, res, async (resolved) => {
140
+ const tables = await (0, dbConnection_1.listTablesInternal)(resolved.client, resolved.type, req.params.id);
141
+ res.status(200).json({ data: tables });
142
+ });
213
143
  }
214
144
  catch (err) {
215
145
  res.status(500).json({ message: 'Failed to list tables', details: err.message });
@@ -230,31 +160,14 @@ function dbConnectionRouter(config) {
230
160
  const schema = req.body;
231
161
  if (!schema.tableName)
232
162
  return res.status(400).json({ message: 'tableName is required' });
233
- const conn = findDbConnection(project, req.params.connId);
234
- if (!conn)
235
- return res.status(404).json({ message: 'DB connection not found' });
236
- if (conn.source === 'builtin') {
237
- const builtinId = conn.integrationId;
238
- if (!(await (0, builtinAccess_1.assertBuiltinAccess)(auth, builtinId, config, 'database'))) {
239
- return res.status(403).json({ message: 'Access to this built-in database is not permitted' });
240
- }
241
- const internal = resolveBuiltinConnection(builtinId, config);
242
- if ('error' in internal)
243
- return res.status(internal.status).json({ message: internal.error });
244
- if (internal.dbType === 'sql' && (!Array.isArray(schema.columns) || schema.columns.length === 0)) {
245
- return res.status(400).json({ message: 'columns are required for SQL tables' });
163
+ await withResolvedDbClient(project, req.params.connId, config, auth, res, async (resolved) => {
164
+ if (resolved.type === 'sql' && (!Array.isArray(schema.columns) || schema.columns.length === 0)) {
165
+ res.status(400).json({ message: 'columns are required for SQL tables' });
166
+ return;
246
167
  }
247
- await (0, dbConnection_1.createTableOrCollectionInternal)(internal.client, internal.dbType, schema, req.params.id);
248
- return res.status(201).json({ message: `${internal.dbType === 'sql' ? 'Table' : 'Collection'} created successfully` });
249
- }
250
- const resolved = await getDecryptedConnectionString(project, req.params.connId);
251
- if ('error' in resolved)
252
- return res.status(resolved.status).json({ message: resolved.error });
253
- if (resolved.conn.dbType === 'postgresql' && (!Array.isArray(schema.columns) || schema.columns.length === 0)) {
254
- return res.status(400).json({ message: 'columns are required for PostgreSQL tables' });
255
- }
256
- await (0, dbConnection_1.createTableOrCollection)(resolved.connectionString, resolved.conn.dbType, schema);
257
- return res.status(201).json({ message: `${resolved.conn.dbType === 'postgresql' ? 'Table' : 'Collection'} created successfully` });
168
+ await (0, dbConnection_1.createTableOrCollectionInternal)(resolved.client, resolved.type, schema, req.params.id);
169
+ res.status(201).json({ message: `${resolved.type === 'sql' ? 'Table' : 'Collection'} created successfully` });
170
+ });
258
171
  }
259
172
  catch (err) {
260
173
  res.status(500).json({ message: 'Failed to create table/collection', details: err.message });
@@ -272,25 +185,10 @@ function dbConnectionRouter(config) {
272
185
  return res.status(404).json({ message: 'Project not found' });
273
186
  if (!(0, auth_1.isProjectMember)(project, auth.userId))
274
187
  return res.status(403).json({ message: 'Unauthorized project access' });
275
- const conn = findDbConnection(project, req.params.connId);
276
- if (!conn)
277
- return res.status(404).json({ message: 'DB connection not found' });
278
- if (conn.source === 'builtin') {
279
- const builtinId = conn.integrationId;
280
- if (!(await (0, builtinAccess_1.assertBuiltinAccess)(auth, builtinId, config, 'database'))) {
281
- return res.status(403).json({ message: 'Access to this built-in database is not permitted' });
282
- }
283
- const internal = resolveBuiltinConnection(builtinId, config);
284
- if ('error' in internal)
285
- return res.status(internal.status).json({ message: internal.error });
286
- await (0, dbConnection_1.deleteTableOrCollectionInternal)(internal.client, internal.dbType, req.params.tableName, req.params.id);
287
- return res.status(200).json({ message: 'Table/collection deleted' });
288
- }
289
- const resolved = await getDecryptedConnectionString(project, req.params.connId);
290
- if ('error' in resolved)
291
- return res.status(resolved.status).json({ message: resolved.error });
292
- await (0, dbConnection_1.deleteTableOrCollection)(resolved.connectionString, resolved.conn.dbType, req.params.tableName);
293
- return res.status(200).json({ message: 'Table/collection deleted' });
188
+ await withResolvedDbClient(project, req.params.connId, config, auth, res, async (resolved) => {
189
+ await (0, dbConnection_1.deleteTableOrCollectionInternal)(resolved.client, resolved.type, req.params.tableName, req.params.id);
190
+ res.status(200).json({ message: 'Table/collection deleted' });
191
+ });
294
192
  }
295
193
  catch (err) {
296
194
  res.status(500).json({ message: 'Failed to delete table/collection', details: err.message });
@@ -307,25 +205,10 @@ function dbConnectionRouter(config) {
307
205
  return res.status(403).json({ message: 'Unauthorized project access' });
308
206
  const limit = Math.min(parseInt(String(req.query.limit ?? 50), 10), 500);
309
207
  const offset = Math.max(parseInt(String(req.query.offset ?? 0), 10), 0);
310
- const conn = findDbConnection(project, req.params.connId);
311
- if (!conn)
312
- return res.status(404).json({ message: 'DB connection not found' });
313
- if (conn.source === 'builtin') {
314
- const builtinId = conn.integrationId;
315
- if (!(await (0, builtinAccess_1.assertBuiltinAccess)(auth, builtinId, config, 'database'))) {
316
- return res.status(403).json({ message: 'Access to this built-in database is not permitted' });
317
- }
318
- const internal = resolveBuiltinConnection(builtinId, config);
319
- if ('error' in internal)
320
- return res.status(internal.status).json({ message: internal.error });
321
- const records = await (0, dbConnection_1.queryRecordsInternal)(internal.client, internal.dbType, req.params.tableName, limit, offset, req.params.id);
322
- return res.status(200).json({ data: records });
323
- }
324
- const resolved = await getDecryptedConnectionString(project, req.params.connId);
325
- if ('error' in resolved)
326
- return res.status(resolved.status).json({ message: resolved.error });
327
- const records = await (0, dbConnection_1.queryRecords)(resolved.connectionString, resolved.conn.dbType, req.params.tableName, limit, offset);
328
- return res.status(200).json({ data: records });
208
+ await withResolvedDbClient(project, req.params.connId, config, auth, res, async (resolved) => {
209
+ const records = await (0, dbConnection_1.queryRecordsInternal)(resolved.client, resolved.type, req.params.tableName, limit, offset, req.params.id);
210
+ res.status(200).json({ data: records });
211
+ });
329
212
  }
330
213
  catch (err) {
331
214
  res.status(500).json({ message: 'Failed to query records', details: err.message });
@@ -347,25 +230,10 @@ function dbConnectionRouter(config) {
347
230
  if (!record || typeof record !== 'object' || Array.isArray(record)) {
348
231
  return res.status(400).json({ message: 'Request body must be a JSON object' });
349
232
  }
350
- const conn = findDbConnection(project, req.params.connId);
351
- if (!conn)
352
- return res.status(404).json({ message: 'DB connection not found' });
353
- if (conn.source === 'builtin') {
354
- const builtinId = conn.integrationId;
355
- if (!(await (0, builtinAccess_1.assertBuiltinAccess)(auth, builtinId, config, 'database'))) {
356
- return res.status(403).json({ message: 'Access to this built-in database is not permitted' });
357
- }
358
- const internal = resolveBuiltinConnection(builtinId, config);
359
- if ('error' in internal)
360
- return res.status(internal.status).json({ message: internal.error });
361
- const inserted = await (0, dbConnection_1.insertRecordInternal)(internal.client, internal.dbType, req.params.tableName, record, req.params.id);
362
- return res.status(201).json({ data: inserted });
363
- }
364
- const resolved = await getDecryptedConnectionString(project, req.params.connId);
365
- if ('error' in resolved)
366
- return res.status(resolved.status).json({ message: resolved.error });
367
- const inserted = await (0, dbConnection_1.insertRecord)(resolved.connectionString, resolved.conn.dbType, req.params.tableName, record);
368
- return res.status(201).json({ data: inserted });
233
+ await withResolvedDbClient(project, req.params.connId, config, auth, res, async (resolved) => {
234
+ const inserted = await (0, dbConnection_1.insertRecordInternal)(resolved.client, resolved.type, req.params.tableName, record, req.params.id);
235
+ res.status(201).json({ data: inserted });
236
+ });
369
237
  }
370
238
  catch (err) {
371
239
  res.status(500).json({ message: 'Failed to insert record', details: err.message });
@@ -386,25 +254,10 @@ function dbConnectionRouter(config) {
386
254
  if (!updates || typeof updates !== 'object' || Array.isArray(updates)) {
387
255
  return res.status(400).json({ message: 'Request body must be a JSON object' });
388
256
  }
389
- const conn = findDbConnection(project, req.params.connId);
390
- if (!conn)
391
- return res.status(404).json({ message: 'DB connection not found' });
392
- if (conn.source === 'builtin') {
393
- const builtinId = conn.integrationId;
394
- if (!(await (0, builtinAccess_1.assertBuiltinAccess)(auth, builtinId, config, 'database'))) {
395
- return res.status(403).json({ message: 'Access to this built-in database is not permitted' });
396
- }
397
- const internal = resolveBuiltinConnection(builtinId, config);
398
- if ('error' in internal)
399
- return res.status(internal.status).json({ message: internal.error });
400
- const updated = await (0, dbConnection_1.updateRecordInternal)(internal.client, internal.dbType, req.params.tableName, req.params.recordId, updates, req.params.id);
401
- return res.status(200).json({ data: updated });
402
- }
403
- const resolved = await getDecryptedConnectionString(project, req.params.connId);
404
- if ('error' in resolved)
405
- return res.status(resolved.status).json({ message: resolved.error });
406
- const updated = await (0, dbConnection_1.updateRecord)(resolved.connectionString, resolved.conn.dbType, req.params.tableName, req.params.recordId, updates);
407
- return res.status(200).json({ data: updated });
257
+ await withResolvedDbClient(project, req.params.connId, config, auth, res, async (resolved) => {
258
+ const updated = await (0, dbConnection_1.updateRecordInternal)(resolved.client, resolved.type, req.params.tableName, req.params.recordId, updates, req.params.id);
259
+ res.status(200).json({ data: updated });
260
+ });
408
261
  }
409
262
  catch (err) {
410
263
  res.status(500).json({ message: 'Failed to update record', details: err.message });
@@ -421,25 +274,10 @@ function dbConnectionRouter(config) {
421
274
  return res.status(404).json({ message: 'Project not found' });
422
275
  if (!(0, auth_1.isProjectMember)(project, auth.userId))
423
276
  return res.status(403).json({ message: 'Unauthorized project access' });
424
- const conn = findDbConnection(project, req.params.connId);
425
- if (!conn)
426
- return res.status(404).json({ message: 'DB connection not found' });
427
- if (conn.source === 'builtin') {
428
- const builtinId = conn.integrationId;
429
- if (!(await (0, builtinAccess_1.assertBuiltinAccess)(auth, builtinId, config, 'database'))) {
430
- return res.status(403).json({ message: 'Access to this built-in database is not permitted' });
431
- }
432
- const internal = resolveBuiltinConnection(builtinId, config);
433
- if ('error' in internal)
434
- return res.status(internal.status).json({ message: internal.error });
435
- await (0, dbConnection_1.deleteRecordInternal)(internal.client, internal.dbType, req.params.tableName, req.params.recordId, req.params.id);
436
- return res.status(200).json({ message: 'Record deleted' });
437
- }
438
- const resolved = await getDecryptedConnectionString(project, req.params.connId);
439
- if ('error' in resolved)
440
- return res.status(resolved.status).json({ message: resolved.error });
441
- await (0, dbConnection_1.deleteRecord)(resolved.connectionString, resolved.conn.dbType, req.params.tableName, req.params.recordId);
442
- return res.status(200).json({ message: 'Record deleted' });
277
+ await withResolvedDbClient(project, req.params.connId, config, auth, res, async (resolved) => {
278
+ await (0, dbConnection_1.deleteRecordInternal)(resolved.client, resolved.type, req.params.tableName, req.params.recordId, req.params.id);
279
+ res.status(200).json({ message: 'Record deleted' });
280
+ });
443
281
  }
444
282
  catch (err) {
445
283
  res.status(500).json({ message: 'Failed to delete record', details: err.message });
@@ -9,6 +9,7 @@ const manager_1 = require("../../models/manager");
9
9
  const auth_1 = require("../../utils/auth");
10
10
  const wsHub_1 = require("../../services/wsHub");
11
11
  const connectionManager_1 = require("../../adapters/database/connectionManager");
12
+ const sanitize_1 = require("../../utils/sanitize");
12
13
  const crypto_1 = __importDefault(require("crypto"));
13
14
  function getDb() {
14
15
  const ids = (0, connectionManager_1.getConnectedIds)().filter(id => (0, connectionManager_1.getConnection)(id).type === 'nosql');
@@ -33,7 +34,7 @@ function distributionRouter(_config) {
33
34
  return res.status(404).json({ message: 'Project not found' });
34
35
  if (!(0, auth_1.isProjectMember)(project, auth.userId))
35
36
  return res.status(403).json({ message: 'Unauthorized' });
36
- res.json({ connections: project.distributionConnections ?? [] });
37
+ res.json({ connections: (0, sanitize_1.sanitizeConnections)(project.distributionConnections) });
37
38
  }
38
39
  catch (err) {
39
40
  res.status(500).json({ message: err.message });
@@ -43,7 +44,7 @@ function distributionRouter(_config) {
43
44
  try {
44
45
  const auth = req.auth;
45
46
  const { projectId } = req.params;
46
- const { name, target, credentialId, config, description } = req.body;
47
+ const { name, target, encryptedCredential, config, description } = req.body;
47
48
  if (!name || !target)
48
49
  return res.status(400).json({ message: 'name and target are required' });
49
50
  const project = await Project.findOne({ _id: projectId });
@@ -55,14 +56,14 @@ function distributionRouter(_config) {
55
56
  id: crypto_1.default.randomUUID(),
56
57
  name,
57
58
  target,
58
- credentialId,
59
+ encryptedCredential,
59
60
  config: config ?? {},
60
61
  description,
61
62
  projectId,
62
63
  createdAt: new Date(),
63
64
  };
64
65
  await Project.update({ _id: projectId }, { $push: { distributionConnections: connection } });
65
- res.status(201).json({ connection });
66
+ res.status(201).json({ connection: (0, sanitize_1.sanitizeConnection)(connection) });
66
67
  }
67
68
  catch (err) {
68
69
  res.status(500).json({ message: err.message });
@@ -120,19 +120,16 @@ function exportRouter(config) {
120
120
  return res.status(404).json({ message: 'Project not found.' });
121
121
  }
122
122
  let headers = {};
123
- if (exportMetadata.credentialId) {
123
+ if (exportMetadata.encryptedCredential) {
124
124
  if (!(0, encryption_1.isEncryptionKeySet)()) {
125
125
  throw new Error('Encryption key is not set. Cannot use encrypted credentials.');
126
126
  }
127
- const credential = project.credentials?.find((cred) => cred.id === exportMetadata.credentialId);
128
- if (credential) {
129
- const decryptedValue = (0, encryption_1.decrypt)(credential.encryptedValue);
130
- const authPrefix = exportMetadata.prefix ? `${exportMetadata.prefix} ` : '';
131
- headers = {
132
- 'Authorization': `${authPrefix}${decryptedValue}`,
133
- 'Content-Type': 'application/json',
134
- };
135
- }
127
+ const decryptedValue = (0, encryption_1.decrypt)(exportMetadata.encryptedCredential);
128
+ const authPrefix = exportMetadata.prefix ? `${exportMetadata.prefix} ` : '';
129
+ headers = {
130
+ 'Authorization': `${authPrefix}${decryptedValue}`,
131
+ 'Content-Type': 'application/json',
132
+ };
136
133
  }
137
134
  const externalApiData = await fetch(exportMetadata.apiUrl, { headers });
138
135
  const apiResponse = await externalApiData.json();
@@ -168,7 +165,7 @@ function exportRouter(config) {
168
165
  createdAt: rawData?.createdAt,
169
166
  updatedAt: rawData?.updatedAt,
170
167
  type: exportMetadata.type,
171
- credentialId: exportMetadata.credentialId,
168
+ hasCredential: !!exportMetadata.encryptedCredential,
172
169
  description: rawData?.description,
173
170
  fields: exportMetadata.fields,
174
171
  };
@@ -372,15 +369,11 @@ function exportRouter(config) {
372
369
  }
373
370
  else if (exportMetadata.type === 'externalApi') {
374
371
  let headers = {};
375
- if (exportMetadata.credentialId) {
372
+ if (exportMetadata.encryptedCredential) {
376
373
  if (!(0, encryption_1.isEncryptionKeySet)()) {
377
374
  throw new Error('Encryption key is not set. Cannot use encrypted credentials.');
378
375
  }
379
- const credential = project.credentials?.find((cred) => cred.id === exportMetadata.credentialId);
380
- if (!credential) {
381
- throw new Error(`Credential with ID ${exportMetadata.credentialId} not found.`);
382
- }
383
- const decryptedValue = (0, encryption_1.decrypt)(credential.encryptedValue);
376
+ const decryptedValue = (0, encryption_1.decrypt)(exportMetadata.encryptedCredential);
384
377
  const authPrefix = exportMetadata.prefix ? `${exportMetadata.prefix} ` : '';
385
378
  headers = {
386
379
  'Authorization': `${authPrefix}${decryptedValue}`,
@@ -193,7 +193,7 @@ function projectRouter(config) {
193
193
  useConnections: e.useConnections,
194
194
  useCredentials: e.useCredentials,
195
195
  }));
196
- const sanitized = (0, sanitize_1.sanitizeProject)({ ...project, id: project._id || project.id, _id: undefined, apiConnections: project.apiConnections || [], exports });
196
+ const sanitized = (0, sanitize_1.sanitizeProject)({ ...project, id: project._id || project.id, _id: undefined, connections: project.connections || [], exports });
197
197
  res.json({ project: sanitized, message: 'Project fetched successfully' });
198
198
  }
199
199
  catch (err) {
@@ -9,6 +9,7 @@ const manager_1 = require("../../models/manager");
9
9
  const auth_1 = require("../../utils/auth");
10
10
  const jobQueue_1 = require("../../services/jobQueue");
11
11
  const vfxProcessor_1 = require("../../services/vfxProcessor");
12
+ const sanitize_1 = require("../../utils/sanitize");
12
13
  const crypto_1 = __importDefault(require("crypto"));
13
14
  function renderFarmRouter(_config) {
14
15
  const router = (0, express_1.Router)();
@@ -23,7 +24,7 @@ function renderFarmRouter(_config) {
23
24
  return res.status(404).json({ message: 'Project not found' });
24
25
  if (!(0, auth_1.isProjectMember)(project, auth.userId))
25
26
  return res.status(403).json({ message: 'Unauthorized' });
26
- res.json({ connections: project.renderFarmConnections ?? [] });
27
+ res.json({ connections: (0, sanitize_1.sanitizeConnections)(project.renderFarmConnections) });
27
28
  }
28
29
  catch (err) {
29
30
  res.status(500).json({ message: err.message });
@@ -33,7 +34,7 @@ function renderFarmRouter(_config) {
33
34
  try {
34
35
  const auth = req.auth;
35
36
  const { projectId } = req.params;
36
- const { name, provider, apiUrl, credentialId, description } = req.body;
37
+ const { name, provider, apiUrl, encryptedCredential, description } = req.body;
37
38
  if (!name || !provider || !apiUrl) {
38
39
  return res.status(400).json({ message: 'name, provider and apiUrl are required' });
39
40
  }
@@ -47,13 +48,13 @@ function renderFarmRouter(_config) {
47
48
  name,
48
49
  provider,
49
50
  apiUrl,
50
- credentialId,
51
+ encryptedCredential,
51
52
  description,
52
53
  projectId,
53
54
  createdAt: new Date(),
54
55
  };
55
56
  await Project.update({ _id: projectId }, { $push: { renderFarmConnections: connection } });
56
- res.status(201).json({ connection });
57
+ res.status(201).json({ connection: (0, sanitize_1.sanitizeConnection)(connection) });
57
58
  }
58
59
  catch (err) {
59
60
  res.status(500).json({ message: err.message });
@@ -8,13 +8,11 @@ const express_1 = require("express");
8
8
  const file_1 = require("../../services/file");
9
9
  const presign_1 = require("../../services/presign");
10
10
  const storage_1 = require("../../providers/storage");
11
- const s3_1 = require("../../adapters/storage/s3");
12
11
  const manager_1 = require("../../models/manager");
13
12
  const connectionManager_1 = require("../../adapters/database/connectionManager");
14
13
  const auth_1 = require("../../utils/auth");
15
- const encryption_1 = require("../../utils/encryption");
16
14
  const builtinAccess_1 = require("../../utils/builtinAccess");
17
- const userIntegration_1 = require("../../services/userIntegration");
15
+ const connectionResolver_1 = require("../../services/connectionResolver");
18
16
  const mongodb_1 = require("mongodb");
19
17
  const crypto_1 = __importDefault(require("crypto"));
20
18
  const VALID_CATEGORIES = ['images', 'audios', 'videos', '3d-models'];
@@ -69,46 +67,7 @@ function storageRouter(config) {
69
67
  : { storageConnectionId: connId };
70
68
  return { projectId, ...connMatch, ...(extra ?? {}) };
71
69
  }
72
- async function resolveConnAdapter(connId, project, auth) {
73
- const conn = findStorageConn(project, connId);
74
- if (!conn)
75
- return { error: 'Storage connection not found', status: 404 };
76
- if (conn.source === 'builtin') {
77
- const builtinId = conn.integrationId;
78
- if (!(await (0, builtinAccess_1.assertBuiltinAccess)(auth, builtinId, config, 'storage'))) {
79
- return { error: 'Access to this built-in storage is not permitted', status: 403 };
80
- }
81
- const provider = config.storageProviders.find(p => p.id === builtinId);
82
- if (!provider)
83
- return { error: 'Storage provider not found', status: 404 };
84
- return provider.type === 's3' ? new s3_1.S3Adapter(provider.config) : adapter;
85
- }
86
- if (conn.source === 'integration') {
87
- if (!conn.integrationId)
88
- return { error: 'Connection is missing its integrationId', status: 500 };
89
- try {
90
- const s3Config = await (0, userIntegration_1.getDecryptedIntegrationCredentialById)(conn.integrationId);
91
- if (!s3Config)
92
- return { error: 'Integration not found', status: 400 };
93
- return new s3_1.S3Adapter(s3Config);
94
- }
95
- catch (e) {
96
- return { error: `Failed to initialize storage adapter: ${e.message}`, status: 500 };
97
- }
98
- }
99
- if (!(0, encryption_1.isEncryptionKeySet)())
100
- return { error: 'Encryption key not set', status: 500 };
101
- const credential = project.credentials?.find((c) => c.id === conn.credentialId);
102
- if (!credential)
103
- return { error: 'Credential not found in project', status: 400 };
104
- try {
105
- const s3Config = JSON.parse((0, encryption_1.decrypt)(credential.encryptedValue));
106
- return new s3_1.S3Adapter(s3Config);
107
- }
108
- catch (e) {
109
- return { error: `Failed to initialize storage adapter: ${e.message}`, status: 500 };
110
- }
111
- }
70
+ const resolveConnAdapter = (connId, project, auth) => (0, connectionResolver_1.resolveStorageAdapter)(project, connId, { ...config, adapter }, auth);
112
71
  router.get('/upload-project-image-url/:id', async (req, res) => {
113
72
  try {
114
73
  const auth = req.auth;