streamby-core 0.25.8 → 0.26.1
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 +3 -6
- package/dist/adapters/database/sql.d.ts +1 -1
- package/dist/adapters/database/sql.js +22 -19
- package/dist/middleware/createRouter.js +2 -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/project.js +10 -1
- package/dist/models/Model.js +5 -5
- package/dist/services/export.d.ts +5 -6
- package/dist/services/export.js +16 -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
package/dist/services/export.js
CHANGED
|
@@ -8,103 +8,39 @@ 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, projectId, exportName, 'GET', nodeSchema);
|
|
21
|
+
exportId = result.exportId;
|
|
50
22
|
}
|
|
51
23
|
else if (dbType === 'sql') {
|
|
52
|
-
result = await (0, sql_1.createSQLRawExportTable)(connection.client, projectId, exportName,
|
|
24
|
+
const result = await (0, sql_1.createSQLRawExportTable)(connection.client, projectId, 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, 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 (exportType === 'externalApi') {
|
|
72
|
-
if (!apiUrl) {
|
|
73
|
-
throw new Error('API URL is required for externalApi export type.');
|
|
74
|
-
}
|
|
75
|
-
const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
|
|
76
|
-
const project = await ProjectModel.findOne({ _id: projectId });
|
|
77
|
-
if (!project) {
|
|
78
|
-
throw new Error('Project not found.');
|
|
79
|
-
}
|
|
80
|
-
if (dbType === 'nosql') {
|
|
81
|
-
const db = connection.client.db();
|
|
82
|
-
const updateData = {
|
|
83
|
-
json: jsonData,
|
|
84
|
-
description: description,
|
|
85
|
-
fields: fields,
|
|
86
|
-
updatedAt: new Date(),
|
|
87
|
-
apiUrl: apiUrl,
|
|
88
|
-
credentialId: credentialId,
|
|
89
|
-
prefix: prefix,
|
|
90
|
-
};
|
|
91
|
-
await db.collection(collectionName).updateOne({ _id: new mongodb_1.ObjectId(exportId) }, { $set: updateData });
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
throw new Error('Unsupported database type for externalApi export update');
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else if (dbType === 'nosql') {
|
|
41
|
+
if (dbType === 'nosql') {
|
|
98
42
|
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 });
|
|
43
|
+
await db.collection(projectId).updateOne({ _id: new mongodb_1.ObjectId(exportId) }, { $set: { nodeSchema, description, updatedAt: new Date() } });
|
|
108
44
|
}
|
|
109
45
|
else {
|
|
110
46
|
throw new Error('Unsupported database type for update');
|
|
@@ -113,11 +49,10 @@ async function updateExport(config, projectId, exportId, description, fields, ex
|
|
|
113
49
|
await NoSQLProject.update({
|
|
114
50
|
_id: new mongodb_1.ObjectId(projectId),
|
|
115
51
|
'exports.id': { $in: [new mongodb_1.ObjectId(exportId), exportId] }
|
|
116
|
-
}, { $set: { 'exports.$.name': exportName, 'exports.$.
|
|
117
|
-
|
|
118
|
-
return { ...result, message: `${exportType} export updated successfully` };
|
|
52
|
+
}, { $set: { 'exports.$.name': exportName, 'exports.$.private': isPrivate, 'exports.$.allowedOrigin': allowedOrigin, 'exports.$.nodeSchema': nodeSchema, 'exports.$.useConnections': useConnections, 'exports.$.useCredentials': useCredentials, 'exports.$.description': description } });
|
|
53
|
+
return { exportId, message: `${exportType} export updated successfully` };
|
|
119
54
|
}
|
|
120
|
-
async function deleteExport(config, projectId, exportId, dbType,
|
|
55
|
+
async function deleteExport(config, projectId, exportId, dbType, exportName) {
|
|
121
56
|
const targetDb = config.databases?.find(db => db.type === dbType && db.main) ||
|
|
122
57
|
config.databases?.find(db => db.type === dbType);
|
|
123
58
|
if (!targetDb) {
|
|
@@ -126,7 +61,7 @@ async function deleteExport(config, projectId, exportId, dbType, collectionName)
|
|
|
126
61
|
const connection = (0, connectionManager_1.getConnection)(targetDb.id);
|
|
127
62
|
if (dbType === 'nosql') {
|
|
128
63
|
const db = connection.client.db();
|
|
129
|
-
await db.collection(
|
|
64
|
+
await db.collection(projectId).deleteOne({ _id: new mongodb_1.ObjectId(exportId) });
|
|
130
65
|
}
|
|
131
66
|
else {
|
|
132
67
|
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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
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
|
-
"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
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "streamby-core",
|
|
3
|
+
"version": "0.26.1",
|
|
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
|
+
}
|