powr-sdk-api 2.5.2 → 3.0.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/dist/config.js +2 -1
- package/dist/routes/chat.js +20 -7
- package/dist/routes/index.js +5 -1
- package/dist/routes/plexx.js +82 -18
- package/dist/routes/routes.js +8 -0
- package/dist/services/plexx.js +181 -0
- package/package.json +1 -1
package/dist/config.js
CHANGED
package/dist/routes/chat.js
CHANGED
|
@@ -14,7 +14,7 @@ router.get('/conversations', async (req, res) => {
|
|
|
14
14
|
try {
|
|
15
15
|
const userId = req.user.powrId;
|
|
16
16
|
const userAccess = req.user.access;
|
|
17
|
-
const projectId = req.projectId;
|
|
17
|
+
const projectId = req.query.projectId || req.projectId;
|
|
18
18
|
console.log('Current user ID:', userId, 'Access:', userAccess, 'Project:', projectId);
|
|
19
19
|
const db = await getDb();
|
|
20
20
|
const conversations = await db.collection('conversations').find({
|
|
@@ -84,7 +84,7 @@ router.get('/conversations/:conversationId/messages', async (req, res) => {
|
|
|
84
84
|
conversationId
|
|
85
85
|
} = req.params;
|
|
86
86
|
const userId = req.user.powrId;
|
|
87
|
-
const projectId = req.projectId;
|
|
87
|
+
const projectId = req.query.projectId || req.projectId;
|
|
88
88
|
const db = await getDb();
|
|
89
89
|
|
|
90
90
|
// Verify user is part of conversation
|
|
@@ -141,10 +141,11 @@ router.post('/conversations/:conversationId/messages', async (req, res) => {
|
|
|
141
141
|
conversationId
|
|
142
142
|
} = req.params;
|
|
143
143
|
const {
|
|
144
|
-
content
|
|
144
|
+
content,
|
|
145
|
+
projectId: bodyProjectId
|
|
145
146
|
} = req.body;
|
|
146
147
|
const userId = req.user.powrId;
|
|
147
|
-
const projectId = req.projectId;
|
|
148
|
+
const projectId = bodyProjectId || req.projectId;
|
|
148
149
|
if (!content || content.trim() === '') {
|
|
149
150
|
return res.status(400).json({
|
|
150
151
|
success: false,
|
|
@@ -217,11 +218,12 @@ router.post('/conversations/:conversationId/messages', async (req, res) => {
|
|
|
217
218
|
router.post('/conversations', async (req, res) => {
|
|
218
219
|
try {
|
|
219
220
|
const {
|
|
220
|
-
participantId
|
|
221
|
+
participantId,
|
|
222
|
+
projectId: bodyProjectId
|
|
221
223
|
} = req.body;
|
|
222
224
|
const userId = req.user.powrId;
|
|
223
225
|
const userAccess = req.user.access;
|
|
224
|
-
const projectId = req.projectId;
|
|
226
|
+
const projectId = bodyProjectId || req.projectId;
|
|
225
227
|
if (!participantId) {
|
|
226
228
|
return res.status(400).json({
|
|
227
229
|
success: false,
|
|
@@ -308,7 +310,7 @@ router.get('/users', async (req, res) => {
|
|
|
308
310
|
try {
|
|
309
311
|
const userId = req.user.powrId;
|
|
310
312
|
const userAccess = req.user.access;
|
|
311
|
-
const projectId = req.projectId;
|
|
313
|
+
const projectId = req.query.projectId || req.projectId;
|
|
312
314
|
console.log('Current user access level:', userAccess, 'Project:', projectId);
|
|
313
315
|
const db = await getDb();
|
|
314
316
|
|
|
@@ -316,7 +318,18 @@ router.get('/users', async (req, res) => {
|
|
|
316
318
|
const projectUsers = await db.collection('profiles').find({
|
|
317
319
|
projectId: projectId
|
|
318
320
|
}).toArray();
|
|
321
|
+
console.log('Project users found:', projectUsers.length, 'for projectId:', projectId);
|
|
319
322
|
const userIds = projectUsers.map(profile => profile.userId);
|
|
323
|
+
console.log('User IDs extracted:', userIds);
|
|
324
|
+
|
|
325
|
+
// If no users found for this project, return empty array
|
|
326
|
+
if (userIds.length === 0) {
|
|
327
|
+
console.log('No users found for project:', projectId);
|
|
328
|
+
return res.json({
|
|
329
|
+
success: true,
|
|
330
|
+
data: []
|
|
331
|
+
});
|
|
332
|
+
}
|
|
320
333
|
let userQuery = {
|
|
321
334
|
_id: {
|
|
322
335
|
$in: userIds.map(id => new ObjectId(id))
|
package/dist/routes/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
const {
|
|
8
8
|
verifyToken
|
|
9
9
|
} = require('../middleware/jwtToken');
|
|
10
|
+
const plexxManager = require('../services/plexx');
|
|
10
11
|
|
|
11
12
|
// Import all route modules
|
|
12
13
|
const commentsRoutes = require('./comments');
|
|
@@ -24,9 +25,12 @@ const slidesRoutes = require('./slides');
|
|
|
24
25
|
const notificationsRoutes = require('./notifications');
|
|
25
26
|
const profilesRoutes = require('./profiles');
|
|
26
27
|
const chatRoutes = require('./chat');
|
|
27
|
-
const createPowrRoutes = (options = {}) => {
|
|
28
|
+
const createPowrRoutes = async (options = {}) => {
|
|
28
29
|
const router = express.Router();
|
|
29
30
|
|
|
31
|
+
// Initialize Plexx manager with options
|
|
32
|
+
await plexxManager.initialize(options);
|
|
33
|
+
|
|
30
34
|
// Use the dedicated projectId injection middleware
|
|
31
35
|
router.use(injectProjectId(options));
|
|
32
36
|
router.use('/comments', commentsRoutes);
|
package/dist/routes/plexx.js
CHANGED
|
@@ -2,15 +2,86 @@
|
|
|
2
2
|
|
|
3
3
|
const express = require("express");
|
|
4
4
|
const router = express.Router();
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const plexxManager = require("../services/plexx");
|
|
6
|
+
|
|
7
|
+
// Get Plexx status
|
|
8
|
+
router.get("/status", async (req, res) => {
|
|
9
|
+
try {
|
|
10
|
+
const stats = plexxManager.getStats();
|
|
11
|
+
return res.status(200).json({
|
|
12
|
+
success: true,
|
|
13
|
+
data: {
|
|
14
|
+
...stats,
|
|
15
|
+
message: stats.isEnabled ? "Plexx is running" : "Plexx is disabled"
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
} catch (err) {
|
|
19
|
+
console.error("Error getting Plexx status:", err);
|
|
20
|
+
return res.status(500).json({
|
|
21
|
+
success: false,
|
|
22
|
+
message: "Error getting Plexx status"
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Enable Plexx
|
|
28
|
+
router.post("/enable", async (req, res) => {
|
|
29
|
+
try {
|
|
30
|
+
plexxManager.enable();
|
|
31
|
+
return res.status(200).json({
|
|
32
|
+
success: true,
|
|
33
|
+
message: "Plexx enabled successfully",
|
|
34
|
+
data: plexxManager.getStats()
|
|
35
|
+
});
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error("Error enabling Plexx:", err);
|
|
38
|
+
return res.status(500).json({
|
|
39
|
+
success: false,
|
|
40
|
+
message: "Error enabling Plexx"
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Disable Plexx
|
|
46
|
+
router.post("/disable", async (req, res) => {
|
|
47
|
+
try {
|
|
48
|
+
plexxManager.disable();
|
|
49
|
+
return res.status(200).json({
|
|
50
|
+
success: true,
|
|
51
|
+
message: "Plexx disabled successfully",
|
|
52
|
+
data: plexxManager.getStats()
|
|
53
|
+
});
|
|
54
|
+
} catch (err) {
|
|
55
|
+
console.error("Error disabling Plexx:", err);
|
|
56
|
+
return res.status(500).json({
|
|
57
|
+
success: false,
|
|
58
|
+
message: "Error disabling Plexx"
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Toggle Plexx
|
|
64
|
+
router.post("/toggle", async (req, res) => {
|
|
65
|
+
try {
|
|
66
|
+
const isEnabled = plexxManager.toggle();
|
|
67
|
+
return res.status(200).json({
|
|
68
|
+
success: true,
|
|
69
|
+
message: isEnabled ? "Plexx enabled" : "Plexx disabled",
|
|
70
|
+
data: plexxManager.getStats()
|
|
71
|
+
});
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.error("Error toggling Plexx:", err);
|
|
74
|
+
return res.status(500).json({
|
|
75
|
+
success: false,
|
|
76
|
+
message: "Error toggling Plexx"
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
8
80
|
router.get("/:route", async (req, res) => {
|
|
9
81
|
const {
|
|
10
82
|
route
|
|
11
83
|
} = req.params;
|
|
12
84
|
const {
|
|
13
|
-
name,
|
|
14
85
|
projectId
|
|
15
86
|
} = req.query;
|
|
16
87
|
if (!projectId) {
|
|
@@ -19,23 +90,16 @@ router.get("/:route", async (req, res) => {
|
|
|
19
90
|
message: 'projectId is required.'
|
|
20
91
|
});
|
|
21
92
|
}
|
|
22
|
-
const logicEntry = await getDb().collection("routes").findOne({
|
|
23
|
-
route,
|
|
24
|
-
projectId
|
|
25
|
-
});
|
|
26
|
-
if (!logicEntry) {
|
|
27
|
-
return res.status(404).json({
|
|
28
|
-
success: false,
|
|
29
|
-
message: "Logic not found"
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
const codeString = logicEntry.code;
|
|
33
93
|
try {
|
|
34
|
-
|
|
35
|
-
const
|
|
94
|
+
// Use pre-compiled function (NO COMPILATION HERE)
|
|
95
|
+
const params = {
|
|
96
|
+
...req.query,
|
|
97
|
+
...req.body
|
|
98
|
+
};
|
|
99
|
+
const result = await plexxManager.execute(projectId, route, params);
|
|
36
100
|
return res.status(200).json({
|
|
37
101
|
success: true,
|
|
38
|
-
data:
|
|
102
|
+
data: result
|
|
39
103
|
});
|
|
40
104
|
} catch (err) {
|
|
41
105
|
console.error("Error executing logic:", err);
|
package/dist/routes/routes.js
CHANGED
|
@@ -107,6 +107,8 @@ router.put('/:route', async (req, res) => {
|
|
|
107
107
|
message: 'Route not found.'
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
|
+
|
|
111
|
+
// Update database
|
|
110
112
|
const result = await db.collection('routes').updateOne(query, {
|
|
111
113
|
$set: {
|
|
112
114
|
code
|
|
@@ -118,6 +120,12 @@ router.put('/:route', async (req, res) => {
|
|
|
118
120
|
message: 'Route not found.'
|
|
119
121
|
});
|
|
120
122
|
}
|
|
123
|
+
|
|
124
|
+
// Recompile the updated route using Plexx manager (only if enabled)
|
|
125
|
+
const plexxManager = require('../services/plexx');
|
|
126
|
+
if (plexxManager.getStats().isEnabled) {
|
|
127
|
+
await plexxManager.updateRoute(projectId, route, code);
|
|
128
|
+
}
|
|
121
129
|
const updatedRoute = await db.collection('routes').findOne(query);
|
|
122
130
|
return res.status(200).json({
|
|
123
131
|
success: true,
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
getDb
|
|
5
|
+
} = require("./mongo");
|
|
6
|
+
const crypto = require('crypto');
|
|
7
|
+
const config = require('../config');
|
|
8
|
+
class PlexxManager {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.compiledFunctions = new Map();
|
|
11
|
+
this.isInitialized = false;
|
|
12
|
+
this.isCentralService = false;
|
|
13
|
+
this.isEnabled = false; // Default disabled
|
|
14
|
+
}
|
|
15
|
+
async initialize(options = {}) {
|
|
16
|
+
this.isCentralService = options.isCentralService || false;
|
|
17
|
+
this.isEnabled = options.enablePlexx === true; // Default false unless explicitly enabled
|
|
18
|
+
|
|
19
|
+
if (!this.isEnabled) {
|
|
20
|
+
console.log("🚫 Plexx is disabled");
|
|
21
|
+
this.isInitialized = true;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (this.isCentralService) {
|
|
25
|
+
// Central service: Don't pre-load, load dynamically
|
|
26
|
+
console.log("🔄 Central service mode - loading routes dynamically");
|
|
27
|
+
this.isInitialized = true;
|
|
28
|
+
} else {
|
|
29
|
+
// Individual API: Load only this project's routes
|
|
30
|
+
const projectId = config.projectId;
|
|
31
|
+
console.log(`📦 Loading routes for project: ${projectId}`);
|
|
32
|
+
try {
|
|
33
|
+
const routes = await getDb().collection("routes").find({
|
|
34
|
+
projectId
|
|
35
|
+
}).toArray();
|
|
36
|
+
routes.forEach(route => {
|
|
37
|
+
this.compileAndCache(route);
|
|
38
|
+
});
|
|
39
|
+
this.isInitialized = true;
|
|
40
|
+
console.log(`✅ Pre-compiled ${routes.length} routes for project ${projectId}`);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error("❌ Failed to initialize routes:", error);
|
|
43
|
+
this.isInitialized = true; // Still mark as initialized to prevent blocking
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
compileAndCache(route) {
|
|
48
|
+
const cacheKey = `${route.projectId}:${route.route}`;
|
|
49
|
+
try {
|
|
50
|
+
// Security validation
|
|
51
|
+
if (!this.validateCode(route.code)) {
|
|
52
|
+
console.error(`❌ Invalid code in route: ${route.route}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Pre-compile function
|
|
57
|
+
const compiledFunction = new Function("params", route.code);
|
|
58
|
+
this.compiledFunctions.set(cacheKey, {
|
|
59
|
+
function: compiledFunction,
|
|
60
|
+
metadata: {
|
|
61
|
+
route: route.route,
|
|
62
|
+
projectId: route.projectId,
|
|
63
|
+
compiledAt: new Date(),
|
|
64
|
+
codeHash: this.generateHash(route.code)
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
console.log(`✅ Compiled: ${route.route}`);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error(`❌ Failed to compile ${route.route}:`, error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async execute(projectId, route, params) {
|
|
73
|
+
if (!this.isEnabled) {
|
|
74
|
+
throw new Error("Plexx is disabled");
|
|
75
|
+
}
|
|
76
|
+
const cacheKey = `${projectId}:${route}`;
|
|
77
|
+
const cached = this.compiledFunctions.get(cacheKey);
|
|
78
|
+
if (!cached) {
|
|
79
|
+
if (this.isCentralService) {
|
|
80
|
+
// Try to load project routes dynamically
|
|
81
|
+
await this.loadProjectRoutes(projectId);
|
|
82
|
+
const retryCached = this.compiledFunctions.get(cacheKey);
|
|
83
|
+
if (retryCached) {
|
|
84
|
+
return retryCached.function(params);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
throw new Error(`Route not found: ${route}`);
|
|
88
|
+
}
|
|
89
|
+
return cached.function(params);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Dynamic loading for central service
|
|
93
|
+
async loadProjectRoutes(projectId) {
|
|
94
|
+
if (!this.isCentralService) {
|
|
95
|
+
throw new Error("Dynamic loading only available in central service mode");
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const routes = await getDb().collection("routes").find({
|
|
99
|
+
projectId
|
|
100
|
+
}).toArray();
|
|
101
|
+
routes.forEach(route => {
|
|
102
|
+
this.compileAndCache(route);
|
|
103
|
+
});
|
|
104
|
+
console.log(`✅ Loaded ${routes.length} routes for project ${projectId}`);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error(`❌ Failed to load routes for project ${projectId}:`, error);
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Security validation
|
|
112
|
+
validateCode(code) {
|
|
113
|
+
const dangerousPatterns = [/process\./, /require\(/, /eval\(/, /setTimeout\(/, /setInterval\(/, /global\./, /__dirname/, /__filename/];
|
|
114
|
+
return !dangerousPatterns.some(pattern => pattern.test(code));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Generate hash for change detection
|
|
118
|
+
generateHash(code) {
|
|
119
|
+
return crypto.createHash('md5').update(code).digest('hex');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Update route (re-compile)
|
|
123
|
+
async updateRoute(projectId, route, newCode) {
|
|
124
|
+
const routeData = {
|
|
125
|
+
projectId,
|
|
126
|
+
route,
|
|
127
|
+
code: newCode
|
|
128
|
+
};
|
|
129
|
+
this.compileAndCache(routeData);
|
|
130
|
+
|
|
131
|
+
// Optionally save to database
|
|
132
|
+
try {
|
|
133
|
+
await getDb().collection("routes").updateOne({
|
|
134
|
+
projectId,
|
|
135
|
+
route
|
|
136
|
+
}, {
|
|
137
|
+
$set: {
|
|
138
|
+
code: newCode,
|
|
139
|
+
updatedAt: new Date()
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error(`❌ Failed to update route in database: ${route}`, error);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Get route statistics
|
|
148
|
+
getStats() {
|
|
149
|
+
return {
|
|
150
|
+
totalRoutes: this.compiledFunctions.size,
|
|
151
|
+
isInitialized: this.isInitialized,
|
|
152
|
+
isCentralService: this.isCentralService,
|
|
153
|
+
isEnabled: this.isEnabled,
|
|
154
|
+
cacheKeys: Array.from(this.compiledFunctions.keys())
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Clear cache (for testing or maintenance)
|
|
159
|
+
clearCache() {
|
|
160
|
+
this.compiledFunctions.clear();
|
|
161
|
+
console.log("🧹 Route cache cleared");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Enable/Disable Plexx
|
|
165
|
+
enable() {
|
|
166
|
+
this.isEnabled = true;
|
|
167
|
+
console.log("✅ Plexx enabled");
|
|
168
|
+
}
|
|
169
|
+
disable() {
|
|
170
|
+
this.isEnabled = false;
|
|
171
|
+
console.log("🚫 Plexx disabled");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Toggle Plexx
|
|
175
|
+
toggle() {
|
|
176
|
+
this.isEnabled = !this.isEnabled;
|
|
177
|
+
console.log(this.isEnabled ? "✅ Plexx enabled" : "🚫 Plexx disabled");
|
|
178
|
+
return this.isEnabled;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
module.exports = new PlexxManager();
|