@verdaccio/web 6.0.0-6-next.26 → 6.0.0-6-next.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/build/api/readme.js +2 -3
- package/build/api/readme.js.map +1 -1
- package/build/api/search.js +64 -61
- package/build/api/search.js.map +1 -1
- package/build/middleware/render-web.d.ts +1 -1
- package/build/middleware/render-web.js +1 -6
- package/build/middleware/render-web.js.map +1 -1
- package/build/middleware/web-api.js +1 -6
- package/build/middleware/web-api.js.map +1 -1
- package/build/renderHTML.js +30 -14
- package/build/renderHTML.js.map +1 -1
- package/build/utils/web-utils.js +1 -1
- package/build/utils/web-utils.js.map +1 -1
- package/build/web-middleware.js +1 -1
- package/build/web-middleware.js.map +1 -1
- package/package.json +70 -65
- package/src/api/readme.ts +2 -3
- package/src/api/search.ts +64 -55
- package/src/middleware/render-web.ts +1 -3
- package/src/middleware/web-api.ts +0 -2
- package/src/renderHTML.ts +31 -9
- package/src/utils/web-utils.ts +1 -1
- package/src/web-middleware.ts +1 -1
- package/test/api.readme.test.ts +29 -27
- package/test/api.search.test.ts +18 -45
- package/test/api.sidebar.test.ts +22 -36
- package/test/api.user.test.ts +1 -1
- package/test/config/default-test.yaml +1 -5
- package/test/config/login-disabled.yaml +1 -5
- package/test/config/web.yaml +46 -0
- package/test/helper.ts +7 -23
- package/test/partials/search/search-v1.json +157 -0
- package/test/render.test.ts +71 -24
- package/test/utils.spec.ts +10 -1
- package/tsconfig.json +6 -0
package/package.json
CHANGED
|
@@ -1,66 +1,71 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
2
|
+
"name": "@verdaccio/web",
|
|
3
|
+
"version": "6.0.0-6-next.29",
|
|
4
|
+
"description": "web ui middleware",
|
|
5
|
+
"main": "./build/index.js",
|
|
6
|
+
"types": "build/index.d.ts",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "https",
|
|
9
|
+
"url": "https://github.com/verdaccio/verdaccio"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"private",
|
|
13
|
+
"package",
|
|
14
|
+
"repository",
|
|
15
|
+
"registry",
|
|
16
|
+
"enterprise",
|
|
17
|
+
"modules",
|
|
18
|
+
"proxy",
|
|
19
|
+
"server",
|
|
20
|
+
"verdaccio"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=14",
|
|
24
|
+
"npm": ">=6"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@verdaccio/auth": "6.0.0-6-next.22",
|
|
29
|
+
"@verdaccio/core": "6.0.0-6-next.5",
|
|
30
|
+
"@verdaccio/config": "6.0.0-6-next.14",
|
|
31
|
+
"@verdaccio/loaders": "6.0.0-6-next.12",
|
|
32
|
+
"@verdaccio/logger": "6.0.0-6-next.11",
|
|
33
|
+
"@verdaccio/middleware": "6.0.0-6-next.22",
|
|
34
|
+
"@verdaccio/readme": "11.0.0-6-next.4",
|
|
35
|
+
"@verdaccio/store": "6.0.0-6-next.22",
|
|
36
|
+
"@verdaccio/tarball": "11.0.0-6-next.12",
|
|
37
|
+
"@verdaccio/url": "11.0.0-6-next.9",
|
|
38
|
+
"@verdaccio/utils": "6.0.0-6-next.11",
|
|
39
|
+
"body-parser": "1.19.1",
|
|
40
|
+
"debug": "4.3.3",
|
|
41
|
+
"express": "4.17.2",
|
|
42
|
+
"lodash": "4.17.21",
|
|
43
|
+
"lru-cache": "6.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "16.11.21",
|
|
47
|
+
"@verdaccio/types": "11.0.0-6-next.12",
|
|
48
|
+
"@verdaccio/test-helper": "1.1.0-6-next.1",
|
|
49
|
+
"@verdaccio/api": "6.0.0-6-next.25",
|
|
50
|
+
"node-html-parser": "4.1.5",
|
|
51
|
+
"supertest": "6.2.2",
|
|
52
|
+
"nock": "13.2.2",
|
|
53
|
+
"jsdom": "20.0.0",
|
|
54
|
+
"undici": "4.15.0",
|
|
55
|
+
"verdaccio-auth-memory": "11.0.0-6-next.8",
|
|
56
|
+
"verdaccio-memory": "11.0.0-6-next.10"
|
|
57
|
+
},
|
|
58
|
+
"funding": {
|
|
59
|
+
"type": "opencollective",
|
|
60
|
+
"url": "https://opencollective.com/verdaccio"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"clean": "rimraf ./build",
|
|
64
|
+
"test": "jest",
|
|
65
|
+
"type-check": "tsc --noEmit -p tsconfig.build.json",
|
|
66
|
+
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
|
|
67
|
+
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
|
|
68
|
+
"watch": "pnpm build:js -- --watch",
|
|
69
|
+
"build": "pnpm run build:js && pnpm run build:types"
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/api/readme.ts
CHANGED
|
@@ -39,12 +39,11 @@ function addReadmeWebApi(storage: Storage, auth: IAuth): Router {
|
|
|
39
39
|
uplinksLook: true,
|
|
40
40
|
req,
|
|
41
41
|
callback: function (err, info): void {
|
|
42
|
-
debug('readme
|
|
42
|
+
debug('readme pkg %o', info?.name);
|
|
43
|
+
res.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8);
|
|
43
44
|
if (err) {
|
|
44
45
|
return next(err);
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
res.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8);
|
|
48
47
|
try {
|
|
49
48
|
next(parseReadme(info.name, info.readme));
|
|
50
49
|
} catch {
|
package/src/api/search.ts
CHANGED
|
@@ -1,55 +1,39 @@
|
|
|
1
1
|
import buildDebug from 'debug';
|
|
2
2
|
import { Router } from 'express';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import { URLSearchParams } from 'url';
|
|
3
5
|
|
|
4
6
|
import { IAuth } from '@verdaccio/auth';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
+
import { errorUtils, searchUtils } from '@verdaccio/core';
|
|
8
|
+
import { SearchQuery } from '@verdaccio/core/src/search-utils';
|
|
7
9
|
import { Storage } from '@verdaccio/store';
|
|
8
|
-
import {
|
|
10
|
+
import { Manifest } from '@verdaccio/types';
|
|
9
11
|
|
|
10
12
|
import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from './package';
|
|
11
13
|
|
|
12
14
|
const debug = buildDebug('verdaccio:web:api:search');
|
|
13
15
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
auth.allow_access(
|
|
29
|
-
{ packageName: pkg.name },
|
|
30
|
-
remoteUser,
|
|
31
|
-
function (err, allowed): void {
|
|
32
|
-
debug('is allowed %o', allowed);
|
|
33
|
-
if (err || !allowed) {
|
|
34
|
-
debug('deny access');
|
|
35
|
-
reject(err);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
debug('access succeed');
|
|
39
|
-
resolve(pkg.versions[pkg[DIST_TAGS].latest]);
|
|
40
|
-
}
|
|
41
|
-
);
|
|
42
|
-
} else {
|
|
43
|
-
reject(err);
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
} catch (err: any) {
|
|
48
|
-
reject(err);
|
|
16
|
+
function checkAccess(pkg: any, auth: any, remoteUser): Promise<Manifest | null> {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
auth.allow_access({ packageName: pkg?.package?.name }, remoteUser, function (err, allowed) {
|
|
19
|
+
if (err) {
|
|
20
|
+
if (err.status && String(err.status).match(/^4\d\d$/)) {
|
|
21
|
+
// auth plugin returns 4xx user error,
|
|
22
|
+
// that's equivalent of !allowed basically
|
|
23
|
+
allowed = false;
|
|
24
|
+
return resolve(null);
|
|
25
|
+
} else {
|
|
26
|
+
reject(err);
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
return resolve(allowed ? pkg : null);
|
|
49
30
|
}
|
|
50
31
|
});
|
|
51
|
-
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
52
34
|
|
|
35
|
+
function addSearchWebApi(storage: Storage, auth: IAuth): Router {
|
|
36
|
+
const router = Router(); /* eslint new-cap: 0 */
|
|
53
37
|
router.get(
|
|
54
38
|
'/search/:anything',
|
|
55
39
|
async function (
|
|
@@ -57,22 +41,47 @@ function addSearchWebApi(storage: Storage, auth: IAuth): Router {
|
|
|
57
41
|
res: $ResponseExtend,
|
|
58
42
|
next: $NextFunctionVer
|
|
59
43
|
): Promise<void> {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
44
|
+
try {
|
|
45
|
+
let data;
|
|
46
|
+
const abort = new AbortController();
|
|
47
|
+
req.on('aborted', () => {
|
|
48
|
+
debug('search web aborted');
|
|
49
|
+
abort.abort();
|
|
50
|
+
});
|
|
51
|
+
const text: string = (req.params.anything as string) ?? '';
|
|
52
|
+
// These values are declared as optimal by npm cli
|
|
53
|
+
// FUTURE: could be overwritten by ui settings.
|
|
54
|
+
const size = 20;
|
|
55
|
+
const from = 0;
|
|
56
|
+
const query: SearchQuery = {
|
|
57
|
+
from: 0,
|
|
58
|
+
maintenance: 0.5,
|
|
59
|
+
popularity: 0.98,
|
|
60
|
+
quality: 0.65,
|
|
61
|
+
size: 20,
|
|
62
|
+
text,
|
|
63
|
+
};
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
const urlParams = new URLSearchParams(query);
|
|
66
|
+
debug('search web init');
|
|
67
|
+
data = await storage.searchManager?.search({
|
|
68
|
+
query,
|
|
69
|
+
url: `/-/v1/search?${urlParams.toString()}`,
|
|
70
|
+
abort,
|
|
71
|
+
});
|
|
72
|
+
const checkAccessPromises: searchUtils.SearchItemPkg[] = await Promise.all(
|
|
73
|
+
data.map((pkgItem) => {
|
|
74
|
+
return checkAccess(pkgItem, auth, req.remote_user);
|
|
75
|
+
})
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const final: searchUtils.SearchItemPkg[] = checkAccessPromises
|
|
79
|
+
.filter((i) => !_.isNull(i))
|
|
80
|
+
.slice(from, size);
|
|
81
|
+
|
|
82
|
+
next(final);
|
|
83
|
+
} catch (err: any) {
|
|
84
|
+
next(errorUtils.getInternalError(err.message));
|
|
76
85
|
}
|
|
77
86
|
}
|
|
78
87
|
);
|
|
@@ -5,7 +5,6 @@ import path from 'path';
|
|
|
5
5
|
|
|
6
6
|
import { HTTP_STATUS } from '@verdaccio/core';
|
|
7
7
|
import { loadPlugin } from '@verdaccio/loaders';
|
|
8
|
-
import { SearchInstance } from '@verdaccio/store';
|
|
9
8
|
import { isURLhasValidProtocol } from '@verdaccio/url';
|
|
10
9
|
|
|
11
10
|
import renderHTML from '../renderHTML';
|
|
@@ -40,10 +39,9 @@ const sendFileCallback = (next) => (err) => {
|
|
|
40
39
|
}
|
|
41
40
|
};
|
|
42
41
|
|
|
43
|
-
export function renderWebMiddleware(config, auth
|
|
42
|
+
export function renderWebMiddleware(config, auth): any {
|
|
44
43
|
const { staticPath, manifest, manifestFiles } = require('@verdaccio/ui-theme')();
|
|
45
44
|
debug('static path %o', staticPath);
|
|
46
|
-
SearchInstance.configureStorage(storage);
|
|
47
45
|
|
|
48
46
|
/* eslint new-cap:off */
|
|
49
47
|
const router = express.Router();
|
|
@@ -3,7 +3,6 @@ import { Router } from 'express';
|
|
|
3
3
|
|
|
4
4
|
import { IAuth } from '@verdaccio/auth';
|
|
5
5
|
import { match, validateName, validatePackage } from '@verdaccio/middleware';
|
|
6
|
-
import { SearchInstance } from '@verdaccio/store';
|
|
7
6
|
import { Storage } from '@verdaccio/store';
|
|
8
7
|
import { Config } from '@verdaccio/types';
|
|
9
8
|
|
|
@@ -13,7 +12,6 @@ import { setSecurityWebHeaders } from './security';
|
|
|
13
12
|
export function webAPI(config: Config, auth: IAuth, storage: Storage): Router {
|
|
14
13
|
// eslint-disable-next-line new-cap
|
|
15
14
|
const route = Router();
|
|
16
|
-
SearchInstance.configureStorage(storage);
|
|
17
15
|
// validate all of these params as a package name
|
|
18
16
|
// this might be too harsh, so ask if it causes trouble=
|
|
19
17
|
route.param('package', validatePackage);
|
package/src/renderHTML.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { URL } from 'url';
|
|
|
4
4
|
|
|
5
5
|
import { WEB_TITLE } from '@verdaccio/config';
|
|
6
6
|
import { HEADERS } from '@verdaccio/core';
|
|
7
|
+
import { TemplateUIOptions } from '@verdaccio/types';
|
|
7
8
|
import { getPublicUrl } from '@verdaccio/url';
|
|
8
9
|
|
|
9
10
|
import renderTemplate from './template';
|
|
@@ -25,6 +26,9 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
|
|
|
25
26
|
const base = getPublicUrl(config?.url_prefix, req);
|
|
26
27
|
const basename = new URL(base).pathname;
|
|
27
28
|
const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;
|
|
29
|
+
const needHtmlCache = [undefined, null].includes(config?.web?.html_cache)
|
|
30
|
+
? true
|
|
31
|
+
: config.web.html_cache;
|
|
28
32
|
const darkMode = config?.web?.darkMode ?? false;
|
|
29
33
|
const title = config?.web?.title ?? WEB_TITLE;
|
|
30
34
|
const login = hasLogin(config);
|
|
@@ -32,8 +36,21 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
|
|
|
32
36
|
const logoURI = config?.web?.logo ?? '';
|
|
33
37
|
const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm'];
|
|
34
38
|
const version = pkgJSON.version;
|
|
39
|
+
const flags = {
|
|
40
|
+
...config.flags,
|
|
41
|
+
};
|
|
35
42
|
const primaryColor = validatePrimaryColor(config?.web?.primary_color) ?? '#4b5e40';
|
|
36
|
-
const {
|
|
43
|
+
const {
|
|
44
|
+
scriptsBodyAfter,
|
|
45
|
+
metaScripts,
|
|
46
|
+
scriptsbodyBefore,
|
|
47
|
+
showInfo,
|
|
48
|
+
showSettings,
|
|
49
|
+
showThemeSwitch,
|
|
50
|
+
showFooter,
|
|
51
|
+
showSearch,
|
|
52
|
+
showDownloadTarball,
|
|
53
|
+
} = Object.assign(
|
|
37
54
|
{},
|
|
38
55
|
{
|
|
39
56
|
scriptsBodyAfter: [],
|
|
@@ -42,7 +59,13 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
|
|
|
42
59
|
},
|
|
43
60
|
config?.web
|
|
44
61
|
);
|
|
45
|
-
const options = {
|
|
62
|
+
const options: TemplateUIOptions = {
|
|
63
|
+
showInfo,
|
|
64
|
+
showSettings,
|
|
65
|
+
showThemeSwitch,
|
|
66
|
+
showFooter,
|
|
67
|
+
showSearch,
|
|
68
|
+
showDownloadTarball,
|
|
46
69
|
darkMode,
|
|
47
70
|
url_prefix,
|
|
48
71
|
basename,
|
|
@@ -50,6 +73,7 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
|
|
|
50
73
|
primaryColor,
|
|
51
74
|
version,
|
|
52
75
|
logoURI,
|
|
76
|
+
flags,
|
|
53
77
|
login,
|
|
54
78
|
pkgManagers,
|
|
55
79
|
title,
|
|
@@ -61,10 +85,7 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
|
|
|
61
85
|
|
|
62
86
|
try {
|
|
63
87
|
webPage = cache.get('template');
|
|
64
|
-
|
|
65
88
|
if (!webPage) {
|
|
66
|
-
debug('web options %o', options);
|
|
67
|
-
debug('web manifestFiles %o', manifestFiles);
|
|
68
89
|
webPage = renderTemplate(
|
|
69
90
|
{
|
|
70
91
|
manifest: manifestFiles ?? defaultManifestFiles,
|
|
@@ -75,9 +96,10 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
|
|
|
75
96
|
},
|
|
76
97
|
manifest
|
|
77
98
|
);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
99
|
+
if (needHtmlCache) {
|
|
100
|
+
cache.set('template', webPage);
|
|
101
|
+
debug('set template cache');
|
|
102
|
+
}
|
|
81
103
|
} else {
|
|
82
104
|
debug('reuse template cache');
|
|
83
105
|
}
|
|
@@ -86,5 +108,5 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
|
|
|
86
108
|
}
|
|
87
109
|
res.setHeader('Content-Type', HEADERS.TEXT_HTML);
|
|
88
110
|
res.send(webPage);
|
|
89
|
-
debug('
|
|
111
|
+
debug('web rendered');
|
|
90
112
|
}
|
package/src/utils/web-utils.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type AuthorAvatar = Author & { avatar?: string };
|
|
|
10
10
|
const debug = buildDebug('verdaccio:web:utils');
|
|
11
11
|
|
|
12
12
|
export function validatePrimaryColor(primaryColor) {
|
|
13
|
-
const isHex =
|
|
13
|
+
const isHex = /^#([0-9A-F]{3}){1,2}$/i.test(primaryColor);
|
|
14
14
|
if (!isHex) {
|
|
15
15
|
debug('invalid primary color %o', primaryColor);
|
|
16
16
|
return;
|
package/src/web-middleware.ts
CHANGED
|
@@ -7,7 +7,7 @@ export default (config, auth, storage) => {
|
|
|
7
7
|
// eslint-disable-next-line new-cap
|
|
8
8
|
const app = express.Router();
|
|
9
9
|
// load application
|
|
10
|
-
app.use('/', renderWebMiddleware(config, auth
|
|
10
|
+
app.use('/', renderWebMiddleware(config, auth));
|
|
11
11
|
// web endpoints, search, packages, etc
|
|
12
12
|
app.use('/-/verdaccio/', webAPI(config, auth, storage));
|
|
13
13
|
return app;
|
package/test/api.readme.test.ts
CHANGED
|
@@ -3,7 +3,7 @@ import supertest from 'supertest';
|
|
|
3
3
|
|
|
4
4
|
import { HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
|
|
5
5
|
import { setup } from '@verdaccio/logger';
|
|
6
|
-
import {
|
|
6
|
+
import { publishVersion } from '@verdaccio/test-helper';
|
|
7
7
|
|
|
8
8
|
import { NOT_README_FOUND } from '../src/api/readme';
|
|
9
9
|
import { initializeServer } from './helper';
|
|
@@ -13,30 +13,6 @@ setup([]);
|
|
|
13
13
|
const mockManifest = jest.fn();
|
|
14
14
|
jest.mock('@verdaccio/ui-theme', () => mockManifest());
|
|
15
15
|
|
|
16
|
-
jest.mock('@verdaccio/store', () => ({
|
|
17
|
-
Storage: class {
|
|
18
|
-
public init() {
|
|
19
|
-
return Promise.resolve();
|
|
20
|
-
}
|
|
21
|
-
public getPackage({ name, callback }: IGetPackageOptions) {
|
|
22
|
-
callback(null, {
|
|
23
|
-
name,
|
|
24
|
-
['dist-tags']: {
|
|
25
|
-
latest: '1.0.0',
|
|
26
|
-
},
|
|
27
|
-
versions: {
|
|
28
|
-
['1.0.0']: {
|
|
29
|
-
name,
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
SearchInstance: {
|
|
36
|
-
configureStorage: () => {},
|
|
37
|
-
},
|
|
38
|
-
}));
|
|
39
|
-
|
|
40
16
|
describe('readme api', () => {
|
|
41
17
|
beforeAll(() => {
|
|
42
18
|
mockManifest.mockReturnValue(() => ({
|
|
@@ -54,7 +30,20 @@ describe('readme api', () => {
|
|
|
54
30
|
});
|
|
55
31
|
|
|
56
32
|
test('should fetch readme scoped package', async () => {
|
|
57
|
-
const
|
|
33
|
+
const app = await initializeServer('default-test.yaml');
|
|
34
|
+
await publishVersion(app, '@scope/pk1-test', '1.0.0', { readme: 'my readme scoped' });
|
|
35
|
+
const response = await supertest(app)
|
|
36
|
+
.get('/-/verdaccio/data/package/readme/@scope/pk1-test')
|
|
37
|
+
.set('Accept', HEADERS.TEXT_PLAIN)
|
|
38
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
|
|
39
|
+
.expect(HTTP_STATUS.OK);
|
|
40
|
+
expect(response.text).toMatch('my readme scoped');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('should fetch readme scoped package with not found message', async () => {
|
|
44
|
+
const app = await initializeServer('default-test.yaml');
|
|
45
|
+
await publishVersion(app, '@scope/pk1-test', '1.0.0', { readme: null });
|
|
46
|
+
const response = await supertest(app)
|
|
58
47
|
.get('/-/verdaccio/data/package/readme/@scope/pk1-test')
|
|
59
48
|
.set('Accept', HEADERS.TEXT_PLAIN)
|
|
60
49
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
|
|
@@ -63,7 +52,20 @@ describe('readme api', () => {
|
|
|
63
52
|
});
|
|
64
53
|
|
|
65
54
|
test('should fetch readme a package', async () => {
|
|
66
|
-
const
|
|
55
|
+
const app = await initializeServer('default-test.yaml');
|
|
56
|
+
await publishVersion(app, 'pk1-test', '1.0.0', { readme: 'my readme' });
|
|
57
|
+
const response = await supertest(app)
|
|
58
|
+
.get('/-/verdaccio/data/package/readme/pk1-test')
|
|
59
|
+
.set('Accept', HEADERS.TEXT_PLAIN)
|
|
60
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
|
|
61
|
+
.expect(HTTP_STATUS.OK);
|
|
62
|
+
expect(response.text).toMatch('my readme');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('should fetch readme a package with not found message', async () => {
|
|
66
|
+
const app = await initializeServer('default-test.yaml');
|
|
67
|
+
await publishVersion(app, 'pk1-test', '1.0.0', { readme: null });
|
|
68
|
+
const response = await supertest(app)
|
|
67
69
|
.get('/-/verdaccio/data/package/readme/pk1-test')
|
|
68
70
|
.set('Accept', HEADERS.TEXT_PLAIN)
|
|
69
71
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
|
package/test/api.search.test.ts
CHANGED
|
@@ -3,44 +3,15 @@ import supertest from 'supertest';
|
|
|
3
3
|
|
|
4
4
|
import { HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
|
|
5
5
|
import { setup } from '@verdaccio/logger';
|
|
6
|
-
import {
|
|
6
|
+
import { publishVersion } from '@verdaccio/test-helper';
|
|
7
7
|
|
|
8
8
|
import { initializeServer } from './helper';
|
|
9
9
|
|
|
10
10
|
setup([]);
|
|
11
11
|
|
|
12
12
|
const mockManifest = jest.fn();
|
|
13
|
-
const mockQuery = jest.fn(() => [
|
|
14
|
-
{ ref: 'pkg1', score: 1 },
|
|
15
|
-
{ ref: 'pk2', score: 0.9 },
|
|
16
|
-
]);
|
|
17
13
|
jest.mock('@verdaccio/ui-theme', () => mockManifest());
|
|
18
14
|
|
|
19
|
-
jest.mock('@verdaccio/store', () => ({
|
|
20
|
-
Storage: class {
|
|
21
|
-
public init() {
|
|
22
|
-
return Promise.resolve();
|
|
23
|
-
}
|
|
24
|
-
public getPackage({ name, callback }: IGetPackageOptions) {
|
|
25
|
-
callback(null, {
|
|
26
|
-
name,
|
|
27
|
-
['dist-tags']: {
|
|
28
|
-
latest: '1.0.0',
|
|
29
|
-
},
|
|
30
|
-
versions: {
|
|
31
|
-
['1.0.0']: {
|
|
32
|
-
name,
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
SearchInstance: {
|
|
39
|
-
configureStorage: () => {},
|
|
40
|
-
query: () => mockQuery(),
|
|
41
|
-
},
|
|
42
|
-
}));
|
|
43
|
-
|
|
44
15
|
describe('test web server', () => {
|
|
45
16
|
beforeAll(() => {
|
|
46
17
|
mockManifest.mockReturnValue(() => ({
|
|
@@ -53,21 +24,24 @@ describe('test web server', () => {
|
|
|
53
24
|
});
|
|
54
25
|
|
|
55
26
|
afterEach(() => {
|
|
27
|
+
Date.now = jest.fn(() => new Date(Date.UTC(2017, 1, 14)).valueOf());
|
|
56
28
|
jest.clearAllMocks();
|
|
57
29
|
mockManifest.mockClear();
|
|
58
30
|
});
|
|
59
31
|
|
|
60
|
-
test('should
|
|
61
|
-
const
|
|
62
|
-
|
|
32
|
+
test('should find results to search api', async () => {
|
|
33
|
+
const app = await initializeServer('default-test.yaml');
|
|
34
|
+
await publishVersion(app, 'foo', '1.0.0');
|
|
35
|
+
const response = await supertest(app)
|
|
36
|
+
.get('/-/verdaccio/data/search/foo')
|
|
63
37
|
.set('Accept', HEADERS.JSON_CHARSET)
|
|
64
38
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
65
39
|
.expect(HTTP_STATUS.OK);
|
|
66
|
-
expect(response.body).toHaveLength(
|
|
40
|
+
expect(response.body).toHaveLength(1);
|
|
41
|
+
// FUTURE: we can improve here matching the right outcome
|
|
67
42
|
});
|
|
68
43
|
|
|
69
|
-
test('should
|
|
70
|
-
mockQuery.mockReturnValue([]);
|
|
44
|
+
test('should found no results to search', async () => {
|
|
71
45
|
const response = await supertest(await initializeServer('default-test.yaml'))
|
|
72
46
|
.get('/-/verdaccio/data/search/notFound')
|
|
73
47
|
.set('Accept', HEADERS.JSON_CHARSET)
|
|
@@ -76,19 +50,18 @@ describe('test web server', () => {
|
|
|
76
50
|
expect(response.body).toHaveLength(0);
|
|
77
51
|
});
|
|
78
52
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return [
|
|
82
|
-
{ ref: 'aa', score: 1 },
|
|
83
|
-
{ ref: 'bb', score: 0.8 },
|
|
84
|
-
{ ref: 'cc', score: 0.6 },
|
|
85
|
-
];
|
|
86
|
-
});
|
|
53
|
+
// TODO: need a way to make this fail
|
|
54
|
+
test.skip('should fail search api', async () => {
|
|
87
55
|
const response = await supertest(await initializeServer('default-test.yaml'))
|
|
88
|
-
.get('/-/verdaccio/data/search/
|
|
56
|
+
.get('/-/verdaccio/data/search/thisWillFail')
|
|
89
57
|
.set('Accept', HEADERS.JSON_CHARSET)
|
|
90
58
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
91
59
|
.expect(HTTP_STATUS.OK);
|
|
92
60
|
expect(response.body).toHaveLength(3);
|
|
93
61
|
});
|
|
62
|
+
|
|
63
|
+
test.todo('search abort request');
|
|
64
|
+
// maybe these could be done in storage package to avoid have specifics on this level
|
|
65
|
+
test.todo('search allow request permissions');
|
|
66
|
+
test.todo('search query params, pagination etc');
|
|
94
67
|
});
|