@nocobase/server 2.2.0-alpha.1 → 2.2.0-alpha.11

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.
@@ -49,6 +49,8 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
49
49
  private commandAdapterName;
50
50
  private appDbCreator;
51
51
  private appConditions;
52
+ private appManifests;
53
+ private appSsoIssuer?;
52
54
  appOptionsFactory: AppOptionsFactory;
53
55
  private environmentHeartbeatInterval;
54
56
  private environmentHeartbeatTimer;
@@ -81,6 +83,8 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
81
83
  registerAppDbCreator(condition: Predicate<AppDbCreatorOptions>, creator: AppDbCreator, priority?: number): void;
82
84
  createDatabase(options: AppDbCreatorOptions): Promise<void>;
83
85
  setAppOptionsFactory(factory: AppOptionsFactory): void;
86
+ setAppSsoIssuer(issuer?: string): void;
87
+ getAppSsoIssuer(): string;
84
88
  bootstrapApp(appName: string): Promise<void>;
85
89
  initApp({ appName, options }: {
86
90
  appName: string;
@@ -108,6 +112,14 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
108
112
  getAppLastSeenAt(appName: string): Promise<number>;
109
113
  addAppModel(appModel: AppModel): Promise<void>;
110
114
  getAppModel(appName: string): Promise<AppModel>;
115
+ listAppModels(): Promise<AppModel[]>;
116
+ setAppManifestItem(appName: string, namespace: string, itemKey: string, item: unknown): Promise<void>;
117
+ removeAppManifestItem(appName: string, namespace: string, itemKey: string): Promise<void>;
118
+ removeAppManifest(appName: string, namespace: string): Promise<void>;
119
+ getAppManifestItems<T = unknown>(appName: string, namespace: string): Promise<T[]>;
120
+ getAppManifests<T = unknown>(namespace: string, appNames: string[]): Promise<Record<string, T[]>>;
121
+ private getAppManifestKey;
122
+ private getOrCreateAppManifest;
111
123
  registerAppCondition(name: string, condition: AppCondition): void;
112
124
  unregisterAppCondition(name: string): void;
113
125
  getAppCondition(name: string): AppCondition;
@@ -70,6 +70,8 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
70
70
  commandAdapterName;
71
71
  appDbCreator = new import_condition_registry.ConditionalRegistry();
72
72
  appConditions = /* @__PURE__ */ new Map();
73
+ appManifests = /* @__PURE__ */ new Map();
74
+ appSsoIssuer;
73
75
  appOptionsFactory = import_app_options_factory.appOptionsFactory;
74
76
  environmentHeartbeatInterval = 2 * 60 * 1e3;
75
77
  environmentHeartbeatTimer = null;
@@ -228,6 +230,13 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
228
230
  setAppOptionsFactory(factory) {
229
231
  this.appOptionsFactory = factory ?? import_app_options_factory.appOptionsFactory;
230
232
  }
233
+ setAppSsoIssuer(issuer) {
234
+ const normalized = String(issuer || "").trim().replace(/\/+$/, "");
235
+ this.appSsoIssuer = normalized || void 0;
236
+ }
237
+ getAppSsoIssuer() {
238
+ return this.appSsoIssuer;
239
+ }
231
240
  async bootstrapApp(appName) {
232
241
  return this.processAdapter.bootstrapApp(appName);
233
242
  }
@@ -276,6 +285,7 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
276
285
  await this.processAdapter.removeAllApps();
277
286
  await ((_b = (_a = this.discoveryAdapter).dispose) == null ? void 0 : _b.call(_a));
278
287
  await ((_d = (_c = this.commandAdapter) == null ? void 0 : _c.dispose) == null ? void 0 : _d.call(_c));
288
+ this.appManifests.clear();
279
289
  if (this.environmentHeartbeatTimer) {
280
290
  this.environmentHeartbeatTimer = null;
281
291
  }
@@ -421,6 +431,67 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
421
431
  async getAppModel(appName) {
422
432
  return this.discoveryAdapter.getAppModel(appName);
423
433
  }
434
+ async listAppModels() {
435
+ if (typeof this.discoveryAdapter.listAppModels !== "function") {
436
+ return [];
437
+ }
438
+ return this.discoveryAdapter.listAppModels();
439
+ }
440
+ async setAppManifestItem(appName, namespace, itemKey, item) {
441
+ if (typeof this.discoveryAdapter.setAppManifestItem === "function") {
442
+ return this.discoveryAdapter.setAppManifestItem(appName, namespace, itemKey, item);
443
+ }
444
+ const manifest = this.getOrCreateAppManifest(appName, namespace);
445
+ manifest.set(itemKey, item);
446
+ }
447
+ async removeAppManifestItem(appName, namespace, itemKey) {
448
+ var _a;
449
+ if (typeof this.discoveryAdapter.removeAppManifestItem === "function") {
450
+ return this.discoveryAdapter.removeAppManifestItem(appName, namespace, itemKey);
451
+ }
452
+ (_a = this.appManifests.get(this.getAppManifestKey(appName, namespace))) == null ? void 0 : _a.delete(itemKey);
453
+ }
454
+ async removeAppManifest(appName, namespace) {
455
+ if (typeof this.discoveryAdapter.removeAppManifest === "function") {
456
+ return this.discoveryAdapter.removeAppManifest(appName, namespace);
457
+ }
458
+ this.appManifests.delete(this.getAppManifestKey(appName, namespace));
459
+ }
460
+ async getAppManifestItems(appName, namespace) {
461
+ var _a;
462
+ if (typeof this.discoveryAdapter.getAppManifestItems === "function") {
463
+ return this.discoveryAdapter.getAppManifestItems(appName, namespace);
464
+ }
465
+ return Array.from(((_a = this.appManifests.get(this.getAppManifestKey(appName, namespace))) == null ? void 0 : _a.values()) || []);
466
+ }
467
+ async getAppManifests(namespace, appNames) {
468
+ if (typeof this.discoveryAdapter.getAppManifests === "function") {
469
+ return this.discoveryAdapter.getAppManifests(namespace, appNames);
470
+ }
471
+ const result = {};
472
+ await Promise.all(
473
+ appNames.map(async (appName) => {
474
+ const manifest = await this.getAppManifestItems(appName, namespace);
475
+ if (manifest.length > 0) {
476
+ result[appName] = manifest;
477
+ }
478
+ })
479
+ );
480
+ return result;
481
+ }
482
+ getAppManifestKey(appName, namespace) {
483
+ return `${namespace}:${appName}`;
484
+ }
485
+ getOrCreateAppManifest(appName, namespace) {
486
+ const key = this.getAppManifestKey(appName, namespace);
487
+ const manifest = this.appManifests.get(key);
488
+ if (manifest) {
489
+ return manifest;
490
+ }
491
+ const nextManifest = /* @__PURE__ */ new Map();
492
+ this.appManifests.set(key, nextManifest);
493
+ return nextManifest;
494
+ }
424
495
  registerAppCondition(name, condition) {
425
496
  this.appConditions.set(name, condition);
426
497
  }
@@ -21,6 +21,7 @@ export declare class MainOnlyAdapter implements AppDiscoveryAdapter, AppProcessA
21
21
  bootstrapApp(appName: string): Promise<void>;
22
22
  addApp(app: Application): Application<import("../application").DefaultState, import("../application").DefaultContext>;
23
23
  getApps(): Application<import("../application").DefaultState, import("../application").DefaultContext>[];
24
+ listAppModels(): Promise<any[]>;
24
25
  hasApp(appName: string): boolean;
25
26
  startApp(appName: string): Promise<void>;
26
27
  stopApp(appName: string): Promise<void>;
@@ -78,6 +78,9 @@ const _MainOnlyAdapter = class _MainOnlyAdapter {
78
78
  getApps() {
79
79
  return Object.values(this.apps);
80
80
  }
81
+ async listAppModels() {
82
+ return [];
83
+ }
81
84
  hasApp(appName) {
82
85
  if (appName !== "main") {
83
86
  return false;
@@ -66,6 +66,7 @@ export type AppModel = {
66
66
  environments?: string[];
67
67
  options: AppModelOptions;
68
68
  };
69
+ export type AppManifestValue = unknown;
69
70
  export type AppCondition = {
70
71
  filter?: Record<string, any>;
71
72
  match?: (appModel: AppModel) => boolean;
@@ -115,11 +116,17 @@ export interface AppDiscoveryAdapter {
115
116
  loadAppModels?(mainApp: Application): Promise<void>;
116
117
  getAppsStatuses?(appNames?: string[]): Promise<AppStatusesResult> | AppStatusesResult;
117
118
  getAppsByCondition?(conditionName: string, condition: AppCondition, options?: GetAppsByConditionOptions): Promise<string[]>;
119
+ listAppModels?(): Promise<AppModel[]>;
118
120
  addAppsToCondition?(conditionName: string, environmentName: string, appNames: string[]): Promise<void>;
119
121
  removeAppsFromCondition?(conditionName: string, environmentName: string, appNames: string[]): Promise<void>;
120
122
  addAppModel?(appModel: AppModel): Promise<void>;
121
123
  getAppModel?(appName: string): Promise<AppModel>;
122
124
  removeAppModel?(appName: string): Promise<void>;
125
+ setAppManifestItem?(appName: string, namespace: string, itemKey: string, item: AppManifestValue): Promise<void>;
126
+ removeAppManifestItem?(appName: string, namespace: string, itemKey: string): Promise<void>;
127
+ removeAppManifest?(appName: string, namespace: string): Promise<void>;
128
+ getAppManifestItems?<T = AppManifestValue>(appName: string, namespace: string): Promise<T[]>;
129
+ getAppManifests?<T = AppManifestValue>(namespace: string, appNames: string[]): Promise<Record<string, T[]>>;
123
130
  getAppNameByCName?(cname: string): Promise<string | null>;
124
131
  registerEnvironment?(environment: EnvironmentInfo): Promise<boolean>;
125
132
  unregisterEnvironment?(): Promise<void>;
@@ -944,6 +944,7 @@ const _Application = class _Application extends import_koa.default {
944
944
  }
945
945
  });
946
946
  this._dataSourceManager.use(this._authManager.middleware(), { tag: "auth", before: "default" });
947
+ this._dataSourceManager.use(import_auth.csrfMiddleware, { tag: "csrf", after: "auth", before: "default" });
947
948
  this._dataSourceManager.use(import_validate_filter_params.default, { tag: "validate-filter-params", before: ["auth"] });
948
949
  this._dataSourceManager.use(import_middlewares.parseVariables, {
949
950
  group: "parseVariables",
@@ -53,17 +53,18 @@ export interface EventQueueOptions {
53
53
  export declare class MemoryEventQueueAdapter implements IEventQueueAdapter {
54
54
  private options;
55
55
  private connected;
56
- private emitter;
57
56
  private reading;
57
+ private scheduledChannels;
58
58
  protected events: Map<string, QueueEventOptions>;
59
59
  protected queues: Map<string, {
60
60
  id: string;
61
61
  content: any;
62
62
  options?: QueueMessageOptions;
63
63
  }[]>;
64
- get processing(): Promise<Promise<void>[][]>;
64
+ get processing(): Promise<void[]>;
65
65
  private get storagePath();
66
66
  listen: (channel: string) => void;
67
+ private scheduleListen;
67
68
  constructor(options: {
68
69
  appName: string;
69
70
  logger: SystemLogger;
@@ -46,7 +46,6 @@ __export(event_queue_exports, {
46
46
  });
47
47
  module.exports = __toCommonJS(event_queue_exports);
48
48
  var import_crypto = require("crypto");
49
- var import_events = require("events");
50
49
  var import_path = __toESM(require("path"));
51
50
  var import_promises = __toESM(require("fs/promises"));
52
51
  var import_utils = require("@nocobase/utils");
@@ -56,15 +55,14 @@ const QUEUE_DEFAULT_ACK_TIMEOUT = 15e3;
56
55
  const _MemoryEventQueueAdapter = class _MemoryEventQueueAdapter {
57
56
  constructor(options) {
58
57
  this.options = options;
59
- this.emitter.setMaxListeners(0);
60
58
  }
61
59
  connected = false;
62
- emitter = new import_events.EventEmitter();
63
60
  reading = /* @__PURE__ */ new Map();
61
+ scheduledChannels = /* @__PURE__ */ new Set();
64
62
  events = /* @__PURE__ */ new Map();
65
63
  queues = /* @__PURE__ */ new Map();
66
64
  get processing() {
67
- const processing = Array.from(this.reading.values());
65
+ const processing = Array.from(this.reading.values()).flat();
68
66
  if (processing.length > 0) {
69
67
  return Promise.all(processing);
70
68
  }
@@ -80,7 +78,6 @@ const _MemoryEventQueueAdapter = class _MemoryEventQueueAdapter {
80
78
  const { logger } = this.options;
81
79
  const event = this.events.get(channel);
82
80
  if (!event) {
83
- logger.warn(`memory queue (${channel}) not found, skipping...`);
84
81
  return;
85
82
  }
86
83
  if (!event.idle()) {
@@ -99,10 +96,24 @@ const _MemoryEventQueueAdapter = class _MemoryEventQueueAdapter {
99
96
  if (index > -1) {
100
97
  reading.splice(index, 1);
101
98
  }
99
+ this.scheduleListen(channel);
102
100
  });
103
101
  });
104
102
  this.reading.set(channel, reading);
105
103
  }, "listen");
104
+ scheduleListen(channel) {
105
+ if (this.scheduledChannels.has(channel)) {
106
+ return;
107
+ }
108
+ this.scheduledChannels.add(channel);
109
+ setImmediate(() => {
110
+ this.scheduledChannels.delete(channel);
111
+ if (!this.events.has(channel)) {
112
+ return;
113
+ }
114
+ this.listen(channel);
115
+ });
116
+ }
106
117
  isConnected() {
107
118
  return this.connected;
108
119
  }
@@ -181,7 +192,6 @@ const _MemoryEventQueueAdapter = class _MemoryEventQueueAdapter {
181
192
  if (!this.queues.has(channel)) {
182
193
  this.queues.set(channel, []);
183
194
  }
184
- this.emitter.on(channel, this.listen);
185
195
  if (this.connected) {
186
196
  this.consume(channel);
187
197
  }
@@ -191,12 +201,12 @@ const _MemoryEventQueueAdapter = class _MemoryEventQueueAdapter {
191
201
  return;
192
202
  }
193
203
  this.events.delete(channel);
194
- this.emitter.off(channel, this.listen);
195
204
  }
196
205
  publish(channel, content, options = { timestamp: Date.now() }) {
206
+ const { logger } = this.options;
197
207
  const event = this.events.get(channel);
198
208
  if (!event) {
199
- console.debug(`memory queue (${channel}) not subscribed, skip`);
209
+ logger.debug(`memory queue (${channel}) not subscribed, skip`);
200
210
  return;
201
211
  }
202
212
  if (!this.queues.get(channel)) {
@@ -205,11 +215,8 @@ const _MemoryEventQueueAdapter = class _MemoryEventQueueAdapter {
205
215
  const queue = this.queues.get(channel);
206
216
  const message = { id: (0, import_crypto.randomUUID)(), content, options };
207
217
  queue.push(message);
208
- const { logger } = this.options;
209
218
  logger.debug(`memory queue (${channel}) published message`, content);
210
- setImmediate(() => {
211
- this.emitter.emit(channel, channel);
212
- });
219
+ this.scheduleListen(channel);
213
220
  }
214
221
  async consume(channel, once = false) {
215
222
  while (this.connected && this.events.get(channel)) {
@@ -80,6 +80,11 @@ export declare class Gateway extends EventEmitter {
80
80
  responseErrorWithCode(code: any, res: any, options: any): void;
81
81
  private getV2PublicPath;
82
82
  private getAppPublicPath;
83
+ private getPortalRootPublicPath;
84
+ private getPortalAppPublicPath;
85
+ private getPortalMatch;
86
+ private isPortalIndexRequest;
87
+ private getPortalDistRoot;
83
88
  private isV2Request;
84
89
  private isV2IndexRequest;
85
90
  private getV2RuntimeConfig;
@@ -78,6 +78,17 @@ function normalizeBasePath(path = "") {
78
78
  return normalized || "/";
79
79
  }
80
80
  __name(normalizeBasePath, "normalizeBasePath");
81
+ function getFilesPathPrefixes(appPublicPath = "/") {
82
+ const normalizedPublicPath = normalizeBasePath(appPublicPath);
83
+ const canonicalPrefix = `${normalizedPublicPath === "/" ? "" : normalizedPublicPath}/files/`;
84
+ return canonicalPrefix === "/files/" ? ["/files/"] : [canonicalPrefix, "/files/"];
85
+ }
86
+ __name(getFilesPathPrefixes, "getFilesPathPrefixes");
87
+ function getFileAccessRestPath(pathname, appPublicPath = "/") {
88
+ const prefix = getFilesPathPrefixes(appPublicPath).find((prefix2) => pathname.startsWith(prefix2));
89
+ return prefix ? pathname.slice(prefix.length) : null;
90
+ }
91
+ __name(getFileAccessRestPath, "getFileAccessRestPath");
81
92
  function getSocketPath() {
82
93
  const socketPath = import_node_process.default.env.SOCKET_PATH;
83
94
  if (socketPath) {
@@ -177,19 +188,28 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
177
188
  this.selectorMiddlewares = new import_utils.Toposort();
178
189
  this.addAppSelectorMiddleware(
179
190
  async (ctx, next) => {
180
- var _a, _b;
191
+ var _a, _b, _c;
181
192
  const { req } = ctx;
182
193
  const parsedUrl = (0, import_url.parse)(req.url);
183
194
  const appName = (_a = import_qs.default.parse(parsedUrl.query)) == null ? void 0 : _a.__appName;
184
195
  const apiBasePath = normalizeBasePath(import_node_process.default.env.API_BASE_PATH || "/api");
185
196
  const appPathPrefix = `${apiBasePath}/__app/`;
197
+ const appPublicPath = (0, import_utils3.resolvePublicPath)(import_node_process.default.env.APP_PUBLIC_PATH || "/");
198
+ const portalAppsPathPrefix = `${appPublicPath.replace(/\/$/, "")}/${import_utils3.PORTAL_CLIENT_PREFIX}/apps/`;
186
199
  if (req.headers["x-app"]) {
187
200
  ctx.resolvedAppName = req.headers["x-app"];
188
201
  }
189
202
  if (appName) {
190
203
  ctx.resolvedAppName = appName;
191
204
  }
192
- if ((_b = parsedUrl.pathname) == null ? void 0 : _b.startsWith(appPathPrefix)) {
205
+ if ((_b = parsedUrl.pathname) == null ? void 0 : _b.startsWith(portalAppsPathPrefix)) {
206
+ const restPath = parsedUrl.pathname.slice(portalAppsPathPrefix.length);
207
+ const [pathAppName] = restPath.split("/");
208
+ if (pathAppName) {
209
+ ctx.resolvedAppName = (0, import_utils3.normalizePortalAppName)(pathAppName);
210
+ }
211
+ }
212
+ if ((_c = parsedUrl.pathname) == null ? void 0 : _c.startsWith(appPathPrefix)) {
193
213
  const restPath = parsedUrl.pathname.slice(appPathPrefix.length);
194
214
  const [pathAppName, ...segments] = restPath.split("/");
195
215
  if (pathAppName) {
@@ -202,6 +222,17 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
202
222
  req.url = rewrittenUrl;
203
223
  }
204
224
  }
225
+ const fileAccessRestPath = parsedUrl.pathname ? getFileAccessRestPath(parsedUrl.pathname, import_node_process.default.env.APP_PUBLIC_PATH || "/") : null;
226
+ if (fileAccessRestPath) {
227
+ const restPath = fileAccessRestPath;
228
+ const [pathAppName] = restPath.split("/");
229
+ if (pathAppName) {
230
+ try {
231
+ ctx.resolvedAppName = decodeURIComponent(pathAppName);
232
+ } catch (error) {
233
+ }
234
+ }
235
+ }
205
236
  await next();
206
237
  },
207
238
  {
@@ -270,6 +301,62 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
270
301
  getAppPublicPath() {
271
302
  return (0, import_utils3.resolvePublicPath)(import_node_process.default.env.APP_PUBLIC_PATH || "/");
272
303
  }
304
+ getPortalRootPublicPath() {
305
+ return `${this.getAppPublicPath().replace(/\/$/, "")}/${import_utils3.PORTAL_CLIENT_PREFIX}/`;
306
+ }
307
+ getPortalAppPublicPath(appName) {
308
+ if (appName === import_utils3.DEFAULT_PORTAL_APP_NAME) {
309
+ return this.getPortalRootPublicPath();
310
+ }
311
+ return `${this.getPortalRootPublicPath()}apps/${(0, import_utils3.normalizePortalAppName)(appName)}/`;
312
+ }
313
+ getPortalMatch(pathname) {
314
+ const portalRootPublicPath = this.getPortalRootPublicPath();
315
+ if (!pathname.startsWith(portalRootPublicPath)) {
316
+ return null;
317
+ }
318
+ let appName = import_utils3.DEFAULT_PORTAL_APP_NAME;
319
+ let publicRoot = portalRootPublicPath;
320
+ let restPath = pathname.slice(portalRootPublicPath.length).replace(/^\/+/, "");
321
+ const [firstSegment, secondSegment, ...remainingSegments] = restPath.split("/");
322
+ if (firstSegment === "apps") {
323
+ if (!secondSegment || !/^[A-Za-z0-9_-]+$/.test(secondSegment)) {
324
+ return null;
325
+ }
326
+ appName = (0, import_utils3.normalizePortalAppName)(secondSegment);
327
+ publicRoot = this.getPortalAppPublicPath(appName);
328
+ if (!pathname.startsWith(publicRoot)) {
329
+ return null;
330
+ }
331
+ restPath = remainingSegments.join("/").replace(/^\/+/, "");
332
+ }
333
+ const [portalName] = restPath.split("/");
334
+ if (!portalName || !/^[A-Za-z0-9_-]+$/.test(portalName)) {
335
+ return null;
336
+ }
337
+ return {
338
+ appName,
339
+ portalName,
340
+ publicPath: `${publicRoot}${portalName}/`
341
+ };
342
+ }
343
+ isPortalIndexRequest(pathname, portalPublicPath) {
344
+ if (pathname === portalPublicPath || pathname === portalPublicPath.slice(0, -1) || pathname === `${portalPublicPath}index.html`) {
345
+ return true;
346
+ }
347
+ return !(0, import_path.extname)(pathname);
348
+ }
349
+ getPortalDistRoot(portalMatch) {
350
+ const scopedRoot = (0, import_utils.storagePathJoin)("portals", portalMatch.appName, portalMatch.portalName, "dist");
351
+ if (portalMatch.appName !== import_utils3.DEFAULT_PORTAL_APP_NAME) {
352
+ return scopedRoot;
353
+ }
354
+ const legacyRoot = (0, import_utils.storagePathJoin)("portals", portalMatch.portalName, "dist");
355
+ if (!import_fs.default.existsSync((0, import_path.resolve)(scopedRoot, "index.html")) && import_fs.default.existsSync((0, import_path.resolve)(legacyRoot, "index.html"))) {
356
+ return legacyRoot;
357
+ }
358
+ return scopedRoot;
359
+ }
273
360
  isV2Request(pathname) {
274
361
  const v2PublicPath = this.getV2PublicPath();
275
362
  return pathname === v2PublicPath.slice(0, -1) || pathname.startsWith(v2PublicPath);
@@ -337,7 +424,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
337
424
  return (0, import_utils3.injectRuntimeScript)(html, this.getV2RuntimeConfigScript());
338
425
  }
339
426
  async requestHandler(req, res) {
340
- const { pathname } = (0, import_url.parse)(req.url);
427
+ const { pathname, search } = (0, import_url.parse)(req.url);
341
428
  const { PLUGIN_STATICS_PATH } = import_node_process.default.env;
342
429
  const APP_PUBLIC_PATH = this.getAppPublicPath();
343
430
  if (pathname.endsWith("/__umi/api/bundle-status")) {
@@ -345,6 +432,12 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
345
432
  res.end("ok");
346
433
  return;
347
434
  }
435
+ if (APP_PUBLIC_PATH !== "/" && pathname.startsWith("/files/")) {
436
+ res.statusCode = 302;
437
+ res.setHeader("Location", `${APP_PUBLIC_PATH.replace(/\/$/, "")}${pathname}${search || ""}`);
438
+ res.end();
439
+ return;
440
+ }
348
441
  const supervisor = import_app_supervisor.AppSupervisor.getInstance();
349
442
  let handleApp = "main";
350
443
  try {
@@ -361,15 +454,18 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
361
454
  return;
362
455
  }
363
456
  }
364
- const headers = (0, import_static_file_security.getStorageUploadSecurityHeaders)(pathname);
365
- for (const [key, value] of Object.entries(headers)) {
366
- res.setHeader(key, value);
367
- }
457
+ const headers = (0, import_static_file_security.getStorageUploadSecurityHeaders)(`${pathname}${search || ""}`);
368
458
  req.url = req.url.substring(APP_PUBLIC_PATH.length + "storage".length);
369
459
  await compress(req, res);
370
460
  return (0, import_serve_handler.default)(req, res, {
371
461
  public: (0, import_utils.resolveStorageRoot)(),
372
- directoryListing: false
462
+ directoryListing: false,
463
+ headers: [
464
+ {
465
+ source: "**/*",
466
+ headers: Object.entries(headers).map(([key, value]) => ({ key, value }))
467
+ }
468
+ ]
373
469
  });
374
470
  }
375
471
  if (pathname.startsWith(APP_PUBLIC_PATH + "dist/")) {
@@ -407,7 +503,47 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
407
503
  ]
408
504
  });
409
505
  }
410
- if (!pathname.startsWith(import_node_process.default.env.API_BASE_PATH)) {
506
+ const isFilesRequest = Boolean(getFileAccessRestPath(pathname, APP_PUBLIC_PATH));
507
+ if (!pathname.startsWith(import_node_process.default.env.API_BASE_PATH) && !isFilesRequest) {
508
+ const portalMatch = this.getPortalMatch(pathname);
509
+ if (portalMatch) {
510
+ if (handleApp !== "main" && handleApp !== portalMatch.appName) {
511
+ const isProxy = await this.proxyRequestToSubApp(supervisor, handleApp, req, res);
512
+ if (isProxy) {
513
+ return;
514
+ }
515
+ }
516
+ if (!pathname.startsWith(portalMatch.publicPath)) {
517
+ res.statusCode = 302;
518
+ res.setHeader("Location", `${portalMatch.publicPath}${search || ""}`);
519
+ res.end();
520
+ return;
521
+ }
522
+ const portalDistRoot = this.getPortalDistRoot(portalMatch);
523
+ const portalIndex = (0, import_path.resolve)(portalDistRoot, "index.html");
524
+ if (!import_fs.default.existsSync(portalIndex)) {
525
+ res.statusCode = 404;
526
+ res.end();
527
+ return;
528
+ }
529
+ if (this.isPortalIndexRequest(pathname, portalMatch.publicPath)) {
530
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
531
+ res.end(import_fs.default.readFileSync(portalIndex, "utf-8"));
532
+ return;
533
+ }
534
+ req.url = req.url.substring(portalMatch.publicPath.length - 1);
535
+ await compress(req, res);
536
+ return (0, import_serve_handler.default)(req, res, {
537
+ public: portalDistRoot,
538
+ directoryListing: false
539
+ });
540
+ }
541
+ const portalRootPublicPath = this.getPortalRootPublicPath();
542
+ if (pathname === portalRootPublicPath.slice(0, -1) || pathname.startsWith(portalRootPublicPath)) {
543
+ res.statusCode = 404;
544
+ res.end();
545
+ return;
546
+ }
411
547
  if (this.isV2Request(pathname)) {
412
548
  if (handleApp !== "main") {
413
549
  const isProxy = await this.proxyRequestToSubApp(supervisor, handleApp, req, res);
@@ -42,11 +42,31 @@ __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", ".pdf", ".svg", ".svgz", ".xhtml"]);
45
+ const ACTIVE_CONTENT_EXTENSIONS = /* @__PURE__ */ new Set([
46
+ ".htm",
47
+ ".html",
48
+ ".pdf",
49
+ ".svg",
50
+ ".svgz",
51
+ ".xht",
52
+ ".xhtml",
53
+ ".xml",
54
+ ".xsl",
55
+ ".xslt"
56
+ ]);
46
57
  function stripQueryAndHash(pathname = "") {
47
58
  return pathname.split("?")[0].split("#")[0];
48
59
  }
49
60
  __name(stripQueryAndHash, "stripQueryAndHash");
61
+ function shouldDownload(pathname = "") {
62
+ var _a;
63
+ const query = (_a = pathname.split("?")[1]) == null ? void 0 : _a.split("#")[0];
64
+ if (!query) {
65
+ return false;
66
+ }
67
+ return new URLSearchParams(query).get("download") === "1";
68
+ }
69
+ __name(shouldDownload, "shouldDownload");
50
70
  function hasActiveContentExtension(pathname = "") {
51
71
  const ext = import_node_path.default.extname(stripQueryAndHash(pathname)).toLowerCase();
52
72
  return ACTIVE_CONTENT_EXTENSIONS.has(ext);
@@ -54,9 +74,10 @@ function hasActiveContentExtension(pathname = "") {
54
74
  __name(hasActiveContentExtension, "hasActiveContentExtension");
55
75
  function getStorageUploadSecurityHeaders(pathname = "") {
56
76
  const headers = {
77
+ "Content-Security-Policy": "sandbox",
57
78
  "X-Content-Type-Options": "nosniff"
58
79
  };
59
- if (hasActiveContentExtension(pathname)) {
80
+ if (hasActiveContentExtension(pathname) || shouldDownload(pathname)) {
60
81
  headers["Content-Disposition"] = "attachment";
61
82
  }
62
83
  return headers;
@@ -10,9 +10,15 @@
10
10
  import { IncomingMessage } from 'http';
11
11
  import { IncomingRequest } from '.';
12
12
  export declare const MODERN_CLIENT_DIST_DIR = "v";
13
+ export declare const PORTAL_CLIENT_PREFIX = "x";
14
+ export declare const DEFAULT_PORTAL_APP_NAME = "main";
15
+ export declare const DEFAULT_PORTAL_NAME = "admin";
13
16
  export declare function resolvePublicPath(appPublicPath?: string): string;
14
17
  export declare function normalizeModernClientPrefix(value?: string): string;
15
18
  export declare function resolveV2PublicPath(appPublicPath?: string): string;
19
+ export declare function normalizePortalName(value?: string): string;
20
+ export declare function normalizePortalAppName(value?: string): string;
21
+ export declare function resolvePortalPublicPath(portalName: string, appPublicPath?: string): string;
16
22
  export declare function rewriteV2AssetPublicPath(html: string, assetPublicPath: string): string;
17
23
  export declare function injectRuntimeScript(html: string, runtimeScript: string): string;
18
24
  export declare function getHost(req: IncomingMessage | IncomingRequest): any;
@@ -27,17 +27,26 @@ 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
+ DEFAULT_PORTAL_APP_NAME: () => DEFAULT_PORTAL_APP_NAME,
31
+ DEFAULT_PORTAL_NAME: () => DEFAULT_PORTAL_NAME,
30
32
  MODERN_CLIENT_DIST_DIR: () => MODERN_CLIENT_DIST_DIR,
33
+ PORTAL_CLIENT_PREFIX: () => PORTAL_CLIENT_PREFIX,
31
34
  getHost: () => getHost,
32
35
  getHostname: () => getHostname,
33
36
  injectRuntimeScript: () => injectRuntimeScript,
34
37
  normalizeModernClientPrefix: () => normalizeModernClientPrefix,
38
+ normalizePortalAppName: () => normalizePortalAppName,
39
+ normalizePortalName: () => normalizePortalName,
40
+ resolvePortalPublicPath: () => resolvePortalPublicPath,
35
41
  resolvePublicPath: () => resolvePublicPath,
36
42
  resolveV2PublicPath: () => resolveV2PublicPath,
37
43
  rewriteV2AssetPublicPath: () => rewriteV2AssetPublicPath
38
44
  });
39
45
  module.exports = __toCommonJS(utils_exports);
40
46
  const MODERN_CLIENT_DIST_DIR = "v";
47
+ const PORTAL_CLIENT_PREFIX = "x";
48
+ const DEFAULT_PORTAL_APP_NAME = "main";
49
+ const DEFAULT_PORTAL_NAME = "admin";
41
50
  function resolvePublicPath(appPublicPath = "/") {
42
51
  const normalized = String(appPublicPath || "/").trim() || "/";
43
52
  const withLeadingSlash = normalized.startsWith("/") ? normalized : `/${normalized}`;
@@ -55,6 +64,21 @@ function resolveV2PublicPath(appPublicPath = "/") {
55
64
  return `${publicPath.replace(/\/$/, "")}/${prefix}/`;
56
65
  }
57
66
  __name(resolveV2PublicPath, "resolveV2PublicPath");
67
+ function normalizePortalName(value) {
68
+ const segment = String(value || "").trim().replace(/^\/+|\/+$/g, "");
69
+ return segment || DEFAULT_PORTAL_NAME;
70
+ }
71
+ __name(normalizePortalName, "normalizePortalName");
72
+ function normalizePortalAppName(value) {
73
+ const segment = String(value || "").trim().replace(/^\/+|\/+$/g, "");
74
+ return segment || DEFAULT_PORTAL_APP_NAME;
75
+ }
76
+ __name(normalizePortalAppName, "normalizePortalAppName");
77
+ function resolvePortalPublicPath(portalName, appPublicPath = "/") {
78
+ const publicPath = resolvePublicPath(appPublicPath);
79
+ return `${publicPath.replace(/\/$/, "")}/${PORTAL_CLIENT_PREFIX}/${normalizePortalName(portalName)}/`;
80
+ }
81
+ __name(resolvePortalPublicPath, "resolvePortalPublicPath");
58
82
  function ensureTrailingSlash(value) {
59
83
  return value.endsWith("/") ? value : `${value}/`;
60
84
  }
@@ -117,11 +141,17 @@ function getHostname(req) {
117
141
  __name(getHostname, "getHostname");
118
142
  // Annotate the CommonJS export names for ESM import in node:
119
143
  0 && (module.exports = {
144
+ DEFAULT_PORTAL_APP_NAME,
145
+ DEFAULT_PORTAL_NAME,
120
146
  MODERN_CLIENT_DIST_DIR,
147
+ PORTAL_CLIENT_PREFIX,
121
148
  getHost,
122
149
  getHostname,
123
150
  injectRuntimeScript,
124
151
  normalizeModernClientPrefix,
152
+ normalizePortalAppName,
153
+ normalizePortalName,
154
+ resolvePortalPublicPath,
125
155
  resolvePublicPath,
126
156
  resolveV2PublicPath,
127
157
  rewriteV2AssetPublicPath
package/lib/helper.d.ts CHANGED
@@ -11,6 +11,7 @@ import { Command } from 'commander';
11
11
  import Application, { ApplicationOptions } from './application';
12
12
  export declare function createI18n(options: ApplicationOptions): import("i18next").i18n;
13
13
  export declare function createResourcer(options: ApplicationOptions): Resourcer;
14
+ export declare function resolveCorsOrigin(ctx: any): any;
14
15
  export declare function registerMiddlewares(app: Application, options: ApplicationOptions): void;
15
16
  export declare const createAppProxy: (app: Application) => Application<import("./application").DefaultState, import("./application").DefaultContext>;
16
17
  export declare const getCommandFullName: (command: Command) => string;
package/lib/helper.js CHANGED
@@ -45,6 +45,7 @@ __export(helper_exports, {
45
45
  getBodyLimit: () => getBodyLimit,
46
46
  getCommandFullName: () => getCommandFullName,
47
47
  registerMiddlewares: () => registerMiddlewares,
48
+ resolveCorsOrigin: () => resolveCorsOrigin,
48
49
  tsxRerunning: () => tsxRerunning
49
50
  });
50
51
  module.exports = __toCommonJS(helper_exports);
@@ -76,23 +77,25 @@ function createResourcer(options) {
76
77
  return new import_resourcer.Resourcer({ ...options.resourcer });
77
78
  }
78
79
  __name(createResourcer, "createResourcer");
80
+ function isWhitelistedCorsOrigin(ctx) {
81
+ const origin = ctx.get("origin");
82
+ if (!origin) {
83
+ return false;
84
+ }
85
+ return (0, import_utils.isTrustedOrigin)(ctx, origin);
86
+ }
87
+ __name(isWhitelistedCorsOrigin, "isWhitelistedCorsOrigin");
79
88
  function resolveCorsOrigin(ctx) {
80
89
  const origin = ctx.get("origin");
81
90
  const disallowNoOrigin = process.env.CORS_DISALLOW_NO_ORIGIN === "true";
82
- const whitelistString = process.env.CORS_ORIGIN_WHITELIST;
91
+ const whitelist = (0, import_utils.getCorsWhitelist)();
83
92
  if (!origin && disallowNoOrigin) {
84
93
  return false;
85
94
  }
86
- if (!whitelistString) {
95
+ if (isWhitelistedCorsOrigin(ctx)) {
87
96
  return origin;
88
97
  }
89
- const whitelist = new Set(
90
- whitelistString.split(",").map((item) => item.trim()).filter(Boolean)
91
- );
92
- if (whitelist.has(origin)) {
93
- return origin;
94
- }
95
- return false;
98
+ return whitelist ? false : origin;
96
99
  }
97
100
  __name(resolveCorsOrigin, "resolveCorsOrigin");
98
101
  function registerMiddlewares(app, options) {
@@ -108,6 +111,7 @@ function registerMiddlewares(app, options) {
108
111
  app.use((0, import_logger.requestLogger)(app.name, app.requestLogger, (_a = options.logger) == null ? void 0 : _a.request), { tag: "logger" });
109
112
  app.use(
110
113
  (0, import_cors.default)({
114
+ credentials: isWhitelistedCorsOrigin,
111
115
  exposeHeaders: ["content-disposition"],
112
116
  origin: resolveCorsOrigin,
113
117
  ...options.cors
@@ -134,8 +138,18 @@ function registerMiddlewares(app, options) {
134
138
  }
135
139
  app.use(/* @__PURE__ */ __name(async function getBearerToken(ctx, next) {
136
140
  ctx.getBearerToken = () => {
137
- const token = ctx.get("Authorization").replace(/^Bearer\s+/gi, "");
138
- return token || ctx.query.token;
141
+ const authorization = ctx.get("Authorization");
142
+ if (authorization) {
143
+ ctx.state.pendingAuthTokenSource = "authorization";
144
+ return authorization.replace(/^Bearer\s+/gi, "");
145
+ }
146
+ if (ctx.query.token) {
147
+ ctx.state.pendingAuthTokenSource = "query";
148
+ return ctx.query.token;
149
+ }
150
+ const cookieToken = ctx.cookies.get((0, import_utils.getAuthCookieName)("authToken", app.name));
151
+ ctx.state.pendingAuthTokenSource = cookieToken ? "cookie" : void 0;
152
+ return cookieToken;
139
153
  };
140
154
  await next();
141
155
  }, "getBearerToken"));
@@ -309,5 +323,6 @@ __name(createContextVariablesScope, "createContextVariablesScope");
309
323
  getBodyLimit,
310
324
  getCommandFullName,
311
325
  registerMiddlewares,
326
+ resolveCorsOrigin,
312
327
  tsxRerunning
313
328
  });
package/lib/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export * from './gateway/ws-server';
13
13
  export { Application as default } from './application';
14
14
  export * from './audit-manager';
15
15
  export * from './gateway';
16
+ export * from './gateway/static-file-security';
16
17
  export * as middlewares from './middlewares';
17
18
  export * from './migration';
18
19
  export * from './plugin';
package/lib/index.js CHANGED
@@ -55,6 +55,7 @@ __reExport(src_exports, require("./gateway/ws-server"), module.exports);
55
55
  var import_application = require("./application");
56
56
  __reExport(src_exports, require("./audit-manager"), module.exports);
57
57
  __reExport(src_exports, require("./gateway"), module.exports);
58
+ __reExport(src_exports, require("./gateway/static-file-security"), module.exports);
58
59
  var middlewares = __toESM(require("./middlewares"));
59
60
  __reExport(src_exports, require("./migration"), module.exports);
60
61
  __reExport(src_exports, require("./plugin"), module.exports);
@@ -85,6 +86,7 @@ var import_helper = require("./helper");
85
86
  ...require("./gateway/ws-server"),
86
87
  ...require("./audit-manager"),
87
88
  ...require("./gateway"),
89
+ ...require("./gateway/static-file-security"),
88
90
  ...require("./migration"),
89
91
  ...require("./plugin"),
90
92
  ...require("./plugin-manager"),
@@ -47,7 +47,7 @@ const deps = {
47
47
  koa: "3.x",
48
48
  "@koa/cors": "5.x",
49
49
  "@koa/router": "13.x",
50
- multer: "1.x",
50
+ multer: "2.x",
51
51
  "@koa/multer": "3.x",
52
52
  "koa-bodyparser": "4.x",
53
53
  "koa-static": "5.x",
@@ -62,6 +62,7 @@ async function trim(packageNames) {
62
62
  }
63
63
  __name(trim, "trim");
64
64
  const excludes = [
65
+ "external-db-data-source",
65
66
  "@nocobase/plugin-audit-logs",
66
67
  "@nocobase/plugin-backup-restore",
67
68
  "@nocobase/plugin-charts",
@@ -302,12 +302,19 @@ var resource_default = {
302
302
  if (!keys.length) {
303
303
  ctx.throw(400, "plugin name invalid");
304
304
  }
305
+ for (const key of keys) {
306
+ try {
307
+ (0, import_utils2.assertSafePluginPackageName)(key);
308
+ } catch (error) {
309
+ ctx.throw(400, "plugin name invalid");
310
+ }
311
+ }
305
312
  const awaitResponse = coerceAwaitResponse(awaitResponseRaw);
306
313
  const argv = ["pm", "enable", ...keys];
307
314
  if (awaitResponse) {
308
315
  await app.runAsCLI(argv, { from: "user", throwError: true });
309
316
  } else {
310
- void app.runAsCLI(argv, { from: "user" }).catch((err) => {
317
+ app.runAsCLI(argv, { from: "user" }).catch((err) => {
311
318
  app.log.error(err);
312
319
  });
313
320
  }
@@ -326,7 +333,7 @@ var resource_default = {
326
333
  if (awaitResponse) {
327
334
  await app.runAsCLI(argv, { from: "user", throwError: true });
328
335
  } else {
329
- void app.runAsCLI(argv, { from: "user" }).catch((err) => {
336
+ app.runAsCLI(argv, { from: "user" }).catch((err) => {
330
337
  app.log.error(err);
331
338
  });
332
339
  }
@@ -344,7 +351,7 @@ var resource_default = {
344
351
  await next();
345
352
  },
346
353
  async list(ctx, next) {
347
- const { mode } = ctx.action.params;
354
+ const { mode, v2 } = ctx.action.params;
348
355
  if (mode === "summary") {
349
356
  ctx.body = await (0, import_utils2.pmListSummary)(ctx.app);
350
357
  return next();
@@ -352,7 +359,18 @@ var resource_default = {
352
359
  const locale = ctx.getCurrentLocale();
353
360
  const pm = ctx.app.pm;
354
361
  const plugin = pm.get("nocobase");
355
- ctx.body = await plugin.getAllPlugins(locale);
362
+ const plugins = await plugin.getAllPlugins(locale);
363
+ ctx.body = plugins.filter((item) => {
364
+ var _a;
365
+ if (process.env.NOCOBASE_SHOW_DEPRECATED_PLUGINS === "true") {
366
+ return true;
367
+ }
368
+ if (!v2) {
369
+ return true;
370
+ }
371
+ const nocobaseConfig = ((_a = item == null ? void 0 : item.packageJson) == null ? void 0 : _a.nocobase) || {};
372
+ return nocobaseConfig.internal !== true && nocobaseConfig.deprecated !== true;
373
+ });
356
374
  await next();
357
375
  },
358
376
  async listEnabled(ctx, next) {
@@ -233,6 +233,7 @@ const _PluginManager = class _PluginManager {
233
233
  }
234
234
  }
235
235
  static async parseName(nameOrPkg) {
236
+ (0, import_utils2.assertSafePluginPackageName)(nameOrPkg);
236
237
  if (this.parsedNames[nameOrPkg]) {
237
238
  return this.parsedNames[nameOrPkg];
238
239
  }
package/lib/plugin.js CHANGED
@@ -276,7 +276,7 @@ const _Plugin = class _Plugin {
276
276
  "fr-FR": "fr/"
277
277
  };
278
278
  if (packageName.startsWith("@nocobase/plugin-")) {
279
- packageJson.homepage = `https://v2.docs.nocobase.com/${langMap[locale] || ""}plugins/${packageName}`;
279
+ packageJson.homepage = `https://docs.nocobase.com/${langMap[locale] || ""}plugins/${packageName}`;
280
280
  }
281
281
  const results = {
282
282
  ...this.options,
@@ -12,7 +12,23 @@ declare const _default: {
12
12
  readonly tags: readonly ["app"];
13
13
  readonly summary: "Get the current application language";
14
14
  readonly description: "Return the current locale used by the server.";
15
- readonly parameters: readonly [];
15
+ readonly parameters: readonly [{
16
+ readonly name: "locale";
17
+ readonly in: "query";
18
+ readonly required: false;
19
+ readonly schema: {
20
+ readonly type: "string";
21
+ };
22
+ readonly description: "Requested application locale. The server validates it against enabled languages.";
23
+ }, {
24
+ readonly name: "ns";
25
+ readonly in: "query";
26
+ readonly required: false;
27
+ readonly schema: {
28
+ readonly type: "string";
29
+ };
30
+ readonly description: "Comma-separated resource namespaces to return. Omit it to preserve the full legacy payload.";
31
+ }];
16
32
  readonly responses: {
17
33
  readonly 200: {
18
34
  readonly description: "OK";
@@ -35,7 +35,22 @@ var app_default = {
35
35
  tags: ["app"],
36
36
  summary: "Get the current application language",
37
37
  description: "Return the current locale used by the server.",
38
- parameters: [],
38
+ parameters: [
39
+ {
40
+ name: "locale",
41
+ in: "query",
42
+ required: false,
43
+ schema: { type: "string" },
44
+ description: "Requested application locale. The server validates it against enabled languages."
45
+ },
46
+ {
47
+ name: "ns",
48
+ in: "query",
49
+ required: false,
50
+ schema: { type: "string" },
51
+ description: "Comma-separated resource namespaces to return. Omit it to preserve the full legacy payload."
52
+ }
53
+ ],
39
54
  responses: {
40
55
  200: {
41
56
  description: "OK",
@@ -694,7 +694,23 @@ declare const _default: {
694
694
  readonly tags: readonly ["app"];
695
695
  readonly summary: "Get the current application language";
696
696
  readonly description: "Return the current locale used by the server.";
697
- readonly parameters: readonly [];
697
+ readonly parameters: readonly [{
698
+ readonly name: "locale";
699
+ readonly in: "query";
700
+ readonly required: false;
701
+ readonly schema: {
702
+ readonly type: "string";
703
+ };
704
+ readonly description: "Requested application locale. The server validates it against enabled languages.";
705
+ }, {
706
+ readonly name: "ns";
707
+ readonly in: "query";
708
+ readonly required: false;
709
+ readonly schema: {
710
+ readonly type: "string";
711
+ };
712
+ readonly description: "Comma-separated resource namespaces to return. Omit it to preserve the full legacy payload.";
713
+ }];
698
714
  readonly responses: {
699
715
  readonly 200: {
700
716
  readonly description: "OK";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/server",
3
- "version": "2.2.0-alpha.1",
3
+ "version": "2.2.0-alpha.11",
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.2.0-alpha.1",
14
- "@nocobase/actions": "2.2.0-alpha.1",
15
- "@nocobase/ai": "2.2.0-alpha.1",
16
- "@nocobase/auth": "2.2.0-alpha.1",
17
- "@nocobase/cache": "2.2.0-alpha.1",
18
- "@nocobase/data-source-manager": "2.2.0-alpha.1",
19
- "@nocobase/database": "2.2.0-alpha.1",
20
- "@nocobase/evaluators": "2.2.0-alpha.1",
21
- "@nocobase/lock-manager": "2.2.0-alpha.1",
22
- "@nocobase/logger": "2.2.0-alpha.1",
23
- "@nocobase/resourcer": "2.2.0-alpha.1",
24
- "@nocobase/sdk": "2.2.0-alpha.1",
25
- "@nocobase/snowflake-id": "2.2.0-alpha.1",
26
- "@nocobase/telemetry": "2.2.0-alpha.1",
27
- "@nocobase/utils": "2.2.0-alpha.1",
13
+ "@nocobase/acl": "2.2.0-alpha.11",
14
+ "@nocobase/actions": "2.2.0-alpha.11",
15
+ "@nocobase/ai": "2.2.0-alpha.11",
16
+ "@nocobase/auth": "2.2.0-alpha.11",
17
+ "@nocobase/cache": "2.2.0-alpha.11",
18
+ "@nocobase/data-source-manager": "2.2.0-alpha.11",
19
+ "@nocobase/database": "2.2.0-alpha.11",
20
+ "@nocobase/evaluators": "2.2.0-alpha.11",
21
+ "@nocobase/lock-manager": "2.2.0-alpha.11",
22
+ "@nocobase/logger": "2.2.0-alpha.11",
23
+ "@nocobase/resourcer": "2.2.0-alpha.11",
24
+ "@nocobase/sdk": "2.2.0-alpha.11",
25
+ "@nocobase/snowflake-id": "2.2.0-alpha.11",
26
+ "@nocobase/telemetry": "2.2.0-alpha.11",
27
+ "@nocobase/utils": "2.2.0-alpha.11",
28
28
  "@types/decompress": "4.2.7",
29
29
  "@types/ini": "^1.3.31",
30
30
  "@types/koa-send": "^4.1.3",
@@ -47,7 +47,7 @@
47
47
  "koa-send": "^5.0.1",
48
48
  "koa-static": "^5.0.0",
49
49
  "lodash": "^4.17.21",
50
- "multer": "^1.4.5-lts.2",
50
+ "multer": "^2.1.1",
51
51
  "nanoid": "^3.3.11",
52
52
  "p-queue": "^6.6.2",
53
53
  "redis": "^5.10.0",
@@ -61,5 +61,5 @@
61
61
  "@types/serve-handler": "^6.1.1",
62
62
  "@types/ws": "^8.5.5"
63
63
  },
64
- "gitHead": "303663aba6c6eefa27e6a6435b4c0352074ec40f"
64
+ "gitHead": "c9ff1f51e5c33bc6437b64eb779212be71b78f58"
65
65
  }