powr-sdk-api 2.5.3 → 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 CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  const config = {
4
4
  mongoUri: process.env.POWR_DB_URI,
5
- jwtToken: process.env.JWT_TOKEN
5
+ jwtToken: process.env.JWT_TOKEN,
6
+ projectId: process.env.PROJECT_ID
6
7
  };
7
8
  module.exports = config;
@@ -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);
@@ -2,15 +2,86 @@
2
2
 
3
3
  const express = require("express");
4
4
  const router = express.Router();
5
- const {
6
- getDb
7
- } = require("../services/mongo");
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
- const logicFunction = new Function("age", codeString);
35
- const status = logicFunction(name);
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: status
102
+ data: result
39
103
  });
40
104
  } catch (err) {
41
105
  console.error("Error executing logic:", err);
@@ -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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "powr-sdk-api",
3
- "version": "2.5.3",
3
+ "version": "3.0.0",
4
4
  "description": "Shared API core library for PowrStack projects",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",