@nocobase/server 0.19.0-alpha.1 → 0.19.0-alpha.10

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.
@@ -213,9 +213,17 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
213
213
  });
214
214
  app.on("__started", async (_app, options) => {
215
215
  const { maintainingStatus, options: startOptions } = options;
216
- if (maintainingStatus && ["install", "upgrade", "pm.add", "pm.update", "pm.enable", "pm.disable", "pm.remove", "restore"].includes(
217
- maintainingStatus.command.name
218
- ) && !startOptions.recover) {
216
+ if (maintainingStatus && [
217
+ "install",
218
+ "upgrade",
219
+ "refresh",
220
+ "restore",
221
+ "pm.add",
222
+ "pm.update",
223
+ "pm.enable",
224
+ "pm.disable",
225
+ "pm.remove"
226
+ ].includes(maintainingStatus.command.name) && !startOptions.recover) {
219
227
  this.setAppStatus(app.name, "running", {
220
228
  refresh: true
221
229
  });
@@ -498,20 +498,30 @@ const _Application = class _Application extends import_koa.default {
498
498
  this.emit("__restarted", this, options);
499
499
  }
500
500
  async stop(options = {}) {
501
- this.log.debug("stop app...", { method: "stop" });
501
+ const log = options.logging === false ? {
502
+ debug() {
503
+ },
504
+ warn() {
505
+ },
506
+ info() {
507
+ },
508
+ error() {
509
+ }
510
+ } : this.log;
511
+ log.debug("stop app...", { method: "stop" });
502
512
  this.setMaintainingMessage("stopping app...");
503
513
  if (this.stopped) {
504
- this.log.warn(`app is stopped`, { method: "stop" });
514
+ log.warn(`app is stopped`, { method: "stop" });
505
515
  return;
506
516
  }
507
517
  await this.emitAsync("beforeStop", this, options);
508
518
  try {
509
519
  if (!this.db.closed()) {
510
- this.log.info(`close db`, { method: "stop" });
520
+ log.info(`close db`, { method: "stop" });
511
521
  await this.db.close();
512
522
  }
513
523
  } catch (e) {
514
- this.log.error(e.message, { method: "stop", err: e.stack });
524
+ log.error(e.message, { method: "stop", err: e.stack });
515
525
  }
516
526
  if (this.cacheManager) {
517
527
  await this.cacheManager.close();
@@ -521,7 +531,7 @@ const _Application = class _Application extends import_koa.default {
521
531
  }
522
532
  await this.emitAsync("afterStop", this, options);
523
533
  this.stopped = true;
524
- this.log.info(`app has stopped`, { method: "stop" });
534
+ log.info(`app has stopped`, { method: "stop" });
525
535
  this._started = false;
526
536
  }
527
537
  async destroy(options = {}) {
@@ -38,6 +38,7 @@ var import_db_sync = __toESM(require("./db-sync"));
38
38
  var import_destroy = __toESM(require("./destroy"));
39
39
  var import_install = __toESM(require("./install"));
40
40
  var import_pm = __toESM(require("./pm"));
41
+ var import_refresh = __toESM(require("./refresh"));
41
42
  var import_restart = __toESM(require("./restart"));
42
43
  var import_start = __toESM(require("./start"));
43
44
  var import_stop = __toESM(require("./stop"));
@@ -54,6 +55,7 @@ function registerCli(app) {
54
55
  (0, import_stop.default)(app);
55
56
  (0, import_destroy.default)(app);
56
57
  (0, import_start.default)(app);
58
+ (0, import_refresh.default)(app);
57
59
  app.command("build").argument("[packages...]");
58
60
  app.command("clean");
59
61
  app.command("dev").usage("[options]").option("-p, --port [port]").option("--client").option("--server");
@@ -22,7 +22,10 @@ __export(install_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(install_exports);
24
24
  var install_default = /* @__PURE__ */ __name((app) => {
25
- app.command("install").ipc().auth().option("-f, --force").option("-c, --clean").action(async (options) => {
25
+ app.command("install").ipc().auth().option("-f, --force").option("-c, --clean").option("--lang <lang>").action(async (options) => {
26
+ if (options.lang) {
27
+ process.env.INIT_APP_LANG = options.lang;
28
+ }
26
29
  await app.install(options);
27
30
  const reinstall = options.clean || options.force;
28
31
  app.log.info(`app ${reinstall ? "reinstalled" : "installed"} successfully [v${app.getVersion()}]`);
@@ -35,8 +35,8 @@ var import_lodash = __toESM(require("lodash"));
35
35
  var import_plugin_command_error = require("../errors/plugin-command-error");
36
36
  var pm_default = /* @__PURE__ */ __name((app) => {
37
37
  const pm = app.command("pm");
38
- pm.command("create").ipc().arguments("plugin").action(async (plugin) => {
39
- await app.pm.create(plugin);
38
+ pm.command("create").arguments("plugin").option("--force-recreate").action(async (plugin, options) => {
39
+ await app.pm.create(plugin, options);
40
40
  });
41
41
  pm.command("add").ipc().preload().argument("<pkg>").option("--registry [registry]").option("--auth-token [authToken]").option("--version [version]").action(async (name, options, cli) => {
42
42
  try {
@@ -69,7 +69,7 @@ var pm_default = /* @__PURE__ */ __name((app) => {
69
69
  throw new import_plugin_command_error.PluginCommandError(`Failed to disable plugin: ${error.message}`);
70
70
  }
71
71
  });
72
- pm.command("remove").ipc().preload().arguments("<plugins...>").action(async (plugins) => {
73
- await app.pm.remove(plugins);
72
+ pm.command("remove").auth().arguments("<plugins...>").option("--force").option("--remove-dir").action(async (plugins, options) => {
73
+ await app.pm.remove(plugins, options);
74
74
  });
75
75
  }, "default");
@@ -0,0 +1,3 @@
1
+ import Application from '../application';
2
+ declare const _default: (app: Application) => void;
3
+ export default _default;
@@ -0,0 +1,31 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var refresh_exports = {};
20
+ __export(refresh_exports, {
21
+ default: () => refresh_default
22
+ });
23
+ module.exports = __toCommonJS(refresh_exports);
24
+ var refresh_default = /* @__PURE__ */ __name((app) => {
25
+ app.command("refresh").ipc().action(async (cliArgs) => {
26
+ await app.restart({
27
+ cliArgs
28
+ });
29
+ app.log.info("refreshing...");
30
+ });
31
+ }, "default");
@@ -66,5 +66,6 @@ export declare class Gateway extends EventEmitter {
66
66
  tryConnectToIPCServer(): Promise<false | IPCSocketClient>;
67
67
  getIPCSocketClient(): Promise<IPCSocketClient>;
68
68
  close(): void;
69
+ static getIPCSocketClient(): Promise<false | IPCSocketClient>;
69
70
  }
70
71
  export {};
@@ -51,7 +51,6 @@ var import_path = require("path");
51
51
  var import_qs = __toESM(require("qs"));
52
52
  var import_serve_handler = __toESM(require("serve-handler"));
53
53
  var import_url = require("url");
54
- var import_xpipe = __toESM(require("xpipe"));
55
54
  var import_app_supervisor = require("../app-supervisor");
56
55
  var import_plugin_manager = require("../plugin-manager");
57
56
  var import_errors = require("./errors");
@@ -69,13 +68,13 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
69
68
  port = process.env.APP_PORT ? parseInt(process.env.APP_PORT) : null;
70
69
  host = "0.0.0.0";
71
70
  wsServer;
72
- socketPath = import_xpipe.default.eq((0, import_path.resolve)(process.cwd(), "storage", "gateway.sock"));
71
+ socketPath = (0, import_path.resolve)(process.cwd(), "storage", "gateway.sock");
73
72
  loggers = new import_utils.Registry();
74
73
  constructor() {
75
74
  super();
76
75
  this.reset();
77
76
  if (process.env.SOCKET_PATH) {
78
- this.socketPath = import_xpipe.default.eq((0, import_path.resolve)(process.cwd(), process.env.SOCKET_PATH));
77
+ this.socketPath = (0, import_path.resolve)(process.cwd(), process.env.SOCKET_PATH);
79
78
  }
80
79
  }
81
80
  static getInstance(options = {}) {
@@ -267,7 +266,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
267
266
  if (ipcClient) {
268
267
  const response = await ipcClient.write({ type: "passCliArgv", payload: { argv: process.argv } });
269
268
  ipcClient.close();
270
- if (response.type !== "error" || response.payload.message !== "Not handle by ipc server") {
269
+ if (!["error", "not_found"].includes(response.type)) {
271
270
  return;
272
271
  }
273
272
  }
@@ -276,16 +275,20 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
276
275
  await (0, import_plugin_symlink.createStoragePluginsSymlink)();
277
276
  }
278
277
  const mainApp = import_app_supervisor.AppSupervisor.getInstance().bootMainApp(options.mainAppOptions);
279
- await mainApp.load();
280
278
  mainApp.runAsCLI(process.argv, {
281
279
  throwError: true,
282
280
  from: "node"
283
281
  }).then(async () => {
284
282
  if (!await mainApp.isStarted()) {
285
- await mainApp.stop();
283
+ await mainApp.stop({ logging: false });
284
+ }
285
+ }).catch(async (e) => {
286
+ if (e.code !== "commander.helpDisplayed") {
287
+ mainApp.log.error(e);
288
+ }
289
+ if (!await mainApp.isStarted()) {
290
+ await mainApp.stop({ logging: false });
286
291
  }
287
- }).catch((e) => {
288
- console.error(e);
289
292
  });
290
293
  }
291
294
  isStart() {
@@ -325,7 +328,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
325
328
  this.wsServer = new import_ws_server.WSServer();
326
329
  this.server.on("upgrade", (request, socket, head) => {
327
330
  const { pathname } = (0, import_url.parse)(request.url);
328
- if (pathname === "/ws") {
331
+ if (pathname === process.env.WS_PATH) {
329
332
  this.wsServer.wss.handleUpgrade(request, socket, head, (ws) => {
330
333
  this.wsServer.wss.emit("connection", ws, request);
331
334
  });
@@ -356,6 +359,14 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
356
359
  (_a = this.server) == null ? void 0 : _a.close();
357
360
  (_b = this.wsServer) == null ? void 0 : _b.close();
358
361
  }
362
+ static async getIPCSocketClient() {
363
+ const socketPath = (0, import_path.resolve)(process.cwd(), process.env.SOCKET_PATH || "storage/gateway.sock");
364
+ try {
365
+ return await import_ipc_socket_client.IPCSocketClient.getConnection(socketPath);
366
+ } catch (error) {
367
+ return false;
368
+ }
369
+ }
359
370
  };
360
371
  __name(_Gateway, "Gateway");
361
372
  __publicField(_Gateway, "instance");
@@ -1,8 +1,8 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
- import net from 'net';
4
- import * as events from 'events';
5
3
  import { Logger } from '@nocobase/logger';
4
+ import * as events from 'events';
5
+ import net from 'net';
6
6
  export declare const writeJSON: (socket: net.Socket, data: object) => void;
7
7
  export declare class IPCSocketClient extends events.EventEmitter {
8
8
  client: net.Socket;
@@ -32,9 +32,10 @@ __export(ipc_socket_client_exports, {
32
32
  writeJSON: () => writeJSON
33
33
  });
34
34
  module.exports = __toCommonJS(ipc_socket_client_exports);
35
- var import_net = __toESM(require("net"));
36
- var events = __toESM(require("events"));
37
35
  var import_logger = require("@nocobase/logger");
36
+ var events = __toESM(require("events"));
37
+ var import_net = __toESM(require("net"));
38
+ var import_xpipe = __toESM(require("xpipe"));
38
39
  const writeJSON = /* @__PURE__ */ __name((socket, data) => {
39
40
  socket.write(JSON.stringify(data) + "\n", "utf8");
40
41
  }, "writeJSON");
@@ -59,7 +60,7 @@ const _IPCSocketClient = class _IPCSocketClient extends events.EventEmitter {
59
60
  }
60
61
  static async getConnection(serverPath) {
61
62
  return new Promise((resolve, reject) => {
62
- const client = import_net.default.createConnection({ path: serverPath }, () => {
63
+ const client = import_net.default.createConnection({ path: import_xpipe.default.eq(serverPath) }, () => {
63
64
  resolve(new _IPCSocketClient(client));
64
65
  });
65
66
  client.on("error", (err) => {
@@ -69,6 +70,8 @@ const _IPCSocketClient = class _IPCSocketClient extends events.EventEmitter {
69
70
  }
70
71
  async handleServerMessage({ reqId, type, payload }) {
71
72
  switch (type) {
73
+ case "not_found":
74
+ break;
72
75
  case "error":
73
76
  this.logger.error({ reqId, message: `${payload.message}|${payload.stack}` });
74
77
  break;
@@ -8,6 +8,6 @@ export declare class IPCSocketServer {
8
8
  reqId: any;
9
9
  type: any;
10
10
  payload: any;
11
- }): Promise<import("../app-command").AppCommand>;
11
+ }): Promise<string | false | import("../app-command").AppCommand>;
12
12
  close(): void;
13
13
  }
@@ -31,12 +31,13 @@ __export(ipc_socket_server_exports, {
31
31
  IPCSocketServer: () => IPCSocketServer
32
32
  });
33
33
  module.exports = __toCommonJS(ipc_socket_server_exports);
34
- var import_net = __toESM(require("net"));
34
+ var import_crypto = require("crypto");
35
35
  var import_fs = __toESM(require("fs"));
36
+ var import_net = __toESM(require("net"));
36
37
  var import_path = __toESM(require("path"));
38
+ var import_xpipe = __toESM(require("xpipe"));
37
39
  var import_app_supervisor = require("../app-supervisor");
38
40
  var import_ipc_socket_client = require("./ipc-socket-client");
39
- var import_crypto = require("crypto");
40
41
  const _IPCSocketServer = class _IPCSocketServer {
41
42
  socketServer;
42
43
  constructor(server) {
@@ -64,10 +65,10 @@ const _IPCSocketServer = class _IPCSocketServer {
64
65
  }
65
66
  const reqId = (0, import_crypto.randomUUID)();
66
67
  const dataObj = JSON.parse(message);
67
- _IPCSocketServer.handleClientMessage({ reqId, ...dataObj }).then(() => {
68
+ _IPCSocketServer.handleClientMessage({ reqId, ...dataObj }).then((result) => {
68
69
  (0, import_ipc_socket_client.writeJSON)(c, {
69
70
  reqId,
70
- type: "success"
71
+ type: result === false ? "not_found" : "success"
71
72
  });
72
73
  }).catch((err) => {
73
74
  (0, import_ipc_socket_client.writeJSON)(c, {
@@ -82,25 +83,43 @@ const _IPCSocketServer = class _IPCSocketServer {
82
83
  }
83
84
  });
84
85
  });
85
- socketServer.listen(socketPath, () => {
86
+ socketServer.listen(import_xpipe.default.eq(socketPath), () => {
86
87
  console.log(`Gateway IPC Server running at ${socketPath}`);
87
88
  });
88
89
  return new _IPCSocketServer(socketServer);
89
90
  }
90
91
  static async handleClientMessage({ reqId, type, payload }) {
91
- console.log(`cli received message ${type}`);
92
+ if (type === "appReady") {
93
+ const status = await new Promise((resolve, reject) => {
94
+ let status2;
95
+ const max = 300;
96
+ let count = 0;
97
+ const timer = setInterval(async () => {
98
+ status2 = import_app_supervisor.AppSupervisor.getInstance().getAppStatus("main");
99
+ if (status2 === "running") {
100
+ clearInterval(timer);
101
+ resolve(status2);
102
+ }
103
+ if (count++ > max) {
104
+ reject("error");
105
+ }
106
+ }, 500);
107
+ });
108
+ console.log("status", status);
109
+ return status;
110
+ }
92
111
  if (type === "passCliArgv") {
93
112
  const argv = payload.argv;
94
113
  const mainApp = await import_app_supervisor.AppSupervisor.getInstance().getApp("main");
95
114
  if (!mainApp.cli.hasCommand(argv[2])) {
96
- console.log("passCliArgv", argv[2]);
97
115
  await mainApp.pm.loadCommands();
98
116
  }
99
117
  const cli = mainApp.cli;
100
118
  if (!cli.parseHandleByIPCServer(argv, {
101
119
  from: "node"
102
120
  })) {
103
- throw new Error("Not handle by ipc server");
121
+ mainApp.log.debug("Not handle by ipc server");
122
+ return false;
104
123
  }
105
124
  return mainApp.runAsCLI(argv, {
106
125
  reqId,
@@ -35,7 +35,7 @@ module.exports = __toCommonJS(data_wrapping_exports);
35
35
  var import_stream = __toESM(require("stream"));
36
36
  function dataWrapping() {
37
37
  return /* @__PURE__ */ __name(async function dataWrapping2(ctx, next) {
38
- var _a;
38
+ var _a, _b;
39
39
  await next();
40
40
  if (ctx.withoutDataWrapping) {
41
41
  return;
@@ -55,27 +55,30 @@ function dataWrapping() {
55
55
  ctx.body = {
56
56
  data: ctx.body
57
57
  };
58
- return;
59
- }
60
- if (ctx.body) {
61
- const { rows, ...meta } = ctx.body;
62
- if (rows) {
63
- ctx.body = {
64
- data: rows,
65
- meta
66
- };
67
- } else {
58
+ } else {
59
+ if (ctx.body) {
60
+ const { rows, ...meta } = ctx.body;
61
+ if (rows) {
62
+ ctx.body = {
63
+ data: rows,
64
+ meta
65
+ };
66
+ } else {
67
+ ctx.body = {
68
+ data: ctx.body
69
+ };
70
+ if (ctx.bodyMeta) {
71
+ ctx.body.meta = ctx.bodyMeta;
72
+ }
73
+ }
74
+ } else if (ctx.action) {
68
75
  ctx.body = {
69
76
  data: ctx.body
70
77
  };
71
- if (ctx.bodyMeta) {
72
- ctx.body.meta = ctx.bodyMeta;
73
- }
74
78
  }
75
- } else if (ctx.action) {
76
- ctx.body = {
77
- data: ctx.body
78
- };
79
+ }
80
+ if (ctx.body && ((_b = ctx.state.messages) == null ? void 0 : _b.length)) {
81
+ ctx.body.messages = ctx.state.messages;
79
82
  }
80
83
  }, "dataWrapping");
81
84
  }
@@ -29,13 +29,20 @@ const _package_name_unique_default = class _package_name_unique_default extends
29
29
  async up() {
30
30
  const tableNameWithSchema = this.pm.collection.getTableNameWithSchema();
31
31
  const field = this.pm.collection.getField("packageName");
32
- await this.db.sequelize.getQueryInterface().addColumn(tableNameWithSchema, field.columnName(), {
33
- type: import_database.DataTypes.STRING
34
- });
35
- await this.db.sequelize.getQueryInterface().addConstraint(tableNameWithSchema, {
36
- type: "unique",
37
- fields: [field.columnName()]
38
- });
32
+ const exists = await field.existsInDb();
33
+ if (exists) {
34
+ return;
35
+ }
36
+ try {
37
+ await this.db.sequelize.getQueryInterface().addColumn(tableNameWithSchema, field.columnName(), {
38
+ type: import_database.DataTypes.STRING
39
+ });
40
+ await this.db.sequelize.getQueryInterface().addConstraint(tableNameWithSchema, {
41
+ type: "unique",
42
+ fields: [field.columnName()]
43
+ });
44
+ } catch (error) {
45
+ }
39
46
  }
40
47
  };
41
48
  __name(_package_name_unique_default, "default");
@@ -5,6 +5,7 @@ import Application from '../application';
5
5
  import { Plugin } from '../plugin';
6
6
  import { PluginManagerRepository } from './plugin-manager-repository';
7
7
  import { PluginData } from './types';
8
+ export declare const sleep: (timeout?: number) => Promise<unknown>;
8
9
  export interface PluginManagerOptions {
9
10
  app: Application;
10
11
  plugins?: any[];
@@ -39,7 +40,9 @@ export declare class PluginManager {
39
40
  get(name: string | typeof Plugin): Plugin<any>;
40
41
  has(name: string | typeof Plugin): boolean;
41
42
  del(name: string | typeof Plugin): void;
42
- create(pluginName: string): Promise<void>;
43
+ create(pluginName: string, options?: {
44
+ forceRecreate?: boolean;
45
+ }): Promise<void>;
43
46
  add(plugin?: any, options?: any, insert?: boolean, isUpgrade?: boolean): Promise<void>;
44
47
  initPlugins(): Promise<void>;
45
48
  loadCommands(): Promise<void>;
@@ -47,7 +50,10 @@ export declare class PluginManager {
47
50
  install(options?: InstallOptions): Promise<void>;
48
51
  enable(name: string | string[]): Promise<void>;
49
52
  disable(name: string | string[]): Promise<void>;
50
- remove(name: string | string[]): Promise<void>;
53
+ remove(name: string | string[], options?: {
54
+ removeDir?: boolean;
55
+ force?: boolean;
56
+ }): Promise<void>;
51
57
  loadOne(plugin: Plugin): Promise<void>;
52
58
  addViaCLI(urlOrName: string, options?: PluginData): Promise<void>;
53
59
  addByNpm(options: {
@@ -30,7 +30,8 @@ var plugin_manager_exports = {};
30
30
  __export(plugin_manager_exports, {
31
31
  AddPresetError: () => AddPresetError,
32
32
  PluginManager: () => PluginManager,
33
- default: () => plugin_manager_default
33
+ default: () => plugin_manager_default,
34
+ sleep: () => sleep
34
35
  });
35
36
  module.exports = __toCommonJS(plugin_manager_exports);
36
37
  var import_utils = require("@nocobase/utils");
@@ -46,6 +47,11 @@ var import_collection = __toESM(require("./options/collection"));
46
47
  var import_resource = __toESM(require("./options/resource"));
47
48
  var import_plugin_manager_repository = require("./plugin-manager-repository");
48
49
  var import_utils2 = require("./utils");
50
+ const sleep = /* @__PURE__ */ __name(async (timeout = 0) => {
51
+ return new Promise((resolve2) => {
52
+ setTimeout(resolve2, timeout);
53
+ });
54
+ }, "sleep");
49
55
  const _AddPresetError = class _AddPresetError extends Error {
50
56
  };
51
57
  __name(_AddPresetError, "AddPresetError");
@@ -177,12 +183,15 @@ const _PluginManager = class _PluginManager {
177
183
  this.app.pm.pluginInstances.delete(instance.constructor);
178
184
  }
179
185
  }
180
- async create(pluginName) {
181
- console.log("creating...");
186
+ async create(pluginName, options) {
182
187
  const createPlugin = /* @__PURE__ */ __name(async (name) => {
188
+ const pluginDir = (0, import_path.resolve)(process.cwd(), "packages/plugins", name);
189
+ if (options == null ? void 0 : options.forceRecreate) {
190
+ await import_fs.default.promises.rm(pluginDir, { recursive: true, force: true });
191
+ }
183
192
  const { PluginGenerator } = require("@nocobase/cli/src/plugin-generator");
184
193
  const generator = new PluginGenerator({
185
- cwd: (0, import_path.resolve)(process.cwd(), name),
194
+ cwd: process.cwd(),
186
195
  args: {},
187
196
  context: {
188
197
  name
@@ -191,13 +200,38 @@ const _PluginManager = class _PluginManager {
191
200
  await generator.run();
192
201
  }, "createPlugin");
193
202
  await createPlugin(pluginName);
194
- await this.repository.create({
203
+ try {
204
+ await this.app.db.auth({ retry: 1 });
205
+ const installed = await this.app.isInstalled();
206
+ if (!installed) {
207
+ console.log(`yarn pm add ${pluginName}`);
208
+ return;
209
+ }
210
+ } catch (error) {
211
+ return;
212
+ }
213
+ this.app.log.info("attempt to add the plugin to the app");
214
+ let packageName;
215
+ try {
216
+ packageName = await _PluginManager.getPackageName(pluginName);
217
+ } catch (error) {
218
+ packageName = pluginName;
219
+ }
220
+ const json = await _PluginManager.getPackageJson(packageName);
221
+ this.app.log.info(`add plugin [${packageName}]`, {
222
+ name: pluginName,
223
+ packageName,
224
+ version: json.version
225
+ });
226
+ await this.repository.updateOrCreate({
195
227
  values: {
196
228
  name: pluginName,
197
- packageName: pluginName,
198
- version: "0.1.0"
199
- }
229
+ packageName,
230
+ version: json.version
231
+ },
232
+ filterKeys: ["name"]
200
233
  });
234
+ await sleep(1e3);
201
235
  await (0, import_helper.tsxRerunning)();
202
236
  }
203
237
  async add(plugin, options = {}, insert = false, isUpgrade = false) {
@@ -254,7 +288,7 @@ const _PluginManager = class _PluginManager {
254
288
  await this.initOtherPlugins();
255
289
  }
256
290
  async loadCommands() {
257
- this.app.log.info("load commands");
291
+ this.app.log.debug("load commands");
258
292
  const items = await this.repository.find({
259
293
  filter: {
260
294
  enabled: true
@@ -486,37 +520,70 @@ const _PluginManager = class _PluginManager {
486
520
  throw error;
487
521
  }
488
522
  }
489
- async remove(name) {
523
+ async remove(name, options) {
490
524
  const pluginNames = import_lodash.default.castArray(name);
491
- for (const pluginName of pluginNames) {
492
- const plugin = this.get(pluginName);
493
- if (!plugin) {
494
- continue;
495
- }
496
- if (plugin.enabled) {
497
- throw new Error(`${pluginName} plugin is enabled`);
525
+ const records = pluginNames.map((name2) => {
526
+ return {
527
+ name: name2,
528
+ packageName: name2
529
+ };
530
+ });
531
+ const removeDir = /* @__PURE__ */ __name(async () => {
532
+ await Promise.all(
533
+ records.map(async (plugin) => {
534
+ const dir = (0, import_path.resolve)(process.env.NODE_MODULES_PATH, plugin.packageName);
535
+ try {
536
+ const realDir = await import_fs.default.promises.realpath(dir);
537
+ this.app.log.debug(`rm -rf ${realDir}`);
538
+ return import_fs.default.promises.rm(realDir, { force: true, recursive: true });
539
+ } catch (error) {
540
+ return false;
541
+ }
542
+ })
543
+ );
544
+ await (0, import_execa.default)("yarn", ["nocobase", "postinstall"]);
545
+ }, "removeDir");
546
+ if (options == null ? void 0 : options.force) {
547
+ await this.repository.destroy({
548
+ filter: {
549
+ name: pluginNames
550
+ }
551
+ });
552
+ } else {
553
+ await this.app.load();
554
+ for (const pluginName of pluginNames) {
555
+ const plugin = this.get(pluginName);
556
+ if (!plugin) {
557
+ continue;
558
+ }
559
+ if (plugin.enabled) {
560
+ throw new Error(`plugin is enabled [${pluginName}]`);
561
+ }
562
+ await plugin.beforeRemove();
498
563
  }
499
- await plugin.beforeRemove();
500
- }
501
- await this.repository.destroy({
502
- filter: {
503
- name: pluginNames
564
+ await this.repository.destroy({
565
+ filter: {
566
+ name: pluginNames
567
+ }
568
+ });
569
+ const plugins = [];
570
+ for (const pluginName of pluginNames) {
571
+ const plugin = this.get(pluginName);
572
+ if (!plugin) {
573
+ continue;
574
+ }
575
+ plugins.push(plugin);
576
+ this.del(pluginName);
577
+ await plugin.afterRemove();
504
578
  }
505
- });
506
- const plugins = [];
507
- for (const pluginName of pluginNames) {
508
- const plugin = this.get(pluginName);
509
- if (!plugin) {
510
- continue;
579
+ if (await this.app.isStarted()) {
580
+ await this.app.tryReloadOrRestart();
511
581
  }
512
- plugins.push(plugin);
513
- this.del(pluginName);
514
582
  }
515
- await this.app.reload();
516
- for (const plugin of plugins) {
517
- await plugin.afterRemove();
583
+ if (options == null ? void 0 : options.removeDir) {
584
+ await removeDir();
518
585
  }
519
- await this.app.emitStartedEvent();
586
+ await (0, import_execa.default)("yarn", ["nocobase", "refresh"]);
520
587
  }
521
588
  async loadOne(plugin) {
522
589
  this.app.setMaintainingMessage(`loading plugin ${plugin.name}...`);
@@ -572,6 +639,7 @@ const _PluginManager = class _PluginManager {
572
639
  await this.add(opts["name"] || urlOrName, opts, true);
573
640
  }
574
641
  await this.app.emitStartedEvent();
642
+ await (0, import_execa.default)("yarn", ["nocobase", "postinstall"]);
575
643
  }
576
644
  async addByNpm(options) {
577
645
  let { name = "", registry, packageName, authToken } = options;
@@ -823,5 +891,6 @@ var plugin_manager_default = PluginManager;
823
891
  // Annotate the CommonJS export names for ESM import in node:
824
892
  0 && (module.exports = {
825
893
  AddPresetError,
826
- PluginManager
894
+ PluginManager,
895
+ sleep
827
896
  });
package/lib/plugin.d.ts CHANGED
@@ -37,7 +37,8 @@ export declare abstract class Plugin<O = any> implements PluginInterface {
37
37
  setOptions(options: any): void;
38
38
  getName(): any;
39
39
  createLogger(options: LoggerOptions): import("winston").Logger;
40
- get _sourceDir(): "src" | "dist" | "lib";
40
+ protected _sourceDir: string;
41
+ protected getSourceDir(): Promise<string>;
41
42
  loadCommands(): Promise<void>;
42
43
  loadMigrations(): Promise<{
43
44
  beforeLoad: any[];
@@ -59,6 +60,7 @@ export declare abstract class Plugin<O = any> implements PluginInterface {
59
60
  loadCollections(): Promise<void>;
60
61
  requiredPlugins(): any[];
61
62
  t(text: TFuncKey | TFuncKey[], options?: TOptions): import("i18next").TFunctionDetailedResult<object>;
63
+ protected isDev(): Promise<boolean>;
62
64
  toJSON(options?: any): Promise<any>;
63
65
  }
64
66
  export default Plugin;
package/lib/plugin.js CHANGED
@@ -86,18 +86,25 @@ const _Plugin = class _Plugin {
86
86
  createLogger(options) {
87
87
  return this.app.createLogger(options);
88
88
  }
89
- get _sourceDir() {
89
+ _sourceDir;
90
+ async getSourceDir() {
91
+ if (this._sourceDir) {
92
+ return this._sourceDir;
93
+ }
94
+ if (await this.isDev()) {
95
+ return this._sourceDir = "src";
96
+ }
90
97
  if ((0, import_path.basename)(__dirname) === "src") {
91
- return "src";
98
+ return this._sourceDir = "src";
92
99
  }
93
- return this.isPreset ? "lib" : "dist";
100
+ return this._sourceDir = this.isPreset ? "lib" : "dist";
94
101
  }
95
102
  async loadCommands() {
96
103
  const extensions = ["js", "ts"];
97
104
  const directory = (0, import_path.resolve)(
98
105
  process.env.NODE_MODULES_PATH,
99
106
  this.options.packageName,
100
- this._sourceDir,
107
+ await this.getSourceDir(),
101
108
  "server/commands"
102
109
  );
103
110
  const patten = `${directory}/*.{${extensions.join(",")}}`;
@@ -122,7 +129,7 @@ const _Plugin = class _Plugin {
122
129
  const directory = (0, import_path.resolve)(
123
130
  process.env.NODE_MODULES_PATH,
124
131
  this.options.packageName,
125
- this._sourceDir,
132
+ await this.getSourceDir(),
126
133
  "server/migrations"
127
134
  );
128
135
  return await this.app.loadMigrations({
@@ -164,7 +171,7 @@ const _Plugin = class _Plugin {
164
171
  const directory = (0, import_path.resolve)(
165
172
  process.env.NODE_MODULES_PATH,
166
173
  this.options.packageName,
167
- this._sourceDir,
174
+ await this.getSourceDir(),
168
175
  "server/collections"
169
176
  );
170
177
  if (await (0, import_utils.fsExists)(directory)) {
@@ -180,6 +187,18 @@ const _Plugin = class _Plugin {
180
187
  t(text, options = {}) {
181
188
  return this.app.i18n.t(text, { ns: this.options["packageName"], ...options });
182
189
  }
190
+ async isDev() {
191
+ if (!this.options.packageName) {
192
+ return false;
193
+ }
194
+ const file = await import_fs.default.promises.realpath(
195
+ (0, import_path.resolve)(process.env.NODE_MODULES_PATH || (0, import_path.resolve)(process.cwd(), "node_modules"), this.options.packageName)
196
+ );
197
+ if (file.startsWith((0, import_path.resolve)(process.cwd(), "packages"))) {
198
+ return !!process.env.IS_DEV_CMD;
199
+ }
200
+ return false;
201
+ }
183
202
  async toJSON(options = {}) {
184
203
  const { locale = "en-US" } = options;
185
204
  const { name, packageName, packageJson } = this.options;
@@ -190,10 +209,12 @@ const _Plugin = class _Plugin {
190
209
  }
191
210
  const results = {
192
211
  ...this.options,
212
+ keywords: packageJson.keywords,
193
213
  readmeUrl: (0, import_plugin_manager.getExposeReadmeUrl)(packageName, locale),
194
214
  changelogUrl: (0, import_plugin_manager.getExposeChangelogUrl)(packageName),
195
215
  displayName: packageJson[`displayName.${locale}`] || packageJson.displayName || name,
196
- description: packageJson[`description.${locale}`] || packageJson.description
216
+ description: packageJson[`description.${locale}`] || packageJson.description,
217
+ homepage: packageJson[`homepage.${locale}`] || packageJson.homepage
197
218
  };
198
219
  if (!options.withOutOpenFile) {
199
220
  const file = await import_fs.default.promises.realpath(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/server",
3
- "version": "0.19.0-alpha.1",
3
+ "version": "0.19.0-alpha.10",
4
4
  "main": "lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -10,17 +10,17 @@
10
10
  "@koa/cors": "^3.1.0",
11
11
  "@koa/multer": "^3.0.2",
12
12
  "@koa/router": "^9.4.0",
13
- "@nocobase/acl": "0.19.0-alpha.1",
14
- "@nocobase/actions": "0.19.0-alpha.1",
15
- "@nocobase/auth": "0.19.0-alpha.1",
16
- "@nocobase/cache": "0.19.0-alpha.1",
17
- "@nocobase/database": "0.19.0-alpha.1",
18
- "@nocobase/evaluators": "0.19.0-alpha.1",
19
- "@nocobase/logger": "0.19.0-alpha.1",
20
- "@nocobase/resourcer": "0.19.0-alpha.1",
21
- "@nocobase/sdk": "0.19.0-alpha.1",
22
- "@nocobase/telemetry": "0.19.0-alpha.1",
23
- "@nocobase/utils": "0.19.0-alpha.1",
13
+ "@nocobase/acl": "0.19.0-alpha.10",
14
+ "@nocobase/actions": "0.19.0-alpha.10",
15
+ "@nocobase/auth": "0.19.0-alpha.10",
16
+ "@nocobase/cache": "0.19.0-alpha.10",
17
+ "@nocobase/database": "0.19.0-alpha.10",
18
+ "@nocobase/evaluators": "0.19.0-alpha.10",
19
+ "@nocobase/logger": "0.19.0-alpha.10",
20
+ "@nocobase/resourcer": "0.19.0-alpha.10",
21
+ "@nocobase/sdk": "0.19.0-alpha.10",
22
+ "@nocobase/telemetry": "0.19.0-alpha.10",
23
+ "@nocobase/utils": "0.19.0-alpha.10",
24
24
  "@types/decompress": "4.2.4",
25
25
  "@types/ini": "^1.3.31",
26
26
  "@types/koa-send": "^4.1.3",
@@ -53,5 +53,5 @@
53
53
  "@types/serve-handler": "^6.1.1",
54
54
  "@types/ws": "^8.5.5"
55
55
  },
56
- "gitHead": "64601944412fc4d2e2bd05f4b982118dd28247dc"
56
+ "gitHead": "d09d81eba67339da36bcec27939a85b35d180770"
57
57
  }