@nocobase/server 1.6.0-alpha.2 → 1.6.0-alpha.21
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/aes-encryptor.d.ts +20 -0
- package/lib/aes-encryptor.js +126 -0
- package/lib/application.d.ts +9 -1
- package/lib/application.js +27 -2
- package/lib/audit-manager/index.js +11 -7
- package/lib/environment.d.ts +18 -0
- package/lib/environment.js +80 -0
- package/lib/gateway/index.js +43 -24
- package/lib/gateway/ws-server.d.ts +18 -2
- package/lib/gateway/ws-server.js +105 -27
- package/lib/helper.js +2 -0
- package/lib/helpers/application-version.js +1 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +4 -2
- package/lib/middlewares/data-template.js +5 -5
- package/lib/middlewares/extract-client-ip.d.ts +10 -0
- package/lib/middlewares/extract-client-ip.js +46 -0
- package/lib/middlewares/index.d.ts +1 -0
- package/lib/middlewares/index.js +3 -1
- package/lib/middlewares/validate-filter-params.d.ts +1 -1
- package/lib/middlewares/validate-filter-params.js +26 -0
- package/lib/plugin-manager/options/collection.js +1 -0
- package/lib/plugin-manager/plugin-manager.d.ts +4 -4
- package/lib/plugin-manager/plugin-manager.js +27 -15
- package/lib/service-container.d.ts +5 -0
- package/lib/service-container.js +50 -0
- package/package.json +15 -15
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
/// <reference types="node" />
|
|
10
|
+
import Application from './application';
|
|
11
|
+
export declare class AesEncryptor {
|
|
12
|
+
private key;
|
|
13
|
+
constructor(key: Buffer);
|
|
14
|
+
encrypt(text: string): Promise<string>;
|
|
15
|
+
decrypt(encryptedText: string): Promise<string>;
|
|
16
|
+
static getOrGenerateKey(keyFilePath: string): Promise<Buffer>;
|
|
17
|
+
static getKeyPath(appName: string): Promise<string>;
|
|
18
|
+
static create(app: Application): Promise<AesEncryptor>;
|
|
19
|
+
}
|
|
20
|
+
export default AesEncryptor;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(from))
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
25
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
26
|
+
}
|
|
27
|
+
return to;
|
|
28
|
+
};
|
|
29
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
30
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
31
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
32
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
33
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
34
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
35
|
+
mod
|
|
36
|
+
));
|
|
37
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
|
+
var aes_encryptor_exports = {};
|
|
39
|
+
__export(aes_encryptor_exports, {
|
|
40
|
+
AesEncryptor: () => AesEncryptor,
|
|
41
|
+
default: () => aes_encryptor_default
|
|
42
|
+
});
|
|
43
|
+
module.exports = __toCommonJS(aes_encryptor_exports);
|
|
44
|
+
var import_crypto = __toESM(require("crypto"));
|
|
45
|
+
var import_fs_extra = __toESM(require("fs-extra"));
|
|
46
|
+
var import_path = __toESM(require("path"));
|
|
47
|
+
const _AesEncryptor = class _AesEncryptor {
|
|
48
|
+
key;
|
|
49
|
+
constructor(key) {
|
|
50
|
+
if (key.length !== 32) {
|
|
51
|
+
throw new Error("Key must be 32 bytes for AES-256 encryption.");
|
|
52
|
+
}
|
|
53
|
+
this.key = key;
|
|
54
|
+
}
|
|
55
|
+
async encrypt(text) {
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
try {
|
|
58
|
+
const iv = import_crypto.default.randomBytes(16);
|
|
59
|
+
const cipher = import_crypto.default.createCipheriv("aes-256-cbc", this.key, iv);
|
|
60
|
+
const encrypted = Buffer.concat([cipher.update(Buffer.from(text, "utf8")), cipher.final()]);
|
|
61
|
+
resolve(iv.toString("hex") + encrypted.toString("hex"));
|
|
62
|
+
} catch (error) {
|
|
63
|
+
reject(error);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async decrypt(encryptedText) {
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
try {
|
|
70
|
+
const iv = Buffer.from(encryptedText.slice(0, 32), "hex");
|
|
71
|
+
const encrypted = Buffer.from(encryptedText.slice(32), "hex");
|
|
72
|
+
const decipher = import_crypto.default.createDecipheriv("aes-256-cbc", this.key, iv);
|
|
73
|
+
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
|
74
|
+
resolve(decrypted.toString("utf8"));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
reject(error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
static async getOrGenerateKey(keyFilePath) {
|
|
81
|
+
try {
|
|
82
|
+
const key = await import_fs_extra.default.readFile(keyFilePath);
|
|
83
|
+
if (key.length !== 32) {
|
|
84
|
+
throw new Error("Invalid key length in file.");
|
|
85
|
+
}
|
|
86
|
+
return key;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
if (error.code === "ENOENT") {
|
|
89
|
+
const key = import_crypto.default.randomBytes(32);
|
|
90
|
+
await import_fs_extra.default.mkdir(import_path.default.dirname(keyFilePath), { recursive: true });
|
|
91
|
+
await import_fs_extra.default.writeFile(keyFilePath, key);
|
|
92
|
+
return key;
|
|
93
|
+
} else {
|
|
94
|
+
throw new Error(`Failed to load key: ${error.message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
static async getKeyPath(appName) {
|
|
99
|
+
const appKeyPath = import_path.default.resolve(process.cwd(), "storage", "apps", appName, "aes_key.dat");
|
|
100
|
+
const appKeyExists = await import_fs_extra.default.exists(appKeyPath);
|
|
101
|
+
if (appKeyExists) {
|
|
102
|
+
return appKeyPath;
|
|
103
|
+
}
|
|
104
|
+
const envKeyPath = import_path.default.resolve(process.cwd(), "storage", "environment-variables", appName, "aes_key.dat");
|
|
105
|
+
const envKeyExists = await import_fs_extra.default.exists(envKeyPath);
|
|
106
|
+
if (envKeyExists) {
|
|
107
|
+
return envKeyPath;
|
|
108
|
+
}
|
|
109
|
+
return appKeyPath;
|
|
110
|
+
}
|
|
111
|
+
static async create(app) {
|
|
112
|
+
let key = process.env.APP_AES_SECRET_KEY;
|
|
113
|
+
if (!key) {
|
|
114
|
+
const keyPath = await this.getKeyPath(app.name);
|
|
115
|
+
key = await _AesEncryptor.getOrGenerateKey(keyPath);
|
|
116
|
+
}
|
|
117
|
+
return new _AesEncryptor(key);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
__name(_AesEncryptor, "AesEncryptor");
|
|
121
|
+
let AesEncryptor = _AesEncryptor;
|
|
122
|
+
var aes_encryptor_default = AesEncryptor;
|
|
123
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
124
|
+
0 && (module.exports = {
|
|
125
|
+
AesEncryptor
|
|
126
|
+
});
|
package/lib/application.d.ts
CHANGED
|
@@ -15,8 +15,8 @@ import Database, { CollectionOptions, IDatabaseOptions } from '@nocobase/databas
|
|
|
15
15
|
import { Logger, LoggerOptions, RequestLoggerOptions, SystemLogger, SystemLoggerOptions } from '@nocobase/logger';
|
|
16
16
|
import { ResourceOptions, Resourcer } from '@nocobase/resourcer';
|
|
17
17
|
import { Telemetry, TelemetryOptions } from '@nocobase/telemetry';
|
|
18
|
-
import { AsyncEmitter, ToposortOptions } from '@nocobase/utils';
|
|
19
18
|
import { LockManager, LockManagerOptions } from '@nocobase/lock-manager';
|
|
19
|
+
import { AsyncEmitter, ToposortOptions } from '@nocobase/utils';
|
|
20
20
|
import { Command, CommandOptions, ParseOptions } from 'commander';
|
|
21
21
|
import { IncomingMessage, ServerResponse } from 'http';
|
|
22
22
|
import { i18n, InitOptions } from 'i18next';
|
|
@@ -31,7 +31,10 @@ import { Plugin } from './plugin';
|
|
|
31
31
|
import { InstallOptions, PluginManager } from './plugin-manager';
|
|
32
32
|
import { PubSubManager, PubSubManagerOptions } from './pub-sub-manager';
|
|
33
33
|
import { SyncMessageManager } from './sync-message-manager';
|
|
34
|
+
import AesEncryptor from './aes-encryptor';
|
|
34
35
|
import { AuditManager } from './audit-manager';
|
|
36
|
+
import { Environment } from './environment';
|
|
37
|
+
import { ServiceContainer } from './service-container';
|
|
35
38
|
export type PluginType = string | typeof Plugin;
|
|
36
39
|
export type PluginConfiguration = PluginType | [PluginType, any];
|
|
37
40
|
export interface ResourceManagerOptions {
|
|
@@ -169,6 +172,7 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
|
|
|
169
172
|
private _maintainingCommandStatus;
|
|
170
173
|
private _maintainingStatusBeforeCommand;
|
|
171
174
|
private _actionCommand;
|
|
175
|
+
container: ServiceContainer;
|
|
172
176
|
lockManager: LockManager;
|
|
173
177
|
constructor(options: ApplicationOptions);
|
|
174
178
|
private static staticCommands;
|
|
@@ -193,6 +197,8 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
|
|
|
193
197
|
* @internal
|
|
194
198
|
*/
|
|
195
199
|
get maintainingMessage(): string;
|
|
200
|
+
private _env;
|
|
201
|
+
get environment(): Environment;
|
|
196
202
|
protected _cronJobManager: CronJobManager;
|
|
197
203
|
get cronJobManager(): CronJobManager;
|
|
198
204
|
get mainDataSource(): SequelizeDataSource;
|
|
@@ -238,6 +244,8 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
|
|
|
238
244
|
get name(): string;
|
|
239
245
|
protected _dataSourceManager: DataSourceManager;
|
|
240
246
|
get dataSourceManager(): DataSourceManager;
|
|
247
|
+
protected _aesEncryptor: AesEncryptor;
|
|
248
|
+
get aesEncryptor(): AesEncryptor;
|
|
241
249
|
/**
|
|
242
250
|
* @internal
|
|
243
251
|
*/
|
package/lib/application.js
CHANGED
|
@@ -49,8 +49,8 @@ var import_data_source_manager = require("@nocobase/data-source-manager");
|
|
|
49
49
|
var import_database = __toESM(require("@nocobase/database"));
|
|
50
50
|
var import_logger = require("@nocobase/logger");
|
|
51
51
|
var import_telemetry = require("@nocobase/telemetry");
|
|
52
|
-
var import_utils = require("@nocobase/utils");
|
|
53
52
|
var import_lock_manager = require("@nocobase/lock-manager");
|
|
53
|
+
var import_utils = require("@nocobase/utils");
|
|
54
54
|
var import_crypto = require("crypto");
|
|
55
55
|
var import_glob = __toESM(require("glob"));
|
|
56
56
|
var import_koa = __toESM(require("koa"));
|
|
@@ -76,7 +76,11 @@ var import_plugin_manager = require("./plugin-manager");
|
|
|
76
76
|
var import_pub_sub_manager = require("./pub-sub-manager");
|
|
77
77
|
var import_sync_message_manager = require("./sync-message-manager");
|
|
78
78
|
var import_package = __toESM(require("../package.json"));
|
|
79
|
+
var import_available_action = require("./acl/available-action");
|
|
80
|
+
var import_aes_encryptor = __toESM(require("./aes-encryptor"));
|
|
79
81
|
var import_audit_manager = require("./audit-manager");
|
|
82
|
+
var import_environment = require("./environment");
|
|
83
|
+
var import_service_container = require("./service-container");
|
|
80
84
|
const _Application = class _Application extends import_koa.default {
|
|
81
85
|
constructor(options) {
|
|
82
86
|
super();
|
|
@@ -125,6 +129,7 @@ const _Application = class _Application extends import_koa.default {
|
|
|
125
129
|
_maintainingCommandStatus;
|
|
126
130
|
_maintainingStatusBeforeCommand;
|
|
127
131
|
_actionCommand;
|
|
132
|
+
container = new import_service_container.ServiceContainer();
|
|
128
133
|
lockManager;
|
|
129
134
|
static addCommand(callback) {
|
|
130
135
|
this.staticCommands.push(callback);
|
|
@@ -161,6 +166,10 @@ const _Application = class _Application extends import_koa.default {
|
|
|
161
166
|
get maintainingMessage() {
|
|
162
167
|
return this._maintainingMessage;
|
|
163
168
|
}
|
|
169
|
+
_env;
|
|
170
|
+
get environment() {
|
|
171
|
+
return this._env;
|
|
172
|
+
}
|
|
164
173
|
_cronJobManager;
|
|
165
174
|
get cronJobManager() {
|
|
166
175
|
return this._cronJobManager;
|
|
@@ -250,6 +259,10 @@ const _Application = class _Application extends import_koa.default {
|
|
|
250
259
|
get dataSourceManager() {
|
|
251
260
|
return this._dataSourceManager;
|
|
252
261
|
}
|
|
262
|
+
_aesEncryptor;
|
|
263
|
+
get aesEncryptor() {
|
|
264
|
+
return this._aesEncryptor;
|
|
265
|
+
}
|
|
253
266
|
/**
|
|
254
267
|
* @internal
|
|
255
268
|
*/
|
|
@@ -370,7 +383,10 @@ const _Application = class _Application extends import_koa.default {
|
|
|
370
383
|
this._loaded = false;
|
|
371
384
|
}
|
|
372
385
|
async createCacheManager() {
|
|
373
|
-
this._cacheManager = await (0, import_cache2.createCacheManager)(this,
|
|
386
|
+
this._cacheManager = await (0, import_cache2.createCacheManager)(this, {
|
|
387
|
+
prefix: this.name,
|
|
388
|
+
...this.options.cacheManager
|
|
389
|
+
});
|
|
374
390
|
return this._cacheManager;
|
|
375
391
|
}
|
|
376
392
|
async load(options) {
|
|
@@ -393,6 +409,7 @@ const _Application = class _Application extends import_koa.default {
|
|
|
393
409
|
await oldDb.close();
|
|
394
410
|
}
|
|
395
411
|
}
|
|
412
|
+
this._aesEncryptor = await import_aes_encryptor.default.create(this);
|
|
396
413
|
if (this.cacheManager) {
|
|
397
414
|
await this.cacheManager.close();
|
|
398
415
|
}
|
|
@@ -830,6 +847,7 @@ const _Application = class _Application extends import_koa.default {
|
|
|
830
847
|
}
|
|
831
848
|
this.createMainDataSource(options);
|
|
832
849
|
this._cronJobManager = new import_cron_job_manager.CronJobManager(this);
|
|
850
|
+
this._env = new import_environment.Environment();
|
|
833
851
|
this._cli = this.createCLI();
|
|
834
852
|
this._i18n = (0, import_helper.createI18n)(options);
|
|
835
853
|
this.pubSubManager = (0, import_pub_sub_manager.createPubSubManager)(this, options.pubSubManager);
|
|
@@ -863,6 +881,13 @@ const _Application = class _Application extends import_koa.default {
|
|
|
863
881
|
name: "auth",
|
|
864
882
|
actions: import_auth.actions
|
|
865
883
|
});
|
|
884
|
+
this._dataSourceManager.afterAddDataSource((dataSource) => {
|
|
885
|
+
if (dataSource.collectionManager instanceof import_data_source_manager.SequelizeCollectionManager) {
|
|
886
|
+
for (const [actionName, actionParams] of Object.entries(import_available_action.availableActions)) {
|
|
887
|
+
dataSource.acl.setAvailableAction(actionName, actionParams);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
});
|
|
866
891
|
this._dataSourceManager.use(this._authManager.middleware(), { tag: "auth" });
|
|
867
892
|
this._dataSourceManager.use(import_validate_filter_params.default, { tag: "validate-filter-params", before: ["auth"] });
|
|
868
893
|
this._dataSourceManager.use(import_middlewares.parseVariables, {
|
|
@@ -260,6 +260,8 @@ const _AuditManager = class _AuditManager {
|
|
|
260
260
|
const auditLog = this.formatAuditData(ctx);
|
|
261
261
|
auditLog.uuid = reqId;
|
|
262
262
|
auditLog.status = ctx.status;
|
|
263
|
+
const defaultMetaData = await this.getDefaultMetaData(ctx);
|
|
264
|
+
auditLog.metadata = { ...metadata, ...defaultMetaData };
|
|
263
265
|
if (typeof action !== "string") {
|
|
264
266
|
if (action.getUserInfo) {
|
|
265
267
|
const userInfo = await action.getUserInfo(ctx);
|
|
@@ -274,10 +276,15 @@ const _AuditManager = class _AuditManager {
|
|
|
274
276
|
}
|
|
275
277
|
if (action.getMetaData) {
|
|
276
278
|
const extra = await action.getMetaData(ctx);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
if (extra) {
|
|
280
|
+
if (extra.request) {
|
|
281
|
+
auditLog.metadata.request = { ...auditLog.metadata.request, ...extra.request };
|
|
282
|
+
}
|
|
283
|
+
if (extra.response) {
|
|
284
|
+
auditLog.metadata.response = { ...auditLog.metadata.response, ...extra.response };
|
|
285
|
+
}
|
|
286
|
+
auditLog.metadata = { ...extra, ...auditLog.metadata };
|
|
287
|
+
}
|
|
281
288
|
}
|
|
282
289
|
if (action.getSourceAndTarget) {
|
|
283
290
|
const sourceAndTarget = await action.getSourceAndTarget(ctx);
|
|
@@ -288,9 +295,6 @@ const _AuditManager = class _AuditManager {
|
|
|
288
295
|
auditLog.targetRecordUK = sourceAndTarget.targetRecordUK;
|
|
289
296
|
}
|
|
290
297
|
}
|
|
291
|
-
} else {
|
|
292
|
-
const defaultMetaData = await this.getDefaultMetaData(ctx);
|
|
293
|
-
auditLog.metadata = { ...metadata, ...defaultMetaData };
|
|
294
298
|
}
|
|
295
299
|
this.logger.log(auditLog);
|
|
296
300
|
} catch (err) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Environment {
|
|
10
|
+
private vars;
|
|
11
|
+
setVariable(key: string, value: string): void;
|
|
12
|
+
removeVariable(key: string): void;
|
|
13
|
+
getVariablesAndSecrets(): {};
|
|
14
|
+
getVariables(): {};
|
|
15
|
+
renderJsonTemplate(template: any, options?: {
|
|
16
|
+
omit?: string[];
|
|
17
|
+
}): any;
|
|
18
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(from))
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
25
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
26
|
+
}
|
|
27
|
+
return to;
|
|
28
|
+
};
|
|
29
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
30
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
31
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
32
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
33
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
34
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
35
|
+
mod
|
|
36
|
+
));
|
|
37
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
|
+
var environment_exports = {};
|
|
39
|
+
__export(environment_exports, {
|
|
40
|
+
Environment: () => Environment
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(environment_exports);
|
|
43
|
+
var import_utils = require("@nocobase/utils");
|
|
44
|
+
var import_lodash = __toESM(require("lodash"));
|
|
45
|
+
const _Environment = class _Environment {
|
|
46
|
+
vars = {};
|
|
47
|
+
setVariable(key, value) {
|
|
48
|
+
this.vars[key] = value;
|
|
49
|
+
}
|
|
50
|
+
removeVariable(key) {
|
|
51
|
+
delete this.vars[key];
|
|
52
|
+
}
|
|
53
|
+
getVariablesAndSecrets() {
|
|
54
|
+
return this.vars;
|
|
55
|
+
}
|
|
56
|
+
getVariables() {
|
|
57
|
+
return this.vars;
|
|
58
|
+
}
|
|
59
|
+
renderJsonTemplate(template, options) {
|
|
60
|
+
if (options == null ? void 0 : options.omit) {
|
|
61
|
+
const omitTemplate = import_lodash.default.omit(template, options.omit);
|
|
62
|
+
const parsed = (0, import_utils.parse)(omitTemplate)({
|
|
63
|
+
$env: this.vars
|
|
64
|
+
});
|
|
65
|
+
for (const key of options.omit) {
|
|
66
|
+
import_lodash.default.set(parsed, key, import_lodash.default.get(template, key));
|
|
67
|
+
}
|
|
68
|
+
return parsed;
|
|
69
|
+
}
|
|
70
|
+
return (0, import_utils.parse)(template)({
|
|
71
|
+
$env: this.vars
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
__name(_Environment, "Environment");
|
|
76
|
+
let Environment = _Environment;
|
|
77
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
78
|
+
0 && (module.exports = {
|
|
79
|
+
Environment
|
|
80
|
+
});
|
package/lib/gateway/index.js
CHANGED
|
@@ -63,7 +63,17 @@ var import_errors = require("./errors");
|
|
|
63
63
|
var import_ipc_socket_client = require("./ipc-socket-client");
|
|
64
64
|
var import_ipc_socket_server = require("./ipc-socket-server");
|
|
65
65
|
var import_ws_server = require("./ws-server");
|
|
66
|
+
var import_node_worker_threads = require("node:worker_threads");
|
|
67
|
+
var import_node_process = __toESM(require("node:process"));
|
|
66
68
|
const compress = (0, import_node_util.promisify)((0, import_compression.default)());
|
|
69
|
+
function getSocketPath() {
|
|
70
|
+
const { SOCKET_PATH } = import_node_process.default.env;
|
|
71
|
+
if ((0, import_path.isAbsolute)(SOCKET_PATH)) {
|
|
72
|
+
return SOCKET_PATH;
|
|
73
|
+
}
|
|
74
|
+
return (0, import_path.resolve)(import_node_process.default.cwd(), SOCKET_PATH);
|
|
75
|
+
}
|
|
76
|
+
__name(getSocketPath, "getSocketPath");
|
|
67
77
|
const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
68
78
|
/**
|
|
69
79
|
* use main app as default app to handle request
|
|
@@ -72,16 +82,14 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
72
82
|
server = null;
|
|
73
83
|
ipcSocketServer = null;
|
|
74
84
|
loggers = new import_utils.Registry();
|
|
75
|
-
port =
|
|
85
|
+
port = import_node_process.default.env.APP_PORT ? parseInt(import_node_process.default.env.APP_PORT) : null;
|
|
76
86
|
host = "0.0.0.0";
|
|
77
87
|
wsServer;
|
|
78
|
-
socketPath = (0, import_path.resolve)(
|
|
88
|
+
socketPath = (0, import_path.resolve)(import_node_process.default.cwd(), "storage", "gateway.sock");
|
|
79
89
|
constructor() {
|
|
80
90
|
super();
|
|
81
91
|
this.reset();
|
|
82
|
-
|
|
83
|
-
this.socketPath = (0, import_path.resolve)(process.cwd(), process.env.SOCKET_PATH);
|
|
84
|
-
}
|
|
92
|
+
this.socketPath = getSocketPath();
|
|
85
93
|
}
|
|
86
94
|
static getInstance(options = {}) {
|
|
87
95
|
if (!_Gateway.instance) {
|
|
@@ -90,7 +98,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
90
98
|
return _Gateway.instance;
|
|
91
99
|
}
|
|
92
100
|
static async getIPCSocketClient() {
|
|
93
|
-
const socketPath = (
|
|
101
|
+
const socketPath = getSocketPath();
|
|
94
102
|
try {
|
|
95
103
|
return await import_ipc_socket_client.IPCSocketClient.getConnection(socketPath);
|
|
96
104
|
} catch (error) {
|
|
@@ -166,7 +174,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
166
174
|
}
|
|
167
175
|
async requestHandler(req, res) {
|
|
168
176
|
const { pathname } = (0, import_url.parse)(req.url);
|
|
169
|
-
const { PLUGIN_STATICS_PATH, APP_PUBLIC_PATH } =
|
|
177
|
+
const { PLUGIN_STATICS_PATH, APP_PUBLIC_PATH } = import_node_process.default.env;
|
|
170
178
|
if (pathname.endsWith("/__umi/api/bundle-status")) {
|
|
171
179
|
res.statusCode = 200;
|
|
172
180
|
res.end("ok");
|
|
@@ -176,7 +184,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
176
184
|
req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
|
|
177
185
|
await compress(req, res);
|
|
178
186
|
return (0, import_serve_handler.default)(req, res, {
|
|
179
|
-
public: (0, import_path.resolve)(
|
|
187
|
+
public: (0, import_path.resolve)(import_node_process.default.cwd()),
|
|
180
188
|
directoryListing: false
|
|
181
189
|
});
|
|
182
190
|
}
|
|
@@ -195,15 +203,22 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
195
203
|
]
|
|
196
204
|
});
|
|
197
205
|
}
|
|
198
|
-
if (!pathname.startsWith(
|
|
206
|
+
if (!pathname.startsWith(import_node_process.default.env.API_BASE_PATH)) {
|
|
199
207
|
req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
|
|
200
208
|
await compress(req, res);
|
|
201
209
|
return (0, import_serve_handler.default)(req, res, {
|
|
202
|
-
public: `${
|
|
210
|
+
public: `${import_node_process.default.env.APP_PACKAGE_ROOT}/dist/client`,
|
|
203
211
|
rewrites: [{ source: "/**", destination: "/index.html" }]
|
|
204
212
|
});
|
|
205
213
|
}
|
|
206
|
-
|
|
214
|
+
let handleApp = "main";
|
|
215
|
+
try {
|
|
216
|
+
handleApp = await this.getRequestHandleAppName(req);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.log(error);
|
|
219
|
+
this.responseErrorWithCode("APP_INITIALIZING", res, { appName: handleApp });
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
207
222
|
const hasApp = import_app_supervisor.AppSupervisor.getInstance().hasApp(handleApp);
|
|
208
223
|
if (!hasApp) {
|
|
209
224
|
void import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleApp);
|
|
@@ -257,10 +272,10 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
257
272
|
}
|
|
258
273
|
/* istanbul ignore next -- @preserve */
|
|
259
274
|
async watch() {
|
|
260
|
-
if (!
|
|
275
|
+
if (!import_node_process.default.env.IS_DEV_CMD) {
|
|
261
276
|
return;
|
|
262
277
|
}
|
|
263
|
-
const file =
|
|
278
|
+
const file = import_node_process.default.env.WATCH_FILE;
|
|
264
279
|
if (!import_fs.default.existsSync(file)) {
|
|
265
280
|
await import_fs.default.promises.writeFile(file, `export const watchId = '${(0, import_utils.uid)()}';`, "utf-8");
|
|
266
281
|
}
|
|
@@ -273,8 +288,8 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
273
288
|
if (isStart) {
|
|
274
289
|
await this.watch();
|
|
275
290
|
const startOptions = this.getStartOptions();
|
|
276
|
-
const port = startOptions.port ||
|
|
277
|
-
const host = startOptions.host ||
|
|
291
|
+
const port = startOptions.port || import_node_process.default.env.APP_PORT || 13e3;
|
|
292
|
+
const host = startOptions.host || import_node_process.default.env.APP_HOST || "0.0.0.0";
|
|
278
293
|
this.start({
|
|
279
294
|
port,
|
|
280
295
|
host
|
|
@@ -282,7 +297,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
282
297
|
} else if (!this.isHelp()) {
|
|
283
298
|
ipcClient = await this.tryConnectToIPCServer();
|
|
284
299
|
if (ipcClient) {
|
|
285
|
-
const response = await ipcClient.write({ type: "passCliArgv", payload: { argv:
|
|
300
|
+
const response = await ipcClient.write({ type: "passCliArgv", payload: { argv: import_node_process.default.argv } });
|
|
286
301
|
ipcClient.close();
|
|
287
302
|
if (!["error", "not_found"].includes(response.type)) {
|
|
288
303
|
return;
|
|
@@ -293,15 +308,19 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
293
308
|
await (0, import_plugin_symlink.createStoragePluginsSymlink)();
|
|
294
309
|
}
|
|
295
310
|
const mainApp = import_app_supervisor.AppSupervisor.getInstance().bootMainApp(options.mainAppOptions);
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
from: "
|
|
299
|
-
}
|
|
311
|
+
let runArgs = [import_node_process.default.argv, { throwError: true, from: "node" }];
|
|
312
|
+
if (!import_node_worker_threads.isMainThread) {
|
|
313
|
+
runArgs = [import_node_worker_threads.workerData.argv, { throwError: true, from: "user" }];
|
|
314
|
+
}
|
|
315
|
+
mainApp.runAsCLI(...runArgs).then(async () => {
|
|
300
316
|
if (!isStart && !await mainApp.isStarted()) {
|
|
301
317
|
await mainApp.stop({ logging: false });
|
|
302
318
|
}
|
|
303
319
|
}).catch(async (e) => {
|
|
304
320
|
if (e.code !== "commander.helpDisplayed") {
|
|
321
|
+
if (!import_node_worker_threads.isMainThread) {
|
|
322
|
+
throw e;
|
|
323
|
+
}
|
|
305
324
|
mainApp.log.error(e);
|
|
306
325
|
}
|
|
307
326
|
if (!isStart && !await mainApp.isStarted()) {
|
|
@@ -310,16 +329,16 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
310
329
|
});
|
|
311
330
|
}
|
|
312
331
|
isStart() {
|
|
313
|
-
const argv =
|
|
332
|
+
const argv = import_node_process.default.argv;
|
|
314
333
|
return argv[2] === "start";
|
|
315
334
|
}
|
|
316
335
|
isHelp() {
|
|
317
|
-
const argv =
|
|
336
|
+
const argv = import_node_process.default.argv;
|
|
318
337
|
return argv[2] === "help";
|
|
319
338
|
}
|
|
320
339
|
getStartOptions() {
|
|
321
340
|
const program = new import_commander.Command();
|
|
322
|
-
program.allowUnknownOption().option("-s, --silent").option("-p, --port [post]").option("-h, --host [host]").option("--db-sync").parse(
|
|
341
|
+
program.allowUnknownOption().option("-s, --silent").option("-p, --port [post]").option("-h, --host [host]").option("--db-sync").parse(import_node_process.default.argv);
|
|
323
342
|
return program.opts();
|
|
324
343
|
}
|
|
325
344
|
start(options) {
|
|
@@ -344,7 +363,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
344
363
|
this.wsServer = new import_ws_server.WSServer();
|
|
345
364
|
this.server.on("upgrade", (request, socket, head) => {
|
|
346
365
|
const { pathname } = (0, import_url.parse)(request.url);
|
|
347
|
-
if (pathname ===
|
|
366
|
+
if (pathname === import_node_process.default.env.WS_PATH) {
|
|
348
367
|
this.wsServer.wss.handleUpgrade(request, socket, head, (ws) => {
|
|
349
368
|
this.wsServer.wss.emit("connection", ws, request);
|
|
350
369
|
});
|
|
@@ -7,29 +7,45 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
/// <reference types="node" />
|
|
10
|
+
/// <reference types="node" />
|
|
10
11
|
import WebSocket from 'ws';
|
|
11
12
|
import { IncomingMessage } from 'http';
|
|
12
13
|
import { Logger } from '@nocobase/logger';
|
|
14
|
+
import EventEmitter from 'events';
|
|
13
15
|
declare class WebSocketWithId extends WebSocket {
|
|
14
16
|
id: string;
|
|
15
17
|
}
|
|
16
18
|
interface WebSocketClient {
|
|
17
19
|
ws: WebSocketWithId;
|
|
18
|
-
tags: string
|
|
20
|
+
tags: Set<string>;
|
|
19
21
|
url: string;
|
|
20
22
|
headers: any;
|
|
21
23
|
app?: string;
|
|
24
|
+
id: string;
|
|
22
25
|
}
|
|
23
|
-
export declare class WSServer {
|
|
26
|
+
export declare class WSServer extends EventEmitter {
|
|
24
27
|
wss: WebSocket.Server;
|
|
25
28
|
webSocketClients: Map<string, WebSocketClient>;
|
|
26
29
|
logger: Logger;
|
|
27
30
|
constructor();
|
|
31
|
+
bindAppWSEvents(app: any): void;
|
|
28
32
|
addNewConnection(ws: WebSocketWithId, request: IncomingMessage): WebSocketClient;
|
|
33
|
+
setClientTag(clientId: string, tagKey: string, tagValue: string): void;
|
|
34
|
+
removeClientTag(clientId: string, tagKey: string): void;
|
|
29
35
|
setClientApp(client: WebSocketClient): Promise<void>;
|
|
30
36
|
removeConnection(id: string): void;
|
|
31
37
|
sendMessageToConnection(client: WebSocketClient, sendMessage: object): void;
|
|
32
38
|
sendToConnectionsByTag(tagName: string, tagValue: string, sendMessage: object): void;
|
|
39
|
+
/**
|
|
40
|
+
* Send message to clients that match all the given tag conditions
|
|
41
|
+
* @param tags Array of tag conditions, each condition is an object with tagName and tagValue
|
|
42
|
+
* @param sendMessage Message to be sent
|
|
43
|
+
*/
|
|
44
|
+
sendToConnectionsByTags(tags: Array<{
|
|
45
|
+
tagName: string;
|
|
46
|
+
tagValue: string;
|
|
47
|
+
}>, sendMessage: object): void;
|
|
48
|
+
sendToClient(clientId: string, sendMessage: object): void;
|
|
33
49
|
loopThroughConnections(callback: (client: WebSocketClient) => void): void;
|
|
34
50
|
close(): void;
|
|
35
51
|
}
|