streamby-core 0.20.2 → 0.21.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.
Files changed (45) hide show
  1. package/dist/adapters/database/connectionManager.d.ts +5 -1
  2. package/dist/adapters/database/connectionManager.js +66 -10
  3. package/dist/adapters/database/nosql.d.ts +1 -0
  4. package/dist/adapters/database/nosql.js +15 -1
  5. package/dist/adapters/database/sql.js +7 -3
  6. package/dist/middleware/createRouter.js +96 -14
  7. package/dist/models/Model.js +167 -36
  8. package/dist/services/auth.d.ts +1 -3
  9. package/dist/services/auth.js +0 -10
  10. package/dist/types/index.d.ts +1 -2
  11. package/package.json +1 -1
  12. package/dist/adapters/database/nosqlAdapter.d.ts +0 -8
  13. package/dist/adapters/database/nosqlAdapter.js +0 -30
  14. package/dist/adapters/database/sqlAdapter.d.ts +0 -8
  15. package/dist/adapters/database/sqlAdapter.js +0 -42
  16. package/dist/adapters/gcs.d.ts +0 -0
  17. package/dist/adapters/gcs.js +0 -1
  18. package/dist/adapters/local.d.ts +0 -0
  19. package/dist/adapters/local.js +0 -1
  20. package/dist/adapters/s3.d.ts +0 -11
  21. package/dist/adapters/s3.js +0 -65
  22. package/dist/database/Model.d.ts +0 -11
  23. package/dist/database/Model.js +0 -95
  24. package/dist/database/connectionManager.d.ts +0 -5
  25. package/dist/database/connectionManager.js +0 -32
  26. package/dist/database/index.d.ts +0 -3
  27. package/dist/database/index.js +0 -19
  28. package/dist/database/model.d.ts +0 -20
  29. package/dist/database/model.js +0 -2
  30. package/dist/database/modelManager.d.ts +0 -8
  31. package/dist/database/modelManager.js +0 -38
  32. package/dist/database/modelRegistry.d.ts +0 -3
  33. package/dist/database/modelRegistry.js +0 -17
  34. package/dist/database/mongoAdapter.d.ts +0 -11
  35. package/dist/database/mongoAdapter.js +0 -42
  36. package/dist/database/sqlAdapter.d.ts +0 -12
  37. package/dist/database/sqlAdapter.js +0 -68
  38. package/dist/models/modelManager.d.ts +0 -2
  39. package/dist/models/modelManager.js +0 -7
  40. package/dist/models/modelRegistry.d.ts +0 -3
  41. package/dist/models/modelRegistry.js +0 -17
  42. package/dist/models/registerModel.d.ts +0 -1
  43. package/dist/models/registerModel.js +0 -8
  44. package/dist/providers/createStorageProvider.d.ts +0 -2
  45. package/dist/providers/createStorageProvider.js +0 -12
@@ -2,5 +2,9 @@ import { Pool } from 'pg';
2
2
  import { MongoClient } from 'mongodb';
3
3
  import { DatabaseCredential } from '../../types';
4
4
  export declare const initConnections: (configs: DatabaseCredential[]) => Promise<void>;
5
- export declare const getConnection: (id: string) => Pool | MongoClient;
5
+ export declare const getConnection: (id: string) => {
6
+ id: string;
7
+ type: "sql" | "nosql";
8
+ client: Pool | MongoClient;
9
+ };
6
10
  export declare const getConnectedIds: () => string[];
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getConnectedIds = exports.getConnection = exports.initConnections = void 0;
4
4
  const pg_1 = require("pg");
5
5
  const mongodb_1 = require("mongodb");
6
- const clients = {};
7
- const connectedIds = [];
6
+ const nosql_1 = require("./nosql");
7
+ const connectedClients = [];
8
8
  const initConnections = async (configs) => {
9
9
  for (const config of configs) {
10
10
  if (!config.connectionString) {
@@ -15,16 +15,16 @@ const initConnections = async (configs) => {
15
15
  if (config.type === 'sql') {
16
16
  const pool = new pg_1.Pool({ connectionString: config.connectionString });
17
17
  await pool.connect();
18
- clients[config.id] = pool;
19
- connectedIds.push(config.id);
18
+ connectedClients.push({ id: config.id, type: 'sql', client: pool });
20
19
  console.log(`🟢 PostgreSQL connection established for ID: ${config.id}`);
20
+ await ensureTablesExist(pool);
21
21
  }
22
22
  else if (config.type === 'nosql') {
23
23
  const client = new mongodb_1.MongoClient(config.connectionString);
24
24
  await client.connect();
25
- clients[config.id] = client;
26
- connectedIds.push(config.id);
25
+ connectedClients.push({ id: config.id, type: 'nosql', client: client });
27
26
  console.log(`🟢 MongoDB connection established for ID: ${config.id}`);
27
+ await (0, nosql_1.ensureCollectionsExist)(client);
28
28
  }
29
29
  }
30
30
  catch (error) {
@@ -34,14 +34,70 @@ const initConnections = async (configs) => {
34
34
  };
35
35
  exports.initConnections = initConnections;
36
36
  const getConnection = (id) => {
37
- const client = clients[id];
38
- if (!client) {
37
+ const clientEntry = connectedClients.find(c => c.id === id);
38
+ if (!clientEntry) {
39
39
  throw new Error(`Connection with id ${id} not found.`);
40
40
  }
41
- return client;
41
+ return clientEntry;
42
42
  };
43
43
  exports.getConnection = getConnection;
44
+ const ensureTablesExist = async (pool) => {
45
+ try {
46
+ await pool.query(`
47
+ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
48
+ CREATE TABLE IF NOT EXISTS projects (
49
+ id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
50
+ name VARCHAR(255) NOT NULL,
51
+ description TEXT,
52
+ "createdAt" TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
53
+ "updatedAt" TIMESTAMP WITH TIME ZONE DEFAULT NOW()
54
+ );
55
+ `);
56
+ console.log('✅ "projects" table ensured to exist.');
57
+ // Ensure dbType column exists and is correctly configured
58
+ await pool.query(`
59
+ ALTER TABLE projects ADD COLUMN IF NOT EXISTS "dbType" VARCHAR(50);
60
+ `);
61
+ await pool.query(`
62
+ UPDATE projects SET "dbType" = 'nosql' WHERE "dbType" IS NULL;
63
+ `);
64
+ await pool.query(`
65
+ ALTER TABLE projects ALTER COLUMN "dbType" SET NOT NULL;
66
+ `);
67
+ await pool.query(`
68
+ ALTER TABLE projects ALTER COLUMN "dbType" SET DEFAULT 'nosql';
69
+ `);
70
+ await pool.query(`
71
+ CREATE TABLE IF NOT EXISTS exports (
72
+ id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
73
+ "projectId" UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
74
+ status VARCHAR(50) NOT NULL DEFAULT 'pending',
75
+ "filePath" TEXT,
76
+ "createdAt" TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
77
+ "updatedAt" TIMESTAMP WITH TIME ZONE DEFAULT NOW()
78
+ );
79
+ `);
80
+ console.log('✅ "exports" table ensured to exist.');
81
+ await pool.query(`
82
+ CREATE TABLE IF NOT EXISTS project_members (
83
+ id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
84
+ "projectId" UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
85
+ "userId" VARCHAR(255) NOT NULL,
86
+ archived BOOLEAN NOT NULL DEFAULT FALSE,
87
+ "archivedBy" VARCHAR(255),
88
+ "archivedAt" TIMESTAMP WITH TIME ZONE,
89
+ "createdAt" TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
90
+ "updatedAt" TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
91
+ UNIQUE ("projectId", "userId")
92
+ );
93
+ `);
94
+ console.log('✅ "project_members" table ensured to exist.');
95
+ }
96
+ catch (error) {
97
+ console.error('❌ Error ensuring tables exist:', error);
98
+ }
99
+ };
44
100
  const getConnectedIds = () => {
45
- return connectedIds;
101
+ return connectedClients.map(c => c.id);
46
102
  };
47
103
  exports.getConnectedIds = getConnectedIds;
@@ -1,4 +1,5 @@
1
1
  import { MongoClient, Document } from 'mongodb';
2
+ export declare const ensureCollectionsExist: (client: MongoClient) => Promise<void>;
2
3
  export declare const nosqlAdapter: {
3
4
  find: (connection: MongoClient, tableName: string, filter: any) => Promise<Document[]>;
4
5
  findOne: (connection: MongoClient, tableName: string, filter: any) => Promise<Document | null>;
@@ -1,7 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.nosqlAdapter = void 0;
3
+ exports.nosqlAdapter = exports.ensureCollectionsExist = void 0;
4
4
  const mongodb_1 = require("mongodb");
5
+ const ensureCollectionsExist = async (client) => {
6
+ const db = client.db();
7
+ // Ensure 'projects' collection exists and define its schema implicitly
8
+ // Schema: { _id: ObjectId, name: string, description: string, dbType: string, createdAt: Date, updatedAt: Date, members: [{ userId: string, archived: boolean }] }
9
+ const projectsCollection = db.collection('projects');
10
+ await projectsCollection.findOne({}); // Attempt to find one to ensure collection is created if it doesn't exist
11
+ console.log('✅ "projects" collection ensured to exist.');
12
+ // Ensure 'exports' collection exists and define its schema implicitly
13
+ // Schema: { _id: ObjectId, projectId: ObjectId, status: string, filePath: string, createdAt: Date, updatedAt: Date }
14
+ const exportsCollection = db.collection('exports');
15
+ await exportsCollection.findOne({}); // Attempt to find one to ensure collection is created if it doesn't exist
16
+ console.log('✅ "exports" collection ensured to exist.');
17
+ };
18
+ exports.ensureCollectionsExist = ensureCollectionsExist;
5
19
  exports.nosqlAdapter = {
6
20
  find: async (connection, tableName, filter) => {
7
21
  const db = connection.db();
@@ -5,8 +5,12 @@ exports.sqlAdapter = {
5
5
  find: async (connection, tableName, filter) => {
6
6
  const keys = Object.keys(filter);
7
7
  const values = Object.values(filter);
8
- const where = keys.map((key, i) => `"${key}" = $${i + 1}`).join(' AND ');
9
- const result = await connection.query(`SELECT * FROM "${tableName}" WHERE ${where}`, values);
8
+ let query = `SELECT * FROM "${tableName}"`;
9
+ if (keys.length > 0) {
10
+ const where = keys.map((key, i) => `"${key}" = $${i + 1}`).join(' AND ');
11
+ query += ` WHERE ${where}`;
12
+ }
13
+ const result = await connection.query(query, values);
10
14
  return result.rows;
11
15
  },
12
16
  findOne: async (connection, tableName, filter) => {
@@ -17,7 +21,7 @@ exports.sqlAdapter = {
17
21
  return result.rows[0] || null;
18
22
  },
19
23
  create: async (connection, tableName, data) => {
20
- const keys = Object.keys(data).join(', ');
24
+ const keys = Object.keys(data).map(key => `"${key}"`).join(', ');
21
25
  const values = Object.values(data);
22
26
  const placeholders = values.map((_, i) => `$${i + 1}`).join(', ');
23
27
  const result = await connection.query(`INSERT INTO "${tableName}" (${keys}) VALUES (${placeholders}) RETURNING *`, values);
@@ -18,28 +18,32 @@ function createStreamByRouter(config) {
18
18
  (0, connectionManager_1.initConnections)(config.databases || []);
19
19
  const adapter = config.adapter || (0, storage_1.createStorageProvider)(config.storageProviders);
20
20
  if (config.databases) {
21
- for (const db of config.databases) {
22
- if (db.type === 'sql') {
23
- (0, manager_1.registerModel)('Project', [db.id], 'projects');
24
- (0, manager_1.registerModel)('Export', [db.id], 'exports');
25
- }
26
- }
21
+ const allDbIds = config.databases.map(db => db.id);
22
+ (0, manager_1.registerModel)('projects', allDbIds, 'projects');
23
+ (0, manager_1.registerModel)('exports', allDbIds, 'exports');
27
24
  }
28
- const Project = (0, manager_1.getModel)('Project');
29
- const Export = (0, manager_1.getModel)('Export');
25
+ const Project = (0, manager_1.getModel)('projects');
26
+ const Export = (0, manager_1.getModel)('exports');
30
27
  router.get('/auth', async (req, res) => {
31
28
  try {
32
29
  const auth = await config.authProvider(req);
33
- res.status(200).json({ logged: true, ...auth });
30
+ if (!auth ||
31
+ !auth.userId ||
32
+ !auth.role) {
33
+ throw new Error('Invalid or missing authentication context');
34
+ }
35
+ return res.status(200).json({ logged: true, ...auth });
34
36
  }
35
37
  catch (err) {
36
- res.status(401).json({ logged: false });
38
+ return res.status(401).json({ logged: false });
37
39
  }
38
40
  });
39
41
  router.get('/databases', async (req, res) => {
40
42
  try {
41
43
  const auth = await config.authProvider(req);
42
- if (!auth) {
44
+ if (!auth ||
45
+ !auth.userId ||
46
+ !auth.role) {
43
47
  return res.status(401).json({ error: 'Unauthorized' });
44
48
  }
45
49
  const connectedDbIds = (0, connectionManager_1.getConnectedIds)();
@@ -55,6 +59,11 @@ function createStreamByRouter(config) {
55
59
  router.get('/upload-project-image-url/:id', async (req, res) => {
56
60
  try {
57
61
  const auth = await config.authProvider(req);
62
+ if (!auth ||
63
+ !auth.userId ||
64
+ !auth.role) {
65
+ return res.status(401).json({ error: 'Unauthorized' });
66
+ }
58
67
  if (auth.role !== 'admin' && auth.role !== 'editor') {
59
68
  return res.status(403).json({ error: 'Permission denied' });
60
69
  }
@@ -72,6 +81,11 @@ function createStreamByRouter(config) {
72
81
  router.delete('/delete-project-image-url/:id', async (req, res) => {
73
82
  try {
74
83
  const auth = await config.authProvider(req);
84
+ if (!auth ||
85
+ !auth.userId ||
86
+ !auth.role) {
87
+ return res.status(401).json({ error: 'Unauthorized' });
88
+ }
75
89
  if (auth.role !== 'admin' && auth.role !== 'editor') {
76
90
  return res.status(403).json({ error: 'Permission denied' });
77
91
  }
@@ -90,6 +104,11 @@ function createStreamByRouter(config) {
90
104
  router.get('/files', async (req, res) => {
91
105
  try {
92
106
  const auth = await config.authProvider(req);
107
+ if (!auth ||
108
+ !auth.userId ||
109
+ !auth.role) {
110
+ return res.status(401).json({ error: 'Unauthorized' });
111
+ }
93
112
  const projectId = (req.query.projectId || req.headers['x-project-id']);
94
113
  if (!projectId) {
95
114
  return res.status(403).json({ error: 'Unauthorized or missing projectId' });
@@ -104,8 +123,26 @@ function createStreamByRouter(config) {
104
123
  router.get('/projects', async (req, res) => {
105
124
  try {
106
125
  const auth = await config.authProvider(req);
107
- const archived = req.query.archived ? String(req.query.archived).toLowerCase() === 'true' : undefined;
108
- const projects = (await Project.find({ members: { $elemMatch: { userId: auth.userId } }, archived })).map(project => {
126
+ if (!auth ||
127
+ !auth.userId ||
128
+ !auth.role) {
129
+ return res.status(401).json({ error: 'Unauthorized' });
130
+ }
131
+ const archivedQuery = req.query.archived;
132
+ const filterArchived = archivedQuery !== undefined ? String(archivedQuery).toLowerCase() === 'true' : undefined;
133
+ const allProjects = await Project.find({}); // Fetch all projects
134
+ const projects = allProjects
135
+ .filter(project => {
136
+ const isMember = project.members?.some((m) => m.userId?.toString() === auth.userId?.toString());
137
+ if (!isMember)
138
+ return false;
139
+ if (filterArchived !== undefined) {
140
+ const currentUserMember = project.members?.find((member) => member.userId === auth.userId);
141
+ return currentUserMember ? (currentUserMember.archived || false) === filterArchived : false;
142
+ }
143
+ return true;
144
+ })
145
+ .map(project => {
109
146
  const currentUserMember = project.members?.find((member) => member.userId === auth.userId);
110
147
  return {
111
148
  id: project._id || project.id,
@@ -118,12 +155,18 @@ function createStreamByRouter(config) {
118
155
  res.json({ projects });
119
156
  }
120
157
  catch (err) {
158
+ console.error('Error in /projects endpoint:', err);
121
159
  res.status(500).json({ error: 'Failed to list projects', details: err });
122
160
  }
123
161
  });
124
162
  router.post('/projects/create', async (req, res) => {
125
163
  try {
126
164
  const auth = await config.authProvider(req);
165
+ if (!auth ||
166
+ !auth.userId ||
167
+ !auth.role) {
168
+ return res.status(401).json({ error: 'Unauthorized' });
169
+ }
127
170
  if (auth.role !== 'admin' && auth.role !== 'editor') {
128
171
  return res.status(403).json({ error: 'Permission denied' });
129
172
  }
@@ -143,6 +186,11 @@ function createStreamByRouter(config) {
143
186
  router.get('/projects/:id', async (req, res) => {
144
187
  try {
145
188
  const auth = await config.authProvider(req);
189
+ if (!auth ||
190
+ !auth.userId ||
191
+ !auth.role) {
192
+ return res.status(401).json({ error: 'Unauthorized' });
193
+ }
146
194
  const projectId = req.params.id;
147
195
  const project = await Project.findOne({ _id: projectId });
148
196
  if (!project) {
@@ -160,6 +208,11 @@ function createStreamByRouter(config) {
160
208
  router.patch('/projects/:id', async (req, res) => {
161
209
  try {
162
210
  const auth = await config.authProvider(req);
211
+ if (!auth ||
212
+ !auth.userId ||
213
+ !auth.role) {
214
+ return res.status(401).json({ error: 'Unauthorized' });
215
+ }
163
216
  if (auth.role !== 'admin' && auth.role !== 'editor') {
164
217
  return res.status(403).json({ error: 'Permission denied' });
165
218
  }
@@ -188,6 +241,11 @@ function createStreamByRouter(config) {
188
241
  router.delete('/projects/:id', async (req, res) => {
189
242
  try {
190
243
  const auth = await config.authProvider(req);
244
+ if (!auth ||
245
+ !auth.userId ||
246
+ !auth.role) {
247
+ return res.status(401).json({ error: 'Unauthorized' });
248
+ }
191
249
  const projectId = req.params.id;
192
250
  const project = await Project.findOne({ _id: projectId });
193
251
  if (!project) {
@@ -206,6 +264,11 @@ function createStreamByRouter(config) {
206
264
  router.patch('/projects/:id/archive', async (req, res) => {
207
265
  try {
208
266
  const auth = await config.authProvider(req);
267
+ if (!auth ||
268
+ !auth.userId ||
269
+ !auth.role) {
270
+ return res.status(401).json({ error: 'Unauthorized' });
271
+ }
209
272
  const projectId = req.params.id;
210
273
  const project = await Project.findOne({ _id: projectId });
211
274
  if (!project || !isProjectMember(project, auth.userId)) {
@@ -234,6 +297,11 @@ function createStreamByRouter(config) {
234
297
  router.patch('/projects/:id/unarchive', async (req, res) => {
235
298
  try {
236
299
  const auth = await config.authProvider(req);
300
+ if (!auth ||
301
+ !auth.userId ||
302
+ !auth.role) {
303
+ return res.status(401).json({ error: 'Unauthorized' });
304
+ }
237
305
  const projectId = req.params.id;
238
306
  const project = await Project.findOne({ _id: projectId });
239
307
  if (!project || !isProjectMember(project, auth.userId)) {
@@ -262,6 +330,11 @@ function createStreamByRouter(config) {
262
330
  router.get('/projects/:id/exports/:export_id', async (req, res) => {
263
331
  try {
264
332
  const auth = await config.authProvider(req);
333
+ if (!auth ||
334
+ !auth.userId ||
335
+ !auth.role) {
336
+ return res.status(401).json({ error: 'Unauthorized' });
337
+ }
265
338
  const projectId = req.params.id;
266
339
  const exportId = req.params.export_id;
267
340
  const project = await Project.findOne({ _id: projectId });
@@ -281,6 +354,11 @@ function createStreamByRouter(config) {
281
354
  router.post('/projects/:id/exports', async (req, res) => {
282
355
  try {
283
356
  const auth = await config.authProvider(req);
357
+ if (!auth ||
358
+ !auth.userId ||
359
+ !auth.role) {
360
+ return res.status(401).json({ error: 'Unauthorized' });
361
+ }
284
362
  const projectId = req.params.id;
285
363
  const { name, description, collectionName } = req.body;
286
364
  if (!name || !collectionName) {
@@ -296,7 +374,6 @@ function createStreamByRouter(config) {
296
374
  collectionName,
297
375
  projectId
298
376
  });
299
- await Project.update({ _id: projectId }, { $push: { exports: newExport._id } });
300
377
  res.status(201).json({ data: { ...newExport, id: newExport._id || newExport.id, _id: undefined } });
301
378
  }
302
379
  catch (err) {
@@ -306,6 +383,11 @@ function createStreamByRouter(config) {
306
383
  router.get('/projects/:id/members', async (req, res) => {
307
384
  try {
308
385
  const auth = await config.authProvider(req);
386
+ if (!auth ||
387
+ !auth.userId ||
388
+ !auth.role) {
389
+ return res.status(401).json({ error: 'Unauthorized' });
390
+ }
309
391
  const projectId = req.params.id;
310
392
  const project = await Project.findOne({ _id: projectId });
311
393
  if (!project) {