UNPKG

cnpmcore

Version:
345 lines 35.4 kB
"use strict"; 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); }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _PackageVersionFileService_instances, _PackageVersionFileService_unpkgWhiteListCheckTime, _PackageVersionFileService_unpkgWhiteListCurrentVersion, _PackageVersionFileService_unpkgWhiteListAllowPackages, _PackageVersionFileService_unpkgWhiteListAllowScopes, _PackageVersionFileService_ensurePackageVersionFilesSync, _PackageVersionFileService_updateUnpkgWhiteList, _PackageVersionFileService_savePackageVersionFile, _PackageVersionFileService_getDirectoryAndName, _PackageVersionFileService_formatTarEntryFilename, _PackageVersionFileService_matchReadmeFilename, _PackageVersionFileService_preferMarkdownReadme; Object.defineProperty(exports, "__esModule", { value: true }); exports.PackageVersionFileService = void 0; const promises_1 = __importDefault(require("node:fs/promises")); const node_path_1 = require("node:path"); const node_crypto_1 = require("node:crypto"); const tar_1 = __importDefault(require("@fengmk2/tar")); const tegg_1 = require("@eggjs/tegg"); const egg_errors_1 = require("egg-errors"); const semver_1 = __importDefault(require("semver")); const AbstractService_1 = require("../../common/AbstractService"); const PackageUtil_1 = require("../../common/PackageUtil"); const FileUtil_1 = require("../../common/FileUtil"); const PackageRepository_1 = require("../../repository/PackageRepository"); const PackageVersionFileRepository_1 = require("../../repository/PackageVersionFileRepository"); const PackageVersionRepository_1 = require("../../repository/PackageVersionRepository"); const DistRepository_1 = require("../../repository/DistRepository"); const PackageVersionFile_1 = require("../entity/PackageVersionFile"); const PackageManagerService_1 = require("./PackageManagerService"); const CacheAdapter_1 = require("../../common/adapter/CacheAdapter"); const unpkgWhiteListUrl = 'https://github.com/cnpm/unpkg-white-list'; const CHECK_TIMEOUT = process.env.NODE_ENV === 'test' ? 1 : 60000; let PackageVersionFileService = class PackageVersionFileService extends AbstractService_1.AbstractService { constructor() { super(...arguments); _PackageVersionFileService_instances.add(this); _PackageVersionFileService_unpkgWhiteListCheckTime.set(this, 0); _PackageVersionFileService_unpkgWhiteListCurrentVersion.set(this, ''); _PackageVersionFileService_unpkgWhiteListAllowPackages.set(this, {}); _PackageVersionFileService_unpkgWhiteListAllowScopes.set(this, []); } async listPackageVersionFiles(pkgVersion, directory) { await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_ensurePackageVersionFilesSync).call(this, pkgVersion); return await this.packageVersionFileRepository.listPackageVersionFiles(pkgVersion.packageVersionId, directory); } async showPackageVersionFile(pkgVersion, path) { await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_ensurePackageVersionFilesSync).call(this, pkgVersion); const { directory, name } = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_getDirectoryAndName).call(this, path); return await this.packageVersionFileRepository.findPackageVersionFile(pkgVersion.packageVersionId, directory, name); } async checkPackageVersionInUnpkgWhiteList(pkgScope, pkgName, pkgVersion) { if (!this.config.cnpmcore.enableSyncUnpkgFilesWhiteList) return; await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_updateUnpkgWhiteList).call(this); // check allow scopes if (__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowScopes, "f").includes(pkgScope)) return; // check allow packages const fullname = (0, PackageUtil_1.getFullname)(pkgScope, pkgName); const pkgConfig = __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowPackages, "f")[fullname]; if (!pkgConfig?.version) { throw new egg_errors_1.ForbiddenError(`"${fullname}" is not allow to unpkg files, see ${unpkgWhiteListUrl}`); } // satisfies 默认不会包含 prerelease 版本 // https://docs.npmjs.com/about-semantic-versioning#using-semantic-versioning-to-specify-update-types-your-package-can-accept // [x, *] 代表任意版本,这里统一通过 semver 来判断 if (!semver_1.default.satisfies(pkgVersion, pkgConfig.version, { includePrerelease: true })) { throw new egg_errors_1.ForbiddenError(`"${fullname}@${pkgVersion}" not satisfies "${pkgConfig.version}" to unpkg files, see ${unpkgWhiteListUrl}`); } } // 基于 latest version 同步 package readme async syncPackageReadme(pkg, latestPkgVersion) { const dirname = `unpkg_${pkg.fullname.replace('/', '_')}@${latestPkgVersion.version}_latest_readme_${(0, node_crypto_1.randomUUID)()}`; const tmpdir = await (0, FileUtil_1.createTempDir)(this.config.dataDir, dirname); const tarFile = `${tmpdir}.tgz`; const readmeFilenames = []; try { this.logger.info('[PackageVersionFileService.syncPackageReadme:download-start] dist:%s(path:%s, size:%s) => tarFile:%s', latestPkgVersion.tarDist.distId, latestPkgVersion.tarDist.path, latestPkgVersion.tarDist.size, tarFile); await this.distRepository.downloadDistToFile(latestPkgVersion.tarDist, tarFile); this.logger.info('[PackageVersionFileService.syncPackageReadme:extract-start] tmpdir:%s', tmpdir); await tar_1.default.extract({ file: tarFile, cwd: tmpdir, strip: 1, onentry: entry => { const filename = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_formatTarEntryFilename).call(this, entry); if (!filename) return; if (__classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_matchReadmeFilename).call(this, filename)) { readmeFilenames.push(filename); } }, }); if (readmeFilenames.length > 0) { const readmeFilename = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_preferMarkdownReadme).call(this, readmeFilenames); const readmeFile = (0, node_path_1.join)(tmpdir, readmeFilename); await this.packageManagerService.savePackageReadme(pkg, readmeFile); } } catch (err) { this.logger.warn('[PackageVersionFileService.syncPackageReadme:error] packageVersionId: %s, readmeFilenames: %j, tmpdir: %s, error: %s', latestPkgVersion.packageVersionId, readmeFilenames, tmpdir, err); // ignore TAR_BAD_ARCHIVE error if (err.code === 'TAR_BAD_ARCHIVE') return; throw err; } finally { try { await promises_1.default.rm(tarFile, { force: true }); await promises_1.default.rm(tmpdir, { recursive: true, force: true }); } catch (err) { this.logger.warn('[PackageVersionFileService.syncPackageReadme:warn] remove tmpdir: %s, error: %s', tmpdir, err); } } } async syncPackageVersionFiles(pkgVersion) { const files = []; // must set enableUnpkg and enableSyncUnpkgFiles = true both if (!this.config.cnpmcore.enableUnpkg) return files; if (!this.config.cnpmcore.enableSyncUnpkgFiles) return files; const pkg = await this.packageRepository.findPackageByPackageId(pkgVersion.packageId); if (!pkg) return files; // check unpkg white list await this.checkPackageVersionInUnpkgWhiteList(pkg.scope, pkg.name, pkgVersion.version); const dirname = `unpkg_${pkg.fullname.replace('/', '_')}@${pkgVersion.version}_${(0, node_crypto_1.randomUUID)()}`; const tmpdir = await (0, FileUtil_1.createTempDir)(this.config.dataDir, dirname); const tarFile = `${tmpdir}.tgz`; const paths = []; const readmeFilenames = []; try { this.logger.info('[PackageVersionFileService.syncPackageVersionFiles:download-start] dist:%s(path:%s, size:%s) => tarFile:%s', pkgVersion.tarDist.distId, pkgVersion.tarDist.path, pkgVersion.tarDist.size, tarFile); await this.distRepository.downloadDistToFile(pkgVersion.tarDist, tarFile); this.logger.info('[PackageVersionFileService.syncPackageVersionFiles:extract-start] tmpdir:%s', tmpdir); await tar_1.default.extract({ file: tarFile, cwd: tmpdir, strip: 1, onentry: entry => { const filename = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_formatTarEntryFilename).call(this, entry); if (!filename) return; paths.push('/' + filename); if (__classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_matchReadmeFilename).call(this, filename)) { readmeFilenames.push(filename); } }, }); for (const path of paths) { const localFile = (0, node_path_1.join)(tmpdir, path); const file = await __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_savePackageVersionFile).call(this, pkg, pkgVersion, path, localFile); files.push(file); } this.logger.info('[PackageVersionFileService.syncPackageVersionFiles:success] packageVersionId: %s, %d paths, %d files, tmpdir: %s', pkgVersion.packageVersionId, paths.length, files.length, tmpdir); if (readmeFilenames.length > 0) { const readmeFilename = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_preferMarkdownReadme).call(this, readmeFilenames); const readmeFile = (0, node_path_1.join)(tmpdir, readmeFilename); await this.packageManagerService.savePackageVersionReadme(pkgVersion, readmeFile); } return files; } catch (err) { this.logger.warn('[PackageVersionFileService.syncPackageVersionFiles:error] packageVersionId: %s, %d paths, tmpdir: %s, error: %s', pkgVersion.packageVersionId, paths.length, tmpdir, err); // ignore TAR_BAD_ARCHIVE error if (err.code === 'TAR_BAD_ARCHIVE') return files; throw err; } finally { try { await promises_1.default.rm(tarFile, { force: true }); await promises_1.default.rm(tmpdir, { recursive: true, force: true }); } catch (err) { this.logger.warn('[PackageVersionFileService.syncPackageVersionFiles:warn] remove tmpdir: %s, error: %s', tmpdir, err); } } } }; exports.PackageVersionFileService = PackageVersionFileService; _PackageVersionFileService_unpkgWhiteListCheckTime = new WeakMap(); _PackageVersionFileService_unpkgWhiteListCurrentVersion = new WeakMap(); _PackageVersionFileService_unpkgWhiteListAllowPackages = new WeakMap(); _PackageVersionFileService_unpkgWhiteListAllowScopes = new WeakMap(); _PackageVersionFileService_instances = new WeakSet(); _PackageVersionFileService_ensurePackageVersionFilesSync = async function _PackageVersionFileService_ensurePackageVersionFilesSync(pkgVersion) { const hasFiles = await this.packageVersionFileRepository.hasPackageVersionFiles(pkgVersion.packageVersionId); if (!hasFiles) { const lockName = `${pkgVersion.packageVersionId}:syncFiles`; const lockRes = await this.cacheAdapter.usingLock(lockName, 60, async () => { await this.syncPackageVersionFiles(pkgVersion); }); // lock fail if (!lockRes) { this.logger.warn('[package:version:syncPackageVersionFiles] check lock:%s fail', lockName); throw new egg_errors_1.ConflictError('Package version file sync is currently in progress. Please try again later.'); } } }; _PackageVersionFileService_updateUnpkgWhiteList = async function _PackageVersionFileService_updateUnpkgWhiteList() { if (!this.config.cnpmcore.enableSyncUnpkgFilesWhiteList) return; if (Date.now() - __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListCheckTime, "f") <= CHECK_TIMEOUT) { // check update every 60s return; } __classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListCheckTime, Date.now(), "f"); const whiteListScope = ''; const whiteListPackageName = 'unpkg-white-list'; const whiteListPackageVersion = await this.packageVersionRepository.findVersionByTag(whiteListScope, whiteListPackageName, 'latest'); if (!whiteListPackageVersion) return; // same version, skip update for performance if (__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListCurrentVersion, "f") === whiteListPackageVersion) return; // update the new version white list const { manifest } = await this.packageManagerService.showPackageVersionManifest(whiteListScope, whiteListPackageName, whiteListPackageVersion, false, true); if (!manifest) return; __classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListCurrentVersion, manifest.version, "f"); __classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListAllowPackages, manifest.allowPackages ?? {}, "f"); __classPrivateFieldSet(this, _PackageVersionFileService_unpkgWhiteListAllowScopes, manifest.allowScopes ?? [], "f"); this.logger.info('[PackageVersionFileService.updateUnpkgWhiteList] version:%s, total %s packages, %s scopes', whiteListPackageVersion, Object.keys(__classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowPackages, "f")).length, __classPrivateFieldGet(this, _PackageVersionFileService_unpkgWhiteListAllowScopes, "f").length); }; _PackageVersionFileService_savePackageVersionFile = async function _PackageVersionFileService_savePackageVersionFile(pkg, pkgVersion, path, localFile) { const { directory, name } = __classPrivateFieldGet(this, _PackageVersionFileService_instances, "m", _PackageVersionFileService_getDirectoryAndName).call(this, path); let file = await this.packageVersionFileRepository.findPackageVersionFile(pkgVersion.packageVersionId, directory, name); if (file) return file; const stat = await promises_1.default.stat(localFile); const distIntegrity = await (0, PackageUtil_1.calculateIntegrity)(localFile); // make sure dist.path store to ascii, e.g. '/resource/ToOneFromχ.js' => '/resource/ToOneFrom%CF%87.js' // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI const distPath = encodeURI(path); const dist = pkg.createPackageVersionFile(distPath, pkgVersion.version, { size: stat.size, shasum: distIntegrity.shasum, integrity: distIntegrity.integrity, }); await this.distRepository.saveDist(dist, localFile); file = PackageVersionFile_1.PackageVersionFile.create({ packageVersionId: pkgVersion.packageVersionId, directory, name, dist, contentType: (0, FileUtil_1.mimeLookup)(path), mtime: pkgVersion.publishTime, }); try { await this.packageVersionFileRepository.createPackageVersionFile(file); this.logger.info('[PackageVersionFileService.#savePackageVersionFile:success] fileId: %s, size: %s, path: %s', file.packageVersionFileId, dist.size, file.path); } catch (err) { // ignore Duplicate entry if (err.code === 'ER_DUP_ENTRY') return file; throw err; } return file; }; _PackageVersionFileService_getDirectoryAndName = function _PackageVersionFileService_getDirectoryAndName(path) { return { directory: (0, node_path_1.dirname)(path), name: (0, node_path_1.basename)(path), }; }; _PackageVersionFileService_formatTarEntryFilename = function _PackageVersionFileService_formatTarEntryFilename(entry) { if (entry.type !== 'File') return; // ignore hidden dir if (entry.path.includes('/./')) return; // https://github.com/cnpm/cnpmcore/issues/452#issuecomment-1570077310 // strip first dir, e.g.: 'package/', 'lodash-es/' const filename = entry.path.split('/').slice(1).join('/'); return filename; }; _PackageVersionFileService_matchReadmeFilename = function _PackageVersionFileService_matchReadmeFilename(filename) { // support README,README.* // https://github.com/npm/read-package-json/blob/main/lib/read-json.js#L280 return (/^README(\.\w{1,20}|$)/i.test(filename)); }; _PackageVersionFileService_preferMarkdownReadme = function _PackageVersionFileService_preferMarkdownReadme(files) { let fallback = 0; const markdownRE = /\.m?a?r?k?d?o?w?n?$/i; for (let i = 0; i < files.length; i++) { const file = files[i]; if (markdownRE.test(file)) { return file; } else if (file.toLowerCase() === 'README') { fallback = i; } } // prefer README.md, followed by README; otherwise, return // the first filename (which could be README) return files[fallback]; }; __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageVersionRepository_1.PackageVersionRepository) ], PackageVersionFileService.prototype, "packageVersionRepository", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageRepository_1.PackageRepository) ], PackageVersionFileService.prototype, "packageRepository", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageVersionFileRepository_1.PackageVersionFileRepository) ], PackageVersionFileService.prototype, "packageVersionFileRepository", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", DistRepository_1.DistRepository) ], PackageVersionFileService.prototype, "distRepository", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageManagerService_1.PackageManagerService) ], PackageVersionFileService.prototype, "packageManagerService", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", CacheAdapter_1.CacheAdapter) ], PackageVersionFileService.prototype, "cacheAdapter", void 0); exports.PackageVersionFileService = PackageVersionFileService = __decorate([ (0, tegg_1.SingletonProto)({ accessLevel: tegg_1.AccessLevel.PUBLIC, }) ], PackageVersionFileService); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFja2FnZVZlcnNpb25GaWxlU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2FwcC9jb3JlL3NlcnZpY2UvUGFja2FnZVZlcnNpb25GaWxlU2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxnRUFBa0M7QUFDbEMseUNBQW9EO0FBQ3BELDZDQUF5QztBQUN6Qyx1REFBK0I7QUFDL0Isc0NBSXFCO0FBQ3JCLDJDQUEyRDtBQUMzRCxvREFBNEI7QUFDNUIsa0VBQStEO0FBQy9ELDBEQUdrQztBQUNsQyxvREFBa0U7QUFDbEUsMEVBRTRDO0FBQzVDLGdHQUE2RjtBQUM3Rix3RkFBcUY7QUFDckYsb0VBQWlFO0FBQ2pFLHFFQUFrRTtBQUdsRSxtRUFBZ0U7QUFDaEUsb0VBQWlFO0FBRWpFLE1BQU0saUJBQWlCLEdBQUcsMENBQTBDLENBQUM7QUFDckUsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztBQUszRCxJQUFNLHlCQUF5QixHQUEvQixNQUFNLHlCQUEwQixTQUFRLGlDQUFlO0lBQXZEOzs7UUFjTCw2REFBbUMsQ0FBQyxFQUFDO1FBQ3JDLGtFQUF3QyxFQUFFLEVBQUM7UUFDM0MsaUVBRUssRUFBRSxFQUFDO1FBQ1IsK0RBQXVDLEVBQUUsRUFBQztJQXlRNUMsQ0FBQztJQXZRQyxLQUFLLENBQUMsdUJBQXVCLENBQUMsVUFBMEIsRUFBRSxTQUFpQjtRQUN6RSxNQUFNLHVCQUFBLElBQUksc0dBQStCLE1BQW5DLElBQUksRUFBZ0MsVUFBVSxDQUFDLENBQUM7UUFDdEQsT0FBTyxNQUFNLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyx1QkFBdUIsQ0FBQyxVQUFVLENBQUMsZ0JBQWdCLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDakgs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