Compare commits
21 Commits
@verdaccio
...
@verdaccio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ef60915e6 | ||
|
|
55ee3fdd97 | ||
|
|
4ebf18816a | ||
|
|
276a0a63a7 | ||
|
|
f3f00052d8 | ||
|
|
d2c65da9c7 | ||
|
|
2924ffa235 | ||
|
|
6b1a28deb8 | ||
|
|
a54c18c02a | ||
|
|
52b47868e3 | ||
|
|
8582548559 | ||
|
|
32f66cc2c7 | ||
|
|
6a01bdbcc9 | ||
|
|
5ddfa5264c | ||
|
|
1cc00cf2ab | ||
|
|
086c4a7c3c | ||
|
|
babe5c3f6c | ||
|
|
0da7031e77 | ||
|
|
393125baa1 | ||
|
|
7fb5c45243 | ||
|
|
aecbd226de |
15
.changeset/afraid-mice-obey.md
Normal file
15
.changeset/afraid-mice-obey.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
'@verdaccio/types': minor
|
||||
'@verdaccio/ui-theme': minor
|
||||
'@verdaccio/web': minor
|
||||
---
|
||||
|
||||
allow disable login on ui and endpoints
|
||||
|
||||
To be able disable the login, set `login: false`, anything else would enable login. This flag will disable access via UI and web endpoints.
|
||||
|
||||
```yml
|
||||
web:
|
||||
title: verdaccio
|
||||
login: false
|
||||
```
|
||||
5
.changeset/calm-pants-impress.md
Normal file
5
.changeset/calm-pants-impress.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'verdaccio-aws-s3-storage': patch
|
||||
---
|
||||
|
||||
Fix the prefix used to delete from s3 when unpublishing packages
|
||||
5
.changeset/gold-vans-tease.md
Normal file
5
.changeset/gold-vans-tease.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@verdaccio/utils': patch
|
||||
---
|
||||
|
||||
Fixed the validation of the name when searching for a tarball that have scoped package name
|
||||
6
.changeset/heavy-ravens-lay.md
Normal file
6
.changeset/heavy-ravens-lay.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@verdaccio/cli': minor
|
||||
'@verdaccio/fastify-migration': minor
|
||||
---
|
||||
|
||||
[Fastify] Add ping endpoint
|
||||
@@ -33,23 +33,27 @@
|
||||
"verdaccio-aws-s3-storage": "11.0.0-alpha.0",
|
||||
"verdaccio-google-cloud": "11.0.0-alpha.0",
|
||||
"verdaccio-memory": "11.0.0-alpha.0",
|
||||
"@verdaccio/website": "0.0.1",
|
||||
"@verdaccio/ui-theme": "6.0.0-alpha.1",
|
||||
"@verdaccio/e2e-cli": "1.0.0",
|
||||
"@verdaccio/e2e-ui": "1.0.0",
|
||||
"@verdaccio/cli-standalone": "6.0.0-alpha.3",
|
||||
"@verdaccio/tarball": "11.0.0-alpha.3",
|
||||
"@verdaccio/url": "11.0.0-alpha.3",
|
||||
"@verdaccio/fastify-migration": "6.0.0-6-next.9"
|
||||
"@verdaccio/fastify-migration": "6.0.0-6-next.9",
|
||||
"@verdaccio/eslint-config": "1.0.0"
|
||||
},
|
||||
"changesets": [
|
||||
"afraid-mice-obey",
|
||||
"big-lobsters-sin",
|
||||
"calm-pants-impress",
|
||||
"few-cooks-destroy",
|
||||
"fifty-jars-rest",
|
||||
"gentle-parrots-lay",
|
||||
"gentle-trains-switch",
|
||||
"gold-vans-tease",
|
||||
"healthy-bikes-behave",
|
||||
"healthy-poets-compare",
|
||||
"heavy-ravens-lay",
|
||||
"hip-hounds-destroy",
|
||||
"late-adults-love",
|
||||
"late-parents-act",
|
||||
@@ -61,11 +65,13 @@
|
||||
"plenty-spiders-melt",
|
||||
"plenty-tables-refuse",
|
||||
"pretty-hounds-tap",
|
||||
"red-chefs-float",
|
||||
"shiny-chefs-heal",
|
||||
"smart-apricots-kneel",
|
||||
"spicy-frogs-press",
|
||||
"tender-bags-call",
|
||||
"three-pots-sit",
|
||||
"two-dolls-check"
|
||||
"two-dolls-check",
|
||||
"wild-jokes-beam"
|
||||
]
|
||||
}
|
||||
|
||||
11
.changeset/red-chefs-float.md
Normal file
11
.changeset/red-chefs-float.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
'@verdaccio/store': patch
|
||||
'@verdaccio/web': patch
|
||||
---
|
||||
|
||||
Fix the search by exact name of the package
|
||||
|
||||
Full package name queries was not finding anithing. It was happening
|
||||
becouse of stemmer of [lunr.js](https://lunrjs.com/).
|
||||
|
||||
To fix this, the stemmer of [lunr.js](https://lunrjs.com/) was removed from search pipeline.
|
||||
32
.changeset/wild-jokes-beam.md
Normal file
32
.changeset/wild-jokes-beam.md
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
'@verdaccio/types': minor
|
||||
'@verdaccio/ui-theme': minor
|
||||
'@verdaccio/web': minor
|
||||
---
|
||||
|
||||
web: allow ui hide package managers on sidebar
|
||||
|
||||
If there is a package manager of preference over others, you can define the package managers to be displayed on the detail page and sidebar, just define in the `config.yaml` and web section the list of package managers to be displayed.
|
||||
|
||||
```
|
||||
web:
|
||||
title: Verdaccio
|
||||
sort_packages: asc
|
||||
primary_color: #cccccc
|
||||
pkgManagers:
|
||||
- pnpm
|
||||
- yarn
|
||||
# - npm
|
||||
```
|
||||
|
||||
To disable all package managers, just define empty:
|
||||
|
||||
```
|
||||
web:
|
||||
title: Verdaccio
|
||||
sort_packages: asc
|
||||
primary_color: #cccccc
|
||||
pkgManagers:
|
||||
```
|
||||
|
||||
and the section would be hidden.
|
||||
102
.eslintrc
102
.eslintrc
@@ -1,102 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"google",
|
||||
"plugin:react/recommended",
|
||||
"plugin:jest/recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:import/typescript",
|
||||
"plugin:jsx-a11y/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"plugins": ["import", "jest", "jsx-a11y", "react-hooks"],
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true,
|
||||
"jest": true
|
||||
},
|
||||
"globals": {
|
||||
"__APP_VERSION__": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"allowImportExportEverywhere": true,
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 11,
|
||||
"ecmaFeatures": {
|
||||
"impliedStrict": true,
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"node": {
|
||||
"extensions": [".js", ".jsx", ".ts", ".tsx"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"rules": {
|
||||
"curly": ["error", "all"],
|
||||
"react/prop-types": 0,
|
||||
"jest/no-export": 0,
|
||||
"jest/no-test-callback": 0,
|
||||
"jest/expect-expect": 0,
|
||||
"jest/no-try-expect": 0,
|
||||
"jest/no-done-callback": "off",
|
||||
"jest/no-conditional-expect": "off",
|
||||
"keyword-spacing": "off",
|
||||
"no-tabs": "off",
|
||||
"no-useless-escape": "off",
|
||||
"padded-blocks": "off",
|
||||
"require-jsdoc": "off",
|
||||
"valid-jsdoc": "off",
|
||||
"import/order": ["error"],
|
||||
"eol-last": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
||||
"no-trailing-spaces": "error",
|
||||
"camelcase": "off",
|
||||
"guard-for-in": "error",
|
||||
"new-cap": "error",
|
||||
"max-len": ["error", 100],
|
||||
"no-console": ["error", { "allow": ["warn"] }],
|
||||
"no-constant-condition": "error",
|
||||
"no-debugger": "error",
|
||||
"no-empty": "error",
|
||||
"no-fallthrough": "error",
|
||||
"no-invalid-this": "error",
|
||||
"no-new-require": "error",
|
||||
"no-undef": "error",
|
||||
"no-unreachable": "error",
|
||||
"no-var": "error",
|
||||
"one-var": "error",
|
||||
"prefer-rest-params": "error",
|
||||
"prefer-spread": "error",
|
||||
"handle-callback-err": 0,
|
||||
"prefer-const": 0,
|
||||
"@typescript-eslint/camelcase": 0,
|
||||
"@typescript-eslint/ban-ts-ignore": 0,
|
||||
"@typescript-eslint/no-var-requires": 0,
|
||||
"@typescript-eslint/no-inferrable-types": 0,
|
||||
"@typescript-eslint/no-empty-function": 0,
|
||||
"@typescript-eslint/no-this-alias": 0,
|
||||
"@typescript-eslint/no-use-before-define": 0,
|
||||
"@typescript-eslint/array-type": ["error"],
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"@typescript-eslint/indent": 0,
|
||||
"@typescript-eslint/ban-ts-comment": 0,
|
||||
"@typescript-eslint/ban-types": 0,
|
||||
"@typescript-eslint/explicit-module-boundary-types": 0,
|
||||
|
||||
// rules to fix
|
||||
"no-unused-vars": ["warn", { "vars": "all", "args": "none" }],
|
||||
"jest/no-identical-title": ["warn"],
|
||||
"prefer-promise-reject-errors": ["warn"],
|
||||
"jest/no-disabled-tests": ["warn"],
|
||||
"jest/no-commented-out-tests": ["warn"],
|
||||
"@typescript-eslint/prefer-optional-chain": ["warn"],
|
||||
"@typescript-eslint/explicit-member-accessibility": ["warn"],
|
||||
"@typescript-eslint/no-unused-vars": ["warn"]
|
||||
}
|
||||
}
|
||||
3
.eslintrc.js
Normal file
3
.eslintrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: ['@verdaccio/eslint-config'],
|
||||
};
|
||||
23
.github/workflows/ci.yml
vendored
23
.github/workflows/ci.yml
vendored
@@ -100,8 +100,6 @@ jobs:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
- name: Install
|
||||
## we run scripts due gatsby needs it
|
||||
## when website is excluded we can add --ignore-scripts
|
||||
run: pnpm recursive install --frozen-lockfile --ignore-scripts
|
||||
- name: build
|
||||
run: pnpm build
|
||||
@@ -194,27 +192,6 @@ jobs:
|
||||
run: pnpm recursive install --frozen-lockfile
|
||||
- name: Test CLI
|
||||
run: pnpm test:e2e:cli
|
||||
website:
|
||||
needs: [format, lint]
|
||||
runs-on: ubuntu-latest
|
||||
name: website build node 14
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.1
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@latest -g
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
- name: Install
|
||||
run: pnpm recursive install --frozen-lockfile
|
||||
- name: Build website
|
||||
run: |
|
||||
cd website
|
||||
pnpm build:website
|
||||
test-windows:
|
||||
needs: [format, lint]
|
||||
runs-on: windows-latest
|
||||
|
||||
@@ -32,7 +32,7 @@ Google Cloud Storage** or create your own plugin.
|
||||
Install with npm:
|
||||
|
||||
```bash
|
||||
npm install --global verdaccio@6-next --https://registry.verdaccio.org/
|
||||
npm install --global verdaccio@6-next --registry https://registry.verdaccio.org/
|
||||
```
|
||||
|
||||
> Published on a temporary registry while setup is ready to publish on npmjs
|
||||
|
||||
@@ -10,7 +10,7 @@ let _localMemory = require('./local-memory');
|
||||
let _localMemory2 = _interopRequireDefault(_localMemory);
|
||||
|
||||
function _interopRequireDefault(obj) {
|
||||
return obj && obj.__esModule ? obj : { default: obj };
|
||||
return obj && obj.__esModule ? obj : {default: obj};
|
||||
}
|
||||
|
||||
exports.LocalMemory = _localMemory2.default;
|
||||
|
||||
@@ -9,7 +9,7 @@ let _memoryHandler = require('./memory-handler');
|
||||
let _memoryHandler2 = _interopRequireDefault(_memoryHandler);
|
||||
|
||||
function _interopRequireDefault(obj) {
|
||||
return obj && obj.__esModule ? obj : { default: obj };
|
||||
return obj && obj.__esModule ? obj : {default: obj};
|
||||
}
|
||||
|
||||
const DEFAULT_LIMIT = 1000;
|
||||
@@ -43,8 +43,8 @@ class LocalMemory {
|
||||
cb(null);
|
||||
} else {
|
||||
this.logger.info(
|
||||
{ limit: this.limit },
|
||||
'Storage memory has reached limit of @{limit} packages'
|
||||
{limit: this.limit},
|
||||
'Storage memory has reached limit of @{limit} packages',
|
||||
);
|
||||
cb(new Error('Storage memory has reached limit of limit packages'));
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ let _memoryFs2 = _interopRequireDefault(_memoryFs);
|
||||
let _streams = require('@verdaccio/streams');
|
||||
|
||||
function _interopRequireDefault(obj) {
|
||||
return obj && obj.__esModule ? obj : { default: obj };
|
||||
return obj && obj.__esModule ? obj : {default: obj};
|
||||
}
|
||||
|
||||
// $FlowFixMe
|
||||
@@ -111,8 +111,8 @@ class MemoryHandler {
|
||||
const uploadStream = new _streams.UploadTarball();
|
||||
const temporalName = `/${name}`;
|
||||
|
||||
process.nextTick(function () {
|
||||
fs.exists(temporalName, function (exists) {
|
||||
process.nextTick(function() {
|
||||
fs.exists(temporalName, function(exists) {
|
||||
if (exists) {
|
||||
return uploadStream.emit('error', fSError(fileExist));
|
||||
}
|
||||
@@ -122,7 +122,7 @@ class MemoryHandler {
|
||||
|
||||
uploadStream.pipe(file);
|
||||
|
||||
uploadStream.done = function () {
|
||||
uploadStream.done = function() {
|
||||
const onEnd = function onEnd() {
|
||||
uploadStream.emit('success');
|
||||
};
|
||||
@@ -130,7 +130,7 @@ class MemoryHandler {
|
||||
uploadStream.on('end', onEnd);
|
||||
};
|
||||
|
||||
uploadStream.abort = function () {
|
||||
uploadStream.abort = function() {
|
||||
uploadStream.emit('error', fSError('transmision aborted', 400));
|
||||
file.end();
|
||||
};
|
||||
@@ -150,8 +150,8 @@ class MemoryHandler {
|
||||
|
||||
const readTarballStream = new _streams.ReadTarball();
|
||||
|
||||
process.nextTick(function () {
|
||||
fs.exists(pathName, function (exists) {
|
||||
process.nextTick(function() {
|
||||
fs.exists(pathName, function(exists) {
|
||||
if (!exists) {
|
||||
readTarballStream.emit('error', noPackageFoundError());
|
||||
} else {
|
||||
@@ -164,7 +164,7 @@ class MemoryHandler {
|
||||
readTarballStream.emit('error', error);
|
||||
});
|
||||
|
||||
readTarballStream.abort = function () {
|
||||
readTarballStream.abort = function() {
|
||||
readStream.destroy(fSError('read has been aborted', 400));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
> Before run examples, build the local image by running `pnpm docker`.
|
||||
|
||||
- [Docker + Nginx + Verdaccio](v5/reverse_proxy/nginx/README.md)
|
||||
- [Docker + Nginx + Verdaccio](reverse_proxy/nginx/README.md)
|
||||
|
||||
27
package.json
27
package.json
@@ -39,7 +39,7 @@
|
||||
"@babel/register": "7.13.14",
|
||||
"@babel/runtime": "7.13.10",
|
||||
"@changesets/changelog-github": "^0.2.8",
|
||||
"@changesets/cli": "^2.15.0",
|
||||
"@changesets/cli": "2.15.0",
|
||||
"@changesets/get-dependents-graph": "^1.2.0",
|
||||
"@commitlint/cli": "8.3.5",
|
||||
"@commitlint/config-conventional": "8.2.0",
|
||||
@@ -71,6 +71,7 @@
|
||||
"@typescript-eslint/parser": "4.13.0",
|
||||
"@verdaccio/types": "workspace:*",
|
||||
"@verdaccio/ui-theme": "workspace:*",
|
||||
"@verdaccio/eslint-config": "workspace:*",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-jest": "26.6.3",
|
||||
@@ -78,20 +79,21 @@
|
||||
"babel-plugin-emotion": "11.0.0",
|
||||
"codecov": "3.8.1",
|
||||
"concurrently": "^5.3.0",
|
||||
"core-js": "^3.10.1",
|
||||
"core-js": "^3.12.1",
|
||||
"cross-env": "7.0.3",
|
||||
"detect-secrets": "1.0.6",
|
||||
"eslint": "7.19.0",
|
||||
"eslint": "7.26.0",
|
||||
"eslint-config-google": "0.14.0",
|
||||
"eslint-config-prettier": "7.2.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-babel": "5.3.1",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eslint-plugin-jest": "24.1.3",
|
||||
"eslint-plugin-import": "2.23.2",
|
||||
"eslint-plugin-jest": "24.3.6",
|
||||
"eslint-plugin-jsx-a11y": "6.4.1",
|
||||
"eslint-plugin-react": "7.22.0",
|
||||
"eslint-plugin-react": "7.23.2",
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"eslint-plugin-simple-import-sort": "7.0.0",
|
||||
"eslint-plugin-verdaccio": "9.6.1",
|
||||
"eslint-plugin-verdaccio": "10.0.0",
|
||||
"eslint-plugin-prettier": "3.4.0",
|
||||
"fs-extra": "9.1.0",
|
||||
"get-stdin": "7.0.0",
|
||||
"husky": "2.7.0",
|
||||
@@ -107,14 +109,14 @@
|
||||
"nock": "12.0.3",
|
||||
"nodemon": "^2.0.7",
|
||||
"npm-run-all": "4.1.5",
|
||||
"prettier": "2.2.1",
|
||||
"prettier": "2.3.0",
|
||||
"rimraf": "3.0.2",
|
||||
"selfsigned": "1.10.8",
|
||||
"supertest": "4.0.2",
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.2.4",
|
||||
"update-ts-references": "2.3.0",
|
||||
"verdaccio": "^5.0.1",
|
||||
"verdaccio": "^5.0.4",
|
||||
"verdaccio-audit": "workspace:*",
|
||||
"verdaccio-auth-memory": "workspace:*",
|
||||
"verdaccio-htpasswd": "workspace:*",
|
||||
@@ -126,7 +128,7 @@
|
||||
"docker": "docker build -t verdaccio/verdaccio:local . --no-cache",
|
||||
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,yml,yaml,md}\"",
|
||||
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,yml,yaml,md}\"",
|
||||
"lint": "eslint \"**/*.{js,jsx,ts,tsx}\"",
|
||||
"lint": "eslint --max-warnings 165 \"**/*.{js,jsx,ts,tsx}\"",
|
||||
"test": "pnpm recursive test --filter ./packages",
|
||||
"test:e2e:cli": "pnpm test --filter ...@verdaccio/e2e-cli",
|
||||
"test:e2e:ui": "pnpm test --filter ...@verdaccio/e2e-ui",
|
||||
@@ -139,9 +141,6 @@
|
||||
"start:ts": "ts-node packages/verdaccio/src/start.ts -- --listen 8000",
|
||||
"debug": "node --inspect packages/verdaccio/debug/bootstrap.js",
|
||||
"debug:break": "node --inspect-brk packages/verdaccio/debug/bootstrap.js",
|
||||
"website:lint": "cd website && yarn lint",
|
||||
"website:develop": "cd website && yarn develop",
|
||||
"website:build": "cd website && yarn build",
|
||||
"changeset": "changeset",
|
||||
"changeset:check": "changeset status --since-master",
|
||||
"ci:version": "run-s ci:version:changeset ci:version:install",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @verdaccio/api
|
||||
|
||||
## 6.0.0-6-next.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d2c65da9]
|
||||
- @verdaccio/utils@6.0.0-6-next.5
|
||||
- @verdaccio/auth@6.0.0-6-next.9
|
||||
- @verdaccio/config@6.0.0-6-next.7
|
||||
- @verdaccio/tarball@11.0.0-6-next.6
|
||||
- @verdaccio/middleware@6.0.0-6-next.9
|
||||
- @verdaccio/store@6.0.0-6-next.10
|
||||
- @verdaccio/hooks@6.0.0-6-next.4
|
||||
|
||||
## 6.0.0-6-next.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5ddfa526]
|
||||
- @verdaccio/store@6.0.0-6-next.9
|
||||
|
||||
## 6.0.0-6-next.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/api",
|
||||
"version": "6.0.0-6-next.10",
|
||||
"version": "6.0.0-6-next.12",
|
||||
"description": "loaders logic",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -39,15 +39,15 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.8",
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.9",
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/hooks": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/middleware": "workspace:6.0.0-6-next.8",
|
||||
"@verdaccio/store": "workspace:6.0.0-6-next.8",
|
||||
"@verdaccio/tarball": "workspace:11.0.0-6-next.5",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/middleware": "workspace:6.0.0-6-next.9",
|
||||
"@verdaccio/store": "workspace:6.0.0-6-next.10",
|
||||
"@verdaccio/tarball": "workspace:11.0.0-6-next.6",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.5",
|
||||
"cookies": "0.8.0",
|
||||
"debug": "^4.1.1",
|
||||
"express": "4.17.1",
|
||||
@@ -56,8 +56,8 @@
|
||||
"semver": "7.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.12",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5",
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.16",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"body-parser": "1.19.0",
|
||||
"lodash": "^4.17.20",
|
||||
"supertest": "next"
|
||||
|
||||
@@ -41,7 +41,7 @@ export default function (route, auth, storage): void {
|
||||
route.get('/-/v1/search', (req, res) => {
|
||||
// TODO: implement proper result scoring weighted by quality, popularity and
|
||||
// maintenance query parameters
|
||||
let [text, size, from /* , quality, popularity, maintenance */] = [
|
||||
let [text, size, from] = [
|
||||
'text',
|
||||
'size',
|
||||
'from' /* , 'quality', 'popularity', 'maintenance' */,
|
||||
|
||||
@@ -5,10 +5,11 @@ import { $ResponseExtend, $RequestExtend } from '../../types/custom';
|
||||
import { initializeServer, publishTaggedVersion, publishVersion } from './_helper';
|
||||
|
||||
const mockApiJWTmiddleware = jest.fn(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'foo', groups: [], real_groups: [] };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'foo', groups: [], real_groups: [] };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
|
||||
jest.mock('@verdaccio/auth', () => ({
|
||||
|
||||
@@ -11,10 +11,11 @@ import { $ResponseExtend, $RequestExtend } from '../../types/custom';
|
||||
import { initializeServer, publishVersion } from './_helper';
|
||||
|
||||
const mockApiJWTmiddleware = jest.fn(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'foo', groups: [], real_groups: [] };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'foo', groups: [], real_groups: [] };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
|
||||
jest.setTimeout(50000000);
|
||||
|
||||
@@ -16,10 +16,11 @@ import { $RequestExtend, $ResponseExtend } from '../../types/custom';
|
||||
import { initializeServer } from './_helper';
|
||||
|
||||
const mockApiJWTmiddleware = jest.fn(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'test', groups: [], real_groups: [] };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'test', groups: [], real_groups: [] };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
|
||||
const mockAuthenticate = jest.fn(() => (_name, _password, callback): void => {
|
||||
@@ -53,10 +54,11 @@ describe('user', () => {
|
||||
|
||||
test('should test add a new user', async (done) => {
|
||||
mockApiJWTmiddleware.mockImplementationOnce(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: undefined };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: undefined };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
|
||||
mockAddUser.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||
@@ -85,10 +87,11 @@ describe('user', () => {
|
||||
|
||||
test('should test fails on add a existing user with login', async (done) => {
|
||||
mockApiJWTmiddleware.mockImplementationOnce(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: undefined };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: undefined };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
supertest(await initializeServer('user.yaml'))
|
||||
.put('/-/user/org.couchdb.user:jotaNew')
|
||||
@@ -124,10 +127,11 @@ describe('user', () => {
|
||||
|
||||
test('should test fails add a new user with missing name', async (done) => {
|
||||
mockApiJWTmiddleware.mockImplementationOnce(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: undefined };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: undefined };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
mockAddUser.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||
return callback(getBadRequest(API_ERROR.USERNAME_PASSWORD_REQUIRED));
|
||||
@@ -153,10 +157,11 @@ describe('user', () => {
|
||||
|
||||
test('should test fails add a new user with missing password', async (done) => {
|
||||
mockApiJWTmiddleware.mockImplementationOnce(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: undefined };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: undefined };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
const credentialsShort = _.cloneDeep(credentials);
|
||||
delete credentialsShort.password;
|
||||
@@ -181,10 +186,11 @@ describe('user', () => {
|
||||
|
||||
test('should test fails add a new user with wrong password', async (done) => {
|
||||
mockApiJWTmiddleware.mockImplementationOnce(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'test' };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'test' };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
mockAuthenticate.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||
return callback(getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
@@ -210,10 +216,11 @@ describe('user', () => {
|
||||
|
||||
test('should be able to logout an user', async (done) => {
|
||||
mockApiJWTmiddleware.mockImplementationOnce(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'test' };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'test' };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
mockAuthenticate.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||
return callback(getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
|
||||
@@ -6,10 +6,11 @@ import { $RequestExtend, $ResponseExtend } from '../../types/custom';
|
||||
import { initializeServer } from './_helper';
|
||||
|
||||
const mockApiJWTmiddleware = jest.fn(
|
||||
() => (req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'foo', groups: [], real_groups: [] };
|
||||
_next();
|
||||
}
|
||||
() =>
|
||||
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||
req.remote_user = { name: 'foo', groups: [], real_groups: [] };
|
||||
_next();
|
||||
}
|
||||
);
|
||||
|
||||
jest.mock('@verdaccio/auth', () => ({
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @verdaccio/auth
|
||||
|
||||
## 6.0.0-6-next.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d2c65da9]
|
||||
- @verdaccio/utils@6.0.0-6-next.5
|
||||
- @verdaccio/config@6.0.0-6-next.7
|
||||
- @verdaccio/loaders@6.0.0-6-next.4
|
||||
|
||||
## 6.0.0-6-next.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/auth",
|
||||
"version": "6.0.0-6-next.8",
|
||||
"version": "6.0.0-6-next.9",
|
||||
"description": "logger",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -40,10 +40,10 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/loaders": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.5",
|
||||
"verdaccio-htpasswd": "workspace:11.0.0-alpha.6",
|
||||
"debug": "^4.1.1",
|
||||
"express": "4.17.1",
|
||||
@@ -51,8 +51,8 @@
|
||||
"lodash": "4.17.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
# @verdaccio/cli
|
||||
|
||||
## 6.0.0-6-next.17
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 55ee3fdd: [Fastify] Add ping endpoint
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [55ee3fdd]
|
||||
- @verdaccio/fastify-migration@6.0.0-6-next.10
|
||||
- @verdaccio/config@6.0.0-6-next.7
|
||||
- @verdaccio/node-api@6.0.0-6-next.17
|
||||
|
||||
## 6.0.0-6-next.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/node-api@6.0.0-6-next.16
|
||||
|
||||
## 6.0.0-6-next.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/fastify-migration@6.0.0-6-next.9
|
||||
- @verdaccio/logger@6.0.0-6-next.4
|
||||
- @verdaccio/node-api@6.0.0-6-next.15
|
||||
|
||||
## 6.0.0-6-next.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/fastify-migration@6.0.0-6-next.9
|
||||
- @verdaccio/logger@6.0.0-6-next.4
|
||||
- @verdaccio/node-api@6.0.0-6-next.14
|
||||
|
||||
## 6.0.0-6-next.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/cli",
|
||||
"version": "6.0.0-6-next.13",
|
||||
"version": "6.0.0-6-next.17",
|
||||
"author": {
|
||||
"name": "Juan Picado",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
@@ -40,19 +40,23 @@
|
||||
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
|
||||
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
|
||||
"watch": "pnpm build:js --F --watch",
|
||||
"build": "pnpm run build:js && pnpm run build:types"
|
||||
"build": "pnpm run build:js && pnpm run build:types",
|
||||
"start": "ts-node src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/node-api": "workspace:6.0.0-6-next.13",
|
||||
"@verdaccio/fastify-migration": "workspace:6.0.0-6-next.9",
|
||||
"@verdaccio/node-api": "workspace:6.0.0-6-next.17",
|
||||
"@verdaccio/fastify-migration": "workspace:6.0.0-6-next.10",
|
||||
"commander": "6.2.0",
|
||||
"clipanion": "3.0.0-rc.11",
|
||||
"envinfo": "7.4.0",
|
||||
"kleur": "3.0.3",
|
||||
"semver": "7.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ts-node": "9.1.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/verdaccio"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Command, Option } from 'clipanion';
|
||||
import { findConfigFile, parseConfigFile } from '@verdaccio/config';
|
||||
import { setup, logger } from '@verdaccio/logger';
|
||||
import server from '@verdaccio/fastify-migration';
|
||||
import { ConfigRuntime } from '@verdaccio/types';
|
||||
|
||||
export const DEFAULT_PROCESS_NAME: string = 'verdaccio';
|
||||
|
||||
@@ -19,17 +21,29 @@ export class NewServer extends Command {
|
||||
description: 'use this configuration file (default: ./config.yaml)',
|
||||
});
|
||||
|
||||
private initLogger(logConfig: ConfigRuntime) {
|
||||
try {
|
||||
if (logConfig.logs) {
|
||||
process.emitWarning('config.logs is deprecated, rename configuration to "config.log"');
|
||||
}
|
||||
// FUTURE: remove fallback when is ready
|
||||
setup(logConfig.log || logConfig.logs);
|
||||
} catch {
|
||||
throw new Error('error on init logger');
|
||||
}
|
||||
}
|
||||
|
||||
public async execute() {
|
||||
try {
|
||||
const configPathLocation = findConfigFile(this.config as string);
|
||||
const configParsed = parseConfigFile(configPathLocation);
|
||||
const { web } = configParsed;
|
||||
this.initLogger(configParsed);
|
||||
|
||||
process.title = web?.title || DEFAULT_PROCESS_NAME;
|
||||
// const { version, name } = require('../../package.json');
|
||||
const ser = await server();
|
||||
await ser.listen(4000);
|
||||
console.log('fastify running on port 4000');
|
||||
const ser = await server({ logger });
|
||||
await ser.listen(4873);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @verdaccio/config
|
||||
|
||||
## 6.0.0-6-next.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d2c65da9]
|
||||
- @verdaccio/utils@6.0.0-6-next.5
|
||||
|
||||
## 6.0.0-6-next.6
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/config",
|
||||
"version": "6.0.0-6-next.6",
|
||||
"version": "6.0.0-6-next.7",
|
||||
"description": "logger",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.5",
|
||||
"debug": "^4.2.0",
|
||||
"js-yaml": "3.14.0",
|
||||
"lodash": "^4.17.20",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import Path from 'path';
|
||||
import _ from 'lodash';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
@@ -27,28 +26,34 @@ const debug = buildDebug('verdaccio:config');
|
||||
* Find and get the first config file that match.
|
||||
* @return {String} the config file path
|
||||
*/
|
||||
function findConfigFile(configPath: string | undefined): string {
|
||||
function findConfigFile(configPath?: string): string {
|
||||
// console.log(process.env);
|
||||
if (typeof configPath !== 'undefined') {
|
||||
return Path.resolve(configPath);
|
||||
return path.resolve(configPath);
|
||||
}
|
||||
|
||||
const configPaths: SetupDirectory[] = getConfigPaths();
|
||||
|
||||
debug('%o posible locations found', configPaths.length);
|
||||
if (_.isEmpty(configPaths)) {
|
||||
// this should never happens
|
||||
throw new Error('no configuration files can be processed');
|
||||
}
|
||||
|
||||
const primaryConf: any = _.find(configPaths, (configLocation: any) =>
|
||||
// find the first location that already exist
|
||||
const primaryConf: SetupDirectory | void = _.find(configPaths, (configLocation: SetupDirectory) =>
|
||||
fileExists(configLocation.path)
|
||||
);
|
||||
if (_.isNil(primaryConf) === false) {
|
||||
|
||||
if (typeof primaryConf !== 'undefined') {
|
||||
debug('previous location exist already %s', primaryConf?.path);
|
||||
return primaryConf.path;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return createConfigFile(_.head(configPaths)).path;
|
||||
}
|
||||
|
||||
function createConfigFile(configLocation: any): SetupDirectory {
|
||||
function createConfigFile(configLocation: SetupDirectory): SetupDirectory {
|
||||
createConfigFolder(configLocation);
|
||||
|
||||
const defaultConfig = updateStorageLinks(configLocation, readDefaultConfig());
|
||||
@@ -60,13 +65,18 @@ function createConfigFile(configLocation: any): SetupDirectory {
|
||||
|
||||
export function readDefaultConfig(): Buffer {
|
||||
const pathDefaultConf: string = path.resolve(__dirname, 'conf/default.yaml');
|
||||
|
||||
try {
|
||||
debug('default configuration file %s', pathDefaultConf);
|
||||
fs.accessSync(pathDefaultConf, fs.constants.R_OK);
|
||||
} catch {
|
||||
throw new TypeError('configuration file does not have enough permissions for reading');
|
||||
}
|
||||
// @ts-ignore
|
||||
return fs.readFileSync(pathDefaultConf, CHARACTER_ENCODING.UTF8);
|
||||
}
|
||||
|
||||
function createConfigFolder(configLocation): void {
|
||||
fs.mkdirSync(Path.dirname(configLocation.path), { recursive: true });
|
||||
fs.mkdirSync(path.dirname(configLocation.path), { recursive: true });
|
||||
debug(`Creating default config file in %o`, configLocation?.path);
|
||||
}
|
||||
|
||||
@@ -78,64 +88,89 @@ function updateStorageLinks(configLocation, defaultConfig): string {
|
||||
// $XDG_DATA_HOME defines the base directory relative to which user specific data
|
||||
// files should be stored, If $XDG_DATA_HOME is either not set or empty, a default
|
||||
// equal to $HOME/.local/share should be used.
|
||||
// $FlowFixMe
|
||||
let dataDir =
|
||||
process.env.XDG_DATA_HOME || Path.join(process.env.HOME as string, '.local', 'share');
|
||||
process.env.XDG_DATA_HOME || path.join(process.env.HOME as string, '.local', 'share');
|
||||
if (folderExists(dataDir)) {
|
||||
dataDir = Path.resolve(Path.join(dataDir, pkgJSON.name, 'storage'));
|
||||
debug(`previous storage located`);
|
||||
debug(`update storage links to %s`, dataDir);
|
||||
dataDir = path.resolve(path.join(dataDir, pkgJSON.name, 'storage'));
|
||||
return defaultConfig.replace(/^storage: .\/storage$/m, `storage: ${dataDir}`);
|
||||
}
|
||||
debug(`could not find a previous storage location, skip override`);
|
||||
return defaultConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of configuration locations by platform.
|
||||
* @returns
|
||||
*/
|
||||
function getConfigPaths(): SetupDirectory[] {
|
||||
const listPaths: SetupDirectory[] = [
|
||||
const listPaths: (SetupDirectory | void)[] = [
|
||||
getXDGDirectory(),
|
||||
getWindowsDirectory(),
|
||||
getRelativeDefaultDirectory(),
|
||||
getOldDirectory(),
|
||||
].reduce(function (acc, currentValue: any): SetupDirectory[] {
|
||||
if (_.isUndefined(currentValue) === false) {
|
||||
];
|
||||
|
||||
return listPaths.reduce(function (acc, currentValue: SetupDirectory | void): SetupDirectory[] {
|
||||
if (typeof currentValue !== 'undefined') {
|
||||
debug('directory detected path %s for type %s', currentValue?.path, currentValue.type);
|
||||
acc.push(currentValue);
|
||||
}
|
||||
return acc;
|
||||
}, [] as SetupDirectory[]);
|
||||
|
||||
return listPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get XDG_CONFIG_HOME or HOME location (usually unix)
|
||||
* @returns
|
||||
*/
|
||||
const getXDGDirectory = (): SetupDirectory | void => {
|
||||
const XDGConfig = getXDGHome() || (process.env.HOME && Path.join(process.env.HOME, '.config'));
|
||||
|
||||
if (XDGConfig && folderExists(XDGConfig)) {
|
||||
const xDGConfigPath =
|
||||
process.env.XDG_CONFIG_HOME || (process.env.HOME && path.join(process.env.HOME, '.config'));
|
||||
if (xDGConfigPath && folderExists(xDGConfigPath)) {
|
||||
debug('XDGConfig folder path %s', xDGConfigPath);
|
||||
return {
|
||||
path: Path.join(XDGConfig, pkgJSON.name, CONFIG_FILE),
|
||||
path: path.join(xDGConfigPath, pkgJSON.name, CONFIG_FILE),
|
||||
type: XDG,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getXDGHome = (): string | void => process.env.XDG_CONFIG_HOME;
|
||||
|
||||
/**
|
||||
* Detect windows location, APPDATA
|
||||
* usually something like C:\User\<Build User>\AppData\Local
|
||||
* @returns
|
||||
*/
|
||||
const getWindowsDirectory = (): SetupDirectory | void => {
|
||||
if (process.platform === WIN32 && process.env.APPDATA && folderExists(process.env.APPDATA)) {
|
||||
debug('is windows appdata: %s', process.env.APPDATA);
|
||||
return {
|
||||
path: Path.resolve(Path.join(process.env.APPDATA, pkgJSON.name, CONFIG_FILE)),
|
||||
path: path.resolve(path.join(process.env.APPDATA, pkgJSON.name, CONFIG_FILE)),
|
||||
type: WIN,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return relative directory, this is the default.
|
||||
* It will cretate config in your {currentLocation/verdaccio/config.yaml}
|
||||
* @returns
|
||||
*/
|
||||
const getRelativeDefaultDirectory = (): SetupDirectory => {
|
||||
return {
|
||||
path: Path.resolve(Path.join('.', pkgJSON.name, CONFIG_FILE)),
|
||||
path: path.resolve(path.join('.', pkgJSON.name, CONFIG_FILE)),
|
||||
type: 'def',
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* This should never happens, consider it DEPRECATED
|
||||
* @returns
|
||||
*/
|
||||
const getOldDirectory = (): SetupDirectory => {
|
||||
return {
|
||||
path: Path.resolve(Path.join('.', CONFIG_FILE)),
|
||||
path: path.resolve(path.join('.', CONFIG_FILE)),
|
||||
type: 'old',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -106,7 +106,7 @@ class Config implements AppConfig {
|
||||
/**
|
||||
* Store or create whether receive a secret key
|
||||
*/
|
||||
public checkSecretKey(secret: string): string {
|
||||
public checkSecretKey(secret?: string): string {
|
||||
debug('check secret key');
|
||||
if (_.isString(secret) && _.isEmpty(secret) === false) {
|
||||
this.secret = secret;
|
||||
|
||||
105
packages/config/test/config.path.spec.ts
Normal file
105
packages/config/test/config.path.spec.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import os from 'os';
|
||||
import { findConfigFile } from '../src/config-path';
|
||||
|
||||
const mockmkDir = jest.fn();
|
||||
const mockaccessSync = jest.fn();
|
||||
const mockwriteFile = jest.fn();
|
||||
|
||||
jest.mock('fs', () => {
|
||||
const fsOri = jest.requireActual('fs');
|
||||
return {
|
||||
...fsOri,
|
||||
statSync: (path) => ({
|
||||
isDirectory: () => {
|
||||
if (path.match(/fail/)) {
|
||||
throw Error('file does not exist');
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}),
|
||||
accessSync: (a) => mockaccessSync(a),
|
||||
mkdirSync: (a) => mockmkDir(a),
|
||||
writeFileSync: (a) => mockwriteFile(a),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
describe('config-path', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('findConfigFile', () => {
|
||||
if (os.platform() !== 'win32') {
|
||||
describe('using defiled location from arguments', () => {
|
||||
test('with custom location', () => {
|
||||
expect(findConfigFile('/home/user/custom/location/config.yaml')).toEqual(
|
||||
'/home/user/custom/location/config.yaml'
|
||||
);
|
||||
expect(mockwriteFile).not.toHaveBeenCalled();
|
||||
expect(mockmkDir).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('whith env variables', () => {
|
||||
test('with XDG_CONFIG_HOME if directory exist but config file is missing', () => {
|
||||
process.env.XDG_CONFIG_HOME = '/home/user';
|
||||
expect(findConfigFile()).toEqual('/home/user/verdaccio/config.yaml');
|
||||
expect(mockwriteFile).toHaveBeenCalledWith('/home/user/verdaccio/config.yaml');
|
||||
expect(mockmkDir).toHaveBeenCalledWith('/home/user/verdaccio');
|
||||
});
|
||||
|
||||
test('with HOME if directory exist but config file is missing', () => {
|
||||
delete process.env.XDG_CONFIG_HOME;
|
||||
process.env.HOME = '/home/user';
|
||||
expect(findConfigFile()).toEqual('/home/user/.config/verdaccio/config.yaml');
|
||||
expect(mockwriteFile).toHaveBeenCalledWith('/home/user/.config/verdaccio/config.yaml');
|
||||
expect(mockmkDir).toHaveBeenCalledWith('/home/user/.config/verdaccio');
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
test('XDG_CONFIG_HOME is not directory fallback to default', () => {
|
||||
process.env.XDG_CONFIG_HOME = '/home/user/fail';
|
||||
mockaccessSync.mockImplementation(() => {});
|
||||
mockwriteFile.mockImplementation(() => {});
|
||||
expect(findConfigFile()).toMatch('packages/config/verdaccio/config.yaml');
|
||||
});
|
||||
|
||||
test('no permissions on read default config file', () => {
|
||||
process.env.XDG_CONFIG_HOME = '/home/user';
|
||||
mockaccessSync.mockImplementation(() => {
|
||||
throw new Error('error on write file');
|
||||
});
|
||||
|
||||
expect(function () {
|
||||
findConfigFile();
|
||||
}).toThrow(/configuration file does not have enough permissions for reading/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with no env variables', () => {
|
||||
test('with relative location', () => {
|
||||
mockaccessSync.mockImplementation(() => {});
|
||||
delete process.env.XDG_CONFIG_HOME;
|
||||
delete process.env.HOME;
|
||||
process.env.APPDATA = '/app/data/';
|
||||
expect(findConfigFile()).toMatch('packages/config/verdaccio/config.yaml');
|
||||
expect(mockwriteFile).toHaveBeenCalled();
|
||||
expect(mockmkDir).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
test('with windows as directory exist but config file is missing', () => {
|
||||
delete process.env.XDG_CONFIG_HOME;
|
||||
delete process.env.HOME;
|
||||
process.env.APPDATA = '/app/data/';
|
||||
expect(findConfigFile()).toEqual('D:\\app\\data\\verdaccio\\config.yaml');
|
||||
expect(mockwriteFile).toHaveBeenCalledWith('D:\\app\\data\\verdaccio\\config.yaml');
|
||||
expect(mockmkDir).toHaveBeenCalledWith('D:\\app\\data\\verdaccio');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
parseConfigFile,
|
||||
ROLES,
|
||||
WEB_TITLE,
|
||||
getMatchedPackagesSpec,
|
||||
} from '../src';
|
||||
import { parseConfigurationFile } from './utils';
|
||||
|
||||
@@ -23,56 +24,56 @@ const checkDefaultUplink = (config) => {
|
||||
expect(config.uplinks[DEFAULT_UPLINK].url).toMatch(DEFAULT_REGISTRY);
|
||||
};
|
||||
|
||||
const checkDefaultConfPackages = (config) => {
|
||||
// auth
|
||||
expect(_.isObject(config.auth)).toBeTruthy();
|
||||
expect(_.isObject(config.auth.htpasswd)).toBeTruthy();
|
||||
expect(config.auth.htpasswd.file).toMatch(/htpasswd/);
|
||||
|
||||
// web
|
||||
expect(_.isObject(config.web)).toBeTruthy();
|
||||
expect(config.web.title).toBe(WEB_TITLE);
|
||||
expect(config.web.enable).toBeUndefined();
|
||||
|
||||
// packages
|
||||
expect(_.isObject(config.packages)).toBeTruthy();
|
||||
expect(Object.keys(config.packages).join('|')).toBe('@*/*|**');
|
||||
expect(config.packages['@*/*'].access).toBeDefined();
|
||||
expect(config.packages['@*/*'].access).toContainEqual(ROLES.$ALL);
|
||||
expect(config.packages['@*/*'].publish).toBeDefined();
|
||||
expect(config.packages['@*/*'].publish).toContainEqual(ROLES.$AUTH);
|
||||
expect(config.packages['@*/*'].proxy).toBeDefined();
|
||||
expect(config.packages['@*/*'].proxy).toContainEqual(DEFAULT_UPLINK);
|
||||
expect(config.packages['**'].access).toBeDefined();
|
||||
expect(config.packages['**'].access).toContainEqual(ROLES.$ALL);
|
||||
expect(config.packages['**'].publish).toBeDefined();
|
||||
expect(config.packages['**'].publish).toContainEqual(ROLES.$AUTH);
|
||||
expect(config.packages['**'].proxy).toBeDefined();
|
||||
expect(config.packages['**'].proxy).toContainEqual(DEFAULT_UPLINK);
|
||||
// uplinks
|
||||
expect(config.uplinks[DEFAULT_UPLINK]).toBeDefined();
|
||||
expect(config.uplinks[DEFAULT_UPLINK].url).toEqual(DEFAULT_REGISTRY);
|
||||
// audit
|
||||
expect(config.middlewares).toBeDefined();
|
||||
expect(config.middlewares.audit).toBeDefined();
|
||||
expect(config.middlewares.audit.enabled).toBeTruthy();
|
||||
// logs
|
||||
expect(config.logs).toBeDefined();
|
||||
expect(config.logs.type).toEqual('stdout');
|
||||
expect(config.logs.format).toEqual('pretty');
|
||||
expect(config.logs.level).toEqual('http');
|
||||
// must not be enabled by default
|
||||
expect(config.notify).toBeUndefined();
|
||||
expect(config.store).toBeUndefined();
|
||||
expect(config.publish).toBeUndefined();
|
||||
expect(config.url_prefix).toBeUndefined();
|
||||
expect(config.url_prefix).toBeUndefined();
|
||||
|
||||
expect(config.experiments).toBeUndefined();
|
||||
expect(config.security).toEqual(defaultSecurity);
|
||||
};
|
||||
|
||||
describe('check basic content parsed file', () => {
|
||||
const checkDefaultConfPackages = (config) => {
|
||||
// auth
|
||||
expect(_.isObject(config.auth)).toBeTruthy();
|
||||
expect(_.isObject(config.auth.htpasswd)).toBeTruthy();
|
||||
expect(config.auth.htpasswd.file).toMatch(/htpasswd/);
|
||||
|
||||
// web
|
||||
expect(_.isObject(config.web)).toBeTruthy();
|
||||
expect(config.web.title).toBe(WEB_TITLE);
|
||||
expect(config.web.enable).toBeUndefined();
|
||||
|
||||
// packages
|
||||
expect(_.isObject(config.packages)).toBeTruthy();
|
||||
expect(Object.keys(config.packages).join('|')).toBe('@*/*|**');
|
||||
expect(config.packages['@*/*'].access).toBeDefined();
|
||||
expect(config.packages['@*/*'].access).toContainEqual(ROLES.$ALL);
|
||||
expect(config.packages['@*/*'].publish).toBeDefined();
|
||||
expect(config.packages['@*/*'].publish).toContainEqual(ROLES.$AUTH);
|
||||
expect(config.packages['@*/*'].proxy).toBeDefined();
|
||||
expect(config.packages['@*/*'].proxy).toContainEqual(DEFAULT_UPLINK);
|
||||
expect(config.packages['**'].access).toBeDefined();
|
||||
expect(config.packages['**'].access).toContainEqual(ROLES.$ALL);
|
||||
expect(config.packages['**'].publish).toBeDefined();
|
||||
expect(config.packages['**'].publish).toContainEqual(ROLES.$AUTH);
|
||||
expect(config.packages['**'].proxy).toBeDefined();
|
||||
expect(config.packages['**'].proxy).toContainEqual(DEFAULT_UPLINK);
|
||||
// uplinks
|
||||
expect(config.uplinks[DEFAULT_UPLINK]).toBeDefined();
|
||||
expect(config.uplinks[DEFAULT_UPLINK].url).toEqual(DEFAULT_REGISTRY);
|
||||
// audit
|
||||
expect(config.middlewares).toBeDefined();
|
||||
expect(config.middlewares.audit).toBeDefined();
|
||||
expect(config.middlewares.audit.enabled).toBeTruthy();
|
||||
// logs
|
||||
expect(config.logs).toBeDefined();
|
||||
expect(config.logs.type).toEqual('stdout');
|
||||
expect(config.logs.format).toEqual('pretty');
|
||||
expect(config.logs.level).toEqual('http');
|
||||
// must not be enabled by default
|
||||
expect(config.notify).toBeUndefined();
|
||||
expect(config.store).toBeUndefined();
|
||||
expect(config.publish).toBeUndefined();
|
||||
expect(config.url_prefix).toBeUndefined();
|
||||
expect(config.url_prefix).toBeUndefined();
|
||||
|
||||
expect(config.experiments).toBeUndefined();
|
||||
expect(config.security).toEqual(defaultSecurity);
|
||||
};
|
||||
|
||||
test('parse default.yaml', () => {
|
||||
const config = new Config(parseConfigFile(resolveConf('default')));
|
||||
checkDefaultUplink(config);
|
||||
@@ -81,6 +82,57 @@ describe('check basic content parsed file', () => {
|
||||
checkDefaultConfPackages(config);
|
||||
});
|
||||
|
||||
test('parse docker.yaml', () => {
|
||||
const config = new Config(parseConfigFile(resolveConf('docker')));
|
||||
checkDefaultUplink(config);
|
||||
expect(config.storage).toBe('/verdaccio/storage/data');
|
||||
expect(config.auth.htpasswd.file).toBe('/verdaccio/storage/htpasswd');
|
||||
checkDefaultConfPackages(config);
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkSecretKey', () => {
|
||||
test('with default.yaml and pre selected secret', () => {
|
||||
const config = new Config(parseConfigFile(resolveConf('default')));
|
||||
expect(config.checkSecretKey('12345')).toEqual('12345');
|
||||
});
|
||||
|
||||
test('with default.yaml and void secret', () => {
|
||||
const config = new Config(parseConfigFile(resolveConf('default')));
|
||||
expect(typeof config.checkSecretKey() === 'string').toBeTruthy();
|
||||
});
|
||||
|
||||
test('with default.yaml and emtpy string secret', () => {
|
||||
const config = new Config(parseConfigFile(resolveConf('default')));
|
||||
expect(typeof config.checkSecretKey('') === 'string').toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMatchedPackagesSpec', () => {
|
||||
test('should match with react as defined in config file', () => {
|
||||
const configParsed = parseConfigFile(parseConfigurationFile('config-getMatchedPackagesSpec'));
|
||||
const config = new Config(configParsed);
|
||||
expect(config.getMatchedPackagesSpec('react')).toEqual({
|
||||
access: ['admin'],
|
||||
proxy: ['facebook'],
|
||||
publish: ['admin'],
|
||||
unpublish: false,
|
||||
});
|
||||
});
|
||||
|
||||
test('should not match with react as defined in config file', () => {
|
||||
const configParsed = parseConfigFile(parseConfigurationFile('config-getMatchedPackagesSpec'));
|
||||
const config = new Config(configParsed);
|
||||
expect(config.getMatchedPackagesSpec('somePackage')).toEqual({
|
||||
access: [ROLES.$ALL],
|
||||
proxy: ['npmjs'],
|
||||
publish: [ROLES.$AUTH],
|
||||
unpublish: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('VERDACCIO_STORAGE_PATH', () => {
|
||||
test('should set storage to value set in VERDACCIO_STORAGE_PATH environment variable', () => {
|
||||
const storageLocation = '/tmp/verdaccio';
|
||||
process.env.VERDACCIO_STORAGE_PATH = storageLocation;
|
||||
@@ -106,12 +158,4 @@ describe('check basic content parsed file', () => {
|
||||
expect(config.storage).toBe(storageLocation);
|
||||
delete process.env.VERDACCIO_STORAGE_PATH;
|
||||
});
|
||||
|
||||
test('parse docker.yaml', () => {
|
||||
const config = new Config(parseConfigFile(resolveConf('docker')));
|
||||
checkDefaultUplink(config);
|
||||
expect(config.storage).toBe('/verdaccio/storage/data');
|
||||
expect(config.auth.htpasswd.file).toBe('/verdaccio/storage/htpasswd');
|
||||
checkDefaultConfPackages(config);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -88,26 +88,17 @@ describe('Package access utilities', () => {
|
||||
() => {
|
||||
const { packages } = parseConfigFile(parseConfigurationFile('deprecated-pkgs-basic'));
|
||||
const access = normalisePackageAccess(packages);
|
||||
|
||||
expect(access).toBeDefined();
|
||||
|
||||
const scoped = access[`${PACKAGE_ACCESS.SCOPE}`];
|
||||
const all = access[`${PACKAGE_ACCESS.ALL}`];
|
||||
const react = access['react-*'];
|
||||
|
||||
expect(react).toBeDefined();
|
||||
expect(react.access).toBeDefined();
|
||||
|
||||
// Intended checks, Typescript should catch this, we test the runtime part
|
||||
// @ts-ignore
|
||||
expect(react.access).toEqual([]);
|
||||
// @ts-ignore
|
||||
expect(react.publish[0]).toBe('admin');
|
||||
expect(react.proxy).toBeDefined();
|
||||
// @ts-ignore
|
||||
expect(react.proxy).toEqual([]);
|
||||
expect(react.storage).toBeDefined();
|
||||
|
||||
expect(react.storage).toBe('react-storage');
|
||||
expect(scoped).toBeDefined();
|
||||
expect(scoped.storage).not.toBeDefined();
|
||||
@@ -126,7 +117,6 @@ describe('Package access utilities', () => {
|
||||
|
||||
const scoped = access[`${PACKAGE_ACCESS.SCOPE}`];
|
||||
expect(scoped).toBeUndefined();
|
||||
|
||||
// ** should be added by default **
|
||||
const all = access[`${PACKAGE_ACCESS.ALL}`];
|
||||
expect(all).toBeDefined();
|
||||
@@ -141,23 +131,23 @@ describe('Package access utilities', () => {
|
||||
describe('getMatchedPackagesSpec', () => {
|
||||
test('should test basic config', () => {
|
||||
const { packages } = parseConfigFile(parseConfigurationFile('pkgs-custom'));
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('react', packages).proxy).toMatch('facebook');
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('angular', packages).proxy).toMatch('google');
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('vue', packages).proxy).toMatch('npmjs');
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('@scope/vue', packages).proxy).toMatch('npmjs');
|
||||
});
|
||||
|
||||
test('should test no ** wildcard on config', () => {
|
||||
const { packages } = parseConfigFile(parseConfigurationFile('pkgs-nosuper-wildcard-custom'));
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('react', packages).proxy).toMatch('facebook');
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('angular', packages).proxy).toMatch('google');
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('@fake/angular', packages).proxy).toMatch('npmjs');
|
||||
expect(getMatchedPackagesSpec('vue', packages)).toBeUndefined();
|
||||
expect(getMatchedPackagesSpec('@scope/vue', packages)).toBeUndefined();
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
packages:
|
||||
'react':
|
||||
access: admin
|
||||
publish: admin
|
||||
proxy: facebook
|
||||
'angular':
|
||||
access: admin
|
||||
publish: admin
|
||||
proxy: google
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $authenticated
|
||||
proxy: npmjs
|
||||
'**':
|
||||
access: $all
|
||||
publish: $authenticated
|
||||
proxy: npmjs
|
||||
@@ -40,7 +40,7 @@
|
||||
"lockfile": "1.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"mockdate": "^3.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('HTPasswd', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = new HTPasswd(getDefaultConfig(), (stuff as unknown) as VerdaccioConfigApp);
|
||||
wrapper = new HTPasswd(getDefaultConfig(), stuff as unknown as VerdaccioConfigApp);
|
||||
jest.resetModules();
|
||||
|
||||
crypto.randomBytes = jest.fn(() => {
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/minimatch": "^3.0.3",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"minimatch": "^3.0.4",
|
||||
"rmdir-sync": "^1.0.1"
|
||||
},
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"marked": "1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
|
||||
6
packages/core/server/CHANGELOG.md
Normal file
6
packages/core/server/CHANGELOG.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# @verdaccio/fastify-migration
|
||||
|
||||
## 6.0.0-6-next.10
|
||||
### Minor Changes
|
||||
|
||||
- 55ee3fdd: [Fastify] Add ping endpoint
|
||||
39
packages/core/server/debug/fastify-conf.yaml
Normal file
39
packages/core/server/debug/fastify-conf.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
storage: ./storage
|
||||
plugins: ./plugins
|
||||
web:
|
||||
title: Verdaccio
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: https://registry.npmjs.org/
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $authenticated
|
||||
unpublish: $authenticated
|
||||
proxy: npmjs
|
||||
|
||||
'**':
|
||||
access: $all
|
||||
publish: $authenticated
|
||||
unpublish: $authenticated
|
||||
proxy: npmjs
|
||||
|
||||
server:
|
||||
keepAliveTimeout: 60
|
||||
|
||||
middlewares:
|
||||
audit:
|
||||
enabled: true
|
||||
|
||||
log: { type: stdout, format: pretty, level: http }
|
||||
flags:
|
||||
token: false
|
||||
search: false
|
||||
|
||||
i18n:
|
||||
web: en-US
|
||||
30
packages/core/server/debug/index.ts
Normal file
30
packages/core/server/debug/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import path from 'path';
|
||||
import buildDebug from 'debug';
|
||||
import { parseConfigFile } from '@verdaccio/config';
|
||||
import { setup, logger } from '@verdaccio/logger';
|
||||
import server from '../src/index';
|
||||
|
||||
const debug = buildDebug('verdaccio:fastify:debug');
|
||||
|
||||
/**
|
||||
* This file is intended for fast development and debug, it should
|
||||
* be removed eventually and the app start from @verdaccio/cli package.
|
||||
*/
|
||||
(async () => {
|
||||
try {
|
||||
const configFile = path.join(__dirname, './fastify-conf.yaml');
|
||||
debug('configFile %s', configFile);
|
||||
const configParsed = parseConfigFile(configFile);
|
||||
setup(configParsed.log);
|
||||
logger.info(`config location ${configFile}`);
|
||||
debug('configParsed %s', configParsed);
|
||||
process.title = 'fastify-verdaccio';
|
||||
const ser = await server({ logger });
|
||||
await ser.listen(4873);
|
||||
logger.info('fastify running on port 4873');
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/fastify-migration",
|
||||
"version": "6.0.0-6-next.9",
|
||||
"version": "6.0.0-6-next.10",
|
||||
"description": "Fastify server migration package",
|
||||
"keywords": [
|
||||
"private",
|
||||
@@ -34,10 +34,15 @@
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"fastify": "3.14.2"
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.4",
|
||||
"fastify": "3.15.1",
|
||||
"fastify-plugin": "3.0.0",
|
||||
"debug": "4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.7",
|
||||
"ts-node": "9.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
@@ -45,7 +50,8 @@
|
||||
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
|
||||
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
|
||||
"watch": "pnpm build:js -- --watch",
|
||||
"build": "pnpm run build:js && pnpm run build:types"
|
||||
"build": "pnpm run build:js && pnpm run build:types",
|
||||
"start": "ts-node debug/index.ts"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
|
||||
10
packages/core/server/src/endpoints/ping.ts
Normal file
10
packages/core/server/src/endpoints/ping.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { logger } from '@verdaccio/logger';
|
||||
|
||||
async function pingRoute(fastify) {
|
||||
fastify.get('/-/ping', async () => {
|
||||
logger.http('ping endpoint');
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
export default pingRoute;
|
||||
@@ -1,12 +1,14 @@
|
||||
import fastify from 'fastify';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
async function startServer() {
|
||||
const app = fastify();
|
||||
import ping from './endpoints/ping';
|
||||
|
||||
app.get('/', async (request, reply) => {
|
||||
return { hello: 'world' };
|
||||
});
|
||||
const debug = buildDebug('verdaccio:fastify');
|
||||
|
||||
async function startServer({ logger }) {
|
||||
debug('start server');
|
||||
const app = fastify({ logger });
|
||||
app.register(ping);
|
||||
return app;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"access": "public"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# Change Log
|
||||
|
||||
## 11.0.0-6-next.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d2c65da9]
|
||||
- @verdaccio/utils@6.0.0-6-next.5
|
||||
|
||||
## 11.0.0-6-next.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/tarball",
|
||||
"version": "11.0.0-6-next.5",
|
||||
"version": "11.0.0-6-next.6",
|
||||
"description": "tarball utilities resolver",
|
||||
"keywords": [
|
||||
"private",
|
||||
@@ -38,12 +38,12 @@
|
||||
"lodash": "^4.17.21",
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/url": "workspace:11.0.0-6-next.4",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.4"
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5",
|
||||
"express": "^4.17.1",
|
||||
"node-mocks-http": "^1.10.1"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"express": "4.17.1",
|
||||
"node-mocks-http": "1.10.1"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
|
||||
@@ -1,5 +1,50 @@
|
||||
# Change Log
|
||||
|
||||
## 11.0.0-6-next.7
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 0da7031e: allow disable login on ui and endpoints
|
||||
|
||||
To be able disable the login, set `login: false`, anything else would enable login. This flag will disable access via UI and web endpoints.
|
||||
|
||||
```yml
|
||||
web:
|
||||
title: verdaccio
|
||||
login: false
|
||||
```
|
||||
|
||||
## 11.0.0-6-next.6
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- aecbd226: web: allow ui hide package managers on sidebar
|
||||
|
||||
If there is a package manager of preference over others, you can define the package managers to be displayed on the detail page and sidebar, just define in the `config.yaml` and web section the list of package managers to be displayed.
|
||||
|
||||
```
|
||||
web:
|
||||
title: Verdaccio
|
||||
sort_packages: asc
|
||||
primary_color: #cccccc
|
||||
pkgManagers:
|
||||
- pnpm
|
||||
- yarn
|
||||
# - npm
|
||||
```
|
||||
|
||||
To disable all package managers, just define empty:
|
||||
|
||||
```
|
||||
web:
|
||||
title: Verdaccio
|
||||
sort_packages: asc
|
||||
primary_color: #cccccc
|
||||
pkgManagers:
|
||||
```
|
||||
|
||||
and the section would be hidden.
|
||||
|
||||
## 11.0.0-6-next.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
62
packages/core/types/index.d.ts
vendored
62
packages/core/types/index.d.ts
vendored
@@ -15,6 +15,51 @@ declare module '@verdaccio/types' {
|
||||
url?: string;
|
||||
}
|
||||
|
||||
type PackageManagers = 'pnpm' | 'yarn' | 'npm';
|
||||
|
||||
// FUTURE: WebConf and TemplateUIOptions should be merged .
|
||||
type CommonWebConf = {
|
||||
title?: string;
|
||||
logo?: string;
|
||||
favicon?: string;
|
||||
gravatar?: boolean;
|
||||
sort_packages?: string;
|
||||
darkMode?: boolean;
|
||||
url_prefix?: string;
|
||||
language?: string;
|
||||
login?: boolean;
|
||||
scope?: string;
|
||||
pkgManagers?: PackageManagers[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Options are passed to the index.html
|
||||
*/
|
||||
export type TemplateUIOptions = {
|
||||
uri?: string;
|
||||
darkMode?: boolean;
|
||||
protocol?: string;
|
||||
host?: string;
|
||||
base: string;
|
||||
primaryColor?: string;
|
||||
version?: string;
|
||||
logoURI?: string;
|
||||
} & CommonWebConf;
|
||||
|
||||
/**
|
||||
* Options on config.yaml for web
|
||||
*/
|
||||
type WebConf = {
|
||||
// FIXME: rename to primaryColor and move it to CommonWebConf
|
||||
primary_color?: string;
|
||||
enable?: boolean;
|
||||
scriptsHead?: string[];
|
||||
scriptsBodyAfter?: string[];
|
||||
metaScripts?: string[];
|
||||
bodyBefore?: string[];
|
||||
bodyAfter?: string[];
|
||||
} & CommonWebConf;
|
||||
|
||||
interface Dist {
|
||||
integrity?: string;
|
||||
shasum: string;
|
||||
@@ -276,23 +321,6 @@ declare module '@verdaccio/types' {
|
||||
interface ListenAddress {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
interface WebConf {
|
||||
enable?: boolean;
|
||||
title?: string;
|
||||
logo?: string;
|
||||
favicon?: string;
|
||||
gravatar?: boolean;
|
||||
sort_packages?: string;
|
||||
scriptsHead?: string[];
|
||||
scriptsBodyAfter?: string[];
|
||||
metaScripts?: string[];
|
||||
bodyBefore?: string[];
|
||||
bodyAfter?: string[];
|
||||
darkMode?: boolean;
|
||||
primary_color?: string;
|
||||
}
|
||||
|
||||
interface HttpsConfKeyCert {
|
||||
key: string;
|
||||
cert: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/types",
|
||||
"version": "11.0.0-6-next.5",
|
||||
"version": "11.0.0-6-next.7",
|
||||
"description": "verdaccio types definitions",
|
||||
"keywords": [
|
||||
"private",
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"node-mocks-http": "^1.10.1",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
"request": "2.87.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.8",
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.9",
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"nock": "^13.0.4"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"homepage": "https://verdaccio.org",
|
||||
"keywords": [
|
||||
|
||||
@@ -59,86 +59,84 @@ export function loadPlugin<T extends IPlugin<T>>(
|
||||
sanityCheck: any,
|
||||
prefix: string = 'verdaccio'
|
||||
): any[] {
|
||||
return Object.keys(pluginConfigs).map(
|
||||
(pluginId: string): IPlugin<T> => {
|
||||
let plugin;
|
||||
return Object.keys(pluginConfigs).map((pluginId: string): IPlugin<T> => {
|
||||
let plugin;
|
||||
|
||||
const localPlugin = Path.resolve(__dirname + '/../plugins', pluginId);
|
||||
// try local plugins first
|
||||
plugin = tryLoad(localPlugin);
|
||||
const localPlugin = Path.resolve(__dirname + '/../plugins', pluginId);
|
||||
// try local plugins first
|
||||
plugin = tryLoad(localPlugin);
|
||||
|
||||
// try the external plugin directory
|
||||
if (plugin === null && config.plugins) {
|
||||
const pluginDir = config.plugins;
|
||||
const externalFilePlugin = Path.resolve(pluginDir, pluginId);
|
||||
plugin = tryLoad(externalFilePlugin);
|
||||
|
||||
// npm package
|
||||
if (plugin === null && pluginId.match(/^[^\.\/]/)) {
|
||||
plugin = tryLoad(Path.resolve(pluginDir, `${prefix}-${pluginId}`));
|
||||
// compatibility for old sinopia plugins
|
||||
if (!plugin) {
|
||||
plugin = tryLoad(Path.resolve(pluginDir, `sinopia-${pluginId}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
// try the external plugin directory
|
||||
if (plugin === null && config.plugins) {
|
||||
const pluginDir = config.plugins;
|
||||
const externalFilePlugin = Path.resolve(pluginDir, pluginId);
|
||||
plugin = tryLoad(externalFilePlugin);
|
||||
|
||||
// npm package
|
||||
if (plugin === null && pluginId.match(/^[^\.\/]/)) {
|
||||
plugin = tryLoad(`${prefix}-${pluginId}`);
|
||||
plugin = tryLoad(Path.resolve(pluginDir, `${prefix}-${pluginId}`));
|
||||
// compatibility for old sinopia plugins
|
||||
if (!plugin) {
|
||||
plugin = tryLoad(`sinopia-${pluginId}`);
|
||||
plugin = tryLoad(Path.resolve(pluginDir, `sinopia-${pluginId}`));
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin === null) {
|
||||
plugin = tryLoad(pluginId);
|
||||
}
|
||||
|
||||
// relative to config path
|
||||
if (plugin === null && pluginId.match(/^\.\.?($|\/)/)) {
|
||||
plugin = tryLoad(Path.resolve(Path.dirname(config.config_path), pluginId));
|
||||
}
|
||||
|
||||
if (plugin === null) {
|
||||
logger.error(
|
||||
{ content: pluginId, prefix },
|
||||
'plugin not found. try npm install @{prefix}-@{content}'
|
||||
);
|
||||
throw Error(`
|
||||
${prefix}-${pluginId} plugin not found. try "npm install ${prefix}-${pluginId}"`);
|
||||
}
|
||||
|
||||
if (!isValid(plugin)) {
|
||||
logger.error(
|
||||
{ content: pluginId },
|
||||
'@{prefix}-@{content} plugin does not have the right code structure'
|
||||
);
|
||||
throw Error(`"${pluginId}" plugin does not have the right code structure`);
|
||||
}
|
||||
|
||||
/* eslint new-cap:off */
|
||||
try {
|
||||
plugin = isES6(plugin)
|
||||
? new plugin.default(mergeConfig(config, pluginConfigs[pluginId]), params)
|
||||
: plugin(pluginConfigs[pluginId], params);
|
||||
} catch (error) {
|
||||
plugin = null;
|
||||
logger.error({ error, pluginId }, 'error loading a plugin @{pluginId}: @{error}');
|
||||
}
|
||||
/* eslint new-cap:off */
|
||||
|
||||
if (plugin === null || !sanityCheck(plugin)) {
|
||||
logger.error(
|
||||
{ content: pluginId, prefix },
|
||||
"@{prefix}-@{content} doesn't look like a valid plugin"
|
||||
);
|
||||
throw Error(`sanity check has failed, "${pluginId}" is not a valid plugin`);
|
||||
}
|
||||
|
||||
debug('Plugin successfully loaded: %o-%o', pluginId, prefix);
|
||||
return plugin;
|
||||
}
|
||||
);
|
||||
|
||||
// npm package
|
||||
if (plugin === null && pluginId.match(/^[^\.\/]/)) {
|
||||
plugin = tryLoad(`${prefix}-${pluginId}`);
|
||||
// compatibility for old sinopia plugins
|
||||
if (!plugin) {
|
||||
plugin = tryLoad(`sinopia-${pluginId}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin === null) {
|
||||
plugin = tryLoad(pluginId);
|
||||
}
|
||||
|
||||
// relative to config path
|
||||
if (plugin === null && pluginId.match(/^\.\.?($|\/)/)) {
|
||||
plugin = tryLoad(Path.resolve(Path.dirname(config.config_path), pluginId));
|
||||
}
|
||||
|
||||
if (plugin === null) {
|
||||
logger.error(
|
||||
{ content: pluginId, prefix },
|
||||
'plugin not found. try npm install @{prefix}-@{content}'
|
||||
);
|
||||
throw Error(`
|
||||
${prefix}-${pluginId} plugin not found. try "npm install ${prefix}-${pluginId}"`);
|
||||
}
|
||||
|
||||
if (!isValid(plugin)) {
|
||||
logger.error(
|
||||
{ content: pluginId },
|
||||
'@{prefix}-@{content} plugin does not have the right code structure'
|
||||
);
|
||||
throw Error(`"${pluginId}" plugin does not have the right code structure`);
|
||||
}
|
||||
|
||||
/* eslint new-cap:off */
|
||||
try {
|
||||
plugin = isES6(plugin)
|
||||
? new plugin.default(mergeConfig(config, pluginConfigs[pluginId]), params)
|
||||
: plugin(pluginConfigs[pluginId], params);
|
||||
} catch (error) {
|
||||
plugin = null;
|
||||
logger.error({ error, pluginId }, 'error loading a plugin @{pluginId}: @{error}');
|
||||
}
|
||||
/* eslint new-cap:off */
|
||||
|
||||
if (plugin === null || !sanityCheck(plugin)) {
|
||||
logger.error(
|
||||
{ content: pluginId, prefix },
|
||||
"@{prefix}-@{content} doesn't look like a valid plugin"
|
||||
);
|
||||
throw Error(`sanity check has failed, "${pluginId}" is not a valid plugin`);
|
||||
}
|
||||
|
||||
debug('Plugin successfully loaded: %o-%o', pluginId, prefix);
|
||||
return plugin;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/pino": "^6.3.3",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @verdaccio/middleware
|
||||
|
||||
## 6.0.0-6-next.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d2c65da9]
|
||||
- @verdaccio/utils@6.0.0-6-next.5
|
||||
- @verdaccio/auth@6.0.0-6-next.9
|
||||
|
||||
## 6.0.0-6-next.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/middleware",
|
||||
"version": "6.0.0-6-next.8",
|
||||
"version": "6.0.0-6-next.9",
|
||||
"description": "loaders logic",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -39,10 +39,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.8",
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.9",
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.5",
|
||||
"lodash": "4.17.15"
|
||||
},
|
||||
"funding": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @verdaccio/mock
|
||||
|
||||
## 6.0.0-6-next.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d2c65da9]
|
||||
- @verdaccio/utils@6.0.0-6-next.5
|
||||
- @verdaccio/config@6.0.0-6-next.7
|
||||
|
||||
## 6.0.0-6-next.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/mock",
|
||||
"version": "6.0.0-6-next.6",
|
||||
"version": "6.0.0-6-next.7",
|
||||
"author": {
|
||||
"name": "Juan Picado",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
@@ -40,8 +40,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.5",
|
||||
"debug": "^4.2.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"lodash": "^4.17.20",
|
||||
@@ -49,7 +49,7 @@
|
||||
"supertest": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
# @verdaccio/node-api
|
||||
|
||||
## 6.0.0-6-next.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/config@6.0.0-6-next.7
|
||||
- @verdaccio/server@6.0.0-6-next.16
|
||||
|
||||
## 6.0.0-6-next.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/server@6.0.0-6-next.15
|
||||
|
||||
## 6.0.0-6-next.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/logger@6.0.0-6-next.4
|
||||
- @verdaccio/server@6.0.0-6-next.14
|
||||
|
||||
## 6.0.0-6-next.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/logger@6.0.0-6-next.4
|
||||
- @verdaccio/server@6.0.0-6-next.13
|
||||
|
||||
## 6.0.0-6-next.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/node-api",
|
||||
"version": "6.0.0-6-next.13",
|
||||
"version": "6.0.0-6-next.17",
|
||||
"description": "node API",
|
||||
"main": "build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -40,16 +40,16 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.12",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.16",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.4",
|
||||
"core-js": "^3.6.5",
|
||||
"debug": "^4.2.0",
|
||||
"lodash": "^4.17.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5",
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"jest-mock-process": "^1.4.0",
|
||||
"selfsigned": "1.10.7",
|
||||
"supertest": "^6.1.3"
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/activedirectory2": "^1.2.1",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
|
||||
@@ -51,7 +51,7 @@ class ActiveDirectoryPlugin implements IPluginAuth<ActiveDirectoryConfig> {
|
||||
connection.getGroupMembershipForUser(username, (err, groups: object[]): void => {
|
||||
if (err) {
|
||||
this.logger.warn(`AD - Active Directory group check failed with error: ${err}`);
|
||||
return cb(getInternalError((err as unknown) as string));
|
||||
return cb(getInternalError(err as unknown as string));
|
||||
}
|
||||
|
||||
const requestedGroups = Array.isArray(groupName) ? groupName : [groupName];
|
||||
|
||||
@@ -83,7 +83,7 @@ describe('Active Directory Plugin', () => {
|
||||
const errorMessage = 'Unknown error retrieving groups';
|
||||
ActiveDirectory.prototype.authenticate = jest.fn((_1, _2, cb) => cb(null, true));
|
||||
ActiveDirectory.prototype.getGroupMembershipForUser = jest.fn((_, cb) =>
|
||||
cb((errorMessage as unknown) as object, null)
|
||||
cb(errorMessage as unknown as object, null)
|
||||
) as jest.Mock;
|
||||
|
||||
adPluginSingleGroup.authenticate('', '', (error, authUser) => {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"node-fetch": "^2.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"body-parser": "^1.19.0",
|
||||
"nock": "^12.0.3",
|
||||
"supertest": "^4.0.2"
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Change Log
|
||||
|
||||
## 11.0.0-6-next.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6b1a28de: Fix the prefix used to delete from s3 when unpublishing packages
|
||||
|
||||
## 11.0.0-6-next.4
|
||||
|
||||
### Major Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "verdaccio-aws-s3-storage",
|
||||
"version": "11.0.0-6-next.4",
|
||||
"version": "11.0.0-6-next.5",
|
||||
"description": "AWS S3 storage implementation for Verdaccio",
|
||||
"keywords": [
|
||||
"private",
|
||||
@@ -36,7 +36,7 @@
|
||||
"aws-sdk": "^2.607.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"recursive-readdir": "2.2.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -29,14 +29,8 @@ export default class S3PackageManager implements ILocalPackageManager {
|
||||
this.config = config;
|
||||
this.packageName = packageName;
|
||||
this.logger = logger;
|
||||
const {
|
||||
endpoint,
|
||||
region,
|
||||
s3ForcePathStyle,
|
||||
accessKeyId,
|
||||
secretAccessKey,
|
||||
sessionToken,
|
||||
} = config;
|
||||
const { endpoint, region, s3ForcePathStyle, accessKeyId, secretAccessKey, sessionToken } =
|
||||
config;
|
||||
|
||||
this.s3 = new S3({
|
||||
endpoint,
|
||||
@@ -172,7 +166,7 @@ export default class S3PackageManager implements ILocalPackageManager {
|
||||
this.s3,
|
||||
{
|
||||
Bucket: this.config.bucket,
|
||||
Prefix: `${this.packagePath}`,
|
||||
Prefix: addTrailingSlash(this.packagePath),
|
||||
},
|
||||
function (err) {
|
||||
if (err && is404Error(err as VerdaccioError)) {
|
||||
|
||||
@@ -79,7 +79,7 @@ describe.skip('S3 package manager', () => {
|
||||
|
||||
describe('savePackage() group', () => {
|
||||
test('savePackage()', (done) => {
|
||||
const data = ('{data:5}' as unknown) as Package;
|
||||
const data = '{data:5}' as unknown as Package;
|
||||
const packageManager = new S3PackageManager(config, 'first-package', logger);
|
||||
|
||||
packageManager.savePackage('pkg.1.0.0.tar.gz', data, (err) => {
|
||||
|
||||
@@ -231,7 +231,7 @@ describe('S3PackageManager with mocked s3', function () {
|
||||
expect(mockListObject).toHaveBeenCalledWith(
|
||||
{
|
||||
Bucket: 'test-bucket',
|
||||
Prefix: 'testKeyPrefix/@company/test-package',
|
||||
Prefix: 'testKeyPrefix/@company/test-package/',
|
||||
},
|
||||
expect.any(Function)
|
||||
);
|
||||
@@ -270,7 +270,7 @@ describe('S3PackageManager with mocked s3', function () {
|
||||
expect(mockListObject).toHaveBeenCalledWith(
|
||||
{
|
||||
Bucket: 'test-bucket',
|
||||
Prefix: 'testKeyPrefix/customFolder/@company/test-package',
|
||||
Prefix: 'testKeyPrefix/customFolder/@company/test-package/',
|
||||
},
|
||||
expect.any(Function)
|
||||
);
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"@verdaccio/streams": "workspace:11.0.0-alpha.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"memory-fs": "0.5.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
||||
@@ -118,14 +118,12 @@ class GoogleCloudDatabase implements IPluginStorage<VerdaccioConfigGoogleStorage
|
||||
// "{\"secret\":\"181bc38698078f880564be1e4d7ec107ac8a3b344a924c6d86cea4a84a885ae0\"}"
|
||||
return entities.secret;
|
||||
})
|
||||
.catch(
|
||||
(err: Error): Promise<string> => {
|
||||
const error: VerdaccioError = getInternalError(err.message);
|
||||
.catch((err: Error): Promise<string> => {
|
||||
const error: VerdaccioError = getInternalError(err.message);
|
||||
|
||||
this.logger.warn({ error }, 'gcloud: [datastore getSecret] init error @{error}');
|
||||
return Promise.reject(getServiceUnavailable('[getSecret] permissions error'));
|
||||
}
|
||||
);
|
||||
this.logger.warn({ error }, 'gcloud: [datastore getSecret] init error @{error}');
|
||||
return Promise.reject(getServiceUnavailable('[getSecret] permissions error'));
|
||||
});
|
||||
}
|
||||
|
||||
public setSecret(secret: string): Promise<CommitResponse> {
|
||||
@@ -194,17 +192,15 @@ class GoogleCloudDatabase implements IPluginStorage<VerdaccioConfigGoogleStorage
|
||||
// };
|
||||
this.helper
|
||||
.getEntities(this.kind)
|
||||
.then(
|
||||
async (entities: any): Promise<void> => {
|
||||
for (const item of entities) {
|
||||
if (item.name === name) {
|
||||
await this._deleteItem(name, item);
|
||||
// deletedItems.push(deletedItem);
|
||||
}
|
||||
.then(async (entities: any): Promise<void> => {
|
||||
for (const item of entities) {
|
||||
if (item.name === name) {
|
||||
await this._deleteItem(name, item);
|
||||
// deletedItems.push(deletedItem);
|
||||
}
|
||||
cb(null);
|
||||
}
|
||||
)
|
||||
cb(null);
|
||||
})
|
||||
.catch((err: Error): void => {
|
||||
cb(getInternalError(err.message));
|
||||
});
|
||||
|
||||
@@ -90,16 +90,14 @@ class GoogleCloudStorageHandler implements IPackageStorageManager {
|
||||
onEnd(getInternalError(err.message));
|
||||
}
|
||||
)
|
||||
.catch(
|
||||
(err: Error): Callback => {
|
||||
this.logger.error(
|
||||
{ name, error: err },
|
||||
'gcloud: trying to update @{name} and was not found on storage err: @{error}'
|
||||
);
|
||||
// @ts-ignore
|
||||
return onEnd(getNotFound());
|
||||
}
|
||||
);
|
||||
.catch((err: Error): Callback => {
|
||||
this.logger.error(
|
||||
{ name, error: err },
|
||||
'gcloud: trying to update @{name} and was not found on storage err: @{error}'
|
||||
);
|
||||
// @ts-ignore
|
||||
return onEnd(getNotFound());
|
||||
});
|
||||
}
|
||||
|
||||
public deletePackage(fileName: string, cb: CallbackAction): void {
|
||||
@@ -197,28 +195,26 @@ class GoogleCloudStorageHandler implements IPackageStorageManager {
|
||||
|
||||
/* eslint-disable no-async-promise-executor */
|
||||
private _savePackage(name: string, metadata: Package): Promise<null | VerdaccioError> {
|
||||
return new Promise(
|
||||
async (resolve, reject): Promise<void> => {
|
||||
const file = this.helper.buildFilePath(name, pkgFileName);
|
||||
try {
|
||||
await file.save(this._convertToString(metadata), {
|
||||
validation: this.config.validation || defaultValidation,
|
||||
/**
|
||||
* When resumable is `undefined` - it will default to `true`as
|
||||
* per GC Storage documentation:
|
||||
* `Resumable uploads are automatically enabled and must be shut
|
||||
* off explicitly by setting options.resumable to false`
|
||||
* @see
|
||||
* https://cloud.google.com/nodejs/docs/reference/storage/2.5.x/File#createWriteStream
|
||||
*/
|
||||
resumable: this.config.resumable,
|
||||
});
|
||||
resolve(null);
|
||||
} catch (err) {
|
||||
reject(getInternalError(err.message));
|
||||
}
|
||||
return new Promise(async (resolve, reject): Promise<void> => {
|
||||
const file = this.helper.buildFilePath(name, pkgFileName);
|
||||
try {
|
||||
await file.save(this._convertToString(metadata), {
|
||||
validation: this.config.validation || defaultValidation,
|
||||
/**
|
||||
* When resumable is `undefined` - it will default to `true`as
|
||||
* per GC Storage documentation:
|
||||
* `Resumable uploads are automatically enabled and must be shut
|
||||
* off explicitly by setting options.resumable to false`
|
||||
* @see
|
||||
* https://cloud.google.com/nodejs/docs/reference/storage/2.5.x/File#createWriteStream
|
||||
*/
|
||||
resumable: this.config.resumable,
|
||||
});
|
||||
resolve(null);
|
||||
} catch (err) {
|
||||
reject(getInternalError(err.message));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
/* eslint-enable no-async-promise-executor */
|
||||
|
||||
@@ -244,48 +240,44 @@ class GoogleCloudStorageHandler implements IPackageStorageManager {
|
||||
|
||||
/* eslint-disable no-async-promise-executor */
|
||||
private _fileExist(name: string, fileName: string): Promise<boolean> {
|
||||
return new Promise(
|
||||
async (resolve, reject): Promise<void> => {
|
||||
const file: File = this.helper.buildFilePath(name, fileName);
|
||||
try {
|
||||
// @ts-ignore
|
||||
const data = await file.exists();
|
||||
const exist = data[0];
|
||||
return new Promise(async (resolve, reject): Promise<void> => {
|
||||
const file: File = this.helper.buildFilePath(name, fileName);
|
||||
try {
|
||||
// @ts-ignore
|
||||
const data = await file.exists();
|
||||
const exist = data[0];
|
||||
|
||||
resolve(exist);
|
||||
this.logger.debug(
|
||||
{ name: name, exist },
|
||||
'gcloud: check whether @{name} exist successfully: @{exist}'
|
||||
);
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
{ name: file.name, err: err.message },
|
||||
'gcloud: check exist package @{name} has failed, cause: @{err}'
|
||||
);
|
||||
resolve(exist);
|
||||
this.logger.debug(
|
||||
{ name: name, exist },
|
||||
'gcloud: check whether @{name} exist successfully: @{exist}'
|
||||
);
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
{ name: file.name, err: err.message },
|
||||
'gcloud: check exist package @{name} has failed, cause: @{err}'
|
||||
);
|
||||
|
||||
reject(getInternalError(err.message));
|
||||
}
|
||||
reject(getInternalError(err.message));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private async _readPackage(name: string): Promise<Package> {
|
||||
return new Promise(
|
||||
async (resolve, reject): Promise<void> => {
|
||||
const file = this.helper.buildFilePath(name, pkgFileName);
|
||||
return new Promise(async (resolve, reject): Promise<void> => {
|
||||
const file = this.helper.buildFilePath(name, pkgFileName);
|
||||
|
||||
try {
|
||||
const content: DownloadResponse = await file.download();
|
||||
this.logger.debug({ name: this.name }, 'gcloud: @{name} was found on storage');
|
||||
const response: Package = JSON.parse(content[0].toString('utf8'));
|
||||
try {
|
||||
const content: DownloadResponse = await file.download();
|
||||
this.logger.debug({ name: this.name }, 'gcloud: @{name} was found on storage');
|
||||
const response: Package = JSON.parse(content[0].toString('utf8'));
|
||||
|
||||
resolve(response);
|
||||
} catch (err) {
|
||||
this.logger.debug({ name: this.name }, 'gcloud: @{name} package not found on storage');
|
||||
reject(getNotFound());
|
||||
}
|
||||
resolve(response);
|
||||
} catch (err) {
|
||||
this.logger.debug({ name: this.name }, 'gcloud: @{name} package not found on storage');
|
||||
reject(getNotFound());
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
/* eslint-disable no-async-promise-executor */
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"memfs": "3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
|
||||
@@ -1,5 +1,50 @@
|
||||
# @verdaccio/ui-theme
|
||||
|
||||
## 6.0.0-6-next.8
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 0da7031e: allow disable login on ui and endpoints
|
||||
|
||||
To be able disable the login, set `login: false`, anything else would enable login. This flag will disable access via UI and web endpoints.
|
||||
|
||||
```yml
|
||||
web:
|
||||
title: verdaccio
|
||||
login: false
|
||||
```
|
||||
|
||||
## 6.0.0-6-next.7
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- aecbd226: web: allow ui hide package managers on sidebar
|
||||
|
||||
If there is a package manager of preference over others, you can define the package managers to be displayed on the detail page and sidebar, just define in the `config.yaml` and web section the list of package managers to be displayed.
|
||||
|
||||
```
|
||||
web:
|
||||
title: Verdaccio
|
||||
sort_packages: asc
|
||||
primary_color: #cccccc
|
||||
pkgManagers:
|
||||
- pnpm
|
||||
- yarn
|
||||
# - npm
|
||||
```
|
||||
|
||||
To disable all package managers, just define empty:
|
||||
|
||||
```
|
||||
web:
|
||||
title: Verdaccio
|
||||
sort_packages: asc
|
||||
primary_color: #cccccc
|
||||
pkgManagers:
|
||||
```
|
||||
|
||||
and the section would be hidden.
|
||||
|
||||
## 6.0.0-6-next.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -15,6 +15,7 @@ global.__VERDACCIO_BASENAME_UI_OPTIONS = {
|
||||
darkMode: false,
|
||||
language: 'en-US',
|
||||
uri: 'http://localhost:4873',
|
||||
pkgManagers: ['pnpm', 'yarn', 'npm'],
|
||||
title: 'Verdaccio Dev UI',
|
||||
scope: '',
|
||||
version: 'v1.0.0',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/ui-theme",
|
||||
"version": "6.0.0-6-next.6",
|
||||
"version": "6.0.0-6-next.8",
|
||||
"description": "Verdaccio User Interface",
|
||||
"author": {
|
||||
"name": "Verdaccio Core Team",
|
||||
@@ -29,7 +29,7 @@
|
||||
"@testing-library/dom": "^7.29.0",
|
||||
"@testing-library/jest-dom": "^5.11.6",
|
||||
"@testing-library/react": "10.4.9",
|
||||
"@verdaccio/node-api": "workspace:6.0.0-6-next.13",
|
||||
"@verdaccio/node-api": "workspace:6.0.0-6-next.17",
|
||||
"autosuggest-highlight": "3.1.1",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
render,
|
||||
fireEvent,
|
||||
waitFor,
|
||||
screen,
|
||||
waitForElementToBeRemoved,
|
||||
} from 'verdaccio-ui/utils/test-react-testing-library';
|
||||
|
||||
@@ -23,7 +24,7 @@ const props = {
|
||||
/* eslint-disable react/jsx-no-bind*/
|
||||
describe('<Header /> component with logged in state', () => {
|
||||
test('should load the component in logged out state', () => {
|
||||
const { container, queryByTestId, getByText } = render(
|
||||
render(
|
||||
<Router>
|
||||
<AppContextProvider>
|
||||
<Header />
|
||||
@@ -31,13 +32,13 @@ describe('<Header /> component with logged in state', () => {
|
||||
</Router>
|
||||
);
|
||||
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
expect(queryByTestId('header--menu-accountcircle')).toBeNull();
|
||||
expect(getByText('Login')).toBeTruthy();
|
||||
expect(screen.queryByTestId('header--menu-accountcircle')).toBeNull();
|
||||
expect(screen.getByText('Login')).toBeTruthy();
|
||||
expect(screen.queryByTestId('header--button-login')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should load the component in logged in state', () => {
|
||||
const { container, getByTestId, queryByText } = render(
|
||||
const { getByTestId, queryByText } = render(
|
||||
<Router>
|
||||
<AppContextProvider user={props.user}>
|
||||
<Header />
|
||||
@@ -45,7 +46,6 @@ describe('<Header /> component with logged in state', () => {
|
||||
</Router>
|
||||
);
|
||||
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
expect(getByTestId('header--menu-accountcircle')).toBeTruthy();
|
||||
expect(queryByText('Login')).toBeNull();
|
||||
});
|
||||
@@ -137,5 +137,22 @@ describe('<Header /> component with logged in state', () => {
|
||||
expect(hasRegistrationInfoModalBeenRemoved).not.toBeDefined();
|
||||
});
|
||||
|
||||
test('should hide login if is disabled', () => {
|
||||
// @ts-expect-error
|
||||
window.__VERDACCIO_BASENAME_UI_OPTIONS = {
|
||||
base: 'foo',
|
||||
login: false,
|
||||
};
|
||||
render(
|
||||
<Router>
|
||||
<AppContextProvider user={props.user}>
|
||||
<Header />
|
||||
</AppContextProvider>
|
||||
</Router>
|
||||
);
|
||||
|
||||
expect(screen.queryByTestId('header--button-login')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test.todo('autocompletion should display suggestions according to the type value');
|
||||
});
|
||||
|
||||
@@ -49,6 +49,7 @@ const Header: React.FC<Props> = ({ withoutSearch }) => {
|
||||
<InnerNavBar>
|
||||
<HeaderLeft />
|
||||
<HeaderRight
|
||||
hasLogin={configOptions?.login}
|
||||
onLogout={handleLogout}
|
||||
onOpenRegistryInfoDialog={() => setOpenInfoDialog(true)}
|
||||
onToggleLogin={() => setShowLoginModal(!showLoginModal)}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { RightSide } from './styles';
|
||||
interface Props {
|
||||
withoutSearch?: boolean;
|
||||
username?: string | null;
|
||||
hasLogin?: boolean;
|
||||
onToggleLogin: () => void;
|
||||
onOpenRegistryInfoDialog: () => void;
|
||||
onToggleMobileNav: () => void;
|
||||
@@ -22,6 +23,7 @@ const HeaderRight: React.FC<Props> = ({
|
||||
withoutSearch = false,
|
||||
username,
|
||||
onToggleLogin,
|
||||
hasLogin,
|
||||
onLogout,
|
||||
onToggleMobileNav,
|
||||
onOpenRegistryInfoDialog,
|
||||
@@ -29,6 +31,7 @@ const HeaderRight: React.FC<Props> = ({
|
||||
const themeContext = useContext(ThemeContext);
|
||||
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
||||
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
|
||||
const hideLoginSection = hasLogin === false;
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -90,19 +93,23 @@ const HeaderRight: React.FC<Props> = ({
|
||||
tooltipIconType={themeContext.isDarkMode ? 'dark-mode' : 'light-mode'}
|
||||
/>
|
||||
|
||||
{username ? (
|
||||
<HeaderMenu
|
||||
anchorEl={anchorEl}
|
||||
isMenuOpen={isMenuOpen}
|
||||
onLoggedInMenu={handleLoggedInMenu}
|
||||
onLoggedInMenuClose={handleLoggedInMenuClose}
|
||||
onLogout={onLogout}
|
||||
username={username}
|
||||
/>
|
||||
) : (
|
||||
<Button color="inherit" data-testid="header--button-login" onClick={handleToggleLogin}>
|
||||
{t('button.login')}
|
||||
</Button>
|
||||
{!hideLoginSection && (
|
||||
<>
|
||||
{username ? (
|
||||
<HeaderMenu
|
||||
anchorEl={anchorEl}
|
||||
isMenuOpen={isMenuOpen}
|
||||
onLoggedInMenu={handleLoggedInMenu}
|
||||
onLoggedInMenuClose={handleLoggedInMenuClose}
|
||||
onLogout={onLogout}
|
||||
username={username}
|
||||
/>
|
||||
) : (
|
||||
<Button color="inherit" data-testid="header--button-login" onClick={handleToggleLogin}>
|
||||
{t('button.login')}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</RightSide>
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,7 @@ const ActionBar: React.FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Box alignItems="center" display="flex" marginBottom="8px">
|
||||
<Box alignItems="center" display="flex" marginBottom="14px">
|
||||
{actions.map((action) => (
|
||||
<ActionBarAction key={action.link} {...action} />
|
||||
))}
|
||||
|
||||
@@ -21,8 +21,13 @@ export interface FilterOptionsState<Option> {
|
||||
}
|
||||
|
||||
function createFilterOptions(config?: CreateFilterOptionsConfig) {
|
||||
const { ignoreAccents = true, ignoreCase = true, trim = false, limit, matchFrom = 'any' } =
|
||||
config || {};
|
||||
const {
|
||||
ignoreAccents = true,
|
||||
ignoreCase = true,
|
||||
trim = false,
|
||||
limit,
|
||||
matchFrom = 'any',
|
||||
} = config || {};
|
||||
|
||||
return <Option extends {}>(
|
||||
options: Option[],
|
||||
|
||||
@@ -6,9 +6,10 @@ import { Theme } from './theme';
|
||||
const resetStyles = makeStyles(({ theme }: { theme?: Theme }) => ({
|
||||
'@global': {
|
||||
// eslint-disable-next-line max-len
|
||||
'html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video': {
|
||||
fontFamily: '"Roboto", Helvetica Neue, Arial, sans-serif',
|
||||
},
|
||||
'html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video':
|
||||
{
|
||||
fontFamily: '"Roboto", Helvetica Neue, Arial, sans-serif',
|
||||
},
|
||||
strong: {
|
||||
fontWeight: theme && theme.fontWeight.semiBold,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { render } from 'verdaccio-ui/utils/test-react-testing-library';
|
||||
import { render, screen } from 'verdaccio-ui/utils/test-react-testing-library';
|
||||
|
||||
import { DetailContext } from '../../context';
|
||||
import { DetailContextProps } from '../../version-config';
|
||||
@@ -22,11 +22,14 @@ const ComponentToBeRendered: React.FC = () => (
|
||||
/* eslint-disable react/jsx-no-bind*/
|
||||
describe('<Install />', () => {
|
||||
test('renders correctly', () => {
|
||||
const { container } = render(<ComponentToBeRendered />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
render(<ComponentToBeRendered />);
|
||||
expect(screen.getByText('pnpm install foo')).toBeInTheDocument();
|
||||
expect(screen.getByText('yarn add foo')).toBeInTheDocument();
|
||||
expect(screen.getByText('npm install foo')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should have 3 children', () => {
|
||||
window.__VERDACCIO_BASENAME_UI_OPTIONS.pkgManagers = ['yarn', 'pnpm', 'npm'];
|
||||
const { getByTestId } = render(<ComponentToBeRendered />);
|
||||
const installListItems = getByTestId('installList');
|
||||
// installitems + subHeader = 4
|
||||
@@ -34,13 +37,17 @@ describe('<Install />', () => {
|
||||
});
|
||||
|
||||
test('should have the element NPM', () => {
|
||||
window.__VERDACCIO_BASENAME_UI_OPTIONS.pkgManagers = ['npm'];
|
||||
const { getByTestId, queryByText } = render(<ComponentToBeRendered />);
|
||||
expect(getByTestId('installListItem-npm')).toBeTruthy();
|
||||
expect(queryByText(`npm install ${detailContextValue.packageName}`)).toBeTruthy();
|
||||
expect(queryByText('Install using npm')).toBeTruthy();
|
||||
expect(screen.queryByText('pnpm install foo')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('yarn add foo')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should have the element YARN', () => {
|
||||
window.__VERDACCIO_BASENAME_UI_OPTIONS.pkgManagers = ['yarn'];
|
||||
const { getByTestId, queryByText } = render(<ComponentToBeRendered />);
|
||||
expect(getByTestId('installListItem-yarn')).toBeTruthy();
|
||||
expect(queryByText(`yarn add ${detailContextValue.packageName}`)).toBeTruthy();
|
||||
@@ -48,6 +55,7 @@ describe('<Install />', () => {
|
||||
});
|
||||
|
||||
test('should have the element PNPM', () => {
|
||||
window.__VERDACCIO_BASENAME_UI_OPTIONS.pkgManagers = ['pnpm'];
|
||||
const { getByTestId, queryByText } = render(<ComponentToBeRendered />);
|
||||
expect(getByTestId('installListItem-pnpm')).toBeTruthy();
|
||||
expect(queryByText(`pnpm install ${detailContextValue.packageName}`)).toBeTruthy();
|
||||
|
||||
@@ -5,18 +5,20 @@ import { useTranslation } from 'react-i18next';
|
||||
import List from 'verdaccio-ui/components/List';
|
||||
import Text from 'verdaccio-ui/components/Text';
|
||||
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
||||
import { useConfig } from 'verdaccio-ui/providers/config';
|
||||
|
||||
import { DetailContext } from '../..';
|
||||
|
||||
import InstallListItem, { DependencyManager } from './InstallListItem';
|
||||
|
||||
const StyledText = styled(Text)<{ theme?: Theme }>((props) => ({
|
||||
fontWeight: props.theme && props.theme.fontWeight.bold,
|
||||
fontWeight: props.theme?.fontWeight.bold,
|
||||
textTransform: 'capitalize',
|
||||
}));
|
||||
|
||||
const Install: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const { configOptions } = useConfig();
|
||||
const detailContext = useContext(DetailContext);
|
||||
|
||||
const { packageMeta, packageName } = detailContext;
|
||||
@@ -25,15 +27,26 @@ const Install: React.FC = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
const hasNpm = configOptions?.pkgManagers?.includes('npm');
|
||||
const hasYarn = configOptions?.pkgManagers?.includes('yarn');
|
||||
const hasPnpm = configOptions?.pkgManagers?.includes('pnpm') ?? true;
|
||||
const hasPkgManagers = hasNpm | hasPnpm | hasYarn;
|
||||
|
||||
return hasPkgManagers ? (
|
||||
<List
|
||||
data-testid={'installList'}
|
||||
subheader={<StyledText variant={'subtitle1'}>{t('sidebar.installation.title')}</StyledText>}>
|
||||
<InstallListItem dependencyManager={DependencyManager.NPM} packageName={packageName} />
|
||||
<InstallListItem dependencyManager={DependencyManager.YARN} packageName={packageName} />
|
||||
<InstallListItem dependencyManager={DependencyManager.PNPM} packageName={packageName} />
|
||||
{hasNpm && (
|
||||
<InstallListItem dependencyManager={DependencyManager.NPM} packageName={packageName} />
|
||||
)}
|
||||
{hasYarn && (
|
||||
<InstallListItem dependencyManager={DependencyManager.YARN} packageName={packageName} />
|
||||
)}
|
||||
{hasPnpm && (
|
||||
<InstallListItem dependencyManager={DependencyManager.PNPM} packageName={packageName} />
|
||||
)}
|
||||
</List>
|
||||
);
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default Install;
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Install /> renders correctly 1`] = `
|
||||
.emotion-0 {
|
||||
font-weight: 700;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.emotion-2 {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.emotion-2:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.emotion-4 {
|
||||
border-radius: 0px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.emotion-4 img {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.emotion-6 {
|
||||
padding: 0 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.emotion-8 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.emotion-10 {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
height: 21px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
<ul
|
||||
class="MuiList-root MuiList-padding MuiList-subheader"
|
||||
data-testid="installList"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root emotion-0 emotion-1 MuiTypography-subtitle1"
|
||||
>
|
||||
Installation
|
||||
</span>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiListItem-root emotion-2 emotion-3 MuiListItem-gutters MuiListItem-button"
|
||||
data-testid="installListItem-npm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiAvatar-root MuiAvatar-circle emotion-4 emotion-5"
|
||||
>
|
||||
<img
|
||||
alt="npm"
|
||||
class="MuiAvatar-img"
|
||||
src="[object Object]"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="MuiListItemText-root emotion-6 emotion-7 MuiListItemText-multiline"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
>
|
||||
<div
|
||||
class="emotion-8 emotion-9"
|
||||
>
|
||||
<span
|
||||
class="emotion-10 emotion-11"
|
||||
>
|
||||
npm install foo
|
||||
</span>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiIconButton-root"
|
||||
data-testid="copy-icon"
|
||||
tabindex="0"
|
||||
title="Copy to clipboard"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiIconButton-label"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</span>
|
||||
<p
|
||||
class="MuiTypography-root MuiListItemText-secondary MuiTypography-body2 MuiTypography-colorTextSecondary MuiTypography-displayBlock"
|
||||
>
|
||||
Install using npm
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiListItem-root emotion-2 emotion-3 MuiListItem-gutters MuiListItem-button"
|
||||
data-testid="installListItem-yarn"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiAvatar-root MuiAvatar-circle emotion-4 emotion-5"
|
||||
>
|
||||
<img
|
||||
alt="yarn"
|
||||
class="MuiAvatar-img"
|
||||
src="[object Object]"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="MuiListItemText-root emotion-6 emotion-7 MuiListItemText-multiline"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
>
|
||||
<div
|
||||
class="emotion-8 emotion-9"
|
||||
>
|
||||
<span
|
||||
class="emotion-10 emotion-11"
|
||||
>
|
||||
yarn add foo
|
||||
</span>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiIconButton-root"
|
||||
data-testid="copy-icon"
|
||||
tabindex="0"
|
||||
title="Copy to clipboard"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiIconButton-label"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</span>
|
||||
<p
|
||||
class="MuiTypography-root MuiListItemText-secondary MuiTypography-body2 MuiTypography-colorTextSecondary MuiTypography-displayBlock"
|
||||
>
|
||||
Install using yarn
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiListItem-root emotion-2 emotion-3 MuiListItem-gutters MuiListItem-button"
|
||||
data-testid="installListItem-pnpm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiAvatar-root MuiAvatar-circle emotion-4 emotion-5"
|
||||
>
|
||||
<img
|
||||
alt="pnpm"
|
||||
class="MuiAvatar-img"
|
||||
src="[object Object]"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="MuiListItemText-root emotion-6 emotion-7 MuiListItemText-multiline"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
>
|
||||
<div
|
||||
class="emotion-8 emotion-9"
|
||||
>
|
||||
<span
|
||||
class="emotion-10 emotion-11"
|
||||
>
|
||||
pnpm install foo
|
||||
</span>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiIconButton-root"
|
||||
data-testid="copy-icon"
|
||||
tabindex="0"
|
||||
title="Copy to clipboard"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiIconButton-label"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</span>
|
||||
<p
|
||||
class="MuiTypography-root MuiListItemText-secondary MuiTypography-body2 MuiTypography-colorTextSecondary MuiTypography-displayBlock"
|
||||
>
|
||||
Install using pnpm
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</div>
|
||||
</ul>
|
||||
`;
|
||||
@@ -22,18 +22,8 @@ const cache = new CellMeasurerCache({
|
||||
/* eslint-disable verdaccio/jsx-no-style */
|
||||
const PackageList: React.FC<Props> = ({ packages }) => {
|
||||
const renderRow = ({ index, key, parent, style }: ListRowProps) => {
|
||||
const {
|
||||
name,
|
||||
version,
|
||||
description,
|
||||
time,
|
||||
keywords,
|
||||
dist,
|
||||
homepage,
|
||||
bugs,
|
||||
author,
|
||||
license,
|
||||
} = packages[index];
|
||||
const { name, version, description, time, keywords, dist, homepage, bugs, author, license } =
|
||||
packages[index];
|
||||
// TODO: move format license to API side.
|
||||
const formattedLicense = formatLicense(license);
|
||||
|
||||
|
||||
@@ -1,26 +1,12 @@
|
||||
import { TemplateUIOptions } from '@verdaccio/types';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import isNil from 'lodash/isNil';
|
||||
import React, { createContext, FunctionComponent, useContext, useMemo, useState } from 'react';
|
||||
|
||||
import { PRIMARY_COLOR } from 'verdaccio-ui/utils/colors';
|
||||
|
||||
export type VerdaccioOptions = {
|
||||
url_prefix: string;
|
||||
base: string;
|
||||
scope: string;
|
||||
title: string;
|
||||
primaryColor: string;
|
||||
darkMode: boolean;
|
||||
uri?: string;
|
||||
language?: string;
|
||||
version?: string;
|
||||
protocol?: string;
|
||||
host?: string;
|
||||
logo?: string;
|
||||
};
|
||||
|
||||
type ConfigProviderProps = {
|
||||
configOptions: VerdaccioOptions;
|
||||
configOptions: TemplateUIOptions;
|
||||
setConfigOptions: Function;
|
||||
};
|
||||
|
||||
@@ -28,8 +14,10 @@ const defaultValues: ConfigProviderProps = {
|
||||
configOptions: {
|
||||
primaryColor: PRIMARY_COLOR,
|
||||
darkMode: false,
|
||||
pkgManagers: ['yarn', 'pnpm', 'npm'],
|
||||
scope: '',
|
||||
base: '',
|
||||
login: true,
|
||||
url_prefix: '',
|
||||
title: 'Verdaccio',
|
||||
},
|
||||
@@ -59,7 +47,6 @@ const AppConfigurationProvider: FunctionComponent = ({ children }) => {
|
||||
[configOptions]
|
||||
);
|
||||
|
||||
// @ts-ignore
|
||||
return (
|
||||
<AppConfigurationContext.Provider value={value}>{children}</AppConfigurationContext.Provider>
|
||||
);
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { SyntheticEvent } from 'react';
|
||||
|
||||
export const copyToClipBoardUtility = (str: string): ((e: SyntheticEvent<HTMLElement>) => void) => (
|
||||
event: SyntheticEvent<HTMLElement>
|
||||
): void => {
|
||||
event.preventDefault();
|
||||
export const copyToClipBoardUtility =
|
||||
(str: string): ((e: SyntheticEvent<HTMLElement>) => void) =>
|
||||
(event: SyntheticEvent<HTMLElement>): void => {
|
||||
event.preventDefault();
|
||||
|
||||
const node = document.createElement('div');
|
||||
node.innerText = str;
|
||||
if (document.body) {
|
||||
document.body.appendChild(node);
|
||||
const node = document.createElement('div');
|
||||
node.innerText = str;
|
||||
if (document.body) {
|
||||
document.body.appendChild(node);
|
||||
|
||||
const range = document.createRange();
|
||||
const selection = window.getSelection() as Selection;
|
||||
range.selectNodeContents(node);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(node);
|
||||
}
|
||||
};
|
||||
const range = document.createRange();
|
||||
const selection = window.getSelection() as Selection;
|
||||
range.selectNodeContents(node);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(node);
|
||||
}
|
||||
};
|
||||
|
||||
export function getCLISetConfigRegistry(
|
||||
command: string,
|
||||
|
||||
@@ -2,6 +2,10 @@ web:
|
||||
title: Verdaccio Local Dev
|
||||
sort_packages: asc
|
||||
primary_color: #CCC
|
||||
login: true
|
||||
pkgManagers:
|
||||
- npm
|
||||
- yarn
|
||||
|
||||
plugins: ../
|
||||
|
||||
|
||||
@@ -8,10 +8,11 @@ import config from './webpack.dev.config.babel';
|
||||
|
||||
const compiler = webpack(config);
|
||||
const spinner = ora('Compiler is running...').start();
|
||||
const port = 4873;
|
||||
compiler.hooks.done.tap('Verdaccio Dev Server', () => {
|
||||
if (!global.rebuild) {
|
||||
spinner.stop();
|
||||
console.log('Dev Server Listening at http://localhost:4873/');
|
||||
console.log(`Dev Server Listening at http://localhost:${port}/`);
|
||||
global.rebuild = true;
|
||||
}
|
||||
});
|
||||
@@ -40,7 +41,7 @@ new WebpackDevServer(compiler, {
|
||||
target: 'http://localhost:8000',
|
||||
},
|
||||
],
|
||||
}).listen(4873, 'localhost', function (err) {
|
||||
}).listen(port, 'localhost', function (err) {
|
||||
if (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import FriendlyErrorsPlugin from 'friendly-errors-webpack-plugin';
|
||||
import HTMLWebpackPlugin from 'html-webpack-plugin';
|
||||
import yalm from 'js-yaml';
|
||||
import StyleLintPlugin from 'stylelint-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
|
||||
@@ -8,6 +11,7 @@ import env from '../config/env';
|
||||
import getPackageJson from './getPackageJson';
|
||||
import baseConfig from './webpack.config';
|
||||
|
||||
const configJsonFormat = yalm.safeLoad(fs.readFileSync('./tools/_verdaccio.config.yaml', 'utf8'));
|
||||
export default {
|
||||
...baseConfig,
|
||||
mode: 'development',
|
||||
@@ -35,8 +39,7 @@ export default {
|
||||
}),
|
||||
new HTMLWebpackPlugin({
|
||||
__UI_OPTIONS: JSON.stringify({
|
||||
title: 'Verdaccio Dev UI',
|
||||
scope: '',
|
||||
...configJsonFormat.web,
|
||||
filename: 'index.html',
|
||||
verdaccioURL: '//localhost:4873',
|
||||
base: new URL('/', 'http://localhost:4873'),
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
// FIXME: this should comes from @verdaccio/types
|
||||
|
||||
type PackageManagers = 'pnpm' | 'yarn' | 'npm';
|
||||
export interface VerdaccioOptions {
|
||||
// @deprecated
|
||||
url_prefix: string;
|
||||
// @deprecated
|
||||
base: string;
|
||||
basePath: string;
|
||||
basename: string;
|
||||
scope: string;
|
||||
title: string;
|
||||
primaryColor: string;
|
||||
darkMode: boolean;
|
||||
uri?: string;
|
||||
login?: boolean;
|
||||
language?: string;
|
||||
darkMode?: boolean;
|
||||
version?: string;
|
||||
protocol?: string;
|
||||
host?: string;
|
||||
logo?: string;
|
||||
pkgManagers?: PackageManagers[];
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @verdaccio/proxy
|
||||
|
||||
## 6.0.0-6-next.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d2c65da9]
|
||||
- @verdaccio/utils@6.0.0-6-next.5
|
||||
- @verdaccio/config@6.0.0-6-next.7
|
||||
|
||||
## 6.0.0-6-next.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/proxy",
|
||||
"version": "6.0.0-6-next.8",
|
||||
"version": "6.0.0-6-next.9",
|
||||
"description": "verdaccio proxy fetcher",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -40,17 +40,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/local-storage": "workspace:11.0.0-6-next.6",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/streams": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.4",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.5",
|
||||
"JSONStream": "1.3.5",
|
||||
"lodash": "^4.17.20",
|
||||
"lodash": "4.17.20",
|
||||
"request": "2.87.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.5"
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"nock": "13.0.11",
|
||||
"node-mocks-http": "1.10.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user