@nocobase/server 2.2.0-beta.9 → 3.0.0-alpha.1
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.
- package/lib/app-supervisor/index.d.ts +3 -0
- package/lib/app-supervisor/index.js +30 -12
- package/lib/app-supervisor/main-only-adapter.d.ts +0 -8
- package/lib/app-supervisor/main-only-adapter.js +0 -39
- package/lib/application.js +1 -0
- package/lib/event-queue.d.ts +3 -2
- package/lib/event-queue.js +19 -12
- package/lib/gateway/index.d.ts +17 -0
- package/lib/gateway/index.js +312 -9
- package/lib/gateway/static-file-security.js +23 -2
- package/lib/gateway/utils.d.ts +9 -0
- package/lib/gateway/utils.js +57 -1
- package/lib/helper.d.ts +1 -0
- package/lib/helper.js +26 -11
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -0
- package/lib/plugin-manager/findPackageNames.js +1 -0
- package/lib/swagger/app.d.ts +17 -1
- package/lib/swagger/app.js +16 -1
- package/lib/swagger/index.d.ts +17 -1
- package/package.json +17 -17
|
@@ -49,6 +49,7 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
|
|
|
49
49
|
private commandAdapterName;
|
|
50
50
|
private appDbCreator;
|
|
51
51
|
private appConditions;
|
|
52
|
+
private appManifests;
|
|
52
53
|
private appSsoIssuer?;
|
|
53
54
|
appOptionsFactory: AppOptionsFactory;
|
|
54
55
|
private environmentHeartbeatInterval;
|
|
@@ -117,6 +118,8 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
|
|
|
117
118
|
removeAppManifest(appName: string, namespace: string): Promise<void>;
|
|
118
119
|
getAppManifestItems<T = unknown>(appName: string, namespace: string): Promise<T[]>;
|
|
119
120
|
getAppManifests<T = unknown>(namespace: string, appNames: string[]): Promise<Record<string, T[]>>;
|
|
121
|
+
private getAppManifestKey;
|
|
122
|
+
private getOrCreateAppManifest;
|
|
120
123
|
registerAppCondition(name: string, condition: AppCondition): void;
|
|
121
124
|
unregisterAppCondition(name: string): void;
|
|
122
125
|
getAppCondition(name: string): AppCondition;
|
|
@@ -70,6 +70,7 @@ 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();
|
|
73
74
|
appSsoIssuer;
|
|
74
75
|
appOptionsFactory = import_app_options_factory.appOptionsFactory;
|
|
75
76
|
environmentHeartbeatInterval = 2 * 60 * 1e3;
|
|
@@ -284,6 +285,7 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
|
|
|
284
285
|
await this.processAdapter.removeAllApps();
|
|
285
286
|
await ((_b = (_a = this.discoveryAdapter).dispose) == null ? void 0 : _b.call(_a));
|
|
286
287
|
await ((_d = (_c = this.commandAdapter) == null ? void 0 : _c.dispose) == null ? void 0 : _d.call(_c));
|
|
288
|
+
this.appManifests.clear();
|
|
287
289
|
if (this.environmentHeartbeatTimer) {
|
|
288
290
|
this.environmentHeartbeatTimer = null;
|
|
289
291
|
}
|
|
@@ -436,28 +438,31 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
|
|
|
436
438
|
return this.discoveryAdapter.listAppModels();
|
|
437
439
|
}
|
|
438
440
|
async setAppManifestItem(appName, namespace, itemKey, item) {
|
|
439
|
-
if (typeof this.discoveryAdapter.setAppManifestItem
|
|
440
|
-
return;
|
|
441
|
+
if (typeof this.discoveryAdapter.setAppManifestItem === "function") {
|
|
442
|
+
return this.discoveryAdapter.setAppManifestItem(appName, namespace, itemKey, item);
|
|
441
443
|
}
|
|
442
|
-
|
|
444
|
+
const manifest = this.getOrCreateAppManifest(appName, namespace);
|
|
445
|
+
manifest.set(itemKey, item);
|
|
443
446
|
}
|
|
444
447
|
async removeAppManifestItem(appName, namespace, itemKey) {
|
|
445
|
-
|
|
446
|
-
|
|
448
|
+
var _a;
|
|
449
|
+
if (typeof this.discoveryAdapter.removeAppManifestItem === "function") {
|
|
450
|
+
return this.discoveryAdapter.removeAppManifestItem(appName, namespace, itemKey);
|
|
447
451
|
}
|
|
448
|
-
|
|
452
|
+
(_a = this.appManifests.get(this.getAppManifestKey(appName, namespace))) == null ? void 0 : _a.delete(itemKey);
|
|
449
453
|
}
|
|
450
454
|
async removeAppManifest(appName, namespace) {
|
|
451
|
-
if (typeof this.discoveryAdapter.removeAppManifest
|
|
452
|
-
return;
|
|
455
|
+
if (typeof this.discoveryAdapter.removeAppManifest === "function") {
|
|
456
|
+
return this.discoveryAdapter.removeAppManifest(appName, namespace);
|
|
453
457
|
}
|
|
454
|
-
|
|
458
|
+
this.appManifests.delete(this.getAppManifestKey(appName, namespace));
|
|
455
459
|
}
|
|
456
460
|
async getAppManifestItems(appName, namespace) {
|
|
457
|
-
|
|
458
|
-
|
|
461
|
+
var _a;
|
|
462
|
+
if (typeof this.discoveryAdapter.getAppManifestItems === "function") {
|
|
463
|
+
return this.discoveryAdapter.getAppManifestItems(appName, namespace);
|
|
459
464
|
}
|
|
460
|
-
return this.
|
|
465
|
+
return Array.from(((_a = this.appManifests.get(this.getAppManifestKey(appName, namespace))) == null ? void 0 : _a.values()) || []);
|
|
461
466
|
}
|
|
462
467
|
async getAppManifests(namespace, appNames) {
|
|
463
468
|
if (typeof this.discoveryAdapter.getAppManifests === "function") {
|
|
@@ -474,6 +479,19 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
|
|
|
474
479
|
);
|
|
475
480
|
return result;
|
|
476
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
|
+
}
|
|
477
495
|
registerAppCondition(name, condition) {
|
|
478
496
|
this.appConditions.set(name, condition);
|
|
479
497
|
}
|
|
@@ -16,18 +16,12 @@ export declare class MainOnlyAdapter implements AppDiscoveryAdapter, AppProcessA
|
|
|
16
16
|
apps: Record<string, Application>;
|
|
17
17
|
status: AppStatus;
|
|
18
18
|
appErrors: Record<string, Error>;
|
|
19
|
-
private readonly appManifests;
|
|
20
19
|
constructor(supervisor: AppSupervisor);
|
|
21
20
|
getApp(appName: string, options?: GetAppOptions): Promise<Application<import("../application").DefaultState, import("../application").DefaultContext>>;
|
|
22
21
|
bootstrapApp(appName: string): Promise<void>;
|
|
23
22
|
addApp(app: Application): Application<import("../application").DefaultState, import("../application").DefaultContext>;
|
|
24
23
|
getApps(): Application<import("../application").DefaultState, import("../application").DefaultContext>[];
|
|
25
24
|
listAppModels(): Promise<any[]>;
|
|
26
|
-
setAppManifestItem(appName: string, namespace: string, itemKey: string, item: unknown): Promise<void>;
|
|
27
|
-
removeAppManifestItem(appName: string, namespace: string, itemKey: string): Promise<void>;
|
|
28
|
-
removeAppManifest(appName: string, namespace: string): Promise<void>;
|
|
29
|
-
getAppManifestItems<T = unknown>(appName: string, namespace: string): Promise<T[]>;
|
|
30
|
-
getAppManifests<T = unknown>(namespace: string, appNames: string[]): Promise<Record<string, T[]>>;
|
|
31
25
|
hasApp(appName: string): boolean;
|
|
32
26
|
startApp(appName: string): Promise<void>;
|
|
33
27
|
stopApp(appName: string): Promise<void>;
|
|
@@ -44,6 +38,4 @@ export declare class MainOnlyAdapter implements AppDiscoveryAdapter, AppProcessA
|
|
|
44
38
|
clearAppError(appName: string): void;
|
|
45
39
|
setAppLastSeenAt(): void;
|
|
46
40
|
getAppLastSeenAt(appName: string): any;
|
|
47
|
-
private getAppManifestKey;
|
|
48
|
-
private getOrCreateAppManifest;
|
|
49
41
|
}
|
|
@@ -39,7 +39,6 @@ const _MainOnlyAdapter = class _MainOnlyAdapter {
|
|
|
39
39
|
apps = {};
|
|
40
40
|
status;
|
|
41
41
|
appErrors = {};
|
|
42
|
-
appManifests = /* @__PURE__ */ new Map();
|
|
43
42
|
async getApp(appName, options = {}) {
|
|
44
43
|
if (appName !== "main") {
|
|
45
44
|
this.supervisor.logger.warn(`only main app is supported`, { method: "getApp", appName });
|
|
@@ -82,31 +81,6 @@ const _MainOnlyAdapter = class _MainOnlyAdapter {
|
|
|
82
81
|
async listAppModels() {
|
|
83
82
|
return [];
|
|
84
83
|
}
|
|
85
|
-
async setAppManifestItem(appName, namespace, itemKey, item) {
|
|
86
|
-
const manifest = this.getOrCreateAppManifest(appName, namespace);
|
|
87
|
-
manifest.set(itemKey, item);
|
|
88
|
-
}
|
|
89
|
-
async removeAppManifestItem(appName, namespace, itemKey) {
|
|
90
|
-
var _a;
|
|
91
|
-
(_a = this.appManifests.get(this.getAppManifestKey(appName, namespace))) == null ? void 0 : _a.delete(itemKey);
|
|
92
|
-
}
|
|
93
|
-
async removeAppManifest(appName, namespace) {
|
|
94
|
-
this.appManifests.delete(this.getAppManifestKey(appName, namespace));
|
|
95
|
-
}
|
|
96
|
-
async getAppManifestItems(appName, namespace) {
|
|
97
|
-
var _a;
|
|
98
|
-
return Array.from(((_a = this.appManifests.get(this.getAppManifestKey(appName, namespace))) == null ? void 0 : _a.values()) || []);
|
|
99
|
-
}
|
|
100
|
-
async getAppManifests(namespace, appNames) {
|
|
101
|
-
const result = {};
|
|
102
|
-
for (const appName of appNames) {
|
|
103
|
-
const data = await this.getAppManifestItems(appName, namespace);
|
|
104
|
-
if (data.length > 0) {
|
|
105
|
-
result[appName] = data;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return result;
|
|
109
|
-
}
|
|
110
84
|
hasApp(appName) {
|
|
111
85
|
if (appName !== "main") {
|
|
112
86
|
return false;
|
|
@@ -188,19 +162,6 @@ const _MainOnlyAdapter = class _MainOnlyAdapter {
|
|
|
188
162
|
getAppLastSeenAt(appName) {
|
|
189
163
|
return null;
|
|
190
164
|
}
|
|
191
|
-
getAppManifestKey(appName, namespace) {
|
|
192
|
-
return `${namespace}:${appName}`;
|
|
193
|
-
}
|
|
194
|
-
getOrCreateAppManifest(appName, namespace) {
|
|
195
|
-
const key = this.getAppManifestKey(appName, namespace);
|
|
196
|
-
const manifest = this.appManifests.get(key);
|
|
197
|
-
if (manifest) {
|
|
198
|
-
return manifest;
|
|
199
|
-
}
|
|
200
|
-
const nextManifest = /* @__PURE__ */ new Map();
|
|
201
|
-
this.appManifests.set(key, nextManifest);
|
|
202
|
-
return nextManifest;
|
|
203
|
-
}
|
|
204
165
|
};
|
|
205
166
|
__name(_MainOnlyAdapter, "MainOnlyAdapter");
|
|
206
167
|
let MainOnlyAdapter = _MainOnlyAdapter;
|
package/lib/application.js
CHANGED
|
@@ -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",
|
package/lib/event-queue.d.ts
CHANGED
|
@@ -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<
|
|
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;
|
package/lib/event-queue.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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)) {
|
package/lib/gateway/index.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export declare class Gateway extends EventEmitter {
|
|
|
59
59
|
private host;
|
|
60
60
|
private socketPath;
|
|
61
61
|
private v2IndexTemplateCache;
|
|
62
|
+
private settingsIndexTemplateCache;
|
|
62
63
|
private terminating;
|
|
63
64
|
private getOriginalRequestUrl;
|
|
64
65
|
private proxyRequestToSubApp;
|
|
@@ -80,6 +81,17 @@ export declare class Gateway extends EventEmitter {
|
|
|
80
81
|
responseErrorWithCode(code: any, res: any, options: any): void;
|
|
81
82
|
private getV2PublicPath;
|
|
82
83
|
private getAppPublicPath;
|
|
84
|
+
private getSettingsPublicPath;
|
|
85
|
+
private getPathWithinAppPublicPath;
|
|
86
|
+
private isSettingsRequest;
|
|
87
|
+
private isSettingsIndexRequest;
|
|
88
|
+
private isSettingsAssetsRequest;
|
|
89
|
+
private resolveLegacyV2SettingsRedirect;
|
|
90
|
+
private getPortalRootPublicPath;
|
|
91
|
+
private getPortalAppPublicPath;
|
|
92
|
+
private getPortalMatch;
|
|
93
|
+
private isPortalIndexRequest;
|
|
94
|
+
private getPortalDistRoot;
|
|
83
95
|
private isV2Request;
|
|
84
96
|
private isV2IndexRequest;
|
|
85
97
|
private getV2RuntimeConfig;
|
|
@@ -87,6 +99,11 @@ export declare class Gateway extends EventEmitter {
|
|
|
87
99
|
private getV2AssetPublicPath;
|
|
88
100
|
private getV2IndexTemplate;
|
|
89
101
|
private renderV2IndexHtml;
|
|
102
|
+
private getSettingsRuntimeConfig;
|
|
103
|
+
private getSettingsRuntimeConfigScript;
|
|
104
|
+
private getSettingsAssetPublicPath;
|
|
105
|
+
private getSettingsIndexTemplate;
|
|
106
|
+
private renderSettingsIndexHtml;
|
|
90
107
|
requestHandler(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
91
108
|
getAppSelectorMiddlewares(): Toposort<AppSelectorMiddleware>;
|
|
92
109
|
getRequestHandleAppName(req: IncomingMessage | IncomingRequest): Promise<string>;
|
package/lib/gateway/index.js
CHANGED
|
@@ -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) {
|
|
@@ -103,6 +114,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
103
114
|
host = "0.0.0.0";
|
|
104
115
|
socketPath = getSocketPath();
|
|
105
116
|
v2IndexTemplateCache = null;
|
|
117
|
+
settingsIndexTemplateCache = null;
|
|
106
118
|
terminating = false;
|
|
107
119
|
getOriginalRequestUrl(req) {
|
|
108
120
|
return req.originalUrl || req.url;
|
|
@@ -145,6 +157,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
145
157
|
}, "onTerminate");
|
|
146
158
|
constructor() {
|
|
147
159
|
super();
|
|
160
|
+
(0, import_utils3.normalizeModernClientPrefix)(import_node_process.default.env.APP_MODERN_CLIENT_PREFIX);
|
|
148
161
|
this.reset();
|
|
149
162
|
import_node_process.default.once("SIGTERM", this.onTerminate);
|
|
150
163
|
import_node_process.default.once("SIGINT", this.onTerminate);
|
|
@@ -177,19 +190,28 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
177
190
|
this.selectorMiddlewares = new import_utils.Toposort();
|
|
178
191
|
this.addAppSelectorMiddleware(
|
|
179
192
|
async (ctx, next) => {
|
|
180
|
-
var _a, _b;
|
|
193
|
+
var _a, _b, _c;
|
|
181
194
|
const { req } = ctx;
|
|
182
195
|
const parsedUrl = (0, import_url.parse)(req.url);
|
|
183
196
|
const appName = (_a = import_qs.default.parse(parsedUrl.query)) == null ? void 0 : _a.__appName;
|
|
184
197
|
const apiBasePath = normalizeBasePath(import_node_process.default.env.API_BASE_PATH || "/api");
|
|
185
198
|
const appPathPrefix = `${apiBasePath}/__app/`;
|
|
199
|
+
const appPublicPath = (0, import_utils3.resolvePublicPath)(import_node_process.default.env.APP_PUBLIC_PATH || "/");
|
|
200
|
+
const portalAppsPathPrefix = `${appPublicPath.replace(/\/$/, "")}/${import_utils3.PORTAL_CLIENT_PREFIX}/apps/`;
|
|
186
201
|
if (req.headers["x-app"]) {
|
|
187
202
|
ctx.resolvedAppName = req.headers["x-app"];
|
|
188
203
|
}
|
|
189
204
|
if (appName) {
|
|
190
205
|
ctx.resolvedAppName = appName;
|
|
191
206
|
}
|
|
192
|
-
if ((_b = parsedUrl.pathname) == null ? void 0 : _b.startsWith(
|
|
207
|
+
if ((_b = parsedUrl.pathname) == null ? void 0 : _b.startsWith(portalAppsPathPrefix)) {
|
|
208
|
+
const restPath = parsedUrl.pathname.slice(portalAppsPathPrefix.length);
|
|
209
|
+
const [pathAppName] = restPath.split("/");
|
|
210
|
+
if (pathAppName) {
|
|
211
|
+
ctx.resolvedAppName = (0, import_utils3.normalizePortalAppName)(pathAppName);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if ((_c = parsedUrl.pathname) == null ? void 0 : _c.startsWith(appPathPrefix)) {
|
|
193
215
|
const restPath = parsedUrl.pathname.slice(appPathPrefix.length);
|
|
194
216
|
const [pathAppName, ...segments] = restPath.split("/");
|
|
195
217
|
if (pathAppName) {
|
|
@@ -202,6 +224,17 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
202
224
|
req.url = rewrittenUrl;
|
|
203
225
|
}
|
|
204
226
|
}
|
|
227
|
+
const fileAccessRestPath = parsedUrl.pathname ? getFileAccessRestPath(parsedUrl.pathname, import_node_process.default.env.APP_PUBLIC_PATH || "/") : null;
|
|
228
|
+
if (fileAccessRestPath) {
|
|
229
|
+
const restPath = fileAccessRestPath;
|
|
230
|
+
const [pathAppName] = restPath.split("/");
|
|
231
|
+
if (pathAppName) {
|
|
232
|
+
try {
|
|
233
|
+
ctx.resolvedAppName = decodeURIComponent(pathAppName);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
205
238
|
await next();
|
|
206
239
|
},
|
|
207
240
|
{
|
|
@@ -270,6 +303,144 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
270
303
|
getAppPublicPath() {
|
|
271
304
|
return (0, import_utils3.resolvePublicPath)(import_node_process.default.env.APP_PUBLIC_PATH || "/");
|
|
272
305
|
}
|
|
306
|
+
getSettingsPublicPath() {
|
|
307
|
+
return (0, import_utils3.resolveSettingsPublicPath)(import_node_process.default.env.APP_PUBLIC_PATH || "/");
|
|
308
|
+
}
|
|
309
|
+
getPathWithinAppPublicPath(pathname) {
|
|
310
|
+
const appPublicPath = this.getAppPublicPath();
|
|
311
|
+
if (appPublicPath === "/") {
|
|
312
|
+
return pathname;
|
|
313
|
+
}
|
|
314
|
+
const appPublicPathWithoutSlash = appPublicPath.slice(0, -1);
|
|
315
|
+
if (pathname === appPublicPathWithoutSlash) {
|
|
316
|
+
return "/";
|
|
317
|
+
}
|
|
318
|
+
if (!pathname.startsWith(appPublicPath)) {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
return pathname.slice(appPublicPath.length - 1);
|
|
322
|
+
}
|
|
323
|
+
isSettingsRequest(pathname) {
|
|
324
|
+
const appPath = this.getPathWithinAppPublicPath(pathname);
|
|
325
|
+
if (!appPath) {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
return /^\/settings(?:\/|$)/.test(appPath);
|
|
329
|
+
}
|
|
330
|
+
isSettingsIndexRequest(pathname) {
|
|
331
|
+
if (!this.isSettingsRequest(pathname)) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
if (pathname.endsWith("/index.html")) {
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
return !(0, import_path.extname)(pathname);
|
|
338
|
+
}
|
|
339
|
+
isSettingsAssetsRequest(pathname) {
|
|
340
|
+
const appPath = this.getPathWithinAppPublicPath(pathname);
|
|
341
|
+
return appPath ? /^\/settings\/assets\//.test(appPath) : false;
|
|
342
|
+
}
|
|
343
|
+
resolveLegacyV2SettingsRedirect(pathname) {
|
|
344
|
+
const appPath = this.getPathWithinAppPublicPath(pathname);
|
|
345
|
+
if (!appPath) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
const modernPrefix = (0, import_utils3.normalizeModernClientPrefix)(import_node_process.default.env.APP_MODERN_CLIENT_PREFIX);
|
|
349
|
+
const escapedModernPrefix = modernPrefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
350
|
+
const match = appPath.match(new RegExp(`^/${escapedModernPrefix}((?:/(?:apps|_app)/[^/]+)?)(/admin(?:/.*)?)$`));
|
|
351
|
+
if (!match) {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
const appScope = match[1] || "";
|
|
355
|
+
const legacyPath = match[2];
|
|
356
|
+
const mappings = [
|
|
357
|
+
{
|
|
358
|
+
from: "/admin/settings/mail/oauth2",
|
|
359
|
+
to: "/admin/settings/mail/oauth2"
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
from: "/admin/ai/knowledge-base/detail",
|
|
363
|
+
to: "/settings/ai/knowledge-base/detail"
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
from: "/admin/workflow/executions",
|
|
367
|
+
to: "/settings/workflow/executions"
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
from: "/admin/workflow/workflows",
|
|
371
|
+
to: "/settings/workflow/workflows"
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
from: "/admin/settings",
|
|
375
|
+
to: "/settings"
|
|
376
|
+
}
|
|
377
|
+
];
|
|
378
|
+
for (const { from, to } of mappings) {
|
|
379
|
+
if (legacyPath !== from && !legacyPath.startsWith(`${from}/`)) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
const appPublicPath = this.getAppPublicPath().replace(/\/$/, "");
|
|
383
|
+
const targetPath = from === "/admin/settings/mail/oauth2" ? `${appScope}${to}` : appScope ? `/settings${appScope}${to.replace(/^\/settings(?=\/|$)/, "")}` : to;
|
|
384
|
+
return `${appPublicPath}${targetPath}${legacyPath.slice(from.length)}`;
|
|
385
|
+
}
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
getPortalRootPublicPath() {
|
|
389
|
+
return `${this.getAppPublicPath().replace(/\/$/, "")}/${import_utils3.PORTAL_CLIENT_PREFIX}/`;
|
|
390
|
+
}
|
|
391
|
+
getPortalAppPublicPath(appName) {
|
|
392
|
+
if (appName === import_utils3.DEFAULT_PORTAL_APP_NAME) {
|
|
393
|
+
return this.getPortalRootPublicPath();
|
|
394
|
+
}
|
|
395
|
+
return `${this.getPortalRootPublicPath()}apps/${(0, import_utils3.normalizePortalAppName)(appName)}/`;
|
|
396
|
+
}
|
|
397
|
+
getPortalMatch(pathname) {
|
|
398
|
+
const portalRootPublicPath = this.getPortalRootPublicPath();
|
|
399
|
+
if (!pathname.startsWith(portalRootPublicPath)) {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
let appName = import_utils3.DEFAULT_PORTAL_APP_NAME;
|
|
403
|
+
let publicRoot = portalRootPublicPath;
|
|
404
|
+
let restPath = pathname.slice(portalRootPublicPath.length).replace(/^\/+/, "");
|
|
405
|
+
const [firstSegment, secondSegment, ...remainingSegments] = restPath.split("/");
|
|
406
|
+
if (firstSegment === "apps") {
|
|
407
|
+
if (!secondSegment || !/^[A-Za-z0-9_-]+$/.test(secondSegment)) {
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
appName = (0, import_utils3.normalizePortalAppName)(secondSegment);
|
|
411
|
+
publicRoot = this.getPortalAppPublicPath(appName);
|
|
412
|
+
if (!pathname.startsWith(publicRoot)) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
restPath = remainingSegments.join("/").replace(/^\/+/, "");
|
|
416
|
+
}
|
|
417
|
+
const [portalName] = restPath.split("/");
|
|
418
|
+
if (!portalName || !/^[A-Za-z0-9_-]+$/.test(portalName)) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
return {
|
|
422
|
+
appName,
|
|
423
|
+
portalName,
|
|
424
|
+
publicPath: `${publicRoot}${portalName}/`
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
isPortalIndexRequest(pathname, portalPublicPath) {
|
|
428
|
+
if (pathname === portalPublicPath || pathname === portalPublicPath.slice(0, -1) || pathname === `${portalPublicPath}index.html`) {
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
return !(0, import_path.extname)(pathname);
|
|
432
|
+
}
|
|
433
|
+
getPortalDistRoot(portalMatch) {
|
|
434
|
+
const scopedRoot = (0, import_utils.storagePathJoin)("portals", portalMatch.appName, portalMatch.portalName, "dist");
|
|
435
|
+
if (portalMatch.appName !== import_utils3.DEFAULT_PORTAL_APP_NAME) {
|
|
436
|
+
return scopedRoot;
|
|
437
|
+
}
|
|
438
|
+
const legacyRoot = (0, import_utils.storagePathJoin)("portals", portalMatch.portalName, "dist");
|
|
439
|
+
if (!import_fs.default.existsSync((0, import_path.resolve)(scopedRoot, "index.html")) && import_fs.default.existsSync((0, import_path.resolve)(legacyRoot, "index.html"))) {
|
|
440
|
+
return legacyRoot;
|
|
441
|
+
}
|
|
442
|
+
return scopedRoot;
|
|
443
|
+
}
|
|
273
444
|
isV2Request(pathname) {
|
|
274
445
|
const v2PublicPath = this.getV2PublicPath();
|
|
275
446
|
return pathname === v2PublicPath.slice(0, -1) || pathname.startsWith(v2PublicPath);
|
|
@@ -336,8 +507,59 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
336
507
|
const html = (0, import_utils3.rewriteV2AssetPublicPath)(template, this.getV2AssetPublicPath());
|
|
337
508
|
return (0, import_utils3.injectRuntimeScript)(html, this.getV2RuntimeConfigScript());
|
|
338
509
|
}
|
|
510
|
+
getSettingsRuntimeConfig() {
|
|
511
|
+
return {
|
|
512
|
+
__nocobase_public_path__: this.getAppPublicPath(),
|
|
513
|
+
__nocobase_modern_client_prefix__: (0, import_utils3.normalizeModernClientPrefix)(import_node_process.default.env.APP_MODERN_CLIENT_PREFIX),
|
|
514
|
+
__webpack_public_path__: import_node_process.default.env.CDN_BASE_URL ? `${import_node_process.default.env.CDN_BASE_URL.replace(/\/+$/, "")}/` : "",
|
|
515
|
+
__nocobase_api_base_url__: import_node_process.default.env.API_BASE_URL || import_node_process.default.env.API_BASE_PATH,
|
|
516
|
+
__nocobase_api_client_storage_prefix__: import_node_process.default.env.API_CLIENT_STORAGE_PREFIX,
|
|
517
|
+
__nocobase_api_client_storage_type__: import_node_process.default.env.API_CLIENT_STORAGE_TYPE,
|
|
518
|
+
__nocobase_api_client_share_token__: import_node_process.default.env.API_CLIENT_SHARE_TOKEN === "true",
|
|
519
|
+
__nocobase_ws_url__: import_node_process.default.env.WEBSOCKET_URL || "",
|
|
520
|
+
__nocobase_ws_path__: import_node_process.default.env.WS_PATH,
|
|
521
|
+
__nocobase_app_dev__: import_node_process.default.env.NOCOBASE_APP_DEV === "true",
|
|
522
|
+
__esm_cdn_base_url__: import_node_process.default.env.ESM_CDN_BASE_URL || "https://esm.sh",
|
|
523
|
+
__esm_cdn_suffix__: import_node_process.default.env.ESM_CDN_SUFFIX || ""
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
getSettingsRuntimeConfigScript() {
|
|
527
|
+
const scriptContent = Object.entries(this.getSettingsRuntimeConfig()).map(([key, value]) => `window['${key}'] = ${JSON.stringify(value)};`).join("\n");
|
|
528
|
+
return `<script>${scriptContent}</script>`;
|
|
529
|
+
}
|
|
530
|
+
getSettingsAssetPublicPath() {
|
|
531
|
+
if (import_node_process.default.env.CDN_BASE_URL) {
|
|
532
|
+
return `${import_node_process.default.env.CDN_BASE_URL.replace(/\/+$/, "")}/${import_utils3.SETTINGS_CLIENT_DIST_DIR}/`;
|
|
533
|
+
}
|
|
534
|
+
return this.getSettingsPublicPath();
|
|
535
|
+
}
|
|
536
|
+
getSettingsIndexTemplate() {
|
|
537
|
+
const file = `${import_node_process.default.env.APP_PACKAGE_ROOT}/dist/client/${import_utils3.SETTINGS_CLIENT_DIST_DIR}/index.html`;
|
|
538
|
+
if (!import_fs.default.existsSync(file)) {
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
const stat = import_fs.default.statSync(file);
|
|
542
|
+
if (this.settingsIndexTemplateCache && this.settingsIndexTemplateCache.file === file && this.settingsIndexTemplateCache.mtimeMs === stat.mtimeMs) {
|
|
543
|
+
return this.settingsIndexTemplateCache.html;
|
|
544
|
+
}
|
|
545
|
+
const html = import_fs.default.readFileSync(file, "utf-8");
|
|
546
|
+
this.settingsIndexTemplateCache = {
|
|
547
|
+
file,
|
|
548
|
+
mtimeMs: stat.mtimeMs,
|
|
549
|
+
html
|
|
550
|
+
};
|
|
551
|
+
return html;
|
|
552
|
+
}
|
|
553
|
+
renderSettingsIndexHtml() {
|
|
554
|
+
const template = this.getSettingsIndexTemplate();
|
|
555
|
+
if (!template) {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
const html = (0, import_utils3.rewriteSettingsAssetPublicPath)(template, this.getSettingsAssetPublicPath());
|
|
559
|
+
return (0, import_utils3.injectRuntimeScript)(html, this.getSettingsRuntimeConfigScript());
|
|
560
|
+
}
|
|
339
561
|
async requestHandler(req, res) {
|
|
340
|
-
const { pathname } = (0, import_url.parse)(req.url);
|
|
562
|
+
const { pathname, search } = (0, import_url.parse)(req.url);
|
|
341
563
|
const { PLUGIN_STATICS_PATH } = import_node_process.default.env;
|
|
342
564
|
const APP_PUBLIC_PATH = this.getAppPublicPath();
|
|
343
565
|
if (pathname.endsWith("/__umi/api/bundle-status")) {
|
|
@@ -345,6 +567,19 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
345
567
|
res.end("ok");
|
|
346
568
|
return;
|
|
347
569
|
}
|
|
570
|
+
if (APP_PUBLIC_PATH !== "/" && pathname.startsWith("/files/")) {
|
|
571
|
+
res.statusCode = 302;
|
|
572
|
+
res.setHeader("Location", `${APP_PUBLIC_PATH.replace(/\/$/, "")}${pathname}${search || ""}`);
|
|
573
|
+
res.end();
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
const settingsRedirect = this.resolveLegacyV2SettingsRedirect(pathname);
|
|
577
|
+
if (settingsRedirect) {
|
|
578
|
+
res.statusCode = 302;
|
|
579
|
+
res.setHeader("Location", `${settingsRedirect}${search || ""}`);
|
|
580
|
+
res.end();
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
348
583
|
const supervisor = import_app_supervisor.AppSupervisor.getInstance();
|
|
349
584
|
let handleApp = "main";
|
|
350
585
|
try {
|
|
@@ -361,15 +596,18 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
361
596
|
return;
|
|
362
597
|
}
|
|
363
598
|
}
|
|
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
|
-
}
|
|
599
|
+
const headers = (0, import_static_file_security.getStorageUploadSecurityHeaders)(`${pathname}${search || ""}`);
|
|
368
600
|
req.url = req.url.substring(APP_PUBLIC_PATH.length + "storage".length);
|
|
369
601
|
await compress(req, res);
|
|
370
602
|
return (0, import_serve_handler.default)(req, res, {
|
|
371
603
|
public: (0, import_utils.resolveStorageRoot)(),
|
|
372
|
-
directoryListing: false
|
|
604
|
+
directoryListing: false,
|
|
605
|
+
headers: [
|
|
606
|
+
{
|
|
607
|
+
source: "**/*",
|
|
608
|
+
headers: Object.entries(headers).map(([key, value]) => ({ key, value }))
|
|
609
|
+
}
|
|
610
|
+
]
|
|
373
611
|
});
|
|
374
612
|
}
|
|
375
613
|
if (pathname.startsWith(APP_PUBLIC_PATH + "dist/")) {
|
|
@@ -407,7 +645,72 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
407
645
|
]
|
|
408
646
|
});
|
|
409
647
|
}
|
|
410
|
-
|
|
648
|
+
const isFilesRequest = Boolean(getFileAccessRestPath(pathname, APP_PUBLIC_PATH));
|
|
649
|
+
if (!pathname.startsWith(import_node_process.default.env.API_BASE_PATH) && !isFilesRequest) {
|
|
650
|
+
if (this.isSettingsRequest(pathname)) {
|
|
651
|
+
if (handleApp !== "main") {
|
|
652
|
+
const isProxy = await this.proxyRequestToSubApp(supervisor, handleApp, req, res);
|
|
653
|
+
if (isProxy) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (this.isSettingsIndexRequest(pathname)) {
|
|
658
|
+
const settingsHtml = this.renderSettingsIndexHtml();
|
|
659
|
+
if (settingsHtml) {
|
|
660
|
+
res.setHeader("Cache-Control", "no-store");
|
|
661
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
662
|
+
res.end(settingsHtml);
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
if (this.isSettingsAssetsRequest(pathname)) {
|
|
667
|
+
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
668
|
+
}
|
|
669
|
+
req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
|
|
670
|
+
await compress(req, res);
|
|
671
|
+
return (0, import_serve_handler.default)(req, res, {
|
|
672
|
+
public: `${import_node_process.default.env.APP_PACKAGE_ROOT}/dist/client`
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
const portalMatch = this.getPortalMatch(pathname);
|
|
676
|
+
if (portalMatch) {
|
|
677
|
+
if (handleApp !== "main" && handleApp !== portalMatch.appName) {
|
|
678
|
+
const isProxy = await this.proxyRequestToSubApp(supervisor, handleApp, req, res);
|
|
679
|
+
if (isProxy) {
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
if (!pathname.startsWith(portalMatch.publicPath)) {
|
|
684
|
+
res.statusCode = 302;
|
|
685
|
+
res.setHeader("Location", `${portalMatch.publicPath}${search || ""}`);
|
|
686
|
+
res.end();
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
const portalDistRoot = this.getPortalDistRoot(portalMatch);
|
|
690
|
+
const portalIndex = (0, import_path.resolve)(portalDistRoot, "index.html");
|
|
691
|
+
if (!import_fs.default.existsSync(portalIndex)) {
|
|
692
|
+
res.statusCode = 404;
|
|
693
|
+
res.end();
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (this.isPortalIndexRequest(pathname, portalMatch.publicPath)) {
|
|
697
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
698
|
+
res.end(import_fs.default.readFileSync(portalIndex, "utf-8"));
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
req.url = req.url.substring(portalMatch.publicPath.length - 1);
|
|
702
|
+
await compress(req, res);
|
|
703
|
+
return (0, import_serve_handler.default)(req, res, {
|
|
704
|
+
public: portalDistRoot,
|
|
705
|
+
directoryListing: false
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
const portalRootPublicPath = this.getPortalRootPublicPath();
|
|
709
|
+
if (pathname === portalRootPublicPath.slice(0, -1) || pathname.startsWith(portalRootPublicPath)) {
|
|
710
|
+
res.statusCode = 404;
|
|
711
|
+
res.end();
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
411
714
|
if (this.isV2Request(pathname)) {
|
|
412
715
|
if (handleApp !== "main") {
|
|
413
716
|
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([
|
|
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;
|
package/lib/gateway/utils.d.ts
CHANGED
|
@@ -10,10 +10,19 @@
|
|
|
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 SETTINGS_CLIENT_DIST_DIR = "settings";
|
|
14
|
+
export declare const PORTAL_CLIENT_PREFIX = "x";
|
|
15
|
+
export declare const DEFAULT_PORTAL_APP_NAME = "main";
|
|
16
|
+
export declare const DEFAULT_PORTAL_NAME = "admin";
|
|
13
17
|
export declare function resolvePublicPath(appPublicPath?: string): string;
|
|
14
18
|
export declare function normalizeModernClientPrefix(value?: string): string;
|
|
15
19
|
export declare function resolveV2PublicPath(appPublicPath?: string): string;
|
|
20
|
+
export declare function resolveSettingsPublicPath(appPublicPath?: string): string;
|
|
21
|
+
export declare function normalizePortalName(value?: string): string;
|
|
22
|
+
export declare function normalizePortalAppName(value?: string): string;
|
|
23
|
+
export declare function resolvePortalPublicPath(portalName: string, appPublicPath?: string): string;
|
|
16
24
|
export declare function rewriteV2AssetPublicPath(html: string, assetPublicPath: string): string;
|
|
25
|
+
export declare function rewriteSettingsAssetPublicPath(html: string, assetPublicPath: string): string;
|
|
17
26
|
export declare function injectRuntimeScript(html: string, runtimeScript: string): string;
|
|
18
27
|
export declare function getHost(req: IncomingMessage | IncomingRequest): any;
|
|
19
28
|
export declare function getHostname(req: IncomingMessage | IncomingRequest): any;
|
package/lib/gateway/utils.js
CHANGED
|
@@ -27,17 +27,30 @@ 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,
|
|
34
|
+
SETTINGS_CLIENT_DIST_DIR: () => SETTINGS_CLIENT_DIST_DIR,
|
|
31
35
|
getHost: () => getHost,
|
|
32
36
|
getHostname: () => getHostname,
|
|
33
37
|
injectRuntimeScript: () => injectRuntimeScript,
|
|
34
38
|
normalizeModernClientPrefix: () => normalizeModernClientPrefix,
|
|
39
|
+
normalizePortalAppName: () => normalizePortalAppName,
|
|
40
|
+
normalizePortalName: () => normalizePortalName,
|
|
41
|
+
resolvePortalPublicPath: () => resolvePortalPublicPath,
|
|
35
42
|
resolvePublicPath: () => resolvePublicPath,
|
|
43
|
+
resolveSettingsPublicPath: () => resolveSettingsPublicPath,
|
|
36
44
|
resolveV2PublicPath: () => resolveV2PublicPath,
|
|
45
|
+
rewriteSettingsAssetPublicPath: () => rewriteSettingsAssetPublicPath,
|
|
37
46
|
rewriteV2AssetPublicPath: () => rewriteV2AssetPublicPath
|
|
38
47
|
});
|
|
39
48
|
module.exports = __toCommonJS(utils_exports);
|
|
40
49
|
const MODERN_CLIENT_DIST_DIR = "v";
|
|
50
|
+
const SETTINGS_CLIENT_DIST_DIR = "settings";
|
|
51
|
+
const PORTAL_CLIENT_PREFIX = "x";
|
|
52
|
+
const DEFAULT_PORTAL_APP_NAME = "main";
|
|
53
|
+
const DEFAULT_PORTAL_NAME = "admin";
|
|
41
54
|
function resolvePublicPath(appPublicPath = "/") {
|
|
42
55
|
const normalized = String(appPublicPath || "/").trim() || "/";
|
|
43
56
|
const withLeadingSlash = normalized.startsWith("/") ? normalized : `/${normalized}`;
|
|
@@ -46,7 +59,11 @@ function resolvePublicPath(appPublicPath = "/") {
|
|
|
46
59
|
__name(resolvePublicPath, "resolvePublicPath");
|
|
47
60
|
function normalizeModernClientPrefix(value) {
|
|
48
61
|
const segment = String(value || "").trim().replace(/^\/+|\/+$/g, "");
|
|
49
|
-
|
|
62
|
+
const normalized = segment || MODERN_CLIENT_DIST_DIR;
|
|
63
|
+
if (normalized === SETTINGS_CLIENT_DIST_DIR) {
|
|
64
|
+
throw new Error('APP_MODERN_CLIENT_PREFIX "settings" is reserved for the standalone Settings application.');
|
|
65
|
+
}
|
|
66
|
+
return normalized;
|
|
50
67
|
}
|
|
51
68
|
__name(normalizeModernClientPrefix, "normalizeModernClientPrefix");
|
|
52
69
|
function resolveV2PublicPath(appPublicPath = "/") {
|
|
@@ -55,6 +72,26 @@ function resolveV2PublicPath(appPublicPath = "/") {
|
|
|
55
72
|
return `${publicPath.replace(/\/$/, "")}/${prefix}/`;
|
|
56
73
|
}
|
|
57
74
|
__name(resolveV2PublicPath, "resolveV2PublicPath");
|
|
75
|
+
function resolveSettingsPublicPath(appPublicPath = "/") {
|
|
76
|
+
const publicPath = resolvePublicPath(appPublicPath);
|
|
77
|
+
return `${publicPath.replace(/\/$/, "")}/${SETTINGS_CLIENT_DIST_DIR}/`;
|
|
78
|
+
}
|
|
79
|
+
__name(resolveSettingsPublicPath, "resolveSettingsPublicPath");
|
|
80
|
+
function normalizePortalName(value) {
|
|
81
|
+
const segment = String(value || "").trim().replace(/^\/+|\/+$/g, "");
|
|
82
|
+
return segment || DEFAULT_PORTAL_NAME;
|
|
83
|
+
}
|
|
84
|
+
__name(normalizePortalName, "normalizePortalName");
|
|
85
|
+
function normalizePortalAppName(value) {
|
|
86
|
+
const segment = String(value || "").trim().replace(/^\/+|\/+$/g, "");
|
|
87
|
+
return segment || DEFAULT_PORTAL_APP_NAME;
|
|
88
|
+
}
|
|
89
|
+
__name(normalizePortalAppName, "normalizePortalAppName");
|
|
90
|
+
function resolvePortalPublicPath(portalName, appPublicPath = "/") {
|
|
91
|
+
const publicPath = resolvePublicPath(appPublicPath);
|
|
92
|
+
return `${publicPath.replace(/\/$/, "")}/${PORTAL_CLIENT_PREFIX}/${normalizePortalName(portalName)}/`;
|
|
93
|
+
}
|
|
94
|
+
__name(resolvePortalPublicPath, "resolvePortalPublicPath");
|
|
58
95
|
function ensureTrailingSlash(value) {
|
|
59
96
|
return value.endsWith("/") ? value : `${value}/`;
|
|
60
97
|
}
|
|
@@ -69,6 +106,16 @@ function rewriteV2AssetPublicPath(html, assetPublicPath) {
|
|
|
69
106
|
return html.replace(sentinelPattern, `$1${normalizedAssetPublicPath}`);
|
|
70
107
|
}
|
|
71
108
|
__name(rewriteV2AssetPublicPath, "rewriteV2AssetPublicPath");
|
|
109
|
+
function rewriteSettingsAssetPublicPath(html, assetPublicPath) {
|
|
110
|
+
const normalizedAssetPublicPath = ensureTrailingSlash(assetPublicPath);
|
|
111
|
+
const sentinel = `/${SETTINGS_CLIENT_DIST_DIR}/`;
|
|
112
|
+
if (normalizedAssetPublicPath === sentinel) {
|
|
113
|
+
return html;
|
|
114
|
+
}
|
|
115
|
+
const sentinelPattern = new RegExp(`((?:src|href)=["'])${sentinel.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "g");
|
|
116
|
+
return html.replace(sentinelPattern, `$1${normalizedAssetPublicPath}`);
|
|
117
|
+
}
|
|
118
|
+
__name(rewriteSettingsAssetPublicPath, "rewriteSettingsAssetPublicPath");
|
|
72
119
|
function injectRuntimeScript(html, runtimeScript) {
|
|
73
120
|
const browserCheckerScriptMatch = html.match(/<script\b[^>]*browser-checker\.js[^>]*><\/script>/i);
|
|
74
121
|
if (browserCheckerScriptMatch == null ? void 0 : browserCheckerScriptMatch[0]) {
|
|
@@ -117,12 +164,21 @@ function getHostname(req) {
|
|
|
117
164
|
__name(getHostname, "getHostname");
|
|
118
165
|
// Annotate the CommonJS export names for ESM import in node:
|
|
119
166
|
0 && (module.exports = {
|
|
167
|
+
DEFAULT_PORTAL_APP_NAME,
|
|
168
|
+
DEFAULT_PORTAL_NAME,
|
|
120
169
|
MODERN_CLIENT_DIST_DIR,
|
|
170
|
+
PORTAL_CLIENT_PREFIX,
|
|
171
|
+
SETTINGS_CLIENT_DIST_DIR,
|
|
121
172
|
getHost,
|
|
122
173
|
getHostname,
|
|
123
174
|
injectRuntimeScript,
|
|
124
175
|
normalizeModernClientPrefix,
|
|
176
|
+
normalizePortalAppName,
|
|
177
|
+
normalizePortalName,
|
|
178
|
+
resolvePortalPublicPath,
|
|
125
179
|
resolvePublicPath,
|
|
180
|
+
resolveSettingsPublicPath,
|
|
126
181
|
resolveV2PublicPath,
|
|
182
|
+
rewriteSettingsAssetPublicPath,
|
|
127
183
|
rewriteV2AssetPublicPath
|
|
128
184
|
});
|
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
|
|
91
|
+
const whitelist = (0, import_utils.getCorsWhitelist)();
|
|
83
92
|
if (!origin && disallowNoOrigin) {
|
|
84
93
|
return false;
|
|
85
94
|
}
|
|
86
|
-
if (
|
|
95
|
+
if (isWhitelistedCorsOrigin(ctx)) {
|
|
87
96
|
return origin;
|
|
88
97
|
}
|
|
89
|
-
|
|
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
|
|
138
|
-
|
|
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"),
|
package/lib/swagger/app.d.ts
CHANGED
|
@@ -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";
|
package/lib/swagger/app.js
CHANGED
|
@@ -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",
|
package/lib/swagger/index.d.ts
CHANGED
|
@@ -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": "
|
|
3
|
+
"version": "3.0.0-alpha.1",
|
|
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": "
|
|
14
|
-
"@nocobase/actions": "
|
|
15
|
-
"@nocobase/ai": "
|
|
16
|
-
"@nocobase/auth": "
|
|
17
|
-
"@nocobase/cache": "
|
|
18
|
-
"@nocobase/data-source-manager": "
|
|
19
|
-
"@nocobase/database": "
|
|
20
|
-
"@nocobase/evaluators": "
|
|
21
|
-
"@nocobase/lock-manager": "
|
|
22
|
-
"@nocobase/logger": "
|
|
23
|
-
"@nocobase/resourcer": "
|
|
24
|
-
"@nocobase/sdk": "
|
|
25
|
-
"@nocobase/snowflake-id": "
|
|
26
|
-
"@nocobase/telemetry": "
|
|
27
|
-
"@nocobase/utils": "
|
|
13
|
+
"@nocobase/acl": "3.0.0-alpha.1",
|
|
14
|
+
"@nocobase/actions": "3.0.0-alpha.1",
|
|
15
|
+
"@nocobase/ai": "3.0.0-alpha.1",
|
|
16
|
+
"@nocobase/auth": "3.0.0-alpha.1",
|
|
17
|
+
"@nocobase/cache": "3.0.0-alpha.1",
|
|
18
|
+
"@nocobase/data-source-manager": "3.0.0-alpha.1",
|
|
19
|
+
"@nocobase/database": "3.0.0-alpha.1",
|
|
20
|
+
"@nocobase/evaluators": "3.0.0-alpha.1",
|
|
21
|
+
"@nocobase/lock-manager": "3.0.0-alpha.1",
|
|
22
|
+
"@nocobase/logger": "3.0.0-alpha.1",
|
|
23
|
+
"@nocobase/resourcer": "3.0.0-alpha.1",
|
|
24
|
+
"@nocobase/sdk": "3.0.0-alpha.1",
|
|
25
|
+
"@nocobase/snowflake-id": "3.0.0-alpha.1",
|
|
26
|
+
"@nocobase/telemetry": "3.0.0-alpha.1",
|
|
27
|
+
"@nocobase/utils": "3.0.0-alpha.1",
|
|
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": "
|
|
64
|
+
"gitHead": "22d8be8ece179cfa5c8a4ebb2c896c92bd418e03"
|
|
65
65
|
}
|