streamby-core 0.27.3 → 0.28.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.
@@ -1,12 +1,7 @@
1
1
  import { MongoClient, Document } from 'mongodb';
2
- import { FieldDefinition, NodeSchema } from '../../types';
2
+ import { NodeSchema } from '../../types';
3
3
  export declare const ensureCollectionsExist: (client: MongoClient) => Promise<void>;
4
- export declare const createNoSQLExportCollection: (connection: MongoClient, projectId: string, exportName: string, fields: FieldDefinition[]) => Promise<{
5
- collectionName: string;
6
- exportId: string;
7
- }>;
8
- export declare const createNoSQLRawExportCollection: (connection: MongoClient, projectId: string, exportName: string, method: string, nodeSchema?: NodeSchema) => Promise<{
9
- collectionName: string;
4
+ export declare const createNoSQLExportCollection: (connection: MongoClient, projectId: string, exportName: string, method: string, nodeSchema?: NodeSchema) => Promise<{
10
5
  exportId: string;
11
6
  }>;
12
7
  export declare const nosqlAdapter: {
@@ -1,45 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.nosqlAdapter = exports.createNoSQLRawExportCollection = exports.createNoSQLExportCollection = exports.ensureCollectionsExist = void 0;
3
+ exports.nosqlAdapter = exports.createNoSQLExportCollection = exports.ensureCollectionsExist = void 0;
4
4
  const mongodb_1 = require("mongodb");
5
5
  const ensureCollectionsExist = async (client) => {
6
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
7
+ await db.collection('projects').findOne({});
11
8
  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
9
+ await db.collection('exports').findOne({});
16
10
  console.log('✅ "exports" collection ensured to exist.');
11
+ await db.collection('records').findOne({});
12
+ console.log('✅ "records" collection ensured to exist.');
13
+ await db.collection('_tables').findOne({});
14
+ console.log('✅ "_tables" collection ensured to exist.');
17
15
  };
18
16
  exports.ensureCollectionsExist = ensureCollectionsExist;
19
- const createNoSQLExportCollection = async (connection, projectId, exportName, fields) => {
17
+ const createNoSQLExportCollection = async (connection, projectId, exportName, method, nodeSchema) => {
20
18
  const db = connection.db();
21
- const slug = exportName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
22
- const collectionName = `export_${projectId}_${slug}`;
23
- // Create the collection implicitly by inserting the metadata document
24
- const metadataDocument = {
25
- __metadata: {
26
- fields,
27
- createdAt: new Date(),
28
- updatedAt: new Date(),
29
- },
30
- };
31
- await db.collection(collectionName).insertOne(metadataDocument);
32
- console.log(`✅ Collection '${collectionName}' created with metadata.`);
33
- return { collectionName, exportId: collectionName };
19
+ const result = await db.collection('exports').insertOne({
20
+ projectId,
21
+ name: exportName,
22
+ method,
23
+ nodeSchema,
24
+ createdAt: new Date(),
25
+ updatedAt: new Date(),
26
+ });
27
+ return { exportId: result.insertedId.toHexString() };
34
28
  };
35
29
  exports.createNoSQLExportCollection = createNoSQLExportCollection;
36
- const createNoSQLRawExportCollection = async (connection, projectId, exportName, method, nodeSchema) => {
37
- const db = connection.db();
38
- const collectionName = projectId;
39
- const result = await db.collection(collectionName).insertOne({ nodeSchema, name: exportName, method, createdAt: new Date(), updatedAt: new Date() });
40
- return { collectionName, exportId: result.insertedId.toHexString() };
41
- };
42
- exports.createNoSQLRawExportCollection = createNoSQLRawExportCollection;
43
30
  exports.nosqlAdapter = {
44
31
  find: async (connection, tableName, filter) => {
45
32
  const db = connection.db();
@@ -1,11 +1,5 @@
1
1
  import { Pool } from 'pg';
2
- import { FieldDefinition } from '../../types';
3
- export declare const createSQLExportTable: (connection: Pool, projectId: string, exportName: string, fields: FieldDefinition[]) => Promise<{
4
- collectionName: string;
5
- exportId: string;
6
- }>;
7
- export declare const createSQLRawExportTable: (connection: Pool, projectId: string, exportName: string, nodeSchema?: any) => Promise<{
8
- collectionName: string;
2
+ export declare const createSQLExportTable: (connection: Pool, projectId: string, exportName: string, nodeSchema?: any) => Promise<{
9
3
  exportId: string;
10
4
  }>;
11
5
  export declare const sqlAdapter: {
@@ -1,51 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sqlAdapter = exports.createSQLRawExportTable = exports.createSQLExportTable = void 0;
3
+ exports.sqlAdapter = exports.createSQLExportTable = void 0;
4
4
  const crypto_1 = require("crypto");
5
- const createSQLExportTable = async (connection, projectId, exportName, fields) => {
6
- const slug = exportName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
7
- const tableName = `export_${projectId}_${slug}`;
8
- const columns = fields.map(field => `"${field.name}" ${field.type}`).join(',');
9
- const createTableQuery = `
10
- CREATE TABLE IF NOT EXISTS "${tableName}" (
11
- id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
12
- "projectId" UUID NOT NULL,
13
- __metadata JSONB NOT NULL,
14
- ${columns ? `, ${columns}` : ''}
15
- );
16
- `;
17
- await connection.query(createTableQuery);
18
- console.log(`✅ Table '${tableName}' created with metadata.`);
19
- const metadata = {
20
- fields,
21
- createdAt: new Date(),
22
- updatedAt: new Date(),
23
- };
24
- // Insert metadata as the first row, or a dedicated metadata row
25
- // For simplicity, we'll just create the table with the metadata column.
26
- // Actual metadata insertion for validation would happen on data inserts.
27
- return { collectionName: tableName, exportId: tableName };
28
- };
29
- exports.createSQLExportTable = createSQLExportTable;
30
- const createSQLRawExportTable = async (connection, projectId, exportName, nodeSchema) => {
31
- const tableName = projectId;
5
+ function serializeForPg(v) {
6
+ if (Array.isArray(v) || (v !== null && typeof v === 'object' && !(v instanceof Date))) {
7
+ return JSON.stringify(v);
8
+ }
9
+ return v;
10
+ }
11
+ const createSQLExportTable = async (connection, projectId, exportName, nodeSchema) => {
32
12
  const exportId = (0, crypto_1.randomUUID)();
33
- const createTableQuery = `
34
- CREATE TABLE IF NOT EXISTS "${tableName}" (
35
- id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
36
- node_schema JSONB,
37
- name TEXT,
38
- method TEXT,
39
- created_at TIMESTAMPTZ DEFAULT NOW(),
40
- updated_at TIMESTAMPTZ DEFAULT NOW()
41
- );
42
- `;
43
- await connection.query(createTableQuery);
44
- await connection.query(`INSERT INTO "${tableName}" (id, node_schema, name, method) VALUES ($1, $2, $3, $4)`, [exportId, nodeSchema ? JSON.stringify(nodeSchema) : null, exportName, 'GET']);
45
- console.log(`✅ Raw table '${tableName}' created.`);
46
- return { collectionName: tableName, exportId };
13
+ await connection.query(`INSERT INTO "exports" (id, "projectId", node_schema, name, method, created_at, updated_at)
14
+ VALUES ($1, $2, $3, $4, 'GET', NOW(), NOW())`, [exportId, projectId, nodeSchema ? JSON.stringify(nodeSchema) : null, exportName]);
15
+ return { exportId };
47
16
  };
48
- exports.createSQLRawExportTable = createSQLRawExportTable;
17
+ exports.createSQLExportTable = createSQLExportTable;
49
18
  exports.sqlAdapter = {
50
19
  find: async (connection, tableName, filter, schema) => {
51
20
  const keys = Object.keys(filter);
@@ -69,7 +38,7 @@ exports.sqlAdapter = {
69
38
  },
70
39
  create: async (connection, tableName, data, schema) => {
71
40
  const keys = Object.keys(data).map(key => `"${key}"`).join(', ');
72
- const values = Object.values(data);
41
+ const values = Object.values(data).map(serializeForPg);
73
42
  const placeholders = values.map((_, i) => `$${i + 1}`).join(', ');
74
43
  const fullTableName = schema ? `"${schema}"."${tableName}"` : `"${tableName}"`;
75
44
  const result = await connection.query(`INSERT INTO ${fullTableName} (${keys}) VALUES (${placeholders}) RETURNING *`, values);
@@ -78,7 +47,7 @@ exports.sqlAdapter = {
78
47
  update: async (connection, tableName, filter, data, schema) => {
79
48
  const dataKeys = Object.keys(data);
80
49
  const filterKeys = Object.keys(filter);
81
- const values = [...Object.values(data), ...Object.values(filter)];
50
+ const values = [...Object.values(data).map(serializeForPg), ...Object.values(filter)];
82
51
  const setClause = dataKeys.map((key, i) => `"${key}" = $${i + 1}`).join(', ');
83
52
  const whereClause = filterKeys.map((key, i) => `"${key}" = $${dataKeys.length + i + 1}`).join(' AND ');
84
53
  const fullTableName = schema ? `"${schema}"."${tableName}"` : `"${tableName}"`;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { createStreamByRouter } from './middleware/createRouter';
2
2
  export { emitToUser } from './services/wsHub';
3
3
  export { createNotification } from './services/notification';
4
+ export type { UserPlan, UserSubscription } from './types';
@@ -23,6 +23,7 @@ const connection_1 = require("./routes/connection");
23
23
  const dbConnection_1 = require("./routes/dbConnection");
24
24
  const storageConnection_1 = require("./routes/storageConnection");
25
25
  const notification_1 = require("./routes/notification");
26
+ const subscription_1 = require("./routes/subscription");
26
27
  function createStreamByRouter(config) {
27
28
  const router = express_1.default.Router();
28
29
  if (config.encrypt)
@@ -42,6 +43,7 @@ function createStreamByRouter(config) {
42
43
  const mainDb = config.databases.find(db => db.main);
43
44
  if (mainDb) {
44
45
  (0, manager_1.registerModel)('users', [mainDb.id], 'users', 'accounts');
46
+ (0, manager_1.registerModel)('user_subscriptions', [mainDb.id], 'user_subscriptions', 'streamby');
45
47
  }
46
48
  }
47
49
  if (config.websocket?.server) {
@@ -50,6 +52,7 @@ function createStreamByRouter(config) {
50
52
  router.use((0, user_1.userRouter)(config));
51
53
  router.use((0, auth_2.authRouter)(config));
52
54
  router.use((0, auth_1.authenticate)(config));
55
+ router.use(subscription_1.ensureSubscription);
53
56
  router.use((0, export_1.exportRouter)(config));
54
57
  router.use((0, member_1.memberRouter)(config));
55
58
  router.use((0, storage_2.storageRouter)(config));
@@ -60,5 +63,6 @@ function createStreamByRouter(config) {
60
63
  router.use((0, dbConnection_1.dbConnectionRouter)(config));
61
64
  router.use((0, storageConnection_1.storageConnectionRouter)(config));
62
65
  router.use((0, notification_1.notificationRouter)(config));
66
+ router.use((0, subscription_1.subscriptionRouter)(config));
63
67
  return router;
64
68
  }
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getExportRoute = getExportRoute;
4
4
  function getExportRoute(req, res, next) {
5
- if (req.path.includes('/get-export/')) {
5
+ if (req.path.includes('/export/')) {
6
6
  return next();
7
7
  }
8
8
  return next();
@@ -84,12 +84,11 @@ function exportRouter(config) {
84
84
  };
85
85
  }
86
86
  else if (exportMetadata.type === 'json') {
87
- const rawData = await db.collection(exportMetadata.collectionName).findOne({ _id: new mongodb_1.ObjectId(exportId) });
87
+ const rawData = await db.collection('exports').findOne({ _id: new mongodb_1.ObjectId(exportId) });
88
88
  data = {
89
89
  json: rawData?.json,
90
90
  name: rawData?.name,
91
91
  method: rawData?.method,
92
- collectionName: rawData?.collectionName,
93
92
  createdAt: rawData?.createdAt,
94
93
  updatedAt: rawData?.updatedAt,
95
94
  type: exportMetadata.type,
@@ -98,7 +97,7 @@ function exportRouter(config) {
98
97
  };
99
98
  }
100
99
  else if (exportMetadata.type === 'externalApi') {
101
- const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
100
+ const ProjectModel = (0, manager_1.getModel)('projects');
102
101
  const currentProject = await ProjectModel.findOne({ _id: projectId });
103
102
  if (!currentProject) {
104
103
  return res.status(404).json({ message: 'Project not found.' });
@@ -144,14 +143,13 @@ function exportRouter(config) {
144
143
  };
145
144
  }
146
145
  else {
147
- const rawData = await db.collection(exportMetadata.collectionName).findOne({ _id: new mongodb_1.ObjectId(exportId) });
146
+ const rawData = await db.collection('exports').findOne({ _id: new mongodb_1.ObjectId(exportId) });
148
147
  data = {
149
148
  json: rawData?.json,
150
149
  name: rawData?.name,
151
150
  method: rawData?.method,
152
151
  createdAt: rawData?.createdAt,
153
152
  updatedAt: rawData?.updatedAt,
154
- collectionName: rawData?.collectionName,
155
153
  type: exportMetadata.type,
156
154
  credentialId: exportMetadata.credentialId,
157
155
  description: rawData?.description,
@@ -160,7 +158,33 @@ function exportRouter(config) {
160
158
  }
161
159
  }
162
160
  else if (project.dbType === 'sql') {
163
- // ... SQL implementation needed
161
+ const pool = connection.client;
162
+ if (exportMetadata.nodeSchema) {
163
+ data = {
164
+ name: exportMetadata.name,
165
+ description: exportMetadata.description,
166
+ nodeSchema: exportMetadata.nodeSchema,
167
+ useConnections: exportMetadata.useConnections,
168
+ useCredentials: exportMetadata.useCredentials,
169
+ type: exportMetadata.type,
170
+ };
171
+ }
172
+ else {
173
+ const result = await pool.query(`SELECT * FROM "exports" WHERE id = $1`, [exportId]);
174
+ const rawData = result.rows[0];
175
+ if (rawData) {
176
+ data = {
177
+ json: rawData.json,
178
+ name: rawData.name,
179
+ method: rawData.method,
180
+ createdAt: rawData.created_at,
181
+ updatedAt: rawData.updated_at,
182
+ type: exportMetadata.type,
183
+ fields: exportMetadata.fields,
184
+ description: rawData.description,
185
+ };
186
+ }
187
+ }
164
188
  }
165
189
  if (!data) {
166
190
  return res.status(404).json({ message: 'Export data not found' });
@@ -253,14 +277,14 @@ function exportRouter(config) {
253
277
  if (!exportMetadata) {
254
278
  return res.status(404).json({ message: 'Export not found in this project' });
255
279
  }
256
- await (0, export_1.deleteExport)(config, projectId, exportId, project.dbType, exportMetadata.name);
280
+ await (0, export_1.deleteExport)(config, projectId, exportId, project.dbType);
257
281
  res.status(200).json({ message: 'Export deleted successfully' });
258
282
  }
259
283
  catch (err) {
260
284
  res.status(500).json({ message: 'Failed to delete export', details: err.message });
261
285
  }
262
286
  });
263
- router.get('/:projectId/get-export/:exportName', async (req, res) => {
287
+ router.get('/:projectId/export/:exportName', async (req, res) => {
264
288
  try {
265
289
  const { projectId, exportName } = req.params;
266
290
  const project = await Project.findOne({ _id: projectId });
@@ -328,9 +352,8 @@ function exportRouter(config) {
328
352
  const connection = (0, connectionManager_1.getConnection)(targetDb.id);
329
353
  if (project.dbType === 'nosql') {
330
354
  const db = connection.client.db();
331
- const legacyCollection = exportMetadata.collectionName ?? projectId;
332
355
  if (exportMetadata.type === 'json') {
333
- const rawData = await db.collection(legacyCollection).findOne({ _id: new mongodb_1.ObjectId(exportMetadata.id.toString()) });
356
+ const rawData = await db.collection('exports').findOne({ _id: new mongodb_1.ObjectId(exportMetadata.id.toString()) });
334
357
  data = rawData ? rawData.json : null;
335
358
  }
336
359
  else if (exportMetadata.type === 'externalApi') {
@@ -197,6 +197,88 @@ function memberRouter(config) {
197
197
  res.status(500).json({ message: 'Failed to reject invitation', details: err.message });
198
198
  }
199
199
  });
200
+ router.post('/projects/:id/request-join', async (req, res) => {
201
+ try {
202
+ const auth = req.auth;
203
+ const projectId = req.params.id;
204
+ const project = await Project.findOne({ _id: projectId });
205
+ if (!project) {
206
+ return res.status(404).json({ message: 'Project not found' });
207
+ }
208
+ if (project.public === false) {
209
+ return res.status(403).json({ message: 'This project is not open for join requests' });
210
+ }
211
+ const alreadyMember = project.members?.some((m) => m.userId?.toString() === auth.userId?.toString());
212
+ if (alreadyMember) {
213
+ return res.status(400).json({ message: 'You are already a member or have a pending request' });
214
+ }
215
+ const User = (0, manager_1.getModel)('users');
216
+ const user = await User.findOne({ _id: auth.userId });
217
+ const username = user?.username || auth.username;
218
+ if (project.dbType === 'sql') {
219
+ const connection = getSqlConnection();
220
+ if (!connection) {
221
+ return res.status(503).json({ message: 'SQL connection not available' });
222
+ }
223
+ await sql_1.sqlAdapter.create(connection, 'project_members', {
224
+ projectId,
225
+ userId: auth.userId,
226
+ role: 'viewer',
227
+ archived: false,
228
+ status: 'pending',
229
+ invitedBy: auth.userId,
230
+ }, 'streamby');
231
+ }
232
+ else {
233
+ await Project.update({ _id: projectId }, {
234
+ $push: { members: { userId: auth.userId, username, role: 'viewer', archived: false, status: 'pending', invitedBy: auth.userId } },
235
+ });
236
+ }
237
+ const admins = (project.members || []).filter((m) => m.role === 'admin' && m.status === 'active');
238
+ await Promise.all(admins.map((admin) => (0, notification_1.createNotification)(admin.userId, 'join_request', `${username} has requested to join "${project.name}"`, { projectId, userId: auth.userId })));
239
+ res.status(201).json({ message: 'Join request sent successfully' });
240
+ }
241
+ catch (err) {
242
+ res.status(500).json({ message: 'Failed to send join request', details: err.message });
243
+ }
244
+ });
245
+ router.patch('/projects/:id/members/:userId/approve', async (req, res) => {
246
+ try {
247
+ const auth = req.auth;
248
+ const { id: projectId, userId: targetUserId } = req.params;
249
+ const project = await Project.findOne({ _id: projectId });
250
+ if (!project) {
251
+ return res.status(404).json({ message: 'Project not found' });
252
+ }
253
+ const requestingMember = project.members?.find((m) => m.userId?.toString() === auth.userId?.toString());
254
+ if (!requestingMember || requestingMember.status !== 'active' || requestingMember.role !== 'admin') {
255
+ return res.status(403).json({ message: 'Only project admins can approve requests' });
256
+ }
257
+ const targetMember = project.members?.find((m) => m.userId?.toString() === targetUserId?.toString());
258
+ if (!targetMember) {
259
+ return res.status(404).json({ message: 'Member not found in project' });
260
+ }
261
+ if (targetMember.status !== 'pending') {
262
+ return res.status(400).json({ message: 'No pending request for this user' });
263
+ }
264
+ if (project.dbType === 'sql') {
265
+ const connection = getSqlConnection();
266
+ if (!connection) {
267
+ return res.status(503).json({ message: 'SQL connection not available' });
268
+ }
269
+ await sql_1.sqlAdapter.update(connection, 'project_members', { projectId, userId: targetUserId }, { status: 'active' }, 'streamby');
270
+ }
271
+ else {
272
+ const updatedMembers = project.members.map((m) => m.userId?.toString() === targetUserId ? { ...m, status: 'active' } : m);
273
+ await Project.update({ _id: projectId }, { members: updatedMembers });
274
+ }
275
+ await (0, notification_1.createNotification)(targetUserId, 'join_approved', `Your request to join "${project.name}" has been approved`, { projectId });
276
+ res.status(200).json({ message: 'Join request approved' });
277
+ }
278
+ catch (err) {
279
+ res.status(500).json({ message: 'Failed to approve join request', details: err.message });
280
+ }
281
+ });
200
282
  router.delete('/projects/:id/members/:userId', async (req, res) => {
201
283
  try {
202
284
  const auth = req.auth;
@@ -44,13 +44,40 @@ function projectRouter(config) {
44
44
  res.status(500).json({ message: 'Failed to list projects', details: err });
45
45
  }
46
46
  });
47
+ router.get('/projects/explore', async (req, res) => {
48
+ try {
49
+ const auth = req.auth;
50
+ const allProjects = await Project.find({});
51
+ const result = allProjects
52
+ .filter((p) => p.public !== false)
53
+ .map((p) => ({
54
+ id: p._id || p.id,
55
+ name: p.name,
56
+ description: p.description || '',
57
+ image: p.image || '',
58
+ memberCount: (p.members || []).filter((m) => m.status === 'active').length,
59
+ isMember: (p.members || []).some((m) => m.userId?.toString() === auth.userId && m.status === 'active'),
60
+ hasPendingRequest: (p.members || []).some((m) => m.userId?.toString() === auth.userId && m.status === 'pending'),
61
+ }));
62
+ res.json({ projects: result });
63
+ }
64
+ catch (err) {
65
+ res.status(500).json({ message: 'Failed to explore projects', details: err.message });
66
+ }
67
+ });
47
68
  router.post('/projects/create', async (req, res) => {
48
69
  try {
49
70
  const auth = req.auth;
71
+ if (req.subscription === 'freemium') {
72
+ return res.status(403).json({ error: 'Freemium users cannot create projects' });
73
+ }
50
74
  if (auth.role !== 'admin' && auth.role !== 'editor') {
51
75
  return res.status(403).json({ message: 'Permission denied' });
52
76
  }
53
- const { name, description, image, allowedOrigin } = req.body;
77
+ const { name, description, image, allowedOrigin, public: isPublic = true } = req.body;
78
+ if (isPublic === false && req.subscription === 'freemium') {
79
+ return res.status(403).json({ error: 'Private projects require a subscriber plan' });
80
+ }
54
81
  const mainDb = config.databases?.find(db => db.main) ?? config.databases?.[0];
55
82
  if (!mainDb) {
56
83
  return res.status(500).json({ message: 'No database configured' });
@@ -67,6 +94,7 @@ function projectRouter(config) {
67
94
  description: description || '',
68
95
  image: image || '',
69
96
  allowedOrigin: allowedOrigin || [],
97
+ public: isPublic,
70
98
  members: [{ userId: auth.userId, username: user.username, role: "admin", status: "active", archived: false }],
71
99
  });
72
100
  const allProjects = await Project.find({});
@@ -0,0 +1,4 @@
1
+ import { Router, Request, Response, NextFunction } from 'express';
2
+ import { StreamByConfig } from '../../types';
3
+ export declare const ensureSubscription: (req: Request, res: Response, next: NextFunction) => Promise<void>;
4
+ export declare function subscriptionRouter(config: StreamByConfig): Router;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureSubscription = void 0;
4
+ exports.subscriptionRouter = subscriptionRouter;
5
+ const express_1 = require("express");
6
+ const manager_1 = require("../../models/manager");
7
+ const resolveSubscription = async (auth) => {
8
+ const Subscription = (0, manager_1.getModel)('user_subscriptions');
9
+ const existing = await Subscription.findOne({ user_id: auth.userId });
10
+ if (existing)
11
+ return existing.plan;
12
+ const plan = auth.role === 'admin' ? 'admin' : 'freemium';
13
+ await Subscription.create({ user_id: auth.userId, plan, dbType: 'sql' });
14
+ return plan;
15
+ };
16
+ const ensureSubscription = async (req, res, next) => {
17
+ try {
18
+ const auth = req.auth;
19
+ const plan = await resolveSubscription(auth);
20
+ req.subscription = plan;
21
+ next();
22
+ }
23
+ catch (err) {
24
+ res.status(403).json({ error: 'Unauthorized', details: err.message });
25
+ }
26
+ };
27
+ exports.ensureSubscription = ensureSubscription;
28
+ function subscriptionRouter(config) {
29
+ const router = (0, express_1.Router)();
30
+ router.get('/user/subscription', async (req, res) => {
31
+ res.json({ subscription: req.subscription });
32
+ });
33
+ return router;
34
+ }
@@ -129,6 +129,11 @@ class Model {
129
129
  archived: member.archived,
130
130
  }));
131
131
  }
132
+ // Track which connection found this record so update() routes correctly
133
+ try {
134
+ Object.defineProperty(transformedResult, '__foundByConnectionId', { value: connectionId, enumerable: false, writable: true });
135
+ }
136
+ catch { }
132
137
  return transformedResult;
133
138
  }
134
139
  }
@@ -144,8 +149,13 @@ class Model {
144
149
  }
145
150
  }
146
151
  const result = await nosql_1.nosqlAdapter.findOne(connection, this.tableName, processedFilter);
147
- if (result)
152
+ if (result) {
153
+ try {
154
+ Object.defineProperty(result, '__foundByConnectionId', { value: connectionId, enumerable: false, writable: true });
155
+ }
156
+ catch { }
148
157
  return result;
158
+ }
149
159
  }
150
160
  }
151
161
  return null;
@@ -170,8 +180,10 @@ class Model {
170
180
  if (this.tableName === 'projects' && key === 'members') {
171
181
  membersToInsert = data[key];
172
182
  }
173
- else if (this.tableName === 'projects' && key.toLowerCase() === 'dbtype') {
174
- dataToInsert["dbType"] = data[key];
183
+ else if (key.toLowerCase() === 'dbtype') {
184
+ if (this.tableName === 'projects')
185
+ dataToInsert["dbType"] = data[key];
186
+ // else: routing hint only — never a real column
175
187
  }
176
188
  else {
177
189
  dataToInsert[key] = data[key];
@@ -219,14 +231,17 @@ class Model {
219
231
  if (!existingProject) {
220
232
  return null; // Project not found
221
233
  }
222
- const targetDbType = existingProject.dbType; // Get the actual dbType of the project
223
- // Find the connection that matches the targetDbType (only among active connections)
224
234
  const activeConnectionIds = this.connectionIds.filter(id => (0, connectionManager_1.getConnectedIds)().includes(id));
225
- const clientEntry = activeConnectionIds
226
- .map(id => (0, connectionManager_1.getConnection)(id))
227
- .find(entry => entry.type === targetDbType);
235
+ // Use the connection where findOne actually found the record, not project.dbType.
236
+ // project.dbType is the DATA db type (where the project's collections live), not the
237
+ // STORAGE db type (where the project document itself lives). Using dbType here would
238
+ // route SQL-stored projects with dbType:'nosql' to MongoDB, causing update failures.
239
+ const storageConnectionId = existingProject.__foundByConnectionId;
240
+ const clientEntry = (storageConnectionId && activeConnectionIds.includes(storageConnectionId))
241
+ ? (0, connectionManager_1.getConnection)(storageConnectionId)
242
+ : activeConnectionIds.map(id => (0, connectionManager_1.getConnection)(id)).find(entry => entry.type === existingProject.dbType);
228
243
  if (!clientEntry) {
229
- throw new Error(`No active connection found for database type: ${targetDbType}`);
244
+ throw new Error(`No active connection found for database type: ${existingProject.dbType}`);
230
245
  }
231
246
  const connection = clientEntry.client;
232
247
  const dbType = clientEntry.type; // This will be the targetDbType
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.authenticate = void 0;
4
4
  exports.checkRole = checkRole;
5
5
  const authenticate = (config) => async (req, res, next) => {
6
- if (req.path.includes('/get-export/')) {
6
+ if (req.path.includes('/export/')) {
7
7
  return next();
8
8
  }
9
9
  try {
@@ -10,7 +10,7 @@ async function addCredential(config, projectId, newCredential) {
10
10
  if (!(0, encryption_1.isEncryptionKeySet)()) {
11
11
  throw new Error('Encryption key is not set. Cannot add credentials.');
12
12
  }
13
- const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
13
+ const ProjectModel = (0, manager_1.getModel)('projects');
14
14
  const project = await ProjectModel.findOne({ _id: projectId });
15
15
  if (!project) {
16
16
  throw new Error('Project not found.');
@@ -31,7 +31,7 @@ async function updateCredential(config, projectId, credentialId, updates) {
31
31
  if (!(0, encryption_1.isEncryptionKeySet)()) {
32
32
  throw new Error('Encryption key is not set. Cannot update credentials.');
33
33
  }
34
- const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
34
+ const ProjectModel = (0, manager_1.getModel)('projects');
35
35
  const project = await ProjectModel.findOne({ _id: projectId });
36
36
  if (!project) {
37
37
  throw new Error('Project not found.');
@@ -57,7 +57,7 @@ async function updateCredential(config, projectId, credentialId, updates) {
57
57
  return updatedProject;
58
58
  }
59
59
  async function deleteCredential(config, projectId, credentialId) {
60
- const ProjectModel = (0, manager_1.getModel)('projects', 'nosql');
60
+ const ProjectModel = (0, manager_1.getModel)('projects');
61
61
  const project = await ProjectModel.findOne({ _id: projectId });
62
62
  if (!project) {
63
63
  throw new Error('Project not found.');
@@ -172,10 +172,16 @@ async function deleteRecord(connectionString, dbType, tableName, recordId) {
172
172
  }
173
173
  // ─── Internal (pool-based) variants ──────────────────────────────────────────
174
174
  // These operate on already-connected Pool / MongoClient from connectionManager.
175
+ //
176
+ // nosql storage pattern: all user records go into a single 'records' collection
177
+ // with _projectId and _tableName metadata fields. Table membership is tracked in
178
+ // a separate '_tables' collection. SQL keeps the legacy db_{projectId}_{tableName}
179
+ // table-per-collection pattern which is appropriate for relational databases.
175
180
  function quoteSqlTable(tableName) {
176
181
  const parts = tableName.split('.');
177
182
  return parts.length === 2 ? `"${parts[0]}"."${parts[1]}"` : `"${tableName}"`;
178
183
  }
184
+ const RECORD_META_PROJECTION = { _projectId: 0, _tableName: 0 };
179
185
  async function listTablesInternal(client, dbType, projectId) {
180
186
  const prefix = projectId ? `db_${projectId}_` : null;
181
187
  if (dbType === 'sql') {
@@ -190,40 +196,54 @@ async function listTablesInternal(client, dbType, projectId) {
190
196
  return prefix ? full.slice(prefix.length) : full;
191
197
  });
192
198
  }
193
- const cols = await client.db().listCollections().toArray();
194
- const names = cols.map(c => c.name).sort();
195
- if (!prefix)
196
- return names;
197
- return names.filter(n => n.startsWith(prefix)).map(n => n.slice(prefix.length));
199
+ const db = client.db();
200
+ if (!projectId) {
201
+ const cols = await db.listCollections().toArray();
202
+ return cols.map(c => c.name).sort();
203
+ }
204
+ const tables = await db.collection('_tables').find({ _projectId: projectId }).toArray();
205
+ return tables.map((t) => t.tableName).sort();
198
206
  }
199
207
  async function queryRecordsInternal(client, dbType, tableName, limit = 50, offset = 0, projectId) {
200
- const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
201
208
  if (dbType === 'sql') {
209
+ const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
202
210
  const result = await client.query(`SELECT * FROM ${quoteSqlTable(fullName)} LIMIT $1 OFFSET $2`, [limit, offset]);
203
211
  return result.rows;
204
212
  }
205
- return client.db().collection(fullName).find().limit(limit).skip(offset).toArray();
213
+ const db = client.db();
214
+ const filter = {};
215
+ if (projectId)
216
+ filter._projectId = projectId;
217
+ if (tableName)
218
+ filter._tableName = tableName;
219
+ return db.collection('records').find(filter, { projection: RECORD_META_PROJECTION }).limit(limit).skip(offset).toArray();
206
220
  }
207
221
  async function queryRecordByIdInternal(client, dbType, tableName, recordId, projectId) {
208
- const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
209
222
  if (dbType === 'sql') {
223
+ const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
210
224
  const result = await client.query(`SELECT * FROM ${quoteSqlTable(fullName)} WHERE id = $1 LIMIT 1`, [recordId]);
211
225
  return result.rows[0] ?? null;
212
226
  }
213
227
  const db = client.db();
214
- let doc = await db.collection(fullName).findOne({ _id: recordId });
228
+ const meta = {};
229
+ if (projectId)
230
+ meta._projectId = projectId;
231
+ if (tableName)
232
+ meta._tableName = tableName;
233
+ const opts = { projection: RECORD_META_PROJECTION };
234
+ let doc = await db.collection('records').findOne({ ...meta, _id: recordId }, opts);
215
235
  if (!doc) {
216
236
  try {
217
237
  const { ObjectId } = await Promise.resolve().then(() => __importStar(require('mongodb')));
218
- doc = await db.collection(fullName).findOne({ _id: new ObjectId(recordId) });
238
+ doc = await db.collection('records').findOne({ ...meta, _id: new ObjectId(recordId) }, opts);
219
239
  }
220
240
  catch { /* invalid ObjectId format — not found */ }
221
241
  }
222
242
  return doc;
223
243
  }
224
244
  async function createTableOrCollectionInternal(client, dbType, schema, projectId) {
225
- const fullName = projectId ? `db_${projectId}_${schema.tableName}` : schema.tableName;
226
245
  if (dbType === 'sql') {
246
+ const fullName = projectId ? `db_${projectId}_${schema.tableName}` : schema.tableName;
227
247
  const columnDdl = schema.columns.map(col => {
228
248
  const nullable = col.nullable === false ? 'NOT NULL' : '';
229
249
  const pk = col.primaryKey ? 'PRIMARY KEY' : '';
@@ -232,11 +252,16 @@ async function createTableOrCollectionInternal(client, dbType, schema, projectId
232
252
  await client.query(`CREATE TABLE IF NOT EXISTS ${quoteSqlTable(fullName)} (${columnDdl})`);
233
253
  return;
234
254
  }
235
- await client.db().createCollection(fullName);
255
+ const db = client.db();
256
+ await db.collection('_tables').insertOne({
257
+ _projectId: projectId ?? null,
258
+ tableName: schema.tableName,
259
+ createdAt: new Date(),
260
+ });
236
261
  }
237
262
  async function insertRecordInternal(client, dbType, tableName, record, projectId) {
238
- const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
239
263
  if (dbType === 'sql') {
264
+ const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
240
265
  const keys = Object.keys(record);
241
266
  const values = Object.values(record);
242
267
  const cols = keys.map(k => `"${k}"`).join(', ');
@@ -244,12 +269,14 @@ async function insertRecordInternal(client, dbType, tableName, record, projectId
244
269
  const result = await client.query(`INSERT INTO ${quoteSqlTable(fullName)} (${cols}) VALUES (${placeholders}) RETURNING *`, values);
245
270
  return result.rows[0];
246
271
  }
247
- const result = await client.db().collection(fullName).insertOne(record);
272
+ const db = client.db();
273
+ const doc = { _projectId: projectId ?? null, _tableName: tableName, ...record };
274
+ const result = await db.collection('records').insertOne(doc);
248
275
  return { ...record, _id: result.insertedId };
249
276
  }
250
277
  async function updateRecordInternal(client, dbType, tableName, recordId, updates, projectId) {
251
- const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
252
278
  if (dbType === 'sql') {
279
+ const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
253
280
  const keys = Object.keys(updates).filter(k => k !== 'id');
254
281
  if (!keys.length)
255
282
  return null;
@@ -258,31 +285,41 @@ async function updateRecordInternal(client, dbType, tableName, recordId, updates
258
285
  return result.rows[0] ?? null;
259
286
  }
260
287
  const { ObjectId } = await Promise.resolve().then(() => __importStar(require('mongodb')));
261
- const { _id, ...fields } = updates;
262
- let filter;
288
+ const { _id, _projectId: _p, _tableName: _t, ...fields } = updates;
289
+ const meta = {};
290
+ if (projectId)
291
+ meta._projectId = projectId;
292
+ if (tableName)
293
+ meta._tableName = tableName;
294
+ let idFilter;
263
295
  try {
264
- filter = { _id: new ObjectId(recordId) };
296
+ idFilter = new ObjectId(recordId);
265
297
  }
266
298
  catch {
267
- filter = { _id: recordId };
299
+ idFilter = recordId;
268
300
  }
269
- return client.db().collection(fullName).findOneAndUpdate(filter, { $set: fields }, { returnDocument: 'after' });
301
+ return client.db().collection('records').findOneAndUpdate({ ...meta, _id: idFilter }, { $set: fields }, { returnDocument: 'after', projection: RECORD_META_PROJECTION });
270
302
  }
271
303
  async function deleteRecordInternal(client, dbType, tableName, recordId, projectId) {
272
- const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
273
304
  if (dbType === 'sql') {
305
+ const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
274
306
  const result = await client.query(`DELETE FROM ${quoteSqlTable(fullName)} WHERE id = $1`, [recordId]);
275
307
  return (result.rowCount ?? 0) > 0;
276
308
  }
277
309
  const { ObjectId } = await Promise.resolve().then(() => __importStar(require('mongodb')));
278
- let filter;
310
+ const meta = {};
311
+ if (projectId)
312
+ meta._projectId = projectId;
313
+ if (tableName)
314
+ meta._tableName = tableName;
315
+ let idFilter;
279
316
  try {
280
- filter = { _id: new ObjectId(recordId) };
317
+ idFilter = new ObjectId(recordId);
281
318
  }
282
319
  catch {
283
- filter = { _id: recordId };
320
+ idFilter = recordId;
284
321
  }
285
- const result = await client.db().collection(fullName).deleteOne(filter);
322
+ const result = await client.db().collection('records').deleteOne({ ...meta, _id: idFilter });
286
323
  return result.deletedCount > 0;
287
324
  }
288
325
  async function deleteTableOrCollection(connectionString, dbType, tableName) {
@@ -295,10 +332,17 @@ async function deleteTableOrCollection(connectionString, dbType, tableName) {
295
332
  });
296
333
  }
297
334
  async function deleteTableOrCollectionInternal(client, dbType, tableName, projectId) {
298
- const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
299
335
  if (dbType === 'sql') {
336
+ const fullName = projectId ? `db_${projectId}_${tableName}` : tableName;
300
337
  await client.query(`DROP TABLE IF EXISTS ${quoteSqlTable(fullName)}`);
301
338
  return;
302
339
  }
303
- await client.db().dropCollection(fullName);
340
+ const db = client.db();
341
+ const meta = {};
342
+ if (projectId)
343
+ meta._projectId = projectId;
344
+ if (tableName)
345
+ meta._tableName = tableName;
346
+ await db.collection('records').deleteMany(meta);
347
+ await db.collection('_tables').deleteOne({ _projectId: projectId ?? null, tableName });
304
348
  }
@@ -5,7 +5,7 @@ interface ExportResult {
5
5
  }
6
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[], devMode?: boolean, devPorts?: number[], nodeSchema?: NodeSchema, useConnections?: boolean, useCredentials?: boolean): Promise<ExportResult>;
8
- export declare function deleteExport(config: StreamByConfig, projectId: string, exportId: string, dbType: DatabaseType, exportName: string): Promise<{
8
+ export declare function deleteExport(config: StreamByConfig, projectId: string, exportId: string, dbType: DatabaseType): Promise<{
9
9
  message: string;
10
10
  }>;
11
11
  export {};
@@ -19,25 +19,20 @@ async function createExport(config, projectId, description, exportName, dbType,
19
19
  const connection = (0, connectionManager_1.getConnection)(targetDb.id);
20
20
  const resolvedDbType = targetDb.type;
21
21
  let exportId;
22
- let collectionName;
23
22
  if (resolvedDbType === 'nosql') {
24
- const result = await (0, nosql_1.createNoSQLRawExportCollection)(connection.client, projectId, exportName, 'GET', nodeSchema);
23
+ const result = await (0, nosql_1.createNoSQLExportCollection)(connection.client, projectId, exportName, 'GET', nodeSchema);
25
24
  exportId = result.exportId;
26
- collectionName = result.collectionName;
27
25
  }
28
26
  else if (resolvedDbType === 'sql') {
29
- const result = await (0, sql_1.createSQLRawExportTable)(connection.client, projectId, exportName, nodeSchema);
27
+ const result = await (0, sql_1.createSQLExportTable)(connection.client, projectId, exportName, nodeSchema);
30
28
  exportId = result.exportId;
31
29
  }
32
30
  else {
33
31
  throw new Error('Unsupported database type');
34
32
  }
35
- // Route the project document update to the correct DB based on where the project lives
36
- const Project = (0, manager_1.getModel)('projects');
37
- const project = await Project.findOne({ _id: projectId });
38
- const isSqlProject = project?.dbType === 'sql';
33
+ const now = new Date();
39
34
  const exportEntry = {
40
- id: isSqlProject ? exportId : new mongodb_1.ObjectId(exportId),
35
+ id: exportId, // Always a plain string; works for both UUID (SQL export) and ObjectId hex (nosql export)
41
36
  name: exportName,
42
37
  type: exportType,
43
38
  method: 'GET',
@@ -48,9 +43,10 @@ async function createExport(config, projectId, description, exportName, dbType,
48
43
  useCredentials,
49
44
  description,
50
45
  storageDbId: targetDb.id,
51
- collectionName,
46
+ createdAt: now,
47
+ updatedAt: now,
52
48
  };
53
- const ProjectModel = isSqlProject ? (0, manager_1.getModel)('projects', 'sql') : (0, manager_1.getModel)('projects', 'nosql');
49
+ const ProjectModel = (0, manager_1.getModel)('projects');
54
50
  const updated = await ProjectModel.update({ _id: projectId }, { $push: { exports: exportEntry } });
55
51
  if (!updated) {
56
52
  throw new Error(`Failed to save export entry to project ${projectId}. The project may not exist or the database update failed.`);
@@ -75,7 +71,7 @@ async function updateExport(config, projectId, exportId, description, exportName
75
71
  const connection = (0, connectionManager_1.getConnection)(targetDb.id);
76
72
  if (targetDb.type === 'nosql') {
77
73
  const db = connection.client.db();
78
- await db.collection(projectId).updateOne({ _id: new mongodb_1.ObjectId(exportId) }, { $set: { nodeSchema, description, updatedAt: new Date() } });
74
+ await db.collection('exports').updateOne({ _id: new mongodb_1.ObjectId(exportId) }, { $set: { nodeSchema, description, updatedAt: new Date() } });
79
75
  }
80
76
  // SQL raw export table update would go here if needed in future
81
77
  // Update the export entry in the project document
@@ -89,12 +85,12 @@ async function updateExport(config, projectId, exportId, description, exportName
89
85
  await SqlProject.update({ _id: projectId }, { exports: updatedExports });
90
86
  }
91
87
  else {
92
- const NoSQLProject = (0, manager_1.getModel)('projects', 'nosql');
88
+ const NoSQLProject = (0, manager_1.getModel)('projects');
93
89
  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.$.devMode': devMode, 'exports.$.devPorts': devPorts, 'exports.$.nodeSchema': nodeSchema, 'exports.$.useConnections': useConnections, 'exports.$.useCredentials': useCredentials, 'exports.$.description': description } });
94
90
  }
95
91
  return { exportId, message: `${exportType} export updated successfully` };
96
92
  }
97
- async function deleteExport(config, projectId, exportId, dbType, exportName) {
93
+ async function deleteExport(config, projectId, exportId, dbType) {
98
94
  // Resolve the project to find where its raw export data lives
99
95
  const Project = (0, manager_1.getModel)('projects');
100
96
  const project = await Project.findOne({ _id: projectId });
@@ -111,15 +107,15 @@ async function deleteExport(config, projectId, exportId, dbType, exportName) {
111
107
  const connection = (0, connectionManager_1.getConnection)(targetDb.id);
112
108
  if (targetDb.type === 'nosql') {
113
109
  const db = connection.client.db();
114
- await db.collection(projectId).deleteOne({ _id: new mongodb_1.ObjectId(exportId) });
110
+ await db.collection('exports').deleteOne({ _id: new mongodb_1.ObjectId(exportId) });
115
111
  }
116
- // SQL raw export table row deletion would go here if needed in future
112
+ // SQL export row deletion would go here if needed in future
117
113
  if (isSqlProject) {
118
114
  const SqlProject = (0, manager_1.getModel)('projects', 'sql');
119
115
  await SqlProject.update({ _id: projectId }, { $pull: { exports: { id: exportId } } });
120
116
  }
121
117
  else {
122
- const NoSQLProject = (0, manager_1.getModel)('projects', 'nosql');
118
+ const NoSQLProject = (0, manager_1.getModel)('projects');
123
119
  await NoSQLProject.update({ _id: new mongodb_1.ObjectId(projectId) }, { $pull: { exports: { id: new mongodb_1.ObjectId(exportId) } } });
124
120
  }
125
121
  return { message: 'Export deleted successfully' };
@@ -91,9 +91,10 @@ async function executePipeline(nodeSchema, project, config) {
91
91
  continue;
92
92
  const connectionId = node.data?.connectionId;
93
93
  const recordId = node.data?.recordId;
94
+ const projectIdentifier = project._id?.toString() ?? project.id;
94
95
  const fetchData = async (client, type) => recordId
95
- ? (0, dbConnection_1.queryRecordByIdInternal)(client, type, tableName, recordId, project.id)
96
- : (0, dbConnection_1.queryRecordsInternal)(client, type, tableName, 500, 0, project.id);
96
+ ? (0, dbConnection_1.queryRecordByIdInternal)(client, type, tableName, recordId, projectIdentifier)
97
+ : (0, dbConnection_1.queryRecordsInternal)(client, type, tableName, 500, 0, projectIdentifier);
97
98
  if (connectionId) {
98
99
  const { client, type } = (0, connectionManager_1.getConnection)(connectionId);
99
100
  dataResults.push(await fetchData(client, type));
@@ -54,6 +54,7 @@ export interface ProjectInfo {
54
54
  dbType?: DatabaseType;
55
55
  name: string;
56
56
  image?: string;
57
+ public?: boolean;
57
58
  members?: {
58
59
  role: 'viewer' | 'editor' | 'admin';
59
60
  userId: string;
@@ -135,6 +136,14 @@ export interface Auth {
135
136
  role: 'viewer' | 'editor' | 'admin';
136
137
  }
137
138
  export type AuthProvider = (req: Request) => Promise<Auth>;
139
+ export type UserPlan = 'freemium' | 'subscriber' | 'admin';
140
+ export interface UserSubscription {
141
+ id: string;
142
+ user_id: string;
143
+ plan: UserPlan;
144
+ created_at: Date;
145
+ updated_at: Date;
146
+ }
138
147
  export type ExternalDbType = 'postgresql' | 'mongodb';
139
148
  export interface DbConnection {
140
149
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "streamby-core",
3
- "version": "0.27.3",
3
+ "version": "0.28.0",
4
4
  "description": "StreamBy middleware framework for media storage management",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",