powr-sdk-api 3.0.6 → 3.0.7
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/index.js +2 -2
- package/dist/routes/functions.js +269 -0
- package/dist/routes/index.js +8 -8
- package/dist/services/functions.js +229 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ const {
|
|
|
15
15
|
} = require("./swagger");
|
|
16
16
|
const {
|
|
17
17
|
createPowrRoutes,
|
|
18
|
-
|
|
18
|
+
initializeFunctions
|
|
19
19
|
} = require("./routes");
|
|
20
20
|
const {
|
|
21
21
|
verifyToken
|
|
@@ -27,6 +27,6 @@ module.exports = {
|
|
|
27
27
|
createSwaggerSpec,
|
|
28
28
|
notFoundHandler,
|
|
29
29
|
createPowrRoutes,
|
|
30
|
-
|
|
30
|
+
initializeFunctions,
|
|
31
31
|
verifyToken
|
|
32
32
|
};
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const express = require("express");
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
const functionsManager = require("../services/functions");
|
|
6
|
+
const {
|
|
7
|
+
getDb
|
|
8
|
+
} = require("../services/mongo");
|
|
9
|
+
|
|
10
|
+
// Get Functions status
|
|
11
|
+
router.get("/status", async (req, res) => {
|
|
12
|
+
try {
|
|
13
|
+
const stats = functionsManager.getStats();
|
|
14
|
+
return res.status(200).json({
|
|
15
|
+
success: true,
|
|
16
|
+
data: {
|
|
17
|
+
...stats,
|
|
18
|
+
message: stats.isEnabled ? "Functions is running" : "Functions is disabled"
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
} catch (err) {
|
|
22
|
+
console.error("Error getting Functions status:", err);
|
|
23
|
+
return res.status(500).json({
|
|
24
|
+
success: false,
|
|
25
|
+
message: "Error getting Functions status"
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Enable Functions
|
|
31
|
+
router.post("/enable", async (req, res) => {
|
|
32
|
+
try {
|
|
33
|
+
functionsManager.enable();
|
|
34
|
+
return res.status(200).json({
|
|
35
|
+
success: true,
|
|
36
|
+
message: "Functions enabled successfully",
|
|
37
|
+
data: functionsManager.getStats()
|
|
38
|
+
});
|
|
39
|
+
} catch (err) {
|
|
40
|
+
console.error("Error enabling Functions:", err);
|
|
41
|
+
return res.status(500).json({
|
|
42
|
+
success: false,
|
|
43
|
+
message: "Error enabling Functions"
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Disable Functions
|
|
49
|
+
router.post("/disable", async (req, res) => {
|
|
50
|
+
try {
|
|
51
|
+
functionsManager.disable();
|
|
52
|
+
return res.status(200).json({
|
|
53
|
+
success: true,
|
|
54
|
+
message: "Functions disabled successfully",
|
|
55
|
+
data: functionsManager.getStats()
|
|
56
|
+
});
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error("Error disabling Functions:", err);
|
|
59
|
+
return res.status(500).json({
|
|
60
|
+
success: false,
|
|
61
|
+
message: "Error disabling Functions"
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Toggle Functions
|
|
67
|
+
router.post("/toggle", async (req, res) => {
|
|
68
|
+
try {
|
|
69
|
+
const isEnabled = functionsManager.toggle();
|
|
70
|
+
return res.status(200).json({
|
|
71
|
+
success: true,
|
|
72
|
+
message: isEnabled ? "Functions enabled" : "Functions disabled",
|
|
73
|
+
data: functionsManager.getStats()
|
|
74
|
+
});
|
|
75
|
+
} catch (err) {
|
|
76
|
+
console.error("Error toggling Functions:", err);
|
|
77
|
+
return res.status(500).json({
|
|
78
|
+
success: false,
|
|
79
|
+
message: "Error toggling Functions"
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// CRUD Operations for Functions
|
|
85
|
+
|
|
86
|
+
// Get all functions entries
|
|
87
|
+
router.get('/', async (req, res) => {
|
|
88
|
+
const {
|
|
89
|
+
projectId
|
|
90
|
+
} = req.query;
|
|
91
|
+
try {
|
|
92
|
+
const query = {
|
|
93
|
+
projectId
|
|
94
|
+
};
|
|
95
|
+
if (!projectId) {
|
|
96
|
+
return res.status(400).json({
|
|
97
|
+
success: false,
|
|
98
|
+
message: 'projectId is required.'
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const db = await getDb();
|
|
102
|
+
const functionsData = await db.collection("functions").find(query).toArray();
|
|
103
|
+
return res.status(200).json({
|
|
104
|
+
success: true,
|
|
105
|
+
allfunctions: functionsData
|
|
106
|
+
});
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("Error retrieving functions entries:", error);
|
|
109
|
+
return res.status(500).json({
|
|
110
|
+
success: false,
|
|
111
|
+
message: "Failed to retrieve functions entries."
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Create a new function
|
|
117
|
+
router.post('/', async (req, res) => {
|
|
118
|
+
try {
|
|
119
|
+
const {
|
|
120
|
+
projectId
|
|
121
|
+
} = req.query;
|
|
122
|
+
if (!projectId) {
|
|
123
|
+
return res.status(400).json({
|
|
124
|
+
success: false,
|
|
125
|
+
message: 'projectId is required.'
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const newFunction = req.body;
|
|
129
|
+
newFunction.projectId = projectId;
|
|
130
|
+
if (!newFunction || Object.keys(newFunction).length === 0) {
|
|
131
|
+
return res.status(400).json({
|
|
132
|
+
success: false,
|
|
133
|
+
message: 'Request body is empty or invalid.'
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const db = await getDb();
|
|
137
|
+
const result = await db.collection('functions').insertOne(newFunction);
|
|
138
|
+
|
|
139
|
+
// Recompile the new function using Functions manager (only if enabled)
|
|
140
|
+
if (functionsManager.getStats().isEnabled) {
|
|
141
|
+
await functionsManager.updateRoute(projectId, newFunction.route, newFunction.code);
|
|
142
|
+
}
|
|
143
|
+
return res.status(201).json({
|
|
144
|
+
success: true,
|
|
145
|
+
entry: result.ops ? result.ops[0] : newFunction
|
|
146
|
+
});
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('Error inserting function entry:', error);
|
|
149
|
+
return res.status(500).json({
|
|
150
|
+
success: false,
|
|
151
|
+
message: 'Failed to insert function entry.'
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Update function code
|
|
157
|
+
router.put('/:function', async (req, res) => {
|
|
158
|
+
try {
|
|
159
|
+
const {
|
|
160
|
+
function: functionName
|
|
161
|
+
} = req.params;
|
|
162
|
+
const {
|
|
163
|
+
code
|
|
164
|
+
} = req.body;
|
|
165
|
+
const {
|
|
166
|
+
projectId
|
|
167
|
+
} = req.query;
|
|
168
|
+
if (!projectId) {
|
|
169
|
+
return res.status(400).json({
|
|
170
|
+
success: false,
|
|
171
|
+
message: 'projectId is required.'
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (!code) {
|
|
175
|
+
return res.status(400).json({
|
|
176
|
+
success: false,
|
|
177
|
+
message: 'Code field is required.'
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
const query = {
|
|
181
|
+
route: functionName,
|
|
182
|
+
projectId
|
|
183
|
+
};
|
|
184
|
+
const db = await getDb();
|
|
185
|
+
const existingFunction = await db.collection('functions').findOne(query);
|
|
186
|
+
if (!existingFunction) {
|
|
187
|
+
return res.status(404).json({
|
|
188
|
+
success: false,
|
|
189
|
+
message: 'Function not found.'
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Update database
|
|
194
|
+
const result = await db.collection('functions').updateOne(query, {
|
|
195
|
+
$set: {
|
|
196
|
+
code
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
if (result.matchedCount === 0) {
|
|
200
|
+
return res.status(404).json({
|
|
201
|
+
success: false,
|
|
202
|
+
message: 'Function not found.'
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Recompile the updated function using Functions manager (only if enabled)
|
|
207
|
+
if (functionsManager.getStats().isEnabled) {
|
|
208
|
+
await functionsManager.updateRoute(projectId, functionName, code);
|
|
209
|
+
}
|
|
210
|
+
const updatedFunction = await db.collection('functions').findOne(query);
|
|
211
|
+
return res.status(200).json({
|
|
212
|
+
success: true,
|
|
213
|
+
entry: updatedFunction
|
|
214
|
+
});
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error('Error updating function code:', error);
|
|
217
|
+
return res.status(500).json({
|
|
218
|
+
success: false,
|
|
219
|
+
message: 'Failed to update function code.',
|
|
220
|
+
error: error.message
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Execute dynamic function
|
|
226
|
+
router.post("/:function", async (req, res) => {
|
|
227
|
+
const {
|
|
228
|
+
function: functionName
|
|
229
|
+
} = req.params;
|
|
230
|
+
const {
|
|
231
|
+
projectId
|
|
232
|
+
} = req.query;
|
|
233
|
+
if (!projectId) {
|
|
234
|
+
return res.status(400).json({
|
|
235
|
+
success: false,
|
|
236
|
+
message: 'projectId is required.'
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
// Use pre-compiled function (NO COMPILATION HERE)
|
|
241
|
+
const params = {
|
|
242
|
+
...req.query,
|
|
243
|
+
...req.body
|
|
244
|
+
};
|
|
245
|
+
const result = await functionsManager.execute(projectId, functionName, params);
|
|
246
|
+
|
|
247
|
+
// Handle the standardized response format
|
|
248
|
+
if (result.success) {
|
|
249
|
+
return res.status(200).json({
|
|
250
|
+
success: true,
|
|
251
|
+
data: result.data,
|
|
252
|
+
message: result.message
|
|
253
|
+
});
|
|
254
|
+
} else {
|
|
255
|
+
return res.status(404).json({
|
|
256
|
+
success: false,
|
|
257
|
+
message: result.message,
|
|
258
|
+
data: result.data
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
} catch (err) {
|
|
262
|
+
console.error("Error executing function:", err);
|
|
263
|
+
return res.status(500).json({
|
|
264
|
+
success: false,
|
|
265
|
+
message: "Error executing function"
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
module.exports = router;
|
package/dist/routes/index.js
CHANGED
|
@@ -7,7 +7,7 @@ const {
|
|
|
7
7
|
const {
|
|
8
8
|
verifyToken
|
|
9
9
|
} = require('../middleware/jwtToken');
|
|
10
|
-
const
|
|
10
|
+
const functionsManager = require('../services/functions');
|
|
11
11
|
|
|
12
12
|
// Import all route modules
|
|
13
13
|
const commentsRoutes = require('./comments');
|
|
@@ -15,7 +15,7 @@ const filesRoutes = require('./files');
|
|
|
15
15
|
const formsRoutes = require('./forms');
|
|
16
16
|
const invoiceRoutes = require('./invoice');
|
|
17
17
|
const likesRoutes = require('./likes');
|
|
18
|
-
const
|
|
18
|
+
const functionsRoutes = require('./functions');
|
|
19
19
|
const ratingsRoutes = require('./ratings');
|
|
20
20
|
const usersRoutes = require('./users');
|
|
21
21
|
const waitlistsRoutes = require('./waitlists');
|
|
@@ -37,7 +37,7 @@ const createPowrRoutes = (options = {}) => {
|
|
|
37
37
|
router.use('/forms', formsRoutes);
|
|
38
38
|
router.use('/invoice', invoiceRoutes);
|
|
39
39
|
router.use('/likes', likesRoutes);
|
|
40
|
-
router.use('/
|
|
40
|
+
router.use('/functions', functionsRoutes);
|
|
41
41
|
router.use('/ratings', ratingsRoutes);
|
|
42
42
|
router.use('/users', usersRoutes);
|
|
43
43
|
router.use('/waitlists', waitlistsRoutes);
|
|
@@ -50,12 +50,12 @@ const createPowrRoutes = (options = {}) => {
|
|
|
50
50
|
return router;
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
// Async
|
|
54
|
-
const
|
|
55
|
-
// Initialize
|
|
56
|
-
await
|
|
53
|
+
// Async Functions initialization function
|
|
54
|
+
const initializeFunctions = async (options = {}) => {
|
|
55
|
+
// Initialize Functions manager with options
|
|
56
|
+
await functionsManager.initialize(options);
|
|
57
57
|
};
|
|
58
58
|
module.exports = {
|
|
59
59
|
createPowrRoutes,
|
|
60
|
-
|
|
60
|
+
initializeFunctions
|
|
61
61
|
};
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
getDb
|
|
5
|
+
} = require("./mongo");
|
|
6
|
+
const crypto = require('crypto');
|
|
7
|
+
const config = require('../config');
|
|
8
|
+
class FunctionsManager {
|
|
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.enableFunctions === true; // Default false unless explicitly enabled
|
|
18
|
+
|
|
19
|
+
if (!this.isEnabled) {
|
|
20
|
+
console.log("🚫 Functions 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 functions dynamically");
|
|
27
|
+
this.isInitialized = true;
|
|
28
|
+
} else {
|
|
29
|
+
// Individual API: Load only this project's functions
|
|
30
|
+
const projectId = config.projectId;
|
|
31
|
+
console.log(`📦 Loading functions for project: ${projectId}`);
|
|
32
|
+
try {
|
|
33
|
+
const db = await getDb();
|
|
34
|
+
const routes = await db.collection("functions").find({
|
|
35
|
+
projectId
|
|
36
|
+
}).toArray();
|
|
37
|
+
routes.forEach(route => {
|
|
38
|
+
this.compileAndCache(route);
|
|
39
|
+
});
|
|
40
|
+
this.isInitialized = true;
|
|
41
|
+
console.log(`✅ Pre-compiled ${routes.length} functions for project ${projectId}`);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error("❌ Failed to initialize functions:", error);
|
|
44
|
+
this.isInitialized = true; // Still mark as initialized to prevent blocking
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
compileAndCache(route) {
|
|
49
|
+
const cacheKey = `${route.projectId}:${route.route}`;
|
|
50
|
+
try {
|
|
51
|
+
// Security validation
|
|
52
|
+
if (!this.validateCode(route.code)) {
|
|
53
|
+
console.error(`❌ Invalid code in function: ${route.route}`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Pre-compile function
|
|
58
|
+
const compiledFunction = new Function("params", route.code);
|
|
59
|
+
this.compiledFunctions.set(cacheKey, {
|
|
60
|
+
function: compiledFunction,
|
|
61
|
+
metadata: {
|
|
62
|
+
route: route.route,
|
|
63
|
+
projectId: route.projectId,
|
|
64
|
+
compiledAt: new Date(),
|
|
65
|
+
codeHash: this.generateHash(route.code)
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
console.log(`✅ Compiled: ${route.route}`);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(`❌ Failed to compile ${route.route}:`, error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async execute(projectId, route, params) {
|
|
74
|
+
if (!this.isEnabled) {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
message: "Functions is disabled",
|
|
78
|
+
data: null
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const cacheKey = `${projectId}:${route}`;
|
|
82
|
+
const cached = this.compiledFunctions.get(cacheKey);
|
|
83
|
+
if (!cached) {
|
|
84
|
+
if (this.isCentralService) {
|
|
85
|
+
// Try to load only the specific function dynamically
|
|
86
|
+
await this.loadSpecificRoute(projectId, route);
|
|
87
|
+
const retryCached = this.compiledFunctions.get(cacheKey);
|
|
88
|
+
if (retryCached) {
|
|
89
|
+
return retryCached.function(params);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
message: `Function not found: ${route}`,
|
|
95
|
+
data: null
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const result = cached.function(params);
|
|
100
|
+
return {
|
|
101
|
+
success: true,
|
|
102
|
+
message: "Function executed successfully",
|
|
103
|
+
data: result
|
|
104
|
+
};
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return {
|
|
107
|
+
success: false,
|
|
108
|
+
message: `Error executing function: ${error.message}`,
|
|
109
|
+
data: null,
|
|
110
|
+
error: error.message
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Load specific function for central service
|
|
116
|
+
async loadSpecificRoute(projectId, route) {
|
|
117
|
+
if (!this.isCentralService) {
|
|
118
|
+
throw new Error("Dynamic loading only available in central service mode");
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const db = await getDb();
|
|
122
|
+
const routeData = await db.collection("functions").findOne({
|
|
123
|
+
projectId,
|
|
124
|
+
route
|
|
125
|
+
});
|
|
126
|
+
if (routeData) {
|
|
127
|
+
this.compileAndCache(routeData);
|
|
128
|
+
console.log(`✅ Loaded function: ${route} for project ${projectId}`);
|
|
129
|
+
} else {
|
|
130
|
+
console.log(`❌ Function not found: ${route} for project ${projectId}`);
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error(`❌ Failed to load function ${route} for project ${projectId}:`, error);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Dynamic loading for central service
|
|
139
|
+
async loadProjectRoutes(projectId) {
|
|
140
|
+
if (!this.isCentralService) {
|
|
141
|
+
throw new Error("Dynamic loading only available in central service mode");
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const db = await getDb();
|
|
145
|
+
const routes = await db.collection("functions").find({
|
|
146
|
+
projectId
|
|
147
|
+
}).toArray();
|
|
148
|
+
routes.forEach(route => {
|
|
149
|
+
this.compileAndCache(route);
|
|
150
|
+
});
|
|
151
|
+
console.log(`✅ Loaded ${routes.length} functions for project ${projectId}`);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.error(`❌ Failed to load functions for project ${projectId}:`, error);
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Security validation
|
|
159
|
+
validateCode(code) {
|
|
160
|
+
const dangerousPatterns = [/process\./, /require\(/, /eval\(/, /setTimeout\(/, /setInterval\(/, /global\./, /__dirname/, /__filename/];
|
|
161
|
+
return !dangerousPatterns.some(pattern => pattern.test(code));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Generate hash for change detection
|
|
165
|
+
generateHash(code) {
|
|
166
|
+
return crypto.createHash('md5').update(code).digest('hex');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Update function (re-compile)
|
|
170
|
+
async updateRoute(projectId, route, newCode) {
|
|
171
|
+
const routeData = {
|
|
172
|
+
projectId,
|
|
173
|
+
route,
|
|
174
|
+
code: newCode
|
|
175
|
+
};
|
|
176
|
+
this.compileAndCache(routeData);
|
|
177
|
+
|
|
178
|
+
// Optionally save to database
|
|
179
|
+
try {
|
|
180
|
+
const db = await getDb();
|
|
181
|
+
await db.collection("functions").updateOne({
|
|
182
|
+
projectId,
|
|
183
|
+
route
|
|
184
|
+
}, {
|
|
185
|
+
$set: {
|
|
186
|
+
code: newCode,
|
|
187
|
+
updatedAt: new Date()
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.error(`❌ Failed to update function in database: ${route}`, error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Get function statistics
|
|
196
|
+
getStats() {
|
|
197
|
+
return {
|
|
198
|
+
totalFunctions: this.compiledFunctions.size,
|
|
199
|
+
isInitialized: this.isInitialized,
|
|
200
|
+
isCentralService: this.isCentralService,
|
|
201
|
+
isEnabled: this.isEnabled,
|
|
202
|
+
cacheKeys: Array.from(this.compiledFunctions.keys())
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Clear cache (for testing or maintenance)
|
|
207
|
+
clearCache() {
|
|
208
|
+
this.compiledFunctions.clear();
|
|
209
|
+
console.log("🧹 Function cache cleared");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Enable/Disable Functions
|
|
213
|
+
enable() {
|
|
214
|
+
this.isEnabled = true;
|
|
215
|
+
console.log("✅ Functions enabled");
|
|
216
|
+
}
|
|
217
|
+
disable() {
|
|
218
|
+
this.isEnabled = false;
|
|
219
|
+
console.log("🚫 Functions disabled");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Toggle Functions
|
|
223
|
+
toggle() {
|
|
224
|
+
this.isEnabled = !this.isEnabled;
|
|
225
|
+
console.log(this.isEnabled ? "✅ Functions enabled" : "🚫 Functions disabled");
|
|
226
|
+
return this.isEnabled;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
module.exports = new FunctionsManager();
|