refactor: use tegg and egg v4 beta (#836)
🦀 for https://github.com/eggjs/egg/issues/3644
This commit is contained in:
@@ -13,7 +13,10 @@
|
||||
"no-console": "warn",
|
||||
"import/no-anonymous-default-export": "error",
|
||||
"no-unassigned-import": "allow",
|
||||
"new-cap": "allow"
|
||||
"new-cap": "allow",
|
||||
"class-methods-use-this": "allow",
|
||||
"import/no-named-export": "allow",
|
||||
"unicorn/no-array-sort": "allow"
|
||||
},
|
||||
"ignorePatterns": ["index.d.ts"]
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"printWidth": 120,
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ private async getPackageEntity(scope: string, name: string) {
|
||||
|
||||
#### 1、请求参数校验
|
||||
|
||||
使用 [egg-typebox-validate](https://github.com/xiekw2010/egg-typebox-validate) 来做请求参数校验,只需要定义一次参数类型和规则,就能同时拥有参数校验和类型定义。
|
||||
使用 [@eggjs/typebox-validate](https://github.com/eggjs/egg/tree/next/plugins/typebox-validate) 来做请求参数校验,只需要定义一次参数类型和规则,就能同时拥有参数校验和类型定义。
|
||||
详细使用方式可以参考 [PR#12](https://github.com/cnpm/cnpmcore/pull/12)。
|
||||
|
||||
使用方式请直接参考 `app/port/typebox.ts` 代码。
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
},
|
||||
typeboxValidate: {
|
||||
enable: true,
|
||||
package: 'egg-typebox-validate',
|
||||
package: '@eggjs/typebox-validate',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
1
app.ts
1
app.ts
@@ -1,6 +1,7 @@
|
||||
import path from 'node:path';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import type { Application, ILifecycleBoot } from 'egg';
|
||||
|
||||
import { ChangesStreamService } from './app/core/service/ChangesStreamService.js';
|
||||
|
||||
declare module 'egg' {
|
||||
|
||||
@@ -77,8 +77,6 @@ export interface AuthClient {
|
||||
}
|
||||
|
||||
declare module 'egg' {
|
||||
// oxlint-disable-next-line prefer-ts-expect-error ban-ts-comment
|
||||
// @ts-ignore
|
||||
interface EggAppConfig {
|
||||
cnpmcore: CnpmcoreConfig;
|
||||
}
|
||||
|
||||
@@ -140,16 +140,20 @@ export class UserRoleManager {
|
||||
`Read-only Token "${token.tokenMark}" can't publish`
|
||||
);
|
||||
}
|
||||
const userAgent: string = ctx.get('user-agent');
|
||||
// only support npm >= 7.0.0 allow publish action
|
||||
// user-agent: "npm/6.14.12 node/v10.24.1 darwin x64"
|
||||
const m = /\bnpm\/(\d{1,5})\./.exec(ctx.get('user-agent'));
|
||||
if (!m) {
|
||||
throw new ForbiddenError('Only allow npm client to access');
|
||||
}
|
||||
// pnpm: "pnpm/10.17.0 npm/? node/v20.19.5 darwin arm64"
|
||||
const isPnpm = userAgent.startsWith('pnpm/');
|
||||
const m = /\bnpm\/(\d{1,5})\./.exec(userAgent);
|
||||
if (m) {
|
||||
const major = Number.parseInt(m[1]);
|
||||
if (major < 7) {
|
||||
throw new ForbiddenError('Only allow npm@>=7.0.0 client to access');
|
||||
}
|
||||
} else if (!isPnpm) {
|
||||
throw new ForbiddenError('Only allow npm client to access');
|
||||
}
|
||||
}
|
||||
if (role === 'setting') {
|
||||
if (token.isReadonly) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
HTTPQuery,
|
||||
Inject,
|
||||
} from '@eggjs/tegg';
|
||||
import { Type } from 'egg-typebox-validate/typebox';
|
||||
import { Type } from '@eggjs/typebox-validate/typebox';
|
||||
|
||||
import { AbstractController } from './AbstractController.js';
|
||||
import type { ChangeRepository } from '../../repository/ChangeRepository.js';
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
|
||||
import { AbstractController } from './AbstractController.js';
|
||||
import type { ProxyCacheRepository } from '../../repository/ProxyCacheRepository.js';
|
||||
import type { Static } from 'egg-typebox-validate/typebox';
|
||||
import type { Static } from '@eggjs/typebox-validate/typebox';
|
||||
import type { QueryPageOptions } from '../typebox.js';
|
||||
import { FULLNAME_REG_STRING } from '../../common/PackageUtil.js';
|
||||
import type { ProxyCacheService } from '../../core/service/ProxyCacheService.js';
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
Middleware,
|
||||
} from '@eggjs/tegg';
|
||||
import { NotFoundError } from 'egg-errors';
|
||||
import type { Static } from 'egg-typebox-validate/typebox';
|
||||
import type { Static } from '@eggjs/typebox-validate/typebox';
|
||||
|
||||
import { AbstractController } from './AbstractController.js';
|
||||
import type {
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
Middleware,
|
||||
} from '@eggjs/tegg';
|
||||
import { E400 } from 'egg-errors';
|
||||
import type { Static } from 'egg-typebox-validate/typebox';
|
||||
import type { Static } from '@eggjs/typebox-validate/typebox';
|
||||
|
||||
import { AbstractController } from './AbstractController.js';
|
||||
import { AdminAccess } from '../middleware/AdminAccess.js';
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
HTTPParam,
|
||||
Inject,
|
||||
} from '@eggjs/tegg';
|
||||
import { Type, type Static } from 'egg-typebox-validate/typebox';
|
||||
import { Type, type Static } from '@eggjs/typebox-validate/typebox';
|
||||
|
||||
import type { AuthAdapter } from '../../infra/AuthAdapter.js';
|
||||
import { AbstractController } from './AbstractController.js';
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
UnauthorizedError,
|
||||
UnprocessableEntityError,
|
||||
} from 'egg-errors';
|
||||
import { Type, type Static } from 'egg-typebox-validate/typebox';
|
||||
import { Type, type Static } from '@eggjs/typebox-validate/typebox';
|
||||
|
||||
import { AbstractController } from './AbstractController.js';
|
||||
import { LoginResultCode } from '../../common/enum/User.js';
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from '@eggjs/tegg';
|
||||
import { checkData, fromData } from 'ssri';
|
||||
import validateNpmPackageName from 'validate-npm-package-name';
|
||||
import { Type, type Static } from 'egg-typebox-validate/typebox';
|
||||
import { Type, type Static } from '@eggjs/typebox-validate/typebox';
|
||||
|
||||
import { AbstractController } from '../AbstractController.js';
|
||||
import {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
Inject,
|
||||
Middleware,
|
||||
} from '@eggjs/tegg';
|
||||
import type { Static } from 'egg-typebox-validate/typebox';
|
||||
import type { Static } from '@eggjs/typebox-validate/typebox';
|
||||
import { E451 } from 'egg-errors';
|
||||
|
||||
import { AbstractController } from '../AbstractController.js';
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
HTTPParam,
|
||||
Inject,
|
||||
} from '@eggjs/tegg';
|
||||
import { Type, type Static } from 'egg-typebox-validate/typebox';
|
||||
import { Type, type Static } from '@eggjs/typebox-validate/typebox';
|
||||
|
||||
import { AbstractController } from '../AbstractController.js';
|
||||
import { FULLNAME_REG_STRING } from '../../../common/PackageUtil.js';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Type, type Static } from 'egg-typebox-validate/typebox';
|
||||
import { Type, type Static } from '@eggjs/typebox-validate/typebox';
|
||||
import semver from 'semver';
|
||||
import npa from 'npm-package-arg';
|
||||
import { uniq } from 'lodash-es';
|
||||
import type { Ajv } from 'egg-typebox-validate';
|
||||
import type { Ajv } from '@eggjs/typebox-validate';
|
||||
|
||||
import { RegistryType } from '../common/enum/Registry.js';
|
||||
import { HookType } from '../common/enum/Hook.js';
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
Inject,
|
||||
} from '@eggjs/tegg';
|
||||
import type { EggAppConfig, EggLogger } from 'egg';
|
||||
import { Type, type Static } from 'egg-typebox-validate/typebox';
|
||||
import '@eggjs/typebox-validate';
|
||||
import { Type, type Static } from '@eggjs/typebox-validate/typebox';
|
||||
import { ForbiddenError, NotFoundError } from 'egg-errors';
|
||||
import { createHash } from 'node:crypto';
|
||||
import base64url from 'base64url';
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { join } from 'node:path';
|
||||
import type { Context, EggAppConfig, PowerPartial } from 'egg';
|
||||
|
||||
import type { Context, EggAppConfig, PartialEggConfig } from 'egg';
|
||||
import OSSClient from 'oss-cnpm';
|
||||
import S3Client from 's3-cnpmcore';
|
||||
import { env } from 'read-env-value';
|
||||
@@ -84,9 +85,9 @@ export interface NFSConfig {
|
||||
removeBeforeUpload: boolean;
|
||||
}
|
||||
|
||||
export type Config = PowerPartial<EggAppConfig> & { nfs: NFSConfig };
|
||||
export type Config = PartialEggConfig & { nfs: NFSConfig };
|
||||
|
||||
export default function startConfig(appInfo: EggAppConfig) {
|
||||
export default function startConfig(appInfo: EggAppConfig): Config {
|
||||
const config = {} as Config;
|
||||
|
||||
config.keys = env('CNPMCORE_EGG_KEYS', 'string', randomUUID());
|
||||
|
||||
@@ -7,7 +7,7 @@ import { database } from './database.js';
|
||||
// @ts-expect-error has no construct signatures
|
||||
export const mockES = new Mock();
|
||||
|
||||
export default function startConfig(appInfo: EggAppConfig) {
|
||||
export default function startConfig(appInfo: EggAppConfig): PowerPartial<EggAppConfig> {
|
||||
const config = {} as PowerPartial<EggAppConfig>;
|
||||
config.dataDir = join(appInfo.root, '.cnpmcore_unittest');
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ const plugin: EggPlugin = {
|
||||
},
|
||||
typeboxValidate: {
|
||||
enable: true,
|
||||
package: 'egg-typebox-validate',
|
||||
package: '@eggjs/typebox-validate',
|
||||
},
|
||||
redis: {
|
||||
enable: true,
|
||||
|
||||
28
package.json
28
package.json
@@ -41,24 +41,25 @@
|
||||
"dev:postgresql": "CNPMCORE_DATABASE_TYPE=PostgreSQL egg-bin dev",
|
||||
"lint": "oxlint",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"test:postgresql": "npm run lint:fix && npm run test:local:postgresql",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test:postgresql": "npm run lint && npm run test:local:postgresql",
|
||||
"pretest:local:postgresql": "bash prepare-database-postgresql.sh",
|
||||
"test:local:postgresql": "CNPMCORE_DATABASE_TYPE=PostgreSQL egg-bin test",
|
||||
"pretest": "npm run clean",
|
||||
"test": "npm run lint:fix && npm run test:local",
|
||||
"test": "npm run lint && npm run typecheck && npm run test:local",
|
||||
"pretest:local": "bash prepare-database-mysql.sh",
|
||||
"test:local": "egg-bin test",
|
||||
"pret": "bash prepare-database-mysql.sh",
|
||||
"t": "npm run lint:fix && egg-bin test --changed",
|
||||
"t": "npm run lint && egg-bin test --changed",
|
||||
"precov": "bash prepare-database-mysql.sh",
|
||||
"cov": "egg-bin cov",
|
||||
"precov:postgresql": "bash prepare-database-postgresql.sh",
|
||||
"cov:postgresql": "CNPMCORE_DATABASE_TYPE=PostgreSQL egg-bin cov",
|
||||
"preci": "npm run clean && npm run lint",
|
||||
"preci": "npm run clean && npm run lint && npm run typecheck",
|
||||
"ci": "npm run cov ",
|
||||
"postci": "npm run tsc:prod && npm run clean",
|
||||
"ci:postgresql": "npm run lint && npm run cov:postgresql && npm run tsc:prod && npm run clean",
|
||||
"clean": "tsc -b --clean && rm -rf dist",
|
||||
"clean": "tsc -b --clean && rm -rf dist *.tsbuildinfo",
|
||||
"tsc": "npm run clean && tsc -p ./tsconfig.json",
|
||||
"tsc:prod": "npm run clean && tsc -p ./tsconfig.prod.json",
|
||||
"prepublishOnly": "npm run tsc:prod",
|
||||
@@ -88,7 +89,7 @@
|
||||
"mocha": "11.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@eggjs/redis": "^3.0.0",
|
||||
"@eggjs/redis": "beta",
|
||||
"@eggjs/scripts": "^4.0.0",
|
||||
"@eggjs/tegg": "beta",
|
||||
"@eggjs/tegg-aop-plugin": "beta",
|
||||
@@ -99,7 +100,8 @@
|
||||
"@eggjs/tegg-orm-plugin": "beta",
|
||||
"@eggjs/tegg-plugin": "beta",
|
||||
"@eggjs/tegg-schedule-plugin": "beta",
|
||||
"@eggjs/tracer": "^3.0.0",
|
||||
"@eggjs/tracer": "beta",
|
||||
"@eggjs/typebox-validate": "beta",
|
||||
"@elastic/elasticsearch": "^8.8.1",
|
||||
"@fengmk2/tar": "^6.2.0",
|
||||
"@node-rs/crc32": "^1.2.2",
|
||||
@@ -108,11 +110,10 @@
|
||||
"base64url": "^3.0.1",
|
||||
"bson-objectid": "^2.0.4",
|
||||
"dayjs": "^1.10.7",
|
||||
"egg": "^4.0.8",
|
||||
"egg": "beta",
|
||||
"egg-cors": "^3.0.0",
|
||||
"egg-errors": "^2.3.0",
|
||||
"egg-status": "^1.0.0",
|
||||
"egg-typebox-validate": "^3.0.0",
|
||||
"egg-view-nunjucks": "^2.3.0",
|
||||
"eggjs-elasticsearch": "^0.0.6",
|
||||
"fast-xml-parser": "^5.0.9",
|
||||
@@ -138,10 +139,10 @@
|
||||
"s3-cnpmcore": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eggjs/bin": "^7.1.0",
|
||||
"@eggjs/mock": "^6.0.7",
|
||||
"@eggjs/bin": "beta",
|
||||
"@eggjs/mock": "beta",
|
||||
"@eggjs/oxlint-config": "^1.0.0",
|
||||
"@eggjs/tsconfig": "^2.0.0",
|
||||
"@eggjs/tsconfig": "beta",
|
||||
"@elastic/elasticsearch-mock": "^2.0.0",
|
||||
"@simplewebauthn/typescript-types": "^7.0.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
@@ -159,6 +160,7 @@
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^15.5.0",
|
||||
"oxlint": "^1.11.0",
|
||||
"oxlint-tsgolint": "^0.2.0",
|
||||
"prettier": "^3.5.3",
|
||||
"typescript": "5"
|
||||
},
|
||||
@@ -169,7 +171,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/cnpm/cnpmcore#readme",
|
||||
"engines": {
|
||||
"node": ">= 20.18.0"
|
||||
"node": "^20.18.0 || >=22.18.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": "prettier --write --ignore-unknown --cache",
|
||||
|
||||
@@ -263,6 +263,24 @@ describe('test/port/controller/package/UpdatePackageController.test.ts', () => {
|
||||
assert.deepEqual(res.body, { ok: true });
|
||||
});
|
||||
|
||||
it('should support pnpm client', async () => {
|
||||
const user = await TestUtil.createUser();
|
||||
mock(app.config.cnpmcore, 'admins', { [user.name]: user.email });
|
||||
const res = await app
|
||||
.httpRequest()
|
||||
.put(`/${scopedName}/-rev/${rev}`)
|
||||
.set('authorization', user.authorization)
|
||||
.set('user-agent', 'pnpm/7.3.1 npm/?')
|
||||
.set('npm-command', 'owner')
|
||||
.send({
|
||||
_id: rev,
|
||||
_rev: rev,
|
||||
maintainers: [{ name: user.name, email: user.email }],
|
||||
});
|
||||
assert.deepEqual(res.body, { ok: true });
|
||||
assert.equal(res.statusCode, 200);
|
||||
});
|
||||
|
||||
it('should 403 when npm client invalid', async () => {
|
||||
const user = await TestUtil.createUser();
|
||||
let res = await app
|
||||
@@ -474,6 +492,24 @@ describe('test/port/controller/package/UpdatePackageController.test.ts', () => {
|
||||
})
|
||||
.expect(200);
|
||||
assert.equal(res.body.ok, true);
|
||||
|
||||
// should valid with pnpm10 and npm=?
|
||||
res = await app
|
||||
.httpRequest()
|
||||
.put(`/${scopedName}/-rev/${rev}`)
|
||||
.set('authorization', publisher.authorization)
|
||||
.set('user-agent', 'pnpm/10.0.0 npm/?')
|
||||
.set('npm-command', 'owner')
|
||||
.send({
|
||||
_id: rev,
|
||||
_rev: rev,
|
||||
maintainers: [
|
||||
{ name: user.name, email: user.email },
|
||||
{ name: publisher.name, email: publisher.email },
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
assert.equal(res.body.ok, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"target": "ES2021",
|
||||
"resolveJsonModule": true,
|
||||
"useUnknownInCatchVariables": false,
|
||||
"declaration": false
|
||||
},
|
||||
"exclude": ["test"]
|
||||
"declaration": false,
|
||||
"erasableSyntaxOnly": false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user