lupine.api 1.1.58 → 1.1.59
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/README.md +3 -3
- package/admin/admin-about.tsx +12 -16
- package/admin/admin-config.tsx +47 -44
- package/admin/admin-css.tsx +3 -3
- package/admin/admin-db.tsx +75 -75
- package/admin/admin-frame-helper.tsx +364 -364
- package/admin/admin-frame.tsx +164 -164
- package/admin/admin-index.tsx +65 -65
- package/admin/admin-login.tsx +111 -111
- package/admin/admin-menu-edit.tsx +637 -637
- package/admin/admin-menu-list.tsx +87 -87
- package/admin/admin-page-edit.tsx +564 -564
- package/admin/admin-page-list.tsx +83 -83
- package/admin/admin-performance.tsx +28 -28
- package/admin/admin-release.tsx +427 -426
- package/admin/admin-resources.tsx +382 -382
- package/admin/admin-shell.tsx +89 -89
- package/admin/admin-table-data.tsx +146 -146
- package/admin/admin-table-list.tsx +230 -230
- package/admin/admin-test-animations.tsx +395 -395
- package/admin/admin-test-component.tsx +823 -808
- package/admin/admin-test-edit.tsx +319 -319
- package/admin/admin-test-themes.tsx +56 -56
- package/admin/admin-tokens.tsx +338 -338
- package/admin/design/admin-design.tsx +174 -174
- package/admin/design/block-grid.tsx +36 -36
- package/admin/design/block-grid1.tsx +21 -21
- package/admin/design/block-paragraph.tsx +19 -19
- package/admin/design/block-title.tsx +19 -19
- package/admin/design/design-block-box.tsx +140 -140
- package/admin/design/drag-data.tsx +24 -24
- package/admin/index.ts +9 -9
- package/admin/package.json +15 -15
- package/admin/tsconfig.json +127 -127
- package/dev/copy-folder.js +32 -32
- package/dev/cp-index-html.js +69 -69
- package/dev/file-utils.js +12 -12
- package/dev/index.js +18 -19
- package/dev/package.json +12 -12
- package/dev/plugin-ifelse.js +168 -168
- package/dev/plugin-ifelse.test.js +37 -37
- package/dev/run-cmd.js +14 -14
- package/dev/send-request.js +12 -12
- package/package.json +55 -55
- package/src/admin-api/admin-api-helper.ts +210 -205
- package/src/admin-api/admin-api.ts +65 -65
- package/src/admin-api/admin-auth.ts +152 -146
- package/src/admin-api/admin-config.ts +94 -84
- package/src/admin-api/admin-csv.ts +94 -94
- package/src/admin-api/admin-db.ts +269 -269
- package/src/admin-api/admin-menu.ts +135 -135
- package/src/admin-api/admin-page.ts +135 -135
- package/src/admin-api/admin-performance.ts +128 -128
- package/src/admin-api/admin-release.ts +703 -700
- package/src/admin-api/admin-resources.ts +318 -318
- package/src/admin-api/admin-token-helper.ts +82 -79
- package/src/admin-api/admin-tokens.ts +90 -90
- package/src/admin-api/index.ts +2 -2
- package/src/admin-api/web-config-api.ts +19 -19
- package/src/api/api-cache.ts +103 -103
- package/src/api/api-helper.ts +44 -44
- package/src/api/api-module.ts +67 -60
- package/src/api/api-router.ts +177 -177
- package/src/api/api-shared-storage.ts +64 -64
- package/src/api/async-storage.ts +5 -5
- package/src/api/debug-service.ts +56 -56
- package/src/api/encode-html.ts +27 -27
- package/src/api/handle-status.ts +75 -75
- package/src/api/index.ts +15 -16
- package/src/api/mini-web-socket.ts +270 -270
- package/src/api/server-content-type.ts +82 -82
- package/src/api/server-render.ts +235 -215
- package/src/api/shell-service.ts +74 -74
- package/src/api/simple-storage.ts +80 -80
- package/src/api/static-server.ts +128 -125
- package/src/api/to-client-delivery.ts +26 -26
- package/src/app/app-cache.ts +55 -55
- package/src/app/app-helper.ts +62 -62
- package/src/app/app-message.ts +109 -109
- package/src/app/app-shared-storage.ts +363 -363
- package/src/app/app-start.ts +136 -136
- package/src/app/cleanup-exit.ts +16 -16
- package/src/app/host-to-path.ts +38 -38
- package/src/app/index.ts +11 -11
- package/src/app/process-dev-requests.ts +130 -130
- package/src/app/web-listener.ts +294 -294
- package/src/app/web-processor.ts +47 -42
- package/src/app/web-server.ts +100 -100
- package/src/common-js/web-env.js +104 -104
- package/src/index.ts +7 -7
- package/src/lang/api-lang-en.ts +26 -26
- package/src/lang/api-lang-zh-cn.ts +27 -27
- package/src/lang/index.ts +2 -2
- package/src/lang/lang-helper.ts +76 -76
- package/src/lang/lang-props.ts +6 -6
- package/src/lib/db/db-helper.ts +23 -23
- package/src/lib/db/db-mysql.ts +249 -250
- package/src/lib/db/db-sqlite.ts +101 -101
- package/src/lib/db/db.spec.ts +28 -28
- package/src/lib/db/db.ts +325 -325
- package/src/lib/db/index.ts +5 -5
- package/src/lib/index.ts +3 -3
- package/src/lib/logger.spec.ts +214 -214
- package/src/lib/logger.ts +281 -281
- package/src/lib/runtime-require.ts +37 -37
- package/src/lib/utils/cookie-util.ts +34 -34
- package/src/lib/utils/crypto.ts +58 -58
- package/src/lib/utils/date-utils.ts +317 -317
- package/src/lib/utils/deep-merge.ts +37 -37
- package/src/lib/utils/delay.ts +12 -12
- package/src/lib/utils/file-setting.ts +55 -55
- package/src/lib/utils/format-bytes.ts +11 -11
- package/src/lib/utils/fs-utils.ts +158 -158
- package/src/lib/utils/get-env.ts +27 -27
- package/src/lib/utils/index.ts +12 -12
- package/src/lib/utils/is-type.ts +48 -48
- package/src/lib/utils/load-env.ts +14 -14
- package/src/lib/utils/pad.ts +6 -6
- package/src/models/api-base.ts +5 -5
- package/src/models/api-module-props.ts +10 -11
- package/src/models/api-router-props.ts +26 -26
- package/src/models/app-cache-props.ts +33 -33
- package/src/models/app-data-props.ts +10 -10
- package/src/models/app-helper-props.ts +6 -6
- package/src/models/app-shared-storage-props.ts +38 -38
- package/src/models/app-start-props.ts +18 -18
- package/src/models/async-storage-props.ts +13 -13
- package/src/models/db-config.ts +30 -30
- package/src/models/host-to-path-props.ts +12 -12
- package/src/models/index.ts +16 -16
- package/src/models/json-object.ts +8 -8
- package/src/models/locals-props.ts +36 -36
- package/src/models/logger-props.ts +84 -84
- package/src/models/simple-storage-props.ts +13 -14
- package/src/models/to-client-delivery-props.ts +6 -6
- package/tsconfig.json +115 -115
- package/dev/plugin-gen-versions.js +0 -20
package/src/app/web-processor.ts
CHANGED
|
@@ -1,42 +1,47 @@
|
|
|
1
|
-
import { ServerResponse } from 'http';
|
|
2
|
-
import { Logger } from '../lib/logger';
|
|
3
|
-
import { handler404 } from '../api';
|
|
4
|
-
import { ApiRouterCallback, AppCacheKeys, AsyncStorageProps, getAppCache, ServerRequest } from '../models';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
static
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
WebProcessor.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
import { ServerResponse } from 'http';
|
|
2
|
+
import { Logger } from '../lib/logger';
|
|
3
|
+
import { handler404 } from '../api';
|
|
4
|
+
import { ApiRouterCallback, AppCacheKeys, AsyncStorageProps, getAppCache, ServerRequest } from '../models';
|
|
5
|
+
import { processRestartApp } from './process-dev-requests';
|
|
6
|
+
const logger = new Logger('web-processor');
|
|
7
|
+
|
|
8
|
+
export class WebProcessor {
|
|
9
|
+
static debugPath: string | undefined;
|
|
10
|
+
static debugHandler: ApiRouterCallback | undefined;
|
|
11
|
+
|
|
12
|
+
static enableDebug(path: string, debugHandler: ApiRouterCallback) {
|
|
13
|
+
WebProcessor.debugPath = path;
|
|
14
|
+
WebProcessor.debugHandler = debugHandler;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async processRequest(store: AsyncStorageProps, req: ServerRequest, res: ServerResponse) {
|
|
18
|
+
if (WebProcessor.debugPath && req.locals.urlWithoutQuery.startsWith(WebProcessor.debugPath)) {
|
|
19
|
+
if (WebProcessor.debugHandler) {
|
|
20
|
+
await WebProcessor.debugHandler(req, res, req.locals.urlWithoutQuery);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// check if the request is handled by the api
|
|
26
|
+
try {
|
|
27
|
+
const _lupineApi = getAppCache().get(store.appName, AppCacheKeys.API_MODULE);
|
|
28
|
+
if (_lupineApi && _lupineApi.processApi) {
|
|
29
|
+
const result = await _lupineApi.processApi(store, store.locals.urlWithoutQuery, req, res);
|
|
30
|
+
if (result) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
logger.error(`url: ${store.locals.url}, appName: ${store.appName}, no api module found`);
|
|
35
|
+
}
|
|
36
|
+
} catch (e: any) {
|
|
37
|
+
logger.error(`url: ${store.locals.url}, appName: ${store.appName}, process api error: `, e.message);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// rescue
|
|
41
|
+
if (req.locals.urlWithoutQuery.startsWith('/admin_dev')) {
|
|
42
|
+
await processRestartApp();
|
|
43
|
+
}
|
|
44
|
+
handler404(res, `Request is not processed, url: ${req.locals.url}`);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/app/web-server.ts
CHANGED
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
import { ServerOptions } from 'https';
|
|
2
|
-
import { Logger } from '../lib/logger';
|
|
3
|
-
import { WebListener } from './web-listener';
|
|
4
|
-
import * as fs from 'fs';
|
|
5
|
-
import * as http from 'http';
|
|
6
|
-
import * as https from 'https';
|
|
7
|
-
import { IncomingMessage, ServerResponse } from 'http';
|
|
8
|
-
import { Duplex } from 'stream';
|
|
9
|
-
import { WebProcessor } from './web-processor';
|
|
10
|
-
import { DebugService } from '../api/debug-service';
|
|
11
|
-
import cluster from 'cluster';
|
|
12
|
-
const logger = new Logger('web-server');
|
|
13
|
-
|
|
14
|
-
export class WebServer {
|
|
15
|
-
webListener: WebListener;
|
|
16
|
-
constructor(webListener?: WebListener) {
|
|
17
|
-
this.webListener = webListener || new WebListener(new WebProcessor());
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
handleUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer) {
|
|
21
|
-
const clientIp = `${(socket as any).remoteAddress}:${(socket as any).remotePort}`;
|
|
22
|
-
if (req.url?.startsWith('/debug') && socket.readable && socket.writable) {
|
|
23
|
-
logger.debug(`Upgrade WebSocket access: ${req.url} from ${clientIp}.`);
|
|
24
|
-
DebugService.handleUpgrade(req, socket, head);
|
|
25
|
-
} else {
|
|
26
|
-
logger.error(`Unexpected web socket access: ${req.url} from ${clientIp}`);
|
|
27
|
-
socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
|
|
28
|
-
socket.destroy();
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async listenerWrap(reqOrigin: IncomingMessage, res: ServerResponse) {
|
|
33
|
-
try {
|
|
34
|
-
await this.webListener.listener.bind(this.webListener)(reqOrigin, res);
|
|
35
|
-
} catch (err) {
|
|
36
|
-
console.error('Request error:', err);
|
|
37
|
-
if (!res.headersSent) {
|
|
38
|
-
res.statusCode = 500;
|
|
39
|
-
res.end('Internal Server Error');
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
startHttp(httpPort: number, bindIp?: string, timeout?: number) {
|
|
45
|
-
const httpServer = http.createServer(this.listenerWrap.bind(this));
|
|
46
|
-
if (typeof timeout === 'number') httpServer.setTimeout(timeout);
|
|
47
|
-
|
|
48
|
-
httpServer.on('upgrade', this.handleUpgrade.bind(this));
|
|
49
|
-
|
|
50
|
-
httpServer.listen(httpPort, bindIp, () => {
|
|
51
|
-
logger.info(`Http Server ${cluster.worker ? cluster.worker.id : -1} is started: http://localhost:${httpPort}`);
|
|
52
|
-
});
|
|
53
|
-
httpServer.on('error', (error: any) => {
|
|
54
|
-
logger.error('Error occurred on http server', error);
|
|
55
|
-
});
|
|
56
|
-
return httpServer;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// multi domain https hosting
|
|
60
|
-
// https://stackoverflow.com/questions/38162077/expressjs-multi-domain-https-hosting
|
|
61
|
-
startHttps(httpsPort: number, bindIp?: string, sslKeyPath?: string, sslCrtPath?: string, timeout?: number) {
|
|
62
|
-
const httpsOptions: ServerOptions = {};
|
|
63
|
-
if (sslKeyPath && fs.existsSync(sslKeyPath) && sslCrtPath && fs.existsSync(sslCrtPath)) {
|
|
64
|
-
logger.info('Load site ssl certificate.');
|
|
65
|
-
// The options to https.createServer must include key and cert as they are required.
|
|
66
|
-
// Even though that set won't be used if SNI provides a hostname.
|
|
67
|
-
httpsOptions['key'] = fs.readFileSync(sslKeyPath, 'utf8');
|
|
68
|
-
httpsOptions['cert'] = fs.readFileSync(sslCrtPath, 'utf8');
|
|
69
|
-
// httpsOptions['ca'] = 'pem';
|
|
70
|
-
// httpsOptions['SNICallback'] = function (domain, cb) {
|
|
71
|
-
// if (typeof sites[domain] === "undefined") {
|
|
72
|
-
// cb(new Error("domain not found"), null);
|
|
73
|
-
// console.log("Error: domain not found: " + domain);
|
|
74
|
-
|
|
75
|
-
// } else {
|
|
76
|
-
// cb(null, sites[domain].context);
|
|
77
|
-
// }
|
|
78
|
-
// };
|
|
79
|
-
} else {
|
|
80
|
-
logger.warn(
|
|
81
|
-
`Ssl certificate is not defined or doesn't exist, key file: ${sslKeyPath}, certificate file: ${sslCrtPath}`
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const httpsServer = https.createServer(httpsOptions, this.listenerWrap.bind(this));
|
|
86
|
-
httpsServer.on('upgrade', this.handleUpgrade.bind(this));
|
|
87
|
-
|
|
88
|
-
if (typeof timeout === 'number') {
|
|
89
|
-
httpsServer.setTimeout(timeout);
|
|
90
|
-
}
|
|
91
|
-
httpsServer.listen(httpsPort, bindIp, () => {
|
|
92
|
-
logger.info(`Https Server ${cluster.worker ? cluster.worker.id : -1} is started: https://localhost:${httpsPort}`);
|
|
93
|
-
});
|
|
94
|
-
httpsServer.on('error', (error: any) => {
|
|
95
|
-
logger.error('Error occurred on https server', error);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
return httpsServer;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
1
|
+
import { ServerOptions } from 'https';
|
|
2
|
+
import { Logger } from '../lib/logger';
|
|
3
|
+
import { WebListener } from './web-listener';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as http from 'http';
|
|
6
|
+
import * as https from 'https';
|
|
7
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
8
|
+
import { Duplex } from 'stream';
|
|
9
|
+
import { WebProcessor } from './web-processor';
|
|
10
|
+
import { DebugService } from '../api/debug-service';
|
|
11
|
+
import cluster from 'cluster';
|
|
12
|
+
const logger = new Logger('web-server');
|
|
13
|
+
|
|
14
|
+
export class WebServer {
|
|
15
|
+
webListener: WebListener;
|
|
16
|
+
constructor(webListener?: WebListener) {
|
|
17
|
+
this.webListener = webListener || new WebListener(new WebProcessor());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
handleUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer) {
|
|
21
|
+
const clientIp = `${(socket as any).remoteAddress}:${(socket as any).remotePort}`;
|
|
22
|
+
if (req.url?.startsWith('/debug') && socket.readable && socket.writable) {
|
|
23
|
+
logger.debug(`Upgrade WebSocket access: ${req.url} from ${clientIp}.`);
|
|
24
|
+
DebugService.handleUpgrade(req, socket, head);
|
|
25
|
+
} else {
|
|
26
|
+
logger.error(`Unexpected web socket access: ${req.url} from ${clientIp}`);
|
|
27
|
+
socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
|
|
28
|
+
socket.destroy();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async listenerWrap(reqOrigin: IncomingMessage, res: ServerResponse) {
|
|
33
|
+
try {
|
|
34
|
+
await this.webListener.listener.bind(this.webListener)(reqOrigin, res);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error('Request error:', err);
|
|
37
|
+
if (!res.headersSent) {
|
|
38
|
+
res.statusCode = 500;
|
|
39
|
+
res.end('Internal Server Error');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
startHttp(httpPort: number, bindIp?: string, timeout?: number) {
|
|
45
|
+
const httpServer = http.createServer(this.listenerWrap.bind(this));
|
|
46
|
+
if (typeof timeout === 'number') httpServer.setTimeout(timeout);
|
|
47
|
+
|
|
48
|
+
httpServer.on('upgrade', this.handleUpgrade.bind(this));
|
|
49
|
+
|
|
50
|
+
httpServer.listen(httpPort, bindIp, () => {
|
|
51
|
+
logger.info(`Http Server ${cluster.worker ? cluster.worker.id : -1} is started: http://localhost:${httpPort}`);
|
|
52
|
+
});
|
|
53
|
+
httpServer.on('error', (error: any) => {
|
|
54
|
+
logger.error('Error occurred on http server', error);
|
|
55
|
+
});
|
|
56
|
+
return httpServer;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// multi domain https hosting
|
|
60
|
+
// https://stackoverflow.com/questions/38162077/expressjs-multi-domain-https-hosting
|
|
61
|
+
startHttps(httpsPort: number, bindIp?: string, sslKeyPath?: string, sslCrtPath?: string, timeout?: number) {
|
|
62
|
+
const httpsOptions: ServerOptions = {};
|
|
63
|
+
if (sslKeyPath && fs.existsSync(sslKeyPath) && sslCrtPath && fs.existsSync(sslCrtPath)) {
|
|
64
|
+
logger.info('Load site ssl certificate.');
|
|
65
|
+
// The options to https.createServer must include key and cert as they are required.
|
|
66
|
+
// Even though that set won't be used if SNI provides a hostname.
|
|
67
|
+
httpsOptions['key'] = fs.readFileSync(sslKeyPath, 'utf8');
|
|
68
|
+
httpsOptions['cert'] = fs.readFileSync(sslCrtPath, 'utf8');
|
|
69
|
+
// httpsOptions['ca'] = 'pem';
|
|
70
|
+
// httpsOptions['SNICallback'] = function (domain, cb) {
|
|
71
|
+
// if (typeof sites[domain] === "undefined") {
|
|
72
|
+
// cb(new Error("domain not found"), null);
|
|
73
|
+
// console.log("Error: domain not found: " + domain);
|
|
74
|
+
|
|
75
|
+
// } else {
|
|
76
|
+
// cb(null, sites[domain].context);
|
|
77
|
+
// }
|
|
78
|
+
// };
|
|
79
|
+
} else {
|
|
80
|
+
logger.warn(
|
|
81
|
+
`Ssl certificate is not defined or doesn't exist, key file: ${sslKeyPath}, certificate file: ${sslCrtPath}`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const httpsServer = https.createServer(httpsOptions, this.listenerWrap.bind(this));
|
|
86
|
+
httpsServer.on('upgrade', this.handleUpgrade.bind(this));
|
|
87
|
+
|
|
88
|
+
if (typeof timeout === 'number') {
|
|
89
|
+
httpsServer.setTimeout(timeout);
|
|
90
|
+
}
|
|
91
|
+
httpsServer.listen(httpsPort, bindIp, () => {
|
|
92
|
+
logger.info(`Https Server ${cluster.worker ? cluster.worker.id : -1} is started: https://localhost:${httpsPort}`);
|
|
93
|
+
});
|
|
94
|
+
httpsServer.on('error', (error: any) => {
|
|
95
|
+
logger.error('Error occurred on https server', error);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return httpsServer;
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/common-js/web-env.js
CHANGED
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
// This file is defined as CommonJS module, because it's used in dev as well
|
|
2
|
-
const fs = require('fs/promises');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
exports.readFile = async (filePath) => {
|
|
6
|
-
try {
|
|
7
|
-
const text = await fs.readFile(filePath, 'utf-8');
|
|
8
|
-
return text;
|
|
9
|
-
} catch {
|
|
10
|
-
return undefined;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
exports.parseEnv = async (envFile) => {
|
|
15
|
-
let obj = {};
|
|
16
|
-
const text = await exports.readFile(envFile);
|
|
17
|
-
if (!text) {
|
|
18
|
-
return obj;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
let lines = text.replace(/\r\n?/gm, '\n').split('\n');
|
|
22
|
-
for (let i = 0; i < lines.length; i++) {
|
|
23
|
-
const line = lines[i].split(/=(.*)/s);
|
|
24
|
-
const key = line[0].trim();
|
|
25
|
-
|
|
26
|
-
if (key && !key.startsWith('#')) {
|
|
27
|
-
if (key.endsWith('+')) {
|
|
28
|
-
// if the line is like [key+=...] then it will be added to the same key
|
|
29
|
-
obj[key.substring(0, key.length - 1)] += line[1] || '';
|
|
30
|
-
} else if (key.endsWith('*')) {
|
|
31
|
-
// if the line is like [key*=LINE_MARKER] then it's a multiline string, ending with "LINE_MARKER"
|
|
32
|
-
const LINE_MARKER = line[1].trim();
|
|
33
|
-
line[1] = '';
|
|
34
|
-
for (i++; i < lines.length; i++) {
|
|
35
|
-
if (lines[i].trim() === LINE_MARKER) {
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
line[1] += lines[i] + '\n';
|
|
39
|
-
}
|
|
40
|
-
obj[key.substring(0, key.length - 1)] = line[1];
|
|
41
|
-
} else {
|
|
42
|
-
obj[key] = line[1] || ''; // .replace(/\\n/g, '\n').replace(/\\r/g, '\r')
|
|
43
|
-
}
|
|
44
|
-
} else if (key.startsWith('#!import ')) {
|
|
45
|
-
// use "#!import file_name" to import another env file
|
|
46
|
-
const file = key.substring(9).trim();
|
|
47
|
-
const newObj = await exports.parseEnv(path.join(path.dirname(envFile), file));
|
|
48
|
-
obj = Object.assign(obj, newObj);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return obj;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
exports.copyToProcessEnv = (envObject, overrideEnv) => {
|
|
56
|
-
for (const key of Object.keys(envObject)) {
|
|
57
|
-
if (overrideEnv || typeof process.env[key] === 'undefined') {
|
|
58
|
-
process.env[key] = envObject[key];
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
exports.loadEnv = async (envFile, overrideEnv = false) => {
|
|
64
|
-
console.log(`Load env from: ${envFile}`);
|
|
65
|
-
const envObject = await exports.parseEnv(envFile);
|
|
66
|
-
exports.copyToProcessEnv(envObject, overrideEnv);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
exports.getWebEnv = (appName) => {
|
|
70
|
-
const envWeb = {};
|
|
71
|
-
for (const envName in process.env) {
|
|
72
|
-
if (envName.startsWith(`WEB.`)) {
|
|
73
|
-
envWeb[envName.substring(4)] = process.env[envName];
|
|
74
|
-
} else if (envName.startsWith(`${appName}.WEB.`)) {
|
|
75
|
-
envWeb[envName.substring(appName.length + 5)] = process.env[envName];
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return envWeb;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// defined app-shared-storage-props.ts
|
|
82
|
-
const AppSharedStorageWebPrefix = 'WEB.';
|
|
83
|
-
exports.getWebConfig = (allConfig) => {
|
|
84
|
-
const result = {};
|
|
85
|
-
for (let key in allConfig) {
|
|
86
|
-
if (key.startsWith(AppSharedStorageWebPrefix)) {
|
|
87
|
-
result[key.substring(AppSharedStorageWebPrefix.length)] = allConfig[key];
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return result;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// // Replace <!--META-ENV-START-->...<!--META-ENV-END--> for mobile app and replace it again for web app
|
|
94
|
-
// exports.replaceWebEnv = (html, appName, addMetaTag) => {
|
|
95
|
-
// const envWeb = exports.getWebEnv(appName);
|
|
96
|
-
// return html.replace(
|
|
97
|
-
// /\<\!--META-ENV-START--\>(.*?)\<\!--META-ENV-END--\>/gm,
|
|
98
|
-
// addMetaTag
|
|
99
|
-
// ? '<!--META-ENV-START--><script id="web-env" type="application/json">' +
|
|
100
|
-
// JSON.stringify(envWeb) +
|
|
101
|
-
// '</script><!--META-ENV-END-->'
|
|
102
|
-
// : '<script id="web-env" type="application/json">' + JSON.stringify(envWeb) + '</script>'
|
|
103
|
-
// );
|
|
104
|
-
// };
|
|
1
|
+
// This file is defined as CommonJS module, because it's used in dev as well
|
|
2
|
+
const fs = require('fs/promises');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
exports.readFile = async (filePath) => {
|
|
6
|
+
try {
|
|
7
|
+
const text = await fs.readFile(filePath, 'utf-8');
|
|
8
|
+
return text;
|
|
9
|
+
} catch {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
exports.parseEnv = async (envFile) => {
|
|
15
|
+
let obj = {};
|
|
16
|
+
const text = await exports.readFile(envFile);
|
|
17
|
+
if (!text) {
|
|
18
|
+
return obj;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let lines = text.replace(/\r\n?/gm, '\n').split('\n');
|
|
22
|
+
for (let i = 0; i < lines.length; i++) {
|
|
23
|
+
const line = lines[i].split(/=(.*)/s);
|
|
24
|
+
const key = line[0].trim();
|
|
25
|
+
|
|
26
|
+
if (key && !key.startsWith('#')) {
|
|
27
|
+
if (key.endsWith('+')) {
|
|
28
|
+
// if the line is like [key+=...] then it will be added to the same key
|
|
29
|
+
obj[key.substring(0, key.length - 1)] += line[1] || '';
|
|
30
|
+
} else if (key.endsWith('*')) {
|
|
31
|
+
// if the line is like [key*=LINE_MARKER] then it's a multiline string, ending with "LINE_MARKER"
|
|
32
|
+
const LINE_MARKER = line[1].trim();
|
|
33
|
+
line[1] = '';
|
|
34
|
+
for (i++; i < lines.length; i++) {
|
|
35
|
+
if (lines[i].trim() === LINE_MARKER) {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
line[1] += lines[i] + '\n';
|
|
39
|
+
}
|
|
40
|
+
obj[key.substring(0, key.length - 1)] = line[1];
|
|
41
|
+
} else {
|
|
42
|
+
obj[key] = line[1] || ''; // .replace(/\\n/g, '\n').replace(/\\r/g, '\r')
|
|
43
|
+
}
|
|
44
|
+
} else if (key.startsWith('#!import ')) {
|
|
45
|
+
// use "#!import file_name" to import another env file
|
|
46
|
+
const file = key.substring(9).trim();
|
|
47
|
+
const newObj = await exports.parseEnv(path.join(path.dirname(envFile), file));
|
|
48
|
+
obj = Object.assign(obj, newObj);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return obj;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
exports.copyToProcessEnv = (envObject, overrideEnv) => {
|
|
56
|
+
for (const key of Object.keys(envObject)) {
|
|
57
|
+
if (overrideEnv || typeof process.env[key] === 'undefined') {
|
|
58
|
+
process.env[key] = envObject[key];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
exports.loadEnv = async (envFile, overrideEnv = false) => {
|
|
64
|
+
console.log(`Load env from: ${envFile}`);
|
|
65
|
+
const envObject = await exports.parseEnv(envFile);
|
|
66
|
+
exports.copyToProcessEnv(envObject, overrideEnv);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
exports.getWebEnv = (appName) => {
|
|
70
|
+
const envWeb = {};
|
|
71
|
+
for (const envName in process.env) {
|
|
72
|
+
if (envName.startsWith(`WEB.`)) {
|
|
73
|
+
envWeb[envName.substring(4)] = process.env[envName];
|
|
74
|
+
} else if (envName.startsWith(`${appName}.WEB.`)) {
|
|
75
|
+
envWeb[envName.substring(appName.length + 5)] = process.env[envName];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return envWeb;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// defined app-shared-storage-props.ts
|
|
82
|
+
const AppSharedStorageWebPrefix = 'WEB.';
|
|
83
|
+
exports.getWebConfig = (allConfig) => {
|
|
84
|
+
const result = {};
|
|
85
|
+
for (let key in allConfig) {
|
|
86
|
+
if (key.startsWith(AppSharedStorageWebPrefix)) {
|
|
87
|
+
result[key.substring(AppSharedStorageWebPrefix.length)] = allConfig[key];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// // Replace <!--META-ENV-START-->...<!--META-ENV-END--> for mobile app and replace it again for web app
|
|
94
|
+
// exports.replaceWebEnv = (html, appName, addMetaTag) => {
|
|
95
|
+
// const envWeb = exports.getWebEnv(appName);
|
|
96
|
+
// return html.replace(
|
|
97
|
+
// /\<\!--META-ENV-START--\>(.*?)\<\!--META-ENV-END--\>/gm,
|
|
98
|
+
// addMetaTag
|
|
99
|
+
// ? '<!--META-ENV-START--><script id="web-env" type="application/json">' +
|
|
100
|
+
// JSON.stringify(envWeb) +
|
|
101
|
+
// '</script><!--META-ENV-END-->'
|
|
102
|
+
// : '<script id="web-env" type="application/json">' + JSON.stringify(envWeb) + '</script>'
|
|
103
|
+
// );
|
|
104
|
+
// };
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from './models';
|
|
2
|
-
export * from './lib';
|
|
3
|
-
export * from './lang';
|
|
4
|
-
|
|
5
|
-
export * from './admin-api';
|
|
6
|
-
export * from './api';
|
|
7
|
-
export * from './app';
|
|
1
|
+
export * from './models';
|
|
2
|
+
export * from './lib';
|
|
3
|
+
export * from './lang';
|
|
4
|
+
|
|
5
|
+
export * from './admin-api';
|
|
6
|
+
export * from './api';
|
|
7
|
+
export * from './app';
|
package/src/lang/api-lang-en.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import { OneLangProps } from './lang-props';
|
|
2
|
-
|
|
3
|
-
export const apiLangEn: OneLangProps = {
|
|
4
|
-
langName: 'en',
|
|
5
|
-
langs: {
|
|
6
|
-
'shared:operation_success': 'Operation success',
|
|
7
|
-
'shared:operation_error': 'Operation error',
|
|
8
|
-
|
|
9
|
-
'shared:wrong_data': 'Wrong data.',
|
|
10
|
-
'shared:permission_denied': 'Permission denied.',
|
|
11
|
-
'shared:name_not_existed': '{name} not existed.',
|
|
12
|
-
'shared:name_not_set': '{name} not set.',
|
|
13
|
-
'shared:name_is_wrong': '{name} is wrong.',
|
|
14
|
-
|
|
15
|
-
'shared:login_success': 'Logged in.',
|
|
16
|
-
'shared:login_failed': 'Login failed.',
|
|
17
|
-
'shared:not_logged_in': 'Not logged in.',
|
|
18
|
-
|
|
19
|
-
'shared:user_not_found': 'User not found.',
|
|
20
|
-
'shared:user_locked': 'User locked.',
|
|
21
|
-
|
|
22
|
-
'shared:not_found_file': 'File {fileName} is not found.',
|
|
23
|
-
|
|
24
|
-
'shared:wrong_hash': 'Wrong hash.',
|
|
25
|
-
},
|
|
26
|
-
};
|
|
1
|
+
import { OneLangProps } from './lang-props';
|
|
2
|
+
|
|
3
|
+
export const apiLangEn: OneLangProps = {
|
|
4
|
+
langName: 'en',
|
|
5
|
+
langs: {
|
|
6
|
+
'shared:operation_success': 'Operation success',
|
|
7
|
+
'shared:operation_error': 'Operation error',
|
|
8
|
+
|
|
9
|
+
'shared:wrong_data': 'Wrong data.',
|
|
10
|
+
'shared:permission_denied': 'Permission denied.',
|
|
11
|
+
'shared:name_not_existed': '{name} not existed.',
|
|
12
|
+
'shared:name_not_set': '{name} not set.',
|
|
13
|
+
'shared:name_is_wrong': '{name} is wrong.',
|
|
14
|
+
|
|
15
|
+
'shared:login_success': 'Logged in.',
|
|
16
|
+
'shared:login_failed': 'Login failed.',
|
|
17
|
+
'shared:not_logged_in': 'Not logged in.',
|
|
18
|
+
|
|
19
|
+
'shared:user_not_found': 'User not found.',
|
|
20
|
+
'shared:user_locked': 'User locked.',
|
|
21
|
+
|
|
22
|
+
'shared:not_found_file': 'File {fileName} is not found.',
|
|
23
|
+
|
|
24
|
+
'shared:wrong_hash': 'Wrong hash.',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { OneLangProps } from './lang-props';
|
|
2
|
-
|
|
3
|
-
export const apiLangZhCn: OneLangProps = {
|
|
4
|
-
langName: 'zh-cn',
|
|
5
|
-
langs: {
|
|
6
|
-
'shared:operation_success': '操作成功',
|
|
7
|
-
'shared:operation_error': '操作失败',
|
|
8
|
-
|
|
9
|
-
'shared:wrong_data': '数据错误',
|
|
10
|
-
'shared:permission_denied': '权限拒绝',
|
|
11
|
-
|
|
12
|
-
'shared:name_not_existed': '{name} 不存在',
|
|
13
|
-
'shared:name_not_set': '{name} 未设置',
|
|
14
|
-
'shared:name_is_wrong': '{name} 是错误的',
|
|
15
|
-
|
|
16
|
-
'shared:login_success': '登录成功',
|
|
17
|
-
'shared:login_failed': '登录失败',
|
|
18
|
-
'shared:not_logged_in': '未登录',
|
|
19
|
-
|
|
20
|
-
'shared:user_not_found': '用户未找到',
|
|
21
|
-
'shared:user_locked': '用户已封锁',
|
|
22
|
-
|
|
23
|
-
'shared:not_found_file': '文件 {fileName} 未找到',
|
|
24
|
-
|
|
25
|
-
'shared:wrong_hash': '错误的hash',
|
|
26
|
-
},
|
|
27
|
-
};
|
|
1
|
+
import { OneLangProps } from './lang-props';
|
|
2
|
+
|
|
3
|
+
export const apiLangZhCn: OneLangProps = {
|
|
4
|
+
langName: 'zh-cn',
|
|
5
|
+
langs: {
|
|
6
|
+
'shared:operation_success': '操作成功',
|
|
7
|
+
'shared:operation_error': '操作失败',
|
|
8
|
+
|
|
9
|
+
'shared:wrong_data': '数据错误',
|
|
10
|
+
'shared:permission_denied': '权限拒绝',
|
|
11
|
+
|
|
12
|
+
'shared:name_not_existed': '{name} 不存在',
|
|
13
|
+
'shared:name_not_set': '{name} 未设置',
|
|
14
|
+
'shared:name_is_wrong': '{name} 是错误的',
|
|
15
|
+
|
|
16
|
+
'shared:login_success': '登录成功',
|
|
17
|
+
'shared:login_failed': '登录失败',
|
|
18
|
+
'shared:not_logged_in': '未登录',
|
|
19
|
+
|
|
20
|
+
'shared:user_not_found': '用户未找到',
|
|
21
|
+
'shared:user_locked': '用户已封锁',
|
|
22
|
+
|
|
23
|
+
'shared:not_found_file': '文件 {fileName} 未找到',
|
|
24
|
+
|
|
25
|
+
'shared:wrong_hash': '错误的hash',
|
|
26
|
+
},
|
|
27
|
+
};
|
package/src/lang/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './lang-helper';
|
|
2
|
-
export * from './lang-props';
|
|
1
|
+
export * from './lang-helper';
|
|
2
|
+
export * from './lang-props';
|