@verdaccio/middleware 7.0.0-next.5 → 8.0.0-next-8.0

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +217 -0
  2. package/LICENSE +1 -1
  3. package/build/index.js.map +1 -1
  4. package/build/middlewares/allow.js +2 -2
  5. package/build/middlewares/allow.js.map +1 -1
  6. package/build/middlewares/antiLoop.js +1 -1
  7. package/build/middlewares/antiLoop.js.map +1 -1
  8. package/build/middlewares/encode-pkg.js.map +1 -1
  9. package/build/middlewares/error.js +1 -1
  10. package/build/middlewares/error.js.map +1 -1
  11. package/build/middlewares/final.js +2 -2
  12. package/build/middlewares/final.js.map +1 -1
  13. package/build/middlewares/json.js.map +1 -1
  14. package/build/middlewares/log.js +1 -1
  15. package/build/middlewares/log.js.map +1 -1
  16. package/build/middlewares/match.js.map +1 -1
  17. package/build/middlewares/media.js.map +1 -1
  18. package/build/middlewares/rate-limit.js +1 -1
  19. package/build/middlewares/rate-limit.js.map +1 -1
  20. package/build/middlewares/security-headers.js.map +1 -1
  21. package/build/middlewares/user-agent.js.map +1 -1
  22. package/build/middlewares/validation.js.map +1 -1
  23. package/build/middlewares/web/index.js +1 -1
  24. package/build/middlewares/web/index.js.map +1 -1
  25. package/build/middlewares/web/render-web.js +46 -26
  26. package/build/middlewares/web/render-web.js.map +1 -1
  27. package/build/middlewares/web/security.js.map +1 -1
  28. package/build/middlewares/web/utils/manifest.js +8 -2
  29. package/build/middlewares/web/utils/manifest.js.map +1 -1
  30. package/build/middlewares/web/utils/renderHTML.d.ts +6 -2
  31. package/build/middlewares/web/utils/renderHTML.js +30 -24
  32. package/build/middlewares/web/utils/renderHTML.js.map +1 -1
  33. package/build/middlewares/web/utils/template.js +7 -7
  34. package/build/middlewares/web/utils/template.js.map +1 -1
  35. package/build/middlewares/web/utils/web-utils.js +2 -2
  36. package/build/middlewares/web/utils/web-utils.js.map +1 -1
  37. package/build/middlewares/web/web-api.js +1 -1
  38. package/build/middlewares/web/web-api.js.map +1 -1
  39. package/build/middlewares/web/web-middleware.js +1 -1
  40. package/build/middlewares/web/web-middleware.js.map +1 -1
  41. package/build/types.js.map +1 -1
  42. package/package.json +14 -13
  43. package/src/middlewares/web/render-web.ts +46 -26
  44. package/src/middlewares/web/utils/manifest.ts +9 -1
  45. package/src/middlewares/web/utils/renderHTML.ts +34 -12
  46. package/src/middlewares/web/utils/template.ts +6 -6
  47. package/test/__snapshots__/template.test.ts.snap +49 -69
  48. package/test/config/favicon.ico +0 -0
  49. package/test/config/file-logo.yaml +2 -0
  50. package/test/config/http-logo.yaml +26 -0
  51. package/test/config/no-logo.yaml +1 -0
  52. package/test/manifest.test.ts +12 -0
  53. package/test/render.spec.ts +23 -0
  54. package/test/template.test.ts +10 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/middleware",
3
- "version": "7.0.0-next.5",
3
+ "version": "8.0.0-next-8.0",
4
4
  "description": "express middleware utils",
5
5
  "main": "./build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -29,25 +29,25 @@
29
29
  "node": ">=12"
30
30
  },
31
31
  "dependencies": {
32
- "@verdaccio/core": "7.0.0-next.5",
33
- "@verdaccio/utils": "7.0.0-next.5",
34
- "@verdaccio/config": "7.0.0-next.5",
35
- "@verdaccio/url": "12.0.0-next.5",
36
- "debug": "4.3.4",
37
- "lru-cache": "7.18.3",
38
- "express": "4.18.2",
32
+ "@verdaccio/config": "8.0.0-next-8.0",
33
+ "@verdaccio/core": "8.0.0-next-8.0",
34
+ "@verdaccio/url": "13.0.0-next-8.0",
35
+ "@verdaccio/utils": "7.0.1-next-8.0",
36
+ "debug": "4.3.7",
37
+ "express": "4.21.0",
38
+ "express-rate-limit": "5.5.1",
39
39
  "lodash": "4.17.21",
40
- "mime": "2.6.0",
41
- "express-rate-limit": "5.5.1"
40
+ "lru-cache": "7.18.3",
41
+ "mime": "2.6.0"
42
42
  },
43
43
  "funding": {
44
44
  "type": "opencollective",
45
45
  "url": "https://opencollective.com/verdaccio"
46
46
  },
47
47
  "devDependencies": {
48
- "@verdaccio/logger": "7.0.0-next.5",
49
- "body-parser": "1.20.2",
50
- "supertest": "6.3.3"
48
+ "@verdaccio/logger": "8.0.0-next-8.0",
49
+ "body-parser": "1.20.3",
50
+ "supertest": "7.0.0"
51
51
  },
52
52
  "scripts": {
53
53
  "clean": "rimraf ./build",
@@ -56,6 +56,7 @@
56
56
  "build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
57
57
  "watch": "pnpm build:js -- --watch",
58
58
  "test": "jest",
59
+ "test:snap": "jest --updateSnapshot",
59
60
  "build": "pnpm run build:js && pnpm run build:types"
60
61
  }
61
62
  }
@@ -37,39 +37,59 @@ export function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
37
37
  // any match within the static is routed to the file system
38
38
  router.get('/-/static/*', function (req, res, next) {
39
39
  const filename = req.params[0];
40
- const file = `${staticPath}/${filename}`;
40
+ let file = `${staticPath}/${filename}`;
41
+ if (filename === 'favicon.ico' && config?.web?.favicon) {
42
+ file = config?.web?.favicon;
43
+ if (isURLhasValidProtocol(file)) {
44
+ debug('redirect to favicon %s', file);
45
+ req.url = file;
46
+ return next();
47
+ }
48
+ }
41
49
  debug('render static file %o', file);
42
50
  res.sendFile(file, sendFileCallback(next));
43
51
  });
44
52
 
45
- // check the origin of the logo
46
- if (config?.web?.logo && !isURLhasValidProtocol(config?.web?.logo)) {
47
- // URI related to a local file
48
- const absoluteLocalFile = path.posix.resolve(config.web.logo);
49
- debug('serve local logo %s', absoluteLocalFile);
50
- try {
51
- // TODO: replace existsSync by async alternative
52
- if (
53
- fs.existsSync(absoluteLocalFile) &&
54
- typeof fs.accessSync(absoluteLocalFile, fs.constants.R_OK) === 'undefined'
55
- ) {
56
- // Note: `path.join` will break on Windows, because it transforms `/` to `\`
57
- // Use POSIX version `path.posix.join` instead.
58
- config.web.logo = path.posix.join('/-/static/', path.basename(config.web.logo));
59
- router.get(config.web.logo, function (_req, res, next) {
60
- // @ts-ignore
61
- debug('serve custom logo web:%s - local:%s', config.web.logo, absoluteLocalFile);
62
- res.sendFile(absoluteLocalFile, sendFileCallback(next));
63
- });
64
- debug('enabled custom logo %s', config.web.logo);
65
- } else {
66
- config.web.logo = undefined;
53
+ function renderLogo(logo: string | undefined): string | undefined {
54
+ // check the origin of the logo
55
+ if (logo && !isURLhasValidProtocol(logo)) {
56
+ // URI related to a local file
57
+ const absoluteLocalFile = path.posix.resolve(logo);
58
+ debug('serve local logo %s', absoluteLocalFile);
59
+ try {
60
+ // TODO: replace existsSync by async alternative
61
+ if (
62
+ fs.existsSync(absoluteLocalFile) &&
63
+ typeof fs.accessSync(absoluteLocalFile, fs.constants.R_OK) === 'undefined'
64
+ ) {
65
+ // Note: `path.join` will break on Windows, because it transforms `/` to `\`
66
+ // Use POSIX version `path.posix.join` instead.
67
+ logo = path.posix.join('/-/static/', path.basename(logo));
68
+ router.get(logo, function (_req, res, next) {
69
+ // @ts-ignore
70
+ debug('serve custom logo web:%s - local:%s', logo, absoluteLocalFile);
71
+ res.sendFile(absoluteLocalFile, sendFileCallback(next));
72
+ });
73
+ debug('enabled custom logo %s', logo);
74
+ } else {
75
+ logo = undefined;
76
+ debug(`web logo is wrong, path ${absoluteLocalFile} does not exist or is not readable`);
77
+ }
78
+ } catch {
79
+ logo = undefined;
67
80
  debug(`web logo is wrong, path ${absoluteLocalFile} does not exist or is not readable`);
68
81
  }
69
- } catch {
70
- config.web.logo = undefined;
71
- debug(`web logo is wrong, path ${absoluteLocalFile} does not exist or is not readable`);
72
82
  }
83
+ return logo;
84
+ }
85
+
86
+ const logo = renderLogo(config?.web?.logo);
87
+ if (config?.web?.logo) {
88
+ config.web.logo = logo;
89
+ }
90
+ const logoDark = renderLogo(config?.web?.logoDark);
91
+ if (config?.web?.logoDark) {
92
+ config.web.logoDark = logoDark;
73
93
  }
74
94
 
75
95
  router.get('/-/web/:section/*', function (req, res) {
@@ -16,8 +16,16 @@ export function getManifestValue(
16
16
  ): string[] {
17
17
  return manifestItems?.map((item) => {
18
18
  debug('resolve item %o', item);
19
- const resolvedItem = `${basePath}${manifest[item]}`;
19
+ const resolvedItem = `${stripTrailingSlash(basePath)}/${stripLeadingSlash(manifest[item])}`;
20
20
  debug('resolved item %o', resolvedItem);
21
21
  return resolvedItem;
22
22
  });
23
23
  }
24
+
25
+ function stripTrailingSlash(path: string): string {
26
+ return path.replace(/\/$/, '');
27
+ }
28
+
29
+ function stripLeadingSlash(path: string): string {
30
+ return path.replace(/^\//, '');
31
+ }
@@ -1,4 +1,5 @@
1
1
  import buildDebug from 'debug';
2
+ import type { Response } from 'express';
2
3
  import LRU from 'lru-cache';
3
4
  import path from 'path';
4
5
  import { URL } from 'url';
@@ -6,10 +7,12 @@ import { URL } from 'url';
6
7
  import { WEB_TITLE } from '@verdaccio/config';
7
8
  import { HEADERS } from '@verdaccio/core';
8
9
  import { ConfigYaml, TemplateUIOptions } from '@verdaccio/types';
9
- import { isURLhasValidProtocol } from '@verdaccio/url';
10
- import { getPublicUrl } from '@verdaccio/url';
10
+ import type { RequestOptions } from '@verdaccio/url';
11
+ import { getPublicUrl, isURLhasValidProtocol } from '@verdaccio/url';
11
12
 
13
+ import type { Manifest } from './manifest';
12
14
  import renderTemplate from './template';
15
+ import type { WebpackManifest } from './template';
13
16
  import { hasLogin, validatePrimaryColor } from './web-utils';
14
17
 
15
18
  const DEFAULT_LANGUAGE = 'es-US';
@@ -17,29 +20,40 @@ const cache = new LRU({ max: 500, ttl: 1000 * 60 * 60 });
17
20
 
18
21
  const debug = buildDebug('verdaccio:web:render');
19
22
 
20
- const defaultManifestFiles = {
23
+ const defaultManifestFiles: Manifest = {
21
24
  js: ['runtime.js', 'vendors.js', 'main.js'],
22
25
  ico: 'favicon.ico',
26
+ css: [],
23
27
  };
24
28
 
25
- export function resolveLogo(config: ConfigYaml, req) {
26
- if (typeof config?.web?.logo !== 'string') {
29
+ export function resolveLogo(
30
+ logo: string | undefined,
31
+ url_prefix: string | undefined,
32
+ requestOptions: RequestOptions
33
+ ) {
34
+ if (typeof logo !== 'string') {
27
35
  return '';
28
36
  }
29
- const isLocalFile = config?.web?.logo && !isURLhasValidProtocol(config?.web?.logo);
37
+ const isLocalFile = logo && !isURLhasValidProtocol(logo);
30
38
 
31
39
  if (isLocalFile) {
32
- return `${getPublicUrl(config?.url_prefix, req)}-/static/${path.basename(config?.web?.logo)}`;
33
- } else if (isURLhasValidProtocol(config?.web?.logo)) {
34
- return config?.web?.logo;
40
+ return `${getPublicUrl(url_prefix, requestOptions)}-/static/${path.basename(logo)}`;
41
+ } else if (isURLhasValidProtocol(logo)) {
42
+ return logo;
35
43
  } else {
36
44
  return '';
37
45
  }
38
46
  }
39
47
 
40
- export default function renderHTML(config: ConfigYaml, manifest, manifestFiles, req, res) {
48
+ export default function renderHTML(
49
+ config: ConfigYaml,
50
+ manifest: WebpackManifest,
51
+ manifestFiles: Manifest | null | undefined,
52
+ requestOptions: RequestOptions,
53
+ res: Response
54
+ ) {
41
55
  const { url_prefix } = config;
42
- const base = getPublicUrl(config?.url_prefix, req);
56
+ const base = getPublicUrl(config?.url_prefix, requestOptions);
43
57
  const basename = new URL(base).pathname;
44
58
  const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;
45
59
  const hideDeprecatedVersions = config?.web?.hideDeprecatedVersions ?? false;
@@ -51,7 +65,9 @@ export default function renderHTML(config: ConfigYaml, manifest, manifestFiles,
51
65
  const title = config?.web?.title ?? WEB_TITLE;
52
66
  const login = hasLogin(config);
53
67
  const scope = config?.web?.scope ?? '';
54
- const logo = resolveLogo(config, req);
68
+ const favicon = resolveLogo(config?.web?.favicon, config?.url_prefix, requestOptions);
69
+ const logo = resolveLogo(config?.web?.logo, config?.url_prefix, requestOptions);
70
+ const logoDark = resolveLogo(config?.web?.logoDark, config?.url_prefix, requestOptions);
55
71
  const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm'];
56
72
  const version = res.locals.app_version ?? '';
57
73
  const flags = {
@@ -71,6 +87,8 @@ export default function renderHTML(config: ConfigYaml, manifest, manifestFiles,
71
87
  showFooter,
72
88
  showSearch,
73
89
  showDownloadTarball,
90
+ showRaw,
91
+ showUplinks,
74
92
  } = Object.assign(
75
93
  {},
76
94
  {
@@ -87,6 +105,8 @@ export default function renderHTML(config: ConfigYaml, manifest, manifestFiles,
87
105
  showFooter,
88
106
  showSearch,
89
107
  showDownloadTarball,
108
+ showRaw,
109
+ showUplinks,
90
110
  darkMode,
91
111
  url_prefix,
92
112
  basename,
@@ -94,6 +114,8 @@ export default function renderHTML(config: ConfigYaml, manifest, manifestFiles,
94
114
  primaryColor,
95
115
  version,
96
116
  logo,
117
+ logoDark,
118
+ favicon,
97
119
  flags,
98
120
  login,
99
121
  pkgManagers,
@@ -25,24 +25,24 @@ export default function renderTemplate(template: Template, manifest: WebpackMani
25
25
 
26
26
  return `
27
27
  <!DOCTYPE html>
28
- <html lang="en-us">
28
+ <html lang="en-us">
29
29
  <head>
30
30
  <meta charset="utf-8">
31
31
  <base href="${template?.options.base}">
32
- <title>${template?.options?.title ?? ''}</title>
32
+ <title>${template?.options?.title ?? ''}</title>
33
33
  <link rel="icon" href="${template?.options.base}-/static/favicon.ico"/>
34
- <meta name="viewport" content="width=device-width, initial-scale=1" />
34
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
35
35
  <script>
36
36
  window.__VERDACCIO_BASENAME_UI_OPTIONS=${JSON.stringify(template.options)}
37
37
  </script>
38
38
  ${template?.metaScripts ? template.metaScripts.join('') : ''}
39
- </head>
39
+ </head>
40
40
  <body class="body">
41
- ${template?.scriptsbodyBefore ? template.scriptsbodyBefore.join('') : ''}
41
+ ${template?.scriptsbodyBefore ? template.scriptsbodyBefore.join('') : ''}
42
42
  <div id="root"></div>
43
43
  ${getManifestValue(template.manifest.js, manifest, template?.options.base)
44
44
  .map((item) => `<script defer="defer" src="${item}"></script>`)
45
- .join('')}
45
+ .join(`\n `)}
46
46
  ${template?.scriptsBodyAfter ? template.scriptsBodyAfter.join('') : ''}
47
47
  </body>
48
48
  </html>
@@ -3,22 +3,23 @@
3
3
  exports[`template custom body after 1`] = `
4
4
  "
5
5
  <!DOCTYPE html>
6
- <html lang="en-us">
6
+ <html lang="en-us">
7
7
  <head>
8
8
  <meta charset="utf-8">
9
- <base href="http://domain.com">
10
- <title></title>
11
- <link rel="icon" href="http://domain.com-/static/favicon.ico"/>
12
- <meta name="viewport" content="width=device-width, initial-scale=1" />
9
+ <base href="http://domain.com/">
10
+ <title></title>
11
+ <link rel="icon" href="http://domain.com/-/static/favicon.ico"/>
12
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
13
13
  <script>
14
- window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com"}
14
+ window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com/"}
15
15
  </script>
16
16
 
17
- </head>
17
+ </head>
18
18
  <body class="body">
19
-
19
+
20
20
  <div id="root"></div>
21
- <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script><script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
21
+ <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script>
22
+ <script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
22
23
  <script src="foo"/>
23
24
  </body>
24
25
  </html>
@@ -28,22 +29,23 @@ exports[`template custom body after 1`] = `
28
29
  exports[`template custom body before 1`] = `
29
30
  "
30
31
  <!DOCTYPE html>
31
- <html lang="en-us">
32
+ <html lang="en-us">
32
33
  <head>
33
34
  <meta charset="utf-8">
34
- <base href="http://domain.com">
35
- <title></title>
36
- <link rel="icon" href="http://domain.com-/static/favicon.ico"/>
37
- <meta name="viewport" content="width=device-width, initial-scale=1" />
35
+ <base href="http://domain.com/">
36
+ <title></title>
37
+ <link rel="icon" href="http://domain.com/-/static/favicon.ico"/>
38
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
38
39
  <script>
39
- window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com"}
40
+ window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com/"}
40
41
  </script>
41
42
 
42
- </head>
43
+ </head>
43
44
  <body class="body">
44
- <script src="fooBefore"/><script src="barBefore"/>
45
+ <script src="fooBefore"/><script src="barBefore"/>
45
46
  <div id="root"></div>
46
- <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script><script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
47
+ <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script>
48
+ <script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
47
49
 
48
50
  </body>
49
51
  </html>
@@ -53,22 +55,23 @@ exports[`template custom body before 1`] = `
53
55
  exports[`template custom render 1`] = `
54
56
  "
55
57
  <!DOCTYPE html>
56
- <html lang="en-us">
58
+ <html lang="en-us">
57
59
  <head>
58
60
  <meta charset="utf-8">
59
- <base href="http://domain.com">
60
- <title></title>
61
- <link rel="icon" href="http://domain.com-/static/favicon.ico"/>
62
- <meta name="viewport" content="width=device-width, initial-scale=1" />
61
+ <base href="http://domain.com/">
62
+ <title></title>
63
+ <link rel="icon" href="http://domain.com/-/static/favicon.ico"/>
64
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
63
65
  <script>
64
- window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com"}
66
+ window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com/"}
65
67
  </script>
66
68
 
67
- </head>
69
+ </head>
68
70
  <body class="body">
69
-
71
+
70
72
  <div id="root"></div>
71
- <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script><script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
73
+ <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script>
74
+ <script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
72
75
 
73
76
  </body>
74
77
  </html>
@@ -78,47 +81,23 @@ exports[`template custom render 1`] = `
78
81
  exports[`template custom title 1`] = `
79
82
  "
80
83
  <!DOCTYPE html>
81
- <html lang="en-us">
84
+ <html lang="en-us">
82
85
  <head>
83
86
  <meta charset="utf-8">
84
- <base href="http://domain.com">
85
- <title>foo title</title>
86
- <link rel="icon" href="http://domain.com-/static/favicon.ico"/>
87
- <meta name="viewport" content="width=device-width, initial-scale=1" />
87
+ <base href="http://domain.com/">
88
+ <title>foo title</title>
89
+ <link rel="icon" href="http://domain.com/-/static/favicon.ico"/>
90
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
88
91
  <script>
89
- window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com","title":"foo title"}
92
+ window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com/","title":"foo title"}
90
93
  </script>
91
94
 
92
- </head>
95
+ </head>
93
96
  <body class="body">
94
-
95
- <div id="root"></div>
96
- <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script><script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
97
97
 
98
- </body>
99
- </html>
100
- "
101
- `;
102
-
103
- exports[`template custom title 2`] = `
104
- "
105
- <!DOCTYPE html>
106
- <html lang="en-us">
107
- <head>
108
- <meta charset="utf-8">
109
- <base href="http://domain.com">
110
- <title>foo title</title>
111
- <link rel="icon" href="http://domain.com-/static/favicon.ico"/>
112
- <meta name="viewport" content="width=device-width, initial-scale=1" />
113
- <script>
114
- window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com","title":"foo title"}
115
- </script>
116
-
117
- </head>
118
- <body class="body">
119
-
120
98
  <div id="root"></div>
121
- <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script><script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
99
+ <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script>
100
+ <script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
122
101
 
123
102
  </body>
124
103
  </html>
@@ -128,22 +107,23 @@ exports[`template custom title 2`] = `
128
107
  exports[`template meta scripts 1`] = `
129
108
  "
130
109
  <!DOCTYPE html>
131
- <html lang="en-us">
110
+ <html lang="en-us">
132
111
  <head>
133
112
  <meta charset="utf-8">
134
- <base href="http://domain.com">
135
- <title></title>
136
- <link rel="icon" href="http://domain.com-/static/favicon.ico"/>
137
- <meta name="viewport" content="width=device-width, initial-scale=1" />
113
+ <base href="http://domain.com/">
114
+ <title></title>
115
+ <link rel="icon" href="http://domain.com/-/static/favicon.ico"/>
116
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
138
117
  <script>
139
- window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com"}
118
+ window.__VERDACCIO_BASENAME_UI_OPTIONS={"base":"http://domain.com/"}
140
119
  </script>
141
120
  <style>.someclass{font-size:10px;}</style>
142
- </head>
121
+ </head>
143
122
  <body class="body">
144
-
123
+
145
124
  <div id="root"></div>
146
- <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script><script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
125
+ <script defer="defer" src="http://domain.com/-/static/runtime.6126058572f989c948b1.js"></script>
126
+ <script defer="defer" src="http://domain.com/-/static/main.6126058572f989c948b1.js"></script>
147
127
 
148
128
  </body>
149
129
  </html>
Binary file
@@ -14,6 +14,8 @@ web:
14
14
  showRaw: true
15
15
  primary_color: '#ffffff'
16
16
  logo: './test/config/dark-logo.png'
17
+ logoDark: './test/config/dark-logo.png'
18
+ favicon: './test/config/favicon.ico'
17
19
  html_cache: false
18
20
 
19
21
  url_prefix: /prefix
@@ -0,0 +1,26 @@
1
+ web:
2
+ title: verdaccio web
3
+ login: true
4
+ scope: '@scope'
5
+ pkgManagers:
6
+ - pnpm
7
+ - yarn
8
+ showInfo: true
9
+ showSettings: true
10
+ showSearch: true
11
+ showFooter: true
12
+ showThemeSwitch: true
13
+ showDownloadTarball: true
14
+ showRaw: true
15
+ primary_color: '#ffffff'
16
+ logo: https://raw.githubusercontent.com/verdaccio/verdaccio/master/assets/svg/logo-small.svg
17
+ logoDark: https://raw.githubusercontent.com/verdaccio/verdaccio/master/assets/svg/logo-blackwhite.svg
18
+ favicon: https://raw.githubusercontent.com/verdaccio/verdaccio/master/website/static/img/favicon/favicon.ico
19
+ html_cache: false
20
+
21
+ url_prefix: /prefix
22
+
23
+ log: { type: stdout, format: pretty, level: trace }
24
+
25
+ flags:
26
+ changePassword: true
@@ -14,6 +14,7 @@ web:
14
14
  showRaw: true
15
15
  primary_color: '#ffffff'
16
16
  logo:
17
+ favicon:
17
18
  html_cache: false
18
19
 
19
20
  url_prefix: /prefix
@@ -8,4 +8,16 @@ describe('manifest', () => {
8
8
  '/-/static/main.6126058572f989c948b1.js',
9
9
  ]);
10
10
  });
11
+
12
+ test('getManifestValue with base', () => {
13
+ expect(getManifestValue(['favicon.ico'], manifest, 'http://domain.com')).toEqual([
14
+ 'http://domain.com/-/static/favicon.ico',
15
+ ]);
16
+ });
17
+
18
+ test('getManifestValue with base with trailing slash', () => {
19
+ expect(getManifestValue(['favicon.ico'], manifest, 'http://domain.com/')).toEqual([
20
+ 'http://domain.com/-/static/favicon.ico',
21
+ ]);
22
+ });
11
23
  });
@@ -79,6 +79,28 @@ describe('test web server', () => {
79
79
  return loadLogo('file-logo.yaml', '/-/static/dark-logo.png');
80
80
  });
81
81
 
82
+ test('should render dark logo as file', async () => {
83
+ const {
84
+ window: { __VERDACCIO_BASENAME_UI_OPTIONS },
85
+ } = await render('file-logo.yaml');
86
+ expect(__VERDACCIO_BASENAME_UI_OPTIONS.logoDark).toMatch('/prefix/-/static/dark-logo.png');
87
+ });
88
+
89
+ test('should render favicon as file', async () => {
90
+ const {
91
+ window: { __VERDACCIO_BASENAME_UI_OPTIONS },
92
+ } = await render('file-logo.yaml');
93
+ expect(__VERDACCIO_BASENAME_UI_OPTIONS.favicon).toMatch('/prefix/-/static/favicon.ico');
94
+ });
95
+
96
+ test('should render logo and favicon as URL', async () => {
97
+ const {
98
+ window: { __VERDACCIO_BASENAME_UI_OPTIONS },
99
+ } = await render('http-logo.yaml');
100
+ expect(__VERDACCIO_BASENAME_UI_OPTIONS.logo).toMatch(/https:.*logo-small.svg/i);
101
+ expect(__VERDACCIO_BASENAME_UI_OPTIONS.favicon).toMatch(/https:.*favicon.ico/i);
102
+ });
103
+
82
104
  test('should not render logo as absolute file is wrong', async () => {
83
105
  const {
84
106
  window: { __VERDACCIO_BASENAME_UI_OPTIONS },
@@ -91,6 +113,7 @@ describe('test web server', () => {
91
113
  window: { __VERDACCIO_BASENAME_UI_OPTIONS },
92
114
  } = await render('no-logo.yaml');
93
115
  expect(__VERDACCIO_BASENAME_UI_OPTIONS.logo).toEqual('');
116
+ expect(__VERDACCIO_BASENAME_UI_OPTIONS.favicon).toEqual('');
94
117
  });
95
118
 
96
119
  test.todo('should default title');