@nocobase/server 1.5.0-beta.8 → 1.5.0

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.
@@ -31,6 +31,7 @@ import { Plugin } from './plugin';
31
31
  import { InstallOptions, PluginManager } from './plugin-manager';
32
32
  import { PubSubManager, PubSubManagerOptions } from './pub-sub-manager';
33
33
  import { SyncMessageManager } from './sync-message-manager';
34
+ import { ServiceContainer } from './service-container';
34
35
  import { AuditManager } from './audit-manager';
35
36
  export type PluginType = string | typeof Plugin;
36
37
  export type PluginConfiguration = PluginType | [PluginType, any];
@@ -169,6 +170,7 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
169
170
  private _maintainingCommandStatus;
170
171
  private _maintainingStatusBeforeCommand;
171
172
  private _actionCommand;
173
+ container: ServiceContainer;
172
174
  lockManager: LockManager;
173
175
  constructor(options: ApplicationOptions);
174
176
  private static staticCommands;
@@ -76,6 +76,7 @@ var import_plugin_manager = require("./plugin-manager");
76
76
  var import_pub_sub_manager = require("./pub-sub-manager");
77
77
  var import_sync_message_manager = require("./sync-message-manager");
78
78
  var import_package = __toESM(require("../package.json"));
79
+ var import_service_container = require("./service-container");
79
80
  var import_available_action = require("./acl/available-action");
80
81
  var import_audit_manager = require("./audit-manager");
81
82
  const _Application = class _Application extends import_koa.default {
@@ -126,6 +127,7 @@ const _Application = class _Application extends import_koa.default {
126
127
  _maintainingCommandStatus;
127
128
  _maintainingStatusBeforeCommand;
128
129
  _actionCommand;
130
+ container = new import_service_container.ServiceContainer();
129
131
  lockManager;
130
132
  static addCommand(callback) {
131
133
  this.staticCommands.push(callback);
@@ -63,7 +63,17 @@ var import_errors = require("./errors");
63
63
  var import_ipc_socket_client = require("./ipc-socket-client");
64
64
  var import_ipc_socket_server = require("./ipc-socket-server");
65
65
  var import_ws_server = require("./ws-server");
66
+ var import_node_worker_threads = require("node:worker_threads");
67
+ var import_node_process = __toESM(require("node:process"));
66
68
  const compress = (0, import_node_util.promisify)((0, import_compression.default)());
69
+ function getSocketPath() {
70
+ const { SOCKET_PATH } = import_node_process.default.env;
71
+ if ((0, import_path.isAbsolute)(SOCKET_PATH)) {
72
+ return SOCKET_PATH;
73
+ }
74
+ return (0, import_path.resolve)(import_node_process.default.cwd(), SOCKET_PATH);
75
+ }
76
+ __name(getSocketPath, "getSocketPath");
67
77
  const _Gateway = class _Gateway extends import_events.EventEmitter {
68
78
  /**
69
79
  * use main app as default app to handle request
@@ -72,16 +82,14 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
72
82
  server = null;
73
83
  ipcSocketServer = null;
74
84
  loggers = new import_utils.Registry();
75
- port = process.env.APP_PORT ? parseInt(process.env.APP_PORT) : null;
85
+ port = import_node_process.default.env.APP_PORT ? parseInt(import_node_process.default.env.APP_PORT) : null;
76
86
  host = "0.0.0.0";
77
87
  wsServer;
78
- socketPath = (0, import_path.resolve)(process.cwd(), "storage", "gateway.sock");
88
+ socketPath = (0, import_path.resolve)(import_node_process.default.cwd(), "storage", "gateway.sock");
79
89
  constructor() {
80
90
  super();
81
91
  this.reset();
82
- if (process.env.SOCKET_PATH) {
83
- this.socketPath = (0, import_path.resolve)(process.cwd(), process.env.SOCKET_PATH);
84
- }
92
+ this.socketPath = getSocketPath();
85
93
  }
86
94
  static getInstance(options = {}) {
87
95
  if (!_Gateway.instance) {
@@ -90,7 +98,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
90
98
  return _Gateway.instance;
91
99
  }
92
100
  static async getIPCSocketClient() {
93
- const socketPath = (0, import_path.resolve)(process.cwd(), process.env.SOCKET_PATH || "storage/gateway.sock");
101
+ const socketPath = getSocketPath();
94
102
  try {
95
103
  return await import_ipc_socket_client.IPCSocketClient.getConnection(socketPath);
96
104
  } catch (error) {
@@ -166,7 +174,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
166
174
  }
167
175
  async requestHandler(req, res) {
168
176
  const { pathname } = (0, import_url.parse)(req.url);
169
- const { PLUGIN_STATICS_PATH, APP_PUBLIC_PATH } = process.env;
177
+ const { PLUGIN_STATICS_PATH, APP_PUBLIC_PATH } = import_node_process.default.env;
170
178
  if (pathname.endsWith("/__umi/api/bundle-status")) {
171
179
  res.statusCode = 200;
172
180
  res.end("ok");
@@ -176,7 +184,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
176
184
  req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
177
185
  await compress(req, res);
178
186
  return (0, import_serve_handler.default)(req, res, {
179
- public: (0, import_path.resolve)(process.cwd()),
187
+ public: (0, import_path.resolve)(import_node_process.default.cwd()),
180
188
  directoryListing: false
181
189
  });
182
190
  }
@@ -195,15 +203,22 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
195
203
  ]
196
204
  });
197
205
  }
198
- if (!pathname.startsWith(process.env.API_BASE_PATH)) {
206
+ if (!pathname.startsWith(import_node_process.default.env.API_BASE_PATH)) {
199
207
  req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
200
208
  await compress(req, res);
201
209
  return (0, import_serve_handler.default)(req, res, {
202
- public: `${process.env.APP_PACKAGE_ROOT}/dist/client`,
210
+ public: `${import_node_process.default.env.APP_PACKAGE_ROOT}/dist/client`,
203
211
  rewrites: [{ source: "/**", destination: "/index.html" }]
204
212
  });
205
213
  }
206
- const handleApp = await this.getRequestHandleAppName(req);
214
+ let handleApp = "main";
215
+ try {
216
+ handleApp = await this.getRequestHandleAppName(req);
217
+ } catch (error) {
218
+ console.log(error);
219
+ this.responseErrorWithCode("APP_INITIALIZING", res, { appName: handleApp });
220
+ return;
221
+ }
207
222
  const hasApp = import_app_supervisor.AppSupervisor.getInstance().hasApp(handleApp);
208
223
  if (!hasApp) {
209
224
  void import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleApp);
@@ -257,10 +272,10 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
257
272
  }
258
273
  /* istanbul ignore next -- @preserve */
259
274
  async watch() {
260
- if (!process.env.IS_DEV_CMD) {
275
+ if (!import_node_process.default.env.IS_DEV_CMD) {
261
276
  return;
262
277
  }
263
- const file = process.env.WATCH_FILE;
278
+ const file = import_node_process.default.env.WATCH_FILE;
264
279
  if (!import_fs.default.existsSync(file)) {
265
280
  await import_fs.default.promises.writeFile(file, `export const watchId = '${(0, import_utils.uid)()}';`, "utf-8");
266
281
  }
@@ -273,8 +288,8 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
273
288
  if (isStart) {
274
289
  await this.watch();
275
290
  const startOptions = this.getStartOptions();
276
- const port = startOptions.port || process.env.APP_PORT || 13e3;
277
- const host = startOptions.host || process.env.APP_HOST || "0.0.0.0";
291
+ const port = startOptions.port || import_node_process.default.env.APP_PORT || 13e3;
292
+ const host = startOptions.host || import_node_process.default.env.APP_HOST || "0.0.0.0";
278
293
  this.start({
279
294
  port,
280
295
  host
@@ -282,7 +297,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
282
297
  } else if (!this.isHelp()) {
283
298
  ipcClient = await this.tryConnectToIPCServer();
284
299
  if (ipcClient) {
285
- const response = await ipcClient.write({ type: "passCliArgv", payload: { argv: process.argv } });
300
+ const response = await ipcClient.write({ type: "passCliArgv", payload: { argv: import_node_process.default.argv } });
286
301
  ipcClient.close();
287
302
  if (!["error", "not_found"].includes(response.type)) {
288
303
  return;
@@ -293,15 +308,19 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
293
308
  await (0, import_plugin_symlink.createStoragePluginsSymlink)();
294
309
  }
295
310
  const mainApp = import_app_supervisor.AppSupervisor.getInstance().bootMainApp(options.mainAppOptions);
296
- mainApp.runAsCLI(process.argv, {
297
- throwError: true,
298
- from: "node"
299
- }).then(async () => {
311
+ let runArgs = [import_node_process.default.argv, { throwError: true, from: "node" }];
312
+ if (!import_node_worker_threads.isMainThread) {
313
+ runArgs = [import_node_worker_threads.workerData.argv, { throwError: true, from: "user" }];
314
+ }
315
+ mainApp.runAsCLI(...runArgs).then(async () => {
300
316
  if (!isStart && !await mainApp.isStarted()) {
301
317
  await mainApp.stop({ logging: false });
302
318
  }
303
319
  }).catch(async (e) => {
304
320
  if (e.code !== "commander.helpDisplayed") {
321
+ if (!import_node_worker_threads.isMainThread) {
322
+ throw e;
323
+ }
305
324
  mainApp.log.error(e);
306
325
  }
307
326
  if (!isStart && !await mainApp.isStarted()) {
@@ -310,16 +329,16 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
310
329
  });
311
330
  }
312
331
  isStart() {
313
- const argv = process.argv;
332
+ const argv = import_node_process.default.argv;
314
333
  return argv[2] === "start";
315
334
  }
316
335
  isHelp() {
317
- const argv = process.argv;
336
+ const argv = import_node_process.default.argv;
318
337
  return argv[2] === "help";
319
338
  }
320
339
  getStartOptions() {
321
340
  const program = new import_commander.Command();
322
- program.allowUnknownOption().option("-s, --silent").option("-p, --port [post]").option("-h, --host [host]").option("--db-sync").parse(process.argv);
341
+ program.allowUnknownOption().option("-s, --silent").option("-p, --port [post]").option("-h, --host [host]").option("--db-sync").parse(import_node_process.default.argv);
323
342
  return program.opts();
324
343
  }
325
344
  start(options) {
@@ -344,7 +363,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
344
363
  this.wsServer = new import_ws_server.WSServer();
345
364
  this.server.on("upgrade", (request, socket, head) => {
346
365
  const { pathname } = (0, import_url.parse)(request.url);
347
- if (pathname === process.env.WS_PATH) {
366
+ if (pathname === import_node_process.default.env.WS_PATH) {
348
367
  this.wsServer.wss.handleUpgrade(request, socket, head, (ws) => {
349
368
  this.wsServer.wss.emit("connection", ws, request);
350
369
  });
@@ -7,29 +7,45 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
  /// <reference types="node" />
10
+ /// <reference types="node" />
10
11
  import WebSocket from 'ws';
11
12
  import { IncomingMessage } from 'http';
12
13
  import { Logger } from '@nocobase/logger';
14
+ import EventEmitter from 'events';
13
15
  declare class WebSocketWithId extends WebSocket {
14
16
  id: string;
15
17
  }
16
18
  interface WebSocketClient {
17
19
  ws: WebSocketWithId;
18
- tags: string[];
20
+ tags: Set<string>;
19
21
  url: string;
20
22
  headers: any;
21
23
  app?: string;
24
+ id: string;
22
25
  }
23
- export declare class WSServer {
26
+ export declare class WSServer extends EventEmitter {
24
27
  wss: WebSocket.Server;
25
28
  webSocketClients: Map<string, WebSocketClient>;
26
29
  logger: Logger;
27
30
  constructor();
31
+ bindAppWSEvents(app: any): void;
28
32
  addNewConnection(ws: WebSocketWithId, request: IncomingMessage): WebSocketClient;
33
+ setClientTag(clientId: string, tagKey: string, tagValue: string): void;
34
+ removeClientTag(clientId: string, tagKey: string): void;
29
35
  setClientApp(client: WebSocketClient): Promise<void>;
30
36
  removeConnection(id: string): void;
31
37
  sendMessageToConnection(client: WebSocketClient, sendMessage: object): void;
32
38
  sendToConnectionsByTag(tagName: string, tagValue: string, sendMessage: object): void;
39
+ /**
40
+ * Send message to clients that match all the given tag conditions
41
+ * @param tags Array of tag conditions, each condition is an object with tagName and tagValue
42
+ * @param sendMessage Message to be sent
43
+ */
44
+ sendToConnectionsByTags(tags: Array<{
45
+ tagName: string;
46
+ tagValue: string;
47
+ }>, sendMessage: object): void;
48
+ sendToClient(clientId: string, sendMessage: object): void;
33
49
  loopThroughConnections(callback: (client: WebSocketClient) => void): void;
34
50
  close(): void;
35
51
  }
@@ -46,16 +46,18 @@ var import_nanoid = require("nanoid");
46
46
  var import_app_supervisor = require("../app-supervisor");
47
47
  var import_errors = require("./errors");
48
48
  var import_lodash = __toESM(require("lodash"));
49
+ var import_events = __toESM(require("events"));
49
50
  function getPayloadByErrorCode(code, options) {
50
51
  const error = (0, import_errors.getErrorWithCode)(code);
51
52
  return import_lodash.default.omit((0, import_errors.applyErrorWithArgs)(error, options), ["status", "maintaining"]);
52
53
  }
53
54
  __name(getPayloadByErrorCode, "getPayloadByErrorCode");
54
- const _WSServer = class _WSServer {
55
+ const _WSServer = class _WSServer extends import_events.default {
55
56
  wss;
56
57
  webSocketClients = /* @__PURE__ */ new Map();
57
58
  logger;
58
59
  constructor() {
60
+ super();
59
61
  this.wss = new import_ws.WebSocketServer({ noServer: true });
60
62
  this.wss.on("connection", (ws, request) => {
61
63
  const client = this.addNewConnection(ws, request);
@@ -66,6 +68,15 @@ const _WSServer = class _WSServer {
66
68
  ws.on("close", () => {
67
69
  this.removeConnection(ws.id);
68
70
  });
71
+ ws.on("message", (message) => {
72
+ if (message.toString() === "ping") {
73
+ return;
74
+ }
75
+ this.emit("message", {
76
+ client,
77
+ message
78
+ });
79
+ });
69
80
  });
70
81
  import_gateway.Gateway.getInstance().on("appSelectorChanged", () => {
71
82
  this.loopThroughConnections(async (client) => {
@@ -73,8 +84,12 @@ const _WSServer = class _WSServer {
73
84
  url: client.url,
74
85
  headers: client.headers
75
86
  });
76
- client.tags = client.tags.filter((tag) => !tag.startsWith("app#"));
77
- client.tags.push(`app#${handleAppName}`);
87
+ for (const tag of client.tags) {
88
+ if (tag.startsWith("app#")) {
89
+ client.tags.delete(tag);
90
+ }
91
+ }
92
+ client.tags.add(`app#${handleAppName}`);
78
93
  import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleAppName);
79
94
  });
80
95
  });
@@ -118,19 +133,87 @@ const _WSServer = class _WSServer {
118
133
  }
119
134
  });
120
135
  });
136
+ import_app_supervisor.AppSupervisor.getInstance().on("afterAppAdded", (app) => {
137
+ this.bindAppWSEvents(app);
138
+ });
139
+ this.on("message", async ({ client, message }) => {
140
+ const app = await import_app_supervisor.AppSupervisor.getInstance().getApp(client.app);
141
+ if (!app) {
142
+ return;
143
+ }
144
+ const parsedMessage = JSON.parse(message.toString());
145
+ if (!parsedMessage.type) {
146
+ return;
147
+ }
148
+ const eventName = `ws:message:${parsedMessage.type}`;
149
+ app.emit(eventName, {
150
+ clientId: client.id,
151
+ tags: [...client.tags],
152
+ payload: parsedMessage.payload
153
+ });
154
+ });
155
+ }
156
+ bindAppWSEvents(app) {
157
+ if (app.listenerCount("ws:setTag") > 0) {
158
+ return;
159
+ }
160
+ app.on("ws:setTag", ({ clientId, tagKey, tagValue }) => {
161
+ this.setClientTag(clientId, tagKey, tagValue);
162
+ });
163
+ app.on("ws:removeTag", ({ clientId, tagKey }) => {
164
+ this.removeClientTag(clientId, tagKey);
165
+ });
166
+ app.on("ws:sendToTag", ({ tagKey, tagValue, message }) => {
167
+ this.sendToConnectionsByTags(
168
+ [
169
+ { tagName: tagKey, tagValue },
170
+ { tagName: "app", tagValue: app.name }
171
+ ],
172
+ message
173
+ );
174
+ });
175
+ app.on("ws:sendToClient", ({ clientId, message }) => {
176
+ this.sendToClient(clientId, message);
177
+ });
178
+ app.on("ws:sendToCurrentApp", ({ message }) => {
179
+ this.sendToConnectionsByTag("app", app.name, message);
180
+ });
181
+ app.on("ws:sendToTags", ({ tags, message }) => {
182
+ this.sendToConnectionsByTags(tags, message);
183
+ });
184
+ app.on("ws:authorized", ({ clientId, userId }) => {
185
+ this.sendToClient(clientId, { type: "authorized" });
186
+ });
121
187
  }
122
188
  addNewConnection(ws, request) {
123
189
  const id = (0, import_nanoid.nanoid)();
124
190
  ws.id = id;
125
191
  this.webSocketClients.set(id, {
126
192
  ws,
127
- tags: [],
193
+ tags: /* @__PURE__ */ new Set(),
128
194
  url: request.url,
129
- headers: request.headers
195
+ headers: request.headers,
196
+ id
130
197
  });
131
198
  this.setClientApp(this.webSocketClients.get(id));
132
199
  return this.webSocketClients.get(id);
133
200
  }
201
+ setClientTag(clientId, tagKey, tagValue) {
202
+ const client = this.webSocketClients.get(clientId);
203
+ if (!client) {
204
+ return;
205
+ }
206
+ client.tags.add(`${tagKey}#${tagValue}`);
207
+ console.log(`client tags: ${Array.from(client.tags)}`);
208
+ }
209
+ removeClientTag(clientId, tagKey) {
210
+ const client = this.webSocketClients.get(clientId);
211
+ client.tags.forEach((tag) => {
212
+ if (tag.startsWith(tagKey)) {
213
+ client.tags.delete(tag);
214
+ }
215
+ });
216
+ }
134
217
  async setClientApp(client) {
135
218
  const req = {
136
219
  url: client.url,
@@ -139,31 +222,11 @@ const _WSServer = class _WSServer {
139
222
  const handleAppName = await import_gateway.Gateway.getInstance().getRequestHandleAppName(req);
140
223
  client.app = handleAppName;
141
224
  console.log(`client tags: app#${handleAppName}`);
142
- client.tags.push(`app#${handleAppName}`);
225
+ client.tags.add(`app#${handleAppName}`);
143
226
  const hasApp = import_app_supervisor.AppSupervisor.getInstance().hasApp(handleAppName);
144
227
  if (!hasApp) {
145
228
  import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleAppName);
146
229
  }
147
- const appStatus = import_app_supervisor.AppSupervisor.getInstance().getAppStatus(handleAppName, "initializing");
148
- if (appStatus === "not_found") {
149
- this.sendMessageToConnection(client, {
150
- type: "maintaining",
151
- payload: getPayloadByErrorCode("APP_NOT_FOUND", { appName: handleAppName })
152
- });
153
- return;
154
- }
155
- if (appStatus === "initializing") {
156
- this.sendMessageToConnection(client, {
157
- type: "maintaining",
158
- payload: getPayloadByErrorCode("APP_INITIALIZING", { appName: handleAppName })
159
- });
160
- return;
161
- }
162
- const app = await import_app_supervisor.AppSupervisor.getInstance().getApp(handleAppName);
163
- this.sendMessageToConnection(client, {
164
- type: "maintaining",
165
- payload: getPayloadByErrorCode(appStatus, { app })
166
- });
167
230
  }
168
231
  removeConnection(id) {
169
232
  console.log(`client disconnected ${id}`);
@@ -173,12 +236,27 @@ const _WSServer = class _WSServer {
173
236
  client.ws.send(JSON.stringify(sendMessage));
174
237
  }
175
238
  sendToConnectionsByTag(tagName, tagValue, sendMessage) {
239
+ this.sendToConnectionsByTags([{ tagName, tagValue }], sendMessage);
240
+ }
241
+ /**
242
+ * Send message to clients that match all the given tag conditions
243
+ * @param tags Array of tag conditions, each condition is an object with tagName and tagValue
244
+ * @param sendMessage Message to be sent
245
+ */
246
+ sendToConnectionsByTags(tags, sendMessage) {
176
247
  this.loopThroughConnections((client) => {
177
- if (client.tags.includes(`${tagName}#${tagValue}`)) {
248
+ const allTagsMatch = tags.every(({ tagName, tagValue }) => client.tags.has(`${tagName}#${tagValue}`));
249
+ if (allTagsMatch) {
178
250
  this.sendMessageToConnection(client, sendMessage);
179
251
  }
180
252
  });
181
253
  }
254
+ sendToClient(clientId, sendMessage) {
255
+ const client = this.webSocketClients.get(clientId);
256
+ if (client) {
257
+ this.sendMessageToConnection(client, sendMessage);
258
+ }
259
+ }
182
260
  loopThroughConnections(callback) {
183
261
  this.webSocketClients.forEach((client) => {
184
262
  callback(client);
@@ -36,7 +36,7 @@ async function dataTemplate(ctx, next) {
36
36
  await next();
37
37
  if (isTemplate && actionName === "get") {
38
38
  ctx.body = traverseJSON(JSON.parse(JSON.stringify(ctx.body)), {
39
- collection: ctx.db.getCollection(resourceName),
39
+ collection: ctx.getCurrentRepository().collection,
40
40
  include: [...fields || [], ...appends || []]
41
41
  });
42
42
  }
@@ -101,7 +101,7 @@ const traverseJSON = /* @__PURE__ */ __name((data, options) => {
101
101
  result[key] = data[key];
102
102
  continue;
103
103
  }
104
- if (field.options.primaryKey && excludePk) {
104
+ if (field.options.primaryKey && excludePk && !collection.isMultiFilterTargetKey()) {
105
105
  continue;
106
106
  }
107
107
  if (field.options.isForeignKey) {
@@ -67,7 +67,7 @@ export declare class PluginManager {
67
67
  /**
68
68
  * @internal
69
69
  */
70
- static getPackageName(name: string): Promise<string>;
70
+ static getPackageName(name: string): Promise<any>;
71
71
  /**
72
72
  * @internal
73
73
  */
@@ -75,7 +75,7 @@ export declare class PluginManager {
75
75
  /**
76
76
  * @internal
77
77
  */
78
- static findPackage(name: string): Promise<string>;
78
+ static findPackage(name: string): Promise<any>;
79
79
  /**
80
80
  * @internal
81
81
  */
@@ -89,9 +89,9 @@ export declare class PluginManager {
89
89
  addPreset(plugin: string | typeof Plugin, options?: any): void;
90
90
  getPlugins(): Map<typeof Plugin, Plugin<any>>;
91
91
  getAliases(): IterableIterator<string>;
92
- get(name: string | typeof Plugin): Plugin<any>;
92
+ get<T extends Plugin>(name: string | typeof Plugin | (new () => T)): T;
93
93
  has(name: string | typeof Plugin): boolean;
94
- del(name: string | typeof Plugin): void;
94
+ del(name: any): void;
95
95
  create(pluginName: string, options?: {
96
96
  forceRecreate?: boolean;
97
97
  }): Promise<void>;
@@ -139,15 +139,12 @@ const _PluginManager = class _PluginManager {
139
139
  * @internal
140
140
  */
141
141
  static async getPackageName(name) {
142
- const prefixes = this.getPluginPkgPrefix();
143
- for (const prefix of prefixes) {
144
- const pkg = (0, import_path.resolve)(process.env.NODE_MODULES_PATH, `${prefix}${name}`, "package.json");
145
- const exists = await import_fs_extra.default.exists(pkg);
146
- if (exists) {
147
- return `${prefix}${name}`;
148
- }
142
+ const { packageName } = await this.parseName(name);
143
+ const packageFile = (0, import_path.resolve)(process.env.NODE_MODULES_PATH, packageName, "package.json");
144
+ if (!await import_fs_extra.default.exists(packageFile)) {
145
+ return null;
149
146
  }
150
- throw new Error(`${name} plugin does not exist`);
147
+ return packageName;
151
148
  }
152
149
  /**
153
150
  * @internal
@@ -312,7 +309,9 @@ const _PluginManager = class _PluginManager {
312
309
  try {
313
310
  if (typeof plugin === "string" && options.name && !options.packageName) {
314
311
  const packageName = await _PluginManager.getPackageName(options.name);
315
- options["packageName"] = packageName;
312
+ if (packageName) {
313
+ options["packageName"] = packageName;
314
+ }
316
315
  }
317
316
  if (options.packageName) {
318
317
  const packageJson = await _PluginManager.getPackageJson(options.packageName);
@@ -320,12 +319,14 @@ const _PluginManager = class _PluginManager {
320
319
  options["version"] = packageJson.version;
321
320
  }
322
321
  } catch (error) {
322
+ this.app.log.error(error);
323
323
  console.error(error);
324
324
  }
325
- this.app.log.trace(`add plugin [${options.name}]`, {
325
+ this.app.log.trace(`adding plugin [${options.name}]`, {
326
326
  method: "add",
327
327
  submodule: "plugin-manager",
328
- name: options.name
328
+ name: options.name,
329
+ options
329
330
  });
330
331
  let P;
331
332
  try {
@@ -343,6 +344,12 @@ const _PluginManager = class _PluginManager {
343
344
  this.pluginAliases.set(options.packageName, instance);
344
345
  }
345
346
  await instance.afterAdd();
347
+ this.app.log.trace(`added plugin [${options.name}]`, {
348
+ method: "add",
349
+ submodule: "plugin-manager",
350
+ name: instance.name,
351
+ options: instance.options
352
+ });
346
353
  }
347
354
  /**
348
355
  * @internal
@@ -364,15 +371,20 @@ const _PluginManager = class _PluginManager {
364
371
  const packageNames = items.map((item) => item.packageName);
365
372
  const source = [];
366
373
  for (const packageName of packageNames) {
367
- const dirname = await (0, import_utils2.getPluginBasePath)(packageName);
368
- const directory = (0, import_path.join)(dirname, "server/commands/*." + ((0, import_path.basename)(dirname) === "src" ? "ts" : "js"));
369
- source.push(directory.replaceAll(import_path.sep, "/"));
374
+ try {
375
+ const dirname = await (0, import_utils2.getPluginBasePath)(packageName);
376
+ const directory = (0, import_path.join)(dirname, "server/commands/*." + ((0, import_path.basename)(dirname) === "src" ? "{ts,js}" : "js"));
377
+ source.push(directory.replaceAll(import_path.sep, "/"));
378
+ } catch (error) {
379
+ this.app.log.error(error);
380
+ continue;
381
+ }
370
382
  }
371
383
  for (const plugin of this.options.plugins || []) {
372
384
  if (typeof plugin === "string") {
373
385
  const { packageName } = await _PluginManager.parseName(plugin);
374
386
  const dirname = await (0, import_utils2.getPluginBasePath)(packageName);
375
- const directory = (0, import_path.join)(dirname, "server/commands/*." + ((0, import_path.basename)(dirname) === "src" ? "ts" : "js"));
387
+ const directory = (0, import_path.join)(dirname, "server/commands/*." + ((0, import_path.basename)(dirname) === "src" ? "{ts,js}" : "js"));
376
388
  source.push(directory.replaceAll(import_path.sep, "/"));
377
389
  }
378
390
  }
@@ -0,0 +1,5 @@
1
+ export declare class ServiceContainer {
2
+ private services;
3
+ register<T>(name: string, service: T): void;
4
+ get<T>(name: string): T;
5
+ }
@@ -0,0 +1,50 @@
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 __name = (target, value) => __defProp(target, "name", { value, configurable: true });
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
18
+ };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") {
21
+ for (let key of __getOwnPropNames(from))
22
+ if (!__hasOwnProp.call(to, key) && key !== except)
23
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
+ }
25
+ return to;
26
+ };
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var service_container_exports = {};
29
+ __export(service_container_exports, {
30
+ ServiceContainer: () => ServiceContainer
31
+ });
32
+ module.exports = __toCommonJS(service_container_exports);
33
+ const _ServiceContainer = class _ServiceContainer {
34
+ services = /* @__PURE__ */ new Map();
35
+ register(name, service) {
36
+ if (typeof service === "function") {
37
+ service = service();
38
+ }
39
+ this.services.set(name, service);
40
+ }
41
+ get(name) {
42
+ return this.services.get(name);
43
+ }
44
+ };
45
+ __name(_ServiceContainer, "ServiceContainer");
46
+ let ServiceContainer = _ServiceContainer;
47
+ // Annotate the CommonJS export names for ESM import in node:
48
+ 0 && (module.exports = {
49
+ ServiceContainer
50
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/server",
3
- "version": "1.5.0-beta.8",
3
+ "version": "1.5.0",
4
4
  "main": "lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "license": "AGPL-3.0",
@@ -10,19 +10,19 @@
10
10
  "@koa/cors": "^3.1.0",
11
11
  "@koa/multer": "^3.0.2",
12
12
  "@koa/router": "^9.4.0",
13
- "@nocobase/acl": "1.5.0-beta.8",
14
- "@nocobase/actions": "1.5.0-beta.8",
15
- "@nocobase/auth": "1.5.0-beta.8",
16
- "@nocobase/cache": "1.5.0-beta.8",
17
- "@nocobase/data-source-manager": "1.5.0-beta.8",
18
- "@nocobase/database": "1.5.0-beta.8",
19
- "@nocobase/evaluators": "1.5.0-beta.8",
20
- "@nocobase/lock-manager": "1.5.0-beta.8",
21
- "@nocobase/logger": "1.5.0-beta.8",
22
- "@nocobase/resourcer": "1.5.0-beta.8",
23
- "@nocobase/sdk": "1.5.0-beta.8",
24
- "@nocobase/telemetry": "1.5.0-beta.8",
25
- "@nocobase/utils": "1.5.0-beta.8",
13
+ "@nocobase/acl": "1.5.0",
14
+ "@nocobase/actions": "1.5.0",
15
+ "@nocobase/auth": "1.5.0",
16
+ "@nocobase/cache": "1.5.0",
17
+ "@nocobase/data-source-manager": "1.5.0",
18
+ "@nocobase/database": "1.5.0",
19
+ "@nocobase/evaluators": "1.5.0",
20
+ "@nocobase/lock-manager": "1.5.0",
21
+ "@nocobase/logger": "1.5.0",
22
+ "@nocobase/resourcer": "1.5.0",
23
+ "@nocobase/sdk": "1.5.0",
24
+ "@nocobase/telemetry": "1.5.0",
25
+ "@nocobase/utils": "1.5.0",
26
26
  "@types/decompress": "4.2.7",
27
27
  "@types/ini": "^1.3.31",
28
28
  "@types/koa-send": "^4.1.3",
@@ -56,5 +56,5 @@
56
56
  "@types/serve-handler": "^6.1.1",
57
57
  "@types/ws": "^8.5.5"
58
58
  },
59
- "gitHead": "eb7db7301ac5eed305e73540884611832bc761f6"
59
+ "gitHead": "1eae52e1fc837e9b1c6b63fc31bda7945b6101e9"
60
60
  }