Skip to content

Commit

Permalink
feat: support unpkg alias path access entry file #674 (#675)
Browse files Browse the repository at this point in the history
closes #674

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Implemented a feature to handle compatibility with unpkg by searching
for and redirecting to possible file entries if the requested file is
not found.

- **Tests**
- Added a new test case to ensure the redirection to possible file
entries functions correctly.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
chilingling authored May 16, 2024
1 parent 65d6f44 commit a51891d
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
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;
}

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.
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 () => {
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`);
});
});
});

0 comments on commit a51891d

Please sign in to comment.