@nocobase/server 2.2.0-alpha.1 → 2.2.0-alpha.10
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 +12 -0
- package/lib/app-supervisor/index.js +71 -0
- package/lib/app-supervisor/main-only-adapter.d.ts +1 -0
- package/lib/app-supervisor/main-only-adapter.js +3 -0
- package/lib/app-supervisor/types.d.ts +7 -0
- 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 +5 -0
- package/lib/gateway/index.js +145 -9
- package/lib/gateway/static-file-security.js +23 -2
- package/lib/gateway/utils.d.ts +6 -0
- package/lib/gateway/utils.js +30 -0
- 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/deps.js +1 -1
- package/lib/plugin-manager/findPackageNames.js +1 -0
- package/lib/plugin-manager/options/resource.js +22 -4
- package/lib/plugin-manager/plugin-manager.js +1 -0
- package/lib/plugin.js +1 -1
- 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 +18 -18
|
@@ -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>;
|
|
@@ -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>;
|
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
|
@@ -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;
|
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) {
|
|
@@ -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(
|
|
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
|
-
|
|
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([
|
|
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,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;
|
package/lib/gateway/utils.js
CHANGED
|
@@ -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
|
|
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"),
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|
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://
|
|
279
|
+
packageJson.homepage = `https://docs.nocobase.com/${langMap[locale] || ""}plugins/${packageName}`;
|
|
280
280
|
}
|
|
281
281
|
const results = {
|
|
282
282
|
...this.options,
|
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": "2.2.0-alpha.
|
|
3
|
+
"version": "2.2.0-alpha.10",
|
|
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.
|
|
14
|
-
"@nocobase/actions": "2.2.0-alpha.
|
|
15
|
-
"@nocobase/ai": "2.2.0-alpha.
|
|
16
|
-
"@nocobase/auth": "2.2.0-alpha.
|
|
17
|
-
"@nocobase/cache": "2.2.0-alpha.
|
|
18
|
-
"@nocobase/data-source-manager": "2.2.0-alpha.
|
|
19
|
-
"@nocobase/database": "2.2.0-alpha.
|
|
20
|
-
"@nocobase/evaluators": "2.2.0-alpha.
|
|
21
|
-
"@nocobase/lock-manager": "2.2.0-alpha.
|
|
22
|
-
"@nocobase/logger": "2.2.0-alpha.
|
|
23
|
-
"@nocobase/resourcer": "2.2.0-alpha.
|
|
24
|
-
"@nocobase/sdk": "2.2.0-alpha.
|
|
25
|
-
"@nocobase/snowflake-id": "2.2.0-alpha.
|
|
26
|
-
"@nocobase/telemetry": "2.2.0-alpha.
|
|
27
|
-
"@nocobase/utils": "2.2.0-alpha.
|
|
13
|
+
"@nocobase/acl": "2.2.0-alpha.10",
|
|
14
|
+
"@nocobase/actions": "2.2.0-alpha.10",
|
|
15
|
+
"@nocobase/ai": "2.2.0-alpha.10",
|
|
16
|
+
"@nocobase/auth": "2.2.0-alpha.10",
|
|
17
|
+
"@nocobase/cache": "2.2.0-alpha.10",
|
|
18
|
+
"@nocobase/data-source-manager": "2.2.0-alpha.10",
|
|
19
|
+
"@nocobase/database": "2.2.0-alpha.10",
|
|
20
|
+
"@nocobase/evaluators": "2.2.0-alpha.10",
|
|
21
|
+
"@nocobase/lock-manager": "2.2.0-alpha.10",
|
|
22
|
+
"@nocobase/logger": "2.2.0-alpha.10",
|
|
23
|
+
"@nocobase/resourcer": "2.2.0-alpha.10",
|
|
24
|
+
"@nocobase/sdk": "2.2.0-alpha.10",
|
|
25
|
+
"@nocobase/snowflake-id": "2.2.0-alpha.10",
|
|
26
|
+
"@nocobase/telemetry": "2.2.0-alpha.10",
|
|
27
|
+
"@nocobase/utils": "2.2.0-alpha.10",
|
|
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.
|
|
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": "
|
|
64
|
+
"gitHead": "b5a3f131bb0a4a2fbfd96852896bccadc933d834"
|
|
65
65
|
}
|