Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support unpkg alias path access entry file #674 #675

Merged
merged 10 commits into from
May 16, 2024
34 changes: 33 additions & 1 deletion app/port/controller/PackageVersionFileController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,22 @@ export class PackageVersionFileController extends AbstractController {
}

const file = await this.packageVersionFileService.showPackageVersionFile(packageVersion, path);
const hasMeta = typeof meta === 'string';

if (!file) {
const possibleFile = await this.#searchPossibleEntries(packageVersion, path);

if (possibleFile) {
const route = `/${fullname}/${versionSpec}/files${possibleFile.path}${hasMeta ? '?meta' : ''}`;

ctx.redirect(route);

return;
}

fengmk2 marked this conversation as resolved.
Show resolved Hide resolved
throw new NotFoundError(`File ${fullname}@${versionSpec}${path} not found`);
}
const hasMeta = typeof meta === 'string';

if (hasMeta) {
ctx.set('cache-control', META_CACHE_CONTROL);
return formatFileItem(file);
Expand All @@ -161,6 +173,26 @@ export class PackageVersionFileController extends AbstractController {
return await this.distRepository.getDistStream(file.dist);
}

/**
* compatibility with unpkg
* 1. try to match alias entry. e.g. accessing `index.js` or `index.json` using /index
* 2. if given path is directory and has `index.js` file, redirect to it. e.g. using `lib` alias to access `lib/index.js` or `lib/index.json`
* @param {PackageVersion} packageVersion packageVersion
* @param {String} path filepath
* @return {Promise<PackageVersionFile | undefined>} return packageVersionFile or null
*/
async #searchPossibleEntries(packageVersion: PackageVersion, path: string) {
const possiblePath = [ `${path}.js`, `${path}.json`, `${path}/index.js`, `${path}/index.json` ];

for (const pathItem of possiblePath) {
const file = await this.packageVersionFileService.showPackageVersionFile(packageVersion, pathItem);

if (file) {
return file;
}
}
}

async #getPackageVersion(ctx: EggContext, fullname: string, scope: string, name: string, versionSpec: string) {
const { blockReason, packageVersion } = await this.packageManagerService.showPackageVersionByVersionOrTag(
scope, name, versionSpec);
Expand Down
Binary file added test/fixtures/@cnpm/cnpm-test-find-entry-1.0.0.tgz
Binary file not shown.
Empty file.
Empty file.
11 changes: 11 additions & 0 deletions test/fixtures/@cnpm/test-find-entry/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "@cnpm/test-find-entry",
"version": "1.0.0",
"description": "cnpmcore local test package",
"main": "index.js",
"scripts": {
"test": "echo \"hello\""
},
"author": "",
"license": "MIT"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { setTimeout } from 'node:timers/promises';
import { app, mock } from 'egg-mock/bootstrap';
import { TestUtil } from '../../../../test/TestUtil';
import { PackageVersionFileService } from '../../../../app/core/service/PackageVersionFileService';
import { calculateIntegrity } from '../../../../app/common/PackageUtil';


describe('test/port/controller/PackageVersionFileController/listFiles.test.ts', () => {
let publisher;
Expand Down Expand Up @@ -352,5 +354,50 @@ describe('test/port/controller/PackageVersionFileController/listFiles.test.ts',
assert.equal(called, 1);
assert.equal(resList.filter(res => res.status === 409 && res.body.error === '[CONFLICT] Package version file sync is currently in progress. Please try again later.').length, 1);
});
it('should redirect to possible entry', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

单测挂了,看看

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我再看看

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
我想请问下 cnpmcore 对 redis 版本有要求吗?我用的 redis-server 5.0.7,在 window 和 wsl 下都有上面的报错。看起来像是 redis 版本有问题?
@fengmk2

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/cnpm/cnpmcore/blob/master/docs/setup.md 安装的是最新版本 redis server

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

确实是版本的问题,现在修复了。麻烦大佬再点一下同意跑跑GitHub的单测。
@fengmk2

const tarball = await TestUtil.readFixturesFile('@cnpm/cnpm-test-find-entry-1.0.0.tgz');
const { integrity } = await calculateIntegrity(tarball);
const pkg = await TestUtil.getFullPackage({
name: '@cnpm/test-find-entry',
version: '1.0.0',
versionObject: {
description: 'test find entry description',
},
attachment: {
data: tarball.toString('base64'),
length: tarball.length,
},
dist: {
integrity,
},
});

await app.httpRequest()
.put(`/${pkg.name}`)
.set('authorization', publisher.authorization)
.set('user-agent', publisher.ua)
.send(pkg)
.expect(201);

await app.httpRequest()
.get(`/${pkg.name}/1.0.0/files/es/array/at`)
.expect(302)
.expect('location', `/${pkg.name}/1.0.0/files/es/array/at.js`);

await app.httpRequest()
.get(`/${pkg.name}/1.0.0/files/es/array`)
.expect(302)
.expect('location', `/${pkg.name}/1.0.0/files/es/array/index.js`);

await app.httpRequest()
.get(`/${pkg.name}/1.0.0/files/es/json/test`)
.expect(302)
.expect('location', `/${pkg.name}/1.0.0/files/es/json/test.json`);

await app.httpRequest()
.get(`/${pkg.name}/1.0.0/files/es/json`)
.expect(302)
.expect('location', `/${pkg.name}/1.0.0/files/es/json/index.json`);
});
});
});