plugin-cluster-manager 1.1.0 → 1.1.6

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 (90) hide show
  1. package/README.md +17 -5
  2. package/dist/client/index.js +1 -1
  3. package/dist/externalVersion.js +5 -5
  4. package/dist/locale/en-US.json +28 -4
  5. package/dist/locale/vi-VN.json +28 -4
  6. package/dist/locale/zh-CN.json +28 -4
  7. package/dist/server/actions/event-queue-monitor.js +123 -1
  8. package/dist/server/actions/orchestrator.js +20 -1
  9. package/dist/server/actions/plugin-operations.js +171 -0
  10. package/dist/server/collections/app.js +38 -0
  11. package/dist/server/collections/cluster-manager-acl-cache.js +44 -0
  12. package/dist/server/collections/cluster-manager-cache-mgr.js +44 -0
  13. package/dist/server/collections/cluster-manager-cluster.js +44 -0
  14. package/dist/server/collections/cluster-manager-lock.js +44 -0
  15. package/dist/server/collections/cluster-manager-plugins.js +44 -0
  16. package/dist/server/collections/cluster-manager-queue.js +44 -0
  17. package/dist/server/collections/cluster-manager-redis.js +44 -0
  18. package/dist/server/collections/cluster-manager-workflow.js +44 -0
  19. package/dist/server/collections/cluster-manager.js +44 -0
  20. package/dist/server/collections/worker-orchestrator.js +44 -0
  21. package/dist/server/collections/worker-packages.js +44 -0
  22. package/dist/server/orchestrator/docker-adapter.js +19 -6
  23. package/dist/server/plugin.js +9 -3
  24. package/package.json +9 -4
  25. package/src/client/ClusterManagerLayout.tsx +16 -10
  26. package/src/client/ContainerOrchestrator.tsx +38 -3
  27. package/src/client/EventQueueMonitor.tsx +349 -202
  28. package/src/client/PluginOperations.tsx +226 -0
  29. package/src/locale/en-US.json +28 -4
  30. package/src/locale/vi-VN.json +28 -4
  31. package/src/locale/zh-CN.json +28 -4
  32. package/src/server/actions/event-queue-monitor.ts +234 -95
  33. package/src/server/actions/orchestrator.ts +21 -1
  34. package/src/server/actions/plugin-operations.ts +151 -0
  35. package/src/server/collections/app.ts +7 -0
  36. package/src/server/collections/cluster-manager-acl-cache.ts +23 -0
  37. package/src/server/collections/cluster-manager-cache-mgr.ts +23 -0
  38. package/src/server/collections/cluster-manager-cluster.ts +23 -0
  39. package/src/server/collections/cluster-manager-lock.ts +23 -0
  40. package/src/server/collections/cluster-manager-plugins.ts +19 -0
  41. package/src/server/collections/cluster-manager-queue.ts +23 -0
  42. package/src/server/collections/cluster-manager-redis.ts +23 -0
  43. package/src/server/collections/cluster-manager-workflow.ts +23 -0
  44. package/src/server/collections/cluster-manager.ts +23 -0
  45. package/src/server/collections/worker-orchestrator.ts +23 -0
  46. package/src/server/collections/worker-packages.ts +23 -0
  47. package/src/server/orchestrator/docker-adapter.ts +25 -9
  48. package/src/server/orchestrator/types.ts +3 -0
  49. package/src/server/plugin.ts +29 -21
  50. package/dist/client/AclCacheManager.d.ts +0 -2
  51. package/dist/client/CacheMonitor.d.ts +0 -2
  52. package/dist/client/ClusterManagerLayout.d.ts +0 -2
  53. package/dist/client/ClusterNodes.d.ts +0 -2
  54. package/dist/client/ContainerOrchestrator.d.ts +0 -2
  55. package/dist/client/EventQueueMonitor.d.ts +0 -2
  56. package/dist/client/LockMonitor.d.ts +0 -2
  57. package/dist/client/PackageInstaller.d.ts +0 -2
  58. package/dist/client/RedisMonitor.d.ts +0 -2
  59. package/dist/client/TaskManager.d.ts +0 -2
  60. package/dist/client/WorkflowExecutions.d.ts +0 -2
  61. package/dist/client/index.d.ts +0 -5
  62. package/dist/client/utils.d.ts +0 -12
  63. package/dist/index.d.ts +0 -2
  64. package/dist/server/actions/acl-cache.d.ts +0 -53
  65. package/dist/server/actions/cache-monitor.d.ts +0 -23
  66. package/dist/server/actions/cluster-nodes.d.ts +0 -49
  67. package/dist/server/actions/event-queue-monitor.d.ts +0 -13
  68. package/dist/server/actions/lock-monitor.d.ts +0 -19
  69. package/dist/server/actions/orchestrator.d.ts +0 -53
  70. package/dist/server/actions/package-manager.d.ts +0 -6
  71. package/dist/server/actions/redis-monitor.d.ts +0 -12
  72. package/dist/server/actions/tasks.d.ts +0 -7
  73. package/dist/server/actions/workflow-executions.d.ts +0 -7
  74. package/dist/server/adapters/redis-lock-adapter.d.ts +0 -15
  75. package/dist/server/adapters/redis-node-registry.d.ts +0 -12
  76. package/dist/server/adapters/redis-pubsub-adapter.d.ts +0 -16
  77. package/dist/server/collections/orchestrator-settings.d.ts +0 -59
  78. package/dist/server/collections/orchestrator-stacks.d.ts +0 -102
  79. package/dist/server/collections/worker-packages-configs.d.ts +0 -3
  80. package/dist/server/index.d.ts +0 -1
  81. package/dist/server/orchestrator/PackageManager.d.ts +0 -37
  82. package/dist/server/orchestrator/docker-adapter.d.ts +0 -37
  83. package/dist/server/orchestrator/index.d.ts +0 -4
  84. package/dist/server/orchestrator/k8s-adapter.d.ts +0 -50
  85. package/dist/server/orchestrator/leader-election.d.ts +0 -48
  86. package/dist/server/orchestrator/types.d.ts +0 -79
  87. package/dist/server/plugin.d.ts +0 -26
  88. package/dist/server/utils/node.d.ts +0 -6
  89. package/dist/server/utils/redis.d.ts +0 -29
  90. package/dist/shared/packages.d.ts +0 -23
@@ -11,10 +11,10 @@ module.exports = {
11
11
  "react": "18.2.0",
12
12
  "antd": "5.24.2",
13
13
  "@ant-design/icons": "5.6.1",
14
- "@nocobase/client": "2.0.47",
14
+ "@nocobase/client": "2.0.55",
15
15
  "dayjs": "1.11.13",
16
- "@nocobase/server": "2.0.47",
17
- "@nocobase/actions": "2.0.47",
18
- "@nocobase/lock-manager": "2.0.47",
19
- "@nocobase/database": "2.0.47"
16
+ "@nocobase/server": "2.0.55",
17
+ "@nocobase/actions": "2.0.55",
18
+ "@nocobase/lock-manager": "2.0.55",
19
+ "@nocobase/database": "2.0.55"
20
20
  };
@@ -1,5 +1,5 @@
1
1
  {
2
- "Worker Monitor": "Worker Monitor",
2
+ "Cluster Manager": "Cluster Manager",
3
3
  "Async Tasks": "Async Tasks",
4
4
  "Workflow Executions": "Workflow Executions",
5
5
  "Redis Monitor": "Redis Monitor",
@@ -66,6 +66,30 @@
66
66
  "This will clear all cached data across all stores.": "This will clear all cached data across all stores.",
67
67
  "All caches flushed": "All caches flushed",
68
68
  "Failed to flush caches": "Failed to flush caches",
69
- "Sync Messages": "Sync Messages",
70
- "Subscribers": "Subscribers"
71
- }
69
+ "Sync Messages": "Sync Messages",
70
+ "Subscribers": "Subscribers",
71
+ "Plugins": "Plugins",
72
+ "Plugin": "Plugin",
73
+ "Enabled": "Enabled",
74
+ "Disabled": "Disabled",
75
+ "Installed": "Installed",
76
+ "Not installed": "Not installed",
77
+ "Loaded": "Loaded",
78
+ "Not loaded": "Not loaded",
79
+ "Protected": "Protected",
80
+ "Description": "Description",
81
+ "Force disable": "Force disable",
82
+ "Force remove": "Force remove",
83
+ "Force disable this plugin?": "Force disable this plugin?",
84
+ "Force remove this plugin?": "Force remove this plugin?",
85
+ "This updates the plugin registry directly. Restart or reload is required to fully unload runtime hooks.": "This updates the plugin registry directly. Restart or reload is required to fully unload runtime hooks.",
86
+ "This removes the plugin registry record. Package files are not deleted. Restart or reload is required.": "This removes the plugin registry record. Package files are not deleted. Restart or reload is required.",
87
+ "Force operations bypass plugin lifecycle hooks": "Force operations bypass plugin lifecycle hooks",
88
+ "Use this only when the normal plugin manager cannot disable or remove a broken plugin. Restart or reload the app after a successful operation.": "Use this only when the normal plugin manager cannot disable or remove a broken plugin. Restart or reload the app after a successful operation.",
89
+ "Search plugins": "Search plugins",
90
+ "Plugin force disabled": "Plugin force disabled",
91
+ "Plugin force removed": "Plugin force removed",
92
+ "Failed to load plugins": "Failed to load plugins",
93
+ "Failed to force disable plugin": "Failed to force disable plugin",
94
+ "Failed to force remove plugin": "Failed to force remove plugin"
95
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "Worker Monitor": "Giám sát Worker",
2
+ "Cluster Manager": "Quản cụm",
3
3
  "Async Tasks": "Tác vụ bất đồng bộ",
4
4
  "Workflow Executions": "Thực thi Workflow",
5
5
  "Redis Monitor": "Giám sát Redis",
@@ -66,6 +66,30 @@
66
66
  "This will clear all cached data across all stores.": "Điều này sẽ xóa tất cả dữ liệu đệm trong mọi kho.",
67
67
  "All caches flushed": "Đã xóa tất cả bộ nhớ đệm",
68
68
  "Failed to flush caches": "Xóa bộ nhớ đệm thất bại",
69
- "Sync Messages": "Tin nhắn đồng bộ",
70
- "Subscribers": "Người đăng ký"
71
- }
69
+ "Sync Messages": "Tin nhắn đồng bộ",
70
+ "Subscribers": "Người đăng ký",
71
+ "Plugins": "Plugin",
72
+ "Plugin": "Plugin",
73
+ "Enabled": "Đã bật",
74
+ "Disabled": "Đã tắt",
75
+ "Installed": "Đã cài đặt",
76
+ "Not installed": "Chưa cài đặt",
77
+ "Loaded": "Đã tải",
78
+ "Not loaded": "Chưa tải",
79
+ "Protected": "Được bảo vệ",
80
+ "Description": "Mô tả",
81
+ "Force disable": "Buộc tắt",
82
+ "Force remove": "Buộc xóa",
83
+ "Force disable this plugin?": "Buộc tắt plugin này?",
84
+ "Force remove this plugin?": "Buộc xóa plugin này?",
85
+ "This updates the plugin registry directly. Restart or reload is required to fully unload runtime hooks.": "Thao tác này cập nhật trực tiếp registry plugin. Cần restart hoặc reload để gỡ hoàn toàn các hook runtime.",
86
+ "This removes the plugin registry record. Package files are not deleted. Restart or reload is required.": "Thao tác này xóa bản ghi plugin trong registry. File package không bị xóa. Cần restart hoặc reload.",
87
+ "Force operations bypass plugin lifecycle hooks": "Thao tác force bỏ qua lifecycle hook của plugin",
88
+ "Use this only when the normal plugin manager cannot disable or remove a broken plugin. Restart or reload the app after a successful operation.": "Chỉ dùng khi plugin manager bình thường không thể tắt hoặc xóa plugin lỗi. Restart hoặc reload ứng dụng sau khi thao tác thành công.",
89
+ "Search plugins": "Tìm plugin",
90
+ "Plugin force disabled": "Đã buộc tắt plugin",
91
+ "Plugin force removed": "Đã buộc xóa plugin",
92
+ "Failed to load plugins": "Tải danh sách plugin thất bại",
93
+ "Failed to force disable plugin": "Buộc tắt plugin thất bại",
94
+ "Failed to force remove plugin": "Buộc xóa plugin thất bại"
95
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "Worker Monitor": "Worker 监控",
2
+ "Cluster Manager": "集群管理",
3
3
  "Async Tasks": "异步任务",
4
4
  "Workflow Executions": "工作流执行",
5
5
  "Redis Monitor": "Redis 监控",
@@ -66,6 +66,30 @@
66
66
  "This will clear all cached data across all stores.": "这将清除所有存储中的缓存数据。",
67
67
  "All caches flushed": "所有缓存已清空",
68
68
  "Failed to flush caches": "清空缓存失败",
69
- "Sync Messages": "同步消息",
70
- "Subscribers": "订阅者"
71
- }
69
+ "Sync Messages": "同步消息",
70
+ "Subscribers": "订阅者",
71
+ "Plugins": "插件",
72
+ "Plugin": "插件",
73
+ "Enabled": "已启用",
74
+ "Disabled": "已禁用",
75
+ "Installed": "已安装",
76
+ "Not installed": "未安装",
77
+ "Loaded": "已加载",
78
+ "Not loaded": "未加载",
79
+ "Protected": "受保护",
80
+ "Description": "描述",
81
+ "Force disable": "强制禁用",
82
+ "Force remove": "强制移除",
83
+ "Force disable this plugin?": "强制禁用此插件?",
84
+ "Force remove this plugin?": "强制移除此插件?",
85
+ "This updates the plugin registry directly. Restart or reload is required to fully unload runtime hooks.": "此操作会直接更新插件注册表。需要重启或重新加载后才能完全卸载运行时钩子。",
86
+ "This removes the plugin registry record. Package files are not deleted. Restart or reload is required.": "此操作会移除插件注册记录。不会删除 package 文件。需要重启或重新加载。",
87
+ "Force operations bypass plugin lifecycle hooks": "强制操作会绕过插件生命周期钩子",
88
+ "Use this only when the normal plugin manager cannot disable or remove a broken plugin. Restart or reload the app after a successful operation.": "仅在普通插件管理器无法禁用或移除异常插件时使用。操作成功后请重启或重新加载应用。",
89
+ "Search plugins": "搜索插件",
90
+ "Plugin force disabled": "插件已强制禁用",
91
+ "Plugin force removed": "插件已强制移除",
92
+ "Failed to load plugins": "加载插件失败",
93
+ "Failed to force disable plugin": "强制禁用插件失败",
94
+ "Failed to force remove plugin": "强制移除插件失败"
95
+ }
@@ -29,6 +29,99 @@ __export(event_queue_monitor_exports, {
29
29
  eventQueueActions: () => eventQueueActions
30
30
  });
31
31
  module.exports = __toCommonJS(event_queue_monitor_exports);
32
+ var import_redis = require("../utils/redis");
33
+ const REDIS_QUEUE_CONNECTION = "cluster-manager:queue-monitor";
34
+ const REDIS_QUEUE_PATTERNS = ["*:plugin-git-manager:review:queue", "*:plugin-build-guide-block:build:queue"];
35
+ function getQueueRedisUrl() {
36
+ return process.env.QUEUE_ADAPTER_REDIS_URL || process.env.REDIS_URL;
37
+ }
38
+ async function getQueueRedis(ctx) {
39
+ const url = getQueueRedisUrl();
40
+ const manager = ctx.app.redisConnectionManager;
41
+ if (!url || !(manager == null ? void 0 : manager.getConnectionSync)) {
42
+ return null;
43
+ }
44
+ return manager.getConnectionSync(REDIS_QUEUE_CONNECTION, { connectionString: url });
45
+ }
46
+ function knownRedisQueueKeys(ctx) {
47
+ const appName = ctx.app.name || process.env.APP_NAME || "main";
48
+ return [`${appName}:plugin-git-manager:review:queue`, `${appName}:plugin-build-guide-block:build:queue`];
49
+ }
50
+ function isKnownRedisQueueKey(key) {
51
+ return REDIS_QUEUE_PATTERNS.some((pattern) => {
52
+ const suffix = pattern.replace("*:", "");
53
+ return key === suffix || key.endsWith(`:${suffix}`);
54
+ });
55
+ }
56
+ function describeRedisQueueKey(key) {
57
+ const parts = String(key).split(":");
58
+ const queue = parts[parts.length - 2] || key;
59
+ const plugin = parts[parts.length - 3] || "unknown";
60
+ const appName = parts.slice(0, Math.max(1, parts.length - 3)).join(":") || "main";
61
+ return {
62
+ appName,
63
+ plugin,
64
+ queue,
65
+ channel: `${plugin}.${queue}`
66
+ };
67
+ }
68
+ async function getRedisQueues(ctx) {
69
+ const redis = await getQueueRedis(ctx);
70
+ if (!redis) {
71
+ return {
72
+ connected: false,
73
+ urlConfigured: Boolean(getQueueRedisUrl()),
74
+ queues: [],
75
+ note: "Redis queue connection is not configured"
76
+ };
77
+ }
78
+ const keys = new Set(knownRedisQueueKeys(ctx));
79
+ for (const pattern of REDIS_QUEUE_PATTERNS) {
80
+ try {
81
+ const scanned = await (0, import_redis.scanKeys)(redis, pattern, 200);
82
+ scanned.forEach((key) => keys.add(key));
83
+ } catch {
84
+ }
85
+ }
86
+ const queues = [];
87
+ for (const key of keys) {
88
+ if (!isKnownRedisQueueKey(key)) continue;
89
+ let pending = 0;
90
+ try {
91
+ pending = Number(await redis.sendCommand(["LLEN", key])) || 0;
92
+ } catch {
93
+ pending = 0;
94
+ }
95
+ queues.push({
96
+ source: "redis",
97
+ key,
98
+ type: "list",
99
+ pending,
100
+ ...describeRedisQueueKey(key)
101
+ });
102
+ }
103
+ return {
104
+ connected: true,
105
+ urlConfigured: true,
106
+ queues,
107
+ totalPending: queues.reduce((sum, queue) => sum + (queue.pending || 0), 0)
108
+ };
109
+ }
110
+ function parseRedisQueueMessage(raw, key, index) {
111
+ let content = raw;
112
+ try {
113
+ content = JSON.parse(raw);
114
+ } catch {
115
+ }
116
+ const queuedAt = (content == null ? void 0 : content.queuedAt) ? Date.parse(content.queuedAt) : null;
117
+ return {
118
+ id: `${key}:${index}`,
119
+ index,
120
+ content,
121
+ raw,
122
+ timestamp: Number.isFinite(queuedAt) ? queuedAt : null
123
+ };
124
+ }
32
125
  const eventQueueActions = {
33
126
  /**
34
127
  * GET /clusterManagerQueue:stats
@@ -61,11 +154,13 @@ const eventQueueActions = {
61
154
  }
62
155
  }
63
156
  const totalPending = channels.reduce((sum, c) => sum + (c.pending || 0), 0);
157
+ const redisQueues = await getRedisQueues(ctx);
64
158
  ctx.body = {
65
159
  adapter: adapterName,
66
160
  connected,
67
161
  totalChannels: channels.length,
68
162
  totalPending,
163
+ redisQueues,
69
164
  channels
70
165
  };
71
166
  await next();
@@ -80,7 +175,34 @@ const eventQueueActions = {
80
175
  if (!eq) {
81
176
  ctx.throw(503, "Event queue is not available");
82
177
  }
83
- const { channel, page = 1, pageSize = 20 } = ctx.action.params;
178
+ const { channel, key, source, page = 1, pageSize = 20 } = ctx.action.params;
179
+ if (source === "redis") {
180
+ const redisKey = String(key || channel || "");
181
+ if (!redisKey || !isKnownRedisQueueKey(redisKey)) {
182
+ ctx.throw(400, "Invalid Redis queue key");
183
+ }
184
+ const redis = await getQueueRedis(ctx);
185
+ if (!redis) {
186
+ ctx.body = {
187
+ data: [],
188
+ meta: { count: 0, page: 1, pageSize: 20, note: "Redis queue connection is not configured" }
189
+ };
190
+ await next();
191
+ return;
192
+ }
193
+ const currentPage = Number(page);
194
+ const currentPageSize = Number(pageSize);
195
+ const start2 = (currentPage - 1) * currentPageSize;
196
+ const end = start2 + currentPageSize - 1;
197
+ const count = Number(await redis.sendCommand(["LLEN", redisKey])) || 0;
198
+ const rows = await redis.sendCommand(["LRANGE", redisKey, String(start2), String(end)]);
199
+ ctx.body = {
200
+ data: rows.map((raw, offset) => parseRedisQueueMessage(raw, redisKey, start2 + offset)),
201
+ meta: { count, page: currentPage, pageSize: currentPageSize, source: "redis", key: redisKey }
202
+ };
203
+ await next();
204
+ return;
205
+ }
84
206
  const adapter = eq.adapter;
85
207
  if (!(adapter == null ? void 0 : adapter.queues)) {
86
208
  ctx.body = {
@@ -33,7 +33,7 @@ var import_redis = require("../utils/redis");
33
33
  function getAdapter(ctx) {
34
34
  const plugin = ctx.app.pm.get("plugin-cluster-manager");
35
35
  if (!(plugin == null ? void 0 : plugin.orchestrator)) {
36
- ctx.throw(503, "Orchestrator adapter not configured. Configure it in Worker Monitor settings.");
36
+ ctx.throw(503, "Orchestrator adapter not configured. Configure it in Cluster Manager settings.");
37
37
  }
38
38
  return plugin.orchestrator;
39
39
  }
@@ -237,6 +237,25 @@ const orchestratorActions = {
237
237
  ctx.throw(404, `Container ${containerId} not found: ${err.message}`);
238
238
  }
239
239
  await next();
240
+ },
241
+ /**
242
+ * GET /workerOrchestrator:networks
243
+ * List available networks (if supported by adapter)
244
+ */
245
+ async networks(ctx, next) {
246
+ const adapter = getAdapter(ctx);
247
+ if (!adapter.listNetworks) {
248
+ ctx.body = { data: [] };
249
+ } else {
250
+ try {
251
+ const networks = await adapter.listNetworks();
252
+ ctx.body = { data: networks };
253
+ } catch (err) {
254
+ ctx.app.logger.warn(`Failed to list networks: ${err.message}`);
255
+ ctx.body = { data: [] };
256
+ }
257
+ }
258
+ await next();
240
259
  }
241
260
  };
242
261
  // Annotate the CommonJS export names for ESM import in node:
@@ -0,0 +1,171 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var plugin_operations_exports = {};
28
+ __export(plugin_operations_exports, {
29
+ pluginOperationsActions: () => pluginOperationsActions
30
+ });
31
+ module.exports = __toCommonJS(plugin_operations_exports);
32
+ const PROTECTED_PLUGIN_NAMES = /* @__PURE__ */ new Set(["nocobase", "plugin-cluster-manager"]);
33
+ const PROTECTED_PACKAGE_NAMES = /* @__PURE__ */ new Set(["nocobase", "@nocobase/preset-nocobase", "plugin-cluster-manager"]);
34
+ function getPayload(ctx) {
35
+ var _a, _b, _c;
36
+ return ctx.action.params.values || ((_b = (_a = ctx.request) == null ? void 0 : _a.body) == null ? void 0 : _b.values) || ((_c = ctx.request) == null ? void 0 : _c.body) || {};
37
+ }
38
+ function pluginDisplayName(plugin) {
39
+ return plugin.displayName || plugin.name || plugin.packageName;
40
+ }
41
+ function isProtectedPlugin(plugin) {
42
+ return PROTECTED_PLUGIN_NAMES.has(plugin.name) || PROTECTED_PACKAGE_NAMES.has(plugin.packageName);
43
+ }
44
+ async function getApplicationPlugins(ctx) {
45
+ const repo = ctx.db.getRepository("applicationPlugins");
46
+ const rows = await repo.find({ sort: ["name"] });
47
+ return rows.map((row) => row.toJSON());
48
+ }
49
+ async function findPlugin(ctx, requestedName) {
50
+ const name = String(requestedName || "").trim();
51
+ if (!name) {
52
+ ctx.throw(400, "Plugin name is required.");
53
+ }
54
+ const plugins = await getApplicationPlugins(ctx);
55
+ const plugin = plugins.find((item) => item.name === name || item.packageName === name);
56
+ if (!plugin) {
57
+ ctx.throw(404, `Plugin "${name}" was not found in applicationPlugins.`);
58
+ }
59
+ return plugin;
60
+ }
61
+ async function getLoadedPluginInfo(ctx, plugin, locale) {
62
+ var _a, _b, _c, _d, _e, _f, _g;
63
+ const pm = ctx.app.pm;
64
+ const instance = ((_a = pm == null ? void 0 : pm.get) == null ? void 0 : _a.call(pm, plugin.name)) || ((_b = pm == null ? void 0 : pm.get) == null ? void 0 : _b.call(pm, plugin.packageName));
65
+ if (!instance) {
66
+ return {};
67
+ }
68
+ try {
69
+ return await instance.toJSON({ locale, withOutOpenFile: true });
70
+ } catch {
71
+ return {
72
+ name: instance.name,
73
+ packageName: (_c = instance.options) == null ? void 0 : _c.packageName,
74
+ displayName: (_e = (_d = instance.options) == null ? void 0 : _d.packageJson) == null ? void 0 : _e.displayName,
75
+ description: (_g = (_f = instance.options) == null ? void 0 : _f.packageJson) == null ? void 0 : _g.description
76
+ };
77
+ }
78
+ }
79
+ async function getPackageInfo(ctx, plugin, locale) {
80
+ var _a;
81
+ const loadedInfo = await getLoadedPluginInfo(ctx, plugin, locale);
82
+ if (loadedInfo.displayName || loadedInfo.description) {
83
+ return loadedInfo;
84
+ }
85
+ try {
86
+ const pmCtor = (_a = ctx.app.pm) == null ? void 0 : _a.constructor;
87
+ const pkgJson = await pmCtor.getPackageJson(plugin.packageName);
88
+ return {
89
+ displayName: (pkgJson == null ? void 0 : pkgJson[`displayName.${locale}`]) || (pkgJson == null ? void 0 : pkgJson.displayName) || plugin.name,
90
+ description: (pkgJson == null ? void 0 : pkgJson[`description.${locale}`]) || (pkgJson == null ? void 0 : pkgJson.description),
91
+ keywords: pkgJson == null ? void 0 : pkgJson.keywords
92
+ };
93
+ } catch {
94
+ return {};
95
+ }
96
+ }
97
+ const pluginOperationsActions = {
98
+ async list(ctx, next) {
99
+ var _a;
100
+ const locale = ((_a = ctx.getCurrentLocale) == null ? void 0 : _a.call(ctx)) || "en-US";
101
+ const plugins = await getApplicationPlugins(ctx);
102
+ const data = await Promise.all(
103
+ plugins.map(async (plugin) => {
104
+ var _a2, _b, _c, _d;
105
+ const info = await getPackageInfo(ctx, plugin, locale);
106
+ const loaded = Boolean(((_b = (_a2 = ctx.app.pm) == null ? void 0 : _a2.get) == null ? void 0 : _b.call(_a2, plugin.name)) || ((_d = (_c = ctx.app.pm) == null ? void 0 : _c.get) == null ? void 0 : _d.call(_c, plugin.packageName)));
107
+ return {
108
+ ...plugin,
109
+ displayName: info.displayName || plugin.name,
110
+ description: info.description || "",
111
+ keywords: info.keywords || [],
112
+ loaded,
113
+ protected: isProtectedPlugin(plugin)
114
+ };
115
+ })
116
+ );
117
+ ctx.body = {
118
+ data,
119
+ meta: { count: data.length }
120
+ };
121
+ await next();
122
+ },
123
+ async forceDisable(ctx, next) {
124
+ var _a, _b, _c, _d;
125
+ const payload = getPayload(ctx);
126
+ const plugin = await findPlugin(ctx, payload.name || payload.packageName || ctx.action.params.filterByTk);
127
+ if (isProtectedPlugin(plugin)) {
128
+ ctx.throw(400, `Plugin "${pluginDisplayName(plugin)}" is protected and cannot be disabled from Cluster Manager.`);
129
+ }
130
+ const repo = ctx.db.getRepository("applicationPlugins");
131
+ await repo.update({
132
+ filter: { name: plugin.name },
133
+ values: { enabled: false }
134
+ });
135
+ const instance = ((_b = (_a = ctx.app.pm) == null ? void 0 : _a.get) == null ? void 0 : _b.call(_a, plugin.name)) || ((_d = (_c = ctx.app.pm) == null ? void 0 : _c.get) == null ? void 0 : _d.call(_c, plugin.packageName));
136
+ if (instance) {
137
+ instance.enabled = false;
138
+ }
139
+ ctx.body = {
140
+ success: true,
141
+ name: plugin.name,
142
+ packageName: plugin.packageName,
143
+ restartRequired: true,
144
+ message: `Plugin "${pluginDisplayName(plugin)}" was force disabled. Restart or reload the app to fully unload it.`
145
+ };
146
+ await next();
147
+ },
148
+ async forceRemove(ctx, next) {
149
+ const payload = getPayload(ctx);
150
+ const plugin = await findPlugin(ctx, payload.name || payload.packageName || ctx.action.params.filterByTk);
151
+ if (isProtectedPlugin(plugin)) {
152
+ ctx.throw(400, `Plugin "${pluginDisplayName(plugin)}" is protected and cannot be removed from Cluster Manager.`);
153
+ }
154
+ const repo = ctx.db.getRepository("applicationPlugins");
155
+ await repo.destroy({
156
+ filter: { name: plugin.name }
157
+ });
158
+ ctx.body = {
159
+ success: true,
160
+ name: plugin.name,
161
+ packageName: plugin.packageName,
162
+ restartRequired: true,
163
+ message: `Plugin "${pluginDisplayName(plugin)}" was force removed from the application registry. Package files were not deleted.`
164
+ };
165
+ await next();
166
+ }
167
+ };
168
+ // Annotate the CommonJS export names for ESM import in node:
169
+ 0 && (module.exports = {
170
+ pluginOperationsActions
171
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var app_exports = {};
28
+ __export(app_exports, {
29
+ default: () => app_default
30
+ });
31
+ module.exports = __toCommonJS(app_exports);
32
+ var app_default = {
33
+ name: "app",
34
+ autoCreate: false,
35
+ dumpRules: "skip",
36
+ model: "Collection",
37
+ fields: []
38
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var cluster_manager_acl_cache_exports = {};
28
+ __export(cluster_manager_acl_cache_exports, {
29
+ default: () => cluster_manager_acl_cache_default
30
+ });
31
+ module.exports = __toCommonJS(cluster_manager_acl_cache_exports);
32
+ var cluster_manager_acl_cache_default = {
33
+ name: "clusterManagerAclCache",
34
+ dumpRules: "skip",
35
+ autoGenId: true,
36
+ createdAt: false,
37
+ updatedAt: false,
38
+ fields: [
39
+ {
40
+ name: "name",
41
+ type: "string"
42
+ }
43
+ ]
44
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var cluster_manager_cache_mgr_exports = {};
28
+ __export(cluster_manager_cache_mgr_exports, {
29
+ default: () => cluster_manager_cache_mgr_default
30
+ });
31
+ module.exports = __toCommonJS(cluster_manager_cache_mgr_exports);
32
+ var cluster_manager_cache_mgr_default = {
33
+ name: "clusterManagerCacheMgr",
34
+ dumpRules: "skip",
35
+ autoGenId: true,
36
+ createdAt: false,
37
+ updatedAt: false,
38
+ fields: [
39
+ {
40
+ name: "name",
41
+ type: "string"
42
+ }
43
+ ]
44
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var cluster_manager_cluster_exports = {};
28
+ __export(cluster_manager_cluster_exports, {
29
+ default: () => cluster_manager_cluster_default
30
+ });
31
+ module.exports = __toCommonJS(cluster_manager_cluster_exports);
32
+ var cluster_manager_cluster_default = {
33
+ name: "clusterManagerCluster",
34
+ dumpRules: "skip",
35
+ autoGenId: true,
36
+ createdAt: false,
37
+ updatedAt: false,
38
+ fields: [
39
+ {
40
+ name: "name",
41
+ type: "string"
42
+ }
43
+ ]
44
+ };