@nocobase/server 2.0.0-alpha.7 → 2.0.0-alpha.71

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 (58) hide show
  1. package/lib/acl/available-action.js +1 -1
  2. package/lib/aes-encryptor.d.ts +1 -0
  3. package/lib/aes-encryptor.js +12 -5
  4. package/lib/app-command.d.ts +1 -0
  5. package/lib/app-command.js +3 -0
  6. package/lib/app-supervisor/app-options-factory.d.ts +80 -0
  7. package/lib/app-supervisor/app-options-factory.js +91 -0
  8. package/lib/app-supervisor/condition-registry.d.ts +18 -0
  9. package/lib/app-supervisor/condition-registry.js +60 -0
  10. package/lib/app-supervisor/db-creator.d.ts +16 -0
  11. package/lib/app-supervisor/db-creator.js +163 -0
  12. package/lib/app-supervisor/db-drivers.d.ts +11 -0
  13. package/lib/app-supervisor/db-drivers.js +52 -0
  14. package/lib/app-supervisor/index.d.ts +161 -0
  15. package/lib/app-supervisor/index.js +690 -0
  16. package/lib/app-supervisor/main-only-adapter.d.ts +37 -0
  17. package/lib/app-supervisor/main-only-adapter.js +156 -0
  18. package/lib/app-supervisor/types.d.ts +161 -0
  19. package/lib/app-supervisor/types.js +24 -0
  20. package/lib/application.d.ts +10 -7
  21. package/lib/application.js +30 -18
  22. package/lib/commands/index.js +2 -0
  23. package/lib/commands/pm.js +11 -0
  24. package/lib/commands/repair.d.ts +11 -0
  25. package/lib/commands/repair.js +43 -0
  26. package/lib/commands/start.js +1 -1
  27. package/lib/event-queue.d.ts +8 -1
  28. package/lib/event-queue.js +25 -22
  29. package/lib/gateway/errors.js +50 -12
  30. package/lib/gateway/index.d.ts +8 -0
  31. package/lib/gateway/index.js +80 -16
  32. package/lib/gateway/ipc-socket-server.js +1 -1
  33. package/lib/gateway/ws-server.js +6 -2
  34. package/lib/helper.d.ts +359 -0
  35. package/lib/helper.js +78 -3
  36. package/lib/index.d.ts +2 -1
  37. package/lib/index.js +6 -3
  38. package/lib/locale/locale.js +1 -1
  39. package/lib/locale/resource.js +6 -9
  40. package/lib/main-data-source.d.ts +11 -0
  41. package/lib/main-data-source.js +128 -0
  42. package/lib/middlewares/data-template.js +1 -6
  43. package/lib/middlewares/parse-variables.js +2 -49
  44. package/lib/plugin-manager/deps.js +2 -2
  45. package/lib/plugin-manager/options/resource.js +52 -25
  46. package/lib/plugin-manager/plugin-manager.d.ts +1 -0
  47. package/lib/plugin-manager/plugin-manager.js +36 -1
  48. package/lib/pub-sub-manager/pub-sub-manager.d.ts +1 -1
  49. package/lib/pub-sub-manager/pub-sub-manager.js +14 -20
  50. package/lib/redis-connection-manager.d.ts +15 -5
  51. package/lib/redis-connection-manager.js +117 -24
  52. package/lib/snowflake-id-field.d.ts +2 -1
  53. package/lib/snowflake-id-field.js +2 -2
  54. package/package.json +18 -17
  55. package/lib/app-supervisor.d.ts +0 -69
  56. package/lib/app-supervisor.js +0 -299
  57. package/lib/background-job-manager.d.ts +0 -40
  58. package/lib/background-job-manager.js +0 -111
@@ -0,0 +1,43 @@
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 repair_exports = {};
29
+ __export(repair_exports, {
30
+ default: () => repair_default
31
+ });
32
+ module.exports = __toCommonJS(repair_exports);
33
+ var repair_default = /* @__PURE__ */ __name((app) => {
34
+ app.command("repair").auth().preload().action(async (options) => {
35
+ app.log.info("start repair data...");
36
+ const Collection = app.db.getCollection("collections");
37
+ if (Collection) {
38
+ await Collection.repository.setApp(app);
39
+ await Collection.repository.load();
40
+ }
41
+ await app.emitAsync("repair", options);
42
+ });
43
+ }, "default");
@@ -61,7 +61,7 @@ var start_default = /* @__PURE__ */ __name((app) => {
61
61
  }
62
62
  } else if (options.quickstart) {
63
63
  if (await app.isInstalled()) {
64
- await app.upgrade();
64
+ await app.upgrade({ quickstart: true });
65
65
  } else {
66
66
  await app.install();
67
67
  }
@@ -15,6 +15,7 @@ export type QueueCallbackOptions = {
15
15
  id?: string;
16
16
  retried?: number;
17
17
  signal?: AbortSignal;
18
+ queueOptions?: QueueMessageOptions;
18
19
  };
19
20
  export type QueueCallback = (message: any, options: QueueCallbackOptions) => Promise<void>;
20
21
  export type QueueEventOptions = {
@@ -23,6 +24,12 @@ export type QueueEventOptions = {
23
24
  */
24
25
  interval?: number;
25
26
  concurrency?: number;
27
+ /**
28
+ * Shared across multiple applications.
29
+ * Will not use app prefix for channel name.
30
+ * @experimental
31
+ */
32
+ shared?: boolean;
26
33
  idle(): boolean;
27
34
  process: QueueCallback;
28
35
  };
@@ -84,7 +91,7 @@ export declare class EventQueue {
84
91
  protected events: Map<string, QueueEventOptions>;
85
92
  get channelPrefix(): string;
86
93
  constructor(app: Application, options?: EventQueueOptions);
87
- getFullChannel(channel: string): string;
94
+ getFullChannel(channel: string, shared?: boolean): string;
88
95
  setAdapter<A extends IEventQueueAdapter>(adapter: A): void;
89
96
  isConnected(): boolean;
90
97
  connect(): Promise<void>;
@@ -245,7 +245,8 @@ const _MemoryEventQueueAdapter = class _MemoryEventQueueAdapter {
245
245
  return (async () => event.process(content, {
246
246
  id,
247
247
  retried,
248
- signal: AbortSignal.timeout(timeout)
248
+ signal: AbortSignal.timeout(timeout),
249
+ queueOptions: message.options
249
250
  }))().then(() => {
250
251
  logger.debug(`memory queue (${channel}) consumed message (${id})`);
251
252
  }).catch((ex) => {
@@ -270,16 +271,14 @@ const _EventQueue = class _EventQueue {
270
271
  constructor(app, options = {}) {
271
272
  this.app = app;
272
273
  this.options = options;
273
- if (app.serving()) {
274
- this.setAdapter(new MemoryEventQueueAdapter({ appName: this.app.name, logger: this.app.logger }));
275
- app.on("afterStart", async () => {
276
- await this.connect();
277
- });
278
- app.on("beforeStop", async () => {
279
- app.logger.info("[queue] gracefully shutting down...");
280
- await this.close();
281
- });
282
- }
274
+ this.setAdapter(new MemoryEventQueueAdapter({ appName: this.app.name, logger: this.app.logger }));
275
+ app.on("afterStart", async () => {
276
+ await this.connect();
277
+ });
278
+ app.on("afterStop", async () => {
279
+ app.logger.info("[queue] gracefully shutting down...");
280
+ await this.close();
281
+ });
283
282
  }
284
283
  adapter;
285
284
  events = /* @__PURE__ */ new Map();
@@ -287,7 +286,10 @@ const _EventQueue = class _EventQueue {
287
286
  var _a;
288
287
  return (_a = this.options) == null ? void 0 : _a.channelPrefix;
289
288
  }
290
- getFullChannel(channel) {
289
+ getFullChannel(channel, shared = false) {
290
+ if (shared) {
291
+ return [this.channelPrefix, channel].filter(Boolean).join(".");
292
+ }
291
293
  return [this.app.name, this.channelPrefix, channel].filter(Boolean).join(".");
292
294
  }
293
295
  setAdapter(adapter) {
@@ -303,14 +305,10 @@ const _EventQueue = class _EventQueue {
303
305
  if (!this.adapter) {
304
306
  throw new Error("no adapter set, cannot connect");
305
307
  }
306
- if (!this.app.serving()) {
307
- this.app.logger.warn("app is not serving, will not connect to event queue");
308
- return;
309
- }
310
308
  await this.adapter.connect();
311
309
  this.app.logger.debug(`connected to adapter, using memory? ${this.adapter instanceof MemoryEventQueueAdapter}`);
312
310
  for (const [channel, event] of this.events.entries()) {
313
- this.adapter.subscribe(this.getFullChannel(channel), event);
311
+ this.adapter.subscribe(this.getFullChannel(channel, event.shared), event);
314
312
  }
315
313
  }
316
314
  async close() {
@@ -318,8 +316,8 @@ const _EventQueue = class _EventQueue {
318
316
  return;
319
317
  }
320
318
  await this.adapter.close();
321
- for (const channel of this.events.keys()) {
322
- this.adapter.unsubscribe(this.getFullChannel(channel));
319
+ for (const [channel, event] of this.events.entries()) {
320
+ this.adapter.unsubscribe(this.getFullChannel(channel, event.shared));
323
321
  }
324
322
  }
325
323
  subscribe(channel, options) {
@@ -329,16 +327,17 @@ const _EventQueue = class _EventQueue {
329
327
  }
330
328
  this.events.set(channel, options);
331
329
  if (this.isConnected()) {
332
- this.adapter.subscribe(this.getFullChannel(channel), options);
330
+ this.adapter.subscribe(this.getFullChannel(channel, options.shared), this.events.get(channel));
333
331
  }
334
332
  }
335
333
  unsubscribe(channel) {
334
+ var _a;
336
335
  if (!this.events.has(channel)) {
337
336
  return;
338
337
  }
339
338
  this.events.delete(channel);
340
339
  if (this.isConnected()) {
341
- this.adapter.unsubscribe(this.getFullChannel(channel));
340
+ this.adapter.unsubscribe(this.getFullChannel(channel, (_a = this.events.get(channel)) == null ? void 0 : _a.shared));
342
341
  }
343
342
  }
344
343
  async publish(channel, message, options = {}) {
@@ -348,7 +347,11 @@ const _EventQueue = class _EventQueue {
348
347
  if (!this.isConnected()) {
349
348
  throw new Error("event queue not connected, cannot publish");
350
349
  }
351
- const c = this.getFullChannel(channel);
350
+ const event = this.events.get(channel);
351
+ if (!event) {
352
+ throw new Error(`event queue not subscribed on channel "${channel}", cannot publish`);
353
+ }
354
+ const c = this.getFullChannel(channel, event.shared);
352
355
  this.app.logger.debug(`event queue publishing to channel(${c})`, { message });
353
356
  await this.adapter.publish(c, message, {
354
357
  timeout: QUEUE_DEFAULT_ACK_TIMEOUT,
@@ -44,6 +44,15 @@ __export(errors_exports, {
44
44
  module.exports = __toCommonJS(errors_exports);
45
45
  var import_app_supervisor = require("../app-supervisor");
46
46
  var import_lodash = __toESM(require("lodash"));
47
+ function getMaintaining(app) {
48
+ var _a;
49
+ return (_a = app == null ? void 0 : app.getMaintaining) == null ? void 0 : _a.call(app);
50
+ }
51
+ __name(getMaintaining, "getMaintaining");
52
+ function getAppName(app) {
53
+ return (app == null ? void 0 : app.name) || "unknown";
54
+ }
55
+ __name(getAppName, "getAppName");
47
56
  const errors = {
48
57
  APP_NOT_FOUND: {
49
58
  status: 404,
@@ -53,6 +62,9 @@ const errors = {
53
62
  APP_ERROR: {
54
63
  status: 503,
55
64
  message: /* @__PURE__ */ __name(({ app }) => {
65
+ if (!(app == null ? void 0 : app.name)) {
66
+ return "";
67
+ }
56
68
  const error = import_app_supervisor.AppSupervisor.getInstance().appErrors[app.name];
57
69
  if (!error) {
58
70
  return "";
@@ -64,25 +76,36 @@ const errors = {
64
76
  return message;
65
77
  }, "message"),
66
78
  code: /* @__PURE__ */ __name(({ app }) => {
79
+ if (!(app == null ? void 0 : app.name)) {
80
+ return "APP_ERROR";
81
+ }
67
82
  const error = import_app_supervisor.AppSupervisor.getInstance().appErrors[app.name];
68
- return error["code"] || "APP_ERROR";
83
+ return (error == null ? void 0 : error["code"]) || "APP_ERROR";
69
84
  }, "code"),
70
- command: /* @__PURE__ */ __name(({ app }) => app.getMaintaining().command, "command"),
85
+ command: /* @__PURE__ */ __name(({ app }) => {
86
+ var _a;
87
+ return (_a = getMaintaining(app)) == null ? void 0 : _a.command;
88
+ }, "command"),
89
+ maintaining: true
90
+ },
91
+ APP_PREPARING: {
92
+ status: 503,
93
+ message: /* @__PURE__ */ __name(({ appName }) => `application ${appName} is preparing, please wait patiently`, "message"),
71
94
  maintaining: true
72
95
  },
73
96
  APP_STARTING: {
74
97
  status: 503,
75
- message: /* @__PURE__ */ __name(({ app }) => app.maintainingMessage, "message"),
98
+ message: /* @__PURE__ */ __name(({ app }) => (app == null ? void 0 : app.maintainingMessage) || "", "message"),
76
99
  maintaining: true
77
100
  },
78
101
  APP_STOPPED: {
79
102
  status: 503,
80
- message: /* @__PURE__ */ __name(({ app }) => `application ${app.name} is stopped`, "message"),
103
+ message: /* @__PURE__ */ __name(({ app, appName }) => `application ${appName || getAppName(app)} is stopped`, "message"),
81
104
  maintaining: true
82
105
  },
83
106
  APP_INITIALIZED: {
84
107
  status: 503,
85
- message: /* @__PURE__ */ __name(({ app }) => `application ${app.name} is initialized, waiting for command`, "message"),
108
+ message: /* @__PURE__ */ __name(({ app }) => `application ${getAppName(app)} is initialized, waiting for command`, "message"),
86
109
  maintaining: true
87
110
  },
88
111
  APP_INITIALIZING: {
@@ -93,25 +116,40 @@ const errors = {
93
116
  COMMAND_ERROR: {
94
117
  status: 503,
95
118
  maintaining: true,
96
- message: /* @__PURE__ */ __name(({ app }) => app.getMaintaining().error.message, "message"),
97
- command: /* @__PURE__ */ __name(({ app }) => app.getMaintaining().command, "command")
119
+ message: /* @__PURE__ */ __name(({ app }) => {
120
+ var _a, _b;
121
+ return ((_b = (_a = getMaintaining(app)) == null ? void 0 : _a.error) == null ? void 0 : _b.message) || "";
122
+ }, "message"),
123
+ command: /* @__PURE__ */ __name(({ app }) => {
124
+ var _a;
125
+ return (_a = getMaintaining(app)) == null ? void 0 : _a.command;
126
+ }, "command")
98
127
  },
99
128
  COMMAND_END: {
100
129
  status: 503,
101
130
  maintaining: true,
102
- message: /* @__PURE__ */ __name(({ app }) => `${app.getMaintaining().command.name} running end`, "message"),
103
- command: /* @__PURE__ */ __name(({ app }) => app.getMaintaining().command, "command")
131
+ message: /* @__PURE__ */ __name(({ app }) => {
132
+ var _a, _b;
133
+ return `${((_b = (_a = getMaintaining(app)) == null ? void 0 : _a.command) == null ? void 0 : _b.name) || "command"} running end`;
134
+ }, "message"),
135
+ command: /* @__PURE__ */ __name(({ app }) => {
136
+ var _a;
137
+ return (_a = getMaintaining(app)) == null ? void 0 : _a.command;
138
+ }, "command")
104
139
  },
105
140
  APP_COMMANDING: {
106
141
  status: 503,
107
142
  maintaining: true,
108
- message: /* @__PURE__ */ __name(({ app, message }) => message || app.maintainingMessage, "message"),
109
- command: /* @__PURE__ */ __name(({ app, command }) => command || app.getMaintaining().command, "command")
143
+ message: /* @__PURE__ */ __name(({ app, message }) => message || (app == null ? void 0 : app.maintainingMessage) || "", "message"),
144
+ command: /* @__PURE__ */ __name(({ app, command }) => {
145
+ var _a;
146
+ return command || ((_a = getMaintaining(app)) == null ? void 0 : _a.command);
147
+ }, "command")
110
148
  },
111
149
  APP_RUNNING: {
112
150
  status: 200,
113
151
  maintaining: false,
114
- message: /* @__PURE__ */ __name(({ message, app }) => message || `application ${app.name} is running`, "message")
152
+ message: /* @__PURE__ */ __name(({ message, app }) => message || `application ${getAppName(app)} is running`, "message")
115
153
  },
116
154
  UNKNOWN_ERROR: {
117
155
  status: 500,
@@ -23,6 +23,12 @@ export interface IncomingRequest {
23
23
  url: string;
24
24
  headers: any;
25
25
  }
26
+ export interface GatewayRequestContext {
27
+ req: IncomingMessage;
28
+ res: ServerResponse;
29
+ appName: string;
30
+ }
31
+ type GatewayMiddleware = (ctx: GatewayRequestContext, next: () => Promise<void>) => Promise<void> | void;
26
32
  export type AppSelector = (req: IncomingRequest) => string | Promise<string>;
27
33
  export type AppSelectorMiddleware = (ctx: AppSelectorMiddlewareContext, next: () => Promise<void>) => void;
28
34
  interface StartHttpServerOptions {
@@ -39,6 +45,7 @@ export interface AppSelectorMiddlewareContext {
39
45
  }
40
46
  export declare class Gateway extends EventEmitter {
41
47
  private static instance;
48
+ middlewares: Toposort<GatewayMiddleware>;
42
49
  /**
43
50
  * use main app as default app to handle request
44
51
  */
@@ -54,6 +61,7 @@ export declare class Gateway extends EventEmitter {
54
61
  private onTerminate;
55
62
  private constructor();
56
63
  static getInstance(options?: any): Gateway;
64
+ use(middleware: GatewayMiddleware, options?: ToposortOptions): void;
57
65
  static getIPCSocketClient(): Promise<false | IPCSocketClient>;
58
66
  destroy(): void;
59
67
  reset(): void;
@@ -75,6 +75,7 @@ function getSocketPath() {
75
75
  }
76
76
  __name(getSocketPath, "getSocketPath");
77
77
  const _Gateway = class _Gateway extends import_events.EventEmitter {
78
+ middlewares;
78
79
  /**
79
80
  * use main app as default app to handle request
80
81
  */
@@ -98,6 +99,9 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
98
99
  try {
99
100
  for (const app of apps) {
100
101
  try {
102
+ if (!app) {
103
+ continue;
104
+ }
101
105
  await app.destroy({ signal });
102
106
  } catch (error) {
103
107
  const logger = (app == null ? void 0 : app.log) ?? console;
@@ -124,6 +128,9 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
124
128
  }
125
129
  return _Gateway.instance;
126
130
  }
131
+ use(middleware, options) {
132
+ this.middlewares.add(middleware, options);
133
+ }
127
134
  static async getIPCSocketClient() {
128
135
  const socketPath = getSocketPath();
129
136
  try {
@@ -139,6 +146,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
139
146
  _Gateway.instance = null;
140
147
  }
141
148
  reset() {
149
+ this.middlewares = new import_utils.Toposort();
142
150
  this.selectorMiddlewares = new import_utils.Toposort();
143
151
  this.addAppSelectorMiddleware(
144
152
  async (ctx, next) => {
@@ -202,7 +210,15 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
202
210
  res.end(JSON.stringify({ error }));
203
211
  }
204
212
  responseErrorWithCode(code, res, options) {
213
+ const log = this.getLogger(options.appName, res);
205
214
  const error = (0, import_errors.applyErrorWithArgs)((0, import_errors.getErrorWithCode)(code), options);
215
+ log.error(error.message, {
216
+ method: "responseErrorWithCode",
217
+ code,
218
+ error,
219
+ statusCode: res.statusCode,
220
+ appName: options.appName
221
+ });
206
222
  this.responseError(res, error);
207
223
  }
208
224
  async requestHandler(req, res) {
@@ -213,7 +229,22 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
213
229
  res.end("ok");
214
230
  return;
215
231
  }
232
+ const supervisor = import_app_supervisor.AppSupervisor.getInstance();
233
+ let handleApp = "main";
234
+ try {
235
+ handleApp = await this.getRequestHandleAppName(req);
236
+ } catch (error) {
237
+ this.getLogger("main", res).error("Failed to get handle app name", { error });
238
+ this.responseErrorWithCode("APP_INITIALIZING", res, { appName: handleApp });
239
+ return;
240
+ }
216
241
  if (pathname.startsWith(APP_PUBLIC_PATH + "storage/uploads/")) {
242
+ if (handleApp !== "main") {
243
+ const isProxy = await supervisor.proxyWeb(handleApp, req, res);
244
+ if (isProxy) {
245
+ return;
246
+ }
247
+ }
217
248
  req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
218
249
  await compress(req, res);
219
250
  return (0, import_serve_handler.default)(req, res, {
@@ -222,6 +253,12 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
222
253
  });
223
254
  }
224
255
  if (pathname.startsWith(PLUGIN_STATICS_PATH) && !pathname.includes("/server/")) {
256
+ if (handleApp !== "main") {
257
+ const isProxy = await supervisor.proxyWeb(handleApp, req, res);
258
+ if (isProxy) {
259
+ return;
260
+ }
261
+ }
225
262
  await compress(req, res);
226
263
  const packageName = (0, import_plugin_manager.getPackageNameByExposeUrl)(pathname);
227
264
  const publicDir = (0, import_plugin_manager.getPackageDirByExposeUrl)(pathname);
@@ -237,6 +274,12 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
237
274
  });
238
275
  }
239
276
  if (!pathname.startsWith(import_node_process.default.env.API_BASE_PATH)) {
277
+ if (handleApp !== "main") {
278
+ const isProxy = await supervisor.proxyWeb(handleApp, req, res);
279
+ if (isProxy) {
280
+ return;
281
+ }
282
+ }
240
283
  req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
241
284
  await compress(req, res);
242
285
  return (0, import_serve_handler.default)(req, res, {
@@ -244,33 +287,43 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
244
287
  rewrites: [{ source: "/**", destination: "/index.html" }]
245
288
  });
246
289
  }
247
- let handleApp = "main";
248
- try {
249
- handleApp = await this.getRequestHandleAppName(req);
250
- } catch (error) {
251
- console.log(error);
252
- this.responseErrorWithCode("APP_INITIALIZING", res, { appName: handleApp });
253
- return;
290
+ if (handleApp !== "main") {
291
+ const isProxy = await supervisor.proxyWeb(handleApp, req, res);
292
+ if (isProxy) {
293
+ return;
294
+ }
254
295
  }
255
- const hasApp = import_app_supervisor.AppSupervisor.getInstance().hasApp(handleApp);
296
+ const hasApp = supervisor.hasApp(handleApp);
256
297
  if (!hasApp) {
257
- void import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleApp);
298
+ void supervisor.bootstrapApp(handleApp);
258
299
  }
259
- let appStatus = import_app_supervisor.AppSupervisor.getInstance().getAppStatus(handleApp, "initializing");
300
+ let appStatus = await supervisor.getAppStatus(handleApp, "preparing");
260
301
  if (appStatus === "not_found") {
261
302
  this.responseErrorWithCode("APP_NOT_FOUND", res, { appName: handleApp });
262
303
  return;
263
304
  }
305
+ if (appStatus === "preparing") {
306
+ this.responseErrorWithCode("APP_PREPARING", res, { appName: handleApp });
307
+ return;
308
+ }
264
309
  if (appStatus === "initializing") {
265
310
  this.responseErrorWithCode("APP_INITIALIZING", res, { appName: handleApp });
266
311
  return;
267
312
  }
268
313
  if (appStatus === "initialized") {
269
- const appInstance = await import_app_supervisor.AppSupervisor.getInstance().getApp(handleApp);
270
- appInstance.runCommand("start", "--quickstart");
271
- appStatus = import_app_supervisor.AppSupervisor.getInstance().getAppStatus(handleApp);
314
+ const appInstance = await supervisor.getApp(handleApp);
315
+ if (!appInstance) {
316
+ this.responseErrorWithCode("APP_NOT_FOUND", res, { appName: handleApp });
317
+ return;
318
+ }
319
+ supervisor.startApp(handleApp);
320
+ appStatus = await supervisor.getAppStatus(handleApp);
321
+ }
322
+ const app = await supervisor.getApp(handleApp);
323
+ if (!app) {
324
+ this.responseErrorWithCode("APP_NOT_FOUND", res, { appName: handleApp });
325
+ return;
272
326
  }
273
- const app = await import_app_supervisor.AppSupervisor.getInstance().getApp(handleApp);
274
327
  if (appStatus !== "running") {
275
328
  this.responseErrorWithCode(`${appStatus}`, res, { app, appName: handleApp });
276
329
  return;
@@ -281,9 +334,16 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
281
334
  return;
282
335
  }
283
336
  if (handleApp !== "main") {
284
- import_app_supervisor.AppSupervisor.getInstance().touchApp(handleApp);
337
+ await supervisor.setAppLastSeenAt(handleApp);
285
338
  }
286
- app.callback()(req, res);
339
+ const ctx = { req, res, appName: handleApp };
340
+ const fn = (0, import_koa_compose.default)([
341
+ ...this.middlewares.nodes,
342
+ async (_ctx) => {
343
+ await app.callback()(req, res);
344
+ }
345
+ ]);
346
+ await fn(ctx);
287
347
  }
288
348
  getAppSelectorMiddlewares() {
289
349
  return this.selectorMiddlewares;
@@ -409,6 +469,10 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
409
469
  });
410
470
  this.wsServer = new import_ws_server.WSServer();
411
471
  this.server.on("upgrade", async (request, socket, head) => {
472
+ const isProxy = await import_app_supervisor.AppSupervisor.getInstance().proxyWs(request, socket, head);
473
+ if (isProxy) {
474
+ return;
475
+ }
412
476
  const appInstance = await import_app_supervisor.AppSupervisor.getInstance().getApp("main");
413
477
  for (const handle of _Gateway.wsServers) {
414
478
  const result = await handle(request, socket, head, appInstance);
@@ -104,7 +104,7 @@ const _IPCSocketServer = class _IPCSocketServer {
104
104
  const max = 300;
105
105
  let count = 0;
106
106
  const timer = setInterval(async () => {
107
- status2 = import_app_supervisor.AppSupervisor.getInstance().getAppStatus("main");
107
+ status2 = await import_app_supervisor.AppSupervisor.getInstance().getAppStatus("main");
108
108
  if (status2 === "running") {
109
109
  clearInterval(timer);
110
110
  resolve(status2);
@@ -90,7 +90,7 @@ const _WSServer = class _WSServer extends import_events.default {
90
90
  }
91
91
  }
92
92
  client.tags.add(`app#${handleAppName}`);
93
- import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleAppName);
93
+ import_app_supervisor.AppSupervisor.getInstance().bootstrapApp(handleAppName);
94
94
  });
95
95
  });
96
96
  import_app_supervisor.AppSupervisor.getInstance().on("appError", async ({ appName, error }) => {
@@ -112,6 +112,7 @@ const _WSServer = class _WSServer extends import_events.default {
112
112
  });
113
113
  const payload = getPayloadByErrorCode(status, {
114
114
  app,
115
+ appName,
115
116
  message,
116
117
  command
117
118
  });
@@ -228,6 +229,9 @@ const _WSServer = class _WSServer extends import_events.default {
228
229
  }
229
230
  removeClientTag(clientId, tagKey) {
230
231
  const client = this.webSocketClients.get(clientId);
232
+ if (!client) {
233
+ return;
234
+ }
231
235
  client.tags.forEach((tag) => {
232
236
  if (tag.startsWith(`${tagKey}#`)) {
233
237
  client.tags.delete(tag);
@@ -245,7 +249,7 @@ const _WSServer = class _WSServer extends import_events.default {
245
249
  client.tags.add(`app#${handleAppName}`);
246
250
  const hasApp = import_app_supervisor.AppSupervisor.getInstance().hasApp(handleAppName);
247
251
  if (!hasApp) {
248
- import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleAppName);
252
+ import_app_supervisor.AppSupervisor.getInstance().bootstrapApp(handleAppName);
249
253
  }
250
254
  }
251
255
  removeConnection(id) {