cnpmcore
Version:
Private NPM Registry for Enterprise
250 lines • 23.3 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);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
import { HTTPController, HTTPMethod, HTTPMethodEnum, HTTPParam, Inject } from 'egg';
import { UnprocessableEntityError } from 'egg/errors';
import dayjs from "../../common/dayjs.js";
import { FULLNAME_REG_STRING } from "../../common/PackageUtil.js";
import { AbstractController } from "./AbstractController.js";
const DATE_FORMAT = 'YYYY-MM-DD';
let DownloadController = class DownloadController extends AbstractController {
// npm compatible: /downloads/point/{period}/{package}
// @see https://github.com/npm/registry/blob/master/docs/download-counts.md
async showPackageDownloadPoint(fullname, range) {
const [startDate, endDate] = this.checkAndGetRange(range);
const pkg = await this.getPackageEntityByFullname(fullname);
const entities = await this.packageVersionDownloadRepository.query(pkg.packageId, startDate.toDate(), endDate.toDate());
const total = this.sumDownloads(entities, startDate, endDate);
return {
downloads: total,
start: startDate.format(DATE_FORMAT),
end: endDate.format(DATE_FORMAT),
package: fullname,
};
}
// /downloads/total/point/{period} (all packages, total count)
async showTotalDownloadPoint(range) {
const [startDate, endDate] = this.checkAndGetRange(range);
const entities = await this.packageVersionDownloadRepository.query('total', startDate.toDate(), endDate.toDate());
const total = this.sumDownloads(entities, startDate, endDate);
return {
downloads: total,
start: startDate.format(DATE_FORMAT),
end: endDate.format(DATE_FORMAT),
};
}
async showPackageDownloads(fullname, range) {
const [startDate, endDate] = this.checkAndGetRange(range);
const pkg = await this.getPackageEntityByFullname(fullname);
const entities = await this.packageVersionDownloadRepository.query(pkg.packageId, startDate.toDate(), endDate.toDate());
const days = {};
const versions = {};
for (const entity of entities) {
const yearMonth = entity.yearMonth;
const yearStr = String(yearMonth).slice(0, 4);
const monthStr = String(yearMonth).slice(4, 6);
const prefix = `${yearStr}-${monthStr}`;
const [fromDay, toDay] = this.getDayRange(yearMonth, startDate, endDate);
for (let i = fromDay; i <= toDay; i++) {
const day = String(i).padStart(2, '0');
const field = `d${day}`;
const counter = entity[field];
if (!counter)
continue;
const date = `${prefix}-${day}`;
days[date] = (days[date] || 0) + counter;
if (entity.version === '*') {
// ignore sync data to versions
continue;
}
if (!versions[entity.version])
versions[entity.version] = [];
versions[entity.version].push({ day: date, downloads: counter });
}
}
const downloads = [];
for (const day of Object.keys(days).sort()) {
downloads.push({ day, downloads: days[day] });
}
return {
downloads,
start: startDate.format(DATE_FORMAT),
end: endDate.format(DATE_FORMAT),
package: fullname,
versions,
};
}
async showTotalDownloads(scope, range) {
const [startDate, endDate] = this.checkAndGetRange(range);
const entities = await this.packageVersionDownloadRepository.query(scope, startDate.toDate(), endDate.toDate());
const days = {};
for (const entity of entities) {
const yearMonth = entity.yearMonth;
const yearStr = String(yearMonth).slice(0, 4);
const monthStr = String(yearMonth).slice(4, 6);
const prefix = `${yearStr}-${monthStr}`;
const [fromDay, toDay] = this.getDayRange(yearMonth, startDate, endDate);
for (let i = fromDay; i <= toDay; i++) {
const day = String(i).padStart(2, '0');
const field = `d${day}`;
const counter = entity[field];
if (!counter)
continue;
const date = `${prefix}-${day}`;
days[date] = (days[date] || 0) + counter;
}
}
const downloads = [];
for (const day of Object.keys(days).sort()) {
downloads.push({ day, downloads: days[day] });
}
return {
downloads,
start: startDate.format(DATE_FORMAT),
end: endDate.format(DATE_FORMAT),
};
}
// Get the valid day range [startDay, endDay] for a given entity's yearMonth
// considering the requested date range boundaries
getDayRange(yearMonth, startDate, endDate) {
const year = Math.floor(yearMonth / 100);
const month = yearMonth % 100;
const startYM = startDate.year() * 100 + startDate.month() + 1;
const endYM = endDate.year() * 100 + endDate.month() + 1;
const entityYM = year * 100 + month;
// Days in this month
const daysInMonth = dayjs(`${year}-${String(month).padStart(2, '0')}-01`).daysInMonth();
let fromDay = 1;
let toDay = daysInMonth;
if (entityYM === startYM) {
fromDay = startDate.date();
}
if (entityYM === endYM) {
toDay = endDate.date();
}
return [fromDay, toDay];
}
sumDownloads(entities, startDate, endDate) {
let total = 0;
for (const entity of entities) {
const [fromDay, toDay] = this.getDayRange(entity.yearMonth, startDate, endDate);
for (let i = fromDay; i <= toDay; i++) {
const field = `d${String(i).padStart(2, '0')}`;
const counter = entity[field];
if (counter)
total += counter;
}
}
return total;
}
checkAndGetRange(range) {
// Support npm-compatible period aliases
// @see https://github.com/npm/registry/blob/master/docs/download-counts.md
const today = dayjs();
switch (range) {
case 'last-day':
return [today.subtract(1, 'day'), today.subtract(1, 'day')];
case 'last-week':
return [today.subtract(7, 'day'), today.subtract(1, 'day')];
case 'last-month':
return [today.subtract(30, 'day'), today.subtract(1, 'day')];
case 'last-year':
return [today.subtract(365, 'day'), today.subtract(1, 'day')];
default:
break;
}
// Support single date: YYYY-MM-DD
const singleDateMatch = /^(\d{4}-\d{2}-\d{2})$/.exec(range);
if (singleDateMatch) {
const date = dayjs(singleDateMatch[1], DATE_FORMAT, true);
if (!date.isValid()) {
throw new UnprocessableEntityError(`range(${range}) format invalid, must be "last-day", "last-week", "last-month", "last-year", "${DATE_FORMAT}" or "${DATE_FORMAT}:${DATE_FORMAT}" style`);
}
return [date, date];
}
// Support date range: YYYY-MM-DD:YYYY-MM-DD
const matchs = /^(\d{4}-\d{2}-\d{2}):(\d{4}-\d{2}-\d{2})$/.exec(range);
if (!matchs) {
throw new UnprocessableEntityError(`range(${range}) format invalid, must be "last-day", "last-week", "last-month", "last-year", "${DATE_FORMAT}" or "${DATE_FORMAT}:${DATE_FORMAT}" style`);
}
const start = matchs[1];
const end = matchs[2];
let startDate = dayjs(start, DATE_FORMAT, true);
let endDate = dayjs(end, DATE_FORMAT, true);
if (!startDate.isValid() || !endDate.isValid()) {
throw new UnprocessableEntityError(`range(${range}) format invalid, must be "last-day", "last-week", "last-month", "last-year", "${DATE_FORMAT}" or "${DATE_FORMAT}:${DATE_FORMAT}" style`);
}
if (endDate.isBefore(startDate)) {
const tmp = startDate;
startDate = endDate;
endDate = tmp;
}
// max range for one year
const maxDate = startDate.add(1, 'year');
if (endDate.isAfter(maxDate)) {
throw new UnprocessableEntityError(`range(${range}) beyond the processable range, max up to "${maxDate.format(DATE_FORMAT)}"`);
}
return [startDate, endDate];
}
};
__decorate([
Inject(),
__metadata("design:type", Function)
], DownloadController.prototype, "packageVersionDownloadRepository", void 0);
__decorate([
HTTPMethod({
path: `/downloads/point/:range/:fullname(${FULLNAME_REG_STRING})`,
method: HTTPMethodEnum.GET,
}),
__param(0, HTTPParam()),
__param(1, HTTPParam()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String]),
__metadata("design:returntype", Promise)
], DownloadController.prototype, "showPackageDownloadPoint", null);
__decorate([
HTTPMethod({
path: '/downloads/total/point/:range',
method: HTTPMethodEnum.GET,
}),
__param(0, HTTPParam()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", Promise)
], DownloadController.prototype, "showTotalDownloadPoint", null);
__decorate([
HTTPMethod({
path: `/downloads/range/:range/:fullname(${FULLNAME_REG_STRING})`,
method: HTTPMethodEnum.GET,
}),
__param(0, HTTPParam()),
__param(1, HTTPParam()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String]),
__metadata("design:returntype", Promise)
], DownloadController.prototype, "showPackageDownloads", null);
__decorate([
HTTPMethod({
path: '/downloads/:scope/:range',
method: HTTPMethodEnum.GET,
}),
__param(0, HTTPParam()),
__param(1, HTTPParam()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String]),
__metadata("design:returntype", Promise)
], DownloadController.prototype, "showTotalDownloads", null);
DownloadController = __decorate([
HTTPController()
], DownloadController);
export { DownloadController };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRG93bmxvYWRDb250cm9sbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vYXBwL3BvcnQvY29udHJvbGxlci9Eb3dubG9hZENvbnRyb2xsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsT0FBTyxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFDcEYsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRXRELE9BQU8sS0FBSyxNQUFNLHVCQUF1QixDQUFDO0FBQzFDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBR2xFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRTdELE1BQU0sV0FBVyxHQUFHLFlBQVksQ0FBQztBQUcxQixJQUFNLGtCQUFrQixHQUF4QixNQUFNLGtCQUFtQixTQUFRLGtCQUFrQjtJQUl4RCxzREFBc0Q7SUFDdEQsMkVBQTJFO0lBS3JFLEFBQU4sS0FBSyxDQUFDLHdCQUF3QixDQUFjLFFBQWdCLEVBQWUsS0FBYTtRQUN0RixNQUFNLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMxRCxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1RCxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxnQ0FBZ0MsQ0FBQyxLQUFLLENBQ2hFLEdBQUcsQ0FBQyxTQUFTLEVBQ2IsU0FBUyxDQUFDLE1BQU0sRUFBRSxFQUNsQixPQUFPLENBQUMsTUFBTSxFQUFFLENBQ2pCLENBQUM7UUFDRixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUs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