cnpmcore
Version:
Private NPM Registry for Enterprise
322 lines • 24.2 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 { errors } from '@elastic/elasticsearch';
import dayjs from 'dayjs';
import { AccessLevel, Inject, SingletonProto } from 'egg';
import { AbstractService } from "../../common/AbstractService.js";
import { formatAuthor, getScopeAndName } from "../../common/PackageUtil.js";
let PackageSearchService = class PackageSearchService extends AbstractService {
async syncPackage(fullname, isSync = true) {
const [scope, name] = getScopeAndName(fullname);
const { blockReason, manifest: latestManifest, pkg, } = await this.packageManagerService.showPackageVersionManifest(scope, name, 'latest', isSync, true);
if (!pkg || !latestManifest) {
this.logger.warn('[PackageSearchService.syncPackage] findPackage:%s not found', fullname);
return;
}
if (blockReason) {
this.logger.warn('[PackageSearchService.syncPackage] package:%s is blocked, try to remove es', fullname);
await this.removePackage(fullname);
return;
}
// get last year download data
const startDate = dayjs().subtract(1, 'year');
const endDate = dayjs();
const entities = await this.packageVersionDownloadRepository.query(pkg.packageId, startDate.toDate(), endDate.toDate());
let downloadsAll = 0;
for (const entity of entities) {
for (let i = 1; i <= 31; i++) {
const day = String(i).padStart(2, '0');
const field = `d${day}`;
const counter = entity[field];
if (!counter)
continue;
downloadsAll += counter;
}
}
let time = {};
let _rev = '';
let keywords;
let description;
const builder = await this.distRepository.readDistBytesToJSONBuilder(pkg.manifestsDist);
if (builder) {
time = builder.getIn(['time']);
_rev = builder.getIn(['_rev']);
keywords = builder.getIn(['keywords']);
description = builder.getIn(['description']);
}
const versions = await this.packageVersionRepository.findAllVersions(scope, name);
const distTags = await this.packageManagerService.distTags(pkg);
const packageDoc = {
name: latestManifest.name,
version: latestManifest.version,
_rev,
scope: scope ? scope.replace('@', '') : 'unscoped',
keywords: keywords || latestManifest.keywords || [],
versions,
description,
license: typeof latestManifest.license === 'object' ? latestManifest.license?.type : latestManifest.license,
maintainers: latestManifest.maintainers,
author: formatAuthor(latestManifest.author),
'dist-tags': distTags,
date: time[latestManifest.version],
created: time.created,
modified: time.modified,
// 归属 registry,keywords 枚举值
_source_registry_name: latestManifest._source_registry_name,
// 最新版本发布人 _npmUser:
_npmUser: latestManifest?._npmUser,
// 最新版本发布信息
publish_time: latestManifest?.publish_time,
// deprecated message of the latest version
deprecated: latestManifest?.deprecated,
};
// http://npmmirror.com/package/npm/files/lib/utils/format-search-stream.js#L147-L148
// npm cli 使用 username 字段
if (packageDoc.maintainers) {
packageDoc.maintainers = packageDoc.maintainers.map((maintainer) => {
return {
username: maintainer.name,
...maintainer,
};
});
}
const document = {
package: packageDoc,
downloads: {
all: downloadsAll,
},
};
return await this.searchRepository.upsertPackage(document);
}
async searchPackage(text, from, size) {
const matchQueries = this._buildMatchQueries(text);
const scriptScore = this._buildScriptScore({
text,
scoreEffect: 0.25,
});
const mustNotQueries = this._buildMustNotQueries();
const filterQueries = this._buildFilterQueries();
const res = await this.searchRepository.searchPackage({
body: {
size,
from,
query: {
function_score: {
boost_mode: 'replace',
query: {
bool: {
should: matchQueries,
minimum_should_match: matchQueries.length > 0 ? 1 : 0,
...(mustNotQueries.length > 0 ? { must_not: mustNotQueries } : {}),
...(filterQueries.length > 0 ? { filter: filterQueries } : {}),
},
},
script_score: scriptScore,
},
},
},
});
const { hits, total } = res;
return {
objects: hits?.map((item) => {
// 从 https://github.com/npm/cli/pull/7407 (npm cli v10.6.0) 开始,npm cli 使用 publisher 字段(以前使用 maintainers 字段)
// 从现有数据来看,_npmUser 字段和 publisher 字段是等价的
// 为了兼容老版本,不删除 _npmUser 字段
if (!item._source?.package.publisher && item._source?.package._npmUser) {
item._source.package.publisher = {
username: item._source.package._npmUser.name,
email: item._source.package._npmUser.email,
};
}
return item._source;
}),
total: total.value,
};
}
async removePackage(fullname) {
try {
return await this.searchRepository.removePackage(fullname);
}
catch (error) {
// if the package does not exist, returns success
if (error instanceof errors.ResponseError && error?.statusCode === 404) {
this.logger.warn('[PackageSearchService.removePackage] remove package:%s not found', fullname);
return fullname;
}
throw error;
}
}
// Build must_not queries for filtering deprecated packages
// https://github.com/cnpm/cnpmcore/issues/858
_buildMustNotQueries() {
// oxlint-disable-next-line typescript-eslint/no-explicit-any
const queries = [];
if (this.config.cnpmcore.searchFilterDeprecated) {
queries.push({
exists: {
field: 'package.deprecated',
},
});
}
return queries;
}
// Build filter queries for minimum publish duration
// https://github.com/cnpm/cnpmcore/issues/858
_buildFilterQueries() {
// oxlint-disable-next-line typescript-eslint/no-explicit-any
const queries = [];
const minDuration = this.config.cnpmcore.searchPublishMinDuration;
if (minDuration) {
const ms = this._parseDuration(minDuration);
if (ms > 0) {
const cutoff = new Date(Date.now() - ms);
queries.push({
range: {
'package.created': {
lte: cutoff.toISOString(),
},
},
});
}
}
return queries;
}
// Parse duration string like '1h', '1d', '1w', '2w' to milliseconds
_parseDuration(duration) {
const match = duration.match(/^(\d+)(h|d|w)$/);
if (!match) {
if (duration) {
this.logger.warn('[PackageSearchService._parseDuration] invalid duration format: %s, expected format: 1h, 1d, 1w', duration);
}
return 0;
}
const value = parseInt(match[1], 10);
const unit = match[2];
switch (unit) {
case 'h':
return value * 60 * 60 * 1000;
case 'd':
return value * 24 * 60 * 60 * 1000;
case 'w':
return value * 7 * 24 * 60 * 60 * 1000;
default:
return 0;
}
}
// https://github.com/npms-io/queries/blob/master/lib/search.js#L8C1-L78C2
_buildMatchQueries(text) {
if (!text) {
return [];
}
return [
// Standard match using cross_fields
{
multi_match: {
query: text,
operator: 'and',
fields: ['package.name.standard^4', 'package.description.standard', 'package.keywords.standard^2'],
type: 'cross_fields',
boost: 6,
tie_breaker: 0.5,
},
},
// Partial match using edge-ngram
{
multi_match: {
query: text,
operator: 'and',
fields: ['package.name.edge_ngram^4', 'package.description.edge_ngram', 'package.keywords.edge_ngram^2'],
type: 'phrase',
slop: 3,
boost: 3,
tie_breaker: 0.5,
},
},
// Normal term match with an english stemmer
{
multi_match: {
query: text,
operator: 'and',
fields: [
'package.name.english_docs^4',
'package.description.english_docs',
'package.keywords.english_docs^2',
],
type: 'cross_fields',
boost: 3,
tie_breaker: 0.5,
},
},
// Normal term match with a more aggressive english stemmer (not so important)
{
multi_match: {
query: text,
operator: 'and',
fields: [
'package.name.english_aggressive_docs^4',
'package.description.english_aggressive_docs',
'package.keywords.english_aggressive_docs^2',
],
type: 'cross_fields',
tie_breaker: 0.5,
},
},
];
}
_buildScriptScore(params) {
// keep search simple, only download(popularity)
const downloads = 'doc["downloads.all"].value';
const source = `doc["package.name.raw"].value.equals(params.text) ? 100000 + ${downloads} : _score * Math.pow(${downloads}, params.scoreEffect)`;
return {
script: {
source,
params: {
text: params.text || '',
scoreEffect: params.scoreEffect,
},
},
};
}
};
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageSearchService.prototype, "packageManagerService", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageSearchService.prototype, "searchRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageSearchService.prototype, "packageVersionDownloadRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageSearchService.prototype, "packageRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageSearchService.prototype, "packageVersionBlockRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageSearchService.prototype, "packageVersionRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], PackageSearchService.prototype, "distRepository", void 0);
PackageSearchService = __decorate([
SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
], PackageSearchService);
export { PackageSearchService };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFja2FnZVNlYXJjaFNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9hcHAvY29yZS9zZXJ2aWNlL1BhY2thZ2VTZWFyY2hTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQWdCLE1BQU0sd0JBQXdCLENBQUM7QUFDOUQsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLGNBQWMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUUxRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbEUsT0FBTyxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQVlyRSxJQUFNLG9CQUFvQixHQUExQixNQUFNLG9CQUFxQixTQUFRLGVBQWU7SUFnQnZELEtBQUssQ0FBQyxXQUFXLENBQUMsUUFBZ0IsRUFBRSxNQUFNLEdBQUcsSUFBSTtRQUMvQyxNQUFNLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxHQUFHLGVBQWUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoRCxNQUFNLEVBQ0osV0FBVyxFQUNYLFFBQVEsRUFBRSxjQUFjLEVBQ3hCLEdBQUcsR0FDSixHQUFHLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLDBCQUEwQixDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNyRyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDNUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsNkRBQTZELEVBQUUsUUFBUSxDQUFDLENBQUM7WUFDMUYsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLFdBQVcsRUFBRSxDQUFDO1lBQ2hCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxD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