@nocobase/server 2.1.0-alpha.40 → 2.1.0-alpha.46

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.
@@ -13,7 +13,7 @@ import { IncomingMessage, ServerResponse } from 'http';
13
13
  import { AsyncEmitter } from '@nocobase/utils';
14
14
  import { EventEmitter } from 'events';
15
15
  import Application, { ApplicationOptions } from '../application';
16
- import type { AppDiscoveryAdapter, AppProcessAdapter, AppStatus, EnvironmentInfo, GetAppOptions, ProcessCommand, AppDbCreator, AppOptionsFactory, AppDbCreatorOptions, AppCommandAdapter, AppModel, BootstrapLock } from './types';
16
+ import type { AppDiscoveryAdapter, AppProcessAdapter, AppStatus, EnvironmentInfo, GetAppOptions, ProcessCommand, AppDbCreator, AppOptionsFactory, AppDbCreatorOptions, AppCommandAdapter, AppModel, BootstrapLock, AppCondition, GetAppsByConditionOptions } from './types';
17
17
  import { Predicate } from './condition-registry';
18
18
  import { PubSubManagerPublishOptions } from '../pub-sub-manager';
19
19
  import { Transaction, Transactionable } from '@nocobase/database';
@@ -48,6 +48,7 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
48
48
  private processAdapterName;
49
49
  private commandAdapterName;
50
50
  private appDbCreator;
51
+ private appConditions;
51
52
  appOptionsFactory: AppOptionsFactory;
52
53
  private environmentHeartbeatInterval;
53
54
  private environmentHeartbeatTimer;
@@ -107,11 +108,15 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
107
108
  getAppLastSeenAt(appName: string): Promise<number>;
108
109
  addAppModel(appModel: AppModel): Promise<void>;
109
110
  getAppModel(appName: string): Promise<AppModel>;
111
+ registerAppCondition(name: string, condition: AppCondition): void;
112
+ unregisterAppCondition(name: string): void;
113
+ getAppCondition(name: string): AppCondition;
114
+ getAppConditions(): [string, AppCondition][];
115
+ getAppsByCondition(conditionName: string, options?: GetAppsByConditionOptions): Promise<string[]>;
110
116
  removeAppModel(appName: string): Promise<void>;
111
117
  getAppNameByCName(cname: string): Promise<string>;
112
- addAutoStartApps(environmentName: string, appNames: string[]): Promise<void>;
113
- getAutoStartApps(): Promise<string[]>;
114
- removeAutoStartApps(environmentName: string, appNames: string[]): Promise<void>;
118
+ addAppsToCondition(conditionName: string, environmentName: string, appNames: string[]): Promise<void>;
119
+ removeAppsFromCondition(conditionName: string, environmentName: string, appNames: string[]): Promise<void>;
115
120
  addApp(app: Application): Application<import("../application").DefaultState, import("../application").DefaultContext>;
116
121
  getApp(appName: string, options?: GetAppOptions): Promise<Application<import("../application").DefaultState, import("../application").DefaultContext>>;
117
122
  hasApp(appName: string): boolean;
@@ -134,6 +139,9 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
134
139
  upgradeApp(appName: string, context?: {
135
140
  requestId: string;
136
141
  }): Promise<void>;
142
+ dispatchAppEvent(appName: string, event: string, payload?: any, context?: {
143
+ requestId: string;
144
+ }): Promise<void>;
137
145
  /**
138
146
  * @deprecated
139
147
  * use {#getApps} instead
@@ -157,5 +165,5 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
157
165
  on(eventName: string | symbol, listener: (...args: any[]) => void): this;
158
166
  private bindAppEvents;
159
167
  }
160
- export type { AppDiscoveryAdapter, AppProcessAdapter, AppCommandAdapter, AppStatus, ProcessCommand, EnvironmentInfo, GetAppOptions, AppDbCreator, AppOptionsFactory, AppModel, AppModelOptions, BootstrapLock, } from './types';
168
+ export type { AppDiscoveryAdapter, AppProcessAdapter, AppCommandAdapter, AppStatus, ProcessCommand, EnvironmentInfo, GetAppOptions, AppDbCreator, AppOptionsFactory, AppModel, AppModelOptions, AppCondition, GetAppsByConditionOptions, BootstrapLock, } from './types';
161
169
  export { MainOnlyAdapter } from './main-only-adapter';
@@ -69,6 +69,7 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
69
69
  processAdapterName;
70
70
  commandAdapterName;
71
71
  appDbCreator = new import_condition_registry.ConditionalRegistry();
72
+ appConditions = /* @__PURE__ */ new Map();
72
73
  appOptionsFactory = import_app_options_factory.appOptionsFactory;
73
74
  environmentHeartbeatInterval = 2 * 60 * 1e3;
74
75
  environmentHeartbeatTimer = null;
@@ -420,6 +421,28 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
420
421
  async getAppModel(appName) {
421
422
  return this.discoveryAdapter.getAppModel(appName);
422
423
  }
424
+ registerAppCondition(name, condition) {
425
+ this.appConditions.set(name, condition);
426
+ }
427
+ unregisterAppCondition(name) {
428
+ this.appConditions.delete(name);
429
+ }
430
+ getAppCondition(name) {
431
+ return this.appConditions.get(name);
432
+ }
433
+ getAppConditions() {
434
+ return Array.from(this.appConditions.entries());
435
+ }
436
+ async getAppsByCondition(conditionName, options = {}) {
437
+ const condition = this.getAppCondition(conditionName);
438
+ if (!condition || typeof this.discoveryAdapter.getAppsByCondition !== "function") {
439
+ return [];
440
+ }
441
+ return this.discoveryAdapter.getAppsByCondition(conditionName, condition, {
442
+ ...options,
443
+ environmentName: options.allEnvironments ? options.environmentName : options.environmentName ?? this.environmentName
444
+ });
445
+ }
423
446
  async removeAppModel(appName) {
424
447
  if (typeof this.discoveryAdapter.removeAppModel !== "function") {
425
448
  return;
@@ -432,23 +455,17 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
432
455
  }
433
456
  return this.discoveryAdapter.getAppNameByCName(cname);
434
457
  }
435
- async addAutoStartApps(environmentName, appNames) {
436
- if (typeof this.discoveryAdapter.addAutoStartApps !== "function") {
458
+ async addAppsToCondition(conditionName, environmentName, appNames) {
459
+ if (typeof this.discoveryAdapter.addAppsToCondition !== "function") {
437
460
  return;
438
461
  }
439
- return this.discoveryAdapter.addAutoStartApps(environmentName, appNames);
440
- }
441
- async getAutoStartApps() {
442
- if (typeof this.discoveryAdapter.getAutoStartApps === "function") {
443
- return this.discoveryAdapter.getAutoStartApps(this.environmentName);
444
- }
445
- return [];
462
+ return this.discoveryAdapter.addAppsToCondition(conditionName, environmentName, appNames);
446
463
  }
447
- async removeAutoStartApps(environmentName, appNames) {
448
- if (typeof this.discoveryAdapter.addAutoStartApps !== "function") {
464
+ async removeAppsFromCondition(conditionName, environmentName, appNames) {
465
+ if (typeof this.discoveryAdapter.removeAppsFromCondition !== "function") {
449
466
  return;
450
467
  }
451
- return this.discoveryAdapter.removeAutoStartApps(environmentName, appNames);
468
+ return this.discoveryAdapter.removeAppsFromCondition(conditionName, environmentName, appNames);
452
469
  }
453
470
  addApp(app) {
454
471
  this.processAdapter.addApp(app);
@@ -477,6 +494,10 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
477
494
  async upgradeApp(appName, context) {
478
495
  await this.processAdapter.upgradeApp(appName, context);
479
496
  }
497
+ async dispatchAppEvent(appName, event, payload, context) {
498
+ var _a, _b;
499
+ return (_b = (_a = this.processAdapter).dispatchAppEvent) == null ? void 0 : _b.call(_a, appName, event, payload, context);
500
+ }
480
501
  /**
481
502
  * @deprecated
482
503
  * use {#getApps} instead
@@ -26,6 +26,9 @@ export declare class MainOnlyAdapter implements AppDiscoveryAdapter, AppProcessA
26
26
  stopApp(appName: string): Promise<void>;
27
27
  removeApp(appName: string): Promise<void>;
28
28
  upgradeApp(appName: string): Promise<void>;
29
+ dispatchAppEvent(appName: string, event: string, payload?: any, _context?: {
30
+ requestId: string;
31
+ }): Promise<void>;
29
32
  removeAllApps(): Promise<void>;
30
33
  setAppStatus(appName: string, status: AppStatus, options?: {}): void;
31
34
  getAppStatus(appName: string, defaultStatus?: AppStatus): AppStatus;
@@ -124,6 +124,13 @@ const _MainOnlyAdapter = class _MainOnlyAdapter {
124
124
  }
125
125
  await this.apps[appName].runCommand("upgrade");
126
126
  }
127
+ async dispatchAppEvent(appName, event, payload, _context) {
128
+ const app = await this.getApp(appName, { withOutBootStrap: true });
129
+ if (!app) {
130
+ return;
131
+ }
132
+ await app.emitAsync(event, payload);
133
+ }
127
134
  async removeAllApps() {
128
135
  return this.removeApp("main");
129
136
  }
@@ -57,11 +57,23 @@ export type AppModelOptions = {
57
57
  };
58
58
  export type AppModel = {
59
59
  name: string;
60
+ title?: string;
61
+ icon?: string;
60
62
  cname?: string;
63
+ sort?: number;
64
+ pinned?: boolean;
61
65
  environment?: string;
62
66
  environments?: string[];
63
67
  options: AppModelOptions;
64
68
  };
69
+ export type AppCondition = {
70
+ filter?: Record<string, any>;
71
+ match?: (appModel: AppModel) => boolean;
72
+ };
73
+ export type GetAppsByConditionOptions = {
74
+ environmentName?: string;
75
+ allEnvironments?: boolean;
76
+ };
65
77
  export type ProcessCommand = {
66
78
  requestId: string;
67
79
  appName: string;
@@ -102,9 +114,9 @@ export interface AppDiscoveryAdapter {
102
114
  clearAppStatus?(appName: string): void | Promise<void>;
103
115
  loadAppModels?(mainApp: Application): Promise<void>;
104
116
  getAppsStatuses?(appNames?: string[]): Promise<AppStatusesResult> | AppStatusesResult;
105
- addAutoStartApps?(environmentName: string, appName: string[]): Promise<void>;
106
- getAutoStartApps?(environmentName: string): Promise<string[]>;
107
- removeAutoStartApps?(environmentName: string, appNames: string[]): Promise<void>;
117
+ getAppsByCondition?(conditionName: string, condition: AppCondition, options?: GetAppsByConditionOptions): Promise<string[]>;
118
+ addAppsToCondition?(conditionName: string, environmentName: string, appNames: string[]): Promise<void>;
119
+ removeAppsFromCondition?(conditionName: string, environmentName: string, appNames: string[]): Promise<void>;
108
120
  addAppModel?(appModel: AppModel): Promise<void>;
109
121
  getAppModel?(appName: string): Promise<AppModel>;
110
122
  removeAppModel?(appName: string): Promise<void>;
@@ -149,6 +161,9 @@ export interface AppProcessAdapter {
149
161
  upgradeApp?(appName: string, context?: {
150
162
  requestId: string;
151
163
  }): Promise<void>;
164
+ dispatchAppEvent?(appName: string, event: string, payload?: any, context?: {
165
+ requestId: string;
166
+ }): Promise<void>;
152
167
  removeAllApps?(): Promise<void>;
153
168
  setAppError?(appName: string, error: Error): void;
154
169
  hasAppError?(appName: string): boolean;
@@ -287,6 +287,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
287
287
  getV2RuntimeConfig() {
288
288
  return {
289
289
  __nocobase_public_path__: this.getV2PublicPath(),
290
+ __nocobase_modern_client_prefix__: (0, import_utils3.normalizeModernClientPrefix)(import_node_process.default.env.APP_MODERN_CLIENT_PREFIX),
290
291
  __webpack_public_path__: import_node_process.default.env.CDN_BASE_URL ? `${import_node_process.default.env.CDN_BASE_URL.replace(/\/+$/, "")}/` : "",
291
292
  __nocobase_api_base_url__: import_node_process.default.env.API_BASE_URL || import_node_process.default.env.API_BASE_PATH,
292
293
  __nocobase_api_client_storage_prefix__: import_node_process.default.env.API_CLIENT_STORAGE_PREFIX,
@@ -306,12 +307,12 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
306
307
  }
307
308
  getV2AssetPublicPath() {
308
309
  if (import_node_process.default.env.CDN_BASE_URL) {
309
- return `${import_node_process.default.env.CDN_BASE_URL.replace(/\/+$/, "")}/v2/`;
310
+ return `${import_node_process.default.env.CDN_BASE_URL.replace(/\/+$/, "")}/${import_utils3.MODERN_CLIENT_DIST_DIR}/`;
310
311
  }
311
312
  return this.getV2PublicPath();
312
313
  }
313
314
  getV2IndexTemplate() {
314
- const file = `${import_node_process.default.env.APP_PACKAGE_ROOT}/dist/client/v2/index.html`;
315
+ const file = `${import_node_process.default.env.APP_PACKAGE_ROOT}/dist/client/${import_utils3.MODERN_CLIENT_DIST_DIR}/index.html`;
315
316
  if (!import_fs.default.existsSync(file)) {
316
317
  return null;
317
318
  }
@@ -409,6 +410,10 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
409
410
  }
410
411
  }
411
412
  req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
413
+ const modernPrefix = (0, import_utils3.normalizeModernClientPrefix)(import_node_process.default.env.APP_MODERN_CLIENT_PREFIX);
414
+ if (modernPrefix !== import_utils3.MODERN_CLIENT_DIST_DIR && req.url.startsWith(`/${modernPrefix}/`)) {
415
+ req.url = `/${import_utils3.MODERN_CLIENT_DIST_DIR}/${req.url.slice(modernPrefix.length + 2)}`;
416
+ }
412
417
  await compress(req, res);
413
418
  return (0, import_serve_handler.default)(req, res, {
414
419
  public: `${import_node_process.default.env.APP_PACKAGE_ROOT}/dist/client`
@@ -42,7 +42,7 @@ __export(static_file_security_exports, {
42
42
  });
43
43
  module.exports = __toCommonJS(static_file_security_exports);
44
44
  var import_node_path = __toESM(require("node:path"));
45
- const ACTIVE_CONTENT_EXTENSIONS = /* @__PURE__ */ new Set([".htm", ".html", ".svg", ".svgz", ".xhtml"]);
45
+ const ACTIVE_CONTENT_EXTENSIONS = /* @__PURE__ */ new Set([".htm", ".html", ".pdf", ".svg", ".svgz", ".xhtml"]);
46
46
  function stripQueryAndHash(pathname = "") {
47
47
  return pathname.split("?")[0].split("#")[0];
48
48
  }
@@ -9,7 +9,9 @@
9
9
  /// <reference types="node" />
10
10
  import { IncomingMessage } from 'http';
11
11
  import { IncomingRequest } from '.';
12
+ export declare const MODERN_CLIENT_DIST_DIR = "v";
12
13
  export declare function resolvePublicPath(appPublicPath?: string): string;
14
+ export declare function normalizeModernClientPrefix(value?: string): string;
13
15
  export declare function resolveV2PublicPath(appPublicPath?: string): string;
14
16
  export declare function rewriteV2AssetPublicPath(html: string, assetPublicPath: string): string;
15
17
  export declare function injectRuntimeScript(html: string, runtimeScript: string): string;
@@ -27,23 +27,32 @@ var __copyProps = (to, from, except, desc) => {
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
  var utils_exports = {};
29
29
  __export(utils_exports, {
30
+ MODERN_CLIENT_DIST_DIR: () => MODERN_CLIENT_DIST_DIR,
30
31
  getHost: () => getHost,
31
32
  getHostname: () => getHostname,
32
33
  injectRuntimeScript: () => injectRuntimeScript,
34
+ normalizeModernClientPrefix: () => normalizeModernClientPrefix,
33
35
  resolvePublicPath: () => resolvePublicPath,
34
36
  resolveV2PublicPath: () => resolveV2PublicPath,
35
37
  rewriteV2AssetPublicPath: () => rewriteV2AssetPublicPath
36
38
  });
37
39
  module.exports = __toCommonJS(utils_exports);
40
+ const MODERN_CLIENT_DIST_DIR = "v";
38
41
  function resolvePublicPath(appPublicPath = "/") {
39
42
  const normalized = String(appPublicPath || "/").trim() || "/";
40
43
  const withLeadingSlash = normalized.startsWith("/") ? normalized : `/${normalized}`;
41
44
  return withLeadingSlash.endsWith("/") ? withLeadingSlash : `${withLeadingSlash}/`;
42
45
  }
43
46
  __name(resolvePublicPath, "resolvePublicPath");
47
+ function normalizeModernClientPrefix(value) {
48
+ const segment = String(value || "").trim().replace(/^\/+|\/+$/g, "");
49
+ return segment || MODERN_CLIENT_DIST_DIR;
50
+ }
51
+ __name(normalizeModernClientPrefix, "normalizeModernClientPrefix");
44
52
  function resolveV2PublicPath(appPublicPath = "/") {
45
53
  const publicPath = resolvePublicPath(appPublicPath);
46
- return `${publicPath.replace(/\/$/, "")}/v2/`;
54
+ const prefix = normalizeModernClientPrefix(process.env.APP_MODERN_CLIENT_PREFIX);
55
+ return `${publicPath.replace(/\/$/, "")}/${prefix}/`;
47
56
  }
48
57
  __name(resolveV2PublicPath, "resolveV2PublicPath");
49
58
  function ensureTrailingSlash(value) {
@@ -52,10 +61,12 @@ function ensureTrailingSlash(value) {
52
61
  __name(ensureTrailingSlash, "ensureTrailingSlash");
53
62
  function rewriteV2AssetPublicPath(html, assetPublicPath) {
54
63
  const normalizedAssetPublicPath = ensureTrailingSlash(assetPublicPath);
55
- if (normalizedAssetPublicPath === "/v2/") {
64
+ const sentinel = `/${MODERN_CLIENT_DIST_DIR}/`;
65
+ if (normalizedAssetPublicPath === sentinel) {
56
66
  return html;
57
67
  }
58
- return html.replace(/((?:src|href)=["'])\/v2\//g, `$1${normalizedAssetPublicPath}`);
68
+ const sentinelPattern = new RegExp(`((?:src|href)=["'])${sentinel.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "g");
69
+ return html.replace(sentinelPattern, `$1${normalizedAssetPublicPath}`);
59
70
  }
60
71
  __name(rewriteV2AssetPublicPath, "rewriteV2AssetPublicPath");
61
72
  function injectRuntimeScript(html, runtimeScript) {
@@ -106,9 +117,11 @@ function getHostname(req) {
106
117
  __name(getHostname, "getHostname");
107
118
  // Annotate the CommonJS export names for ESM import in node:
108
119
  0 && (module.exports = {
120
+ MODERN_CLIENT_DIST_DIR,
109
121
  getHost,
110
122
  getHostname,
111
123
  injectRuntimeScript,
124
+ normalizeModernClientPrefix,
112
125
  resolvePublicPath,
113
126
  resolveV2PublicPath,
114
127
  rewriteV2AssetPublicPath
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/server",
3
- "version": "2.1.0-alpha.40",
3
+ "version": "2.1.0-alpha.46",
4
4
  "main": "lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -10,21 +10,21 @@
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.1.0-alpha.40",
14
- "@nocobase/actions": "2.1.0-alpha.40",
15
- "@nocobase/ai": "2.1.0-alpha.40",
16
- "@nocobase/auth": "2.1.0-alpha.40",
17
- "@nocobase/cache": "2.1.0-alpha.40",
18
- "@nocobase/data-source-manager": "2.1.0-alpha.40",
19
- "@nocobase/database": "2.1.0-alpha.40",
20
- "@nocobase/evaluators": "2.1.0-alpha.40",
21
- "@nocobase/lock-manager": "2.1.0-alpha.40",
22
- "@nocobase/logger": "2.1.0-alpha.40",
23
- "@nocobase/resourcer": "2.1.0-alpha.40",
24
- "@nocobase/sdk": "2.1.0-alpha.40",
25
- "@nocobase/snowflake-id": "2.1.0-alpha.40",
26
- "@nocobase/telemetry": "2.1.0-alpha.40",
27
- "@nocobase/utils": "2.1.0-alpha.40",
13
+ "@nocobase/acl": "2.1.0-alpha.46",
14
+ "@nocobase/actions": "2.1.0-alpha.46",
15
+ "@nocobase/ai": "2.1.0-alpha.46",
16
+ "@nocobase/auth": "2.1.0-alpha.46",
17
+ "@nocobase/cache": "2.1.0-alpha.46",
18
+ "@nocobase/data-source-manager": "2.1.0-alpha.46",
19
+ "@nocobase/database": "2.1.0-alpha.46",
20
+ "@nocobase/evaluators": "2.1.0-alpha.46",
21
+ "@nocobase/lock-manager": "2.1.0-alpha.46",
22
+ "@nocobase/logger": "2.1.0-alpha.46",
23
+ "@nocobase/resourcer": "2.1.0-alpha.46",
24
+ "@nocobase/sdk": "2.1.0-alpha.46",
25
+ "@nocobase/snowflake-id": "2.1.0-alpha.46",
26
+ "@nocobase/telemetry": "2.1.0-alpha.46",
27
+ "@nocobase/utils": "2.1.0-alpha.46",
28
28
  "@types/decompress": "4.2.7",
29
29
  "@types/ini": "^1.3.31",
30
30
  "@types/koa-send": "^4.1.3",
@@ -61,5 +61,5 @@
61
61
  "@types/serve-handler": "^6.1.1",
62
62
  "@types/ws": "^8.5.5"
63
63
  },
64
- "gitHead": "e73f99dd0abefe847f2e50ff0fea1f41a82fd048"
64
+ "gitHead": "42b269944cdd1908d7a848c0af4936fe94c03bb7"
65
65
  }