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.
- package/README.md +242 -242
- package/dist/adapters/database/connectionManager.js +41 -41
- package/dist/adapters/database/nosql.d.ts +2 -2
- package/dist/adapters/database/nosql.js +4 -5
- package/dist/adapters/database/sql.d.ts +1 -1
- package/dist/adapters/database/sql.js +22 -18
- package/dist/middleware/createRouter.js +6 -2
- package/dist/middleware/routes/connection.d.ts +3 -0
- package/dist/middleware/routes/connection.js +174 -0
- package/dist/middleware/routes/export.js +82 -70
- package/dist/middleware/routes/member.d.ts +3 -0
- package/dist/middleware/routes/member.js +181 -0
- package/dist/middleware/routes/project.js +10 -33
- package/dist/middleware/routes/user.d.ts +3 -0
- package/dist/middleware/routes/user.js +33 -0
- package/dist/models/Model.js +5 -5
- package/dist/services/export.d.ts +5 -6
- package/dist/services/export.js +18 -81
- package/dist/services/pipeline.d.ts +2 -0
- package/dist/services/pipeline.js +76 -0
- package/dist/types/index.d.ts +10 -4
- package/dist/utils/crypto.d.ts +3 -0
- package/dist/utils/crypto.js +32 -0
- package/package.json +61 -61
|
@@ -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
|
-
|
|
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,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
|
+
}
|
package/dist/models/Model.js
CHANGED
|
@@ -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 {
|
|
2
|
-
interface
|
|
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,
|
|
8
|
-
export declare function updateExport(config: StreamByConfig, projectId: string, exportId: string, description: string,
|
|
9
|
-
export declare function deleteExport(config: StreamByConfig, projectId: string, exportId: string, dbType: DatabaseType,
|
|
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 {};
|
package/dist/services/export.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
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,
|
|
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:
|
|
61
|
-
return {
|
|
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,
|
|
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
|
-
|
|
71
|
-
if (
|
|
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
|
-
|
|
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.$.
|
|
117
|
-
|
|
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,
|
|
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(
|
|
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,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
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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
|
|
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,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
|
+
}
|