cnpmcore
Version:
Private NPM Registry for Enterprise
300 lines • 28.1 kB
JavaScript
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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