From 7b062d52d40150c9d76dd03669cf74014e968059 Mon Sep 17 00:00:00 2001 From: chilingling Date: Thu, 9 May 2024 00:41:55 +0800 Subject: [PATCH 1/8] feat(unpkg): support unpkg alias path access entry file #674 --- .../PackageVersionFileController.ts | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/app/port/controller/PackageVersionFileController.ts b/app/port/controller/PackageVersionFileController.ts index af277525..60316bab 100644 --- a/app/port/controller/PackageVersionFileController.ts +++ b/app/port/controller/PackageVersionFileController.ts @@ -145,10 +145,20 @@ 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); @@ -161,6 +171,28 @@ 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` + * @param packageVersion + * @param path + * @return + */ + async #searchPossibleEntries(packageVersion: any, path: string) { + const possiblePath = [ `${path}.js`, `${path}.json`, `${path}/index.js` ]; + + const possibleFiles = possiblePath.map(pathItem => this.packageVersionFileService.showPackageVersionFile(packageVersion, pathItem)); + + const files = await Promise.allSettled(possibleFiles); + + for (const file of files) { + if (file.status === 'fulfilled' && file.value) { + return file.value; + } + } + } + async #getPackageVersion(ctx: EggContext, fullname: string, scope: string, name: string, versionSpec: string) { const { blockReason, packageVersion } = await this.packageManagerService.showPackageVersionByVersionOrTag( scope, name, versionSpec); From 8e9da2193dbc9dc6872e5e96dd0f4ec168998ab4 Mon Sep 17 00:00:00 2001 From: chilingling Date: Thu, 9 May 2024 23:03:38 +0800 Subject: [PATCH 2/8] fix: improve type description --- .../PackageVersionFileController.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/port/controller/PackageVersionFileController.ts b/app/port/controller/PackageVersionFileController.ts index 60316bab..6e918086 100644 --- a/app/port/controller/PackageVersionFileController.ts +++ b/app/port/controller/PackageVersionFileController.ts @@ -152,7 +152,9 @@ export class PackageVersionFileController extends AbstractController { if (possibleFile) { const route = `/${fullname}/${versionSpec}/files${possibleFile.path}${hasMeta ? '?meta' : ''}`; + ctx.redirect(route); + return; } @@ -174,21 +176,19 @@ export class PackageVersionFileController extends AbstractController { /** * 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` - * @param packageVersion - * @param path - * @return + * 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} return packageVersionFile or null */ - async #searchPossibleEntries(packageVersion: any, path: string) { - const possiblePath = [ `${path}.js`, `${path}.json`, `${path}/index.js` ]; + async #searchPossibleEntries(packageVersion: PackageVersion, path: string) { + const possiblePath = [ `${path}.js`, `${path}.json`, `${path}/index.js`, `${path}/index.json` ]; - const possibleFiles = possiblePath.map(pathItem => this.packageVersionFileService.showPackageVersionFile(packageVersion, pathItem)); + for (const pathItem of possiblePath) { + const file = await this.packageVersionFileService.showPackageVersionFile(packageVersion, pathItem); - const files = await Promise.allSettled(possibleFiles); - - for (const file of files) { - if (file.status === 'fulfilled' && file.value) { - return file.value; + if (file) { + return file; } } } From a8afe894db7f2881bcd3cd6cf9a66a8d66c5e6d6 Mon Sep 17 00:00:00 2001 From: chilingling Date: Tue, 14 May 2024 00:32:42 -0700 Subject: [PATCH 3/8] fix: add unit test for unpkgAliasPath --- .../@cnpm/test-find-entry/es/json/index.json | 0 .../@cnpm/test-find-entry/es/json/test.json | 0 .../@cnpm/test-find-entry/package.json | 11 ++++++ .../listFiles.test.ts | 36 +++++++++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 test/fixtures/@cnpm/test-find-entry/es/json/index.json create mode 100644 test/fixtures/@cnpm/test-find-entry/es/json/test.json create mode 100644 test/fixtures/@cnpm/test-find-entry/package.json diff --git a/test/fixtures/@cnpm/test-find-entry/es/json/index.json b/test/fixtures/@cnpm/test-find-entry/es/json/index.json new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/@cnpm/test-find-entry/es/json/test.json b/test/fixtures/@cnpm/test-find-entry/es/json/test.json new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/@cnpm/test-find-entry/package.json b/test/fixtures/@cnpm/test-find-entry/package.json new file mode 100644 index 00000000..669c6c4a --- /dev/null +++ b/test/fixtures/@cnpm/test-find-entry/package.json @@ -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" +} diff --git a/test/port/controller/PackageVersionFileController/listFiles.test.ts b/test/port/controller/PackageVersionFileController/listFiles.test.ts index 392baede..fd0fb803 100644 --- a/test/port/controller/PackageVersionFileController/listFiles.test.ts +++ b/test/port/controller/PackageVersionFileController/listFiles.test.ts @@ -352,5 +352,41 @@ 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 pkg = await TestUtil.getFullPackage({ + name: '@cnpm/test-find-entry', + version: '1.0.0', + versionObject: { + description: 'work with utf8mb4 ๐Ÿ’ฉ, ๐Œ† utf8_unicode_ci, foo๐Œ†bar ๐Ÿป', + }, + }); + + 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`); + }); }); }); From 6334a811adb3ec8d7fa8f0a32bcebed72f846f66 Mon Sep 17 00:00:00 2001 From: chilingling Date: Thu, 9 May 2024 00:41:55 +0800 Subject: [PATCH 4/8] feat(unpkg): support unpkg alias path access entry file #674 --- .../PackageVersionFileController.ts | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/app/port/controller/PackageVersionFileController.ts b/app/port/controller/PackageVersionFileController.ts index af277525..60316bab 100644 --- a/app/port/controller/PackageVersionFileController.ts +++ b/app/port/controller/PackageVersionFileController.ts @@ -145,10 +145,20 @@ 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); @@ -161,6 +171,28 @@ 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` + * @param packageVersion + * @param path + * @return + */ + async #searchPossibleEntries(packageVersion: any, path: string) { + const possiblePath = [ `${path}.js`, `${path}.json`, `${path}/index.js` ]; + + const possibleFiles = possiblePath.map(pathItem => this.packageVersionFileService.showPackageVersionFile(packageVersion, pathItem)); + + const files = await Promise.allSettled(possibleFiles); + + for (const file of files) { + if (file.status === 'fulfilled' && file.value) { + return file.value; + } + } + } + async #getPackageVersion(ctx: EggContext, fullname: string, scope: string, name: string, versionSpec: string) { const { blockReason, packageVersion } = await this.packageManagerService.showPackageVersionByVersionOrTag( scope, name, versionSpec); From a19f4ef12d3283c4a47ebdff78272177b696e285 Mon Sep 17 00:00:00 2001 From: chilingling Date: Thu, 9 May 2024 23:03:38 +0800 Subject: [PATCH 5/8] fix: improve type description --- .../PackageVersionFileController.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/port/controller/PackageVersionFileController.ts b/app/port/controller/PackageVersionFileController.ts index 60316bab..6e918086 100644 --- a/app/port/controller/PackageVersionFileController.ts +++ b/app/port/controller/PackageVersionFileController.ts @@ -152,7 +152,9 @@ export class PackageVersionFileController extends AbstractController { if (possibleFile) { const route = `/${fullname}/${versionSpec}/files${possibleFile.path}${hasMeta ? '?meta' : ''}`; + ctx.redirect(route); + return; } @@ -174,21 +176,19 @@ export class PackageVersionFileController extends AbstractController { /** * 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` - * @param packageVersion - * @param path - * @return + * 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} return packageVersionFile or null */ - async #searchPossibleEntries(packageVersion: any, path: string) { - const possiblePath = [ `${path}.js`, `${path}.json`, `${path}/index.js` ]; + async #searchPossibleEntries(packageVersion: PackageVersion, path: string) { + const possiblePath = [ `${path}.js`, `${path}.json`, `${path}/index.js`, `${path}/index.json` ]; - const possibleFiles = possiblePath.map(pathItem => this.packageVersionFileService.showPackageVersionFile(packageVersion, pathItem)); + for (const pathItem of possiblePath) { + const file = await this.packageVersionFileService.showPackageVersionFile(packageVersion, pathItem); - const files = await Promise.allSettled(possibleFiles); - - for (const file of files) { - if (file.status === 'fulfilled' && file.value) { - return file.value; + if (file) { + return file; } } } From 72bd7d56b36d3274311c6b1b028a66ba9bc50b6f Mon Sep 17 00:00:00 2001 From: chilingling Date: Tue, 14 May 2024 00:32:42 -0700 Subject: [PATCH 6/8] fix: add unit test for unpkgAliasPath --- .../@cnpm/test-find-entry/es/json/index.json | 0 .../@cnpm/test-find-entry/es/json/test.json | 0 .../@cnpm/test-find-entry/package.json | 11 ++++++ .../listFiles.test.ts | 36 +++++++++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 test/fixtures/@cnpm/test-find-entry/es/json/index.json create mode 100644 test/fixtures/@cnpm/test-find-entry/es/json/test.json create mode 100644 test/fixtures/@cnpm/test-find-entry/package.json diff --git a/test/fixtures/@cnpm/test-find-entry/es/json/index.json b/test/fixtures/@cnpm/test-find-entry/es/json/index.json new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/@cnpm/test-find-entry/es/json/test.json b/test/fixtures/@cnpm/test-find-entry/es/json/test.json new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/@cnpm/test-find-entry/package.json b/test/fixtures/@cnpm/test-find-entry/package.json new file mode 100644 index 00000000..669c6c4a --- /dev/null +++ b/test/fixtures/@cnpm/test-find-entry/package.json @@ -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" +} diff --git a/test/port/controller/PackageVersionFileController/listFiles.test.ts b/test/port/controller/PackageVersionFileController/listFiles.test.ts index 392baede..fd0fb803 100644 --- a/test/port/controller/PackageVersionFileController/listFiles.test.ts +++ b/test/port/controller/PackageVersionFileController/listFiles.test.ts @@ -352,5 +352,41 @@ 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 pkg = await TestUtil.getFullPackage({ + name: '@cnpm/test-find-entry', + version: '1.0.0', + versionObject: { + description: 'work with utf8mb4 ๐Ÿ’ฉ, ๐Œ† utf8_unicode_ci, foo๐Œ†bar ๐Ÿป', + }, + }); + + 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`); + }); }); }); From 8b7c56c23e463924fabe93c7cf981f08fbc29ddd Mon Sep 17 00:00:00 2001 From: chilingling Date: Thu, 16 May 2024 04:18:56 -0700 Subject: [PATCH 7/8] fix: fix unpkgAlias unit test --- .../fixtures/@cnpm/cnpm-test-find-entry-1.0.0.tgz | Bin 0 -> 317 bytes .../@cnpm/test-find-entry/es/json/index.json | 0 .../@cnpm/test-find-entry/es/json/test.json | 0 test/fixtures/@cnpm/test-find-entry/package.json | 11 ----------- .../listFiles.test.ts | 13 ++++++++++++- 5 files changed, 12 insertions(+), 12 deletions(-) create mode 100644 test/fixtures/@cnpm/cnpm-test-find-entry-1.0.0.tgz delete mode 100644 test/fixtures/@cnpm/test-find-entry/es/json/index.json delete mode 100644 test/fixtures/@cnpm/test-find-entry/es/json/test.json delete mode 100644 test/fixtures/@cnpm/test-find-entry/package.json diff --git a/test/fixtures/@cnpm/cnpm-test-find-entry-1.0.0.tgz b/test/fixtures/@cnpm/cnpm-test-find-entry-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..75ff07c337fe5d56976f201cbdff22fe15d64978 GIT binary patch literal 317 zcmV-D0mA+tiwFP!00002|Lv49Ps1<}g*`{ge>i!j$)$0E)QOdWjj@a67?P6Mk?kTX z)c=m0x(vWTQ3yivw^%yAJLU4MH*)dBA7w6W&W+)RoV#pi$*dq^%@}-D4*)5v8jGT? zkpaP?xGpOoNETpk9XAAVh9##(&gVa2{OEtD8u>Es6S&;}HDeh4U)cYh)#}}Tt^U;i zx{UrW>VG(AcK%!bmu&qh|0@>re-U2O1b`|&NV)-fBh)zLPFlBm=v1?k%9#Vbnl#VS z*iI`iD>BS5lpAS<=|&f>`~abigkB5YgC7OqZH0z`ca!p*G@*Q&V(A8^PXeI6*9)a+ zHEd}s`(AG;^|!}U58u018?OmN`c6n?r&aE5?`fJG(}YAW$bbLS=MI4%5om literal 0 HcmV?d00001 diff --git a/test/fixtures/@cnpm/test-find-entry/es/json/index.json b/test/fixtures/@cnpm/test-find-entry/es/json/index.json deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/@cnpm/test-find-entry/es/json/test.json b/test/fixtures/@cnpm/test-find-entry/es/json/test.json deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/@cnpm/test-find-entry/package.json b/test/fixtures/@cnpm/test-find-entry/package.json deleted file mode 100644 index 669c6c4a..00000000 --- a/test/fixtures/@cnpm/test-find-entry/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@cnpm/test-find-entry", - "version": "1.0.0", - "description": "cnpmcore local test package", - "main": "index.js", - "scripts": { - "test": "echo \"hello\"" - }, - "author": "", - "license": "MIT" -} diff --git a/test/port/controller/PackageVersionFileController/listFiles.test.ts b/test/port/controller/PackageVersionFileController/listFiles.test.ts index fd0fb803..8c27596e 100644 --- a/test/port/controller/PackageVersionFileController/listFiles.test.ts +++ b/test/port/controller/PackageVersionFileController/listFiles.test.ts @@ -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; @@ -353,11 +355,20 @@ describe('test/port/controller/PackageVersionFileController/listFiles.test.ts', 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: 'work with utf8mb4 ๐Ÿ’ฉ, ๐Œ† utf8_unicode_ci, foo๐Œ†bar ๐Ÿป', + description: 'test find entry description', + }, + attachment: { + data: tarball.toString('base64'), + length: tarball.length, + }, + dist: { + integrity, }, }); From ae3b5918a396885c4ac96d6e71942d7ae14ac8f4 Mon Sep 17 00:00:00 2001 From: chilingling Date: Thu, 16 May 2024 04:31:21 -0700 Subject: [PATCH 8/8] fix: delete folder, use compressed file --- .../fixtures/@cnpm/test-find-entry/es/json/index.json | 0 test/fixtures/@cnpm/test-find-entry/es/json/test.json | 0 test/fixtures/@cnpm/test-find-entry/package.json | 11 ----------- 3 files changed, 11 deletions(-) delete mode 100644 test/fixtures/@cnpm/test-find-entry/es/json/index.json delete mode 100644 test/fixtures/@cnpm/test-find-entry/es/json/test.json delete mode 100644 test/fixtures/@cnpm/test-find-entry/package.json diff --git a/test/fixtures/@cnpm/test-find-entry/es/json/index.json b/test/fixtures/@cnpm/test-find-entry/es/json/index.json deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/@cnpm/test-find-entry/es/json/test.json b/test/fixtures/@cnpm/test-find-entry/es/json/test.json deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/@cnpm/test-find-entry/package.json b/test/fixtures/@cnpm/test-find-entry/package.json deleted file mode 100644 index 669c6c4a..00000000 --- a/test/fixtures/@cnpm/test-find-entry/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@cnpm/test-find-entry", - "version": "1.0.0", - "description": "cnpmcore local test package", - "main": "index.js", - "scripts": { - "test": "echo \"hello\"" - }, - "author": "", - "license": "MIT" -}