@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
@@ -37,76 +37,170 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
37
37
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
38
  var redis_connection_manager_exports = {};
39
39
  __export(redis_connection_manager_exports, {
40
- Redis: () => import_ioredis.default,
41
40
  RedisConnectionManager: () => RedisConnectionManager
42
41
  });
43
42
  module.exports = __toCommonJS(redis_connection_manager_exports);
44
- var import_ioredis = __toESM(require("ioredis"));
43
+ var import_merge = __toESM(require("lodash/merge"));
44
+ var import_redis = require("redis");
45
45
  const _RedisConnectionManager = class _RedisConnectionManager {
46
46
  logger;
47
47
  config;
48
48
  connections = /* @__PURE__ */ new Map();
49
+ connectionConfigs = /* @__PURE__ */ new Map();
50
+ connecting = /* @__PURE__ */ new WeakMap();
49
51
  constructor(config) {
50
- this.config = config.redisConfig;
52
+ this.config = config.redisConfig || {};
51
53
  this.logger = config.logger;
52
54
  }
53
55
  bindEvents(conn, key, config) {
54
56
  conn.on("connect", () => {
55
57
  this.logger.info(`Redis connected`, {
56
58
  method: "getConnection",
57
- key,
58
- config
59
+ key
60
+ });
61
+ });
62
+ conn.on("ready", () => {
63
+ this.logger.trace(`Redis ready`, {
64
+ method: "getConnection",
65
+ key
59
66
  });
60
67
  });
61
68
  conn.on("error", (err) => {
62
69
  this.logger.error(err.message, {
63
70
  err,
64
71
  method: "getConnection",
65
- key,
66
- config
72
+ key
67
73
  });
68
74
  });
69
- conn.on("close", () => {
75
+ conn.on("end", () => {
70
76
  this.logger.trace(`Redis closed`, {
71
77
  method: "getConnection",
78
+ key
79
+ });
80
+ });
81
+ }
82
+ mergeConfig(config) {
83
+ return (0, import_merge.default)({}, this.config || {}, config || {});
84
+ }
85
+ hasConnectionOptions(config) {
86
+ if (!config) {
87
+ return false;
88
+ }
89
+ return Boolean(config.connectionString || config.url || config.socket);
90
+ }
91
+ buildClientOptions(config) {
92
+ const { connectionString, ...rest } = config;
93
+ const options = { ...rest };
94
+ if (connectionString && !options.url) {
95
+ options.url = connectionString;
96
+ }
97
+ return options;
98
+ }
99
+ ensureConnected(conn, key, config) {
100
+ if (conn.isOpen || this.connecting.has(conn)) {
101
+ return;
102
+ }
103
+ const promise = conn.connect().catch((err) => {
104
+ this.logger.error(err.message, {
105
+ err,
106
+ method: "connect",
72
107
  key,
73
108
  config
74
109
  });
110
+ this.connections.delete(key);
111
+ this.connectionConfigs.delete(key);
112
+ throw err;
113
+ }).finally(() => {
114
+ this.connecting.delete(conn);
75
115
  });
116
+ this.connecting.set(conn, promise);
76
117
  }
77
118
  getClient(key = "default", config) {
78
119
  let conn = this.connections.get(key);
79
120
  if (conn) {
121
+ this.ensureConnected(conn, key, this.connectionConfigs.get(key));
80
122
  return conn;
81
123
  }
82
- const cfg = config || this.config;
83
- if (!cfg.connectionString) {
124
+ const cfg = this.mergeConfig(config);
125
+ if (!this.hasConnectionOptions(cfg)) {
84
126
  return null;
85
127
  }
86
- conn = new import_ioredis.default(cfg.connectionString);
128
+ conn = (0, import_redis.createClient)(this.buildClientOptions(cfg));
87
129
  this.connections.set(key, conn);
130
+ this.connectionConfigs.set(key, cfg);
88
131
  this.bindEvents(conn, key, cfg);
132
+ this.ensureConnected(conn, key, cfg);
89
133
  return conn;
90
134
  }
91
135
  getConnection(key = "default", config) {
92
136
  return this.getClient(key, config);
93
137
  }
94
- async getConnectionSync(key = "default", config) {
95
- return new Promise((resolve, reject) => {
96
- const conn = this.getClient(key, config);
97
- if (!conn) {
98
- return reject(new Error("Redis connect string is missing"));
138
+ async waitUntilReady(conn) {
139
+ if (conn.isReady) {
140
+ return conn;
141
+ }
142
+ const pendingConnect = this.connecting.get(conn);
143
+ if (pendingConnect) {
144
+ await pendingConnect;
145
+ if (conn.isReady) {
146
+ return conn;
99
147
  }
100
- conn.once("connect", () => resolve(conn));
101
- conn.once("error", reject);
148
+ } else if (!conn.isOpen) {
149
+ await conn.connect();
150
+ if (conn.isReady) {
151
+ return conn;
152
+ }
153
+ }
154
+ return new Promise((resolve, reject) => {
155
+ const cleanup = /* @__PURE__ */ __name(() => {
156
+ conn.off("ready", handleReady);
157
+ conn.off("error", handleError);
158
+ }, "cleanup");
159
+ const handleReady = /* @__PURE__ */ __name(() => {
160
+ cleanup();
161
+ resolve(conn);
162
+ }, "handleReady");
163
+ const handleError = /* @__PURE__ */ __name((err) => {
164
+ cleanup();
165
+ reject(err);
166
+ }, "handleError");
167
+ conn.once("ready", handleReady);
168
+ conn.once("error", handleError);
102
169
  });
103
170
  }
104
- async close() {
105
- for (const conn of this.connections.values()) {
106
- if (!(conn == null ? void 0 : conn.status) || conn.status === "close" || conn.status === "end") {
107
- continue;
108
- }
171
+ async getConnectionSync(key = "default", config) {
172
+ const conn = this.getClient(key, config);
173
+ if (!conn) {
174
+ throw new Error("Redis connection configuration is missing");
175
+ }
176
+ return this.waitUntilReady(conn);
177
+ }
178
+ async closeConnection(key, conn) {
179
+ if (!(conn == null ? void 0 : conn.isOpen)) {
180
+ return;
181
+ }
182
+ try {
109
183
  await conn.quit();
184
+ } catch (err) {
185
+ this.logger.warn(`Failed to quit redis connection`, {
186
+ err,
187
+ method: "closeConnection",
188
+ key
189
+ });
190
+ try {
191
+ conn.destroy();
192
+ } catch (disconnectErr) {
193
+ this.logger.warn(`Failed to disconnect redis connection`, {
194
+ err: disconnectErr,
195
+ method: "closeConnection",
196
+ key
197
+ });
198
+ }
199
+ }
200
+ }
201
+ async close() {
202
+ for (const [key, conn] of this.connections.entries()) {
203
+ await this.closeConnection(key, conn);
110
204
  }
111
205
  }
112
206
  };
@@ -114,6 +208,5 @@ __name(_RedisConnectionManager, "RedisConnectionManager");
114
208
  let RedisConnectionManager = _RedisConnectionManager;
115
209
  // Annotate the CommonJS export names for ESM import in node:
116
210
  0 && (module.exports = {
117
- Redis,
118
211
  RedisConnectionManager
119
212
  });
@@ -6,5 +6,6 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
+ import { Database } from '@nocobase/database';
9
10
  import Application from './application';
10
- export declare function setupSnowflakeIdField(app: Application): void;
11
+ export declare function setupSnowflakeIdField(app: Application, db: Database): void;
@@ -31,13 +31,13 @@ __export(snowflake_id_field_exports, {
31
31
  });
32
32
  module.exports = __toCommonJS(snowflake_id_field_exports);
33
33
  var import_database = require("@nocobase/database");
34
- function setupSnowflakeIdField(app) {
34
+ function setupSnowflakeIdField(app, db) {
35
35
  const _SnowflakeIdField = class _SnowflakeIdField extends import_database.SnowflakeIdField {
36
36
  };
37
37
  __name(_SnowflakeIdField, "SnowflakeIdField");
38
38
  let SnowflakeIdField = _SnowflakeIdField;
39
39
  SnowflakeIdField.setApp(app);
40
- app.db.registerFieldTypes({
40
+ db.registerFieldTypes({
41
41
  snowflakeId: SnowflakeIdField
42
42
  });
43
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/server",
3
- "version": "2.0.0-alpha.7",
3
+ "version": "2.0.0-alpha.71",
4
4
  "main": "lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "license": "AGPL-3.0",
@@ -10,20 +10,20 @@
10
10
  "@koa/cors": "^5.0.0",
11
11
  "@koa/multer": "^3.1.0",
12
12
  "@koa/router": "^13.1.0",
13
- "@nocobase/acl": "2.0.0-alpha.7",
14
- "@nocobase/actions": "2.0.0-alpha.7",
15
- "@nocobase/auth": "2.0.0-alpha.7",
16
- "@nocobase/cache": "2.0.0-alpha.7",
17
- "@nocobase/data-source-manager": "2.0.0-alpha.7",
18
- "@nocobase/database": "2.0.0-alpha.7",
19
- "@nocobase/evaluators": "2.0.0-alpha.7",
20
- "@nocobase/lock-manager": "2.0.0-alpha.7",
21
- "@nocobase/logger": "2.0.0-alpha.7",
22
- "@nocobase/resourcer": "2.0.0-alpha.7",
23
- "@nocobase/sdk": "2.0.0-alpha.7",
24
- "@nocobase/snowflake-id": "2.0.0-alpha.7",
25
- "@nocobase/telemetry": "2.0.0-alpha.7",
26
- "@nocobase/utils": "2.0.0-alpha.7",
13
+ "@nocobase/acl": "2.0.0-alpha.71",
14
+ "@nocobase/actions": "2.0.0-alpha.71",
15
+ "@nocobase/auth": "2.0.0-alpha.71",
16
+ "@nocobase/cache": "2.0.0-alpha.71",
17
+ "@nocobase/data-source-manager": "2.0.0-alpha.71",
18
+ "@nocobase/database": "2.0.0-alpha.71",
19
+ "@nocobase/evaluators": "2.0.0-alpha.71",
20
+ "@nocobase/lock-manager": "2.0.0-alpha.71",
21
+ "@nocobase/logger": "2.0.0-alpha.71",
22
+ "@nocobase/resourcer": "2.0.0-alpha.71",
23
+ "@nocobase/sdk": "2.0.0-alpha.71",
24
+ "@nocobase/snowflake-id": "2.0.0-alpha.71",
25
+ "@nocobase/telemetry": "2.0.0-alpha.71",
26
+ "@nocobase/utils": "2.0.0-alpha.71",
27
27
  "@types/decompress": "4.2.7",
28
28
  "@types/ini": "^1.3.31",
29
29
  "@types/koa-send": "^4.1.3",
@@ -41,7 +41,6 @@
41
41
  "fs-extra": "^11.1.1",
42
42
  "i18next": "^22.4.9",
43
43
  "ini": "^4.1.1",
44
- "ioredis": "^5.7.0",
45
44
  "koa": "^2.15.4",
46
45
  "koa-bodyparser": "^4.3.0",
47
46
  "koa-send": "^5.0.1",
@@ -49,6 +48,8 @@
49
48
  "lodash": "^4.17.21",
50
49
  "multer": "^1.4.5-lts.2",
51
50
  "nanoid": "^3.3.11",
51
+ "p-queue": "^6.6.2",
52
+ "redis": "^5.10.0",
52
53
  "semver": "^7.7.1",
53
54
  "serve-handler": "^6.1.6",
54
55
  "ws": "^8.13.0",
@@ -59,5 +60,5 @@
59
60
  "@types/serve-handler": "^6.1.1",
60
61
  "@types/ws": "^8.5.5"
61
62
  },
62
- "gitHead": "cb012f93256f534472d3ae56e075839ca1675779"
63
+ "gitHead": "b6fc484eb698fa12fba02dd468a04e39079b1e79"
63
64
  }
@@ -1,69 +0,0 @@
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
- /// <reference types="node" />
10
- import { AsyncEmitter } from '@nocobase/utils';
11
- import { EventEmitter } from 'events';
12
- import Application, { ApplicationOptions } from './application';
13
- type BootOptions = {
14
- appName: string;
15
- options: any;
16
- appSupervisor: AppSupervisor;
17
- };
18
- type AppBootstrapper = (bootOptions: BootOptions) => Promise<void>;
19
- type AppStatus = 'initializing' | 'initialized' | 'running' | 'commanding' | 'stopped' | 'error' | 'not_found';
20
- export declare class AppSupervisor extends EventEmitter implements AsyncEmitter {
21
- private static instance;
22
- runningMode: 'single' | 'multiple';
23
- singleAppName: string | null;
24
- emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
25
- apps: {
26
- [appName: string]: Application;
27
- };
28
- lastSeenAt: Map<string, number>;
29
- appErrors: {
30
- [appName: string]: Error;
31
- };
32
- appStatus: {
33
- [appName: string]: AppStatus;
34
- };
35
- lastMaintainingMessage: {
36
- [appName: string]: string;
37
- };
38
- statusBeforeCommanding: {
39
- [appName: string]: AppStatus;
40
- };
41
- private appMutexes;
42
- private appBootstrapper;
43
- private constructor();
44
- static getInstance(): AppSupervisor;
45
- setAppError(appName: string, error: Error): void;
46
- hasAppError(appName: string): boolean;
47
- clearAppError(appName: string): void;
48
- reset(): Promise<void>;
49
- destroy(): Promise<void>;
50
- setAppStatus(appName: string, status: AppStatus, options?: {}): void;
51
- getMutexOfApp(appName: string): any;
52
- bootStrapApp(appName: string, options?: {}): Promise<void>;
53
- getApp(appName: string, options?: {
54
- withOutBootStrap?: boolean;
55
- [key: string]: any;
56
- }): Promise<Application<import("./application").DefaultState, import("./application").DefaultContext>>;
57
- setAppBootstrapper(appBootstrapper: AppBootstrapper): void;
58
- getAppStatus(appName: string, defaultStatus?: AppStatus): AppStatus | null;
59
- bootMainApp(options: ApplicationOptions): Application<import("./application").DefaultState, import("./application").DefaultContext>;
60
- hasApp(appName: string): boolean;
61
- touchApp(appName: string): void;
62
- addApp(app: Application): Application<import("./application").DefaultState, import("./application").DefaultContext>;
63
- getAppsNames(): Promise<string[]>;
64
- removeApp(appName: string): Promise<void>;
65
- subApps(): Application<import("./application").DefaultState, import("./application").DefaultContext>[];
66
- on(eventName: string | symbol, listener: (...args: any[]) => void): this;
67
- private bindAppEvents;
68
- }
69
- export {};
@@ -1,299 +0,0 @@
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 __create = Object.create;
11
- var __defProp = Object.defineProperty;
12
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
- var __getOwnPropNames = Object.getOwnPropertyNames;
14
- var __getProtoOf = Object.getPrototypeOf;
15
- var __hasOwnProp = Object.prototype.hasOwnProperty;
16
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
17
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
18
- var __export = (target, all) => {
19
- for (var name in all)
20
- __defProp(target, name, { get: all[name], enumerable: true });
21
- };
22
- var __copyProps = (to, from, except, desc) => {
23
- if (from && typeof from === "object" || typeof from === "function") {
24
- for (let key of __getOwnPropNames(from))
25
- if (!__hasOwnProp.call(to, key) && key !== except)
26
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
27
- }
28
- return to;
29
- };
30
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
31
- // If the importer is in node compatibility mode or this is not an ESM
32
- // file that has been converted to a CommonJS file using a Babel-
33
- // compatible transform (i.e. "__esModule" has not been set), then set
34
- // "default" to the CommonJS "module.exports" for node compatibility.
35
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
36
- mod
37
- ));
38
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
39
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
40
- var app_supervisor_exports = {};
41
- __export(app_supervisor_exports, {
42
- AppSupervisor: () => AppSupervisor
43
- });
44
- module.exports = __toCommonJS(app_supervisor_exports);
45
- var import_utils = require("@nocobase/utils");
46
- var import_async_mutex = require("async-mutex");
47
- var import_events = require("events");
48
- var import_application = __toESM(require("./application"));
49
- var import_handler = require("./errors/handler");
50
- const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
51
- runningMode = "multiple";
52
- singleAppName = null;
53
- apps = {};
54
- lastSeenAt = /* @__PURE__ */ new Map();
55
- appErrors = {};
56
- appStatus = {};
57
- lastMaintainingMessage = {};
58
- statusBeforeCommanding = {};
59
- appMutexes = {};
60
- appBootstrapper = null;
61
- constructor() {
62
- super();
63
- if (process.env.STARTUP_SUBAPP) {
64
- this.runningMode = "single";
65
- this.singleAppName = process.env.STARTUP_SUBAPP;
66
- }
67
- }
68
- static getInstance() {
69
- if (!_AppSupervisor.instance) {
70
- _AppSupervisor.instance = new _AppSupervisor();
71
- }
72
- return _AppSupervisor.instance;
73
- }
74
- setAppError(appName, error) {
75
- this.appErrors[appName] = error;
76
- this.emit("appError", {
77
- appName,
78
- error
79
- });
80
- }
81
- hasAppError(appName) {
82
- return !!this.appErrors[appName];
83
- }
84
- clearAppError(appName) {
85
- delete this.appErrors[appName];
86
- }
87
- async reset() {
88
- const appNames = Object.keys(this.apps);
89
- for (const appName of appNames) {
90
- await this.removeApp(appName);
91
- }
92
- this.appBootstrapper = null;
93
- this.removeAllListeners();
94
- }
95
- async destroy() {
96
- await this.reset();
97
- _AppSupervisor.instance = null;
98
- }
99
- setAppStatus(appName, status, options = {}) {
100
- if (this.appStatus[appName] === status) {
101
- return;
102
- }
103
- this.appStatus[appName] = status;
104
- this.emit("appStatusChanged", {
105
- appName,
106
- status,
107
- options
108
- });
109
- }
110
- getMutexOfApp(appName) {
111
- if (!this.appMutexes[appName]) {
112
- this.appMutexes[appName] = new import_async_mutex.Mutex();
113
- }
114
- return this.appMutexes[appName];
115
- }
116
- async bootStrapApp(appName, options = {}) {
117
- await this.getMutexOfApp(appName).runExclusive(async () => {
118
- if (!this.hasApp(appName)) {
119
- this.setAppStatus(appName, "initializing");
120
- if (this.appBootstrapper) {
121
- await this.appBootstrapper({
122
- appSupervisor: this,
123
- appName,
124
- options
125
- });
126
- }
127
- if (!this.hasApp(appName)) {
128
- this.setAppStatus(appName, "not_found");
129
- } else if (!this.getAppStatus(appName) || this.getAppStatus(appName) == "initializing") {
130
- this.setAppStatus(appName, "initialized");
131
- }
132
- }
133
- });
134
- }
135
- async getApp(appName, options = {}) {
136
- if (!options.withOutBootStrap) {
137
- await this.bootStrapApp(appName, options);
138
- }
139
- return this.apps[appName];
140
- }
141
- setAppBootstrapper(appBootstrapper) {
142
- this.appBootstrapper = appBootstrapper;
143
- }
144
- getAppStatus(appName, defaultStatus) {
145
- const status = this.appStatus[appName];
146
- if (status === void 0 && defaultStatus !== void 0) {
147
- return defaultStatus;
148
- }
149
- return status;
150
- }
151
- bootMainApp(options) {
152
- return new import_application.default(options);
153
- }
154
- hasApp(appName) {
155
- return !!this.apps[appName];
156
- }
157
- touchApp(appName) {
158
- if (!this.hasApp(appName)) {
159
- return;
160
- }
161
- this.lastSeenAt.set(appName, Math.floor(Date.now() / 1e3));
162
- }
163
- // add app into supervisor
164
- addApp(app) {
165
- if (this.apps[app.name]) {
166
- throw new Error(`app ${app.name} already exists`);
167
- }
168
- app.logger.info(`add app ${app.name} into supervisor`, { submodule: "supervisor", method: "addApp" });
169
- this.bindAppEvents(app);
170
- this.apps[app.name] = app;
171
- this.emit("afterAppAdded", app);
172
- if (!this.getAppStatus(app.name) || this.getAppStatus(app.name) == "not_found") {
173
- this.setAppStatus(app.name, "initialized");
174
- }
175
- return app;
176
- }
177
- // get registered app names
178
- async getAppsNames() {
179
- const apps = Object.values(this.apps);
180
- return apps.map((app) => app.name);
181
- }
182
- async removeApp(appName) {
183
- if (!this.apps[appName]) {
184
- console.log(`app ${appName} not exists`);
185
- return;
186
- }
187
- await this.apps[appName].runCommand("destroy");
188
- }
189
- subApps() {
190
- return Object.values(this.apps).filter((app) => app.name !== "main");
191
- }
192
- on(eventName, listener) {
193
- const listeners = this.listeners(eventName);
194
- const listenerName = listener.name;
195
- if (listenerName !== "") {
196
- const exists = listeners.find((l) => l.name === listenerName);
197
- if (exists) {
198
- super.removeListener(eventName, exists);
199
- }
200
- }
201
- return super.on(eventName, listener);
202
- }
203
- bindAppEvents(app) {
204
- app.on("afterDestroy", () => {
205
- delete this.apps[app.name];
206
- delete this.appStatus[app.name];
207
- delete this.appErrors[app.name];
208
- delete this.lastMaintainingMessage[app.name];
209
- delete this.statusBeforeCommanding[app.name];
210
- this.lastSeenAt.delete(app.name);
211
- });
212
- app.on("maintainingMessageChanged", ({ message, maintainingStatus }) => {
213
- if (this.lastMaintainingMessage[app.name] === message) {
214
- return;
215
- }
216
- this.lastMaintainingMessage[app.name] = message;
217
- const appStatus = this.getAppStatus(app.name);
218
- if (!maintainingStatus && appStatus !== "running") {
219
- return;
220
- }
221
- this.emit("appMaintainingMessageChanged", {
222
- appName: app.name,
223
- message,
224
- status: appStatus,
225
- command: appStatus == "running" ? null : maintainingStatus.command
226
- });
227
- });
228
- app.on("__started", async (_app, options) => {
229
- const { maintainingStatus, options: startOptions } = options;
230
- if (maintainingStatus && [
231
- "install",
232
- "upgrade",
233
- "refresh",
234
- "restore",
235
- "pm.add",
236
- "pm.update",
237
- "pm.enable",
238
- "pm.disable",
239
- "pm.remove"
240
- ].includes(maintainingStatus.command.name) && !startOptions.recover) {
241
- this.setAppStatus(app.name, "running", {
242
- refresh: true
243
- });
244
- } else {
245
- this.setAppStatus(app.name, "running");
246
- }
247
- });
248
- app.on("__stopped", async () => {
249
- this.setAppStatus(app.name, "stopped");
250
- });
251
- app.on("maintaining", (maintainingStatus) => {
252
- const { status, command } = maintainingStatus;
253
- switch (status) {
254
- case "command_begin":
255
- {
256
- this.statusBeforeCommanding[app.name] = this.getAppStatus(app.name);
257
- this.setAppStatus(app.name, "commanding");
258
- }
259
- break;
260
- case "command_running":
261
- break;
262
- case "command_end":
263
- {
264
- const appStatus = this.getAppStatus(app.name);
265
- this.emit("appMaintainingStatusChanged", maintainingStatus);
266
- if (appStatus == "commanding") {
267
- this.setAppStatus(app.name, this.statusBeforeCommanding[app.name]);
268
- }
269
- }
270
- break;
271
- case "command_error":
272
- {
273
- const errorLevel = (0, import_handler.getErrorLevel)(maintainingStatus.error);
274
- if (errorLevel === "fatal") {
275
- this.setAppError(app.name, maintainingStatus.error);
276
- this.setAppStatus(app.name, "error");
277
- break;
278
- }
279
- if (errorLevel === "warn") {
280
- this.emit("appError", {
281
- appName: app.name,
282
- error: maintainingStatus.error
283
- });
284
- }
285
- this.setAppStatus(app.name, this.statusBeforeCommanding[app.name]);
286
- }
287
- break;
288
- }
289
- });
290
- }
291
- };
292
- __name(_AppSupervisor, "AppSupervisor");
293
- __publicField(_AppSupervisor, "instance");
294
- let AppSupervisor = _AppSupervisor;
295
- (0, import_utils.applyMixins)(AppSupervisor, [import_utils.AsyncEmitter]);
296
- // Annotate the CommonJS export names for ESM import in node:
297
- 0 && (module.exports = {
298
- AppSupervisor
299
- });