Initial LisgloSIPS V2 implementation

This commit is contained in:
hectorzhao
2026-06-22 10:56:38 +08:00
commit 5fa1bd35e9
303 changed files with 35644 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
import Joi from 'joi';
export interface RuntimeConfig {
service: {
name: string;
};
http: {
host: string;
port: number;
};
logging: {
level: string;
requestIdHeader: string;
};
database: {
url: string;
};
redis: {
url: string;
};
auth: {
accessTokenSecret: string;
accessTokenTtlSeconds: number;
refreshTokenTtlDays: number;
lockMaxFailures: number;
lockWindowSeconds: number;
cookieSecure: boolean;
tokenIssuer: string;
tokenAudience: string;
};
}
export const validationSchema = Joi.object({
NODE_ENV: Joi.string().valid('development', 'test', 'production').default('development'),
LISGLOSIPS_SERVICE_NAME: Joi.string().default('api'),
LISGLOSIPS_HOST: Joi.string().hostname().default('127.0.0.1'),
LISGLOSIPS_PORT: Joi.number().port().default(3000),
LISGLOSIPS_LOG_LEVEL: Joi.string().valid('trace', 'debug', 'info', 'warn', 'error', 'fatal', 'silent').default('info'),
LISGLOSIPS_REQUEST_ID_HEADER: Joi.string().default('x-request-id'),
DATABASE_URL: Joi.string().uri({ scheme: ['mysql'] }).required(),
REDIS_URL: Joi.string().uri({ scheme: ['redis', 'rediss'] }).required(),
AUTH_ACCESS_TOKEN_SECRET: Joi.string().min(32).when('NODE_ENV', {
is: 'production',
then: Joi.required(),
otherwise: Joi.string().default('dev-only-change-this-auth-secret-32-bytes-min')
}),
AUTH_ACCESS_TOKEN_TTL_SECONDS: Joi.number().integer().min(60).max(86_400).default(900),
AUTH_REFRESH_TOKEN_TTL_DAYS: Joi.number().integer().min(1).max(30).default(7),
AUTH_LOCK_MAX_FAILURES: Joi.number().integer().min(3).max(20).default(5),
AUTH_LOCK_WINDOW_SECONDS: Joi.number().integer().min(60).max(86_400).default(900),
AUTH_COOKIE_SECURE: Joi.boolean().truthy('true').falsy('false').default(true),
AUTH_TOKEN_ISSUER: Joi.string().default('lisglosips-api'),
AUTH_TOKEN_AUDIENCE: Joi.string().default('lisglosips-web')
});
export function appConfig(): RuntimeConfig {
return {
service: {
name: process.env.LISGLOSIPS_SERVICE_NAME ?? 'api'
},
http: {
host: process.env.LISGLOSIPS_HOST ?? '127.0.0.1',
port: Number(process.env.LISGLOSIPS_PORT ?? 3000)
},
logging: {
level: process.env.LISGLOSIPS_LOG_LEVEL ?? 'info',
requestIdHeader: process.env.LISGLOSIPS_REQUEST_ID_HEADER ?? 'x-request-id'
},
database: {
url: process.env.DATABASE_URL ?? ''
},
redis: {
url: process.env.REDIS_URL ?? ''
},
auth: {
accessTokenSecret: process.env.AUTH_ACCESS_TOKEN_SECRET ?? 'dev-only-change-this-auth-secret-32-bytes-min',
accessTokenTtlSeconds: Number(process.env.AUTH_ACCESS_TOKEN_TTL_SECONDS ?? 900),
refreshTokenTtlDays: Number(process.env.AUTH_REFRESH_TOKEN_TTL_DAYS ?? 7),
lockMaxFailures: Number(process.env.AUTH_LOCK_MAX_FAILURES ?? 5),
lockWindowSeconds: Number(process.env.AUTH_LOCK_WINDOW_SECONDS ?? 900),
cookieSecure: (process.env.AUTH_COOKIE_SECURE ?? 'true') !== 'false',
tokenIssuer: process.env.AUTH_TOKEN_ISSUER ?? 'lisglosips-api',
tokenAudience: process.env.AUTH_TOKEN_AUDIENCE ?? 'lisglosips-web'
}
};
}