UNPKG

cnpmcore

Version:

Private NPM Registry for Enterprise

216 lines 18.4 kB
import assert from 'node:assert/strict'; import { randomUUID } from 'node:crypto'; import { join } from 'node:path'; import OSSClient from 'oss-cnpm'; import { env } from 'read-env-value'; import S3Client from 's3-cnpmcore'; import { ChangesStreamMode, NOT_IMPLEMENTED_PATH, SyncDeleteMode, SyncMode } from "../app/common/constants.js"; import { patchAjv } from "../app/port/typebox.js"; import { database } from "./database.js"; export const cnpmcoreConfig = { name: 'cnpm', hookEnable: false, hooksLimit: 20, sourceRegistry: env('CNPMCORE_CONFIG_SOURCE_REGISTRY', 'string', 'https://registry.npmjs.org'), sourceRegistryIsCNpm: env('CNPMCORE_CONFIG_SOURCE_REGISTRY_IS_CNPM', 'boolean', false), syncUpstreamFirst: false, sourceRegistrySyncTimeout: 180_000, taskQueueHighWaterSize: 100, syncMode: env('CNPMCORE_CONFIG_SYNC_MODE', 'string', SyncMode.none), syncDeleteMode: SyncDeleteMode.delete, syncPackageWorkerMaxConcurrentTasks: 10, triggerHookWorkerMaxConcurrentTasks: 10, createTriggerHookWorkerMaxConcurrentTasks: 10, syncPackageBlockList: [], enableCheckRecentlyUpdated: true, enableSyncBinary: false, syncBinaryFromAPISource: '', enableSyncDownloadData: false, syncDownloadDataSourceRegistry: '', syncDownloadDataMaxDate: '', enableChangesStream: false, checkChangesStreamInterval: 500, changesStreamRegistry: 'https://replicate.npmjs.com/registry', changesStreamRegistryMode: ChangesStreamMode.streaming, registry: env('CNPMCORE_CONFIG_REGISTRY', 'string', 'http://localhost:7001'), alwaysAuth: false, allowScopes: ['@cnpm', '@cnpmcore', '@example'], allowPublishNonScopePackage: false, allowPublicRegistration: false, admins: { cnpmcore_admin: 'admin@cnpmjs.org', }, enableWebAuthn: env('CNPMCORE_CONFIG_ENABLE_WEB_AUTHN', 'boolean', false), enableCDN: false, cdnCacheControlHeader: 'public, max-age=300', cdnVaryHeader: 'Accept, Accept-Encoding', enableStoreFullPackageVersionManifestsToDatabase: false, enableNpmClientAndVersionCheck: true, syncNotFound: false, redirectNotFound: true, enableUnpkg: true, enableSyncUnpkgFiles: true, enableSyncUnpkgFilesWhiteList: false, largePackageVersionSize: Number.MAX_SAFE_INTEGER, largePackageVersionBlockThreshold: 3, strictSyncSpecivicVersion: false, enableElasticsearch: env('CNPMCORE_CONFIG_ENABLE_ES', 'boolean', false), elasticsearchIndex: 'cnpmcore_packages', searchFilterDeprecated: env('CNPMCORE_CONFIG_SEARCH_FILTER_DEPRECATED', 'boolean', false), searchPublishMinDuration: env('CNPMCORE_CONFIG_SEARCH_PUBLISH_MIN_DURATION', 'string', ''), strictValidateTarballPkg: false, strictValidatePackageDeps: false, database: { type: database.type, }, experimental: { syncPackageWithPackument: env('CNPMCORE_CONFIG_SYNC_PACKAGE_WITH_PACKUMENT', 'boolean', false), enableJSONBuilder: env('CNPMCORE_CONFIG_ENABLE_JSON_BUILDER', 'boolean', false), }, }; export default function startConfig(appInfo) { const config = {}; config.keys = env('CNPMCORE_EGG_KEYS', 'string', randomUUID()); config.cnpmcore = cnpmcoreConfig; // override config from framework / plugin config.dataDir = env('CNPMCORE_DATA_DIR', 'string', join(appInfo.root, '.cnpmcore')); config.orm = { ...database, database: database.name ?? 'cnpmcore', charset: 'utf8mb4', // https://github.com/cyjake/leoric/pull/446 // Skip cloning database values for performance optimization skipCloneValue: true, logger: { // https://github.com/cyjake/leoric/blob/master/docs/zh/logging.md#logqueryerror // ignore query error logQueryError() { // do nothing }, // logQueryError(...args: any[]) { // console.log(args); // }, }, }; config.redis = { client: { port: env('CNPMCORE_REDIS_PORT', 'number', 6379), host: env('CNPMCORE_REDIS_HOST', 'string', '127.0.0.1'), password: env('CNPMCORE_REDIS_PASSWORD', 'string', ''), db: env('CNPMCORE_REDIS_DB', 'number', 0) + Number(env('VITEST_POOL_ID', 'number', 0)), }, }; config.security = { csrf: { enable: false, }, }; config.cors = { // allow all domains origin: (ctx) => { return ctx.get('Origin'); }, credentials: true, // https://github.com/koajs/cors/blob/master/index.js#L10C57-L10C64 allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS', }; config.nfs = { client: null, dir: env('CNPMCORE_NFS_DIR', 'string', join(config.dataDir, 'nfs')), removeBeforeUpload: env('CNPMCORE_NFS_REMOVE_BEFORE_UPLOAD', 'boolean', false), }; /* c8 ignore next 17 */ // enable oss nfs store by env values const nfsType = env('CNPMCORE_NFS_TYPE', 'string', ''); if (nfsType === 'oss') { const ossConfig = { cdnBaseUrl: env('CNPMCORE_NFS_OSS_CDN', 'string', ''), endpoint: env('CNPMCORE_NFS_OSS_ENDPOINT', 'string', ''), bucket: env('CNPMCORE_NFS_OSS_BUCKET', 'string', ''), accessKeyId: env('CNPMCORE_NFS_OSS_ID', 'string', ''), accessKeySecret: env('CNPMCORE_NFS_OSS_SECRET', 'string', ''), defaultHeaders: { 'Cache-Control': 'max-age=0, s-maxage=60', }, }; assert.ok(ossConfig.bucket, 'require env CNPMCORE_NFS_OSS_BUCKET'); assert.ok(ossConfig.endpoint, 'require env CNPMCORE_NFS_OSS_ENDPOINT'); assert.ok(ossConfig.accessKeyId, 'require env CNPMCORE_NFS_OSS_ID'); assert.ok(ossConfig.accessKeySecret, 'require env CNPMCORE_NFS_OSS_SECRET'); config.nfs.client = new OSSClient(ossConfig); } else if (nfsType === 's3') { const s3Config = { region: env('CNPMCORE_NFS_S3_CLIENT_REGION', 'string', 'default'), endpoint: env('CNPMCORE_NFS_S3_CLIENT_ENDPOINT', 'string', ''), credentials: { accessKeyId: env('CNPMCORE_NFS_S3_CLIENT_ID', 'string', ''), secretAccessKey: env('CNPMCORE_NFS_S3_CLIENT_SECRET', 'string', ''), }, bucket: env('CNPMCORE_NFS_S3_CLIENT_BUCKET', 'string', ''), forcePathStyle: env('CNPMCORE_NFS_S3_CLIENT_FORCE_PATH_STYLE', 'boolean', false), disableURL: env('CNPMCORE_NFS_S3_CLIENT_DISABLE_URL', 'boolean', false), }; assert.ok(s3Config.endpoint, 'require env CNPMCORE_NFS_S3_CLIENT_ENDPOINT'); assert.ok(s3Config.credentials.accessKeyId, 'require env CNPMCORE_NFS_S3_CLIENT_ID'); assert.ok(s3Config.credentials.secretAccessKey, 'require env CNPMCORE_NFS_S3_CLIENT_SECRET'); assert.ok(s3Config.bucket, 'require env CNPMCORE_NFS_S3_CLIENT_BUCKET'); // @ts-expect-error has no construct signatures config.nfs.client = new S3Client(s3Config); } config.logger = { consoleLevel: 'WARN', enablePerformanceTimer: true, enableFastContextLogger: true, appLogName: env('CNPMCORE_APP_LOG_NAME', 'string', `${appInfo.name}-web.log`), coreLogName: env('CNPMCORE_CORE_LOG_NAME', 'string', 'egg-web.log'), agentLogName: env('CNPMCORE_AGENT_LOG_NAME', 'string', 'egg-agent.log'), errorLogName: env('CNPMCORE_ERROR_LOG_NAME', 'string', 'common-error.log'), outputJSON: env('CNPMCORE_LOG_JSON_OUTPUT', 'boolean', false), }; const logDir = env('CNPMCORE_LOG_DIR', 'string', ''); if (logDir) { config.logger.dir = logDir; } config.logrotator = { // only keep 1 days log files maxDays: 1, }; config.bodyParser = { // saveTag will send version string in JSON format strict: false, // set default limit to 10mb, see https://github.com/npm/npm/issues/12750 jsonLimit: '10mb', // https://github.com/cnpm/cnpmcore/issues/551 ignore: NOT_IMPLEMENTED_PATH, }; // https://github.com/xiekw2010/egg-typebox-validate#%E5%A6%82%E4%BD%95%E5%86%99%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%A1%E9%AA%8C%E8%A7%84%E5%88%99 config.typeboxValidate = { patchAjv }; config.httpclient = { useHttpClientNext: true, allowH2: true, }; config.view = { root: join(appInfo.baseDir, 'app/port'), defaultViewEngine: 'nunjucks', }; config.customLogger = { sqlLogger: { file: 'sql.log', }, }; // more options: https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html if (config.cnpmcore.enableElasticsearch) { config.elasticsearch = { client: { node: env('CNPMCORE_CONFIG_ES_CLIENT_NODE', 'string', ''), auth: { username: env('CNPMCORE_CONFIG_ES_CLIENT_AUTH_USERNAME', 'string', ''), password: env('CNPMCORE_CONFIG_ES_CLIENT_AUTH_PASSWORD', 'string', ''), }, }, }; } return config; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmRlZmF1bHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9jb25maWcvY29uZmlnLmRlZmF1bHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxNQUFNLE1BQU0sb0JBQW9CLENBQUM7QUFDeEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN6QyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBR2pDLE9BQU8sU0FBUyxNQUFNLFVBQVUsQ0FBQztBQUNqQyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDckMsT0FBTyxRQUFRLE1BQU0sYUFBYSxDQUFDO0FBRW5DLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxvQkFBb0IsRUFBRSxjQUFjLEVBQUUsUUFBUSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFL0csT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2xELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFekMsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFtQjtJQUM1QyxJQUFJLEVBQUUsTUFBTTtJQUNaLFVBQVUsRUFBRSxLQUFLO0lBQ2pCLFVBQVUsRUFBRSxFQUFFO0lBQ2QsY0FBYyxFQUFFLEdBQUcsQ0FBQyxpQ0FBaUMsRUFBRSxRQUFRLEVBQUUsNEJBQTRCLENBQUM7SUFDOUYsb0JBQW9CLEVBQUUsR0FBRyxDQUFDLHlDQUF5QyxFQUFFLFNBQVMsRUFBRSxLQUFLLENBQUM7SUFDdEYsaUJBQWlCLEVBQUUsS0FBSztJQUN4Qix5QkFBeUIsRUFBRSxPQUFPO0lBQ2xDLHNCQUFzQixFQUFFLEdBQUc7SUFDM0IsUUFBUSxFQUFFLEdBQUcsQ0FBQywyQkFBMkIsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLElBQUksQ0FBYTtJQUMvRSxjQUFjLEVBQUUsY0FBYyxDQUFDLE1BQU07SUFDckMsbUNBQW1DLEVB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