UNPKG

cnpmcore

Version:
910 lines 88.6 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var PackageManagerService_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.PackageManagerService = void 0; const promises_1 = require("node:fs/promises"); const tegg_1 = require("@eggjs/tegg"); const egg_errors_1 = require("egg-errors"); const npm_package_arg_1 = __importDefault(require("npm-package-arg")); const semver_1 = __importDefault(require("semver")); const PackageUtil_1 = require("../../common/PackageUtil"); const AbstractService_1 = require("../../common/AbstractService"); const PackageRepository_1 = require("../../repository/PackageRepository"); const PackageVersionBlockRepository_1 = require("../../repository/PackageVersionBlockRepository"); const PackageVersionDownloadRepository_1 = require("../../repository/PackageVersionDownloadRepository"); const DistRepository_1 = require("../../repository/DistRepository"); const Package_1 = require("../entity/Package"); const PackageVersion_1 = require("../entity/PackageVersion"); const PackageVersionBlock_1 = require("../entity/PackageVersionBlock"); const PackageTag_1 = require("../entity/PackageTag"); const event_1 = require("../event"); const BugVersionService_1 = require("./BugVersionService"); const RegistryManagerService_1 = require("./RegistryManagerService"); const PackageVersionService_1 = require("./PackageVersionService"); const TOTAL = '@@TOTAL@@'; const SCOPE_TOTAL_PREFIX = '@@SCOPE@@:'; const DESCRIPTION_LIMIT = 1024 * 10; let PackageManagerService = PackageManagerService_1 = class PackageManagerService extends AbstractService_1.AbstractService { // support user publish private package and sync worker publish public package async publish(cmd, publisher) { let pkg = await this.packageRepository.findPackage(cmd.scope, cmd.name); if (!pkg) { pkg = Package_1.Package.create({ scope: cmd.scope, name: cmd.name, isPrivate: cmd.isPrivate, description: cmd.description || '', registryId: cmd.registryId, }); } else { // update description // will read database twice to update description by model to entity and entity to model if (pkg.description !== cmd.description) { pkg.description = cmd.description || ''; } /* c8 ignore next 3 */ // package can be migrated into another registry if (cmd.registryId) { pkg.registryId = cmd.registryId; } } // 防止 description 长度超过 db 限制 if (pkg.description?.length > DESCRIPTION_LIMIT) { pkg.description = pkg.description.substring(0, DESCRIPTION_LIMIT); } await this.packageRepository.savePackage(pkg); // create maintainer await this.packageRepository.savePackageMaintainer(pkg.packageId, publisher.userId); let pkgVersion = await this.packageRepository.findPackageVersion(pkg.packageId, cmd.version); if (pkgVersion) { throw new egg_errors_1.ForbiddenError(`Can't modify pre-existing version: ${pkg.fullname}@${pkgVersion.version}`); } // make sure cmd.packageJson.readme is deleted if ('readme' in cmd.packageJson) { delete cmd.packageJson.readme; } const publishTime = cmd.publishTime || new Date(); // add _cnpmcore_publish_time field to cmd.packageJson if (!cmd.packageJson._cnpmcore_publish_time) { cmd.packageJson._cnpmcore_publish_time = publishTime; } if (!cmd.packageJson.publish_time) { cmd.packageJson.publish_time = publishTime.getTime(); } if (cmd.packageJson._hasShrinkwrap === undefined) { cmd.packageJson._hasShrinkwrap = await (0, PackageUtil_1.hasShrinkWrapInTgz)(cmd.dist.content || cmd.dist.localFile); } // set _npmUser field to cmd.packageJson cmd.packageJson._npmUser = { // clean user scope prefix name: publisher.displayName, email: publisher.email, }; // add _registry_name field to cmd.packageJson const registry = await this.getSourceRegistry(pkg); if (registry) { cmd.packageJson._source_registry_name = registry.name; } // https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#abbreviated-version-object const hasInstallScript = (0, PackageUtil_1.detectInstallScript)(cmd.packageJson) ? true : undefined; let tarDistIntegrity; let tarDistSize = 0; if (cmd.dist.content) { const tarDistBytes = cmd.dist.content; tarDistIntegrity = await (0, PackageUtil_1.calculateIntegrity)(tarDistBytes); tarDistSize = tarDistBytes.length; } else if (cmd.dist.localFile) { const localFile = cmd.dist.localFile; const fileStat = await (0, promises_1.stat)(localFile); tarDistIntegrity = await (0, PackageUtil_1.calculateIntegrity)(localFile); tarDistSize = fileStat.size; } const tarDist = pkg.createTar(cmd.version, { size: tarDistSize, shasum: tarDistIntegrity.shasum, integrity: tarDistIntegrity.integrity, }); if (cmd.dist.content) { await this.distRepository.saveDist(tarDist, cmd.dist.content); } else if (cmd.dist.localFile) { await this.distRepository.saveDist(tarDist, cmd.dist.localFile); } cmd.packageJson.dist = { ...cmd.packageJson.dist, tarball: (0, PackageUtil_1.formatTarball)(this.config.cnpmcore.registry, pkg.scope, pkg.name, cmd.version), size: tarDistSize, shasum: tarDistIntegrity.shasum, integrity: tarDistIntegrity.integrity, }; // https://github.com/npm/registry/blob/main/docs/responses/package-metadata.md#abbreviated-version-object // Abbreviated version object const abbreviated = JSON.stringify({ name: cmd.packageJson.name, version: cmd.packageJson.version, deprecated: cmd.packageJson.deprecated, dependencies: cmd.packageJson.dependencies, acceptDependencies: cmd.packageJson.acceptDependencies, optionalDependencies: cmd.packageJson.optionalDependencies, devDependencies: cmd.packageJson.devDependencies, bundleDependencies: cmd.packageJson.bundleDependencies, peerDependencies: cmd.packageJson.peerDependencies, peerDependenciesMeta: cmd.packageJson.peerDependenciesMeta, bin: cmd.packageJson.bin, directories: cmd.packageJson.directories, os: cmd.packageJson.os, cpu: cmd.packageJson.cpu, libc: cmd.packageJson.libc, workspaces: cmd.packageJson.workspaces, dist: cmd.packageJson.dist, engines: cmd.packageJson.engines, _hasShrinkwrap: cmd.packageJson._hasShrinkwrap, hasInstallScript, funding: cmd.packageJson.funding, // https://github.com/cnpm/npminstall/blob/13efc7eec21a61e509226e3772bfb75cd5605612/lib/install_package.js#L176 // npminstall require publish time to show the recently update versions publish_time: cmd.packageJson.publish_time, _source_registry_name: cmd.packageJson._source_registry_name, }); const abbreviatedDistBytes = Buffer.from(abbreviated); const abbreviatedDistIntegrity = await (0, PackageUtil_1.calculateIntegrity)(abbreviatedDistBytes); const readmeDistBytes = Buffer.from(cmd.readme); const readmeDistIntegrity = await (0, PackageUtil_1.calculateIntegrity)(readmeDistBytes); const manifestDistBytes = Buffer.from(JSON.stringify(cmd.packageJson)); const manifestDistIntegrity = await (0, PackageUtil_1.calculateIntegrity)(manifestDistBytes); pkgVersion = PackageVersion_1.PackageVersion.create({ packageId: pkg.packageId, version: cmd.version, publishTime, manifestDist: pkg.createManifest(cmd.version, { size: manifestDistBytes.length, shasum: manifestDistIntegrity.shasum, integrity: manifestDistIntegrity.integrity, }), readmeDist: pkg.createReadme(cmd.version, { size: readmeDistBytes.length, shasum: readmeDistIntegrity.shasum, integrity: readmeDistIntegrity.integrity, }), abbreviatedDist: pkg.createAbbreviated(cmd.version, { size: abbreviatedDistBytes.length, shasum: abbreviatedDistIntegrity.shasum, integrity: abbreviatedDistIntegrity.integrity, }), tarDist, }); await Promise.all([ this.distRepository.saveDist(pkgVersion.abbreviatedDist, abbreviatedDistBytes), this.distRepository.saveDist(pkgVersion.manifestDist, manifestDistBytes), this.distRepository.saveDist(pkgVersion.readmeDist, readmeDistBytes), ]); try { await this.packageRepository.createPackageVersion(pkgVersion); } catch (e) { if (e.code === 'ER_DUP_ENTRY') { throw new egg_errors_1.ForbiddenError(`Can't modify pre-existing version: ${pkg.fullname}@${cmd.version}`); } throw e; } if (cmd.skipRefreshPackageManifests !== true) { await this.refreshPackageChangeVersionsToDists(pkg, [pkgVersion.version]); } if (cmd.tags) { for (const tag of cmd.tags) { await this.savePackageTag(pkg, tag, cmd.version, true); this.eventBus.emit(event_1.PACKAGE_VERSION_ADDED, pkg.fullname, pkgVersion.version, tag); } } else { this.eventBus.emit(event_1.PACKAGE_VERSION_ADDED, pkg.fullname, pkgVersion.version, undefined); } return pkgVersion; } async blockPackageByFullname(name, reason) { const [scope, pkgName] = (0, PackageUtil_1.getScopeAndName)(name); const pkg = await this.packageRepository.findPackage(scope, pkgName); if (!pkg) { throw new egg_errors_1.NotFoundError(`Package name(${name}) not found`); } return await this.blockPackage(pkg, reason); } async blockPackage(pkg, reason) { let block = await this.packageVersionBlockRepository.findPackageBlock(pkg.packageId); if (block) { block.reason = reason; } else { block = PackageVersionBlock_1.PackageVersionBlock.create({ packageId: pkg.packageId, version: '*', reason, }); } await this.packageVersionBlockRepository.savePackageVersionBlock(block); if (pkg.manifestsDist && pkg.abbreviatedsDist) { const fullManifests = await this.distRepository.readDistBytesToJSON(pkg.manifestsDist); if (fullManifests) { fullManifests.block = reason; } const abbreviatedManifests = await this.distRepository.readDistBytesToJSON(pkg.abbreviatedsDist); if (abbreviatedManifests) { abbreviatedManifests.block = reason; } await this._updatePackageManifestsToDists(pkg, fullManifests || null, abbreviatedManifests || null); this.eventBus.emit(event_1.PACKAGE_BLOCKED, pkg.fullname); this.logger.info('[packageManagerService.blockPackage:success] packageId: %s, reason: %j', pkg.packageId, reason); } return block; } async unblockPackageByFullname(name) { const [scope, pkgName] = (0, PackageUtil_1.getScopeAndName)(name); const pkg = await this.packageRepository.findPackage(scope, pkgName); if (!pkg) { throw new egg_errors_1.NotFoundError(`Package name(${name}) not found`); } return await this.unblockPackage(pkg); } async unblockPackage(pkg) { const block = await this.packageVersionBlockRepository.findPackageVersionBlock(pkg.packageId, '*'); if (block) { await this.packageVersionBlockRepository.removePackageVersionBlock(block.packageVersionBlockId); } if (pkg.manifestsDist && pkg.abbreviatedsDist) { const fullManifests = await this.distRepository.readDistBytesToJSON(pkg.manifestsDist); if (fullManifests) { fullManifests.block = undefined; } const abbreviatedManifests = await this.distRepository.readDistBytesToJSON(pkg.abbreviatedsDist); if (abbreviatedManifests) { abbreviatedManifests.block = undefined; } await this._updatePackageManifestsToDists(pkg, fullManifests || null, abbreviatedManifests || null); this.eventBus.emit(event_1.PACKAGE_UNBLOCKED, pkg.fullname); this.logger.info('[packageManagerService.unblockPackage:success] packageId: %s', pkg.packageId); } } async replacePackageMaintainersAndDist(pkg, maintainers) { await this.packageRepository.replacePackageMaintainers(pkg.packageId, maintainers.map(m => m.userId)); await this.refreshPackageMaintainersToDists(pkg); this.eventBus.emit(event_1.PACKAGE_MAINTAINER_CHANGED, pkg.fullname, maintainers); } async savePackageMaintainers(pkg, maintainers) { let hasNewRecord = false; for (const maintainer of maintainers) { const newRecord = await this.packageRepository.savePackageMaintainer(pkg.packageId, maintainer.userId); if (newRecord) { hasNewRecord = true; } } if (hasNewRecord) { this.eventBus.emit(event_1.PACKAGE_MAINTAINER_CHANGED, pkg.fullname, maintainers); } } async removePackageMaintainer(pkg, maintainer) { await this.packageRepository.removePackageMaintainer(pkg.packageId, maintainer.userId); this.eventBus.emit(event_1.PACKAGE_MAINTAINER_REMOVED, pkg.fullname, maintainer.name); } async refreshPackageMaintainersToDists(pkg) { await this._refreshPackageManifestRootAttributeOnlyToDists(pkg, 'maintainers'); } async refreshPackageDistTagsToDists(pkg) { await this._refreshPackageManifestRootAttributeOnlyToDists(pkg, 'dist-tags'); } async listPackageFullManifests(scope, name, isSync = false) { return await this._listPackageFullOrAbbreviatedManifests(scope, name, true, isSync); } async listPackageAbbreviatedManifests(scope, name, isSync = false) { return await this._listPackageFullOrAbbreviatedManifests(scope, name, false, isSync); } async showPackageVersionByVersionOrTag(scope, name, spec) { const pkg = await this.packageRepository.findPackage(scope, name); if (!pkg) return {}; const block = await this.packageVersionBlockRepository.findPackageBlock(pkg.packageId); if (block) { return { blockReason: block.reason, pkg }; } const fullname = (0, PackageUtil_1.getFullname)(scope, name); const result = (0, npm_package_arg_1.default)(`${fullname}@${spec}`); const version = await this.packageVersionService.getVersion(result); if (!version) { return {}; } const packageVersion = await this.packageRepository.findPackageVersion(pkg.packageId, version); return { packageVersion, pkg }; } async showPackageVersionManifest(scope, name, spec, isSync = false, isFullManifests = false) { const pkg = await this.packageRepository.findPackage(scope, name); if (!pkg) return {}; const block = await this.packageVersionBlockRepository.findPackageBlock(pkg.packageId); if (block) { return { blockReason: block.reason, pkg }; } const fullname = (0, PackageUtil_1.getFullname)(scope, name); const result = (0, npm_package_arg_1.default)(`${fullname}@${spec}`); const manifest = await this.packageVersionService.readManifest(pkg.packageId, result, isFullManifests, !isSync); return { manifest, blockReason: null, pkg }; } async downloadPackageVersionTar(packageVersion) { return await this.distRepository.downloadDist(packageVersion.tarDist); } plusPackageVersionCounter(fullname, version) { // set counter + 1, schedule will store them into database const counters = PackageManagerService_1.downloadCounters; if (!counters[fullname]) counters[fullname] = {}; counters[fullname][version] = (counters[fullname][version] || 0) + 1; // Total const ALL = '*'; if (!counters[TOTAL]) counters[TOTAL] = {}; counters[TOTAL][ALL] = (counters[TOTAL][ALL] || 0) + 1; // scope total const scope = (0, PackageUtil_1.getScopeAndName)(fullname)[0]; if (scope) { const scopeKey = `${SCOPE_TOTAL_PREFIX}${scope}`; if (!counters[scopeKey]) counters[scopeKey] = {}; counters[scopeKey][ALL] = (counters[scopeKey][ALL] || 0) + 1; } } // will be call by schedule/SavePackageVersionDownloadCounter.ts async savePackageVersionCounters() { // { [fullname]: { [version]: number } } const counters = PackageManagerService_1.downloadCounters; const fullnames = Object.keys(counters); if (fullnames.length === 0) return; PackageManagerService_1.downloadCounters = {}; this.logger.info('[packageManagerService.savePackageVersionCounters:saving] %d fullnames', fullnames.length); let total = 0; for (const fullname in counters) { const versions = counters[fullname]; let packageId = null; if (fullname === TOTAL) { packageId = 'total'; } else if (fullname.startsWith(SCOPE_TOTAL_PREFIX)) { packageId = fullname.replace(SCOPE_TOTAL_PREFIX, ''); } else { // find packageId from fullname const [scope, name] = (0, PackageUtil_1.getScopeAndName)(fullname); packageId = await this.packageRepository.findPackageId(scope, name); } if (!packageId) continue; for (const version in versions) { const counter = versions[version]; await this.packageVersionDownloadRepository.plus(packageId, version, counter); total += counter; } } this.logger.info('[packageManagerService.savePackageVersionCounters:saved] %d total', total); } async saveDeprecatedVersions(pkg, deprecatedList) { const updateVersions = []; for (const { version, deprecated } of deprecatedList) { const pkgVersion = await this.packageRepository.findPackageVersion(pkg.packageId, version); if (!pkgVersion) continue; const message = deprecated === '' ? undefined : deprecated; await this._mergeManifestDist(pkgVersion.manifestDist, { deprecated: message }); await this._mergeManifestDist(pkgVersion.abbreviatedDist, { deprecated: message }); await this.packageRepository.savePackageVersion(pkgVersion); updateVersions.push(version); } await this.refreshPackageChangeVersionsToDists(pkg, updateVersions); this.eventBus.emit(event_1.PACKAGE_META_CHANGED, pkg.fullname, { deprecateds: deprecatedList }); } async savePackageVersionManifest(pkgVersion, mergeManifest, mergeAbbreviated) { await this._mergeManifestDist(pkgVersion.manifestDist, mergeManifest); await this._mergeManifestDist(pkgVersion.abbreviatedDist, mergeAbbreviated); } /** * save package version readme */ async savePackageVersionReadme(pkgVersion, readmeFile) { await this.distRepository.saveDist(pkgVersion.readmeDist, readmeFile); this.logger.info('[PackageManagerService.savePackageVersionReadme] save packageVersionId:%s readme:%s to dist:%s', pkgVersion.packageVersionId, readmeFile, pkgVersion.readmeDist.distId); } async savePackageReadme(pkg, readmeFile) { if (!pkg.manifestsDist) return; const fullManifests = await this.distRepository.readDistBytesToJSON(pkg.manifestsDist); if (!fullManifests) return; fullManifests.readme = await (0, promises_1.readFile)(readmeFile, 'utf-8'); await this._updatePackageManifestsToDists(pkg, fullManifests, null); this.logger.info('[PackageManagerService.savePackageReadme] save packageId:%s readme, size: %s', pkg.packageId, fullManifests.readme.length); } async _removePackageVersionAndDist(pkgVersion) { // remove nfs dists await Promise.all([ this.distRepository.destroyDist(pkgVersion.abbreviatedDist), this.distRepository.destroyDist(pkgVersion.manifestDist), this.distRepository.destroyDist(pkgVersion.readmeDist), this.distRepository.destroyDist(pkgVersion.tarDist), ]); // remove from repository await this.packageRepository.removePackageVersion(pkgVersion); } async unpublishPackage(pkg) { const pkgVersions = await this.packageRepository.listPackageVersions(pkg.packageId); // already unpublished if (pkgVersions.length === 0) { this.logger.info(`[packageManagerService.unpublishPackage:skip] ${pkg.packageId} already unpublished`); return; } for (const pkgVersion of pkgVersions) { await this._removePackageVersionAndDist(pkgVersion); } // set unpublished dist to package's manifestDist and abbreviatedDist const unpublishedInfo = { _id: pkg.fullname, name: pkg.fullname, time: { created: pkg.createdAt, modified: pkg.updatedAt, unpublished: new Date(), }, // keep this property exists for forward compatibility // https://github.com/cnpm/cnpmjs.org/blob/ad622d55e384743b48e79bb6aec574a7f354ee9f/controllers/sync_module_worker.js#L828 'dist-tags': {}, }; await this._mergeManifestDist(pkg.manifestsDist, undefined, unpublishedInfo); await this._mergeManifestDist(pkg.abbreviatedsDist, undefined, unpublishedInfo); this.eventBus.emit(event_1.PACKAGE_UNPUBLISHED, pkg.fullname); } async removePackageVersion(pkg, pkgVersion, skipRefreshPackageManifests = false) { const currentVersions = await this.packageRepository.listPackageVersionNames(pkg.packageId); // only one version, unpublish the package if (currentVersions.length === 1 && currentVersions[0] === pkgVersion.version) { await this.unpublishPackage(pkg); return; } // remove version & update tags await this._removePackageVersionAndDist(pkgVersion); const versions = await this.packageRepository.listPackageVersionNames(pkg.packageId); if (versions.length > 0) { let updateTag; // make sure latest tag exists const latestTag = await this.packageRepository.findPackageTag(pkg.packageId, 'latest'); if (latestTag?.version === pkgVersion.version) { // change latest version // https://github.com/npm/libnpmpublish/blob/main/unpublish.js#L62 const latestVersion = versions.sort(semver_1.default.compareLoose).pop(); if (latestVersion) { updateTag = latestTag.tag; await this.savePackageTag(pkg, latestTag.tag, latestVersion, true); } } if (skipRefreshPackageManifests !== true) { await this.refreshPackageChangeVersionsToDists(pkg, undefined, [pkgVersion.version]); this.eventBus.emit(event_1.PACKAGE_VERSION_REMOVED, pkg.fullname, pkgVersion.version, updateTag); } return; } } async savePackageTag(pkg, tag, version, skipEvent = false) { let tagEntity = await this.packageRepository.findPackageTag(pkg.packageId, tag); if (!tagEntity) { tagEntity = PackageTag_1.PackageTag.create({ packageId: pkg.packageId, tag, version, }); await this.packageRepository.savePackageTag(tagEntity); await this._refreshPackageManifestRootAttributeOnlyToDists(pkg, 'dist-tags'); if (!skipEvent) { this.eventBus.emit(event_1.PACKAGE_TAG_ADDED, pkg.fullname, tagEntity.tag); } return true; } if (tagEntity.version === version) { // nothing change return false; } tagEntity.version = version; await this.packageRepository.savePackageTag(tagEntity); await this._refreshPackageManifestRootAttributeOnlyToDists(pkg, 'dist-tags'); if (!skipEvent) { this.eventBus.emit(event_1.PACKAGE_TAG_CHANGED, pkg.fullname, tagEntity.tag); } return true; } async removePackageTag(pkg, tag) { const tagEntity = await this.packageRepository.findPackageTag(pkg.packageId, tag); if (!tagEntity) return false; await this.packageRepository.removePackageTag(tagEntity); await this._refreshPackageManifestRootAttributeOnlyToDists(pkg, 'dist-tags'); this.eventBus.emit(event_1.PACKAGE_TAG_REMOVED, pkg.fullname, tagEntity.tag); return true; } async refreshPackageChangeVersionsToDists(pkg, updateVersions, removeVersions) { if (!pkg.manifestsDist?.distId || !pkg.abbreviatedsDist?.distId) { return await this._refreshPackageManifestsToDists(pkg); } const fullManifests = await this.distRepository.readDistBytesToJSON(pkg.manifestsDist); const abbreviatedManifests = await this.distRepository.readDistBytesToJSON(pkg.abbreviatedsDist); if (!fullManifests?.versions || !abbreviatedManifests?.versions) { // is unpublished, refresh all again return await this._refreshPackageManifestsToDists(pkg); } if (updateVersions) { for (const version of updateVersions) { const packageVersion = await this.packageRepository.findPackageVersion(pkg.packageId, version); if (packageVersion) { const manifest = await this.distRepository.readDistBytesToJSON(packageVersion.manifestDist); if (!manifest) continue; if ('readme' in manifest) { delete manifest.readme; } fullManifests.versions[packageVersion.version] = manifest; fullManifests.time[packageVersion.version] = packageVersion.publishTime; const abbreviatedManifest = await this.distRepository.readDistBytesToJSON(packageVersion.abbreviatedDist); if (abbreviatedManifest) { abbreviatedManifests.versions[packageVersion.version] = abbreviatedManifest; } } } } if (removeVersions) { for (const version of removeVersions) { delete fullManifests.versions[version]; delete fullManifests.time[version]; delete abbreviatedManifests.versions[version]; } } // update dist-tags await this._setPackageDistTagsAndLatestInfos(pkg, fullManifests, abbreviatedManifests); // store to nfs dist await this._updatePackageManifestsToDists(pkg, fullManifests, abbreviatedManifests); } async getSourceRegistry(pkg) { let registry; if (pkg.registryId) { registry = await this.registryManagerService.findByRegistryId(pkg.registryId); } else { registry = await this.registryManagerService.ensureDefaultRegistry(); } return registry; } async _listPackageDistTags(pkg) { const tags = await this.packageRepository.listPackageTags(pkg.packageId); const distTags = {}; for (const tag of tags) { distTags[tag.tag] = tag.version; } return distTags; } // refresh package full manifests and abbreviated manifests to NFS async _refreshPackageManifestsToDists(pkg) { const [fullManifests, abbreviatedManifests,] = await Promise.all([ await this._listPackageFullManifests(pkg), await this._listPackageAbbreviatedManifests(pkg), ]); await this._updatePackageManifestsToDists(pkg, fullManifests, abbreviatedManifests); } // only refresh root attributes only, e.g.: dist-tags, maintainers async _refreshPackageManifestRootAttributeOnlyToDists(pkg, refreshAttr) { if (refreshAttr === 'maintainers') { const fullManifests = await this.distRepository.readDistBytesToJSON(pkg.manifestsDist); const maintainers = await this._listPackageMaintainers(pkg); if (fullManifests) { fullManifests.maintainers = maintainers; await this._updatePackageManifestsToDists(pkg, fullManifests, null); } } else if (refreshAttr === 'dist-tags') { const fullManifests = await this.distRepository.readDistBytesToJSON(pkg.manifestsDist); if (fullManifests) { const abbreviatedManifests = await this.distRepository.readDistBytesToJSON(pkg.abbreviatedsDist); if (abbreviatedManifests) { await this._setPackageDistTagsAndLatestInfos(pkg, fullManifests, abbreviatedManifests); } await this._updatePackageManifestsToDists(pkg, fullManifests, abbreviatedManifests || null); } } } _mergeLatestManifestFields(fullManifests, latestManifest) { if (!latestManifest) return; // https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#full-metadata-format const fieldsFromLatestManifest = [ 'author', 'bugs', 'contributors', 'description', 'homepage', 'keywords', 'license', 'readmeFilename', 'repository', ]; // the latest version metas for (const field of fieldsFromLatestManifest) { if (latestManifest[field]) { fullManifests[field] = latestManifest[field]; } } } async _setPackageDistTagsAndLatestInfos(pkg, fullManifests, abbreviatedManifests) { const distTags = await this._listPackageDistTags(pkg); if (distTags.latest) { const packageVersion = await this.packageRepository.findPackageVersion(pkg.packageId, distTags.latest); if (packageVersion) { fullManifests.readme = await this.distRepository.readDistBytesToString(packageVersion.readmeDist); const latestManifest = await this.distRepository.readDistBytesToJSON(packageVersion.manifestDist); this._mergeLatestManifestFields(fullManifests, latestManifest || null); } } fullManifests['dist-tags'] = distTags; abbreviatedManifests['dist-tags'] = distTags; } async _mergeManifestDist(manifestDist, mergeData, replaceData) { let manifest = await this.distRepository.readDistBytesToJSON(manifestDist); if (mergeData && manifest) { Object.assign(manifest, mergeData); } if (replaceData) { manifest = replaceData; } const manifestBytes = Buffer.from(JSON.stringify(manifest)); const manifestIntegrity = await (0, PackageUtil_1.calculateIntegrity)(manifestBytes); manifestDist.size = manifestBytes.length; manifestDist.shasum = manifestIntegrity.shasum; manifestDist.integrity = manifestIntegrity.integrity; await this.distRepository.saveDist(manifestDist, manifestBytes); } async _updatePackageManifestsToDists(pkg, fullManifests, abbreviatedManifests) { const modified = new Date(); if (fullManifests) { fullManifests.time.modified = modified; // same to dist const fullManifestsDistBytes = Buffer.from(JSON.stringify(fullManifests)); const fullManifestsDistIntegrity = await (0, PackageUtil_1.calculateIntegrity)(fullManifestsDistBytes); if (pkg.manifestsDist?.distId) { pkg.manifestsDist.size = fullManifestsDistBytes.length; pkg.manifestsDist.shasum = fullManifestsDistIntegrity.shasum; pkg.manifestsDist.integrity = fullManifestsDistIntegrity.integrity; } else { pkg.manifestsDist = pkg.createFullManifests({ size: fullManifestsDistBytes.length, shasum: fullManifestsDistIntegrity.shasum, integrity: fullManifestsDistIntegrity.integrity, }); } await this.distRepository.saveDist(pkg.manifestsDist, fullManifestsDistBytes); await this.packageRepository.savePackageDist(pkg, true); } if (abbreviatedManifests) { abbreviatedManifests.modified = modified; const abbreviatedManifestsDistBytes = Buffer.from(JSON.stringify(abbreviatedManifests)); const abbreviatedManifestsDistIntegrity = await (0, PackageUtil_1.calculateIntegrity)(abbreviatedManifestsDistBytes); if (pkg.abbreviatedsDist?.distId) { pkg.abbreviatedsDist.size = abbreviatedManifestsDistBytes.length; pkg.abbreviatedsDist.shasum = abbreviatedManifestsDistIntegrity.shasum; pkg.abbreviatedsDist.integrity = abbreviatedManifestsDistIntegrity.integrity; } else { pkg.abbreviatedsDist = pkg.createAbbreviatedManifests({ size: abbreviatedManifestsDistBytes.length, shasum: abbreviatedManifestsDistIntegrity.shasum, integrity: abbreviatedManifestsDistIntegrity.integrity, }); } await this.distRepository.saveDist(pkg.abbreviatedsDist, abbreviatedManifestsDistBytes); await this.packageRepository.savePackageDist(pkg, false); } } async _listPackageFullOrAbbreviatedManifests(scope, name, isFullManifests, isSync) { let etag = ''; let blockReason = ''; const pkg = await this.packageRepository.findPackage(scope, name); if (!pkg) return { etag, data: null, blockReason }; const registry = await this.getSourceRegistry(pkg); const block = await this.packageVersionBlockRepository.findPackageBlock(pkg.packageId); if (block) { blockReason = block.reason; } let bugVersion; // sync mode response no bug version fixed if (!isSync) { bugVersion = await this.bugVersionService.getBugVersion(); } const fullname = (0, PackageUtil_1.getFullname)(scope, name); let dist = isFullManifests ? pkg.manifestsDist : pkg.abbreviatedsDist; // read from dist if (dist?.distId) { etag = `"${dist.shasum}"`; const data = (await this.distRepository.readDistBytesToJSON(dist)); if (bugVersion) { await this.bugVersionService.fixPackageBugVersions(bugVersion, fullname, data.versions); } // set _source_registry_name in full manifestDist if (registry) { data._source_registry_name = registry?.name; } const distBytes = Buffer.from(JSON.stringify(data)); const distIntegrity = await (0, PackageUtil_1.calculateIntegrity)(distBytes); etag = `"${distIntegrity.shasum}"`; return { etag, data, blockReason }; } // read from database const fullManifests = isFullManifests ? await this._listPackageFullManifests(pkg) : null; const abbreviatedManifests = isFullManifests ? null : await this._listPackageAbbreviatedManifests(pkg); if (!fullManifests && !abbreviatedManifests) { // not exists return { etag, data: null, blockReason }; } await this._updatePackageManifestsToDists(pkg, fullManifests, abbreviatedManifests); const manifests = (fullManifests || abbreviatedManifests); /* c8 ignore next 5 */ if (bugVersion) { await this.bugVersionService.fixPackageBugVersions(bugVersion, fullname, manifests.versions); const distBytes = Buffer.from(JSON.stringify(manifests)); const distIntegrity = await (0, PackageUtil_1.calculateIntegrity)(distBytes); etag = `"${distIntegrity.shasum}"`; } else { dist = isFullManifests ? pkg.manifestsDist : pkg.abbreviatedsDist; etag = `"${dist.shasum}"`; } return { etag, data: manifests, blockReason }; } async _listPackageMaintainers(pkg) { const users = await this.packageRepository.listPackageMaintainers(pkg.packageId); return users.map(({ displayName, email }) => ({ name: displayName, email })); } async _listPackageFullManifests(pkg) { // read all verions from db const packageVersions = await this.packageRepository.listPackageVersions(pkg.packageId); if (packageVersions.length === 0) return null; const distTags = await this._listPackageDistTags(pkg); const maintainers = await this._listPackageMaintainers(pkg); const registry = await this.getSourceRegistry(pkg); // https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#full-metadata-format const data = { _id: `${pkg.fullname}`, _rev: `${pkg.id}-${pkg.packageId}`, 'dist-tags': distTags, // the package name name: pkg.fullname, // an object mapping versions to the time published, along with created and modified timestamps time: { // '1.0.0': '2012-09-18T14:46:08.346Z', created: pkg.createdAt, modified: pkg.updatedAt, }, // a mapping of semver-compliant version numbers to version data versions: {}, // The following fields are hoisted to the top-level of the package json from the latest version published: // human object author: undefined, bugs: undefined, description: pkg.description, homepage: undefined, keywords: undefined, // the SPDX identifier of the package's license license: undefined, // array of human objects for people with permission to publish this package; not authoritative but informational maintainers, // contributors: array of human objects // the first 64K of the README data for the most-recently published version of the package readme: '', // The name of the file from which the readme data was taken readmeFilename: undefined, // as given in package.json, for the latest version repository: undefined, // users: an object whose keys are the npm user names of people who have starred this package _source_registry_name: registry?.name, }; let latestTagVersion = ''; if (distTags.latest) { latestTagVersion = distTags.latest; } let latestManifest; let latestPackageVersion = packageVersions[0]; // https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#package-metadata for (const packageVersion of packageVersions) { const manifest = await this.distRepository.readDistBytesToJSON(packageVersion.manifestDist); if (!manifest) continue; /* c8 ignore next 3 */ if ('readme' in manifest) { delete manifest.readme; } if (latestTagVersion && packageVersion.version === latestTagVersion) { latestManifest = manifest; latestPackageVersion = packageVersion; } data.versions[packageVersion.version] = manifest; data.time[packageVersion.version] = packageVersion.publishTime; } // the latest version readme data.readme = await this.distRepository.readDistBytesToString(latestPackageVersion.readmeDist); if (!latestManifest) { latestManifest = data.versions[latestPackageVersion.version]; } this._mergeLatestManifestFields(data, latestManifest); return data; } async _listPackageAbbreviatedManifests(pkg) { // read all verions from db const packageVersions = await this.packageRepository.listPackageVersions(pkg.packageId); if (packageVersions.length === 0) return null; const distTags = await this._listPackageDistTags(pkg); // https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#package-metadata // tiny-tarball is a small package with only one version and no dependencies. const data = { 'dist-tags': distTags, modified: pkg.updatedAt, name: pkg.fullname, versions: {}, }; for (const packageVersion of packageVersions) { const manifest = await this.distRepository.readDistBytesToJSON(packageVersion.abbreviatedDist); if (manifest) { data.versions[packageVersion.version] = manifest; } } return data; } }; exports.PackageManagerService = PackageManagerService; PackageManagerService.downloadCounters = {}; __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", Object) ], PackageManagerService.prototype, "eventBus", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageRepository_1.PackageRepository) ], PackageManagerService.prototype, "packageRepository", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageVersionBlockRepository_1.PackageVersionBlockRepository) ], PackageManagerService.prototype, "packageVersionBlockRepository", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageVersionDownloadRepository_1.PackageVersionDownloadRepository) ], PackageManagerService.prototype, "packageVersionDownloadRepository", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", BugVersionService_1.BugVersionService) ], PackageManagerService.prototype, "bugVersionService", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", DistRepository_1.DistRepository) ], PackageManagerService.prototype, "distRepository", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", RegistryManagerService_1.RegistryManagerService) ], PackageManagerService.prototype, "registryManagerService", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageVersionService_1.PackageVersionService) ], PackageManagerService.prototype, "packageVersionService", void 0); exports.PackageManagerService = PackageManagerService = PackageManagerService_1 = __decorate([ (0, tegg_1.SingletonProto)({ accessLevel: tegg_1.AccessLevel.PUBLIC, }) ], PackageManagerService); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFja2FnZU1hbmFnZXJTZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vYXBwL2NvcmUvc2VydmljZS9QYWNrYWdlTWFuYWdlclNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLCtDQUFrRDtBQUNsRCxzQ0FLcUI7QUFDckIsMkNBQTJEO0FBRTNELHNFQUFrQztBQUNsQyxvREFBNEI7QUFDNUIsMERBT2tDO0FBQ2xDLGtFQUErRDtBQUMvRCwwRUFBeUs7QUFDekssa0dBQStGO0FBQy9GLHdHQUFxRztBQUNyRyxvRUFBaUU7QUFDakUsK0NBQTRDO0FBQzVDLDZEQUEwRDtBQUMxRCx1RUFBb0U7QUFDcEUscURBQWtEO0FBR2xELG9DQVlrQjtBQUNsQiwyREFBd0Q7QUFFeEQscUVBQWtFO0FBRWxFLG1FQUFnRTtBQTJCaEUsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDO0FBQzFCLE1BQU0sa0JBQWtCLEdBQUcsWUFBWSxDQUFDO0FBQ3hDLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztBQUs3QixJQUFNLHFCQUFxQiw2QkFBM0IsTUFBTSxxQkFBc0IsU0FBUSxpQ0FBZTtJQW9CeEQsOEVBQThFO0lBQzlFLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBc0IsRUFBRSxTQUFlO1FBQ25ELElBQUksR0FBRyxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN4RSxJQUFJLENBQUMsR0FBRyxFQUFFO1lBQ1IsR0FBRyxHQUFHLGlCQUFPLENBQUMsTUFBTSxDQUFDO2dCQUNuQixLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7Z0JBQ2hCLElBQUksRUFBRSxHQUFHLENBQUMsSUFBSTtnQkFDZCxTQUFTLEVBQUUsR0FBRyxDQUFDLFNBQVM7Z0JBQ3hCLFdBQVcs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