UNPKG

cnpmcore

Version:

Private NPM Registry for Enterprise

300 lines 28.1 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import { AccessLevel, Inject, SingletonProto, BackgroundTaskHelper, } from 'egg'; import { ForbiddenError } from 'egg/errors'; import { valid as semverValid } from 'semver'; import { AbstractService } from "../../common/AbstractService.js"; import { ABBREVIATED_META_TYPE, PROXY_CACHE_DIR_NAME } from "../../common/constants.js"; import { TaskState, TaskType } from "../../common/enum/Task.js"; import { calculateIntegrity } from "../../common/PackageUtil.js"; import { DIST_NAMES, isPkgManifest } from "../entity/Package.js"; import { ProxyCache } from "../entity/ProxyCache.js"; import { Task } from "../entity/Task.js"; function isoNow() { return new Date().toISOString(); } let ProxyCacheService = class ProxyCacheService extends AbstractService { async getPackageVersionTarResponse(fullname, ctx) { if (this.config.cnpmcore.syncPackageBlockList.includes(fullname)) { throw new ForbiddenError(`stop proxy by block list: ${JSON.stringify(this.config.cnpmcore.syncPackageBlockList)}`); } return await this.getProxyResponse(ctx); } async getPackageManifest(fullname, fileType) { const isFullManifests = fileType === DIST_NAMES.FULL_MANIFESTS; const proxyCache = await this.proxyCacheRepository.findProxyCache(fullname, fileType); const cachedStoreKey = proxyCache?.filePath; if (cachedStoreKey) { try { const nfsBytes = await this.nfsAdapter.getBytes(cachedStoreKey); if (!nfsBytes) throw new Error('not found proxy cache, try again later.'); const nfsBuffer = Buffer.from(nfsBytes); const { shasum: etag } = await calculateIntegrity(nfsBytes); await this.cacheService.savePackageEtagAndManifests(fullname, isFullManifests, etag, nfsBuffer); const nfsString = nfsBuffer.toString(); const nfsPkgManifest = JSON.parse(nfsString); return nfsPkgManifest; } catch (error) { /* c8 ignore next 6 */ if (error.message.includes('not found proxy cache') || error.message.includes('Unexpected token : in JSON at')) { await this.nfsAdapter.remove(cachedStoreKey); await this.proxyCacheRepository.removeProxyCache(fullname, fileType); } throw error; } } const manifest = await this.getRewrittenManifest(fullname, fileType); this.backgroundTaskHelper.run(async () => { await this.storeRewrittenManifest(manifest, fullname, fileType); const cachedFiles = ProxyCache.create({ fullname, fileType }); await this.proxyCacheRepository.saveProxyCache(cachedFiles); }); return manifest; } // used by GET /:fullname/:versionOrTag async getPackageVersionManifest(fullname, fileType, versionOrTag) { let version; if (semverValid(versionOrTag)) { version = versionOrTag; } else { const pkgManifest = await this.getPackageManifest(fullname, DIST_NAMES.ABBREVIATED_MANIFESTS); const distTags = pkgManifest['dist-tags'] || {}; version = distTags[versionOrTag] ?? versionOrTag; } const proxyCache = await this.proxyCacheRepository.findProxyCache(fullname, fileType, version); const cachedStoreKey = proxyCache?.filePath; if (cachedStoreKey) { try { const nfsBytes = await this.nfsAdapter.getBytes(cachedStoreKey); if (!nfsBytes) throw new Error('not found proxy cache, try again later.'); const nfsString = Buffer.from(nfsBytes).toString(); return JSON.parse(nfsString); } catch (error) { /* c8 ignore next 6 */ if (error.message.includes('not found proxy cache') || error.message.includes('Unexpected token : in JSON at')) { await this.nfsAdapter.remove(cachedStoreKey); await this.proxyCacheRepository.removeProxyCache(fullname, fileType); } throw error; } } const manifest = await this.getRewrittenManifest(fullname, fileType, versionOrTag); this.backgroundTaskHelper.run(async () => { await this.storeRewrittenManifest(manifest, fullname, fileType); const cachedFiles = ProxyCache.create({ fullname, fileType, version }); await this.proxyCacheRepository.saveProxyCache(cachedFiles); }); return manifest; } async removeProxyCache(fullname, fileType, version) { const storeKey = isPkgManifest(fileType) ? `/${PROXY_CACHE_DIR_NAME}/${fullname}/${fileType}` : `/${PROXY_CACHE_DIR_NAME}/${fullname}/${version}/${fileType}`; await this.nfsAdapter.remove(storeKey); await this.proxyCacheRepository.removeProxyCache(fullname, fileType, version); } replaceTarballUrl(manifest, fileType) { const { sourceRegistry, registry } = this.config.cnpmcore; if (isPkgManifest(fileType)) { // pkg manifest const versionMap = manifest?.versions; for (const key in versionMap) { const versionItem = versionMap[key]; if (versionItem?.dist?.tarball) { versionItem.dist.tarball = versionItem.dist.tarball.replace(sourceRegistry, registry); } } } else { // pkg version manifest const distItem = manifest.dist; if (distItem?.tarball) { distItem.tarball = distItem.tarball.replace(sourceRegistry, registry); } } return manifest; } async createTask(targetName, options) { return (await this.taskService.createTask(Task.createUpdateProxyCache(targetName, options), false)); } async findExecuteTask() { return await this.taskService.findExecuteTask(TaskType.UpdateProxyCache); } async executeTask(task) { const logs = []; const fullname = task.data.fullname; const { fileType, version } = task.data; let cachedManifest; logs.push(`[${isoNow()}] 🚧🚧🚧🚧🚧 Start update "${fullname}-${fileType}" 🚧🚧🚧🚧🚧`); try { const cachedFiles = await this.proxyCacheRepository.findProxyCache(fullname, fileType); if (!cachedFiles) throw new Error('task params error, can not found record in repo.'); cachedManifest = await this.getRewrittenManifest(fullname, fileType); await this.storeRewrittenManifest(cachedManifest, fullname, fileType); ProxyCache.update(cachedFiles); await this.proxyCacheRepository.saveProxyCache(cachedFiles); } catch (error) { task.error = error; logs.push(`[${isoNow()}] ❌ ${task.error}`); logs.push(`[${isoNow()}] ❌❌❌❌❌ ${fullname}-${fileType} ${version ?? ''} ❌❌❌❌❌`); await this.taskService.finishTask(task, TaskState.Fail, logs.join('\n')); this.logger.info('[ProxyCacheService.executeTask:fail] taskId: %s, targetName: %s, %s', task.taskId, task.targetName, task.error); return; } logs.push(`[${isoNow()}] 🟢 Update Success.`); const isFullManifests = fileType === DIST_NAMES.FULL_MANIFESTS; const cachedKey = await this.cacheService.getPackageEtag(fullname, isFullManifests); if (cachedKey) { const cacheBytes = Buffer.from(JSON.stringify(cachedManifest)); const { shasum: etag } = await calculateIntegrity(cacheBytes); await this.cacheService.savePackageEtagAndManifests(fullname, isFullManifests, etag, cacheBytes); logs.push(`[${isoNow()}] 🟢 Update Cache Success.`); } await this.taskService.finishTask(task, TaskState.Success, logs.join('\n')); } // only used by schedule task async getRewrittenManifest(fullname, fileType, versionOrTag) { let responseResult; const USER_AGENT = 'npm_service.cnpmjs.org/cnpmcore'; switch (fileType) { case DIST_NAMES.FULL_MANIFESTS: { const url = `/${encodeURIComponent(fullname)}?t=${Date.now()}&cache=0`; responseResult = await this.getProxyResponse({ url, headers: { accept: 'application/json', 'user-agent': USER_AGENT }, }, { dataType: 'json' }); break; } case DIST_NAMES.ABBREVIATED_MANIFESTS: { const url = `/${encodeURIComponent(fullname)}?t=${Date.now()}&cache=0`; responseResult = await this.getProxyResponse({ url, headers: { accept: ABBREVIATED_META_TYPE, 'user-agent': USER_AGENT, }, }, { dataType: 'json' }); break; } case DIST_NAMES.MANIFEST: { const url = `/${encodeURIComponent(fullname)}/${encodeURIComponent(versionOrTag ?? '')}`; responseResult = await this.getProxyResponse({ url, headers: { accept: 'application/json', 'user-agent': USER_AGENT }, }, { dataType: 'json' }); break; } case DIST_NAMES.ABBREVIATED: { const url = `/${encodeURIComponent(fullname)}/${encodeURIComponent(versionOrTag ?? '')}`; responseResult = await this.getProxyResponse({ url, headers: { accept: ABBREVIATED_META_TYPE, 'user-agent': USER_AGENT, }, }, { dataType: 'json' }); break; } default: { break; } } // replace tarball url const manifest = this.replaceTarballUrl(responseResult?.data, fileType); return manifest; } async storeRewrittenManifest( // oxlint-disable-next-line typescript-eslint/no-explicit-any manifest, fullname, fileType) { let storeKey; if (isPkgManifest(fileType)) { storeKey = `/${PROXY_CACHE_DIR_NAME}/${fullname}/${fileType}`; } else { const version = manifest.version; storeKey = `/${PROXY_CACHE_DIR_NAME}/${fullname}/${version}/${fileType}`; } const nfsBytes = Buffer.from(JSON.stringify(manifest)); await this.nfsAdapter.uploadBytes(storeKey, nfsBytes); } async getProxyResponse(ctx, options) { const registry = this.npmRegistry.registry; const remoteAuthToken = await this.registryManagerService.getAuthTokenByRegistryHost(registry); const authorization = this.npmRegistry.genAuthorizationHeader(remoteAuthToken); const url = `${this.npmRegistry.registry}${ctx.url}`; const res = (await this.httpClient.request(url, { timing: true, followRedirect: true, // once redirection is also count as a retry retry: 7, dataType: 'stream', timeout: 10_000, compressed: true, ...options, headers: { accept: ctx.headers?.accept, 'user-agent': ctx.headers?.['user-agent'], authorization, 'x-forwarded-for': ctx?.ip, via: `1.1, ${this.config.cnpmcore.registry}`, }, })); this.logger.info('[ProxyCacheService:getProxyStreamResponse] %s, status: %s', url, res.status); return res; } }; __decorate([ Inject(), __metadata("design:type", Function) ], ProxyCacheService.prototype, "httpClient", void 0); __decorate([ Inject(), __metadata("design:type", Function) ], ProxyCacheService.prototype, "npmRegistry", void 0); __decorate([ Inject(), __metadata("design:type", Function) ], ProxyCacheService.prototype, "nfsAdapter", void 0); __decorate([ Inject(), __metadata("design:type", Function) ], ProxyCacheService.prototype, "proxyCacheRepository", void 0); __decorate([ Inject(), __metadata("design:type", Function) ], ProxyCacheService.prototype, "registryManagerService", void 0); __decorate([ Inject(), __metadata("design:type", Function) ], ProxyCacheService.prototype, "taskService", void 0); __decorate([ Inject(), __metadata("design:type", Function) ], ProxyCacheService.prototype, "cacheService", void 0); __decorate([ Inject(), __metadata("design:type", BackgroundTaskHelper) ], ProxyCacheService.prototype, "backgroundTaskHelper", void 0); ProxyCacheService = __decorate([ SingletonProto({ accessLevel: AccessLevel.PUBLIC, }) ], ProxyCacheService); export { ProxyCacheService }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHJveHlDYWNoZVNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9hcHAvY29yZS9zZXJ2aWNlL1Byb3h5Q2FjaGVTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sRUFLTCxXQUFXLEVBQ1gsTUFBTSxFQUNOLGNBQWMsRUFDZCxvQkFBb0IsR0FDckIsTUFBTSxLQUFLLENBQUM7QUFDYixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksV0FBVyxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRTlDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUdsRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN4RixPQUFPLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBUWpFLE9BQU8sRUFBRSxVQUFVLEVBQUUsYUFBYSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDakUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3JELE9BQU8sRUFBcUUsSUFBSSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFLNUcsU0FBUyxNQUFNO0lBQ2IsT0FBTyxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQ2xDLENBQUM7QUFXTSxJQUFNLGlCQUFpQixHQUF2QixNQUFNLGlCQUFrQixTQUFRLGVBQWU7SUFrQnBELEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxRQUFnQixFQUFFLEdBQVk7UUFDL0QsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FB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