diff --git a/.env.default b/.env.default index eca226f..bf07762 100644 --- a/.env.default +++ b/.env.default @@ -1,6 +1,6 @@ +# FIXME: deprecated, suggest use config.json only REDIS_HOST= -# parseInt(process.env.REDIS_PORT, 10) REDIS_PORT= REDIS_PWD= REDIS_DB= @@ -15,8 +15,6 @@ AWS_REGION= COOKIE_SIGN_KEY= -REDIS_HOST= - LOKALISE_TOKEN= LOKALISE_PROJECT_ID= diff --git a/.eslintrc.js b/.eslintrc.js index caa81c2..158d1e1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,3 @@ -const isDev = process.env.NODE_ENV !== 'production'; const jsRules = { // eslint-disable-next-line global-require 'prettier/prettier': ['error', require('./.prettierrc.js')], @@ -25,7 +24,7 @@ const tsRules = { '@typescript-eslint/default-param-last': 'off', '@typescript-eslint/consistent-type-imports': 'off', '@typescript-eslint/no-var-requires': 'off', - '@typescript-eslint/no-unused-vars': [isDev ? 'warn' : 'error'], + '@typescript-eslint/no-unused-vars': ['error'], '@typescript-eslint/no-use-before-define': ['error'], '@typescript-eslint/no-shadow': ['error'], '@typescript-eslint/explicit-module-boundary-types': 'off', diff --git a/.gitignore b/.gitignore index 8178952..dd59738 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ run/ .tsbuildinfo .tsbuildinfo.* .env +config.json junit.xml test-report.html jest-stare/ diff --git a/Dockerfile b/Dockerfile index 4420077..61a6097 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,6 +28,6 @@ RUN yarn run prepare-env\ ENV TZ="Asia/Shanghai" -EXPOSE 7001 +EXPOSE 80 CMD ["yarn", "run", "start"] \ No newline at end of file diff --git a/config.default.json b/config.default.json new file mode 100644 index 0000000..9f69371 --- /dev/null +++ b/config.default.json @@ -0,0 +1,17 @@ +{ + "COOKIE_SIGN_KEY": "0000000000000_000", + "PORT": "80", + "GLOBAL_PREFIX": "", + "REDIS_HOST": "localhost", + "REDIS_PORT": "6379", + "REDIS_PWD": "", + "REDIS_DB": "0", + "MONGODB_URI": "mongodb://localhost:27017/test", + "MONGODB_USER": "", + "MONGODB_PASSWORD": "", + "AWS_ACCESS_KEY_ID": "", + "AWS_SECRET_KEY": "", + "AWS_REGION": "", + "LOKALISE_TOKEN": "", + "LOKALISE_PROJECT_ID": "" +} \ No newline at end of file diff --git a/src/config/config.default.ts b/src/config/config.default.ts index dbf5334..4d3c782 100644 --- a/src/config/config.default.ts +++ b/src/config/config.default.ts @@ -2,13 +2,7 @@ import localeConfig from '../locales'; -const getRedisConfig = (db = 0, options: Record = {}) => ({ - host: process.env.REDIS_HOST, - port: parseInt(process.env.REDIS_PORT, 10), - password: process.env.REDIS_PWD, - db, - ...options, -}); +import type { MidwayConfig } from '@midwayjs/core'; /* default中的配置项,会被config.xxxx.ts中相同配置项覆盖 @@ -24,7 +18,12 @@ export default { enableConsole: false, }, }, - redis: getRedisConfig(parseInt(process.env.REDIS_DB, 10)), + redis: { + host: process.env.REDIS_HOST, + port: parseInt(process.env.REDIS_PORT, 10), + password: process.env.REDIS_PWD, + db: parseInt(process.env.REDIS_DB, 10), + }, mongoose: { dataSource: { default: { @@ -52,4 +51,4 @@ export default { writeCookie: false, resolver: false, }, -}; +} as MidwayConfig; diff --git a/src/config/config.jest.ts b/src/config/config.jest.ts new file mode 100644 index 0000000..c137031 --- /dev/null +++ b/src/config/config.jest.ts @@ -0,0 +1,3 @@ +import { MidwayConfig } from '@midwayjs/core'; + +export default {} as MidwayConfig; diff --git a/src/config/config.local.ts b/src/config/config.local.ts index c137031..8956114 100644 --- a/src/config/config.local.ts +++ b/src/config/config.local.ts @@ -1,3 +1,12 @@ import { MidwayConfig } from '@midwayjs/core'; -export default {} as MidwayConfig; +export default { + midwayLogger: { + default: { + fileLevel: 'info', + enableFile: false, + consoleLevel: 'debug', + enableConsole: true, + }, + }, +} as MidwayConfig; diff --git a/src/configuration.ts b/src/configuration.ts index 49748b8..ccfc23b 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -1,4 +1,5 @@ -import './init'; +// eslint-disable-next-line import/order +import './init'; // XXX: must run before all code import { hostname } from 'os'; import path, { join } from 'path'; @@ -23,10 +24,11 @@ import { sync } from 'read-pkg'; import { DefaultErrorFilter } from './filter/default.filter'; import { LocaleMiddleware } from './middleware/locale.middleware'; import { ResponseWrapperMiddleware } from './middleware/response-wrapper.middleware'; -import { RUNTIME_ENV_MAP, ServerEnv } from './types/config/config.dto'; -import { validateBy } from './utils/common'; +import { NODE_ENV, ConfigDTO } from './types/config.dto'; +import { validateBy } from './utils'; import { CloudwatchTransport } from './utils/logger'; import { registerModel } from './utils/register-model'; + @Configuration({ imports: [ koa, @@ -64,7 +66,7 @@ export class MainConfiguration { async onConfigLoad() { const config = this.app.getConfig(); - return validateBy(config, ServerEnv, { + return validateBy(config, ConfigDTO, { allowUnknown: true, }); } @@ -73,7 +75,7 @@ export class MainConfiguration { this.app.useMiddleware([LocaleMiddleware, ResponseWrapperMiddleware]); this.app.useFilter([DefaultErrorFilter]); - if (this.envConfig === RUNTIME_ENV_MAP.PRODUCTION) { + if (this.envConfig === NODE_ENV.PRODUCTION) { const cloudwatchTransport = new CloudwatchTransport({ app: this.app.getProjectName(), hostname: hostname(), diff --git a/src/init.ts b/src/init.ts index 8f27675..0424b0b 100644 --- a/src/init.ts +++ b/src/init.ts @@ -1,37 +1,50 @@ /* eslint-disable no-process-env */ -import { join, resolve } from 'path'; + +import path from 'path'; import * as dotenv from 'dotenv'; -export const ServerSecretsPath = resolve( - '/', - 'mnt', - 'secrets', - `onekey-eks-dashboard-${process.env.NODE_ENV}.json` -); -export const ServerConfigPath = resolve('/', 'mnt', 'config', 'config.json'); - -function loadJsonConfigFile(file: string, errorMessage: string) { - try { - dotenv.populate(process.env, require(file)); - } catch (error) { - console.log(errorMessage, file); - } +import { NODE_ENV } from './types/config.dto'; + +// ============================================================================ +const PROJECT_NAME = ''; // FIXME: set by your project +if (!PROJECT_NAME) { + console.log('Please set your own PROJECT_NAME and delete this console'); +} + +// first load config as default, second load config will not cover prev load config +if ( + [NODE_ENV.LOCAL, NODE_ENV.JEST].includes(process.env.NODE_ENV as NODE_ENV) +) { + // local load config + dotenv.populate( + process.env, + require(path.resolve(__dirname, '..', 'config.json')) + ); + + // FIXME: deprecated, suggest use config.json only + dotenv.config({ + path: path.join(__dirname, '..', '.env'), + }); +} else { + // online load config + dotenv.populate( + process.env, + require(path.resolve('/', 'mnt', 'config', 'config.json')) + ); + + dotenv.populate( + process.env, + require(path.resolve( + '/', + 'mnt', + 'secrets', + `onekey-eks-${PROJECT_NAME}-${process.env.NODE_ENV}.json` + )) + ); } -/* - 加载线上配置文件 -*/ -loadJsonConfigFile(ServerConfigPath, 'No config found path:'); -loadJsonConfigFile(ServerSecretsPath, 'No secrets found path:'); -loadJsonConfigFile( - join(__dirname, '..', '.config.json'), - 'No local json config found' -); - -/* - 加载本地配置文件,注意.config.json和.env只需要一个即可,两个都存在的话,.config.json会覆盖.env -*/ -dotenv.config({ - path: join(__dirname, '..', '.env'), -}); +// ============================================================================ +BigInt.prototype['toJSON'] = function () { + return this.toString(); +}; diff --git a/src/types/config.dto.ts b/src/types/config.dto.ts new file mode 100644 index 0000000..b462087 --- /dev/null +++ b/src/types/config.dto.ts @@ -0,0 +1,103 @@ +import { getSchema, Rule, RuleType } from '@midwayjs/validate'; + +// ============================================================================ +export enum NODE_ENV { + LOCAL = 'local', + JEST = 'jest', + TEST = 'test', + STAGING = 'staging', + PRODUCTION = 'production', +} + +// ============================================================================ +class AwsDTO { + @Rule(RuleType.string().allow('').required()) + awsAccessKeyId!: string; + + @Rule(RuleType.string().allow('').required()) + awsSecretKey!: string; + + @Rule(RuleType.string().allow('').required()) + awsRegion!: string; +} + +// ============================================================================ + +class RedisDTO { + @Rule(RuleType.string().required()) + host!: string; + + @Rule(RuleType.number().integer().positive().required()) + port!: number; + + @Rule(RuleType.string().allow('').required()) + password!: string; + + @Rule(RuleType.number().integer().min(0).required()) + db!: number; +} + +// ============================================================================ +class MongooseDataSourceManagerOptionsDTO { + @Rule(RuleType.string().allow('').required()) + user!: string; + + @Rule(RuleType.string().allow('').required()) + pass!: string; +} + +class MongooseDataSourceManagerDTO { + @Rule(RuleType.string().required()) + uri!: string; + + @Rule(getSchema(MongooseDataSourceManagerOptionsDTO).required()) + options: MongooseDataSourceManagerOptionsDTO; +} + +class MongooseDataSourceDTO { + @Rule(getSchema(MongooseDataSourceManagerDTO).required()) + default!: MongooseDataSourceManagerDTO; + + @Rule(getSchema(MongooseDataSourceManagerDTO)) + test?: MongooseDataSourceManagerDTO; +} + +class MongooseDTO { + @Rule(getSchema(MongooseDataSourceDTO).required()) + dataSource!: MongooseDataSourceDTO; +} + +// ============================================================================ +class KoaDTO { + @Rule(RuleType.number().required()) + port!: number; + + @Rule(RuleType.string().allow('').required()) + globalPrefix!: string; +} + +// ============================================================================ + +export class ConfigDTO { + @Rule( + RuleType.string() + .valid(...Object.values(NODE_ENV)) + .required() + ) + NODE_ENV!: NODE_ENV; + + @Rule(RuleType.string().required().description('cookieSignKey')) + keys!: string; + + @Rule(getSchema(KoaDTO).required()) + koa: KoaDTO; + + @Rule(getSchema(AwsDTO).required()) + aws!: AwsDTO; + + @Rule(getSchema(MongooseDTO).required()) + mongoose: MongooseDTO; + + @Rule(getSchema(RedisDTO).required()) + redis: RedisDTO; +} diff --git a/src/types/config/config.base.dto.ts b/src/types/config/config.base.dto.ts deleted file mode 100644 index 6f3b264..0000000 --- a/src/types/config/config.base.dto.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Rule, RuleType, getSchema } from '@midwayjs/validate'; - -export class Redis { - @Rule(RuleType.string().required()) - host!: string; - - @Rule(RuleType.number().required()) - port!: number; - - @Rule(RuleType.string().required().allow('')) - password!: string; - - @Rule(RuleType.number().required()) - db!: number; -} - -class MongooseOptions { - @Rule(RuleType.string().optional()) - user?: string; - - @Rule(RuleType.string().optional()) - pass?: string; -} - -class MongooseConfig { - @Rule(RuleType.string().required()) - uri!: string; - - @Rule(getSchema(MongooseOptions).required()) - options!: MongooseOptions; -} - -class MongooseDataSource { - @Rule(getSchema(MongooseConfig).required()) - test?: MongooseConfig; - - @Rule(getSchema(MongooseConfig).required()) - default!: MongooseConfig; -} - -export class Mongoose { - @Rule(getSchema(MongooseDataSource).required()) - dataSource!: MongooseDataSource; -} - -export class AWS { - @Rule(RuleType.string().required()) - awsAccessKeyId!: string; - - @Rule(RuleType.string().required()) - awsSecretKey!: string; - - @Rule(RuleType.string().required()) - awsRegion!: string; -} - -export class KOAConfig { - @Rule(RuleType.number().required()) - port!: number; - - @Rule(RuleType.string().required()) - globalPrefix!: string; -} diff --git a/src/types/config/config.dto.ts b/src/types/config/config.dto.ts deleted file mode 100644 index c252570..0000000 --- a/src/types/config/config.dto.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Rule, RuleType, getSchema } from '@midwayjs/validate'; - -import { AWS, KOAConfig, Redis } from './config.base.dto'; - -export enum RUNTIME_ENV_MAP { - LOCAL = 'local', - PRODUCTION = 'production', - TEST = 'test', - JEST = 'jest', -} - -export class ServerEnv { - @Rule(getSchema(Redis).required()) - redis: Redis; - - @Rule(getSchema(AWS).required()) - aws!: AWS; - - @Rule(RuleType.string().required()) - NODE_ENV: RUNTIME_ENV_MAP; - - @Rule(RuleType.string().required()) - keys: string; - - @Rule(getSchema(KOAConfig).required()) - koa: KOAConfig; -} diff --git a/src/utils/common.ts b/src/utils/index.ts similarity index 100% rename from src/utils/common.ts rename to src/utils/index.ts diff --git a/tsconfig.json b/tsconfig.json index c5822e0..7410d3a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compileOnSave": true, "compilerOptions": { - "target": "es2018", + "target": "es2022", "module": "commonjs", "moduleResolution": "node", "esModuleInterop": true, @@ -9,7 +9,7 @@ "emitDecoratorMetadata": true, "inlineSourceMap": true, "noImplicitThis": true, - "noUnusedLocals": true, + "noUnusedLocals": false, "stripInternal": true, "skipLibCheck": true, "pretty": true,