@nocobase/server 2.1.0-beta.9 → 2.2.0-beta.1

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 (64) hide show
  1. package/lib/acl/available-action.js +1 -1
  2. package/lib/aes-encryptor.js +3 -2
  3. package/lib/app-supervisor/app-options-factory.d.ts +1 -0
  4. package/lib/app-supervisor/index.d.ts +13 -5
  5. package/lib/app-supervisor/index.js +48 -13
  6. package/lib/app-supervisor/main-only-adapter.d.ts +3 -0
  7. package/lib/app-supervisor/main-only-adapter.js +7 -0
  8. package/lib/app-supervisor/types.d.ts +18 -3
  9. package/lib/application.d.ts +1 -2
  10. package/lib/application.js +3 -24
  11. package/lib/audit-manager/index.d.ts +2 -0
  12. package/lib/audit-manager/index.js +5 -2
  13. package/lib/commands/ai.js +1 -6
  14. package/lib/commands/create-migration.js +1 -1
  15. package/lib/commands/install.js +0 -4
  16. package/lib/commands/pm.js +7 -0
  17. package/lib/commands/start.js +2 -5
  18. package/lib/commands/upgrade.js +0 -4
  19. package/lib/{ai/create-docs-index.d.ts → constants.d.ts} +1 -5
  20. package/lib/constants.js +36 -0
  21. package/lib/event-queue.js +1 -1
  22. package/lib/gateway/index.d.ts +15 -3
  23. package/lib/gateway/index.js +180 -20
  24. package/lib/gateway/static-file-security.d.ts +10 -0
  25. package/lib/gateway/static-file-security.js +69 -0
  26. package/lib/gateway/utils.d.ts +19 -0
  27. package/lib/gateway/utils.js +128 -0
  28. package/lib/helpers/application-version.js +1 -0
  29. package/lib/index.d.ts +3 -1
  30. package/lib/index.js +5 -4
  31. package/lib/locale/locale.d.ts +24 -0
  32. package/lib/locale/locale.js +29 -5
  33. package/lib/main-data-source.js +12 -5
  34. package/lib/plugin-manager/constants.js +1 -1
  35. package/lib/plugin-manager/deps.js +3 -2
  36. package/lib/plugin-manager/findPackageNames.d.ts +5 -5
  37. package/lib/plugin-manager/findPackageNames.js +35 -58
  38. package/lib/plugin-manager/options/collection.js +1 -0
  39. package/lib/plugin-manager/options/resource.d.ts +12 -1
  40. package/lib/plugin-manager/options/resource.js +210 -65
  41. package/lib/plugin-manager/plugin-manager.d.ts +7 -2
  42. package/lib/plugin-manager/plugin-manager.js +59 -81
  43. package/lib/plugin-manager/utils.d.ts +9 -1
  44. package/lib/plugin-manager/utils.js +67 -9
  45. package/lib/plugin.js +33 -2
  46. package/lib/pub-sub-manager/handler-manager.d.ts +1 -0
  47. package/lib/pub-sub-manager/handler-manager.js +11 -0
  48. package/lib/pub-sub-manager/pub-sub-manager.js +2 -1
  49. package/lib/swagger/app.d.ts +102 -0
  50. package/lib/swagger/app.js +124 -0
  51. package/lib/swagger/base.d.ts +244 -0
  52. package/lib/swagger/base.js +292 -0
  53. package/lib/swagger/collections.d.ts +996 -0
  54. package/lib/swagger/collections.js +1264 -0
  55. package/lib/swagger/index.d.ts +1774 -0
  56. package/lib/swagger/index.js +70 -0
  57. package/lib/swagger/pm.d.ts +462 -0
  58. package/lib/swagger/pm.js +422 -0
  59. package/lib/sync-message-manager.js +8 -1
  60. package/lib/worker-mode.d.ts +19 -0
  61. package/lib/worker-mode.js +67 -0
  62. package/package.json +18 -18
  63. package/lib/ai/create-docs-index.js +0 -892
  64. package/lib/swagger/index.json +0 -1569
@@ -39,59 +39,193 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
39
39
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
40
40
  var resource_exports = {};
41
41
  __export(resource_exports, {
42
+ PackageUrls: () => PackageUrls,
42
43
  default: () => resource_default
43
44
  });
44
45
  module.exports = __toCommonJS(resource_exports);
45
46
  var import_utils = require("@nocobase/utils");
47
+ var import_crypto = __toESM(require("crypto"));
46
48
  var import_fs = __toESM(require("fs"));
47
49
  var import_fs_extra = __toESM(require("fs-extra"));
48
50
  var import_path = __toESM(require("path"));
49
- var import_crypto = __toESM(require("crypto"));
51
+ var import_plugin_manager = __toESM(require("../plugin-manager"));
52
+ var import_utils2 = require("../utils");
50
53
  var import_package = __toESM(require("../../../package.json"));
54
+ const PLUGIN_CLIENT_ENTRY_FILES = {
55
+ client: "dist/client/index.js",
56
+ "client-v2": "dist/client-v2/index.js"
57
+ };
58
+ const PLUGIN_CLIENT_MARKER_FILES = {
59
+ client: "client.js",
60
+ "client-v2": "client-v2.js"
61
+ };
62
+ function getAppDevPluginUrls() {
63
+ if (process.env.NOCOBASE_APP_DEV !== "true" || !process.env.NOCOBASE_APP_DEV_PLUGIN_URLS) {
64
+ return {};
65
+ }
66
+ try {
67
+ return JSON.parse(process.env.NOCOBASE_APP_DEV_PLUGIN_URLS);
68
+ } catch (error) {
69
+ return {};
70
+ }
71
+ }
72
+ __name(getAppDevPluginUrls, "getAppDevPluginUrls");
73
+ function getAppDevPluginDependencies(packageJson2, lane) {
74
+ const appDevPluginUrls = getAppDevPluginUrls();
75
+ const deps = {
76
+ ...packageJson2.dependencies,
77
+ ...packageJson2.peerDependencies,
78
+ ...packageJson2.devDependencies
79
+ };
80
+ return Object.keys(deps).filter(
81
+ (packageName) => {
82
+ var _a;
83
+ return ((_a = appDevPluginUrls[packageName]) == null ? void 0 : _a[lane]) || packageName.startsWith("@nocobase/plugin-") || packageName.startsWith("@nocobase/preset-");
84
+ }
85
+ );
86
+ }
87
+ __name(getAppDevPluginDependencies, "getAppDevPluginDependencies");
51
88
  const _PackageUrls = class _PackageUrls {
52
- static async get(packageName) {
53
- if (!this.items[packageName]) {
54
- this.items[packageName] = await this.fetch(packageName);
89
+ static clear() {
90
+ this.items = {};
91
+ }
92
+ static getCacheKey(packageName, lane) {
93
+ return `${lane}:${packageName}`;
94
+ }
95
+ static async get(packageName, lane = "client") {
96
+ const appDevUrl = this.getAppDevUrl(packageName, lane);
97
+ if (appDevUrl) {
98
+ return appDevUrl;
99
+ }
100
+ const cacheKey = this.getCacheKey(packageName, lane);
101
+ const cached = this.items[cacheKey];
102
+ if (cached) {
103
+ return cached;
55
104
  }
56
- return this.items[packageName];
105
+ const nextUrl = await this.fetch(packageName, lane);
106
+ if (nextUrl == null ? void 0 : nextUrl.includes("?hash=")) {
107
+ this.items[cacheKey] = nextUrl;
108
+ } else {
109
+ delete this.items[cacheKey];
110
+ }
111
+ return nextUrl;
112
+ }
113
+ static getAppDevUrl(packageName, lane) {
114
+ var _a;
115
+ return (_a = getAppDevPluginUrls()[packageName]) == null ? void 0 : _a[lane];
57
116
  }
58
- static async fetch(packageName) {
59
- const PLUGIN_CLIENT_ENTRY_FILE = "dist/client/index.js";
117
+ static async hasClientEntry(packageName, lane) {
118
+ if (this.getAppDevUrl(packageName, lane)) {
119
+ return true;
120
+ }
60
121
  const pkgPath = import_path.default.resolve(process.env.NODE_MODULES_PATH, packageName);
61
- const r = await import_fs_extra.default.exists(pkgPath);
62
- if (r) {
63
- let t = "";
64
- const dist = import_path.default.resolve(pkgPath, PLUGIN_CLIENT_ENTRY_FILE);
65
- const distExists = await import_fs_extra.default.exists(dist);
66
- if (distExists) {
67
- const fsState = await import_fs_extra.default.stat(distExists ? dist : pkgPath);
68
- const appKey = process.env.APP_KEY || "";
69
- let version = "";
70
- try {
71
- const pkgJson = await import_fs_extra.default.readJson(import_path.default.resolve(pkgPath, "package.json"));
72
- if (pkgJson && typeof pkgJson.version === "string") {
73
- version = pkgJson.version;
74
- }
75
- } catch (error) {
122
+ if (!await import_fs_extra.default.exists(pkgPath)) {
123
+ return false;
124
+ }
125
+ return await import_fs_extra.default.exists(import_path.default.resolve(pkgPath, PLUGIN_CLIENT_MARKER_FILES[lane]));
126
+ }
127
+ static async fetch(packageName, lane = "client") {
128
+ const pluginClientEntryFile = PLUGIN_CLIENT_ENTRY_FILES[lane];
129
+ const pkgPath = import_path.default.resolve(process.env.NODE_MODULES_PATH, packageName);
130
+ const pkgExists = await import_fs_extra.default.exists(pkgPath);
131
+ if (!pkgExists) {
132
+ return;
133
+ }
134
+ let t = "";
135
+ const dist = import_path.default.resolve(pkgPath, pluginClientEntryFile);
136
+ const distExists = await import_fs_extra.default.exists(dist);
137
+ if (distExists) {
138
+ const fsState = await import_fs_extra.default.stat(dist);
139
+ const appKey = process.env.APP_KEY || "";
140
+ let version = "";
141
+ try {
142
+ const pkgJson = await import_fs_extra.default.readJson(import_path.default.resolve(pkgPath, "package.json"));
143
+ if (pkgJson && typeof pkgJson.version === "string") {
144
+ version = pkgJson.version;
76
145
  }
77
- const appVersion = import_package.default.version;
78
- const salt = process.env.PLUGIN_URL_HASH_SALT || "";
79
- const hash = import_crypto.default.createHash("sha256").update(fsState.mtime.getTime() + appKey + version + appVersion + salt).digest("hex").slice(0, 8);
80
- t = `?hash=${hash}`;
81
- }
82
- const cdnBaseUrl = process.env.CDN_BASE_URL.replace(/\/+$/, "");
83
- const url = `${cdnBaseUrl}${"/static/plugins/"}${packageName}/${PLUGIN_CLIENT_ENTRY_FILE}${t}`;
84
- return url;
146
+ } catch (error) {
147
+ }
148
+ const appVersion = import_package.default.version;
149
+ const salt = process.env.PLUGIN_URL_HASH_SALT || "";
150
+ const hash = import_crypto.default.createHash("sha256").update(fsState.mtime.getTime() + appKey + version + appVersion + salt).digest("hex").slice(0, 8);
151
+ t = `?hash=${hash}`;
85
152
  }
153
+ const cdnBaseUrl = process.env.CDN_BASE_URL.replace(/\/+$/, "");
154
+ const url = `${cdnBaseUrl}${"/static/plugins/"}${packageName}/${pluginClientEntryFile}${t}`;
155
+ return url;
86
156
  }
87
157
  };
88
158
  __name(_PackageUrls, "PackageUrls");
89
159
  __publicField(_PackageUrls, "items", {});
90
160
  let PackageUrls = _PackageUrls;
161
+ async function listEnabledPlugins(ctx, lane = "client") {
162
+ const pm = ctx.db.getRepository("applicationPlugins");
163
+ const items = await pm.find({
164
+ filter: {
165
+ enabled: true
166
+ }
167
+ });
168
+ const arr = [];
169
+ for (const item of items) {
170
+ if (lane === "client-v2" && !await PackageUrls.hasClientEntry(item.packageName, lane)) {
171
+ continue;
172
+ }
173
+ const url = await PackageUrls.get(item.packageName, lane);
174
+ const { name, packageName, options } = item.toJSON();
175
+ if (url) {
176
+ const entry = {
177
+ name,
178
+ packageName,
179
+ options,
180
+ url
181
+ };
182
+ if (PackageUrls.getAppDevUrl(packageName, lane)) {
183
+ const packageJson2 = await import_plugin_manager.default.getPackageJson(packageName);
184
+ entry.devMode = "esm";
185
+ entry.appDevDependencies = getAppDevPluginDependencies(packageJson2, lane);
186
+ }
187
+ if (lane === "client" && await PackageUrls.hasClientEntry(packageName, "client-v2")) {
188
+ const clientV2Url = await PackageUrls.get(packageName, "client-v2");
189
+ if (clientV2Url) {
190
+ entry.clientV2Url = clientV2Url;
191
+ }
192
+ }
193
+ arr.push(entry);
194
+ }
195
+ }
196
+ return arr;
197
+ }
198
+ __name(listEnabledPlugins, "listEnabledPlugins");
199
+ function normalizePmPluginKeys(filterByTk) {
200
+ if (typeof filterByTk === "string") {
201
+ return filterByTk.split(",").map((k) => k.trim()).filter(Boolean);
202
+ }
203
+ if (!Array.isArray(filterByTk) || filterByTk.some((item) => typeof item !== "string")) {
204
+ return [];
205
+ }
206
+ return filterByTk.flatMap(
207
+ (item) => item.split(",").map((k) => k.trim()).filter(Boolean)
208
+ );
209
+ }
210
+ __name(normalizePmPluginKeys, "normalizePmPluginKeys");
211
+ function coerceAwaitResponse(value) {
212
+ if (value === true || value === 1) {
213
+ return true;
214
+ }
215
+ if (typeof value === "string") {
216
+ const v = value.trim().toLowerCase();
217
+ return v === "true" || v === "1" || v === "yes";
218
+ }
219
+ return false;
220
+ }
221
+ __name(coerceAwaitResponse, "coerceAwaitResponse");
91
222
  var resource_default = {
92
223
  name: "pm",
93
224
  actions: {
94
225
  async add(ctx, next) {
226
+ if (process.env.DISABLE_PM_ADD === "true") {
227
+ ctx.throw(403, "The current environment does not allow adding plugins online");
228
+ }
95
229
  const app = ctx.app;
96
230
  const { values = {} } = ctx.action.params;
97
231
  if (values == null ? void 0 : values.packageName) {
@@ -107,12 +241,12 @@ var resource_default = {
107
241
  }
108
242
  app.runAsCLI(["pm", "add", values.packageName, ...args], { from: "user" });
109
243
  } else if (ctx.file) {
110
- const tmpDir = import_path.default.resolve(process.cwd(), "storage", "tmp");
244
+ const tmpDir = (0, import_utils.storagePathJoin)("tmp");
111
245
  try {
112
246
  await import_fs.default.promises.mkdir(tmpDir, { recursive: true });
113
247
  } catch (error) {
114
248
  }
115
- const tempFile = import_path.default.join(process.cwd(), "storage/tmp", (0, import_utils.uid)() + import_path.default.extname(ctx.file.originalname));
249
+ const tempFile = import_path.default.join(tmpDir, (0, import_utils.uid)() + import_path.default.extname(ctx.file.originalname));
116
250
  await import_fs.default.promises.writeFile(tempFile, ctx.file.buffer, "binary");
117
251
  app.runAsCLI(["pm", "add", tempFile], { from: "user" });
118
252
  } else if (values.compressedFileUrl) {
@@ -122,6 +256,9 @@ var resource_default = {
122
256
  await next();
123
257
  },
124
258
  async update(ctx, next) {
259
+ if (process.env.DISABLE_PM_ADD === "true") {
260
+ ctx.throw(403, "The current environment does not allow adding plugins online");
261
+ }
125
262
  const app = ctx.app;
126
263
  const values = ctx.action.params.values || {};
127
264
  const args = [];
@@ -136,12 +273,12 @@ var resource_default = {
136
273
  }
137
274
  if (ctx.file) {
138
275
  values.packageName = ctx.request.body.packageName;
139
- const tmpDir = import_path.default.resolve(process.cwd(), "storage", "tmp");
276
+ const tmpDir = (0, import_utils.storagePathJoin)("tmp");
140
277
  try {
141
278
  await import_fs.default.promises.mkdir(tmpDir, { recursive: true });
142
279
  } catch (error) {
143
280
  }
144
- const tempFile = import_path.default.join(process.cwd(), "storage/tmp", (0, import_utils.uid)() + import_path.default.extname(ctx.file.originalname));
281
+ const tempFile = import_path.default.join(tmpDir, (0, import_utils.uid)() + import_path.default.extname(ctx.file.originalname));
145
282
  await import_fs.default.promises.writeFile(tempFile, ctx.file.buffer, "binary");
146
283
  values.compressedFileUrl = tempFile;
147
284
  }
@@ -159,23 +296,40 @@ var resource_default = {
159
296
  await next();
160
297
  },
161
298
  async enable(ctx, next) {
162
- const { filterByTk } = ctx.action.params;
299
+ const { filterByTk, awaitResponse: awaitResponseRaw } = ctx.action.params;
163
300
  const app = ctx.app;
164
- if (!filterByTk) {
301
+ const keys = normalizePmPluginKeys(filterByTk);
302
+ if (!keys.length) {
165
303
  ctx.throw(400, "plugin name invalid");
166
304
  }
167
- const keys = Array.isArray(filterByTk) ? filterByTk : [filterByTk];
168
- app.runAsCLI(["pm", "enable", ...keys], { from: "user" });
305
+ const awaitResponse = coerceAwaitResponse(awaitResponseRaw);
306
+ const argv = ["pm", "enable", ...keys];
307
+ if (awaitResponse) {
308
+ await app.runAsCLI(argv, { from: "user", throwError: true });
309
+ } else {
310
+ void app.runAsCLI(argv, { from: "user" }).catch((err) => {
311
+ app.log.error(err);
312
+ });
313
+ }
169
314
  ctx.body = filterByTk;
170
315
  await next();
171
316
  },
172
317
  async disable(ctx, next) {
173
- const { filterByTk } = ctx.action.params;
174
- if (!filterByTk) {
318
+ const { filterByTk, awaitResponse: awaitResponseRaw } = ctx.action.params;
319
+ const app = ctx.app;
320
+ const keys = normalizePmPluginKeys(filterByTk);
321
+ if (!keys.length) {
175
322
  ctx.throw(400, "plugin name invalid");
176
323
  }
177
- const app = ctx.app;
178
- app.runAsCLI(["pm", "disable", filterByTk], { from: "user" });
324
+ const awaitResponse = coerceAwaitResponse(awaitResponseRaw);
325
+ const argv = ["pm", "disable", ...keys];
326
+ if (awaitResponse) {
327
+ await app.runAsCLI(argv, { from: "user", throwError: true });
328
+ } else {
329
+ void app.runAsCLI(argv, { from: "user" }).catch((err) => {
330
+ app.log.error(err);
331
+ });
332
+ }
179
333
  ctx.body = filterByTk;
180
334
  await next();
181
335
  },
@@ -190,6 +344,11 @@ var resource_default = {
190
344
  await next();
191
345
  },
192
346
  async list(ctx, next) {
347
+ const { mode } = ctx.action.params;
348
+ if (mode === "summary") {
349
+ ctx.body = await (0, import_utils2.pmListSummary)(ctx.app);
350
+ return next();
351
+ }
193
352
  const locale = ctx.getCurrentLocale();
194
353
  const pm = ctx.app.pm;
195
354
  const plugin = pm.get("nocobase");
@@ -197,29 +356,11 @@ var resource_default = {
197
356
  await next();
198
357
  },
199
358
  async listEnabled(ctx, next) {
200
- const toArr = /* @__PURE__ */ __name(async () => {
201
- const pm = ctx.db.getRepository("applicationPlugins");
202
- const items = await pm.find({
203
- filter: {
204
- enabled: true
205
- }
206
- });
207
- const arr = [];
208
- for (const item of items) {
209
- const url = await PackageUrls.get(item.packageName);
210
- const { name, packageName, options } = item.toJSON();
211
- if (url) {
212
- arr.push({
213
- name,
214
- packageName,
215
- options,
216
- url
217
- });
218
- }
219
- }
220
- return arr;
221
- }, "toArr");
222
- ctx.body = await toArr();
359
+ ctx.body = await listEnabledPlugins(ctx, "client");
360
+ await next();
361
+ },
362
+ async listEnabledV2(ctx, next) {
363
+ ctx.body = await listEnabledPlugins(ctx, "client-v2");
223
364
  await next();
224
365
  },
225
366
  async get(ctx, next) {
@@ -235,3 +376,7 @@ var resource_default = {
235
376
  }
236
377
  }
237
378
  };
379
+ // Annotate the CommonJS export names for ESM import in node:
380
+ 0 && (module.exports = {
381
+ PackageUrls
382
+ });
@@ -13,7 +13,6 @@ import Application from '../application';
13
13
  import { Plugin } from '../plugin';
14
14
  import { PluginManagerRepository } from './plugin-manager-repository';
15
15
  import { PluginData } from './types';
16
- import { checkAndGetCompatible } from './utils';
17
16
  export declare const sleep: (timeout?: number) => Promise<unknown>;
18
17
  export interface PluginManagerOptions {
19
18
  app: Application;
@@ -29,7 +28,12 @@ export declare class AddPresetError extends Error {
29
28
  }
30
29
  export declare class PluginManager {
31
30
  options: PluginManagerOptions;
32
- static checkAndGetCompatible: typeof checkAndGetCompatible;
31
+ private static compatibleCache;
32
+ private static compatiblePending;
33
+ static checkAndGetCompatible(packageName: string): Promise<{
34
+ isCompatible: boolean;
35
+ depsCompatible: import("./utils").DepCompatible[];
36
+ }>;
33
37
  /**
34
38
  * @internal
35
39
  */
@@ -95,6 +99,7 @@ export declare class PluginManager {
95
99
  create(pluginName: string, options?: {
96
100
  forceRecreate?: boolean;
97
101
  }): Promise<void>;
102
+ addOrThrow(plugin?: string | typeof Plugin, options?: any, insert?: boolean, isUpgrade?: boolean): Promise<void>;
98
103
  add(plugin?: string | typeof Plugin, options?: any, insert?: boolean, isUpgrade?: boolean): Promise<void>;
99
104
  /**
100
105
  * @internal
@@ -57,6 +57,7 @@ var import_middleware = require("./middleware");
57
57
  var import_collection = __toESM(require("./options/collection"));
58
58
  var import_resource = __toESM(require("./options/resource"));
59
59
  var import_plugin_manager_repository = require("./plugin-manager-repository");
60
+ var import_plugin_package = require("../../../utils/plugin-package");
60
61
  var import_utils2 = require("./utils");
61
62
  const _PluginLoadError = class _PluginLoadError extends Error {
62
63
  constructor(pluginName) {
@@ -90,6 +91,7 @@ const _PluginManager = class _PluginManager {
90
91
  this._repository.setPluginManager(this);
91
92
  this.app.resourcer.define(import_resource.default);
92
93
  this.app.acl.allow("pm", "listEnabled", "public");
94
+ this.app.acl.allow("pm", "listEnabledV2", "public");
93
95
  this.app.acl.registerSnippet({
94
96
  name: "pm",
95
97
  actions: ["pm:*"]
@@ -100,6 +102,23 @@ const _PluginManager = class _PluginManager {
100
102
  });
101
103
  this.app.resourceManager.use(import_middleware.uploadMiddleware, { tag: "upload", after: "acl" });
102
104
  }
105
+ static async checkAndGetCompatible(packageName) {
106
+ if (this.compatibleCache.has(packageName)) {
107
+ return this.compatibleCache.get(packageName);
108
+ }
109
+ const pending = this.compatiblePending.get(packageName);
110
+ if (pending) {
111
+ return pending;
112
+ }
113
+ const task = (0, import_utils2.checkAndGetCompatible)(packageName).then((compatible) => {
114
+ this.compatibleCache.set(packageName, compatible);
115
+ return compatible;
116
+ }).finally(() => {
117
+ this.compatiblePending.delete(packageName);
118
+ });
119
+ this.compatiblePending.set(packageName, task);
120
+ return task;
121
+ }
103
122
  /**
104
123
  * @internal
105
124
  */
@@ -137,7 +156,11 @@ const _PluginManager = class _PluginManager {
137
156
  */
138
157
  static async getPackageJson(nameOrPkg) {
139
158
  const { packageName } = await this.parseName(nameOrPkg);
140
- const packageFile = (0, import_path.resolve)(process.env.NODE_MODULES_PATH, packageName, "package.json");
159
+ const nodeModulesPath = String(process.env.NODE_MODULES_PATH ?? "").trim();
160
+ if (!nodeModulesPath) {
161
+ throw new Error("NODE_MODULES_PATH is not configured");
162
+ }
163
+ const packageFile = (0, import_path.resolve)(nodeModulesPath, packageName, "package.json");
141
164
  if (!await import_fs_extra.default.exists(packageFile)) {
142
165
  throw new Error(`Cannot find plugin '${nameOrPkg}'`);
143
166
  }
@@ -158,9 +181,7 @@ const _PluginManager = class _PluginManager {
158
181
  * @internal
159
182
  */
160
183
  static getPluginPkgPrefix() {
161
- return (process.env.PLUGIN_PACKAGE_PREFIX || "@nocobase/plugin-,@nocobase/preset-,@nocobase/plugin-pro-").split(
162
- ","
163
- );
184
+ return (0, import_plugin_package.getPluginPackagePrefixes)();
164
185
  }
165
186
  /**
166
187
  * @internal
@@ -215,32 +236,10 @@ const _PluginManager = class _PluginManager {
215
236
  if (this.parsedNames[nameOrPkg]) {
216
237
  return this.parsedNames[nameOrPkg];
217
238
  }
218
- if (nameOrPkg.startsWith("@nocobase/plugin-")) {
219
- this.parsedNames[nameOrPkg] = {
220
- packageName: nameOrPkg,
221
- name: nameOrPkg.replace("@nocobase/plugin-", "")
222
- };
223
- return this.parsedNames[nameOrPkg];
224
- }
225
- if (nameOrPkg.startsWith("@nocobase/preset-")) {
226
- this.parsedNames[nameOrPkg] = {
227
- packageName: nameOrPkg,
228
- name: nameOrPkg.replace("@nocobase/preset-", "")
229
- };
230
- return this.parsedNames[nameOrPkg];
231
- }
232
- const exists = /* @__PURE__ */ __name(async (name, isPreset = false) => {
233
- return import_fs_extra.default.exists(
234
- (0, import_path.resolve)(process.env.NODE_MODULES_PATH, `@nocobase/${isPreset ? "preset" : "plugin"}-${name}`, "package.json")
235
- );
236
- }, "exists");
237
- if (await exists(nameOrPkg)) {
238
- this.parsedNames[nameOrPkg] = { name: nameOrPkg, packageName: `@nocobase/plugin-${nameOrPkg}` };
239
- } else if (await exists(nameOrPkg, true)) {
240
- this.parsedNames[nameOrPkg] = { name: nameOrPkg, packageName: `@nocobase/preset-${nameOrPkg}` };
241
- } else {
242
- this.parsedNames[nameOrPkg] = { name: nameOrPkg, packageName: nameOrPkg };
243
- }
239
+ this.parsedNames[nameOrPkg] = await (0, import_plugin_package.parsePluginName)(nameOrPkg, {
240
+ nodeModulesPath: process.env.NODE_MODULES_PATH,
241
+ pluginPackagePrefixes: this.getPluginPkgPrefix()
242
+ });
244
243
  return this.parsedNames[nameOrPkg];
245
244
  }
246
245
  addPreset(plugin, options = {}) {
@@ -279,69 +278,46 @@ const _PluginManager = class _PluginManager {
279
278
  }
280
279
  /* istanbul ignore next -- @preserve */
281
280
  async create(pluginName, options) {
282
- const createPlugin = /* @__PURE__ */ __name(async (name2) => {
283
- const pluginDir = (0, import_path.resolve)(process.cwd(), "packages/plugins", name2);
281
+ const createPlugin = /* @__PURE__ */ __name(async (name) => {
282
+ const pluginDir = (0, import_path.resolve)(process.cwd(), "packages/plugins", name);
284
283
  if (options == null ? void 0 : options.forceRecreate) {
285
284
  await import_fs_extra.default.rm(pluginDir, { recursive: true, force: true });
286
285
  }
287
- const { PluginGenerator } = require("@nocobase/cli/src/plugin-generator");
286
+ const { PluginGenerator } = require("@nocobase/cli-v1/src/plugin-generator");
288
287
  const generator = new PluginGenerator({
289
288
  cwd: process.cwd(),
290
289
  args: {},
291
290
  context: {
292
- name: name2
291
+ name
293
292
  }
294
293
  });
295
294
  await generator.run();
296
295
  }, "createPlugin");
297
296
  await createPlugin(pluginName);
298
297
  this.app.log.info("attempt to add the plugin to the app");
299
- const { name, packageName } = await _PluginManager.parseName(pluginName);
300
- const json = await _PluginManager.getPackageJson(packageName);
301
- this.app.log.info(`add plugin [${packageName}]`, {
302
- name,
303
- packageName,
304
- version: json.version
305
- });
306
- await (0, import_helper.tsxRerunning)();
307
298
  }
308
- async add(plugin, options = {}, insert = false, isUpgrade = false) {
299
+ async addOrThrow(plugin, options = {}, insert = false, isUpgrade = false) {
309
300
  if (!isUpgrade && this.has(plugin)) {
310
301
  const name = typeof plugin === "string" ? plugin : plugin.name;
311
- this.app.log.warn(`plugin [${name}] added`);
312
- return;
302
+ throw new Error(`plugin [${name}] already added`);
313
303
  }
314
304
  if (!options.name && typeof plugin === "string") {
315
305
  options.name = plugin;
316
306
  }
317
- try {
318
- if (typeof plugin === "string" && options.name && !options.packageName) {
319
- const packageName = await _PluginManager.getPackageName(options.name);
320
- if (packageName) {
321
- options["packageName"] = packageName;
322
- }
323
- }
324
- if (options.packageName) {
325
- const packageJson = await _PluginManager.getPackageJson(options.packageName);
326
- options["packageJson"] = packageJson;
327
- options["version"] = packageJson.version;
307
+ if (typeof plugin === "string" && options.name && !options.packageName) {
308
+ const packageName = await _PluginManager.getPackageName(options.name);
309
+ if (packageName) {
310
+ options["packageName"] = packageName;
328
311
  }
329
- } catch (error) {
330
- this.app.log.error(error);
331
- console.error(error);
332
312
  }
333
- this.app.log.trace(`adding plugin [${options.name}]`, {
334
- method: "add",
335
- submodule: "plugin-manager",
336
- name: options.name,
337
- options
338
- });
339
- let P;
340
- try {
341
- P = await _PluginManager.resolvePlugin(options.packageName || plugin, isUpgrade, !!options.packageName);
342
- } catch (error) {
343
- this.app.log.warn("plugin not found", error);
344
- return;
313
+ if (options.packageName) {
314
+ const packageJson = await _PluginManager.getPackageJson(options.packageName);
315
+ options["packageJson"] = packageJson;
316
+ options["version"] = packageJson.version;
317
+ }
318
+ const P = await _PluginManager.resolvePlugin(options.packageName || plugin, isUpgrade, !!options.packageName);
319
+ if (!P) {
320
+ throw new Error(`plugin [${(options == null ? void 0 : options.name) || "unknown"}] load error`);
345
321
  }
346
322
  const instance = new P((0, import_helper.createAppProxy)(this.app), options);
347
323
  this.pluginInstances.set(P, instance);
@@ -352,12 +328,13 @@ const _PluginManager = class _PluginManager {
352
328
  this.pluginAliases.set(options.packageName, instance);
353
329
  }
354
330
  await instance.afterAdd();
355
- this.app.log.trace(`added plugin [${options.name}]`, {
356
- method: "add",
357
- submodule: "plugin-manager",
358
- name: instance.name,
359
- options: instance.options
360
- });
331
+ }
332
+ async add(plugin, options = {}, insert = false, isUpgrade = false) {
333
+ try {
334
+ await this.addOrThrow(plugin, options, insert, isUpgrade);
335
+ } catch (error) {
336
+ this.app.log.error(error);
337
+ }
361
338
  }
362
339
  /**
363
340
  * @internal
@@ -528,7 +505,7 @@ const _PluginManager = class _PluginManager {
528
505
  added[pluginName] = true;
529
506
  continue;
530
507
  }
531
- await this.add(pluginName);
508
+ await this.addOrThrow(pluginName);
532
509
  }
533
510
  for (const name of pluginNames) {
534
511
  const { name: pluginName } = await _PluginManager.parseName(name);
@@ -771,7 +748,7 @@ const _PluginManager = class _PluginManager {
771
748
  if (process.env.VITEST) {
772
749
  return;
773
750
  }
774
- const file = (0, import_path.resolve)(process.cwd(), "storage/.upgrading");
751
+ const file = (0, import_utils.storagePathJoin)(".upgrading");
775
752
  this.app.log.debug("pending upgrade");
776
753
  await import_fs_extra.default.writeFile(file, "upgrading");
777
754
  }, "writeFile");
@@ -856,7 +833,7 @@ const _PluginManager = class _PluginManager {
856
833
  });
857
834
  return;
858
835
  }
859
- const file = (0, import_path.resolve)(process.cwd(), "storage/app-upgrading");
836
+ const file = (0, import_utils.storagePathJoin)("app-upgrading");
860
837
  await import_fs_extra.default.writeFile(file, "", "utf-8");
861
838
  await (0, import_helper.tsxRerunning)();
862
839
  await (0, import_execa.default)("yarn", ["nocobase", "pm2-restart"], {
@@ -1121,7 +1098,8 @@ const _PluginManager = class _PluginManager {
1121
1098
  }
1122
1099
  };
1123
1100
  __name(_PluginManager, "PluginManager");
1124
- __publicField(_PluginManager, "checkAndGetCompatible", import_utils2.checkAndGetCompatible);
1101
+ __publicField(_PluginManager, "compatibleCache", /* @__PURE__ */ new Map());
1102
+ __publicField(_PluginManager, "compatiblePending", /* @__PURE__ */ new Map());
1125
1103
  __publicField(_PluginManager, "parsedNames", {});
1126
1104
  let PluginManager = _PluginManager;
1127
1105
  var plugin_manager_default = PluginManager;
@@ -9,6 +9,7 @@
9
9
  import { AxiosRequestConfig } from 'axios';
10
10
  import { PluginManagerRepository } from './plugin-manager-repository';
11
11
  import { PluginData } from './types';
12
+ import Application from '../application';
12
13
  /**
13
14
  * get temp dir
14
15
  *
@@ -16,7 +17,8 @@ import { PluginData } from './types';
16
17
  * getTempDir() => '/tmp/nocobase'
17
18
  */
18
19
  export declare function getTempDir(): Promise<string>;
19
- export declare function getPluginStoragePath(): string;
20
+ export declare function assertSafePluginPackageName(packageName: string): void;
21
+ export declare function resolveSafeChildPath(baseDir: string, child: string): string;
20
22
  export declare function getLocalPluginPackagesPathArr(): string[];
21
23
  export declare function getStoragePluginDir(packageName: string): string;
22
24
  export declare function getLocalPluginDir(packageDirBasename: string): string;
@@ -112,4 +114,10 @@ export declare function checkAndGetCompatible(packageName: string): Promise<{
112
114
  depsCompatible: DepCompatible[];
113
115
  }>;
114
116
  export declare function getPluginBasePath(packageName: string): Promise<string>;
117
+ export declare function pmListSummary(app: Application): Promise<{
118
+ displayName: any;
119
+ packageName: any;
120
+ enabled: boolean;
121
+ description: any;
122
+ }[]>;
115
123
  export {};