@nocobase/server 0.12.0-alpha.5 → 0.13.0-alpha.2

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 (52) hide show
  1. package/lib/app-supervisor.d.ts +59 -0
  2. package/lib/app-supervisor.js +268 -0
  3. package/lib/application.d.ts +65 -52
  4. package/lib/application.js +369 -269
  5. package/lib/commands/db-sync.js +0 -3
  6. package/lib/commands/destroy.d.ts +3 -0
  7. package/lib/commands/destroy.js +16 -0
  8. package/lib/commands/index.js +3 -0
  9. package/lib/commands/install.js +1 -37
  10. package/lib/commands/pm.js +53 -13
  11. package/lib/commands/restart.d.ts +3 -0
  12. package/lib/commands/restart.js +16 -0
  13. package/lib/commands/start.js +10 -10
  14. package/lib/commands/stop.d.ts +3 -0
  15. package/lib/commands/stop.js +16 -0
  16. package/lib/commands/upgrade.js +0 -3
  17. package/lib/errors/application-not-install.d.ts +4 -0
  18. package/lib/errors/application-not-install.js +14 -0
  19. package/lib/gateway/errors.d.ts +22 -0
  20. package/lib/gateway/errors.js +146 -0
  21. package/lib/gateway/handle-plugin-static-file.d.ts +3 -0
  22. package/lib/gateway/handle-plugin-static-file.js +91 -0
  23. package/lib/gateway/index.d.ts +59 -0
  24. package/lib/gateway/index.js +327 -0
  25. package/lib/gateway/ipc-socket-client.d.ts +9 -0
  26. package/lib/gateway/ipc-socket-client.js +48 -0
  27. package/lib/gateway/ipc-socket-server.d.ts +12 -0
  28. package/lib/gateway/ipc-socket-server.js +86 -0
  29. package/lib/gateway/ws-server.d.ts +26 -0
  30. package/lib/gateway/ws-server.js +198 -0
  31. package/lib/helper.d.ts +3 -0
  32. package/lib/helper.js +32 -1
  33. package/lib/helpers/application-version.d.ts +10 -0
  34. package/lib/helpers/application-version.js +78 -0
  35. package/lib/index.d.ts +2 -1
  36. package/lib/index.js +24 -8
  37. package/lib/locale/locale.d.ts +1 -1
  38. package/lib/locale/locale.js +26 -17
  39. package/lib/locale/resource.js +8 -0
  40. package/lib/plugin-manager/clientStaticMiddleware.d.ts +0 -8
  41. package/lib/plugin-manager/clientStaticMiddleware.js +2 -95
  42. package/lib/plugin-manager/options/resource.js +12 -3
  43. package/lib/plugin-manager/plugin-manager-repository.d.ts +2 -1
  44. package/lib/plugin-manager/plugin-manager-repository.js +53 -18
  45. package/lib/plugin-manager/plugin-manager.d.ts +21 -18
  46. package/lib/plugin-manager/plugin-manager.js +394 -332
  47. package/lib/plugin.d.ts +10 -2
  48. package/lib/plugin.js +21 -3
  49. package/lib/swagger/index.json +1565 -0
  50. package/package.json +18 -13
  51. package/lib/app-manager.d.ts +0 -21
  52. package/lib/app-manager.js +0 -138
@@ -0,0 +1,59 @@
1
+ /// <reference types="node" />
2
+ import { AsyncEmitter } from '@nocobase/utils';
3
+ import { EventEmitter } from 'events';
4
+ import Application, { ApplicationOptions } from './application';
5
+ type BootOptions = {
6
+ appName: string;
7
+ options: any;
8
+ appSupervisor: AppSupervisor;
9
+ };
10
+ type AppBootstrapper = (bootOptions: BootOptions) => Promise<void>;
11
+ type AppStatus = 'initializing' | 'initialized' | 'running' | 'commanding' | 'stopped' | 'error' | 'not_found';
12
+ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter {
13
+ private static instance;
14
+ runningMode: 'single' | 'multiple';
15
+ singleAppName: string | null;
16
+ emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
17
+ apps: {
18
+ [appName: string]: Application;
19
+ };
20
+ appErrors: {
21
+ [appName: string]: Error;
22
+ };
23
+ appStatus: {
24
+ [appName: string]: AppStatus;
25
+ };
26
+ lastMaintainingMessage: {
27
+ [appName: string]: string;
28
+ };
29
+ statusBeforeCommanding: {
30
+ [appName: string]: AppStatus;
31
+ };
32
+ private appMutexes;
33
+ private appBootstrapper;
34
+ private constructor();
35
+ static getInstance(): AppSupervisor;
36
+ setAppError(appName: string, error: Error): void;
37
+ hasAppError(appName: string): boolean;
38
+ clearAppError(appName: string): void;
39
+ reset(): Promise<void>;
40
+ destroy(): Promise<void>;
41
+ setAppStatus(appName: string, status: AppStatus): void;
42
+ getMutexOfApp(appName: string): any;
43
+ bootStrapApp(appName: string, options?: {}): Promise<void>;
44
+ getApp(appName: string, options?: {
45
+ withOutBootStrap?: boolean;
46
+ [key: string]: any;
47
+ }): Promise<Application<import("./application").DefaultState, import("./application").DefaultContext>>;
48
+ setAppBootstrapper(appBootstrapper: AppBootstrapper): void;
49
+ getAppStatus(appName: string, defaultStatus?: AppStatus): AppStatus | null;
50
+ bootMainApp(options: ApplicationOptions): Application<import("./application").DefaultState, import("./application").DefaultContext>;
51
+ hasApp(appName: string): boolean;
52
+ addApp(app: Application): Application<import("./application").DefaultState, import("./application").DefaultContext>;
53
+ getAppsNames(): Promise<string[]>;
54
+ removeApp(appName: string): Promise<void>;
55
+ subApps(): Application<import("./application").DefaultState, import("./application").DefaultContext>[];
56
+ on(eventName: string | symbol, listener: (...args: any[]) => void): this;
57
+ private bindAppEvents;
58
+ }
59
+ export {};
@@ -0,0 +1,268 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.AppSupervisor = void 0;
7
+ function _utils() {
8
+ const data = require("@nocobase/utils");
9
+ _utils = function _utils() {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _asyncMutex() {
15
+ const data = require("async-mutex");
16
+ _asyncMutex = function _asyncMutex() {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ function _events() {
22
+ const data = require("events");
23
+ _events = function _events() {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
28
+ var _application = _interopRequireDefault(require("./application"));
29
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
30
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
31
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
32
+ class AppSupervisor extends _events().EventEmitter {
33
+ constructor() {
34
+ super();
35
+ this.runningMode = 'multiple';
36
+ this.singleAppName = null;
37
+ this.apps = {};
38
+ this.appErrors = {};
39
+ this.appStatus = {};
40
+ this.lastMaintainingMessage = {};
41
+ this.statusBeforeCommanding = {};
42
+ this.appMutexes = {};
43
+ this.appBootstrapper = null;
44
+ if (process.env.STARTUP_SUBAPP) {
45
+ this.runningMode = 'single';
46
+ this.singleAppName = process.env.STARTUP_SUBAPP;
47
+ }
48
+ }
49
+ static getInstance() {
50
+ if (!AppSupervisor.instance) {
51
+ AppSupervisor.instance = new AppSupervisor();
52
+ }
53
+ return AppSupervisor.instance;
54
+ }
55
+ setAppError(appName, error) {
56
+ this.appErrors[appName] = error;
57
+ this.emit('appError', {
58
+ appName: appName,
59
+ error
60
+ });
61
+ }
62
+ hasAppError(appName) {
63
+ return !!this.appErrors[appName];
64
+ }
65
+ clearAppError(appName) {
66
+ delete this.appErrors[appName];
67
+ }
68
+ reset() {
69
+ var _this = this;
70
+ return _asyncToGenerator(function* () {
71
+ const appNames = Object.keys(_this.apps);
72
+ for (var _i = 0, _appNames = appNames; _i < _appNames.length; _i++) {
73
+ const appName = _appNames[_i];
74
+ yield _this.removeApp(appName);
75
+ }
76
+ _this.appBootstrapper = null;
77
+ _this.removeAllListeners();
78
+ })();
79
+ }
80
+ destroy() {
81
+ var _this2 = this;
82
+ return _asyncToGenerator(function* () {
83
+ yield _this2.reset();
84
+ AppSupervisor.instance = null;
85
+ })();
86
+ }
87
+ setAppStatus(appName, status) {
88
+ if (this.appStatus[appName] === status) {
89
+ return;
90
+ }
91
+ this.appStatus[appName] = status;
92
+ this.emit('appStatusChanged', {
93
+ appName,
94
+ status
95
+ });
96
+ }
97
+ getMutexOfApp(appName) {
98
+ if (!this.appMutexes[appName]) {
99
+ this.appMutexes[appName] = new (_asyncMutex().Mutex)();
100
+ }
101
+ return this.appMutexes[appName];
102
+ }
103
+ bootStrapApp(appName, options = {}) {
104
+ var _this3 = this;
105
+ return _asyncToGenerator(function* () {
106
+ yield _this3.getMutexOfApp(appName).runExclusive( /*#__PURE__*/_asyncToGenerator(function* () {
107
+ if (!_this3.hasApp(appName)) {
108
+ _this3.setAppStatus(appName, 'initializing');
109
+ if (_this3.appBootstrapper) {
110
+ yield _this3.appBootstrapper({
111
+ appSupervisor: _this3,
112
+ appName,
113
+ options
114
+ });
115
+ }
116
+ if (!_this3.hasApp(appName)) {
117
+ _this3.setAppStatus(appName, 'not_found');
118
+ } else if (!_this3.getAppStatus(appName) || _this3.getAppStatus(appName) == 'initializing') {
119
+ _this3.setAppStatus(appName, 'initialized');
120
+ }
121
+ }
122
+ }));
123
+ })();
124
+ }
125
+ getApp(appName, options = {}) {
126
+ var _this4 = this;
127
+ return _asyncToGenerator(function* () {
128
+ if (!options.withOutBootStrap) {
129
+ yield _this4.bootStrapApp(appName, options);
130
+ }
131
+ return _this4.apps[appName];
132
+ })();
133
+ }
134
+ setAppBootstrapper(appBootstrapper) {
135
+ this.appBootstrapper = appBootstrapper;
136
+ }
137
+ getAppStatus(appName, defaultStatus) {
138
+ const status = this.appStatus[appName];
139
+ if (status === undefined && defaultStatus !== undefined) {
140
+ return defaultStatus;
141
+ }
142
+ return status;
143
+ }
144
+ bootMainApp(options) {
145
+ return new _application.default(options);
146
+ }
147
+ hasApp(appName) {
148
+ return !!this.apps[appName];
149
+ }
150
+ // add app into supervisor
151
+ addApp(app) {
152
+ // if there is already an app with the same name, throw error
153
+ if (this.apps[app.name]) {
154
+ throw new Error(`app ${app.name} already exists`);
155
+ }
156
+ console.log(`add app ${app.name} into supervisor`);
157
+ this.bindAppEvents(app);
158
+ this.apps[app.name] = app;
159
+ this.emit('afterAppAdded', app);
160
+ if (!this.getAppStatus(app.name) || this.getAppStatus(app.name) == 'not_found') {
161
+ this.setAppStatus(app.name, 'initialized');
162
+ }
163
+ return app;
164
+ }
165
+ // get registered app names
166
+ getAppsNames() {
167
+ var _this5 = this;
168
+ return _asyncToGenerator(function* () {
169
+ const apps = Object.values(_this5.apps);
170
+ return apps.map(app => app.name);
171
+ })();
172
+ }
173
+ removeApp(appName) {
174
+ var _this6 = this;
175
+ return _asyncToGenerator(function* () {
176
+ if (!_this6.apps[appName]) {
177
+ console.log(`app ${appName} not exists`);
178
+ return;
179
+ }
180
+ // call app.destroy
181
+ yield _this6.apps[appName].runCommand('destroy');
182
+ })();
183
+ }
184
+ subApps() {
185
+ return Object.values(this.apps).filter(app => app.name !== 'main');
186
+ }
187
+ on(eventName, listener) {
188
+ const listeners = this.listeners(eventName);
189
+ const listenerName = listener.name;
190
+ if (listenerName !== '') {
191
+ const exists = listeners.find(l => l.name === listenerName);
192
+ if (exists) {
193
+ super.removeListener(eventName, exists);
194
+ }
195
+ }
196
+ return super.on(eventName, listener);
197
+ }
198
+ bindAppEvents(app) {
199
+ var _this7 = this;
200
+ app.on('afterDestroy', () => {
201
+ delete this.apps[app.name];
202
+ delete this.appStatus[app.name];
203
+ delete this.appErrors[app.name];
204
+ delete this.lastMaintainingMessage[app.name];
205
+ delete this.statusBeforeCommanding[app.name];
206
+ });
207
+ app.on('maintainingMessageChanged', ({
208
+ message,
209
+ maintainingStatus
210
+ }) => {
211
+ if (this.lastMaintainingMessage[app.name] === message) {
212
+ return;
213
+ }
214
+ this.lastMaintainingMessage[app.name] = message;
215
+ const appStatus = this.getAppStatus(app.name);
216
+ if (!maintainingStatus && appStatus !== 'running') {
217
+ return;
218
+ }
219
+ this.emit('appMaintainingMessageChanged', {
220
+ appName: app.name,
221
+ message,
222
+ status: appStatus,
223
+ command: appStatus == 'running' ? null : maintainingStatus.command
224
+ });
225
+ });
226
+ app.on('__started', /*#__PURE__*/_asyncToGenerator(function* () {
227
+ _this7.setAppStatus(app.name, 'running');
228
+ }));
229
+ app.on('afterStop', /*#__PURE__*/_asyncToGenerator(function* () {
230
+ _this7.setAppStatus(app.name, 'stopped');
231
+ }));
232
+ app.on('maintaining', maintainingStatus => {
233
+ const status = maintainingStatus.status;
234
+ switch (status) {
235
+ case 'command_begin':
236
+ {
237
+ this.statusBeforeCommanding[app.name] = this.getAppStatus(app.name);
238
+ this.setAppStatus(app.name, 'commanding');
239
+ }
240
+ break;
241
+ case 'command_running':
242
+ // emit status changed
243
+ // this.emit('appMaintainingStatusChanged', maintainingStatus);
244
+ break;
245
+ case 'command_end':
246
+ {
247
+ const appStatus = this.getAppStatus(app.name);
248
+ // emit status changed
249
+ this.emit('appMaintainingStatusChanged', maintainingStatus);
250
+ // not change
251
+ if (appStatus == 'commanding') {
252
+ this.setAppStatus(app.name, this.statusBeforeCommanding[app.name]);
253
+ }
254
+ }
255
+ break;
256
+ case 'command_error':
257
+ {
258
+ this.setAppError(app.name, maintainingStatus.error);
259
+ this.setAppStatus(app.name, 'error');
260
+ }
261
+ break;
262
+ }
263
+ });
264
+ }
265
+ }
266
+ exports.AppSupervisor = AppSupervisor;
267
+ AppSupervisor.instance = void 0;
268
+ (0, _utils().applyMixins)(AppSupervisor, [_utils().AsyncEmitter]);
@@ -3,19 +3,21 @@
3
3
  import { ACL } from '@nocobase/acl';
4
4
  import { AuthManager } from '@nocobase/auth';
5
5
  import { Cache, ICacheConfig } from '@nocobase/cache';
6
- import Database, { Collection, CollectionOptions, IDatabaseOptions } from '@nocobase/database';
6
+ import Database, { CollectionOptions, IDatabaseOptions } from '@nocobase/database';
7
7
  import { AppLoggerOptions, Logger } from '@nocobase/logger';
8
8
  import Resourcer, { ResourceOptions } from '@nocobase/resourcer';
9
9
  import { AsyncEmitter, ToposortOptions } from '@nocobase/utils';
10
10
  import { Command, CommandOptions, ParseOptions } from 'commander';
11
- import { Server } from 'http';
11
+ import { IncomingMessage, Server, ServerResponse } from 'http';
12
12
  import { i18n, InitOptions } from 'i18next';
13
13
  import Koa, { DefaultContext as KoaDefaultContext, DefaultState as KoaDefaultState } from 'koa';
14
- import { AppManager } from './app-manager';
14
+ import { AppSupervisor } from './app-supervisor';
15
+ import { ApplicationVersion } from './helpers/application-version';
15
16
  import { Locale } from './locale';
16
17
  import { Plugin } from './plugin';
17
18
  import { InstallOptions, PluginManager } from './plugin-manager';
18
- export type PluginConfiguration = string | [string, any];
19
+ export type PluginType = string | typeof Plugin;
20
+ export type PluginConfiguration = PluginType | [PluginType, any];
19
21
  export interface ResourcerOptions {
20
22
  prefix?: string;
21
23
  }
@@ -49,84 +51,92 @@ interface ActionsOptions {
49
51
  resourceName?: string;
50
52
  resourceNames?: string[];
51
53
  }
52
- interface ListenOptions {
53
- port?: number | undefined;
54
- host?: string | undefined;
55
- backlog?: number | undefined;
56
- path?: string | undefined;
57
- exclusive?: boolean | undefined;
58
- readableAll?: boolean | undefined;
59
- writableAll?: boolean | undefined;
60
- /**
61
- * @default false
62
- */
63
- ipv6Only?: boolean | undefined;
64
- signal?: AbortSignal | undefined;
65
- }
66
54
  interface StartOptions {
67
55
  cliArgs?: any[];
68
56
  dbSync?: boolean;
69
- listen?: ListenOptions;
70
- }
71
- export declare class ApplicationVersion {
72
- protected app: Application;
73
- protected collection: Collection;
74
- constructor(app: Application);
75
- get(): Promise<any>;
76
- update(): Promise<void>;
77
- satisfies(range: string): Promise<boolean>;
57
+ checkInstall?: boolean;
78
58
  }
59
+ type MaintainingStatus = 'command_begin' | 'command_end' | 'command_running' | 'command_error';
60
+ export type MaintainingCommandStatus = {
61
+ command: {
62
+ name: string;
63
+ };
64
+ status: MaintainingStatus;
65
+ error?: Error;
66
+ };
79
67
  export declare class Application<StateT = DefaultState, ContextT = DefaultContext> extends Koa implements AsyncEmitter {
80
68
  options: ApplicationOptions;
69
+ listenServer: Server;
70
+ middleware: any;
71
+ stopped: boolean;
72
+ ready: boolean;
73
+ emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
74
+ rawOptions: ApplicationOptions;
75
+ activatedCommand: {
76
+ name: string;
77
+ };
78
+ running: boolean;
79
+ protected plugins: Map<string, Plugin<any>>;
80
+ protected _appSupervisor: AppSupervisor;
81
+ protected _started: boolean;
82
+ private _authenticated;
83
+ private _maintaining;
84
+ private _maintainingCommandStatus;
85
+ private _maintainingStatusBeforeCommand;
86
+ constructor(options: ApplicationOptions);
87
+ protected _loaded: boolean;
88
+ get loaded(): boolean;
89
+ private _maintainingMessage;
90
+ get maintainingMessage(): string;
81
91
  protected _db: Database;
92
+ get db(): Database;
82
93
  protected _logger: Logger;
94
+ get logger(): Logger;
83
95
  protected _resourcer: Resourcer;
96
+ get resourcer(): Resourcer;
84
97
  protected _cache: Cache;
98
+ get cache(): Cache;
85
99
  protected _cli: Command;
100
+ get cli(): Command;
86
101
  protected _i18n: i18n;
102
+ get i18n(): i18n;
87
103
  protected _pm: PluginManager;
104
+ get pm(): PluginManager;
88
105
  protected _acl: ACL;
89
- protected _appManager: AppManager;
106
+ get acl(): ACL;
90
107
  protected _authManager: AuthManager;
108
+ get authManager(): AuthManager;
91
109
  protected _locales: Locale;
110
+ get locales(): Locale;
92
111
  protected _version: ApplicationVersion;
93
- protected plugins: Map<string, Plugin<any>>;
94
- listenServer: Server;
95
- middleware: any;
96
- stopped: boolean;
97
- constructor(options: ApplicationOptions);
98
- get db(): Database;
99
- get cache(): Cache;
100
- get resourcer(): Resourcer;
101
- get cli(): Command;
102
- get acl(): ACL;
103
- get i18n(): i18n;
104
- get pm(): PluginManager;
105
112
  get version(): ApplicationVersion;
106
- get appManager(): AppManager;
107
- get authManager(): AuthManager;
108
- get logger(): Logger;
109
113
  get log(): Logger;
110
- get locales(): Locale;
111
114
  get name(): string;
112
- protected init(): void;
113
- private createDatabase;
115
+ isMaintaining(): boolean;
116
+ getMaintaining(): MaintainingCommandStatus;
117
+ setMaintaining(_maintainingCommandStatus: MaintainingCommandStatus): void;
118
+ setMaintainingMessage(message: string): void;
114
119
  getVersion(): any;
115
- plugin<O = any>(pluginClass: any, options?: O): Plugin;
120
+ plugin<O = any>(pluginClass: any, options?: O): void;
116
121
  use<NewStateT = {}, NewContextT = {}>(middleware: Koa.Middleware<StateT & NewStateT, ContextT & NewContextT>, options?: ToposortOptions): this;
117
- callback(): (req: any, res: any) => any;
118
- collection(options: CollectionOptions): Collection<any, any>;
122
+ callback(): (req: IncomingMessage, res: ServerResponse) => any;
123
+ collection(options: CollectionOptions): import("@nocobase/database").Collection<any, any>;
119
124
  resource(options: ResourceOptions): import("@nocobase/resourcer").Resource;
120
125
  actions(handlers: any, options?: ActionsOptions): void;
121
126
  command(name: string, desc?: string, opts?: CommandOptions): Command;
122
127
  findCommand(name: string): Command;
123
128
  load(options?: any): Promise<void>;
124
129
  reload(options?: any): Promise<void>;
125
- getPlugin<P extends Plugin>(name: string): P;
130
+ getPlugin<P extends Plugin>(name: string | typeof Plugin): P;
126
131
  parse(argv?: string[]): Promise<Command>;
132
+ authenticate(): Promise<void>;
133
+ runCommand(command: string, ...args: any[]): Promise<Command>;
134
+ createCli(): Command;
127
135
  runAsCLI(argv?: string[], options?: ParseOptions): Promise<Command>;
128
136
  start(options?: StartOptions): Promise<void>;
129
- listen(...args: any[]): Server;
137
+ isStarted(): Promise<boolean>;
138
+ tryReloadOrRestart(): Promise<void>;
139
+ restart(options?: StartOptions): Promise<void>;
130
140
  stop(options?: any): Promise<void>;
131
141
  destroy(options?: any): Promise<void>;
132
142
  dbVersionCheck(options?: {
@@ -135,9 +145,12 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
135
145
  isInstalled(): Promise<boolean>;
136
146
  install(options?: InstallOptions): Promise<void>;
137
147
  upgrade(options?: any): Promise<void>;
138
- emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
139
148
  toJSON(): {
140
149
  appName: string;
150
+ name: string;
141
151
  };
152
+ reInitEvents(): void;
153
+ protected init(): void;
154
+ private createDatabase;
142
155
  }
143
156
  export default Application;