streamby-core 0.24.6 → 0.24.9

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.
@@ -5,7 +5,7 @@ export declare const createNoSQLExportCollection: (connection: MongoClient, proj
5
5
  collectionName: string;
6
6
  exportId: string;
7
7
  }>;
8
- export declare const createNoSQLRawExportCollection: (connection: MongoClient, projectId: string, exportName: string, jsonData: any, method: string) => Promise<{
8
+ export declare const createNoSQLRawExportCollection: (connection: MongoClient, projectId: string, exportName: string, method: string, jsonData?: any) => Promise<{
9
9
  collectionName: string;
10
10
  exportId: string;
11
11
  }>;
@@ -33,7 +33,7 @@ const createNoSQLExportCollection = async (connection, projectId, exportName, fi
33
33
  return { collectionName, exportId: collectionName };
34
34
  };
35
35
  exports.createNoSQLExportCollection = createNoSQLExportCollection;
36
- const createNoSQLRawExportCollection = async (connection, projectId, exportName, jsonData, method) => {
36
+ const createNoSQLRawExportCollection = async (connection, projectId, exportName, method, jsonData) => {
37
37
  const db = connection.db();
38
38
  const slug = exportName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
39
39
  const collectionName = `raw_export_${projectId}_${slug}`;
@@ -4,7 +4,7 @@ export declare const createSQLExportTable: (connection: Pool, projectId: string,
4
4
  collectionName: string;
5
5
  exportId: string;
6
6
  }>;
7
- export declare const createSQLRawExportTable: (connection: Pool, projectId: string, exportName: string, jsonData: any) => Promise<{
7
+ export declare const createSQLRawExportTable: (connection: Pool, projectId: string, exportName: string, jsonData?: any) => Promise<{
8
8
  collectionName: string;
9
9
  exportId: string;
10
10
  }>;
@@ -13,9 +13,12 @@ const database_1 = require("./routes/database");
13
13
  const storage_2 = require("./routes/storage");
14
14
  const project_1 = require("./routes/project");
15
15
  const export_1 = require("./routes/export");
16
+ const credential_1 = require("./routes/credential");
16
17
  const auth_2 = require("../services/auth");
18
+ const encryption_1 = require("../utils/encryption");
17
19
  function createStreamByRouter(config) {
18
20
  const router = express_1.default.Router();
21
+ (0, encryption_1.setEncryptionKey)(config.encrypt || "");
19
22
  (0, connectionManager_1.initConnections)(config.databases || []);
20
23
  const adapter = config.adapter || (0, storage_1.createStorageProvider)(config.storageProviders);
21
24
  if (config.databases) {
@@ -35,5 +38,6 @@ function createStreamByRouter(config) {
35
38
  router.use((0, storage_2.storageRouter)(config));
36
39
  router.use((0, project_1.projectRouter)(config));
37
40
  router.use((0, export_1.exportRouter)(config));
41
+ router.use((0, credential_1.credentialRouter)(config));
38
42
  return router;
39
43
  }
@@ -0,0 +1,3 @@
1
+ import { Router } from 'express';
2
+ import { StreamByConfig } from '../../types';
3
+ export declare function credentialRouter(config: StreamByConfig): Router;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.credentialRouter = credentialRouter;
4
+ const express_1 = require("express");
5
+ const manager_1 = require("../../models/manager");
6
+ const auth_1 = require("../../utils/auth");
7
+ const credential_1 = require("../../services/credential");
8
+ function credentialRouter(config) {
9
+ const router = (0, express_1.Router)();
10
+ const Project = (0, manager_1.getModel)('projects');
11
+ // Add a new credential to a project
12
+ router.post('/projects/:id/credentials', async (req, res) => {
13
+ try {
14
+ const auth = req.auth;
15
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
16
+ return res.status(403).json({ message: 'Permission denied' });
17
+ }
18
+ const projectId = req.params.id;
19
+ const { id, key, value } = req.body;
20
+ if (!key || !value) {
21
+ return res.status(400).json({ message: 'Missing credential key or value' });
22
+ }
23
+ const project = await Project.findOne({ _id: projectId });
24
+ if (!project || !(0, auth_1.isProjectMember)(project, auth.userId)) {
25
+ return res.status(403).json({ message: 'Unauthorized project access' });
26
+ }
27
+ const updatedProject = await (0, credential_1.addCredential)(config, projectId, { id, key, value });
28
+ res.status(201).json({ message: 'Credential added successfully', project: updatedProject });
29
+ }
30
+ catch (err) {
31
+ res.status(500).json({ message: 'Failed to add credential', details: err.message });
32
+ }
33
+ });
34
+ // Update an existing credential in a project
35
+ router.patch('/projects/:id/credentials/:credentialId', async (req, res) => {
36
+ try {
37
+ const auth = req.auth;
38
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
39
+ return res.status(403).json({ message: 'Permission denied' });
40
+ }
41
+ const projectId = req.params.id;
42
+ const credentialId = req.params.credentialId;
43
+ const { key, value } = req.body;
44
+ if (!key && !value) {
45
+ return res.status(400).json({ message: 'No update fields provided' });
46
+ }
47
+ const project = await Project.findOne({ _id: projectId });
48
+ if (!project || !(0, auth_1.isProjectMember)(project, auth.userId)) {
49
+ return res.status(403).json({ message: 'Unauthorized project access' });
50
+ }
51
+ const updatedProject = await (0, credential_1.updateCredential)(config, projectId, credentialId, { key, value });
52
+ res.status(200).json({ message: 'Credential updated successfully', project: updatedProject });
53
+ }
54
+ catch (err) {
55
+ res.status(500).json({ message: 'Failed to update credential', details: err.message });
56
+ }
57
+ });
58
+ // Delete a credential from a project
59
+ router.delete('/projects/:id/credentials/:credentialId', async (req, res) => {
60
+ try {
61
+ const auth = req.auth;
62
+ if (auth.role !== 'admin' && auth.role !== 'editor') {
63
+ return res.status(403).json({ message: 'Permission denied' });
64
+ }
65
+ const projectId = req.params.id;
66
+ const credentialId = req.params.credentialId;
67
+ const project = await Project.findOne({ _id: projectId });
68
+ if (!project || !(0, auth_1.isProjectMember)(project, auth.userId)) {
69
+ return res.status(403).json({ message: 'Unauthorized project access' });
70
+ }
71
+ const updatedProject = await (0, credential_1.deleteCredential)(config, projectId, credentialId);
72
+ res.status(200).json({ message: 'Credential deleted successfully', project: updatedProject });
73
+ }
74
+ catch (err) {
75
+ res.status(500).json({ message: 'Failed to delete credential', details: err.message });
76
+ }
77
+ });
78
+ return router;
79
+ }
@@ -1,4 +1,7 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.exportRouter = exportRouter;
4
7
  const express_1 = require("express");
@@ -7,6 +10,8 @@ const auth_1 = require("../../utils/auth");
7
10
  const export_1 = require("../../services/export");
8
11
  const connectionManager_1 = require("../../adapters/database/connectionManager");
9
12
  const mongodb_1 = require("mongodb");
13
+ const encryption_1 = require("../../utils/encryption");
14
+ const node_fetch_1 = __importDefault(require("node-fetch")); // Import fetch here
10
15
  function exportRouter(config) {
11
16
  const router = (0, express_1.Router)();
12
17
  const Project = (0, manager_1.getModel)('projects');
@@ -43,6 +48,37 @@ function exportRouter(config) {
43
48
  const rawData = await db.collection(exportMetadata.collectionName).findOne({ _id: new mongodb_1.ObjectId(exportId) });
44
49
  data = rawData ? { json: rawData.json, name: rawData.name, method: rawData.method, collectionName: rawData.collectionName, createdAt: rawData.createdAt, updatedAt: rawData.updatedAt, type: exportMetadata.type } : null;
45
50
  }
51
+ else if (exportMetadata.type === 'externalApi') {
52
+ const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
53
+ const currentProject = await ProjectModel.findOne({ _id: projectId });
54
+ if (!currentProject) {
55
+ return res.status(404).json({ message: 'Project not found.' });
56
+ }
57
+ let headers = {};
58
+ if (exportMetadata.credentialId) {
59
+ const credential = currentProject.credentials?.find((cred) => cred.id === exportMetadata.credentialId);
60
+ if (!credential) {
61
+ return res.status(404).json({ message: `Credential with ID ${exportMetadata.credentialId} not found.` });
62
+ }
63
+ const decryptedValue = (0, encryption_1.decrypt)(credential.encryptedValue);
64
+ const authPrefix = exportMetadata.prefix ? `${exportMetadata.prefix} ` : 'Bearer ';
65
+ headers = {
66
+ 'Authorization': `${authPrefix}${decryptedValue}`,
67
+ 'Content-Type': 'application/json',
68
+ };
69
+ }
70
+ try {
71
+ const response = await (0, node_fetch_1.default)(exportMetadata.apiUrl, { headers });
72
+ if (!response.ok) {
73
+ throw new Error(`Failed to fetch from external API: ${response.statusText}`);
74
+ }
75
+ const responseData = await response.json();
76
+ data = { responseData, name: exportMetadata.name, createdAt: exportMetadata.createdAt, updatedAt: exportMetadata.updatedAt, type: exportMetadata.type, collectionName: exportMetadata.collectionName };
77
+ }
78
+ catch (error) {
79
+ return res.status(500).json({ message: 'Failed to fetch from external API', details: error.message });
80
+ }
81
+ }
46
82
  else {
47
83
  data = await db.collection(exportMetadata.collectionName).find({ __metadata: { $exists: false } }).toArray();
48
84
  }
@@ -86,15 +122,23 @@ function exportRouter(config) {
86
122
  return res.status(401).json({ message: 'Unauthorized' });
87
123
  }
88
124
  const projectId = req.params.id;
89
- const { name, description, collectionName, jsonData, isPrivate, allowedOrigin } = req.body;
90
- if (!name || !collectionName || !jsonData) {
91
- return res.status(400).json({ message: 'Missing export name, collectionName, or jsonData' });
125
+ const { name, description, collectionName, jsonData, isPrivate, allowedOrigin, exportType, apiUrl, credentialId, prefix } = req.body;
126
+ if (!name || !collectionName) {
127
+ return res.status(400).json({ message: 'Missing export name or collectionName' });
128
+ }
129
+ if (exportType === 'externalApi') {
130
+ if (!apiUrl) {
131
+ return res.status(400).json({ message: 'API URL is required for externalApi export type' });
132
+ }
133
+ }
134
+ else if (!jsonData) {
135
+ return res.status(400).json({ message: 'Missing jsonData for non-externalApi export types' });
92
136
  }
93
137
  const project = await Project.findOne({ _id: projectId });
94
138
  if (!project || !(0, auth_1.isProjectMember)(project, auth.userId)) {
95
139
  return res.status(403).json({ message: 'Unauthorized project access' });
96
140
  }
97
- const result = await (0, export_1.createExport)(config, projectId, name, collectionName, jsonData, project.dbType, isPrivate, allowedOrigin);
141
+ const result = await (0, export_1.createExport)(config, projectId, name, collectionName, jsonData, project.dbType, exportType || 'raw', isPrivate, allowedOrigin, apiUrl, credentialId, prefix);
98
142
  res.status(201).json({ data: result, message: result.message });
99
143
  }
100
144
  catch (err) {
@@ -108,15 +152,23 @@ function exportRouter(config) {
108
152
  return res.status(401).json({ message: 'Unauthorized' });
109
153
  }
110
154
  const { id: projectId, export_id: exportId } = req.params;
111
- const { name, collectionName, description, jsonData, isPrivate, allowedOrigin } = req.body;
112
- if (!name || !collectionName || !jsonData) {
113
- return res.status(400).json({ message: 'Missing name, collectionName, or jsonData' });
155
+ const { name, collectionName, description, jsonData, isPrivate, allowedOrigin, exportType, apiUrl, credentialId, prefix } = req.body;
156
+ if (!name || !collectionName) {
157
+ return res.status(400).json({ message: 'Missing name or collectionName' });
158
+ }
159
+ if (exportType === 'externalApi') {
160
+ if (!apiUrl) {
161
+ return res.status(400).json({ message: 'API URL is required for externalApi export type' });
162
+ }
163
+ }
164
+ else if (!jsonData) {
165
+ return res.status(400).json({ message: 'Missing jsonData for non-externalApi export types' });
114
166
  }
115
167
  const project = await Project.findOne({ _id: projectId });
116
168
  if (!project || !(0, auth_1.isProjectMember)(project, auth.userId)) {
117
169
  return res.status(403).json({ message: 'Unauthorized project access' });
118
170
  }
119
- const result = await (0, export_1.updateExport)(config, projectId, exportId, name, collectionName, jsonData, project.dbType, isPrivate, allowedOrigin);
171
+ const result = await (0, export_1.updateExport)(config, projectId, exportId, name, collectionName, jsonData, project.dbType, exportType || 'raw', isPrivate, allowedOrigin, apiUrl, credentialId, prefix);
120
172
  res.status(200).json({ data: result, message: result.message });
121
173
  }
122
174
  catch (err) {
@@ -193,8 +245,33 @@ function exportRouter(config) {
193
245
  const rawData = await db.collection(exportMetadata.collectionName).findOne({ _id: new mongodb_1.ObjectId(exportMetadata.id) });
194
246
  data = rawData ? rawData.json : null;
195
247
  }
196
- else {
197
- data = await db.collection(exportMetadata.collectionName).find({ __metadata: { $exists: false } }).toArray();
248
+ else if (exportMetadata.type === 'externalApi') {
249
+ let headers = {};
250
+ if (exportMetadata.credentialId) {
251
+ if (!(0, encryption_1.isEncryptionKeySet)()) {
252
+ throw new Error('Encryption key is not set. Cannot use encrypted credentials.');
253
+ }
254
+ const credential = project.credentials?.find((cred) => cred.id === exportMetadata.credentialId);
255
+ if (!credential) {
256
+ throw new Error(`Credential with ID ${exportMetadata.credentialId} not found.`);
257
+ }
258
+ const decryptedValue = (0, encryption_1.decrypt)(credential.encryptedValue);
259
+ const authPrefix = exportMetadata.prefix ? `${exportMetadata.prefix} ` : '';
260
+ headers = {
261
+ 'Authorization': `${authPrefix}${decryptedValue}`,
262
+ 'Content-Type': 'application/json',
263
+ };
264
+ }
265
+ try {
266
+ const response = await (0, node_fetch_1.default)(exportMetadata.apiUrl, { headers });
267
+ if (!response.ok) {
268
+ throw new Error(`Failed to fetch from external API: ${response.statusText}`);
269
+ }
270
+ data = await response.json();
271
+ }
272
+ catch (error) {
273
+ throw new Error(`Error fetching from external API: ${error.message}`);
274
+ }
198
275
  }
199
276
  }
200
277
  else if (project.dbType === 'sql') {
@@ -69,7 +69,7 @@ function projectRouter(config) {
69
69
  description: description || '',
70
70
  image: image || '',
71
71
  allowedOrigin: allowedOrigin || [],
72
- members: [{ userId: auth.userId, username: user.username, role: "admin", archived: false }]
72
+ members: [{ userId: auth.userId, username: user.username, role: "admin", archived: false }],
73
73
  });
74
74
  const allProjects = await Project.find({});
75
75
  const projects = allProjects
@@ -0,0 +1,8 @@
1
+ import { StreamByConfig, Credential, ProjectInfo } from '../types';
2
+ export declare function addCredential(config: StreamByConfig, projectId: string, newCredential: Omit<Credential, 'encryptedValue'> & {
3
+ value: string;
4
+ }): Promise<ProjectInfo>;
5
+ export declare function updateCredential(config: StreamByConfig, projectId: string, credentialId: string, updates: Partial<Omit<Credential, 'encryptedValue'> & {
6
+ value: string;
7
+ }>): Promise<ProjectInfo>;
8
+ export declare function deleteCredential(config: StreamByConfig, projectId: string, credentialId: string): Promise<ProjectInfo>;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addCredential = addCredential;
4
+ exports.updateCredential = updateCredential;
5
+ exports.deleteCredential = deleteCredential;
6
+ const manager_1 = require("../models/manager");
7
+ const encryption_1 = require("../utils/encryption");
8
+ const mongodb_1 = require("mongodb");
9
+ async function addCredential(config, projectId, newCredential) {
10
+ if (!(0, encryption_1.isEncryptionKeySet)()) {
11
+ throw new Error('Encryption key is not set. Cannot add credentials.');
12
+ }
13
+ const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
14
+ const project = await ProjectModel.findOne({ _id: projectId });
15
+ if (!project) {
16
+ throw new Error('Project not found.');
17
+ }
18
+ const encryptedValue = (0, encryption_1.encrypt)(newCredential.value);
19
+ const credentialToSave = {
20
+ id: newCredential.id || new mongodb_1.ObjectId().toHexString(), // Generate ID if not provided
21
+ key: newCredential.key,
22
+ encryptedValue: encryptedValue,
23
+ };
24
+ const updatedProject = await ProjectModel.update({ _id: projectId }, { $push: { credentials: credentialToSave } });
25
+ if (!updatedProject) {
26
+ throw new Error('Failed to add credential to project.');
27
+ }
28
+ return updatedProject;
29
+ }
30
+ async function updateCredential(config, projectId, credentialId, updates) {
31
+ if (!(0, encryption_1.isEncryptionKeySet)()) {
32
+ throw new Error('Encryption key is not set. Cannot update credentials.');
33
+ }
34
+ const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
35
+ const project = await ProjectModel.findOne({ _id: projectId });
36
+ if (!project) {
37
+ throw new Error('Project not found.');
38
+ }
39
+ const credentialIndex = project.credentials?.findIndex(cred => cred.id === credentialId);
40
+ if (credentialIndex === undefined || credentialIndex === -1) {
41
+ throw new Error(`Credential with ID ${credentialId} not found.`);
42
+ }
43
+ const currentCredential = project.credentials[credentialIndex];
44
+ let encryptedValue = currentCredential.encryptedValue;
45
+ if (updates.value !== undefined) {
46
+ encryptedValue = (0, encryption_1.encrypt)(updates.value);
47
+ }
48
+ const updatedCredential = {
49
+ ...currentCredential,
50
+ key: updates.key || currentCredential.key,
51
+ encryptedValue: encryptedValue,
52
+ };
53
+ const updatedProject = await ProjectModel.update({ _id: projectId, 'credentials.id': credentialId }, { $set: { 'credentials.$': updatedCredential } });
54
+ if (!updatedProject) {
55
+ throw new Error('Failed to update credential in project.');
56
+ }
57
+ return updatedProject;
58
+ }
59
+ async function deleteCredential(config, projectId, credentialId) {
60
+ const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
61
+ const project = await ProjectModel.findOne({ _id: projectId });
62
+ if (!project) {
63
+ throw new Error('Project not found.');
64
+ }
65
+ const updatedProject = await ProjectModel.update({ _id: projectId }, { $pull: { credentials: { id: credentialId } } });
66
+ if (!updatedProject) {
67
+ throw new Error('Failed to delete credential from project.');
68
+ }
69
+ return updatedProject;
70
+ }
@@ -1,12 +1,11 @@
1
- import { DatabaseType } from '../types';
1
+ import { DatabaseType, StreamByConfig } from '../types';
2
2
  interface CreateExportResult {
3
3
  exportId: string;
4
4
  collectionName: string;
5
5
  message: string;
6
6
  }
7
- import { StreamByConfig } from '../types';
8
- export declare function createExport(config: StreamByConfig, projectId: string, exportName: string, collectionName: string, jsonData: any, dbType: DatabaseType, isPrivate?: boolean, allowedOrigin?: string[]): Promise<CreateExportResult>;
9
- export declare function updateExport(config: StreamByConfig, projectId: string, exportId: string, exportName: string, collectionName: string, jsonData: any, dbType: DatabaseType, isPrivate?: boolean, allowedOrigin?: string[]): Promise<CreateExportResult>;
7
+ export declare function createExport(config: StreamByConfig, projectId: string, exportName: string, collectionName: string, jsonData: any, dbType: DatabaseType, exportType: 'structured' | 'raw' | 'externalApi', isPrivate?: boolean, allowedOrigin?: string[], apiUrl?: string, credentialId?: string, prefix?: string): Promise<CreateExportResult>;
8
+ export declare function updateExport(config: StreamByConfig, projectId: string, exportId: string, exportName: string, collectionName: string, jsonData: any, dbType: DatabaseType, exportType: 'structured' | 'raw' | 'externalApi', isPrivate?: boolean, allowedOrigin?: string[], apiUrl?: string, credentialId?: string, prefix?: string): Promise<CreateExportResult>;
10
9
  export declare function deleteExport(config: StreamByConfig, projectId: string, exportId: string, dbType: DatabaseType, collectionName: string): Promise<{
11
10
  message: string;
12
11
  }>;
@@ -8,7 +8,8 @@ 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
- async function createExport(config, projectId, exportName, collectionName, jsonData, dbType, isPrivate, allowedOrigin) {
11
+ const encryption_1 = require("../utils/encryption");
12
+ async function createExport(config, projectId, exportName, collectionName, jsonData, dbType, exportType, isPrivate, allowedOrigin, apiUrl, credentialId, prefix) {
12
13
  const targetDb = config.databases?.find(db => db.type === dbType && db.main) ||
13
14
  config.databases?.find(db => db.type === dbType);
14
15
  if (!targetDb) {
@@ -16,8 +17,36 @@ async function createExport(config, projectId, exportName, collectionName, jsonD
16
17
  }
17
18
  const connection = (0, connectionManager_1.getConnection)(targetDb.id);
18
19
  let result;
19
- if (dbType === 'nosql') {
20
- result = await (0, nosql_1.createNoSQLRawExportCollection)(connection.client, projectId, exportName, jsonData, 'GET');
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);
21
50
  }
22
51
  else if (dbType === 'sql') {
23
52
  result = await (0, sql_1.createSQLRawExportTable)(connection.client, projectId, exportName, jsonData);
@@ -28,10 +57,10 @@ async function createExport(config, projectId, exportName, collectionName, jsonD
28
57
  // Update the project with the new export reference
29
58
  // Assuming project metadata is always in NoSQL (MongoDB)
30
59
  const NoSQLProject = (0, manager_1.getModel)('projects', 'nosql');
31
- await NoSQLProject.update({ _id: projectId }, { $push: { exports: { id: dbType === 'nosql' ? new mongodb_1.ObjectId(result.exportId) : result.exportId, name: exportName, collectionName: result.collectionName, type: 'raw', method: 'GET', private: isPrivate, allowedOrigin: allowedOrigin } } });
32
- return { ...result, message: 'Raw export created successfully' };
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 } } });
61
+ return { ...result, message: `${exportType} export created successfully` };
33
62
  }
34
- async function updateExport(config, projectId, exportId, exportName, collectionName, jsonData, dbType, isPrivate, allowedOrigin) {
63
+ async function updateExport(config, projectId, exportId, exportName, collectionName, jsonData, dbType, exportType, isPrivate, allowedOrigin, apiUrl, credentialId, prefix) {
35
64
  const targetDb = config.databases?.find(db => db.type === dbType && db.main) ||
36
65
  config.databases?.find(db => db.type === dbType);
37
66
  if (!targetDb) {
@@ -39,7 +68,33 @@ async function updateExport(config, projectId, exportId, exportName, collectionN
39
68
  }
40
69
  const connection = (0, connectionManager_1.getConnection)(targetDb.id);
41
70
  let result;
42
- if (dbType === 'nosql') {
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
+ name: exportName,
85
+ updatedAt: new Date(),
86
+ apiUrl: apiUrl,
87
+ credentialId: credentialId,
88
+ prefix: prefix,
89
+ };
90
+ await db.collection(collectionName).updateOne({ _id: new mongodb_1.ObjectId(exportId) }, { $set: updateData });
91
+ result = { collectionName, exportId };
92
+ }
93
+ else {
94
+ throw new Error('Unsupported database type for externalApi export update');
95
+ }
96
+ }
97
+ else if (dbType === 'nosql') {
43
98
  const db = connection.client.db();
44
99
  const updateData = {
45
100
  json: jsonData,
@@ -56,8 +111,8 @@ async function updateExport(config, projectId, exportId, exportName, collectionN
56
111
  await NoSQLProject.update({
57
112
  _id: new mongodb_1.ObjectId(projectId),
58
113
  'exports.id': { $in: [new mongodb_1.ObjectId(exportId), exportId] }
59
- }, { $set: { 'exports.$.name': exportName, 'exports.$.collectionName': collectionName, 'exports.$.private': isPrivate, 'exports.$.allowedOrigin': allowedOrigin } });
60
- return { ...result, message: 'Raw export updated successfully' };
114
+ }, { $set: { 'exports.$.name': exportName, 'exports.$.collectionName': collectionName, 'exports.$.private': isPrivate, 'exports.$.allowedOrigin': allowedOrigin, 'exports.$.apiUrl': apiUrl, 'exports.$.credentialId': credentialId, 'exports.$.prefix': prefix } });
115
+ return { ...result, message: `${exportType} export updated successfully` };
61
116
  }
62
117
  async function deleteExport(config, projectId, exportId, dbType, collectionName) {
63
118
  const targetDb = config.databases?.find(db => db.type === dbType && db.main) ||
@@ -43,6 +43,12 @@ export interface ProjectInfo {
43
43
  allowUpload?: boolean;
44
44
  allowSharing?: boolean;
45
45
  };
46
+ credentials?: Credential[];
47
+ }
48
+ export interface Credential {
49
+ id: string;
50
+ key: string;
51
+ encryptedValue: string;
46
52
  }
47
53
  export interface ProjectListInfo {
48
54
  id: string;
@@ -66,6 +72,7 @@ export interface StreamByConfig {
66
72
  authProvider: AuthProvider;
67
73
  databases?: DatabaseCredential[];
68
74
  adapter?: StorageAdapter;
75
+ encrypt?: string;
69
76
  }
70
77
  export interface Auth {
71
78
  userId: string;
@@ -80,9 +87,12 @@ export interface Export {
80
87
  projectId: string;
81
88
  createdAt: Date;
82
89
  updatedAt: Date;
83
- type: 'structured' | 'raw';
90
+ type: 'structured' | 'raw' | 'externalApi';
84
91
  fields?: FieldDefinition[];
85
92
  jsonData?: any;
86
93
  private?: boolean;
87
94
  allowedOrigin?: string[];
95
+ apiUrl?: string;
96
+ credentialId?: string;
97
+ prefix?: string;
88
98
  }
@@ -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
+ }
@@ -0,0 +1,4 @@
1
+ export declare const setEncryptionKey: (key: string) => void;
2
+ export declare const encrypt: (text: string) => string;
3
+ export declare const decrypt: (text: string) => string;
4
+ export declare const isEncryptionKeySet: () => boolean;
@@ -0,0 +1,75 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.isEncryptionKeySet = exports.decrypt = exports.encrypt = exports.setEncryptionKey = void 0;
37
+ const crypto = __importStar(require("crypto"));
38
+ const ALGORITHM = 'aes-256-cbc';
39
+ const IV_LENGTH = 16; // For AES, this is always 16
40
+ let ENCRYPTION_KEY = undefined;
41
+ const setEncryptionKey = (key) => {
42
+ if (key.length !== 64) { // 32 bytes * 2 hex characters per byte
43
+ throw new Error('Invalid encryption key length. Key must be 32 bytes (64 hexadecimal characters).');
44
+ }
45
+ ENCRYPTION_KEY = key;
46
+ };
47
+ exports.setEncryptionKey = setEncryptionKey;
48
+ const encrypt = (text) => {
49
+ if (!ENCRYPTION_KEY) {
50
+ throw new Error('Encryption key is not set. Cannot encrypt credentials.');
51
+ }
52
+ const iv = crypto.randomBytes(IV_LENGTH);
53
+ const cipher = crypto.createCipheriv(ALGORITHM, Buffer.from(ENCRYPTION_KEY, 'hex'), iv);
54
+ let encrypted = cipher.update(text);
55
+ encrypted = Buffer.concat([encrypted, cipher.final()]);
56
+ return iv.toString('hex') + ':' + encrypted.toString('hex');
57
+ };
58
+ exports.encrypt = encrypt;
59
+ const decrypt = (text) => {
60
+ if (!ENCRYPTION_KEY) {
61
+ throw new Error('Encryption key is not set. Cannot decrypt credentials.');
62
+ }
63
+ const textParts = text.split(':');
64
+ const iv = Buffer.from(textParts.shift(), 'hex');
65
+ const encryptedText = Buffer.from(textParts.join(':'), 'hex');
66
+ const decipher = crypto.createDecipheriv(ALGORITHM, Buffer.from(ENCRYPTION_KEY, 'hex'), iv);
67
+ let decrypted = decipher.update(encryptedText);
68
+ decrypted = Buffer.concat([decrypted, decipher.final()]);
69
+ return decrypted.toString();
70
+ };
71
+ exports.decrypt = decrypt;
72
+ const isEncryptionKeySet = () => {
73
+ return !!ENCRYPTION_KEY;
74
+ };
75
+ exports.isEncryptionKeySet = isEncryptionKeySet;
package/package.json CHANGED
@@ -1,60 +1,61 @@
1
- {
2
- "name": "streamby-core",
3
- "version": "0.24.6",
4
- "description": "StreamBy middleware framework for media storage management",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "files": [
8
- "dist"
9
- ],
10
- "scripts": {
11
- "build": "tsc",
12
- "test": "vitest",
13
- "dev": "ts-node-dev --respawn --clear dev.ts",
14
- "prepublishOnly": "npm run build"
15
- },
16
- "repository": {
17
- "type": "git",
18
- "url": "https://github.com/GwerhDev/StreamBy-Package.git"
19
- },
20
- "keywords": [
21
- "streamby",
22
- "middleware",
23
- "upload",
24
- "storage",
25
- "s3",
26
- "express",
27
- "typescript"
28
- ],
29
- "author": "TerminalCore Labs",
30
- "license": "MIT",
31
- "dependencies": {
32
- "@aws-sdk/client-s3": "^3.528.0",
33
- "@aws-sdk/s3-request-presigner": "^3.787.0",
34
- "@prisma/client": "^6.12.0",
35
- "bcrypt": "^5.1.1",
36
- "dotenv": "^16.5.0",
37
- "express": "^4.0.0",
38
- "mongodb": "^6.17.0",
39
- "mongoose": "^8.13.2",
40
- "pg": "^8.16.3",
41
- "prisma": "^6.12.0"
42
- },
43
- "devDependencies": {
44
- "@types/bcrypt": "^5.0.2",
45
- "@types/cors": "^2.8.18",
46
- "@types/express": "^4.17.17",
47
- "@types/mongodb": "^4.0.7",
48
- "@types/node": "^22.15.21",
49
- "@types/pg": "^8.15.4",
50
- "@types/supertest": "^6.0.3",
51
- "cors": "^2.8.5",
52
- "supertest": "^7.1.4",
53
- "ts-node-dev": "^2.0.0",
54
- "typescript": "^5.8.3",
55
- "vitest": "^3.1.1"
56
- },
57
- "peerDependencies": {
58
- "express": "^4.0.0"
59
- }
60
- }
1
+ {
2
+ "name": "streamby-core",
3
+ "version": "0.24.9",
4
+ "description": "StreamBy middleware framework for media storage management",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "test": "vitest",
13
+ "dev": "ts-node-dev --respawn --clear dev.ts",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/GwerhDev/StreamBy-Package.git"
19
+ },
20
+ "keywords": [
21
+ "streamby",
22
+ "middleware",
23
+ "upload",
24
+ "storage",
25
+ "s3",
26
+ "express",
27
+ "typescript"
28
+ ],
29
+ "author": "TerminalCore Labs",
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "@aws-sdk/client-s3": "^3.528.0",
33
+ "@aws-sdk/s3-request-presigner": "^3.787.0",
34
+ "@prisma/client": "^6.12.0",
35
+ "bcrypt": "^5.1.1",
36
+ "dotenv": "^16.5.0",
37
+ "express": "^4.0.0",
38
+ "mongodb": "^6.17.0",
39
+ "mongoose": "^8.13.2",
40
+ "pg": "^8.16.3",
41
+ "prisma": "^6.12.0",
42
+ "node-fetch": "^3.0.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/bcrypt": "^5.0.2",
46
+ "@types/cors": "^2.8.18",
47
+ "@types/express": "^4.17.17",
48
+ "@types/mongodb": "^4.0.7",
49
+ "@types/node": "^22.15.21",
50
+ "@types/pg": "^8.15.4",
51
+ "@types/supertest": "^6.0.3",
52
+ "cors": "^2.8.5",
53
+ "supertest": "^7.1.4",
54
+ "ts-node-dev": "^2.0.0",
55
+ "typescript": "^5.8.3",
56
+ "vitest": "^3.1.1"
57
+ },
58
+ "peerDependencies": {
59
+ "express": "^4.0.0"
60
+ }
61
+ }