@nocobase/server 2.0.0-alpha.6 → 2.0.0-alpha.61

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 (40) hide show
  1. package/lib/acl/available-action.js +1 -1
  2. package/lib/aes-encryptor.js +4 -0
  3. package/lib/app-command.d.ts +1 -0
  4. package/lib/app-command.js +3 -0
  5. package/lib/app-supervisor.d.ts +7 -2
  6. package/lib/app-supervisor.js +54 -15
  7. package/lib/application.d.ts +9 -6
  8. package/lib/application.js +24 -12
  9. package/lib/commands/index.js +2 -0
  10. package/lib/commands/pm.js +11 -0
  11. package/lib/commands/repair.d.ts +11 -0
  12. package/lib/commands/repair.js +43 -0
  13. package/lib/commands/start.js +1 -1
  14. package/lib/event-queue.d.ts +7 -1
  15. package/lib/event-queue.js +23 -21
  16. package/lib/gateway/errors.js +50 -12
  17. package/lib/gateway/index.d.ts +8 -0
  18. package/lib/gateway/index.js +26 -2
  19. package/lib/gateway/ws-server.js +3 -0
  20. package/lib/helper.d.ts +359 -0
  21. package/lib/helper.js +58 -0
  22. package/lib/index.d.ts +2 -1
  23. package/lib/index.js +6 -3
  24. package/lib/locale/locale.js +1 -1
  25. package/lib/locale/resource.js +6 -9
  26. package/lib/main-data-source.d.ts +11 -0
  27. package/lib/main-data-source.js +128 -0
  28. package/lib/middlewares/data-template.js +1 -6
  29. package/lib/middlewares/parse-variables.js +2 -49
  30. package/lib/plugin-manager/deps.js +1 -1
  31. package/lib/plugin-manager/options/resource.js +48 -25
  32. package/lib/plugin-manager/plugin-manager.d.ts +1 -0
  33. package/lib/plugin-manager/plugin-manager.js +36 -1
  34. package/lib/pub-sub-manager/pub-sub-manager.d.ts +1 -1
  35. package/lib/pub-sub-manager/pub-sub-manager.js +14 -20
  36. package/lib/snowflake-id-field.d.ts +2 -1
  37. package/lib/snowflake-id-field.js +2 -2
  38. package/package.json +17 -16
  39. package/lib/background-job-manager.d.ts +0 -40
  40. package/lib/background-job-manager.js +0 -111
@@ -56,7 +56,7 @@ const availableActions = {
56
56
  update: {
57
57
  displayName: '{{t("Edit")}}',
58
58
  type: "old-data",
59
- aliases: ["update", "move", "add", "set", "remove", "toggle"],
59
+ aliases: ["update", "move"],
60
60
  allowConfigureFields: true
61
61
  },
62
62
  destroy: {
@@ -109,6 +109,10 @@ const _AesEncryptor = class _AesEncryptor {
109
109
  return appKeyPath;
110
110
  }
111
111
  static async create(app) {
112
+ if (process.env.APP_AES_SECRET_KEY) {
113
+ const key2 = Buffer.from(process.env.APP_AES_SECRET_KEY, "hex");
114
+ return new _AesEncryptor(key2);
115
+ }
112
116
  const KEY_PATH = process.env.APP_AES_SECRET_KEY_PATH;
113
117
  const keyPath = KEY_PATH ? (0, import_path.resolve)(process.cwd(), KEY_PATH) : await this.getKeyPath(app.name);
114
118
  const key = await _AesEncryptor.getOrGenerateKey(keyPath);
@@ -14,6 +14,7 @@ export declare class AppCommand extends Command {
14
14
  auth(): this;
15
15
  preload(): this;
16
16
  hasCommand(name: string): boolean;
17
+ findCommand(name: string): any;
17
18
  isHandleByIPCServer(): boolean;
18
19
  createCommand(name?: string): AppCommand;
19
20
  parseHandleByIPCServer(argv: any, parseOptions?: any): Boolean;
@@ -51,6 +51,9 @@ const _AppCommand = class _AppCommand extends import_commander.Command {
51
51
  const names = this.commands.map((c) => c.name());
52
52
  return names.includes(name);
53
53
  }
54
+ findCommand(name) {
55
+ return this._findCommand(name);
56
+ }
54
57
  isHandleByIPCServer() {
55
58
  return this._handleByIPCServer;
56
59
  }
@@ -8,6 +8,7 @@
8
8
  */
9
9
  /// <reference types="node" />
10
10
  import { AsyncEmitter } from '@nocobase/utils';
11
+ import { Mutex } from 'async-mutex';
11
12
  import { EventEmitter } from 'events';
12
13
  import Application, { ApplicationOptions } from './application';
13
14
  type BootOptions = {
@@ -16,9 +17,10 @@ type BootOptions = {
16
17
  appSupervisor: AppSupervisor;
17
18
  };
18
19
  type AppBootstrapper = (bootOptions: BootOptions) => Promise<void>;
19
- type AppStatus = 'initializing' | 'initialized' | 'running' | 'commanding' | 'stopped' | 'error' | 'not_found';
20
+ export type AppStatus = 'preparing' | 'initializing' | 'initialized' | 'running' | 'commanding' | 'stopped' | 'error' | 'not_found';
20
21
  export declare class AppSupervisor extends EventEmitter implements AsyncEmitter {
21
22
  private static instance;
23
+ private bootstrapQueue;
22
24
  runningMode: 'single' | 'multiple';
23
25
  singleAppName: string | null;
24
26
  emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
@@ -48,7 +50,8 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
48
50
  reset(): Promise<void>;
49
51
  destroy(): Promise<void>;
50
52
  setAppStatus(appName: string, status: AppStatus, options?: {}): void;
51
- getMutexOfApp(appName: string): any;
53
+ getMutexOfApp(appName: string): Mutex;
54
+ private _bootStrapApp;
52
55
  bootStrapApp(appName: string, options?: {}): Promise<void>;
53
56
  getApp(appName: string, options?: {
54
57
  withOutBootStrap?: boolean;
@@ -61,6 +64,8 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
61
64
  touchApp(appName: string): void;
62
65
  addApp(app: Application): Application<import("./application").DefaultState, import("./application").DefaultContext>;
63
66
  getAppsNames(): Promise<string[]>;
67
+ startApp(appName: string): Promise<void>;
68
+ stopApp(appName: string): Promise<void>;
64
69
  removeApp(appName: string): Promise<void>;
65
70
  subApps(): Application<import("./application").DefaultState, import("./application").DefaultContext>[];
66
71
  on(eventName: string | symbol, listener: (...args: any[]) => void): this;
@@ -47,7 +47,9 @@ var import_async_mutex = require("async-mutex");
47
47
  var import_events = require("events");
48
48
  var import_application = __toESM(require("./application"));
49
49
  var import_handler = require("./errors/handler");
50
+ var import_p_queue = __toESM(require("p-queue"));
50
51
  const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
52
+ bootstrapQueue;
51
53
  runningMode = "multiple";
52
54
  singleAppName = null;
53
55
  apps = {};
@@ -64,6 +66,12 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
64
66
  this.runningMode = "single";
65
67
  this.singleAppName = process.env.STARTUP_SUBAPP;
66
68
  }
69
+ this.bootstrapQueue = new import_p_queue.default({
70
+ concurrency: process.env.SUBAPP_BOOTSTRAP_CONCURRENCY ? parseInt(process.env.SUBAPP_BOOTSTRAP_CONCURRENCY) : Infinity,
71
+ intervalCap: process.env.SUBAPP_BOOTSTRAP_INTERVAL_CAP ? parseInt(process.env.SUBAPP_BOOTSTRAP_INTERVAL_CAP) : Infinity,
72
+ interval: process.env.SUBAPP_BOOTSTRAP_INTERVAL ? parseInt(process.env.SUBAPP_BOOTSTRAP_INTERVAL) : 0,
73
+ timeout: 1 * 60 * 1e3
74
+ });
67
75
  }
68
76
  static getInstance() {
69
77
  if (!_AppSupervisor.instance) {
@@ -113,24 +121,42 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
113
121
  }
114
122
  return this.appMutexes[appName];
115
123
  }
124
+ async _bootStrapApp(appName, options = {}) {
125
+ this.setAppStatus(appName, "initializing");
126
+ if (this.appBootstrapper) {
127
+ await this.appBootstrapper({
128
+ appSupervisor: this,
129
+ appName,
130
+ options
131
+ });
132
+ }
133
+ if (!this.hasApp(appName)) {
134
+ this.setAppStatus(appName, "not_found");
135
+ } else if (!this.getAppStatus(appName) || this.getAppStatus(appName) === "initializing") {
136
+ this.setAppStatus(appName, "initialized");
137
+ }
138
+ }
116
139
  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
- });
140
+ const mutex = this.getMutexOfApp(appName);
141
+ try {
142
+ await (0, import_async_mutex.tryAcquire)(mutex).runExclusive(async () => {
143
+ if (this.hasApp(appName) && this.getAppStatus(appName) !== "preparing") {
144
+ return;
126
145
  }
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");
146
+ if (appName === "main") {
147
+ return this._bootStrapApp(appName, options);
131
148
  }
149
+ this.setAppStatus(appName, "preparing");
150
+ await this.bootstrapQueue.add(async () => {
151
+ await this._bootStrapApp(appName, options);
152
+ });
153
+ });
154
+ } catch (e) {
155
+ console.log(e);
156
+ if (e === import_async_mutex.E_ALREADY_LOCKED) {
157
+ return;
132
158
  }
133
- });
159
+ }
134
160
  }
135
161
  async getApp(appName, options = {}) {
136
162
  if (!options.withOutBootStrap) {
@@ -170,7 +196,7 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
170
196
  this.apps[app.name] = app;
171
197
  this.emit("afterAppAdded", app);
172
198
  if (!this.getAppStatus(app.name) || this.getAppStatus(app.name) == "not_found") {
173
- this.setAppStatus(app.name, "initialized");
199
+ this.setAppStatus(app.name, "preparing");
174
200
  }
175
201
  return app;
176
202
  }
@@ -179,12 +205,25 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
179
205
  const apps = Object.values(this.apps);
180
206
  return apps.map((app) => app.name);
181
207
  }
208
+ async startApp(appName) {
209
+ const appInstance = await _AppSupervisor.getInstance().getApp(appName);
210
+ await appInstance.runCommand("start", "--quickstart");
211
+ }
212
+ async stopApp(appName) {
213
+ if (!this.apps[appName]) {
214
+ console.log(`app ${appName} not exists`);
215
+ return;
216
+ }
217
+ await this.apps[appName].runCommand("stop");
218
+ this.apps[appName] = null;
219
+ }
182
220
  async removeApp(appName) {
183
221
  if (!this.apps[appName]) {
184
222
  console.log(`app ${appName} not exists`);
185
223
  return;
186
224
  }
187
225
  await this.apps[appName].runCommand("destroy");
226
+ this.apps[appName] = null;
188
227
  }
189
228
  subApps() {
190
229
  return Object.values(this.apps).filter((app) => app.name !== "main");
@@ -34,10 +34,9 @@ import { SyncMessageManager } from './sync-message-manager';
34
34
  import AesEncryptor from './aes-encryptor';
35
35
  import { AuditManager } from './audit-manager';
36
36
  import { Environment } from './environment';
37
- import { ServiceContainer } from './service-container';
38
37
  import { EventQueue, EventQueueOptions } from './event-queue';
39
- import { BackgroundJobManager, BackgroundJobManagerOptions } from './background-job-manager';
40
38
  import { RedisConfig, RedisConnectionManager } from './redis-connection-manager';
39
+ import { ServiceContainer } from './service-container';
41
40
  import { WorkerIdAllocator } from './worker-id-allocator';
42
41
  export type PluginType = string | typeof Plugin;
43
42
  export type PluginConfiguration = PluginType | [PluginType, any];
@@ -89,7 +88,6 @@ export interface ApplicationOptions {
89
88
  auditManager?: AuditManager;
90
89
  lockManager?: LockManagerOptions;
91
90
  eventQueue?: EventQueueOptions;
92
- backgroundJobManager?: BackgroundJobManagerOptions;
93
91
  /**
94
92
  * @internal
95
93
  */
@@ -129,7 +127,12 @@ interface StartOptions {
129
127
  type MaintainingStatus = 'command_begin' | 'command_end' | 'command_running' | 'command_error';
130
128
  export type MaintainingCommandStatus = {
131
129
  command: {
130
+ components?: {
131
+ maintaining: string;
132
+ maintainingDialog: string;
133
+ };
132
134
  name: string;
135
+ [key: string]: any;
133
136
  };
134
137
  status: MaintainingStatus;
135
138
  error?: Error;
@@ -190,9 +193,9 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
190
193
  container: ServiceContainer;
191
194
  lockManager: LockManager;
192
195
  eventQueue: EventQueue;
193
- backgroundJobManager: BackgroundJobManager;
194
196
  constructor(options: ApplicationOptions);
195
197
  private static staticCommands;
198
+ static registerStaticCommand(callback: (app: Application) => void): void;
196
199
  static addCommand(callback: (app: Application) => void): void;
197
200
  private _sqlLogger;
198
201
  get instanceId(): number;
@@ -219,7 +222,7 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
219
222
  get environment(): Environment;
220
223
  protected _cronJobManager: CronJobManager;
221
224
  get cronJobManager(): CronJobManager;
222
- get mainDataSource(): SequelizeDataSource;
225
+ get mainDataSource(): SequelizeDataSource<import("@nocobase/data-source-manager").DatabaseIntrospector>;
223
226
  get db(): Database;
224
227
  get resourceManager(): import("@nocobase/resourcer").ResourceManager;
225
228
  /**
@@ -283,7 +286,7 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
283
286
  setMaintainingMessage(message: string): void;
284
287
  /**
285
288
  * This method is deprecated and should not be used.
286
- * Use {@link #this.version.get()} instead.
289
+ * Use {@link #this.getPackageVersion} instead.
287
290
  * @deprecated
288
291
  */
289
292
  getVersion(): string;
@@ -50,8 +50,8 @@ var import_database = __toESM(require("@nocobase/database"));
50
50
  var import_logger = require("@nocobase/logger");
51
51
  var import_telemetry = require("@nocobase/telemetry");
52
52
  var import_lock_manager = require("@nocobase/lock-manager");
53
- var import_utils = require("@nocobase/utils");
54
53
  var import_snowflake_id = require("@nocobase/snowflake-id");
54
+ var import_utils = require("@nocobase/utils");
55
55
  var import_crypto = require("crypto");
56
56
  var import_glob = __toESM(require("glob"));
57
57
  var import_koa = __toESM(require("koa"));
@@ -81,12 +81,11 @@ var import_available_action = require("./acl/available-action");
81
81
  var import_aes_encryptor = __toESM(require("./aes-encryptor"));
82
82
  var import_audit_manager = require("./audit-manager");
83
83
  var import_environment = require("./environment");
84
- var import_service_container = require("./service-container");
85
84
  var import_event_queue = require("./event-queue");
86
- var import_background_job_manager = require("./background-job-manager");
87
85
  var import_redis_connection_manager = require("./redis-connection-manager");
88
- var import_worker_id_allocator = require("./worker-id-allocator");
86
+ var import_service_container = require("./service-container");
89
87
  var import_snowflake_id_field = require("./snowflake-id-field");
88
+ var import_worker_id_allocator = require("./worker-id-allocator");
90
89
  const _Application = class _Application extends import_koa.default {
91
90
  constructor(options) {
92
91
  super();
@@ -142,7 +141,9 @@ const _Application = class _Application extends import_koa.default {
142
141
  container = new import_service_container.ServiceContainer();
143
142
  lockManager;
144
143
  eventQueue;
145
- backgroundJobManager;
144
+ static registerStaticCommand(callback) {
145
+ this.staticCommands.push(callback);
146
+ }
146
147
  static addCommand(callback) {
147
148
  this.staticCommands.push(callback);
148
149
  }
@@ -336,7 +337,7 @@ const _Application = class _Application extends import_koa.default {
336
337
  }
337
338
  /**
338
339
  * This method is deprecated and should not be used.
339
- * Use {@link #this.version.get()} instead.
340
+ * Use {@link #this.getPackageVersion} instead.
340
341
  * @deprecated
341
342
  */
342
343
  getVersion() {
@@ -777,6 +778,12 @@ const _Application = class _Application extends import_koa.default {
777
778
  }
778
779
  async upgrade(options = {}) {
779
780
  this.log.info("upgrading...");
781
+ const pkgVersion = this.getPackageVersion();
782
+ const appVersion = await this.version.get();
783
+ if (process.env.SKIP_SAME_VERSION_UPGRADE === "true" && pkgVersion === appVersion) {
784
+ this.log.info(`app is already the latest version (${appVersion})`);
785
+ return;
786
+ }
780
787
  await this.reInit();
781
788
  const migrator1 = await this.loadCoreMigrations();
782
789
  await migrator1.beforeLoad.up();
@@ -800,7 +807,9 @@ const _Application = class _Application extends import_koa.default {
800
807
  await migrator3.afterLoad.up();
801
808
  await this.pm.repository.updateVersions();
802
809
  await this.version.update();
803
- await this.emitAsync("afterUpgrade", this, options);
810
+ if (!options.quickstart) {
811
+ await this.emitAsync("afterUpgrade", this, options);
812
+ }
804
813
  await this.restart();
805
814
  }
806
815
  toJSON() {
@@ -911,7 +920,6 @@ const _Application = class _Application extends import_koa.default {
911
920
  this.pubSubManager = (0, import_pub_sub_manager.createPubSubManager)(this, options.pubSubManager);
912
921
  this.syncMessageManager = new import_sync_message_manager.SyncMessageManager(this, options.syncMessageManager);
913
922
  this.eventQueue = new import_event_queue.EventQueue(this, options.eventQueue);
914
- this.backgroundJobManager = new import_background_job_manager.BackgroundJobManager(this, options.backgroundJobManager);
915
923
  this.lockManager = new import_lock_manager.LockManager({
916
924
  defaultAdapter: process.env.LOCK_ADAPTER_DEFAULT,
917
925
  ...options.lockManager
@@ -927,8 +935,8 @@ const _Application = class _Application extends import_koa.default {
927
935
  plugins: plugins || []
928
936
  });
929
937
  this._telemetry = new import_telemetry.Telemetry({
930
- serviceName: `nocobase-${this.name}`,
931
- version: this.getVersion(),
938
+ appName: this.name,
939
+ version: this.getPackageVersion(),
932
940
  ...options.telemetry
933
941
  });
934
942
  this._authManager = new import_auth.AuthManager({
@@ -941,6 +949,11 @@ const _Application = class _Application extends import_koa.default {
941
949
  name: "auth",
942
950
  actions: import_auth.actions
943
951
  });
952
+ this._dataSourceManager.beforeAddDataSource((dataSource) => {
953
+ if (dataSource.collectionManager instanceof import_data_source_manager.SequelizeCollectionManager) {
954
+ (0, import_snowflake_id_field.setupSnowflakeIdField)(this, dataSource.collectionManager.db);
955
+ }
956
+ });
944
957
  this._dataSourceManager.afterAddDataSource((dataSource) => {
945
958
  if (dataSource.collectionManager instanceof import_data_source_manager.SequelizeCollectionManager) {
946
959
  for (const [actionName, actionParams] of Object.entries(import_available_action.availableActions)) {
@@ -948,7 +961,7 @@ const _Application = class _Application extends import_koa.default {
948
961
  }
949
962
  }
950
963
  });
951
- this._dataSourceManager.use(this._authManager.middleware(), { tag: "auth" });
964
+ this._dataSourceManager.use(this._authManager.middleware(), { tag: "auth", before: "default" });
952
965
  this._dataSourceManager.use(import_validate_filter_params.default, { tag: "validate-filter-params", before: ["auth"] });
953
966
  this._dataSourceManager.use(import_middlewares.parseVariables, {
954
967
  group: "parseVariables",
@@ -982,7 +995,6 @@ const _Application = class _Application extends import_koa.default {
982
995
  app: this
983
996
  });
984
997
  this.dataSourceManager.dataSources.set("main", mainDataSourceInstance);
985
- (0, import_snowflake_id_field.setupSnowflakeIdField)(this);
986
998
  }
987
999
  createDatabase(options) {
988
1000
  const logging = /* @__PURE__ */ __name((...args) => {
@@ -53,6 +53,7 @@ var import_start = __toESM(require("./start"));
53
53
  var import_stop = __toESM(require("./stop"));
54
54
  var import_upgrade = __toESM(require("./upgrade"));
55
55
  var import_console = __toESM(require("./console"));
56
+ var import_repair = __toESM(require("./repair"));
56
57
  /* istanbul ignore file -- @preserve */
57
58
  function registerCli(app) {
58
59
  (0, import_console.default)(app);
@@ -68,6 +69,7 @@ function registerCli(app) {
68
69
  (0, import_destroy.default)(app);
69
70
  (0, import_start.default)(app);
70
71
  (0, import_refresh.default)(app);
72
+ (0, import_repair.default)(app);
71
73
  app.command("build").argument("[packages...]");
72
74
  app.command("clean");
73
75
  app.command("dev").usage("[options]").option("-p, --port [port]").option("--client").option("--server");
@@ -38,6 +38,17 @@ var pm_default = /* @__PURE__ */ __name((app) => {
38
38
  pm.command("create").argument("plugin").option("--force-recreate").action(async (plugin, options) => {
39
39
  await app.pm.create(plugin, options);
40
40
  });
41
+ pm.command("pull").arguments("<packageNames...>").option("--registry [registry]").option("--auth-token [authToken]").option("--version [version]").action(async (packageNames, options, cli) => {
42
+ try {
43
+ let name = packageNames;
44
+ if (Array.isArray(packageNames) && packageNames.length === 1) {
45
+ name = packageNames[0];
46
+ }
47
+ await app.pm.pull(name, { ...options });
48
+ } catch (error) {
49
+ throw new import_plugin_command_error.PluginCommandError(`Failed to pull plugin`, { cause: error });
50
+ }
51
+ });
41
52
  pm.command("add").ipc().preload().arguments("<packageNames...>").option("--registry [registry]").option("--auth-token [authToken]").option("--version [version]").action(async (packageNames, options, cli) => {
42
53
  try {
43
54
  let name = packageNames;
@@ -0,0 +1,11 @@
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
+ import Application from '../application';
10
+ declare const _default: (app: Application) => void;
11
+ export default _default;
@@ -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
  }
@@ -23,6 +23,12 @@ export type QueueEventOptions = {
23
23
  */
24
24
  interval?: number;
25
25
  concurrency?: number;
26
+ /**
27
+ * Shared across multiple applications.
28
+ * Will not use app prefix for channel name.
29
+ * @experimental
30
+ */
31
+ shared?: boolean;
26
32
  idle(): boolean;
27
33
  process: QueueCallback;
28
34
  };
@@ -84,7 +90,7 @@ export declare class EventQueue {
84
90
  protected events: Map<string, QueueEventOptions>;
85
91
  get channelPrefix(): string;
86
92
  constructor(app: Application, options?: EventQueueOptions);
87
- getFullChannel(channel: string): string;
93
+ getFullChannel(channel: string, shared?: boolean): string;
88
94
  setAdapter<A extends IEventQueueAdapter>(adapter: A): void;
89
95
  isConnected(): boolean;
90
96
  connect(): Promise<void>;
@@ -270,16 +270,14 @@ const _EventQueue = class _EventQueue {
270
270
  constructor(app, options = {}) {
271
271
  this.app = app;
272
272
  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
- }
273
+ this.setAdapter(new MemoryEventQueueAdapter({ appName: this.app.name, logger: this.app.logger }));
274
+ app.on("afterStart", async () => {
275
+ await this.connect();
276
+ });
277
+ app.on("afterStop", async () => {
278
+ app.logger.info("[queue] gracefully shutting down...");
279
+ await this.close();
280
+ });
283
281
  }
284
282
  adapter;
285
283
  events = /* @__PURE__ */ new Map();
@@ -287,7 +285,10 @@ const _EventQueue = class _EventQueue {
287
285
  var _a;
288
286
  return (_a = this.options) == null ? void 0 : _a.channelPrefix;
289
287
  }
290
- getFullChannel(channel) {
288
+ getFullChannel(channel, shared = false) {
289
+ if (shared) {
290
+ return [this.channelPrefix, channel].filter(Boolean).join(".");
291
+ }
291
292
  return [this.app.name, this.channelPrefix, channel].filter(Boolean).join(".");
292
293
  }
293
294
  setAdapter(adapter) {
@@ -303,14 +304,10 @@ const _EventQueue = class _EventQueue {
303
304
  if (!this.adapter) {
304
305
  throw new Error("no adapter set, cannot connect");
305
306
  }
306
- if (!this.app.serving()) {
307
- this.app.logger.warn("app is not serving, will not connect to event queue");
308
- return;
309
- }
310
307
  await this.adapter.connect();
311
308
  this.app.logger.debug(`connected to adapter, using memory? ${this.adapter instanceof MemoryEventQueueAdapter}`);
312
309
  for (const [channel, event] of this.events.entries()) {
313
- this.adapter.subscribe(this.getFullChannel(channel), event);
310
+ this.adapter.subscribe(this.getFullChannel(channel, event.shared), event);
314
311
  }
315
312
  }
316
313
  async close() {
@@ -318,8 +315,8 @@ const _EventQueue = class _EventQueue {
318
315
  return;
319
316
  }
320
317
  await this.adapter.close();
321
- for (const channel of this.events.keys()) {
322
- this.adapter.unsubscribe(this.getFullChannel(channel));
318
+ for (const [channel, event] of this.events.entries()) {
319
+ this.adapter.unsubscribe(this.getFullChannel(channel, event.shared));
323
320
  }
324
321
  }
325
322
  subscribe(channel, options) {
@@ -329,16 +326,17 @@ const _EventQueue = class _EventQueue {
329
326
  }
330
327
  this.events.set(channel, options);
331
328
  if (this.isConnected()) {
332
- this.adapter.subscribe(this.getFullChannel(channel), options);
329
+ this.adapter.subscribe(this.getFullChannel(channel, options.shared), this.events.get(channel));
333
330
  }
334
331
  }
335
332
  unsubscribe(channel) {
333
+ var _a;
336
334
  if (!this.events.has(channel)) {
337
335
  return;
338
336
  }
339
337
  this.events.delete(channel);
340
338
  if (this.isConnected()) {
341
- this.adapter.unsubscribe(this.getFullChannel(channel));
339
+ this.adapter.unsubscribe(this.getFullChannel(channel, (_a = this.events.get(channel)) == null ? void 0 : _a.shared));
342
340
  }
343
341
  }
344
342
  async publish(channel, message, options = {}) {
@@ -348,7 +346,11 @@ const _EventQueue = class _EventQueue {
348
346
  if (!this.isConnected()) {
349
347
  throw new Error("event queue not connected, cannot publish");
350
348
  }
351
- const c = this.getFullChannel(channel);
349
+ const event = this.events.get(channel);
350
+ if (!event) {
351
+ throw new Error(`event queue not subscribed on channel "${channel}", cannot publish`);
352
+ }
353
+ const c = this.getFullChannel(channel, event.shared);
352
354
  this.app.logger.debug(`event queue publishing to channel(${c})`, { message });
353
355
  await this.adapter.publish(c, message, {
354
356
  timeout: QUEUE_DEFAULT_ACK_TIMEOUT,