streamby-core 0.26.10 → 0.27.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 +283 -283
- package/dist/adapters/database/connectionManager.js +67 -44
- package/dist/adapters/database/sql.js +21 -21
- package/dist/middleware/createRouter.js +2 -0
- package/dist/middleware/routes/dbConnection.d.ts +3 -0
- package/dist/middleware/routes/dbConnection.js +278 -0
- package/dist/middleware/routes/export.js +4 -2
- package/dist/middleware/routes/project.js +6 -6
- package/dist/models/Model.d.ts +1 -0
- package/dist/models/Model.js +29 -6
- package/dist/services/dbConnection.d.ts +11 -0
- package/dist/services/dbConnection.js +148 -0
- package/dist/services/export.d.ts +1 -1
- package/dist/services/export.js +70 -22
- package/dist/services/pipeline.js +59 -1
- package/dist/types/index.d.ts +24 -2
- package/dist/utils/crypto.d.ts +3 -0
- package/dist/utils/crypto.js +32 -0
- package/package.json +63 -63
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listTablesOrCollections = listTablesOrCollections;
|
|
4
|
+
exports.createTableOrCollection = createTableOrCollection;
|
|
5
|
+
exports.queryRecords = queryRecords;
|
|
6
|
+
exports.insertRecord = insertRecord;
|
|
7
|
+
exports.listTablesInternal = listTablesInternal;
|
|
8
|
+
exports.queryRecordsInternal = queryRecordsInternal;
|
|
9
|
+
exports.createTableOrCollectionInternal = createTableOrCollectionInternal;
|
|
10
|
+
exports.insertRecordInternal = insertRecordInternal;
|
|
11
|
+
const pg_1 = require("pg");
|
|
12
|
+
const mongodb_1 = require("mongodb");
|
|
13
|
+
// ─── Ephemeral connection helpers ─────────────────────────────────────────────
|
|
14
|
+
async function withPostgres(connectionString, fn) {
|
|
15
|
+
const client = new pg_1.Client({ connectionString });
|
|
16
|
+
await client.connect();
|
|
17
|
+
try {
|
|
18
|
+
return await fn(client);
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
await client.end();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function withMongo(connectionString, fn) {
|
|
25
|
+
const mongo = new mongodb_1.MongoClient(connectionString);
|
|
26
|
+
await mongo.connect();
|
|
27
|
+
try {
|
|
28
|
+
return await fn(mongo.db());
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
await mongo.close();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// ─── Operations ───────────────────────────────────────────────────────────────
|
|
35
|
+
async function listTablesOrCollections(connectionString, dbType) {
|
|
36
|
+
if (dbType === 'postgresql') {
|
|
37
|
+
return withPostgres(connectionString, async (client) => {
|
|
38
|
+
const result = await client.query(`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name`);
|
|
39
|
+
return result.rows.map(r => r.table_name);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return withMongo(connectionString, async (db) => {
|
|
43
|
+
const cols = await db.listCollections().toArray();
|
|
44
|
+
return cols.map(c => c.name).sort();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
async function createTableOrCollection(connectionString, dbType, schema) {
|
|
48
|
+
if (dbType === 'postgresql') {
|
|
49
|
+
const columnDdl = schema.columns.map(col => {
|
|
50
|
+
const nullable = col.nullable === false ? 'NOT NULL' : '';
|
|
51
|
+
const pk = col.primaryKey ? 'PRIMARY KEY' : '';
|
|
52
|
+
return `"${col.name}" ${col.type} ${nullable} ${pk}`.trim();
|
|
53
|
+
}).join(', ');
|
|
54
|
+
const ddl = `CREATE TABLE IF NOT EXISTS "${schema.tableName}" (${columnDdl})`;
|
|
55
|
+
await withPostgres(connectionString, client => client.query(ddl).then(() => undefined));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
await withMongo(connectionString, async (db) => {
|
|
59
|
+
await db.createCollection(schema.tableName);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async function queryRecords(connectionString, dbType, tableName, limit = 50, offset = 0) {
|
|
63
|
+
if (dbType === 'postgresql') {
|
|
64
|
+
return withPostgres(connectionString, async (client) => {
|
|
65
|
+
const result = await client.query(`SELECT * FROM "${tableName}" LIMIT $1 OFFSET $2`, [limit, offset]);
|
|
66
|
+
return result.rows;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return withMongo(connectionString, async (db) => {
|
|
70
|
+
return db.collection(tableName).find().limit(limit).skip(offset).toArray();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async function insertRecord(connectionString, dbType, tableName, record) {
|
|
74
|
+
if (dbType === 'postgresql') {
|
|
75
|
+
return withPostgres(connectionString, async (client) => {
|
|
76
|
+
const keys = Object.keys(record);
|
|
77
|
+
const values = Object.values(record);
|
|
78
|
+
const cols = keys.map(k => `"${k}"`).join(', ');
|
|
79
|
+
const placeholders = keys.map((_, i) => `$${i + 1}`).join(', ');
|
|
80
|
+
const result = await client.query(`INSERT INTO "${tableName}" (${cols}) VALUES (${placeholders}) RETURNING *`, values);
|
|
81
|
+
return result.rows[0];
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return withMongo(connectionString, async (db) => {
|
|
85
|
+
const result = await db.collection(tableName).insertOne(record);
|
|
86
|
+
return { ...record, _id: result.insertedId };
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// ─── Internal (pool-based) variants ──────────────────────────────────────────
|
|
90
|
+
// These operate on already-connected Pool / MongoClient from connectionManager.
|
|
91
|
+
function quoteSqlTable(tableName) {
|
|
92
|
+
const parts = tableName.split('.');
|
|
93
|
+
return parts.length === 2 ? `"${parts[0]}"."${parts[1]}"` : `"${tableName}"`;
|
|
94
|
+
}
|
|
95
|
+
async function listTablesInternal(client, dbType, projectId) {
|
|
96
|
+
const prefix = projectId ? `db_${projectId}_` : null;
|
|
97
|
+
if (dbType === 'sql') {
|
|
98
|
+
const result = await client.query(`SELECT table_schema, table_name
|
|
99
|
+
FROM information_schema.tables
|
|
100
|
+
WHERE table_type = 'BASE TABLE'
|
|
101
|
+
AND table_schema NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
|
|
102
|
+
${prefix ? `AND table_name LIKE $1` : ''}
|
|
103
|
+
ORDER BY table_schema, table_name`, prefix ? [`${prefix}%`] : []);
|
|
104
|
+
return result.rows.map(r => {
|
|
105
|
+
const full = r.table_schema === 'public' ? r.table_name : `${r.table_schema}.${r.table_name}`;
|
|
106
|
+
return prefix ? full.slice(prefix.length) : full;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const cols = await client.db().listCollections().toArray();
|
|
110
|
+
const names = cols.map(c => c.name).sort();
|
|
111
|
+
if (!prefix)
|
|
112
|
+
return names;
|
|
113
|
+
return names.filter(n => n.startsWith(prefix)).map(n => n.slice(prefix.length));
|
|
114
|
+
}
|
|
115
|
+
async function queryRecordsInternal(client, dbType, tableName, limit = 50, offset = 0, projectId) {
|
|
116
|
+
const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
|
|
117
|
+
if (dbType === 'sql') {
|
|
118
|
+
const result = await client.query(`SELECT * FROM ${quoteSqlTable(fullName)} LIMIT $1 OFFSET $2`, [limit, offset]);
|
|
119
|
+
return result.rows;
|
|
120
|
+
}
|
|
121
|
+
return client.db().collection(fullName).find().limit(limit).skip(offset).toArray();
|
|
122
|
+
}
|
|
123
|
+
async function createTableOrCollectionInternal(client, dbType, schema, projectId) {
|
|
124
|
+
const fullName = projectId ? `db_${projectId}_${schema.tableName}` : schema.tableName;
|
|
125
|
+
if (dbType === 'sql') {
|
|
126
|
+
const columnDdl = schema.columns.map(col => {
|
|
127
|
+
const nullable = col.nullable === false ? 'NOT NULL' : '';
|
|
128
|
+
const pk = col.primaryKey ? 'PRIMARY KEY' : '';
|
|
129
|
+
return `"${col.name}" ${col.type} ${nullable} ${pk}`.trim();
|
|
130
|
+
}).join(', ');
|
|
131
|
+
await client.query(`CREATE TABLE IF NOT EXISTS ${quoteSqlTable(fullName)} (${columnDdl})`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
await client.db().createCollection(fullName);
|
|
135
|
+
}
|
|
136
|
+
async function insertRecordInternal(client, dbType, tableName, record, projectId) {
|
|
137
|
+
const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
|
|
138
|
+
if (dbType === 'sql') {
|
|
139
|
+
const keys = Object.keys(record);
|
|
140
|
+
const values = Object.values(record);
|
|
141
|
+
const cols = keys.map(k => `"${k}"`).join(', ');
|
|
142
|
+
const placeholders = keys.map((_, i) => `$${i + 1}`).join(', ');
|
|
143
|
+
const result = await client.query(`INSERT INTO ${quoteSqlTable(fullName)} (${cols}) VALUES (${placeholders}) RETURNING *`, values);
|
|
144
|
+
return result.rows[0];
|
|
145
|
+
}
|
|
146
|
+
const result = await client.db().collection(fullName).insertOne(record);
|
|
147
|
+
return { ...record, _id: result.insertedId };
|
|
148
|
+
}
|
|
@@ -3,7 +3,7 @@ interface ExportResult {
|
|
|
3
3
|
exportId: string;
|
|
4
4
|
message: string;
|
|
5
5
|
}
|
|
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>;
|
|
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, storageDbId?: string): Promise<ExportResult>;
|
|
7
7
|
export declare function updateExport(config: StreamByConfig, projectId: string, exportId: string, description: string, exportName: string, dbType: DatabaseType, exportType: 'json' | 'externalApi', isPrivate?: boolean, allowedOrigin?: string[], nodeSchema?: NodeSchema, useConnections?: boolean, useCredentials?: boolean): Promise<ExportResult>;
|
|
8
8
|
export declare function deleteExport(config: StreamByConfig, projectId: string, exportId: string, dbType: DatabaseType, exportName: string): Promise<{
|
|
9
9
|
message: string;
|
package/dist/services/export.js
CHANGED
|
@@ -8,65 +8,113 @@ 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, description, exportName, dbType, exportType, isPrivate, allowedOrigin, nodeSchema, useConnections, useCredentials) {
|
|
12
|
-
const targetDb =
|
|
13
|
-
config.databases?.find(db => db.
|
|
11
|
+
async function createExport(config, projectId, description, exportName, dbType, exportType, isPrivate, allowedOrigin, nodeSchema, useConnections, useCredentials, storageDbId) {
|
|
12
|
+
const targetDb = storageDbId
|
|
13
|
+
? config.databases?.find(db => db.id === storageDbId)
|
|
14
|
+
: config.databases?.find(db => db.type === dbType && db.main) ||
|
|
15
|
+
config.databases?.find(db => db.type === dbType);
|
|
14
16
|
if (!targetDb) {
|
|
15
17
|
throw new Error(`Database connection not found for type ${dbType}`);
|
|
16
18
|
}
|
|
17
19
|
const connection = (0, connectionManager_1.getConnection)(targetDb.id);
|
|
20
|
+
const resolvedDbType = targetDb.type;
|
|
18
21
|
let exportId;
|
|
19
|
-
if (
|
|
22
|
+
if (resolvedDbType === 'nosql') {
|
|
20
23
|
const result = await (0, nosql_1.createNoSQLRawExportCollection)(connection.client, projectId, exportName, 'GET', nodeSchema);
|
|
21
24
|
exportId = result.exportId;
|
|
22
25
|
}
|
|
23
|
-
else if (
|
|
26
|
+
else if (resolvedDbType === 'sql') {
|
|
24
27
|
const result = await (0, sql_1.createSQLRawExportTable)(connection.client, projectId, exportName, nodeSchema);
|
|
25
28
|
exportId = result.exportId;
|
|
26
29
|
}
|
|
27
30
|
else {
|
|
28
31
|
throw new Error('Unsupported database type');
|
|
29
32
|
}
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
// Route the project document update to the correct DB based on where the project lives
|
|
34
|
+
const Project = (0, manager_1.getModel)('projects');
|
|
35
|
+
const project = await Project.findOne({ _id: projectId });
|
|
36
|
+
const isSqlProject = project?.dbType === 'sql';
|
|
37
|
+
const exportEntry = {
|
|
38
|
+
id: isSqlProject ? exportId : new mongodb_1.ObjectId(exportId),
|
|
39
|
+
name: exportName,
|
|
40
|
+
type: exportType,
|
|
41
|
+
method: 'GET',
|
|
42
|
+
private: isPrivate,
|
|
43
|
+
allowedOrigin,
|
|
44
|
+
nodeSchema,
|
|
45
|
+
useConnections,
|
|
46
|
+
useCredentials,
|
|
47
|
+
description,
|
|
48
|
+
storageDbId: targetDb.id,
|
|
49
|
+
};
|
|
50
|
+
const ProjectModel = isSqlProject ? (0, manager_1.getModel)('projects', 'sql') : (0, manager_1.getModel)('projects', 'nosql');
|
|
51
|
+
await ProjectModel.update({ _id: projectId }, { $push: { exports: exportEntry } });
|
|
32
52
|
return { exportId, message: `${exportType} export created successfully` };
|
|
33
53
|
}
|
|
34
54
|
async function updateExport(config, projectId, exportId, description, exportName, dbType, exportType, isPrivate, allowedOrigin, nodeSchema, useConnections, useCredentials) {
|
|
35
|
-
|
|
36
|
-
|
|
55
|
+
// Resolve the project to find where its raw export data lives
|
|
56
|
+
const Project = (0, manager_1.getModel)('projects');
|
|
57
|
+
const project = await Project.findOne({ _id: projectId });
|
|
58
|
+
const isSqlProject = project?.dbType === 'sql';
|
|
59
|
+
// Find storageDbId from the export entry, or fall back to the legacy dbType lookup
|
|
60
|
+
const exportEntry = project?.exports?.find((e) => String(e.id) === exportId);
|
|
61
|
+
const resolvedStorageDbId = exportEntry?.storageDbId;
|
|
62
|
+
const targetDb = resolvedStorageDbId
|
|
63
|
+
? config.databases?.find(db => db.id === resolvedStorageDbId)
|
|
64
|
+
: config.databases?.find(db => db.type === dbType && db.main) ||
|
|
65
|
+
config.databases?.find(db => db.type === dbType);
|
|
37
66
|
if (!targetDb) {
|
|
38
67
|
throw new Error(`Database connection not found for type ${dbType}`);
|
|
39
68
|
}
|
|
40
69
|
const connection = (0, connectionManager_1.getConnection)(targetDb.id);
|
|
41
|
-
if (
|
|
70
|
+
if (targetDb.type === 'nosql') {
|
|
42
71
|
const db = connection.client.db();
|
|
43
72
|
await db.collection(projectId).updateOne({ _id: new mongodb_1.ObjectId(exportId) }, { $set: { nodeSchema, description, updatedAt: new Date() } });
|
|
44
73
|
}
|
|
74
|
+
// SQL raw export table update would go here if needed in future
|
|
75
|
+
// Update the export entry in the project document
|
|
76
|
+
if (isSqlProject) {
|
|
77
|
+
// For SQL projects: read-modify-write the exports JSONB array
|
|
78
|
+
const SqlProject = (0, manager_1.getModel)('projects', 'sql');
|
|
79
|
+
const currentExports = project?.exports ?? [];
|
|
80
|
+
const updatedExports = currentExports.map((e) => String(e.id) === exportId
|
|
81
|
+
? { ...e, name: exportName, private: isPrivate, allowedOrigin, nodeSchema, useConnections, useCredentials, description }
|
|
82
|
+
: e);
|
|
83
|
+
await SqlProject.update({ _id: projectId }, { exports: updatedExports });
|
|
84
|
+
}
|
|
45
85
|
else {
|
|
46
|
-
|
|
86
|
+
const NoSQLProject = (0, manager_1.getModel)('projects', 'nosql');
|
|
87
|
+
await NoSQLProject.update({ _id: new mongodb_1.ObjectId(projectId), 'exports.id': { $in: [new mongodb_1.ObjectId(exportId), exportId] } }, { $set: { 'exports.$.name': exportName, 'exports.$.private': isPrivate, 'exports.$.allowedOrigin': allowedOrigin, 'exports.$.nodeSchema': nodeSchema, 'exports.$.useConnections': useConnections, 'exports.$.useCredentials': useCredentials, 'exports.$.description': description } });
|
|
47
88
|
}
|
|
48
|
-
const NoSQLProject = (0, manager_1.getModel)('projects', 'nosql');
|
|
49
|
-
await NoSQLProject.update({
|
|
50
|
-
_id: new mongodb_1.ObjectId(projectId),
|
|
51
|
-
'exports.id': { $in: [new mongodb_1.ObjectId(exportId), exportId] }
|
|
52
|
-
}, { $set: { 'exports.$.name': exportName, 'exports.$.private': isPrivate, 'exports.$.allowedOrigin': allowedOrigin, 'exports.$.nodeSchema': nodeSchema, 'exports.$.useConnections': useConnections, 'exports.$.useCredentials': useCredentials, 'exports.$.description': description } });
|
|
53
89
|
return { exportId, message: `${exportType} export updated successfully` };
|
|
54
90
|
}
|
|
55
91
|
async function deleteExport(config, projectId, exportId, dbType, exportName) {
|
|
56
|
-
|
|
57
|
-
|
|
92
|
+
// Resolve the project to find where its raw export data lives
|
|
93
|
+
const Project = (0, manager_1.getModel)('projects');
|
|
94
|
+
const project = await Project.findOne({ _id: projectId });
|
|
95
|
+
const isSqlProject = project?.dbType === 'sql';
|
|
96
|
+
const exportEntry = project?.exports?.find((e) => String(e.id) === exportId);
|
|
97
|
+
const resolvedStorageDbId = exportEntry?.storageDbId;
|
|
98
|
+
const targetDb = resolvedStorageDbId
|
|
99
|
+
? config.databases?.find(db => db.id === resolvedStorageDbId)
|
|
100
|
+
: config.databases?.find(db => db.type === dbType && db.main) ||
|
|
101
|
+
config.databases?.find(db => db.type === dbType);
|
|
58
102
|
if (!targetDb) {
|
|
59
103
|
throw new Error(`Database connection not found for type ${dbType}`);
|
|
60
104
|
}
|
|
61
105
|
const connection = (0, connectionManager_1.getConnection)(targetDb.id);
|
|
62
|
-
if (
|
|
106
|
+
if (targetDb.type === 'nosql') {
|
|
63
107
|
const db = connection.client.db();
|
|
64
108
|
await db.collection(projectId).deleteOne({ _id: new mongodb_1.ObjectId(exportId) });
|
|
65
109
|
}
|
|
110
|
+
// SQL raw export table row deletion would go here if needed in future
|
|
111
|
+
if (isSqlProject) {
|
|
112
|
+
const SqlProject = (0, manager_1.getModel)('projects', 'sql');
|
|
113
|
+
await SqlProject.update({ _id: projectId }, { $pull: { exports: { id: exportId } } });
|
|
114
|
+
}
|
|
66
115
|
else {
|
|
67
|
-
|
|
116
|
+
const NoSQLProject = (0, manager_1.getModel)('projects', 'nosql');
|
|
117
|
+
await NoSQLProject.update({ _id: new mongodb_1.ObjectId(projectId) }, { $pull: { exports: { id: new mongodb_1.ObjectId(exportId) } } });
|
|
68
118
|
}
|
|
69
|
-
const NoSQLProject = (0, manager_1.getModel)('projects', 'nosql');
|
|
70
|
-
await NoSQLProject.update({ _id: new mongodb_1.ObjectId(projectId) }, { $pull: { exports: { id: new mongodb_1.ObjectId(exportId) } } });
|
|
71
119
|
return { message: 'Export deleted successfully' };
|
|
72
120
|
}
|
|
@@ -3,6 +3,62 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.executePipeline = executePipeline;
|
|
4
4
|
const connectionManager_1 = require("../adapters/database/connectionManager");
|
|
5
5
|
const encryption_1 = require("../utils/encryption");
|
|
6
|
+
function applyFilterConfig(payload, config) {
|
|
7
|
+
const isArr = Array.isArray(payload);
|
|
8
|
+
let r = isArr ? [...payload] : payload;
|
|
9
|
+
if (config.conditions?.length) {
|
|
10
|
+
const matches = (item) => config.conditions.every(c => {
|
|
11
|
+
const v = item?.[c.field];
|
|
12
|
+
switch (c.op) {
|
|
13
|
+
case 'eq': return String(v) === c.value;
|
|
14
|
+
case 'neq': return String(v) !== c.value;
|
|
15
|
+
case 'gt': return Number(v) > Number(c.value);
|
|
16
|
+
case 'lt': return Number(v) < Number(c.value);
|
|
17
|
+
case 'gte': return Number(v) >= Number(c.value);
|
|
18
|
+
case 'lte': return Number(v) <= Number(c.value);
|
|
19
|
+
case 'contains': return String(v).includes(c.value);
|
|
20
|
+
case 'startsWith': return String(v).startsWith(c.value);
|
|
21
|
+
case 'endsWith': return String(v).endsWith(c.value);
|
|
22
|
+
default: return true;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
r = isArr ? r.filter(matches) : (matches(r) ? r : null);
|
|
26
|
+
if (r === null)
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (config.includeFields?.length) {
|
|
30
|
+
const pick = (item) => {
|
|
31
|
+
if (!item || typeof item !== 'object')
|
|
32
|
+
return item;
|
|
33
|
+
const o = {};
|
|
34
|
+
for (const f of config.includeFields)
|
|
35
|
+
if (f in item)
|
|
36
|
+
o[f] = item[f];
|
|
37
|
+
return o;
|
|
38
|
+
};
|
|
39
|
+
r = isArr ? r.map(pick) : pick(r);
|
|
40
|
+
}
|
|
41
|
+
if (config.renameFields?.length) {
|
|
42
|
+
const ren = (item) => {
|
|
43
|
+
if (!item || typeof item !== 'object')
|
|
44
|
+
return item;
|
|
45
|
+
const o = { ...item };
|
|
46
|
+
for (const { from, to } of config.renameFields) {
|
|
47
|
+
if (from in o) {
|
|
48
|
+
o[to] = o[from];
|
|
49
|
+
delete o[from];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return o;
|
|
53
|
+
};
|
|
54
|
+
r = isArr ? r.map(ren) : ren(r);
|
|
55
|
+
}
|
|
56
|
+
if (config.limit && isArr)
|
|
57
|
+
r = r.slice(0, config.limit);
|
|
58
|
+
if (config.wrapKey)
|
|
59
|
+
r = { [config.wrapKey]: r };
|
|
60
|
+
return r;
|
|
61
|
+
}
|
|
6
62
|
function getSources(nodes, edges, targetId, targetHandle) {
|
|
7
63
|
return edges
|
|
8
64
|
.filter(e => e.target === targetId && e.targetHandle === targetHandle)
|
|
@@ -69,7 +125,9 @@ async function executePipeline(nodeSchema, project, config) {
|
|
|
69
125
|
// 3. Filter layer — chain from streamby out-right → filterNode in-filter → out-filter → ...
|
|
70
126
|
let filterNode = getTarget(nodes, edges, 'streamby', 'out-right');
|
|
71
127
|
while (filterNode) {
|
|
72
|
-
|
|
128
|
+
const cfg = filterNode.data?.filterConfig;
|
|
129
|
+
if (cfg)
|
|
130
|
+
payload = applyFilterConfig(payload, cfg);
|
|
73
131
|
filterNode = getTarget(nodes, edges, filterNode.id, 'out-filter');
|
|
74
132
|
}
|
|
75
133
|
return payload;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export interface FieldDefinition {
|
|
|
40
40
|
export interface ProjectInfo {
|
|
41
41
|
_id?: string;
|
|
42
42
|
id: string;
|
|
43
|
-
dbType
|
|
43
|
+
dbType?: DatabaseType;
|
|
44
44
|
name: string;
|
|
45
45
|
image?: string;
|
|
46
46
|
members?: {
|
|
@@ -59,6 +59,7 @@ export interface ProjectInfo {
|
|
|
59
59
|
};
|
|
60
60
|
credentials?: Credential[];
|
|
61
61
|
apiConnections?: ApiConnection[];
|
|
62
|
+
dbConnections?: DbConnection[];
|
|
62
63
|
}
|
|
63
64
|
export interface Credential {
|
|
64
65
|
id: string;
|
|
@@ -79,7 +80,7 @@ export interface ApiConnection {
|
|
|
79
80
|
}
|
|
80
81
|
export interface ProjectListInfo {
|
|
81
82
|
id: string;
|
|
82
|
-
dbType
|
|
83
|
+
dbType?: DatabaseType;
|
|
83
84
|
name: string;
|
|
84
85
|
image?: string;
|
|
85
86
|
archived: boolean;
|
|
@@ -122,6 +123,26 @@ export interface Auth {
|
|
|
122
123
|
role: 'viewer' | 'editor' | 'admin';
|
|
123
124
|
}
|
|
124
125
|
export type AuthProvider = (req: Request) => Promise<Auth>;
|
|
126
|
+
export type ExternalDbType = 'postgresql' | 'mongodb';
|
|
127
|
+
export interface DbConnection {
|
|
128
|
+
id: string;
|
|
129
|
+
name: string;
|
|
130
|
+
dbType: ExternalDbType;
|
|
131
|
+
credentialId: string;
|
|
132
|
+
projectId: string;
|
|
133
|
+
createdAt: Date;
|
|
134
|
+
description?: string;
|
|
135
|
+
}
|
|
136
|
+
export interface ColumnDefinition {
|
|
137
|
+
name: string;
|
|
138
|
+
type: string;
|
|
139
|
+
nullable?: boolean;
|
|
140
|
+
primaryKey?: boolean;
|
|
141
|
+
}
|
|
142
|
+
export interface CreateTableSchema {
|
|
143
|
+
tableName: string;
|
|
144
|
+
columns: ColumnDefinition[];
|
|
145
|
+
}
|
|
125
146
|
export interface NodeSchema {
|
|
126
147
|
nodes: any[];
|
|
127
148
|
edges: any[];
|
|
@@ -143,4 +164,5 @@ export interface Export {
|
|
|
143
164
|
nodeSchema?: NodeSchema;
|
|
144
165
|
useConnections?: boolean;
|
|
145
166
|
useCredentials?: boolean;
|
|
167
|
+
storageDbId?: string;
|
|
146
168
|
}
|
|
@@ -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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "streamby-core",
|
|
3
|
-
"version": "0.
|
|
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
|
-
"node-fetch": "^3.0.0",
|
|
41
|
-
"pg": "^8.16.3",
|
|
42
|
-
"prisma": "^6.12.0",
|
|
43
|
-
"ws": "^8.20.0"
|
|
44
|
-
},
|
|
45
|
-
"devDependencies": {
|
|
46
|
-
"@types/bcrypt": "^5.0.2",
|
|
47
|
-
"@types/cors": "^2.8.18",
|
|
48
|
-
"@types/express": "^4.17.17",
|
|
49
|
-
"@types/mongodb": "^4.0.7",
|
|
50
|
-
"@types/node": "^22.15.21",
|
|
51
|
-
"@types/pg": "^8.15.4",
|
|
52
|
-
"@types/supertest": "^6.0.3",
|
|
53
|
-
"@types/ws": "^8.18.1",
|
|
54
|
-
"cors": "^2.8.5",
|
|
55
|
-
"supertest": "^7.1.4",
|
|
56
|
-
"ts-node-dev": "^2.0.0",
|
|
57
|
-
"typescript": "^5.8.3",
|
|
58
|
-
"vitest": "^3.1.1"
|
|
59
|
-
},
|
|
60
|
-
"peerDependencies": {
|
|
61
|
-
"express": "^4.0.0"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "streamby-core",
|
|
3
|
+
"version": "0.27.00",
|
|
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
|
+
"node-fetch": "^3.0.0",
|
|
41
|
+
"pg": "^8.16.3",
|
|
42
|
+
"prisma": "^6.12.0",
|
|
43
|
+
"ws": "^8.20.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/bcrypt": "^5.0.2",
|
|
47
|
+
"@types/cors": "^2.8.18",
|
|
48
|
+
"@types/express": "^4.17.17",
|
|
49
|
+
"@types/mongodb": "^4.0.7",
|
|
50
|
+
"@types/node": "^22.15.21",
|
|
51
|
+
"@types/pg": "^8.15.4",
|
|
52
|
+
"@types/supertest": "^6.0.3",
|
|
53
|
+
"@types/ws": "^8.18.1",
|
|
54
|
+
"cors": "^2.8.5",
|
|
55
|
+
"supertest": "^7.1.4",
|
|
56
|
+
"ts-node-dev": "^2.0.0",
|
|
57
|
+
"typescript": "^5.8.3",
|
|
58
|
+
"vitest": "^3.1.1"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"express": "^4.0.0"
|
|
62
|
+
}
|
|
63
|
+
}
|