streamby-core 0.25.7 → 0.26.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.
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.memberRouter = memberRouter;
4
+ const express_1 = require("express");
5
+ const manager_1 = require("../../models/manager");
6
+ const auth_1 = require("../../utils/auth");
7
+ const connectionManager_1 = require("../../adapters/database/connectionManager");
8
+ const sql_1 = require("../../adapters/database/sql");
9
+ const VALID_ROLES = ['viewer', 'editor', 'admin'];
10
+ function memberRouter(config) {
11
+ const router = (0, express_1.Router)();
12
+ const Project = (0, manager_1.getModel)('projects');
13
+ const getSqlConnection = () => {
14
+ const sqlDb = config.databases?.find(db => db.type === 'sql');
15
+ if (!sqlDb || !(0, connectionManager_1.getConnectedIds)().includes(sqlDb.id))
16
+ return null;
17
+ return (0, connectionManager_1.getConnection)(sqlDb.id).client;
18
+ };
19
+ router.get('/projects/:id/members', async (req, res) => {
20
+ try {
21
+ const auth = req.auth;
22
+ const projectId = req.params.id;
23
+ const project = await Project.findOne({ _id: projectId });
24
+ if (!project) {
25
+ return res.status(404).json({ message: 'Project not found' });
26
+ }
27
+ if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
28
+ return res.status(403).json({ message: 'Unauthorized project access' });
29
+ }
30
+ const mainDb = config.databases?.find(db => db.main);
31
+ if (!mainDb) {
32
+ return res.status(500).json({ message: 'Main database not configured' });
33
+ }
34
+ const User = (0, manager_1.getModel)('users');
35
+ const membersWithUsernames = await Promise.all(project.members.map(async (member) => {
36
+ const user = await User.findOne({ _id: member.userId });
37
+ return {
38
+ userId: member.userId,
39
+ username: user ? user.username : 'Unknown',
40
+ role: member.role,
41
+ profilePic: user ? user.profilePic : '',
42
+ };
43
+ }));
44
+ res.json({ members: membersWithUsernames, message: 'Project members fetched successfully' });
45
+ }
46
+ catch (err) {
47
+ res.status(500).json({ message: 'Failed to fetch project members', details: err.message });
48
+ }
49
+ });
50
+ router.post('/projects/:id/members', async (req, res) => {
51
+ try {
52
+ const auth = req.auth;
53
+ if (auth.role !== 'admin') {
54
+ return res.status(403).json({ message: 'Only admins can invite members' });
55
+ }
56
+ const projectId = req.params.id;
57
+ const { userId, role } = req.body;
58
+ if (!userId || !role) {
59
+ return res.status(400).json({ message: 'userId and role are required' });
60
+ }
61
+ if (!VALID_ROLES.includes(role)) {
62
+ return res.status(400).json({ message: `role must be one of: ${VALID_ROLES.join(', ')}` });
63
+ }
64
+ const project = await Project.findOne({ _id: projectId });
65
+ if (!project) {
66
+ return res.status(404).json({ message: 'Project not found' });
67
+ }
68
+ if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
69
+ return res.status(403).json({ message: 'Unauthorized project access' });
70
+ }
71
+ const alreadyMember = project.members?.some((m) => m.userId?.toString() === userId?.toString());
72
+ if (alreadyMember) {
73
+ return res.status(400).json({ message: 'User is already a member of this project' });
74
+ }
75
+ const User = (0, manager_1.getModel)('users');
76
+ const user = await User.findOne({ _id: userId });
77
+ if (!user) {
78
+ return res.status(404).json({ message: 'User not found' });
79
+ }
80
+ const newMember = { userId, username: user.username, role, archived: false };
81
+ if (project.dbType === 'sql') {
82
+ const connection = getSqlConnection();
83
+ if (!connection) {
84
+ return res.status(503).json({ message: 'SQL connection not available' });
85
+ }
86
+ await sql_1.sqlAdapter.create(connection, 'project_members', {
87
+ projectId,
88
+ userId,
89
+ role,
90
+ archived: false,
91
+ }, 'streamby');
92
+ }
93
+ else {
94
+ await Project.update({ _id: projectId }, { $push: { members: newMember } });
95
+ }
96
+ res.status(201).json({ member: newMember, message: 'Member invited successfully' });
97
+ }
98
+ catch (err) {
99
+ res.status(500).json({ message: 'Failed to invite member', details: err.message });
100
+ }
101
+ });
102
+ router.patch('/projects/:id/members/:userId', async (req, res) => {
103
+ try {
104
+ const auth = req.auth;
105
+ if (auth.role !== 'admin') {
106
+ return res.status(403).json({ message: 'Only admins can update member roles' });
107
+ }
108
+ const projectId = req.params.id;
109
+ const targetUserId = req.params.userId;
110
+ const { role } = req.body;
111
+ if (!role || !VALID_ROLES.includes(role)) {
112
+ return res.status(400).json({ message: `role must be one of: ${VALID_ROLES.join(', ')}` });
113
+ }
114
+ const project = await Project.findOne({ _id: projectId });
115
+ if (!project) {
116
+ return res.status(404).json({ message: 'Project not found' });
117
+ }
118
+ if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
119
+ return res.status(403).json({ message: 'Unauthorized project access' });
120
+ }
121
+ const memberExists = project.members?.some((m) => m.userId?.toString() === targetUserId?.toString());
122
+ if (!memberExists) {
123
+ return res.status(404).json({ message: 'Member not found in project' });
124
+ }
125
+ if (project.dbType === 'sql') {
126
+ const connection = getSqlConnection();
127
+ if (!connection) {
128
+ return res.status(503).json({ message: 'SQL connection not available' });
129
+ }
130
+ await sql_1.sqlAdapter.update(connection, 'project_members', { projectId, userId: targetUserId }, { role }, 'streamby');
131
+ }
132
+ else {
133
+ const updatedMembers = project.members.map((m) => m.userId?.toString() === targetUserId?.toString() ? { ...m, role } : m);
134
+ await Project.update({ _id: projectId }, { members: updatedMembers });
135
+ }
136
+ res.status(200).json({ message: 'Member role updated successfully' });
137
+ }
138
+ catch (err) {
139
+ res.status(500).json({ message: 'Failed to update member role', details: err.message });
140
+ }
141
+ });
142
+ router.delete('/projects/:id/members/:userId', async (req, res) => {
143
+ try {
144
+ const auth = req.auth;
145
+ if (auth.role !== 'admin') {
146
+ return res.status(403).json({ message: 'Only admins can remove members' });
147
+ }
148
+ const projectId = req.params.id;
149
+ const targetUserId = req.params.userId;
150
+ if (targetUserId === auth.userId) {
151
+ return res.status(400).json({ message: 'Cannot remove yourself from the project' });
152
+ }
153
+ const project = await Project.findOne({ _id: projectId });
154
+ if (!project) {
155
+ return res.status(404).json({ message: 'Project not found' });
156
+ }
157
+ if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
158
+ return res.status(403).json({ message: 'Unauthorized project access' });
159
+ }
160
+ const memberExists = project.members?.some((m) => m.userId?.toString() === targetUserId?.toString());
161
+ if (!memberExists) {
162
+ return res.status(404).json({ message: 'Member not found in project' });
163
+ }
164
+ if (project.dbType === 'sql') {
165
+ const connection = getSqlConnection();
166
+ if (!connection) {
167
+ return res.status(503).json({ message: 'SQL connection not available' });
168
+ }
169
+ await sql_1.sqlAdapter.delete(connection, 'project_members', { projectId, userId: targetUserId }, 'streamby');
170
+ }
171
+ else {
172
+ await Project.update({ _id: projectId }, { $pull: { members: { userId: targetUserId } } });
173
+ }
174
+ res.status(200).json({ message: 'Member removed successfully' });
175
+ }
176
+ catch (err) {
177
+ res.status(500).json({ message: 'Failed to remove member', details: err.message });
178
+ }
179
+ });
180
+ return router;
181
+ }
@@ -96,7 +96,16 @@ function projectRouter(config) {
96
96
  if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
97
97
  return res.status(403).json({ message: 'Unauthorized project access' });
98
98
  }
99
- res.json({ project: { ...project, id: project._id || project.id, _id: undefined, apiConnections: project.apiConnections || [] }, message: 'Project fetched successfully' });
99
+ const exports = (project.exports || []).map((e) => ({
100
+ id: e.id,
101
+ name: e.name,
102
+ description: e.description,
103
+ method: e.method,
104
+ private: e.private,
105
+ useConnections: e.useConnections,
106
+ useCredentials: e.useCredentials,
107
+ }));
108
+ res.json({ project: { ...project, id: project._id || project.id, _id: undefined, apiConnections: project.apiConnections || [], exports }, message: 'Project fetched successfully' });
100
109
  }
101
110
  catch (err) {
102
111
  res.status(500).json({ message: 'Failed to fetch project', details: err.message });
@@ -234,38 +243,6 @@ function projectRouter(config) {
234
243
  res.status(500).json({ message: 'Failed to unarchive project', details: err.message });
235
244
  }
236
245
  });
237
- router.get('/projects/:id/members', async (req, res) => {
238
- try {
239
- const auth = req.auth;
240
- const projectId = req.params.id;
241
- const project = await Project.findOne({ _id: projectId });
242
- if (!project) {
243
- return res.status(404).json({ message: 'Project not found' });
244
- }
245
- if (!(0, auth_1.isProjectMember)(project, auth.userId)) {
246
- return res.status(403).json({ message: 'Unauthorized project access' });
247
- }
248
- const mainDb = config.databases?.find(db => db.main);
249
- if (!mainDb) {
250
- return res.status(500).json({ message: 'Main database not configured' });
251
- }
252
- const userDbType = mainDb.type;
253
- const User = (0, manager_1.getModel)('users', userDbType);
254
- const membersWithUsernames = await Promise.all(project.members.map(async (member) => {
255
- const user = await User.findOne({ _id: member.userId });
256
- return {
257
- userId: member.userId,
258
- username: user ? user.username : 'Unknown',
259
- role: member.role,
260
- profilePic: user ? user.profilePic : ''
261
- };
262
- }));
263
- res.json({ members: membersWithUsernames, message: 'Project members fetched successfully' });
264
- }
265
- catch (err) {
266
- res.status(500).json({ message: 'Failed to fetch project members', details: err.message });
267
- }
268
- });
269
246
  router.post('/projects/:id/image', async (req, res) => {
270
247
  try {
271
248
  const auth = req.auth;
@@ -0,0 +1,3 @@
1
+ import { Router } from 'express';
2
+ import { StreamByConfig } from '../../types';
3
+ export declare function userRouter(config: StreamByConfig): Router;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.userRouter = userRouter;
4
+ const express_1 = require("express");
5
+ const manager_1 = require("../../models/manager");
6
+ function userRouter(config) {
7
+ const router = (0, express_1.Router)();
8
+ const User = (0, manager_1.getModel)('users');
9
+ router.get('/users/search', async (req, res) => {
10
+ try {
11
+ const auth = req.auth;
12
+ const q = (req.query.q || '').trim();
13
+ if (!q) {
14
+ return res.status(400).json({ message: 'Query param q is required' });
15
+ }
16
+ const allUsers = await User.find({});
17
+ const lower = q.toLowerCase();
18
+ const users = allUsers
19
+ .filter((u) => u.username?.toLowerCase().includes(lower))
20
+ .slice(0, 20)
21
+ .map((u) => ({
22
+ id: u._id || u.id,
23
+ username: u.username,
24
+ profilePic: u.profilePic || '',
25
+ }));
26
+ res.json({ users });
27
+ }
28
+ catch (err) {
29
+ res.status(500).json({ message: 'Failed to search users', details: err.message });
30
+ }
31
+ });
32
+ return router;
33
+ }
@@ -45,11 +45,11 @@ class Model {
45
45
  // Handle members filter for SQL projects
46
46
  const userId = processedFilter.members.$elemMatch.userId;
47
47
  const schema = this.schema || 'streamby'; // Default to 'streamby' if schema not provided
48
- const query = `
49
- SELECT p.*, pm."userId" as memberUserId, pm.archived as memberArchived
50
- FROM "${schema}"."projects" p
51
- JOIN "${schema}"."project_members" pm ON p.id = pm."projectId"
52
- WHERE pm."userId" = $1
48
+ const query = `
49
+ SELECT p.*, pm."userId" as memberUserId, pm.archived as memberArchived
50
+ FROM "${schema}"."projects" p
51
+ JOIN "${schema}"."project_members" pm ON p.id = pm."projectId"
52
+ WHERE pm."userId" = $1
53
53
  `;
54
54
  const result = await connection.query(query, [userId]);
55
55
  sqlResults = result.rows.map(row => ({
@@ -1,12 +1,11 @@
1
- import { FieldDefinition, DatabaseType, StreamByConfig } from '../types';
2
- interface CreateExportResult {
1
+ import { NodeSchema, DatabaseType, StreamByConfig } from '../types';
2
+ interface ExportResult {
3
3
  exportId: string;
4
- collectionName: string;
5
4
  message: string;
6
5
  }
7
- export declare function createExport(config: StreamByConfig, projectId: string, description: string, fields: FieldDefinition[], exportName: string, jsonData: any, dbType: DatabaseType, exportType: 'json' | 'externalApi', isPrivate?: boolean, allowedOrigin?: string[], apiUrl?: string, credentialId?: string, prefix?: string): Promise<CreateExportResult>;
8
- export declare function updateExport(config: StreamByConfig, projectId: string, exportId: string, description: string, fields: FieldDefinition[], exportName: string, collectionName: string, jsonData: any, dbType: DatabaseType, exportType: 'json' | 'externalApi', isPrivate?: boolean, allowedOrigin?: string[], apiUrl?: string, credentialId?: string, prefix?: string): Promise<CreateExportResult>;
9
- export declare function deleteExport(config: StreamByConfig, projectId: string, exportId: string, dbType: DatabaseType, collectionName: string): Promise<{
6
+ export declare function createExport(config: StreamByConfig, projectId: string, description: string, exportName: string, dbType: DatabaseType, exportType: 'json' | 'externalApi', isPrivate?: boolean, allowedOrigin?: string[], nodeSchema?: NodeSchema, useConnections?: boolean, useCredentials?: boolean): Promise<ExportResult>;
7
+ export declare function updateExport(config: StreamByConfig, projectId: string, exportId: string, description: string, exportName: string, storedExportName: string, dbType: DatabaseType, exportType: 'json' | 'externalApi', isPrivate?: boolean, allowedOrigin?: string[], nodeSchema?: NodeSchema, useConnections?: boolean, useCredentials?: boolean): Promise<ExportResult>;
8
+ export declare function deleteExport(config: StreamByConfig, projectId: string, exportId: string, dbType: DatabaseType, exportName: string): Promise<{
10
9
  message: string;
11
10
  }>;
12
11
  export {};
@@ -8,103 +8,40 @@ const mongodb_1 = require("mongodb");
8
8
  const connectionManager_1 = require("../adapters/database/connectionManager");
9
9
  const nosql_1 = require("../adapters/database/nosql");
10
10
  const sql_1 = require("../adapters/database/sql");
11
- const encryption_1 = require("../utils/encryption");
12
- async function createExport(config, projectId, description, fields, exportName, jsonData, dbType, exportType, isPrivate, allowedOrigin, apiUrl, credentialId, prefix) {
11
+ async function createExport(config, projectId, description, exportName, dbType, exportType, isPrivate, allowedOrigin, nodeSchema, useConnections, useCredentials) {
13
12
  const targetDb = config.databases?.find(db => db.type === dbType && db.main) ||
14
13
  config.databases?.find(db => db.type === dbType);
15
14
  if (!targetDb) {
16
15
  throw new Error(`Database connection not found for type ${dbType}`);
17
16
  }
18
17
  const connection = (0, connectionManager_1.getConnection)(targetDb.id);
19
- let result;
20
- if (exportType === 'externalApi') {
21
- if (!apiUrl) {
22
- throw new Error('API URL is required for externalApi export type.');
23
- }
24
- const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
25
- const project = await ProjectModel.findOne({ _id: projectId });
26
- if (!project) {
27
- throw new Error('Project not found.');
28
- }
29
- if (credentialId) {
30
- if (!(0, encryption_1.isEncryptionKeySet)()) {
31
- throw new Error('Encryption key is not set. Cannot use encrypted credentials.');
32
- }
33
- const credential = project.credentials?.find(cred => cred.id === credentialId);
34
- if (!credential) {
35
- throw new Error(`Credential with ID ${credentialId} not found.`);
36
- }
37
- }
38
- if (dbType === 'nosql') {
39
- result = await (0, nosql_1.createNoSQLRawExportCollection)(connection.client, projectId, exportName, 'GET', null);
40
- }
41
- else if (dbType === 'sql') {
42
- result = await (0, sql_1.createSQLRawExportTable)(connection.client, projectId, exportName, null);
43
- }
44
- else {
45
- throw new Error('Unsupported database type for externalApi export');
46
- }
47
- }
48
- else if (dbType === 'nosql') {
49
- result = await (0, nosql_1.createNoSQLRawExportCollection)(connection.client, projectId, exportName, 'GET', jsonData);
18
+ let exportId;
19
+ if (dbType === 'nosql') {
20
+ const result = await (0, nosql_1.createNoSQLRawExportCollection)(connection.client, exportName, 'GET', nodeSchema);
21
+ exportId = result.exportId;
50
22
  }
51
23
  else if (dbType === 'sql') {
52
- result = await (0, sql_1.createSQLRawExportTable)(connection.client, projectId, exportName, jsonData);
24
+ const result = await (0, sql_1.createSQLRawExportTable)(connection.client, exportName, nodeSchema);
25
+ exportId = result.exportId;
53
26
  }
54
27
  else {
55
28
  throw new Error('Unsupported database type');
56
29
  }
57
- // Update the project with the new export reference
58
- // Assuming project metadata is always in NoSQL (MongoDB)
59
30
  const NoSQLProject = (0, manager_1.getModel)('projects', 'nosql');
60
- await NoSQLProject.update({ _id: projectId }, { $push: { exports: { id: dbType === 'nosql' ? new mongodb_1.ObjectId(result.exportId) : result.exportId, name: exportName, collectionName: result.collectionName, type: exportType, method: 'GET', private: isPrivate, allowedOrigin: allowedOrigin, apiUrl: apiUrl, credentialId: credentialId, prefix: prefix, description: description, fields: fields } } });
61
- return { ...result, message: `${exportType} export created successfully` };
31
+ await NoSQLProject.update({ _id: projectId }, { $push: { exports: { id: new mongodb_1.ObjectId(exportId), name: exportName, type: exportType, method: 'GET', private: isPrivate, allowedOrigin, nodeSchema, useConnections, useCredentials, description } } });
32
+ return { exportId, message: `${exportType} export created successfully` };
62
33
  }
63
- async function updateExport(config, projectId, exportId, description, fields, exportName, collectionName, jsonData, dbType, exportType, isPrivate, allowedOrigin, apiUrl, credentialId, prefix) {
34
+ async function updateExport(config, projectId, exportId, description, exportName, storedExportName, dbType, exportType, isPrivate, allowedOrigin, nodeSchema, useConnections, useCredentials) {
64
35
  const targetDb = config.databases?.find(db => db.type === dbType && db.main) ||
65
36
  config.databases?.find(db => db.type === dbType);
66
37
  if (!targetDb) {
67
38
  throw new Error(`Database connection not found for type ${dbType}`);
68
39
  }
69
40
  const connection = (0, connectionManager_1.getConnection)(targetDb.id);
70
- let result;
71
- if (exportType === 'externalApi') {
72
- if (!apiUrl) {
73
- throw new Error('API URL is required for externalApi export type.');
74
- }
75
- const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
76
- const project = await ProjectModel.findOne({ _id: projectId });
77
- if (!project) {
78
- throw new Error('Project not found.');
79
- }
80
- if (dbType === 'nosql') {
81
- const db = connection.client.db();
82
- const updateData = {
83
- json: jsonData,
84
- description: description,
85
- fields: fields,
86
- updatedAt: new Date(),
87
- apiUrl: apiUrl,
88
- credentialId: credentialId,
89
- prefix: prefix,
90
- };
91
- await db.collection(collectionName).updateOne({ _id: new mongodb_1.ObjectId(exportId) }, { $set: updateData });
92
- }
93
- else {
94
- throw new Error('Unsupported database type for externalApi export update');
95
- }
96
- }
97
- else if (dbType === 'nosql') {
41
+ const storedSlug = storedExportName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
42
+ if (dbType === 'nosql') {
98
43
  const db = connection.client.db();
99
- const updateData = {
100
- json: jsonData,
101
- description: description,
102
- fields: fields,
103
- apiUrl: apiUrl,
104
- credentialId: credentialId,
105
- prefix: prefix,
106
- };
107
- await db.collection(collectionName).updateOne({ _id: new mongodb_1.ObjectId(exportId) }, { $set: updateData });
44
+ await db.collection(storedSlug).updateOne({ _id: new mongodb_1.ObjectId(exportId) }, { $set: { nodeSchema, description, updatedAt: new Date() } });
108
45
  }
109
46
  else {
110
47
  throw new Error('Unsupported database type for update');
@@ -113,20 +50,20 @@ async function updateExport(config, projectId, exportId, description, fields, ex
113
50
  await NoSQLProject.update({
114
51
  _id: new mongodb_1.ObjectId(projectId),
115
52
  'exports.id': { $in: [new mongodb_1.ObjectId(exportId), exportId] }
116
- }, { $set: { 'exports.$.name': exportName, 'exports.$.collectionName': collectionName, 'exports.$.private': isPrivate, 'exports.$.allowedOrigin': allowedOrigin, 'exports.$.apiUrl': apiUrl, 'exports.$.credentialId': credentialId, 'exports.$.prefix': prefix, 'exports.$.description': description, 'exports.$.fields': fields } });
117
- result = { collectionName, exportId };
118
- return { ...result, message: `${exportType} export updated successfully` };
53
+ }, { $set: { 'exports.$.name': exportName, 'exports.$.private': isPrivate, 'exports.$.allowedOrigin': allowedOrigin, 'exports.$.nodeSchema': nodeSchema, 'exports.$.useConnections': useConnections, 'exports.$.useCredentials': useCredentials, 'exports.$.description': description } });
54
+ return { exportId, message: `${exportType} export updated successfully` };
119
55
  }
120
- async function deleteExport(config, projectId, exportId, dbType, collectionName) {
56
+ async function deleteExport(config, projectId, exportId, dbType, exportName) {
121
57
  const targetDb = config.databases?.find(db => db.type === dbType && db.main) ||
122
58
  config.databases?.find(db => db.type === dbType);
123
59
  if (!targetDb) {
124
60
  throw new Error(`Database connection not found for type ${dbType}`);
125
61
  }
126
62
  const connection = (0, connectionManager_1.getConnection)(targetDb.id);
63
+ const slug = exportName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
127
64
  if (dbType === 'nosql') {
128
65
  const db = connection.client.db();
129
- await db.collection(collectionName).deleteOne({ _id: new mongodb_1.ObjectId(exportId) });
66
+ await db.collection(slug).deleteOne({ _id: new mongodb_1.ObjectId(exportId) });
130
67
  }
131
68
  else {
132
69
  throw new Error('Unsupported database type for delete');
@@ -0,0 +1,2 @@
1
+ import { NodeSchema, StreamByConfig } from '../types';
2
+ export declare function executePipeline(nodeSchema: NodeSchema, project: any, config: StreamByConfig): Promise<any>;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executePipeline = executePipeline;
4
+ const connectionManager_1 = require("../adapters/database/connectionManager");
5
+ const encryption_1 = require("../utils/encryption");
6
+ function getSources(nodes, edges, targetId, targetHandle) {
7
+ return edges
8
+ .filter(e => e.target === targetId && e.targetHandle === targetHandle)
9
+ .map(e => nodes.find(n => n.id === e.source))
10
+ .filter((n) => n !== undefined);
11
+ }
12
+ function getTarget(nodes, edges, sourceId, sourceHandle) {
13
+ const edge = edges.find(e => e.source === sourceId && e.sourceHandle === sourceHandle);
14
+ return edge ? (nodes.find(n => n.id === edge.target) ?? null) : null;
15
+ }
16
+ async function executePipeline(nodeSchema, project, config) {
17
+ const nodes = nodeSchema.nodes;
18
+ const edges = nodeSchema.edges;
19
+ // 1. Data layer — nodes connected to streamby in-bottom
20
+ const dataSources = getSources(nodes, edges, 'streamby', 'in-bottom');
21
+ const dataResults = [];
22
+ for (const node of dataSources) {
23
+ if (node.type === 'jsonInputNode') {
24
+ try {
25
+ dataResults.push(JSON.parse(node.data?.jsonString || 'null'));
26
+ }
27
+ catch {
28
+ dataResults.push(null);
29
+ }
30
+ }
31
+ else if (node.type === 'dataSourceNode') {
32
+ const collectionName = node.data?.subtitle || node.data?.label;
33
+ if (!collectionName)
34
+ continue;
35
+ const targetDb = config.databases?.find(db => db.type === project.dbType && db.main)
36
+ ?? config.databases?.find(db => db.type === project.dbType);
37
+ if (!targetDb)
38
+ throw new Error(`No database connection for type ${project.dbType}`);
39
+ const connection = (0, connectionManager_1.getConnection)(targetDb.id);
40
+ const db = connection.client.db();
41
+ dataResults.push(await db.collection(collectionName).find({}).toArray());
42
+ }
43
+ else if (node.type === 'apiConnectionNode') {
44
+ const apiConnection = project.apiConnections?.find((c) => c.id === node.data?.connectionId);
45
+ if (!apiConnection)
46
+ continue;
47
+ const headers = { 'Content-Type': 'application/json' };
48
+ if (apiConnection.credentialId && (0, encryption_1.isEncryptionKeySet)()) {
49
+ const credential = project.credentials?.find((c) => c.id === apiConnection.credentialId);
50
+ if (credential) {
51
+ const decrypted = (0, encryption_1.decrypt)(credential.encryptedValue);
52
+ const prefix = apiConnection.prefix ? `${apiConnection.prefix} ` : '';
53
+ headers['Authorization'] = `${prefix}${decrypted}`;
54
+ }
55
+ }
56
+ const response = await fetch(apiConnection.baseUrl, { method: apiConnection.method || 'GET', headers });
57
+ if (!response.ok)
58
+ throw new Error(`API connection fetch failed: ${response.statusText}`);
59
+ dataResults.push(await response.json());
60
+ }
61
+ }
62
+ let payload = dataResults.length === 1 ? dataResults[0] : dataResults;
63
+ // 2. Process layer — chain from streamby out-top → processNode in-process → out-process → ...
64
+ let processNode = getTarget(nodes, edges, 'streamby', 'out-top');
65
+ while (processNode) {
66
+ // transform/auth/custom logic per processNode.data.label — pass-through until defined
67
+ processNode = getTarget(nodes, edges, processNode.id, 'out-process');
68
+ }
69
+ // 3. Filter layer — chain from streamby out-right → filterNode in-filter → out-filter → ...
70
+ let filterNode = getTarget(nodes, edges, 'streamby', 'out-right');
71
+ while (filterNode) {
72
+ // filter logic per filterNode.data.label — pass-through until defined
73
+ filterNode = getTarget(nodes, edges, filterNode.id, 'out-filter');
74
+ }
75
+ return payload;
76
+ }
@@ -106,19 +106,25 @@ export interface Auth {
106
106
  role: 'viewer' | 'editor' | 'admin';
107
107
  }
108
108
  export type AuthProvider = (req: Request) => Promise<Auth>;
109
+ export interface NodeSchema {
110
+ nodes: any[];
111
+ edges: any[];
112
+ }
109
113
  export interface Export {
110
114
  _id?: string;
111
115
  id: string;
112
- collectionName: string;
113
116
  projectId: string;
114
117
  createdAt: Date;
115
118
  updatedAt: Date;
116
- type: 'json' | 'externalApi';
119
+ type?: 'json' | 'externalApi';
117
120
  fields?: FieldDefinition[];
118
121
  jsonData?: any;
119
- private?: boolean;
120
- allowedOrigin?: string[];
121
122
  apiUrl?: string;
122
123
  credentialId?: string;
123
124
  prefix?: string;
125
+ private?: boolean;
126
+ allowedOrigin?: string[];
127
+ nodeSchema?: NodeSchema;
128
+ useConnections?: boolean;
129
+ useCredentials?: boolean;
124
130
  }
@@ -0,0 +1,3 @@
1
+ export declare function encrypt(text: string, secretKey: string): string;
2
+ export declare function decrypt(text: string, secretKey: string): string;
3
+ export declare function hash(text: string): string;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.encrypt = encrypt;
7
+ exports.decrypt = decrypt;
8
+ exports.hash = hash;
9
+ const crypto_1 = __importDefault(require("crypto"));
10
+ const ALGORITHM = 'aes-256-cbc';
11
+ const IV_LENGTH = 16;
12
+ function encrypt(text, secretKey) {
13
+ const iv = crypto_1.default.randomBytes(IV_LENGTH);
14
+ const key = crypto_1.default.createHash('sha256').update(String(secretKey)).digest('base64').substr(0, 32);
15
+ const cipher = crypto_1.default.createCipheriv(ALGORITHM, Buffer.from(key), iv);
16
+ let encrypted = cipher.update(text);
17
+ encrypted = Buffer.concat([encrypted, cipher.final()]);
18
+ return iv.toString('hex') + ':' + encrypted.toString('hex');
19
+ }
20
+ function decrypt(text, secretKey) {
21
+ const textParts = text.split(':');
22
+ const iv = Buffer.from(textParts.shift(), 'hex');
23
+ const encryptedText = Buffer.from(textParts.join(':'), 'hex');
24
+ const key = crypto_1.default.createHash('sha256').update(String(secretKey)).digest('base64').substr(0, 32);
25
+ const decipher = crypto_1.default.createDecipheriv(ALGORITHM, Buffer.from(key), iv);
26
+ let decrypted = decipher.update(encryptedText);
27
+ decrypted = Buffer.concat([decrypted, decipher.final()]);
28
+ return decrypted.toString();
29
+ }
30
+ function hash(text) {
31
+ return crypto_1.default.createHash('sha256').update(text).digest('hex');
32
+ }