fix: noImplicitAny ts (#568)
> Attempted to apply the `noImplicitAny`, parameter types should be specified unless any is manually declared. * 🐞 Fixed an issue in bugVersionAdvice where AbbreviatedManifest was being set abnormally. * 🤖 Added index.d.ts to store declarations for dependencies without types. * 🤔 skipLibCheck has no effect on leoric for now, so it cannot be enabled temporarily. -------- > 尝试应用 `noImplicitAny` 配置,除非手动声明 any,否则需要指定参数类型 * 🐞 修复 bugVersionAdvice 中,AbbreviatedManifest 设置异常 * 🤖 添加 index.d.ts 存放无类型依赖声明 * 🤔 skipLibCheck 对 leoric 失效,暂时无法开启 
This commit is contained in:
@@ -105,13 +105,13 @@ const WHITE_FILENAME_CONTENT_TYPES = {
|
||||
'.eslintignore': PLAIN_TEXT,
|
||||
'.jshintrc': 'application/json',
|
||||
'.eslintrc': 'application/json',
|
||||
};
|
||||
} as const;
|
||||
|
||||
export function mimeLookup(filepath: string) {
|
||||
const filename = path.basename(filepath).toLowerCase();
|
||||
if (filename.endsWith('.ts')) return PLAIN_TEXT;
|
||||
if (filename.endsWith('.lock')) return PLAIN_TEXT;
|
||||
return mime.lookup(filename) ||
|
||||
WHITE_FILENAME_CONTENT_TYPES[filename] ||
|
||||
WHITE_FILENAME_CONTENT_TYPES[filename as keyof typeof WHITE_FILENAME_CONTENT_TYPES] ||
|
||||
DEFAULT_CONTENT_TYPE;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export function integrity(plain: string): string {
|
||||
}
|
||||
|
||||
export function checkIntegrity(plain: string, expectedIntegrity: string): boolean {
|
||||
return ssri.checkData(plain, expectedIntegrity);
|
||||
return !!ssri.checkData(plain, expectedIntegrity);
|
||||
}
|
||||
|
||||
export function sha512(plain: string): string {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
HttpClientRequestOptions,
|
||||
HttpClientResponse,
|
||||
} from 'egg';
|
||||
import { PackageManifestType } from '../../repository/PackageRepository';
|
||||
|
||||
type HttpMethod = HttpClientRequestOptions['method'];
|
||||
|
||||
@@ -40,7 +41,7 @@ export class NPMRegistry {
|
||||
this.registryHost = registryHost;
|
||||
}
|
||||
|
||||
public async getFullManifests(fullname: string, optionalConfig?: {retries?:number, remoteAuthToken?:string}): Promise<RegistryResponse> {
|
||||
public async getFullManifests(fullname: string, optionalConfig?: { retries?: number, remoteAuthToken?: string }): Promise<{ method: HttpMethod } & HttpClientResponse<PackageManifestType>> {
|
||||
let retries = optionalConfig?.retries || 3;
|
||||
// set query t=timestamp, make sure CDN cache disable
|
||||
// cache=0 is sync worker request flag
|
||||
|
||||
@@ -17,6 +17,8 @@ export type FetchResult = {
|
||||
nextParams?: any;
|
||||
};
|
||||
|
||||
const platforms = [ 'darwin', 'linux', 'win32' ] as const;
|
||||
|
||||
export const BINARY_ADAPTER_ATTRIBUTE = Symbol('BINARY_ADAPTER_ATTRIBUTE');
|
||||
|
||||
export abstract class AbstractBinary {
|
||||
@@ -74,7 +76,7 @@ export abstract class AbstractBinary {
|
||||
|
||||
protected listNodePlatforms() {
|
||||
// https://nodejs.org/api/os.html#osplatform
|
||||
return [ 'darwin', 'linux', 'win32' ];
|
||||
return platforms;
|
||||
}
|
||||
|
||||
protected listNodeArchs(binaryConfig?: BinaryTaskConfig) {
|
||||
@@ -87,11 +89,11 @@ export abstract class AbstractBinary {
|
||||
};
|
||||
}
|
||||
|
||||
protected listNodeLibcs() {
|
||||
protected listNodeLibcs(): Record<typeof platforms[number], string[]> {
|
||||
// https://github.com/lovell/detect-libc/blob/master/lib/detect-libc.js#L42
|
||||
return {
|
||||
linux: [ 'glibc', 'musl' ],
|
||||
darwin: [ 'unknown' ],
|
||||
linux: [ 'glibc', 'musl' ],
|
||||
win32: [ 'unknown' ],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ const DOWNLOAD_PATHS = {
|
||||
'android': {
|
||||
'<unknown>': 'builds/android/%s/android.zip',
|
||||
},
|
||||
};
|
||||
} as const;
|
||||
|
||||
@SingletonProto()
|
||||
@BinaryAdapter(BinaryType.Playwright)
|
||||
@@ -215,7 +215,7 @@ export class PlaywrightBinary extends AbstractBinary {
|
||||
.filter(version => version.match(/^(?:\d+\.\d+\.\d+)(?:-beta-\d+)?$/))
|
||||
// select recently update 20 items
|
||||
.slice(-20);
|
||||
const browsers: { name: string; revision: string; browserVersion: string; revisionOverrides?: Record<string, string> }[] = [];
|
||||
const browsers: { name: keyof typeof DOWNLOAD_PATHS; revision: string; browserVersion: string; revisionOverrides?: Record<string, string> }[] = [];
|
||||
await Promise.all(
|
||||
packageVersions.map(version =>
|
||||
this.requestJSON(
|
||||
|
||||
@@ -6,6 +6,16 @@ import { AbstractChangeStream, RegistryChangesStream } from './AbstractChangesSt
|
||||
|
||||
const MAX_LIMIT = 10000;
|
||||
|
||||
type FetchResults = {
|
||||
results: {
|
||||
seq: number;
|
||||
type: string;
|
||||
id: string;
|
||||
changes: Record<string, string>[];
|
||||
gmt_modified: Date,
|
||||
}[];
|
||||
};
|
||||
|
||||
@SingletonProto()
|
||||
@RegistryChangesStream(RegistryType.Cnpmjsorg)
|
||||
export class CnpmjsorgChangesStream extends AbstractChangeStream {
|
||||
@@ -18,13 +28,13 @@ export class CnpmjsorgChangesStream extends AbstractChangeStream {
|
||||
return since;
|
||||
}
|
||||
|
||||
private async tryFetch(registry: Registry, since: string, limit = 1000) {
|
||||
private async tryFetch(registry: Registry, since: string, limit = 1000): Promise<{ data: FetchResults }> {
|
||||
if (limit > MAX_LIMIT) {
|
||||
throw new E500(`limit too large, current since: ${since}, limit: ${limit}`);
|
||||
}
|
||||
const db = this.getChangesStreamUrl(registry, since, limit);
|
||||
// json mode
|
||||
const res = await this.httpclient.request(db, {
|
||||
const res = await this.httpclient.request<FetchResults>(db, {
|
||||
followRedirect: true,
|
||||
timeout: 30000,
|
||||
dataType: 'json',
|
||||
|
||||
@@ -8,7 +8,7 @@ export type BugVersionPackages = Record<string, BugVersionPackage>;
|
||||
export class BugVersion {
|
||||
private readonly data: BugVersionPackages;
|
||||
|
||||
constructor(data) {
|
||||
constructor(data: BugVersionPackages) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export class Hook extends Entity {
|
||||
}
|
||||
|
||||
// payload 可能会特别大,如果做多次 stringify 浪费太多 cpu
|
||||
signPayload(payload: object): { digest, payloadStr } {
|
||||
signPayload(payload: object) {
|
||||
const payloadStr = JSON.stringify(payload);
|
||||
const digest = crypto.createHmac('sha256', this.secret)
|
||||
.update(JSON.stringify(payload))
|
||||
|
||||
@@ -38,7 +38,7 @@ export class SqlRange {
|
||||
};
|
||||
}
|
||||
const paddingSemver = new PaddingSemVer(comparator.semver);
|
||||
const operator = OPERATOR_MAP[comparator.operator];
|
||||
const operator = OPERATOR_MAP[comparator.operator as keyof typeof OPERATOR_MAP];
|
||||
if (!operator) {
|
||||
throw new Error(`unknown operator ${comparator.operator}`);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export class BugVersionService {
|
||||
const packageVersionJson = (await this.distRepository.findPackageVersionManifest(pkg!.packageId, tag!.version)) as PackageJSONType;
|
||||
if (!packageVersionJson) return;
|
||||
const data = packageVersionJson.config?.['bug-versions'];
|
||||
bugVersion = new BugVersion(data);
|
||||
bugVersion = new BugVersion(data || {});
|
||||
this.bugVersionStore.setBugVersion(bugVersion, tag!.version);
|
||||
}
|
||||
return bugVersion;
|
||||
|
||||
@@ -425,7 +425,7 @@ export class PackageManagerService extends AbstractService {
|
||||
|
||||
public plusPackageVersionCounter(fullname: string, version: string) {
|
||||
// set counter + 1, schedule will store them into database
|
||||
const counters = PackageManagerService.downloadCounters;
|
||||
const counters: Record<string, Record<string, number>> = PackageManagerService.downloadCounters;
|
||||
if (!counters[fullname]) counters[fullname] = {};
|
||||
counters[fullname][version] = (counters[fullname][version] || 0) + 1;
|
||||
// Total
|
||||
@@ -444,7 +444,7 @@ export class PackageManagerService extends AbstractService {
|
||||
// will be call by schedule/SavePackageVersionDownloadCounter.ts
|
||||
async savePackageVersionCounters() {
|
||||
// { [fullname]: { [version]: number } }
|
||||
const counters = PackageManagerService.downloadCounters;
|
||||
const counters: Record<string, Record<string, number>> = PackageManagerService.downloadCounters;
|
||||
const fullnames = Object.keys(counters);
|
||||
if (fullnames.length === 0) return;
|
||||
|
||||
@@ -724,13 +724,16 @@ export class PackageManagerService extends AbstractService {
|
||||
const fieldsFromLatestManifest = [
|
||||
'author', 'bugs', 'contributors', 'description', 'homepage', 'keywords', 'license',
|
||||
'readmeFilename', 'repository',
|
||||
];
|
||||
] as const;
|
||||
// the latest version metas
|
||||
for (const field of fieldsFromLatestManifest) {
|
||||
fullManifests[field] = latestManifest[field];
|
||||
if (latestManifest[field]) {
|
||||
(fullManifests as Record<string, unknown>)[field] = latestManifest[field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async _setPackageDistTagsAndLatestInfos(pkg: Package, fullManifests: PackageManifestType, abbreviatedManifests: AbbreviatedPackageManifestType) {
|
||||
const distTags = await this._listPackageDistTags(pkg);
|
||||
if (distTags.latest) {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { downloadToTempfile } from '../../common/FileUtil';
|
||||
import { TaskState, TaskType } from '../../common/enum/Task';
|
||||
import { AbstractService } from '../../common/AbstractService';
|
||||
import { TaskRepository } from '../../repository/TaskRepository';
|
||||
import { PackageJSONType, PackageRepository } from '../../repository/PackageRepository';
|
||||
import { PackageJSONType, PackageManifestType, PackageRepository } from '../../repository/PackageRepository';
|
||||
import { PackageVersionDownloadRepository } from '../../repository/PackageVersionDownloadRepository';
|
||||
import { UserRepository } from '../../repository/UserRepository';
|
||||
import { Task, SyncPackageTaskOptions, CreateSyncPackageTask } from '../entity/Task';
|
||||
@@ -484,7 +484,7 @@ export class PackageSyncerService extends AbstractService {
|
||||
// { name: 'jasonlaster11', email: 'jason.laster.11@gmail.com' }
|
||||
// ],
|
||||
let maintainers = data.maintainers;
|
||||
const maintainersMap = {};
|
||||
const maintainersMap: Record<string, PackageManifestType['maintainers']> = {};
|
||||
const users: User[] = [];
|
||||
let changedUserCount = 0;
|
||||
if (!Array.isArray(maintainers) || maintainers.length === 0) {
|
||||
@@ -619,7 +619,7 @@ export class PackageSyncerService extends AbstractService {
|
||||
}
|
||||
if (!isEqual(remoteItemValue, existsItem[key])) {
|
||||
diffMeta[key] = remoteItemValue;
|
||||
} else if (!ignoreInAbbreviated.includes(key) && existsAbbreviatedItem && !isEqual(remoteItemValue, existsAbbreviatedItem[key])) {
|
||||
} else if (!ignoreInAbbreviated.includes(key) && existsAbbreviatedItem && !isEqual(remoteItemValue, (existsAbbreviatedItem as Record<string, unknown>)[key])) {
|
||||
// should diff exists abbreviated item too
|
||||
diffMeta[key] = remoteItemValue;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export class PackageVersionService {
|
||||
if (isFullManifests) {
|
||||
manifest = await this.distRepository.findPackageVersionManifest(pkgId, version);
|
||||
} else {
|
||||
manifest = this.distRepository.findPackageAbbreviatedManifest(pkgId, version);
|
||||
manifest = await this.distRepository.findPackageAbbreviatedManifest(pkgId, version);
|
||||
}
|
||||
if (manifest && bugVersionAdvice) {
|
||||
manifest.deprecated = `[WARNING] Use ${bugVersionAdvice.advice.version} instead of ${bugVersionAdvice.version}, reason: ${bugVersionAdvice.advice.reason}`;
|
||||
|
||||
@@ -199,14 +199,14 @@ export class UserService extends AbstractService {
|
||||
await this.userRepository.removeToken(token.tokenId);
|
||||
}
|
||||
|
||||
async findWebauthnCredential(userId: string, browserType?: string) {
|
||||
async findWebauthnCredential(userId: string, browserType: string | undefined | null) {
|
||||
const credential = await this.userRepository.findCredentialByUserIdAndBrowserType(userId, browserType || null);
|
||||
return credential;
|
||||
}
|
||||
|
||||
async createWebauthnCredential(userId: string, options: CreateWebauthnCredentialOptions) {
|
||||
async createWebauthnCredential(userId: string | undefined, options: CreateWebauthnCredentialOptions) {
|
||||
const credentialEntity = WebauthnCredentialEntity.create({
|
||||
userId,
|
||||
userId: userId as string,
|
||||
credentialId: options.credentialId,
|
||||
publicKey: options.publicKey,
|
||||
browserType: options.browserType,
|
||||
@@ -215,7 +215,7 @@ export class UserService extends AbstractService {
|
||||
return credentialEntity;
|
||||
}
|
||||
|
||||
async removeWebauthnCredential(userId: string, browserType?: string) {
|
||||
async removeWebauthnCredential(userId?: string, browserType?: string) {
|
||||
const credential = await this.userRepository.findCredentialByUserIdAndBrowserType(userId, browserType || null);
|
||||
if (credential) {
|
||||
await this.userRepository.removeCredential(credential.wancId);
|
||||
|
||||
@@ -28,15 +28,15 @@ export class DownloadController extends AbstractController {
|
||||
const pkg = await this.packageRepository.findPackage(scope, name);
|
||||
if (!pkg) throw new NotFoundError(`${fullname} not found`);
|
||||
const entities = await this.packageVersionDownloadRepository.query(pkg.packageId, startDate.toDate(), endDate.toDate());
|
||||
const days = {};
|
||||
const versions = {};
|
||||
const days: Record<string, number> = {};
|
||||
const versions: Record<string, { day: string, downloads: number }[]> = {};
|
||||
for (const entity of entities) {
|
||||
const yearMonth = String(entity.yearMonth);
|
||||
const prefix = yearMonth.substring(0, 4) + '-' + yearMonth.substring(4, 6);
|
||||
for (let i = 1; i <= 31; i++) {
|
||||
const day = String(i).padStart(2, '0');
|
||||
const field = `d${day}`;
|
||||
const counter = entity[field];
|
||||
const field = `d${day}` as keyof typeof entity;
|
||||
const counter = entity[field] as number;
|
||||
if (!counter) continue;
|
||||
const date = `${prefix}-${day}`;
|
||||
days[date] = (days[date] || 0) + counter;
|
||||
@@ -66,14 +66,14 @@ export class DownloadController extends AbstractController {
|
||||
async showTotalDownloads(@HTTPParam() scope: string, @HTTPParam() range: string) {
|
||||
const [ startDate, endDate ] = this.checkAndGetRange(range);
|
||||
const entities = await this.packageVersionDownloadRepository.query(scope, startDate.toDate(), endDate.toDate());
|
||||
const days = {};
|
||||
const days: Record<string, number> = {};
|
||||
for (const entity of entities) {
|
||||
const yearMonth = String(entity.yearMonth);
|
||||
const prefix = yearMonth.substring(0, 4) + '-' + yearMonth.substring(4, 6);
|
||||
for (let i = 1; i <= 31; i++) {
|
||||
const day = String(i).padStart(2, '0');
|
||||
const field = `d${day}`;
|
||||
const counter = entity[field];
|
||||
const field = `d${day}` as keyof typeof entity;
|
||||
const counter = entity[field] as number;
|
||||
if (!counter) continue;
|
||||
const date = `${prefix}-${day}`;
|
||||
days[date] = (days[date] || 0) + counter;
|
||||
@@ -115,4 +115,3 @@ export class DownloadController extends AbstractController {
|
||||
return [ startDate, endDate ];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export class PackageTagController extends AbstractController {
|
||||
async showTags(@HTTPParam() fullname: string) {
|
||||
const packageEntity = await this.getPackageEntityByFullname(fullname);
|
||||
const tagEntities = await this.packageRepository.listPackageTags(packageEntity.packageId);
|
||||
const tags = {};
|
||||
const tags: Record<string, string> = {};
|
||||
for (const entity of tagEntities) {
|
||||
tags[entity.tag] = entity.version;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Static, Type } from '@sinclair/typebox';
|
||||
import { AbstractController } from '../AbstractController';
|
||||
import { getScopeAndName, FULLNAME_REG_STRING, extractPackageJSON } from '../../../common/PackageUtil';
|
||||
import { PackageManagerService } from '../../../core/service/PackageManagerService';
|
||||
import { PackageVersion as PackageVersionEntity } from '../../../core/entity/PackageVersion';
|
||||
import {
|
||||
VersionRule,
|
||||
TagWithVersionRule,
|
||||
@@ -103,7 +104,7 @@ export class SavePackageVersionController extends AbstractController {
|
||||
const [ scope, name ] = getScopeAndName(fullname);
|
||||
const pkg = await this.packageRepository.findPackage(scope, name);
|
||||
if (!pkg) {
|
||||
const errors = (validateResult.errors || validateResult.warnings).join(', ');
|
||||
const errors = (validateResult.errors || validateResult.warnings || []).join(', ');
|
||||
throw new UnprocessableEntityError(`package.name invalid, errors: ${errors}`);
|
||||
}
|
||||
}
|
||||
@@ -185,7 +186,8 @@ export class SavePackageVersionController extends AbstractController {
|
||||
const tarballPkg = await extractPackageJSON(tarballBytes);
|
||||
const versionManifest = pkg.versions[tarballPkg.version];
|
||||
const diffKeys = STRICT_CHECK_TARBALL_FIELDS.filter(key => {
|
||||
return !isEqual(tarballPkg[key], versionManifest[key]);
|
||||
const targetKey = key as unknown as keyof typeof versionManifest;
|
||||
return !isEqual(tarballPkg[key], versionManifest[targetKey]);
|
||||
});
|
||||
if (diffKeys.length > 0) {
|
||||
throw new UnprocessableEntityError(`${diffKeys} mismatch between tarball and manifest`);
|
||||
@@ -205,7 +207,7 @@ export class SavePackageVersionController extends AbstractController {
|
||||
|
||||
const registry = await this.registryManagerService.ensureSelfRegistry();
|
||||
|
||||
let packageVersionEntity;
|
||||
let packageVersionEntity: PackageVersionEntity | undefined;
|
||||
const lockRes = await this.cacheAdapter.usingLock(`${pkg.name}:publish`, 60, async () => {
|
||||
packageVersionEntity = await this.packageManagerService.publish({
|
||||
scope,
|
||||
@@ -230,12 +232,12 @@ export class SavePackageVersionController extends AbstractController {
|
||||
}
|
||||
|
||||
this.logger.info('[package:version:add] %s@%s, packageVersionId: %s, tag: %s, userId: %s',
|
||||
packageVersion.name, packageVersion.version, packageVersionEntity.packageVersionId,
|
||||
tagWithVersion.tag, user.userId);
|
||||
packageVersion.name, packageVersion.version, packageVersionEntity?.packageVersionId,
|
||||
tagWithVersion.tag, user?.userId);
|
||||
ctx.status = 201;
|
||||
return {
|
||||
ok: true,
|
||||
rev: `${packageVersionEntity.id}-${packageVersionEntity.packageVersionId}`,
|
||||
rev: `${packageVersionEntity?.id}-${packageVersionEntity?.packageVersionId}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -79,8 +79,8 @@ export class UpdateTotalData {
|
||||
for (const row of rows) {
|
||||
for (let i = 1; i <= 31; i++) {
|
||||
const day = String(i).padStart(2, '0');
|
||||
const field = `d${day}`;
|
||||
const counter = row[field];
|
||||
const field = `d${day}` as keyof typeof row;
|
||||
const counter = row[field] as number;
|
||||
if (!counter) continue;
|
||||
const dayInt = row.yearMonth * 100 + i;
|
||||
if (dayInt === todayInt) download.today += counter;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { RegistryType } from '../common/enum/Registry';
|
||||
import semver from 'semver';
|
||||
import npa from 'npm-package-arg';
|
||||
import { HookType } from '../common/enum/Hook';
|
||||
import binaryConfig from '../../config/binaries';
|
||||
import binaryConfig, { BinaryName } from '../../config/binaries';
|
||||
|
||||
export const Name = Type.String({
|
||||
transform: [ 'trim' ],
|
||||
@@ -151,8 +151,8 @@ export function patchAjv(ajv: any) {
|
||||
});
|
||||
ajv.addFormat('binary-name', {
|
||||
type: 'string',
|
||||
validate: (binaryName: string) => {
|
||||
return !!binaryConfig[binaryName];
|
||||
validate: (binaryName: BinaryName) => {
|
||||
return binaryConfig[binaryName];
|
||||
},
|
||||
});
|
||||
ajv.addFormat('semver-version-array', {
|
||||
|
||||
@@ -22,6 +22,8 @@ import {
|
||||
verifyRegistrationResponse,
|
||||
generateAuthenticationOptions,
|
||||
verifyAuthenticationResponse,
|
||||
VerifyRegistrationResponseOpts,
|
||||
VerifyAuthenticationResponseOpts,
|
||||
} from '@simplewebauthn/server';
|
||||
import type { PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/typescript-types';
|
||||
import { LoginResultCode, WanStatusCode } from '../../common/enum/User';
|
||||
@@ -44,6 +46,17 @@ type LoginPrepareResult = {
|
||||
wanCredentialAuthOption?: PublicKeyCredentialRequestOptionsJSON;
|
||||
};
|
||||
|
||||
type LoginImplementRequest = {
|
||||
accData: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
wanCredentialRegiData: unknown;
|
||||
wanCredentialAuthData: unknown;
|
||||
needUnbindWan: boolean;
|
||||
|
||||
};
|
||||
|
||||
const UserRule = Type.Object({
|
||||
name: Type.String({ minLength: 1, maxLength: 100 }),
|
||||
password: Type.String({ minLength: 8, maxLength: 100 }),
|
||||
@@ -102,7 +115,7 @@ export class WebauthController extends MiddlewareController {
|
||||
path: '/-/v1/login/request/session/:sessionId',
|
||||
method: HTTPMethodEnum.POST,
|
||||
})
|
||||
async loginImplement(@Context() ctx: EggContext, @HTTPParam() sessionId: string, @HTTPBody() loginImplementRequest) {
|
||||
async loginImplement(@Context() ctx: EggContext, @HTTPParam() sessionId: string, @HTTPBody() loginImplementRequest: LoginImplementRequest) {
|
||||
ctx.tValidate(SessionRule, { sessionId });
|
||||
const sessionToken = await this.cacheAdapter.get(sessionId);
|
||||
if (typeof sessionToken !== 'string') {
|
||||
@@ -123,7 +136,7 @@ export class WebauthController extends MiddlewareController {
|
||||
}
|
||||
}
|
||||
|
||||
const browserType = getBrowserTypeForWebauthn(ctx.headers['user-agent']);
|
||||
const browserType = getBrowserTypeForWebauthn(ctx.headers['user-agent']) || undefined;
|
||||
const expectedChallenge = (await this.cacheAdapter.get(`${sessionId}_challenge`)) || '';
|
||||
const expectedOrigin = this.config.cnpmcore.registry;
|
||||
const expectedRPID = new URL(expectedOrigin).hostname;
|
||||
@@ -139,7 +152,7 @@ export class WebauthController extends MiddlewareController {
|
||||
}
|
||||
try {
|
||||
const verification = await verifyAuthenticationResponse({
|
||||
response: wanCredentialAuthData,
|
||||
response: wanCredentialAuthData as VerifyAuthenticationResponseOpts['response'],
|
||||
expectedChallenge,
|
||||
expectedOrigin,
|
||||
expectedRPID,
|
||||
@@ -193,7 +206,7 @@ export class WebauthController extends MiddlewareController {
|
||||
user = result.user;
|
||||
// need unbind webauthn credential
|
||||
if (needUnbindWan) {
|
||||
await this.userService.removeWebauthnCredential(user.userId, browserType);
|
||||
await this.userService.removeWebauthnCredential(user?.userId, browserType);
|
||||
}
|
||||
} else {
|
||||
// others: LoginResultCode.UserNotFound
|
||||
@@ -215,7 +228,7 @@ export class WebauthController extends MiddlewareController {
|
||||
if (enableWebAuthn && isSupportWebAuthn && wanCredentialRegiData) {
|
||||
try {
|
||||
const verification = await verifyRegistrationResponse({
|
||||
response: wanCredentialRegiData,
|
||||
response: wanCredentialRegiData as VerifyRegistrationResponseOpts['response'],
|
||||
expectedChallenge,
|
||||
expectedOrigin,
|
||||
expectedRPID,
|
||||
@@ -225,7 +238,7 @@ export class WebauthController extends MiddlewareController {
|
||||
const { credentialPublicKey, credentialID } = registrationInfo;
|
||||
const base64CredentialPublicKey = base64url.encode(Buffer.from(new Uint8Array(credentialPublicKey)));
|
||||
const base64CredentialID = base64url.encode(Buffer.from(new Uint8Array(credentialID)));
|
||||
this.userService.createWebauthnCredential(user.userId, {
|
||||
this.userService.createWebauthnCredential(user?.userId, {
|
||||
credentialId: base64CredentialID,
|
||||
publicKey: base64CredentialPublicKey,
|
||||
browserType,
|
||||
|
||||
@@ -15,9 +15,9 @@ export class BinaryRepository extends AbstractRepository {
|
||||
if (binary.id) {
|
||||
const model = await this.Binary.findOne({ id: binary.id });
|
||||
if (!model) return;
|
||||
await ModelConvertor.saveEntityToModel(binary, model);
|
||||
await ModelConvertor.saveEntityToModel<BinaryModel>(binary as unknown as Record<string, unknown>, model);
|
||||
} else {
|
||||
const model = await ModelConvertor.convertEntityToModel(binary, this.Binary);
|
||||
const model = await ModelConvertor.convertEntityToModel(binary as unknown as Record<string, unknown>, this.Binary);
|
||||
this.logger.info('[BinaryRepository:saveBinary:new] id: %s, binaryId: %s', model.id, model.binaryId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import type { Maintainer as MaintainerModel } from './model/Maintainer';
|
||||
import type { User as UserModel } from './model/User';
|
||||
import { User as UserEntity } from '../core/entity/User';
|
||||
import { AbstractRepository } from './AbstractRepository';
|
||||
import { BugVersionPackages } from '../core/entity/BugVersion';
|
||||
|
||||
export type PackageManifestType = Pick<PackageJSONType, PackageJSONPickKey> & {
|
||||
_id: string;
|
||||
@@ -63,7 +64,9 @@ export type PackageJSONType = CnpmcorePatchInfo & {
|
||||
directories?: DirectoriesType;
|
||||
repository?: RepositoryType;
|
||||
scripts?: Record<string, string>;
|
||||
config?: Record<string, unknown>;
|
||||
config?: {
|
||||
'bug-versions'?: BugVersionPackages;
|
||||
};
|
||||
dependencies?: DepInfo;
|
||||
devDependencies?: DepInfo;
|
||||
peerDependencies?: DepInfo;
|
||||
@@ -102,7 +105,7 @@ export type PackageJSONType = CnpmcorePatchInfo & {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
type PackageJSONPickKey = 'name' | 'author' | 'bugs' | 'description' | 'homepage' | 'keywords' | 'license' | 'readme' | 'readmeFilename' | 'repository' | 'versions';
|
||||
type PackageJSONPickKey = 'name' | 'author' | 'bugs' | 'description' | 'homepage' | 'keywords' | 'license' | 'readme' | 'readmeFilename' | 'repository' | 'versions' | 'contributors';
|
||||
|
||||
type CnpmcorePatchInfo = {
|
||||
_cnpmcore_publish_time?: Date;
|
||||
|
||||
@@ -65,7 +65,7 @@ export class PackageVersionDownloadRepository extends AbstractRepository {
|
||||
}
|
||||
for (const [ date, counter ] of counters) {
|
||||
const field = `d${date}`;
|
||||
model[field] = counter;
|
||||
(model as unknown as Record<string, number>)[field] = counter;
|
||||
}
|
||||
await model.save();
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export class PackageVersionRepository {
|
||||
scope,
|
||||
name,
|
||||
tag,
|
||||
} as object);
|
||||
} as object) as { version: string }[];
|
||||
const tagModel = tags && tags[0];
|
||||
return tagModel?.version;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ export class PackageVersionRepository {
|
||||
'packages.name': name,
|
||||
...sqlRange.condition,
|
||||
} as object)
|
||||
.order('packageVersions.paddingVersion', 'desc');
|
||||
.order('packageVersions.paddingVersion', 'desc') as { version: string }[];
|
||||
return versions?.[0]?.version;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,6 @@ export class PackageVersionRepository {
|
||||
...sqlRange.condition,
|
||||
} as object);
|
||||
return (versions as any).toObject()
|
||||
.map(t => t.version);
|
||||
.map((t: { version: string }) => t.version);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ export class UserRepository extends AbstractRepository {
|
||||
}
|
||||
}
|
||||
|
||||
async findCredentialByUserIdAndBrowserType(userId: string, browserType: string | null) {
|
||||
async findCredentialByUserIdAndBrowserType(userId: string | undefined, browserType: string | null) {
|
||||
const model = await this.WebauthnCredential.findOne({
|
||||
userId,
|
||||
browserType,
|
||||
|
||||
@@ -55,7 +55,7 @@ export class PackageVersion extends Bone {
|
||||
@Attribute(DataTypes.BOOLEAN)
|
||||
isPreRelease: boolean;
|
||||
|
||||
static beforeCreate(instance) {
|
||||
static beforeCreate(instance: { version: string; paddingVersion: string; isPreRelease: boolean }) {
|
||||
if (!instance.paddingVersion) {
|
||||
const paddingSemVer = new PaddingSemVer(instance.version);
|
||||
instance.paddingVersion = paddingSemVer.paddingVersion;
|
||||
|
||||
@@ -2,5 +2,8 @@
|
||||
"name": "cnpmcore-repository",
|
||||
"eggModule": {
|
||||
"name": "cnpmcoreRepository"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.196"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,16 @@ const CREATED_AT = 'createdAt';
|
||||
const UPDATED_AT = 'updatedAt';
|
||||
const ID = 'id';
|
||||
|
||||
type BonePatchInfo = { id?: bigint, updatedAt?: Date, createdAt?: Date };
|
||||
type PatchedBone = Bone & BonePatchInfo;
|
||||
|
||||
export class ModelConvertor {
|
||||
static async convertEntityToModel<T extends Bone>(entity: object, ModelClazz: EggProtoImplClass<T>, options?): Promise<T> {
|
||||
static async convertEntityToModel<T extends(PatchedBone)>(entity: object, ModelClazz: EggProtoImplClass<T>, options?: object): Promise<T> {
|
||||
const metadata = ModelMetadataUtil.getModelMetadata(ModelClazz);
|
||||
if (!metadata) {
|
||||
throw new Error(`Model ${ModelClazz.name} has no metadata`);
|
||||
}
|
||||
const attributes = {};
|
||||
const attributes: Record<string, unknown> = {};
|
||||
for (const attributeMeta of metadata.attributes) {
|
||||
const modelPropertyName = attributeMeta.propertyName;
|
||||
const entityPropertyName = ModelConvertorUtil.getEntityPropertyName(ModelClazz, modelPropertyName);
|
||||
@@ -22,17 +25,17 @@ export class ModelConvertor {
|
||||
const attributeValue = _.get(entity, entityPropertyName);
|
||||
attributes[modelPropertyName] = attributeValue;
|
||||
}
|
||||
const model = await (ModelClazz as unknown as typeof Bone).create(attributes, options);
|
||||
const model = await (ModelClazz as unknown as typeof Bone).create(attributes, options) as PatchedBone;
|
||||
// auto set entity id to model id
|
||||
entity[ID] = model[ID];
|
||||
(entity as Record<string, unknown>)[ID] = model[ID];
|
||||
// use model dates
|
||||
entity[UPDATED_AT] = model[UPDATED_AT];
|
||||
entity[CREATED_AT] = model[CREATED_AT];
|
||||
(entity as Record<string, unknown>)[UPDATED_AT] = model[UPDATED_AT];
|
||||
(entity as Record<string, unknown>)[CREATED_AT] = model[CREATED_AT];
|
||||
return model as T;
|
||||
}
|
||||
|
||||
static convertEntityToChanges<T extends Bone>(entity: object, ModelClazz: EggProtoImplClass<T>) {
|
||||
const changes = {};
|
||||
const changes: Record<string, unknown> = {};
|
||||
const metadata = ModelMetadataUtil.getModelMetadata(ModelClazz);
|
||||
if (!metadata) {
|
||||
throw new Error(`Model ${ModelClazz.name} has no metadata`);
|
||||
@@ -45,13 +48,13 @@ export class ModelConvertor {
|
||||
changes[modelPropertyName] = attributeValue;
|
||||
}
|
||||
changes[UPDATED_AT] = new Date();
|
||||
entity[UPDATED_AT] = changes[UPDATED_AT];
|
||||
(entity as Record<string, unknown>)[UPDATED_AT] = changes[UPDATED_AT];
|
||||
return changes;
|
||||
}
|
||||
|
||||
// TODO: options is QueryOptions, should let leoric export it to use
|
||||
// Find out which attributes changed and set `updatedAt` to now
|
||||
static async saveEntityToModel<T extends Bone>(entity: object, model: T, options?): Promise<boolean> {
|
||||
static async saveEntityToModel<T extends Bone>(entity: object, model: T & PatchedBone, options?: object): Promise<boolean> {
|
||||
const ModelClazz = model.constructor as EggProtoImplClass<T>;
|
||||
const metadata = ModelMetadataUtil.getModelMetadata(ModelClazz);
|
||||
if (!metadata) {
|
||||
@@ -64,14 +67,14 @@ export class ModelConvertor {
|
||||
// Restricted updates to the primary key
|
||||
if (entityPropertyName === ID && model[ID]) continue;
|
||||
const attributeValue = _.get(entity, entityPropertyName);
|
||||
model[modelPropertyName] = attributeValue;
|
||||
(model as unknown as Record<string, unknown>)[modelPropertyName] = attributeValue;
|
||||
}
|
||||
|
||||
// Restricted updates to the UPDATED_AT
|
||||
// Leoric will set by default
|
||||
model[UPDATED_AT] = undefined;
|
||||
await model.save(options);
|
||||
entity[UPDATED_AT] = model[UPDATED_AT];
|
||||
(entity as Record<string, unknown>)[UPDATED_AT] = model[UPDATED_AT];
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -85,7 +88,7 @@ export class ModelConvertor {
|
||||
for (const attributeMeta of metadata.attributes) {
|
||||
const modelPropertyName = attributeMeta.propertyName;
|
||||
const entityPropertyName = ModelConvertorUtil.getEntityPropertyName(ModelClazz as EggProtoImplClass, modelPropertyName);
|
||||
const attributeValue = bone[attributeMeta.propertyName];
|
||||
const attributeValue = bone[attributeMeta.propertyName as keyof Bone];
|
||||
_.set(data, entityPropertyName, attributeValue);
|
||||
}
|
||||
const model = Reflect.construct(entityClazz, [ data ]);
|
||||
|
||||
113
index.d.ts
vendored
Normal file
113
index.d.ts
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
declare module 'fs-cnpm' {
|
||||
export default class FSClient extends NFSClient {
|
||||
constructor(options: {
|
||||
dir: string;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'ssri' {
|
||||
export interface Integrity {
|
||||
algorithm: string;
|
||||
digest: string;
|
||||
options?: string[];
|
||||
}
|
||||
|
||||
export interface HashLike {
|
||||
digest: string;
|
||||
algorithm: string;
|
||||
options?: string[];
|
||||
sha1: {
|
||||
hexDigest(): string;
|
||||
}[];
|
||||
sha512: { toString(): string }[];
|
||||
}
|
||||
|
||||
export interface HashOptions {
|
||||
algorithms?: string[];
|
||||
options?: string[];
|
||||
}
|
||||
|
||||
export interface IntegrityOptions {
|
||||
algorithms?: string[];
|
||||
options?: string[];
|
||||
single?: boolean;
|
||||
}
|
||||
|
||||
export interface CreateRes {
|
||||
update(v: string): { digest: () => { toString() }; };
|
||||
}
|
||||
|
||||
export function fromHex(hexDigest: string, algorithm: string, options?: string[]): Integrity;
|
||||
|
||||
export function fromData(data: Buffer | string | Uint8Array, options?: HashOptions): HashLike;
|
||||
|
||||
export function fromStream(stream: NodeJS.ReadableStream, options?: HashOptions): Promise<HashLike>;
|
||||
|
||||
export function checkData(data: Buffer | string, sri: string | Integrity, options?: IntegrityOptions): boolean;
|
||||
|
||||
export function checkStream(stream: NodeJS.ReadableStream, sri: string | Integrity, options?: IntegrityOptions): Promise<boolean>;
|
||||
|
||||
export function parse(sri: string): Integrity;
|
||||
|
||||
export function create(): CreateRes;
|
||||
|
||||
export function stringify(integrity: Integrity, options?: { strict?: boolean }): string;
|
||||
}
|
||||
|
||||
declare module 'oss-cnpm' {
|
||||
import { Readable } from 'stream';
|
||||
|
||||
export interface AppendResult {
|
||||
name: string;
|
||||
url: string;
|
||||
etag: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export interface UploadOptions {
|
||||
key: string;
|
||||
content: Readable;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export interface UploadResult {
|
||||
name: string;
|
||||
url: string;
|
||||
etag: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export interface DownloadOptions {
|
||||
key: string;
|
||||
}
|
||||
|
||||
export default class OSSClient {
|
||||
constructor(options: {
|
||||
cdnBaseUrl?: string;
|
||||
accessKeyId: string;
|
||||
accessKeySecret: string;
|
||||
bucket: string;
|
||||
internal?: boolean;
|
||||
secure?: boolean;
|
||||
timeout?: number;
|
||||
cname?: boolean;
|
||||
endpoint?: string;
|
||||
defaultHeaders?: Record<string, string>;
|
||||
});
|
||||
|
||||
append(options: UploadOptions): Promise<AppendResult>;
|
||||
|
||||
upload(options: UploadOptions): Promise<UploadResult>;
|
||||
|
||||
download(options: DownloadOptions): Promise<Readable>;
|
||||
|
||||
delete(key: string): Promise<void>;
|
||||
|
||||
exists(key: string): Promise<boolean>;
|
||||
|
||||
stat(key: string): Promise<{ size: number }>;
|
||||
|
||||
url(key: string): string;
|
||||
}
|
||||
}
|
||||
2
module.d.ts
vendored
2
module.d.ts
vendored
@@ -4,4 +4,4 @@ declare module "egg" {
|
||||
export interface EggContextModule {
|
||||
cnpmcoreCore: ContextCnpmcore;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"devDependencies": {
|
||||
"@cnpmjs/npm-cli-login": "^1.1.0",
|
||||
"@simplewebauthn/typescript-types": "^7.0.0",
|
||||
"@types/mime-types": "^2.1.1",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/mysql": "^2.15.21",
|
||||
"@types/semver": "^7.3.12",
|
||||
@@ -127,7 +128,11 @@
|
||||
"eslint": "^8.29.0",
|
||||
"eslint-config-egg": "^12.1.0",
|
||||
"git-contributor": "2",
|
||||
"typescript": "^5.0.4"
|
||||
"typescript": "^5.0.4",
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
"@types/lodash": "^4.14.196",
|
||||
"@types/npm-package-arg": "^6.1.1",
|
||||
"@types/validate-npm-package-name": "^4.0.0"
|
||||
},
|
||||
"author": "killagu",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
{
|
||||
"extends": "@eggjs/tsconfig",
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"target": "ES2021",
|
||||
"module": "Node16",
|
||||
"moduleResolution": "Node",
|
||||
"declaration": false,
|
||||
"resolveJsonModule": true,
|
||||
"useUnknownInCatchVariables": false
|
||||
"useUnknownInCatchVariables": false,
|
||||
},
|
||||
"exclude": [
|
||||
"test",
|
||||
"node_modules"
|
||||
],
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"config/**/*.ts",
|
||||
"typings/**/*.ts",
|
||||
"app.ts",
|
||||
"module.d.ts"
|
||||
"module.d.ts",
|
||||
"index.d.ts"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user