plugin-cluster-manager 1.1.10 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/client-v2.d.ts +2 -0
  2. package/client-v2.js +1 -0
  3. package/client.js +1 -0
  4. package/dist/client/index.js +1 -1
  5. package/dist/client-v2/914.5dc1105cf3ada6a6.js +10 -0
  6. package/dist/client-v2/index.js +10 -0
  7. package/dist/externalVersion.js +6 -5
  8. package/dist/locale/en-US.json +138 -28
  9. package/dist/locale/vi-VN.json +139 -28
  10. package/dist/locale/zh-CN.json +140 -28
  11. package/dist/server/actions/cache-monitor.js +301 -0
  12. package/dist/server/actions/cluster-nodes.js +391 -11
  13. package/dist/server/actions/doctor.js +1246 -0
  14. package/dist/server/actions/orchestrator.js +37 -0
  15. package/dist/server/actions/queue-mappings.js +107 -0
  16. package/dist/server/collections/cluster-manager-doctor-runs.js +52 -0
  17. package/dist/server/collections/cluster-manager-doctor.js +44 -0
  18. package/dist/server/collections/worker-queue-mappings.js +106 -0
  19. package/dist/server/hooks/cacheInvalidationHooks.js +81 -0
  20. package/dist/server/middlewares/listMetaCacheMiddleware.js +79 -0
  21. package/dist/server/orchestrator/PackageManager.js +21 -24
  22. package/dist/server/orchestrator/docker-adapter.js +49 -27
  23. package/dist/server/plugin.js +71 -16
  24. package/dist/server/queue-scanner.js +141 -0
  25. package/dist/server/utils/node.js +30 -2
  26. package/dist/server/utils/versionManager.js +91 -0
  27. package/package.json +9 -5
  28. package/server.js +1 -0
  29. package/src/client/AclCacheManager.tsx +292 -287
  30. package/src/client/CacheMonitor.tsx +166 -179
  31. package/src/client/ClusterManagerLayout.tsx +54 -42
  32. package/src/client/ClusterNodes.tsx +698 -418
  33. package/src/client/ContainerOrchestrator.tsx +184 -102
  34. package/src/client/Doctor.tsx +559 -0
  35. package/src/client/NginxCacheManager.tsx +415 -0
  36. package/src/client/PluginOperations.tsx +234 -234
  37. package/src/client/QueueAssignment.tsx +355 -0
  38. package/src/client/TaskManager.tsx +194 -187
  39. package/src/client/WorkflowExecutions.tsx +243 -238
  40. package/src/client/index.tsx +22 -14
  41. package/src/client/utils/clientSafeCache.ts +41 -0
  42. package/src/client/utils/requestDedupInterceptor.ts +213 -0
  43. package/src/client-v2/plugin.tsx +24 -0
  44. package/src/locale/en-US.json +138 -28
  45. package/src/locale/vi-VN.json +139 -28
  46. package/src/locale/zh-CN.json +140 -28
  47. package/src/server/__tests__/doctor.test.ts +53 -0
  48. package/src/server/actions/acl-cache.ts +272 -272
  49. package/src/server/actions/cache-monitor.ts +453 -116
  50. package/src/server/actions/cluster-nodes.ts +878 -378
  51. package/src/server/actions/doctor.ts +1536 -0
  52. package/src/server/actions/orchestrator.ts +54 -2
  53. package/src/server/actions/queue-mappings.ts +94 -0
  54. package/src/server/collections/cluster-manager-doctor-runs.ts +23 -0
  55. package/src/server/collections/cluster-manager-doctor.ts +19 -0
  56. package/src/server/collections/worker-queue-mappings.ts +85 -0
  57. package/src/server/hooks/cacheInvalidationHooks.ts +58 -0
  58. package/src/server/middlewares/listMetaCacheMiddleware.ts +55 -0
  59. package/src/server/orchestrator/PackageManager.ts +20 -24
  60. package/src/server/orchestrator/docker-adapter.ts +74 -37
  61. package/src/server/plugin.ts +347 -270
  62. package/src/server/queue-scanner.ts +154 -0
  63. package/src/server/utils/node.ts +48 -0
  64. package/src/server/utils/versionManager.ts +69 -0
  65. package/dist/client/AclCacheManager.d.ts +0 -2
  66. package/dist/client/CacheMonitor.d.ts +0 -2
  67. package/dist/client/ClusterManagerLayout.d.ts +0 -2
  68. package/dist/client/ClusterNodes.d.ts +0 -2
  69. package/dist/client/ContainerOrchestrator.d.ts +0 -2
  70. package/dist/client/EventQueueMonitor.d.ts +0 -2
  71. package/dist/client/LockMonitor.d.ts +0 -2
  72. package/dist/client/PackageInstaller.d.ts +0 -2
  73. package/dist/client/PluginOperations.d.ts +0 -2
  74. package/dist/client/RedisMonitor.d.ts +0 -2
  75. package/dist/client/TaskManager.d.ts +0 -2
  76. package/dist/client/WorkflowExecutions.d.ts +0 -2
  77. package/dist/client/index.d.ts +0 -5
  78. package/dist/client/utils.d.ts +0 -12
  79. package/dist/index.d.ts +0 -2
  80. package/dist/server/actions/acl-cache.d.ts +0 -53
  81. package/dist/server/actions/cache-monitor.d.ts +0 -23
  82. package/dist/server/actions/cluster-nodes.d.ts +0 -49
  83. package/dist/server/actions/event-queue-monitor.d.ts +0 -13
  84. package/dist/server/actions/lock-monitor.d.ts +0 -19
  85. package/dist/server/actions/orchestrator.d.ts +0 -58
  86. package/dist/server/actions/package-manager.d.ts +0 -6
  87. package/dist/server/actions/plugin-operations.d.ts +0 -6
  88. package/dist/server/actions/redis-monitor.d.ts +0 -12
  89. package/dist/server/actions/tasks.d.ts +0 -7
  90. package/dist/server/actions/workflow-executions.d.ts +0 -7
  91. package/dist/server/adapters/redis-lock-adapter.d.ts +0 -15
  92. package/dist/server/adapters/redis-node-registry.d.ts +0 -12
  93. package/dist/server/adapters/redis-pubsub-adapter.d.ts +0 -16
  94. package/dist/server/collections/app.d.ts +0 -8
  95. package/dist/server/collections/cluster-manager-acl-cache.d.ts +0 -22
  96. package/dist/server/collections/cluster-manager-cache-mgr.d.ts +0 -22
  97. package/dist/server/collections/cluster-manager-cluster.d.ts +0 -22
  98. package/dist/server/collections/cluster-manager-lock.d.ts +0 -22
  99. package/dist/server/collections/cluster-manager-plugins.d.ts +0 -18
  100. package/dist/server/collections/cluster-manager-queue.d.ts +0 -22
  101. package/dist/server/collections/cluster-manager-redis.d.ts +0 -22
  102. package/dist/server/collections/cluster-manager-workflow.d.ts +0 -22
  103. package/dist/server/collections/cluster-manager.d.ts +0 -22
  104. package/dist/server/collections/orchestrator-settings.d.ts +0 -59
  105. package/dist/server/collections/orchestrator-stacks.d.ts +0 -102
  106. package/dist/server/collections/worker-orchestrator.d.ts +0 -22
  107. package/dist/server/collections/worker-packages-configs.d.ts +0 -3
  108. package/dist/server/collections/worker-packages.d.ts +0 -22
  109. package/dist/server/orchestrator/PackageManager.d.ts +0 -39
  110. package/dist/server/orchestrator/docker-adapter.d.ts +0 -41
  111. package/dist/server/orchestrator/index.d.ts +0 -4
  112. package/dist/server/orchestrator/k8s-adapter.d.ts +0 -50
  113. package/dist/server/orchestrator/leader-election.d.ts +0 -48
  114. package/dist/server/orchestrator/types.d.ts +0 -84
  115. package/dist/server/plugin.d.ts +0 -26
  116. package/dist/server/utils/node.d.ts +0 -6
  117. package/dist/server/utils/redis.d.ts +0 -29
  118. package/dist/shared/packages.d.ts +0 -23
  119. /package/{dist/server/index.d.ts → src/client-v2/index.tsx} +0 -0
@@ -7,9 +7,11 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
+ var __create = Object.create;
10
11
  var __defProp = Object.defineProperty;
11
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
13
  var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
13
15
  var __hasOwnProp = Object.prototype.hasOwnProperty;
14
16
  var __export = (target, all) => {
15
17
  for (var name in all)
@@ -23,6 +25,14 @@ var __copyProps = (to, from, except, desc) => {
23
25
  }
24
26
  return to;
25
27
  };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
+ // If the importer is in node compatibility mode or this is not an ESM
30
+ // file that has been converted to a CommonJS file using a Babel-
31
+ // compatible transform (i.e. "__esModule" has not been set), then set
32
+ // "default" to the CommonJS "module.exports" for node compatibility.
33
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
+ mod
35
+ ));
26
36
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
37
  var cache_monitor_exports = {};
28
38
  __export(cache_monitor_exports, {
@@ -30,6 +40,220 @@ __export(cache_monitor_exports, {
30
40
  });
31
41
  module.exports = __toCommonJS(cache_monitor_exports);
32
42
  var import_redis = require("../utils/redis");
43
+ var import_fs = require("fs");
44
+ var import_path = __toESM(require("path"));
45
+ var import_child_process = require("child_process");
46
+ var import_http = __toESM(require("http"));
47
+ var import_https = __toESM(require("https"));
48
+ async function exists(p) {
49
+ try {
50
+ await import_fs.promises.access(p);
51
+ return true;
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+ function isSafePath(dirPath) {
57
+ if (!dirPath) return false;
58
+ const resolved = import_path.default.resolve(dirPath);
59
+ const normalized = resolved.toLowerCase().replace(/\\/g, "/");
60
+ const restrictedPatterns = [
61
+ "^/$",
62
+ "^[a-z]:/?$",
63
+ "^/[^/]+$",
64
+ "^[a-z]:/[^/]+$",
65
+ "/windows",
66
+ "/system32",
67
+ "/program files",
68
+ "/etc",
69
+ "/var$",
70
+ "/usr$",
71
+ "/boot",
72
+ "/sys",
73
+ "/proc",
74
+ "/dev",
75
+ "/home$",
76
+ "/root$"
77
+ ];
78
+ for (const pat of restrictedPatterns) {
79
+ const re = new RegExp(pat);
80
+ if (re.test(normalized)) {
81
+ return false;
82
+ }
83
+ }
84
+ const parts = normalized.split("/").filter(Boolean);
85
+ const nonDriveParts = parts.filter((p) => !/^[a-z]:$/.test(p));
86
+ if (nonDriveParts.length < 2) {
87
+ return false;
88
+ }
89
+ return true;
90
+ }
91
+ async function findNginxConfig() {
92
+ const nginxConfPath = await new Promise((resolve) => {
93
+ (0, import_child_process.exec)("nginx -V", (err, stdout, stderr) => {
94
+ if (err) return resolve(null);
95
+ const output = stdout + stderr;
96
+ const match = output.match(/--conf-path=([^\s]+)/);
97
+ if (match && match[1]) {
98
+ resolve(match[1]);
99
+ } else {
100
+ resolve(null);
101
+ }
102
+ });
103
+ });
104
+ if (nginxConfPath && await exists(nginxConfPath)) {
105
+ return nginxConfPath;
106
+ }
107
+ const searchPaths = [
108
+ "/etc/nginx/nginx.conf",
109
+ "/usr/local/nginx/conf/nginx.conf",
110
+ "/usr/local/etc/nginx/nginx.conf",
111
+ "/opt/homebrew/etc/nginx/nginx.conf",
112
+ "C:\\nginx\\conf\\nginx.conf"
113
+ ];
114
+ for (const p of searchPaths) {
115
+ if (await exists(p)) {
116
+ return p;
117
+ }
118
+ }
119
+ return null;
120
+ }
121
+ async function readConfigRecursive(configPath, visited = /* @__PURE__ */ new Set()) {
122
+ const resolvedPath = import_path.default.resolve(configPath);
123
+ if (visited.has(resolvedPath)) return "";
124
+ visited.add(resolvedPath);
125
+ try {
126
+ const content = await import_fs.promises.readFile(resolvedPath, "utf8");
127
+ const lines = content.split(/\r?\n/);
128
+ let fullText = content + "\n";
129
+ const configDir = import_path.default.dirname(resolvedPath);
130
+ for (const line of lines) {
131
+ const trimmed = line.trim();
132
+ if (trimmed.startsWith("#")) continue;
133
+ const includeMatch = trimmed.match(/^include\s+([^\s;]+)/);
134
+ if (includeMatch && includeMatch[1]) {
135
+ let includePattern = includeMatch[1].trim().replace(/^["']|["']$/g, "");
136
+ if (!import_path.default.isAbsolute(includePattern)) {
137
+ includePattern = import_path.default.join(configDir, includePattern);
138
+ }
139
+ if (includePattern.includes("*")) {
140
+ try {
141
+ const patternDir = import_path.default.dirname(includePattern);
142
+ const ext = import_path.default.extname(includePattern);
143
+ if (await exists(patternDir)) {
144
+ const files = await import_fs.promises.readdir(patternDir);
145
+ for (const file of files) {
146
+ if (file.endsWith(ext) || includePattern.endsWith("*")) {
147
+ const filePath = import_path.default.join(patternDir, file);
148
+ fullText += await readConfigRecursive(filePath, visited) + "\n";
149
+ }
150
+ }
151
+ }
152
+ } catch {
153
+ }
154
+ } else {
155
+ if (await exists(includePattern)) {
156
+ fullText += await readConfigRecursive(includePattern, visited) + "\n";
157
+ }
158
+ }
159
+ }
160
+ }
161
+ return fullText;
162
+ } catch {
163
+ return "";
164
+ }
165
+ }
166
+ function extractCachePaths(configText) {
167
+ const paths = [];
168
+ const lines = configText.split(/\r?\n/);
169
+ for (const line of lines) {
170
+ const trimmed = line.trim();
171
+ if (trimmed.startsWith("#")) continue;
172
+ const match = trimmed.match(/^(?:proxy|fastcgi|scgi|uwsgi)_cache_path\s+([^\s;]+)/);
173
+ if (match && match[1]) {
174
+ const p = match[1].trim();
175
+ const cleanPath = p.replace(/^["']|["']$/g, "");
176
+ if (cleanPath && !paths.includes(cleanPath)) {
177
+ paths.push(cleanPath);
178
+ }
179
+ }
180
+ }
181
+ return paths;
182
+ }
183
+ async function emptyDirectory(dirPath) {
184
+ if (!isSafePath(dirPath)) {
185
+ return { success: false, clearedCount: 0, error: "Path is classified as unsafe or restricted" };
186
+ }
187
+ try {
188
+ if (!await exists(dirPath)) {
189
+ return { success: false, clearedCount: 0, error: "Directory does not exist" };
190
+ }
191
+ const stats = await import_fs.promises.stat(dirPath);
192
+ if (!stats.isDirectory()) {
193
+ return { success: false, clearedCount: 0, error: "Path is not a directory" };
194
+ }
195
+ const files = await import_fs.promises.readdir(dirPath);
196
+ let clearedCount = 0;
197
+ for (const file of files) {
198
+ const fullPath = import_path.default.join(dirPath, file);
199
+ await import_fs.promises.rm(fullPath, { recursive: true, force: true });
200
+ clearedCount++;
201
+ }
202
+ return { success: true, clearedCount };
203
+ } catch (err) {
204
+ return { success: false, clearedCount: 0, error: err.message };
205
+ }
206
+ }
207
+ function makePurgeRequest(urlStr, method = "PURGE", headers = {}) {
208
+ return new Promise((resolve) => {
209
+ try {
210
+ const url = new URL(urlStr);
211
+ const isHttps = url.protocol === "https:";
212
+ const client = isHttps ? import_https.default : import_http.default;
213
+ const reqHeaders = { ...headers };
214
+ const req = client.request(
215
+ urlStr,
216
+ {
217
+ method,
218
+ headers: reqHeaders,
219
+ timeout: 1e4
220
+ },
221
+ (res) => {
222
+ let body = "";
223
+ res.on("data", (chunk) => {
224
+ body += chunk;
225
+ });
226
+ res.on("end", () => {
227
+ resolve({
228
+ success: (res.statusCode || 0) >= 200 && (res.statusCode || 0) < 300,
229
+ status: res.statusCode,
230
+ data: body
231
+ });
232
+ });
233
+ }
234
+ );
235
+ req.on("error", (err) => {
236
+ resolve({
237
+ success: false,
238
+ error: err.message
239
+ });
240
+ });
241
+ req.on("timeout", () => {
242
+ req.destroy();
243
+ resolve({
244
+ success: false,
245
+ error: "Request timed out after 10 seconds"
246
+ });
247
+ });
248
+ req.end();
249
+ } catch (err) {
250
+ resolve({
251
+ success: false,
252
+ error: err.message
253
+ });
254
+ }
255
+ });
256
+ }
33
257
  const cacheMonitorActions = {
34
258
  /**
35
259
  * GET /clusterManagerCacheMgr:stores
@@ -125,6 +349,83 @@ const cacheMonitorActions = {
125
349
  await cm.flushAll();
126
350
  ctx.body = { success: true };
127
351
  await next();
352
+ },
353
+ /**
354
+ * GET /clusterManagerCacheMgr:nginxCacheStatus
355
+ * Detect if Nginx is installed, locate conf, and auto-load cache paths
356
+ */
357
+ async nginxCacheStatus(ctx, next) {
358
+ let nginxInstalled = false;
359
+ let mainConfigPath = null;
360
+ let detectedPaths = [];
361
+ try {
362
+ const configText = await new Promise((resolve) => {
363
+ (0, import_child_process.exec)("nginx -T", { maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
364
+ if (err) {
365
+ resolve(null);
366
+ } else {
367
+ nginxInstalled = true;
368
+ resolve(stdout);
369
+ }
370
+ });
371
+ });
372
+ if (configText) {
373
+ detectedPaths = extractCachePaths(configText);
374
+ mainConfigPath = await findNginxConfig();
375
+ } else {
376
+ mainConfigPath = await findNginxConfig();
377
+ if (mainConfigPath) {
378
+ nginxInstalled = true;
379
+ const fullConfigText = await readConfigRecursive(mainConfigPath);
380
+ detectedPaths = extractCachePaths(fullConfigText);
381
+ }
382
+ }
383
+ } catch (err) {
384
+ }
385
+ ctx.body = {
386
+ nginxInstalled,
387
+ mainConfigPath,
388
+ detectedPaths
389
+ };
390
+ await next();
391
+ },
392
+ /**
393
+ * POST /clusterManagerCacheMgr:clearNginxCache
394
+ * Clear physical cache files or send an HTTP Purge request
395
+ */
396
+ async clearNginxCache(ctx, next) {
397
+ const { method = "directory", directory, url, httpMethod = "PURGE", headers = {} } = ctx.action.params.values || {};
398
+ if (method === "directory") {
399
+ if (!directory) {
400
+ ctx.throw(400, "Directory path is required for physical cache clearing");
401
+ }
402
+ const result = await emptyDirectory(directory);
403
+ if (!result.success) {
404
+ ctx.throw(400, result.error || "Failed to clear cache directory");
405
+ }
406
+ ctx.body = {
407
+ success: true,
408
+ message: `Successfully cleared physical cache directory`,
409
+ clearedCount: result.clearedCount
410
+ };
411
+ } else if (method === "purgeRequest") {
412
+ if (!url) {
413
+ ctx.throw(400, "Purge URL is required for HTTP Purge request method");
414
+ }
415
+ const result = await makePurgeRequest(url, httpMethod, headers);
416
+ if (!result.success) {
417
+ ctx.throw(400, result.error || `HTTP Purge request failed with status: ${result.status}`);
418
+ }
419
+ ctx.body = {
420
+ success: true,
421
+ message: `HTTP Purge request sent successfully`,
422
+ status: result.status,
423
+ data: result.data
424
+ };
425
+ } else {
426
+ ctx.throw(400, `Unknown clearing method: ${method}`);
427
+ }
428
+ await next();
128
429
  }
129
430
  };
130
431
  // Annotate the CommonJS export names for ESM import in node: