Compare commits
50 Commits
@verdaccio
...
@verdaccio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b970102bfc | ||
|
|
b702ea3631 | ||
|
|
794af76c50 | ||
|
|
6218d7723d | ||
|
|
b261741ef6 | ||
|
|
61add32bff | ||
|
|
b753b4010f | ||
|
|
c168b4e47a | ||
|
|
3a7f81ab0c | ||
|
|
154b2ecd34 | ||
|
|
cd7947adbc | ||
|
|
5fed1955a9 | ||
|
|
9dbf73e955 | ||
|
|
2c594910d8 | ||
|
|
90818700a3 | ||
|
|
7af1e6cc84 | ||
|
|
757bded72e | ||
|
|
1b9bf35c87 | ||
|
|
eb2afc4d6d | ||
|
|
5be013a059 | ||
|
|
8d6d6097c6 | ||
|
|
531289f59d | ||
|
|
5e784d1188 | ||
|
|
7dde848d0c | ||
|
|
71874de027 | ||
|
|
f13dacef9c | ||
|
|
761f1696f2 | ||
|
|
f412e8f8d6 | ||
|
|
f5fd7bf5bf | ||
|
|
3d26a8190c | ||
|
|
e50410a875 | ||
|
|
60d7b35d88 | ||
|
|
1042f9bf76 | ||
|
|
e10637f0f3 | ||
|
|
459b6fa72b | ||
|
|
10868ed434 | ||
|
|
ada8165f98 | ||
|
|
57755f31ba | ||
|
|
9e29bf8890 | ||
|
|
e2a67bafbe | ||
|
|
7c9561b019 | ||
|
|
ed3677a5b6 | ||
|
|
055544238a | ||
|
|
4937dba06e | ||
|
|
3e65791564 | ||
|
|
cf1b6cdb04 | ||
|
|
ca86082e08 | ||
|
|
ef60e83d6c | ||
|
|
ff1822c961 | ||
|
|
df0da3d699 |
2
.babelrc
2
.babelrc
@@ -7,7 +7,7 @@
|
||||
"version": 3, "proposals": true
|
||||
},
|
||||
"targets": {
|
||||
"node": 12
|
||||
"node": 14
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
59
.changeset/dry-planes-tap.md
Normal file
59
.changeset/dry-planes-tap.md
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
'@verdaccio/api': major
|
||||
'@verdaccio/auth': major
|
||||
'@verdaccio/cli': major
|
||||
'@verdaccio/config': major
|
||||
'@verdaccio/commons-api': major
|
||||
'@verdaccio/core': major
|
||||
'@verdaccio/local-storage': major
|
||||
'@verdaccio/fastify-migration': major
|
||||
'@verdaccio/streams': major
|
||||
'@verdaccio/types': major
|
||||
'@verdaccio/hooks': major
|
||||
'verdaccio-audit': major
|
||||
'verdaccio-aws-s3-storage': major
|
||||
'verdaccio-google-cloud': major
|
||||
'verdaccio-memory': major
|
||||
'@verdaccio/ui-theme': major
|
||||
'@verdaccio/proxy': major
|
||||
'@verdaccio/server': major
|
||||
'@verdaccio/store': major
|
||||
'@verdaccio/eslint-config': major
|
||||
'@verdaccio/dev-types': major
|
||||
'@verdaccio/utils': major
|
||||
'verdaccio': major
|
||||
'@verdaccio/web': major
|
||||
---
|
||||
|
||||
refactor: search v1 endpoint and local-database
|
||||
|
||||
- refactor search `api v1` endpoint, improve performance
|
||||
- remove usage of `async` dependency https://github.com/verdaccio/verdaccio/issues/1225
|
||||
- refactor method storage class
|
||||
- create new module `core` to reduce the ammount of modules with utilities
|
||||
- use `undici` instead `node-fetch`
|
||||
- use `fastify` instead `express` for functional test
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- plugin storage API changes
|
||||
- remove old search endpoint (return 404)
|
||||
- filter local private packages at plugin level
|
||||
|
||||
The storage api changes for methods `get`, `add`, `remove` as promise base. The `search` methods also changes and recieves a `query` object that contains all query params from the client.
|
||||
|
||||
```ts
|
||||
export interface IPluginStorage<T> extends IPlugin {
|
||||
add(name: string): Promise<void>;
|
||||
remove(name: string): Promise<void>;
|
||||
get(): Promise<any>;
|
||||
init(): Promise<void>;
|
||||
getSecret(): Promise<string>;
|
||||
setSecret(secret: string): Promise<any>;
|
||||
getPackageStorage(packageInfo: string): IPackageStorage;
|
||||
search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]>;
|
||||
saveToken(token: Token): Promise<any>;
|
||||
deleteToken(user: string, tokenKey: string): Promise<any>;
|
||||
readTokens(filter: TokenFilter): Promise<Token[]>;
|
||||
}
|
||||
```
|
||||
39
.changeset/eleven-spoons-matter.md
Normal file
39
.changeset/eleven-spoons-matter.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
'@verdaccio/api': major
|
||||
'@verdaccio/auth': major
|
||||
'@verdaccio/cli': major
|
||||
'@verdaccio/config': major
|
||||
'@verdaccio/core': major
|
||||
'@verdaccio/file-locking': major
|
||||
'verdaccio-htpasswd': major
|
||||
'@verdaccio/readme': major
|
||||
'@verdaccio/fastify-migration': major
|
||||
'@verdaccio/streams': major
|
||||
'@verdaccio/tarball': major
|
||||
'@verdaccio/types': major
|
||||
'@verdaccio/url': major
|
||||
'@verdaccio/hooks': major
|
||||
'@verdaccio/loaders': major
|
||||
'@verdaccio/logger': major
|
||||
'@verdaccio/middleware': major
|
||||
'@verdaccio/mock': major
|
||||
'@verdaccio/node-api': major
|
||||
'@verdaccio/active-directory': major
|
||||
'verdaccio-audit': major
|
||||
'verdaccio-auth-memory': major
|
||||
'verdaccio-aws-s3-storage': major
|
||||
'verdaccio-google-cloud': major
|
||||
'verdaccio-memory': major
|
||||
'@verdaccio/ui-theme': major
|
||||
'@verdaccio/server': major
|
||||
'@verdaccio/cli-standalone': major
|
||||
'@verdaccio/store': major
|
||||
'@verdaccio/dev-types': major
|
||||
'@verdaccio/utils': major
|
||||
'verdaccio': major
|
||||
'@verdaccio/web': major
|
||||
---
|
||||
|
||||
Remove Node 12 support
|
||||
|
||||
- We need move to the new `undici` and does not support Node.js 12
|
||||
10
.changeset/fuzzy-onions-draw.md
Normal file
10
.changeset/fuzzy-onions-draw.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
'@verdaccio/api': minor
|
||||
'@verdaccio/fastify-migration': minor
|
||||
'@verdaccio/hooks': minor
|
||||
'@verdaccio/logger-prettify': minor
|
||||
'@verdaccio/proxy': minor
|
||||
'@verdaccio/store': minor
|
||||
---
|
||||
|
||||
abort search request support for proxy
|
||||
5
.changeset/olive-candles-speak.md
Normal file
5
.changeset/olive-candles-speak.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@verdaccio/ui-theme': minor
|
||||
---
|
||||
|
||||
feat: integrate rematch for ui state storage
|
||||
35
.changeset/perfect-candles-clap.md
Normal file
35
.changeset/perfect-candles-clap.md
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
'@verdaccio/api': minor
|
||||
'@verdaccio/auth': minor
|
||||
'@verdaccio/cli': minor
|
||||
'@verdaccio/config': minor
|
||||
'@verdaccio/core': minor
|
||||
'verdaccio-htpasswd': minor
|
||||
'@verdaccio/local-storage': minor
|
||||
'@verdaccio/fastify-migration': minor
|
||||
'@verdaccio/tarball': minor
|
||||
'@verdaccio/types': minor
|
||||
'@verdaccio/url': minor
|
||||
'@verdaccio/hooks': minor
|
||||
'@verdaccio/loaders': minor
|
||||
'@verdaccio/logger': minor
|
||||
'@verdaccio/middleware': minor
|
||||
'@verdaccio/mock': minor
|
||||
'@verdaccio/node-api': minor
|
||||
'@verdaccio/active-directory': minor
|
||||
'verdaccio-auth-memory': minor
|
||||
'verdaccio-aws-s3-storage': minor
|
||||
'verdaccio-google-cloud': minor
|
||||
'verdaccio-memory': minor
|
||||
'@verdaccio/ui-theme': minor
|
||||
'@verdaccio/proxy': minor
|
||||
'@verdaccio/server': minor
|
||||
'@verdaccio/cli-standalone': minor
|
||||
'@verdaccio/store': minor
|
||||
'@verdaccio/utils': minor
|
||||
'verdaccio': minor
|
||||
'@verdaccio/web': minor
|
||||
'@verdaccio/e2e-ui': minor
|
||||
---
|
||||
|
||||
refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplications
|
||||
@@ -6,7 +6,6 @@
|
||||
"@verdaccio/auth": "6.0.0-alpha.0",
|
||||
"@verdaccio/cli": "6.0.0-alpha.0",
|
||||
"@verdaccio/config": "6.0.0-alpha.0",
|
||||
"@verdaccio/commons-api": "11.0.0-alpha.0",
|
||||
"@verdaccio/file-locking": "11.0.0-alpha.0",
|
||||
"verdaccio-htpasswd": "11.0.0-alpha.0",
|
||||
"@verdaccio/local-storage": "11.0.0-alpha.0",
|
||||
@@ -42,15 +41,20 @@
|
||||
"@verdaccio/fastify-migration": "6.0.0-6-next.9",
|
||||
"@verdaccio/eslint-config": "1.0.0",
|
||||
"@verdaccio/benchmark": "1.0.0",
|
||||
"@verdaccio/website": "5.1.3"
|
||||
"@verdaccio/website": "5.1.3",
|
||||
"@verdaccio/core": "6.0.0-next.0",
|
||||
"@verdaccio/helper": "1.0.0"
|
||||
},
|
||||
"changesets": [
|
||||
"afraid-mice-obey",
|
||||
"big-lobsters-sin",
|
||||
"calm-pants-impress",
|
||||
"dry-planes-tap",
|
||||
"eleven-spoons-matter",
|
||||
"few-cooks-destroy",
|
||||
"few-mangos-grow",
|
||||
"fifty-jars-rest",
|
||||
"fuzzy-onions-draw",
|
||||
"gentle-parrots-lay",
|
||||
"gentle-trains-switch",
|
||||
"gold-vans-tease",
|
||||
@@ -64,13 +68,17 @@
|
||||
"many-vans-care",
|
||||
"modern-spies-tell",
|
||||
"neat-toes-report",
|
||||
"olive-candles-speak",
|
||||
"perfect-candles-clap",
|
||||
"perfect-emus-clean",
|
||||
"perfect-kangaroos-agree",
|
||||
"plenty-news-remember",
|
||||
"plenty-spiders-melt",
|
||||
"plenty-tables-refuse",
|
||||
"pretty-hounds-tap",
|
||||
"proud-jeans-walk",
|
||||
"red-chefs-float",
|
||||
"shaggy-carrots-unite",
|
||||
"shiny-chefs-heal",
|
||||
"smart-apricots-kneel",
|
||||
"spicy-frogs-press",
|
||||
|
||||
10
.changeset/proud-jeans-walk.md
Normal file
10
.changeset/proud-jeans-walk.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
'verdaccio-htpasswd': patch
|
||||
'@verdaccio/local-storage': patch
|
||||
'@verdaccio/fastify-migration': patch
|
||||
'@verdaccio/hooks': patch
|
||||
'@verdaccio/mock': patch
|
||||
'@verdaccio/node-api': patch
|
||||
---
|
||||
|
||||
Added core-js missing from dependencies though referenced in .js sources
|
||||
5
.changeset/shaggy-carrots-unite.md
Normal file
5
.changeset/shaggy-carrots-unite.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@verdaccio/logger': patch
|
||||
---
|
||||
|
||||
do not show deprecation warning on default logger config
|
||||
@@ -9,3 +9,5 @@ static/
|
||||
website/
|
||||
wiki/
|
||||
dist/
|
||||
docs/
|
||||
test/functional/store/*
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -7,7 +7,7 @@ contact_links:
|
||||
url: https://github.com/verdaccio/verdaccio/security/policy
|
||||
about: I want to report a security vulnerability
|
||||
- name: Chat 🏘
|
||||
url: http://chat.verdaccio.org
|
||||
url: https://discord.gg/7qWJxBf
|
||||
about: For a quick question you should do it through our community chat
|
||||
- name: User Interface Report 👩🏼🎨👨🏼🎨
|
||||
url: https://github.com/verdaccio/ui/issues/new/choose
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name: ci - benchmark
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# 3 times day
|
||||
# collecting enough data to draw some graphics
|
||||
@@ -56,7 +57,8 @@ jobs:
|
||||
# - local
|
||||
- 3.13.1
|
||||
- 4.12.2
|
||||
- 5.1.2
|
||||
- 5.1.3
|
||||
- 6.0.0-6-next.24
|
||||
name: Benchmark autocannon
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -116,7 +118,8 @@ jobs:
|
||||
# old versions to compare same test along previous releases
|
||||
- 3.13.1
|
||||
- 4.12.2
|
||||
- 5.1.2
|
||||
- 5.1.3
|
||||
- 6.0.0-6-next.24
|
||||
name: Benchmark hyperfine
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
7
.github/workflows/changesets.yml
vendored
7
.github/workflows/changesets.yml
vendored
@@ -46,7 +46,12 @@ jobs:
|
||||
run: pnpm install
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.REGISTRY_AUTH_TOKEN }}
|
||||
|
||||
- name: crowdin download
|
||||
env:
|
||||
CROWDIN_VERDACCIO_PROJECT_ID: ${{ secrets.CROWDIN_VERDACCIO_PROJECT_ID }}
|
||||
CROWDIN_VERDACCIO_API_KEY: ${{ secrets.CROWDIN_VERDACCIO_API_KEY }}
|
||||
CONTEXT: production
|
||||
run: pnpm crowdin:download
|
||||
- name: build
|
||||
run: pnpm build
|
||||
|
||||
|
||||
49
.github/workflows/ci.yml
vendored
49
.github/workflows/ci.yml
vendored
@@ -83,6 +83,7 @@ jobs:
|
||||
run: pnpm recursive install --frozen-lockfile --ignore-scripts
|
||||
- name: Lint
|
||||
run: pnpm format:check
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
name: build
|
||||
@@ -101,6 +102,15 @@ jobs:
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
- name: Install
|
||||
run: pnpm recursive install --frozen-lockfile --ignore-scripts
|
||||
- name: crowdin download
|
||||
env:
|
||||
CROWDIN_VERDACCIO_PROJECT_ID: ${{ secrets.CROWDIN_VERDACCIO_PROJECT_ID }}
|
||||
CROWDIN_VERDACCIO_API_KEY: ${{ secrets.CROWDIN_VERDACCIO_API_KEY }}
|
||||
CONTEXT: production
|
||||
run: pnpm crowdin:download
|
||||
## this step is optional, translations are not mandatory for PR
|
||||
## secrets keys are not available on forks, the failure here is guaranteed
|
||||
continue-on-error: true
|
||||
- name: build
|
||||
run: pnpm build
|
||||
- name: tar packages
|
||||
@@ -116,6 +126,7 @@ jobs:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
## Node 16 breaks UI test, jest issue
|
||||
node_version: [14]
|
||||
name: ${{ matrix.os }} / Node ${{ matrix.node_version }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -165,8 +176,8 @@ jobs:
|
||||
run: pnpm recursive install --frozen-lockfile
|
||||
- name: Test UI
|
||||
run: pnpm test:e2e:ui
|
||||
env:
|
||||
DEBUG: verdaccio:e2e*
|
||||
# env:
|
||||
# DEBUG: verdaccio:e2e*
|
||||
ci-e2e-cli:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
@@ -192,6 +203,8 @@ jobs:
|
||||
run: pnpm recursive install --frozen-lockfile
|
||||
- name: Test CLI
|
||||
run: pnpm test:e2e:cli
|
||||
# env:
|
||||
# DEBUG: verdaccio*
|
||||
test-windows:
|
||||
needs: [format, lint]
|
||||
runs-on: windows-latest
|
||||
@@ -215,3 +228,35 @@ jobs:
|
||||
run: pnpm build
|
||||
- name: Test
|
||||
run: pnpm test
|
||||
sync-translations:
|
||||
needs: [ci-e2e-cli, ci-e2e-ui, test-windows, test]
|
||||
runs-on: ubuntu-latest
|
||||
name: synchronize translations
|
||||
if: (github.event_name == 'push' && github.ref == 'refs/heads/master') || github.event_name == 'workflow_dispatch'
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.1
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: verdaccio-artifact
|
||||
- name: untar packages
|
||||
run: tar -xzvf pkg.tar.gz -C ${{ github.workspace }}/packages
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.10.3 -g
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
- name: Install
|
||||
## we need scripts, pupetter downloads aditional content
|
||||
run: pnpm recursive install --frozen-lockfile
|
||||
- name: generate website translations
|
||||
run: pnpm write-translations --filter ...@verdaccio/website
|
||||
- name: sync
|
||||
env:
|
||||
CROWDIN_VERDACCIO_PROJECT_ID: ${{ secrets.CROWDIN_VERDACCIO_PROJECT_ID }}
|
||||
CROWDIN_VERDACCIO_API_KEY: ${{ secrets.CROWDIN_VERDACCIO_API_KEY }}
|
||||
CONTEXT: production
|
||||
run: pnpm crowdin:sync
|
||||
|
||||
10
.github/workflows/website.yml
vendored
10
.github/workflows/website.yml
vendored
@@ -82,13 +82,13 @@ jobs:
|
||||
|
||||
# Will deploy to Preview URL, only when a pull request is open with changes on the website
|
||||
- name: Build Deployment Preview
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master'
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && github.event.label.name == 'trigger-preview'
|
||||
env:
|
||||
CONTEXT: deploy-preview
|
||||
run: pnpm netlify:build:deployPreview --filter ...@verdaccio/website
|
||||
|
||||
- name: 🤖 Deploy Preview Netlify
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master'
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && github.event.label.name == 'trigger-preview'
|
||||
uses: semoal/action-netlify-deploy@master
|
||||
id: netlify_preview
|
||||
with:
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
build-dir: './website/build'
|
||||
|
||||
- name: Audit preview URL with Lighthouse
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master'
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && github.event.label.name == 'trigger-preview'
|
||||
id: lighthouse_audit
|
||||
uses: treosh/lighthouse-ci-action@v3
|
||||
with:
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
temporaryPublicStorage: true
|
||||
|
||||
- name: Format lighthouse score
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master'
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && github.event.label.name == 'trigger-preview'
|
||||
id: format_lighthouse_score
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
@@ -137,7 +137,7 @@ jobs:
|
||||
core.setOutput("comment", comment);
|
||||
|
||||
- name: Add comment to PR
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master'
|
||||
if: github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && github.event.label.name == 'trigger-preview'
|
||||
id: comment_to_pr
|
||||
uses: marocchino/sticky-pull-request-comment@v1
|
||||
with:
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -34,6 +34,9 @@ packages/standalone/dist/
|
||||
|
||||
## ui
|
||||
packages/plugins/ui-theme/static
|
||||
/packages/plugins/ui-theme/src/i18n/download_translations/
|
||||
!/packages/plugins/ui-theme/src/i18n/crowdin/ui.json
|
||||
|
||||
|
||||
# CI Pnpm cache
|
||||
.pnpm-store/
|
||||
@@ -43,3 +46,7 @@ api-results.json
|
||||
hyper-results.json
|
||||
hyper-results*.json
|
||||
api-results*.json
|
||||
|
||||
#docs
|
||||
./api
|
||||
packages/core/core/docs
|
||||
|
||||
5
.husky/pre-commit
Executable file
5
.husky/pre-commit
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
#./node_modules/.bin/lint-staged
|
||||
npm run husky:pre-commit
|
||||
2
.npmrc
2
.npmrc
@@ -1,5 +1,5 @@
|
||||
always-auth = true
|
||||
recursive-install = true
|
||||
registry = https://registry.verdaccio.org
|
||||
loglevel=warn
|
||||
loglevel=info
|
||||
fetch-retries="10"
|
||||
|
||||
@@ -17,6 +17,7 @@ node_modules/
|
||||
**/static/*.js
|
||||
**/build/*.js
|
||||
packages/core/local-storage/_storage/**
|
||||
packages/partials/storage_default_storage/
|
||||
packages/standalone/dist/bundle.js
|
||||
docker-examples/v5/reverse_proxy/nginx/relative_path/storage/*
|
||||
docker-examples/
|
||||
@@ -24,3 +25,9 @@ build/
|
||||
.vscode/
|
||||
.github/
|
||||
.netlify/
|
||||
packages/**/docs/**
|
||||
packages/mock/mock-store/**
|
||||
api/**
|
||||
packages/core/local-storage/tests/__fixtures__/test-storage/
|
||||
packages/plugins/ui-theme/static/
|
||||
.verdaccio-db.json
|
||||
|
||||
10
.vscode/launch.json
vendored
10
.vscode/launch.json
vendored
@@ -4,6 +4,16 @@
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "Attach",
|
||||
"port": 9229,
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "pwa-node"
|
||||
},
|
||||
{
|
||||
"name": "Verdaccio Debug",
|
||||
"port": 9229,
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
"**/.nyc_output": true,
|
||||
"**/build": true,
|
||||
"**/build": false,
|
||||
"**/coverage": true,
|
||||
".idea": true,
|
||||
"storage_default_storage": true,
|
||||
|
||||
1985
CHANGELOG.md
1985
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ guidelines for you:
|
||||
- [What's is not considered a bug?](#whats-is-not-considered-a-bug)
|
||||
- [Issue Search](#issue-search)
|
||||
- [Chat](#chat)
|
||||
- [Translations](#translations)
|
||||
- [Request Features](#request-features)
|
||||
- [Contributing Guidelines](#contributing-guidelines)
|
||||
- [Submitting a Pull Request](#submitting-a-pull-request)
|
||||
@@ -190,10 +191,28 @@ affecting multiple people.
|
||||
|
||||
### Chat
|
||||
|
||||
Questions can be asked via [Discord](http://chat.verdaccio.org/)
|
||||
Questions can be asked via [Discord](https://discord.gg/7qWJxBf)
|
||||
|
||||
**Please use the `#help` channel.**
|
||||
|
||||
## Translations
|
||||
|
||||
All translations are provided by the `crowdin` platform:
|
||||
[https://translate.verdaccio.org/](https://translate.verdaccio.org/)
|
||||
|
||||
If you want to contribute by adding translations, create an account (GitHub could be used as fast alternative), in the platform you can contribute to two areas, the website or improve User Interface translations.
|
||||
|
||||
If a language is not listed, ask for it in the [Discord](https://discord.gg/7qWJxBf) channel #contribute channel.
|
||||
|
||||
For adding a new **language** on the UI follow these steps:
|
||||
|
||||
1. Ensure the **language** has been enabled, must be visible in the `crowdin` platform.
|
||||
2. Find in the explorer the file `en.US.json` in the path `packages/plugins/ui-theme/src/i18n/crowdin/ui.json` and complete the translations, **not need to find approval on this**.
|
||||
3. Into the project, add a new field into `packages/plugins/ui-theme/src/i18n/crowdin/ui.json` file, in the section `lng`, the new language, eg: `{ lng: {korean:"Korean"}}`. (This file is English based, once the PR has been merged, this string will be available in crowdin for translate to the targeted language).
|
||||
4. Add the language, [flag icon](https://www.npmjs.com/package/country-flag-icons), and the menu key fort he new language eg: `menuKey: 'lng.korean'` to the file `packages/plugins/ui-theme/src/i18n/enabledLanguages.ts`.
|
||||
5. For local testing, read `packages/plugins/ui-theme/src/i18n/ABOUT_TRANSLATIONS.md`.
|
||||
6. Add a `changeset` file, see more info below.
|
||||
|
||||
## Request Features
|
||||
|
||||
New feature requests are welcome. Analyse whether the idea fits within scope of
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} node:14.17.6-alpine as builder
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} node:14.18.1-alpine as builder
|
||||
|
||||
ENV NODE_ENV=development \
|
||||
VERDACCIO_BUILD_REGISTRY=https://registry.verdaccio.org
|
||||
@@ -19,7 +19,7 @@ RUN npm -g i pnpm@6.10.3 && \
|
||||
# FIXME: need to remove devDependencies from the build
|
||||
# RUN pnpm install --prod --ignore-scripts
|
||||
|
||||
FROM node:14.17.6-alpine
|
||||
FROM node:14.18.1-alpine
|
||||
LABEL maintainer="https://github.com/verdaccio/verdaccio"
|
||||
|
||||
ENV VERDACCIO_APPDIR=/opt/verdaccio \
|
||||
|
||||
41
README.md
41
README.md
@@ -29,13 +29,19 @@ Google Cloud Storage** or create your own plugin.
|
||||
|
||||
## Install
|
||||
|
||||
> Latest Node.js v14
|
||||
|
||||
Install with npm:
|
||||
|
||||
```bash
|
||||
npm install --global verdaccio@6-next --registry https://registry.verdaccio.org/
|
||||
npm install --global verdaccio@6-next
|
||||
```
|
||||
|
||||
> Published on a temporary registry while setup is ready to publish on npmjs
|
||||
or
|
||||
|
||||
```bash
|
||||
docker pull verdaccio/verdaccio:nightly-master
|
||||
```
|
||||
|
||||
## Donations
|
||||
|
||||
@@ -71,7 +77,7 @@ booted in a couple of seconds, fast enough for any CI. Many open source projects
|
||||
|
||||
### **Testing the integrity of your React components by publishing in a private registry - React Finland 2021**.
|
||||
|
||||
[](https://react-finland.fi/schedule/#testing-the-integrity-of-your-react-components-by-publishing-in-a-private-registry)
|
||||
[](https://www.youtube.com/watch?v=bRKZbrlQqLY&t=16s&ab_channel=ReactFinland)
|
||||
|
||||
You might want to check out as well our previous talks:
|
||||
|
||||
@@ -186,7 +192,20 @@ Verdaccio aims to support all features of a standard npm client that make sense
|
||||
|
||||
If you want to report a security vulnerability, please follow the steps which we have defined for you in our [security policy](https://github.com/verdaccio/verdaccio/security/policy).
|
||||
|
||||
## Core Team
|
||||
## Special Thanks
|
||||
|
||||
Thanks to the following companies to help us to achieve our goals providing free open source licenses. Every company provides enough resources to move this project forward.
|
||||
|
||||
| Company | Logo | License |
|
||||
| ------------ | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| JetBrains | [](https://www.jetbrains.com/) | JetBrains provides licenses for products for active maintainers, renewable yearly |
|
||||
| Crowdin | [](https://crowdin.com/) | Crowdin provides platform for translations |
|
||||
| BrowserStack | [](https://www.browserstack.com/) | BrowserStack provides plan to run End to End testing for the UI |
|
||||
| Netlify | [](https://www.netlify.com/) | Netlify provides pro plan for website deployment |
|
||||
| Algolia | [](https://algolia.com/) | Algolia provides search services for the website |
|
||||
| Docker | [](https://www.docker.com/community/open-source/application) | Docker offers unlimited pulls and unlimited egress to any and all users |
|
||||
|
||||
## Maintainers
|
||||
|
||||
| [Juan Picado](https://github.com/juanpicado) | [Ayush Sharma](https://github.com/ayusharma) | [Sergio Hg](https://github.com/sergiohgz) |
|
||||
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
|
||||
@@ -240,18 +259,6 @@ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com
|
||||
|
||||
[](https://opencollective.com/verdaccio#backers)
|
||||
|
||||
## Special Thanks
|
||||
|
||||
Thanks to the following companies to help us to achieve our goals providing free open source licenses.
|
||||
|
||||
[](https://www.jetbrains.com/)
|
||||
[](https://crowdin.com/)
|
||||
[](https://www.browserstack.com/)
|
||||
[](https://www.netlify.com/)
|
||||
[](https://algolia.com/)
|
||||
|
||||
Verdaccio also is part of to the [Docker Open Source Program](https://www.docker.com/blog/expanded-support-for-open-source-software-projects/).
|
||||
|
||||
## Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
@@ -266,7 +273,7 @@ If you have any issue you can try the following options, do no desist to ask or
|
||||
- [Donations](https://github.com/sponsors/verdaccio)
|
||||
- [Reporting an issue](https://github.com/verdaccio/verdaccio/issues/new/choose)
|
||||
- [Running discussions](https://github.com/verdaccio/verdaccio/issues?q=is%3Aissue+is%3Aopen+label%3Adiscuss)
|
||||
- [Chat](http://chat.verdaccio.org/)
|
||||
- [Chat](https://discord.gg/7qWJxBf)
|
||||
- [Logos](https://verdaccio.org/docs/en/logo)
|
||||
- [Docker Examples](https://github.com/verdaccio/verdaccio/tree/master/docker-examples)
|
||||
- [FAQ](https://github.com/verdaccio/verdaccio/discussions/categories/q-a)
|
||||
|
||||
@@ -5,6 +5,10 @@ preserve_hierarchy: true
|
||||
|
||||
files:
|
||||
[
|
||||
{
|
||||
source: 'packages/plugins/ui-theme/src/i18n/crowdin/**/*',
|
||||
translation: '/packages/plugins/ui-theme/src/i18n/download_translations/%locale%/**/%original_file_name%',
|
||||
},
|
||||
{
|
||||
source: '/website/i18n/en/**/*',
|
||||
translation: '/website/i18n/%locale%/**/%original_file_name%',
|
||||
@@ -13,4 +17,4 @@ files:
|
||||
source: '/website/docs/**/*',
|
||||
translation: '/website/i18n/%locale%/docusaurus-plugin-content-docs/current/**/%original_file_name%',
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
2
docker-examples/v4/reverse_proxy/nginx/relative_path/nginx_ssl/Dockerfile
Executable file → Normal file
2
docker-examples/v4/reverse_proxy/nginx/relative_path/nginx_ssl/Dockerfile
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
FROM nginx
|
||||
FROM nginx:1
|
||||
|
||||
COPY cert.crt /etc/nginx/cert.crt
|
||||
COPY cert.key /etc/nginx/cert.key
|
||||
|
||||
@@ -55919,7 +55919,6 @@
|
||||
"@babel/plugin-transform-async-to-generator": "7.2.0",
|
||||
"@babel/plugin-transform-classes": "7.2.2",
|
||||
"@babel/plugin-transform-runtime": "7.2.0",
|
||||
"@babel/polyfill": "7.2.3",
|
||||
"@babel/preset-env": "7.2.3",
|
||||
"@babel/preset-flow": "7.0.0",
|
||||
"@babel/preset-react": "7.0.0",
|
||||
|
||||
2
docker-examples/v5/reverse_proxy/nginx_relative/nginx_ssl/Dockerfile
Executable file → Normal file
2
docker-examples/v5/reverse_proxy/nginx_relative/nginx_ssl/Dockerfile
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
FROM nginx
|
||||
FROM nginx:1
|
||||
|
||||
COPY cert.crt /etc/nginx/cert.crt
|
||||
COPY cert.key /etc/nginx/cert.key
|
||||
|
||||
@@ -48,3 +48,7 @@ $ VERDACCIO_FORWARDED_PROTO=CloudFront-Forwarded-Proto verdaccio --listen 5000
|
||||
#### VERDACCIO_STORAGE_PATH
|
||||
|
||||
By default, the storage is taken from config file, but using this variable allows to set it from environment variable.
|
||||
|
||||
#### VERDACCIO_STORAGE_NAME
|
||||
|
||||
The database name for `@verdaccio/local-storge` is by default `.verdaccio-db.json`, but this can be update by using this variable.
|
||||
|
||||
@@ -74,3 +74,7 @@ Introduce environment variables for legacy tokens.
|
||||
|
||||
- `VERDACCIO_LEGACY_ALGORITHM`: Allows to define the specific algorithm for the token signature which by default is `aes-256-ctr`
|
||||
- `VERDACCIO_LEGACY_ENCRYPTION_KEY`: By default, the token stores in the database, but using this variable allows to get it from memory
|
||||
|
||||
#### @verdaccio/commons-api migration
|
||||
|
||||
The package has been removed in favor of `@verdaccio/core` with a similar API, check API documentation for further details.
|
||||
|
||||
71
package.json
71
package.json
@@ -15,11 +15,11 @@
|
||||
"url": "https://opencollective.com/verdaccio"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.14.8",
|
||||
"@babel/core": "7.15.0",
|
||||
"@babel/node": "7.14.9",
|
||||
"@babel/cli": "7.15.4",
|
||||
"@babel/core": "7.15.5",
|
||||
"@babel/node": "7.15.4",
|
||||
"@babel/plugin-proposal-class-properties": "7.14.5",
|
||||
"@babel/plugin-proposal-decorators": "7.14.5",
|
||||
"@babel/plugin-proposal-decorators": "7.15.4",
|
||||
"@babel/plugin-proposal-export-namespace-from": "7.14.5",
|
||||
"@babel/plugin-proposal-function-sent": "7.14.5",
|
||||
"@babel/plugin-proposal-json-strings": "7.14.5",
|
||||
@@ -31,37 +31,27 @@
|
||||
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
||||
"@babel/plugin-syntax-import-meta": "7.10.4",
|
||||
"@babel/plugin-transform-async-to-generator": "7.14.5",
|
||||
"@babel/plugin-transform-classes": "7.14.9",
|
||||
"@babel/plugin-transform-classes": "7.15.4",
|
||||
"@babel/plugin-transform-runtime": "7.15.0",
|
||||
"@babel/polyfill": "7.12.1",
|
||||
"@babel/preset-env": "7.15.0",
|
||||
"@babel/preset-env": "7.15.4",
|
||||
"@babel/preset-react": "7.14.5",
|
||||
"@babel/preset-typescript": "7.15.0",
|
||||
"@babel/register": "7.15.3",
|
||||
"@babel/runtime": "7.15.3",
|
||||
"@changesets/changelog-github": "^0.2.8",
|
||||
"@babel/runtime": "7.15.4",
|
||||
"@changesets/changelog-github": "0.2.8",
|
||||
"@changesets/cli": "2.15.0",
|
||||
"@changesets/get-dependents-graph": "^1.2.0",
|
||||
"@commitlint/cli": "8.3.5",
|
||||
"@commitlint/config-conventional": "8.2.0",
|
||||
"@changesets/get-dependents-graph": "1.2.2",
|
||||
"@crowdin/cli": "3.6.5",
|
||||
"@types/async": "3.2.7",
|
||||
"@types/autocannon": "4.1.1",
|
||||
"@types/autosuggest-highlight": "3.1.1",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/express": "4.17.6",
|
||||
"@types/http-errors": "1.8.1",
|
||||
"@types/jest": "27.0.1",
|
||||
"@types/lodash": "4.14.172",
|
||||
"@types/lowdb": "1.0.11",
|
||||
"@types/mime": "2.0.3",
|
||||
"@types/minimatch": "3.0.5",
|
||||
"@types/node": "14.6.0",
|
||||
"@types/react": "17.0.19",
|
||||
"@types/react-autosuggest": "10.1.5",
|
||||
"@types/react-dom": "17.0.9",
|
||||
"@types/react-helmet": "6.1.2",
|
||||
"@types/react-router-dom": "5.1.8",
|
||||
"@types/react-virtualized": "9.21.13",
|
||||
"@types/request": "2.48.7",
|
||||
"@types/semver": "7.3.8",
|
||||
"@types/supertest": "2.0.11",
|
||||
@@ -80,32 +70,21 @@
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-jest": "27.1.0",
|
||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||
"babel-plugin-emotion": "10.0.33",
|
||||
"babel-plugin-emotion": "10.2.2",
|
||||
"codecov": "3.8.3",
|
||||
"concurrently": "6.2.1",
|
||||
"core-js": "3.17.2",
|
||||
"cross-env": "7.0.3",
|
||||
"debug": "4.3.2",
|
||||
"detect-secrets": "1.0.6",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-google": "0.14.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-babel": "5.3.1",
|
||||
"eslint-plugin-import": "2.24.2",
|
||||
"eslint-plugin-jest": "24.4.0",
|
||||
"eslint-plugin-jsx-a11y": "6.4.1",
|
||||
"eslint-plugin-prettier": "4.0.0",
|
||||
"eslint-plugin-react": "7.25.1",
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"eslint-plugin-simple-import-sort": "7.0.0",
|
||||
"eslint-plugin-verdaccio": "10.0.0",
|
||||
"fs-extra": "10.0.0",
|
||||
"husky": "4.3.5",
|
||||
"husky": "7.0.2",
|
||||
"in-publish": "2.0.1",
|
||||
"jest": "27.1.0",
|
||||
"jest-environment-jsdom": "27.1.0",
|
||||
"jest-environment-jsdom-global": "3.0.0",
|
||||
"jest-environment-node": "27.1.0",
|
||||
"jest-fetch-mock": "3.0.3",
|
||||
"jest-junit": "12.2.0",
|
||||
"kleur": "3.0.3",
|
||||
"lint-staged": "11.1.2",
|
||||
@@ -127,12 +106,13 @@
|
||||
"verdaccio-memory": "workspace:*"
|
||||
},
|
||||
"scripts": {
|
||||
"husky:pre-commit": "lint-staged",
|
||||
"clean": "pnpm recursive run clean",
|
||||
"build": "pnpm recursive run build --filter=!@verdaccio/website",
|
||||
"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 --max-warnings 49 \"**/*.{js,jsx,ts,tsx}\"",
|
||||
"lint": "eslint --max-warnings 60 \"**/*.{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",
|
||||
@@ -142,12 +122,12 @@
|
||||
"benchmark:submit": "pnpm ts-node ./scripts/submit-metrics.ts",
|
||||
"start:watch": "concurrently --kill-others \"pnpm _build:watch\" \"pnpm _start:server\" \"pnpm _debug:reload\"",
|
||||
"_build:watch": "pnpm run --parallel watch --filter ./packages",
|
||||
"_start:server": "node packages/verdaccio/debug/bootstrap.js --listen 8000",
|
||||
"_start:server": "node --inspect packages/verdaccio/debug/bootstrap.js --listen 8000",
|
||||
"_start:web": "pnpm start --filter ...@verdaccio/ui-theme",
|
||||
"_debug:reload": "nodemon -d 3 packages/verdaccio/debug/bootstrap.js",
|
||||
"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",
|
||||
"debug": "node --trace-warnings --trace-uncaught --inspect packages/verdaccio/debug/bootstrap.js",
|
||||
"debug:break": "node --trace-warnings --trace-uncaught --inspect-brk packages/verdaccio/debug/bootstrap.js",
|
||||
"changeset": "changeset",
|
||||
"changeset:check": "changeset status --since-master",
|
||||
"ci:version": "run-s ci:version:changeset ci:version:install",
|
||||
@@ -157,20 +137,11 @@
|
||||
"ts:ref": "update-ts-references --discardComments",
|
||||
"website": "pnpm build --filter ...@verdaccio/website",
|
||||
"crowdin:upload": "crowdin upload sources --auto-update --config ./crowdin.yaml",
|
||||
"crowdin:download": "crowdin download --config ./crowdin.yaml",
|
||||
"crowdin:sync": "pnpm crowdin:upload && pnpm crowdin:download --verbose"
|
||||
"crowdin:download": "crowdin download --verbose --config ./crowdin.yaml",
|
||||
"crowdin:sync": "pnpm crowdin:upload && pnpm crowdin:download --verbose",
|
||||
"postinstall": "husky install"
|
||||
},
|
||||
"license": "MIT",
|
||||
"commitlint": {
|
||||
"extends": [
|
||||
"@commitlint/config-conventional"
|
||||
]
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx,json,yml,yaml,md}": "prettier --write",
|
||||
"*.{js,jsx,ts,tsx}": "eslint --cache --fix"
|
||||
|
||||
@@ -1,5 +1,105 @@
|
||||
# @verdaccio/api
|
||||
|
||||
## 6.0.0-6-next.16
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 794af76c: Remove Node 12 support
|
||||
|
||||
- We need move to the new `undici` and does not support Node.js 12
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- b702ea36: abort search request support for proxy
|
||||
- 154b2ecd: refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplications
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [794af76c]
|
||||
- Updated dependencies [b702ea36]
|
||||
- Updated dependencies [154b2ecd]
|
||||
- @verdaccio/auth@6.0.0-6-next.13
|
||||
- @verdaccio/config@6.0.0-6-next.9
|
||||
- @verdaccio/core@6.0.0-6-next.2
|
||||
- @verdaccio/tarball@11.0.0-6-next.8
|
||||
- @verdaccio/hooks@6.0.0-6-next.8
|
||||
- @verdaccio/logger@6.0.0-6-next.6
|
||||
- @verdaccio/middleware@6.0.0-6-next.13
|
||||
- @verdaccio/store@6.0.0-6-next.14
|
||||
- @verdaccio/utils@6.0.0-6-next.7
|
||||
|
||||
## 6.0.0-6-next.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2c594910]
|
||||
- @verdaccio/logger@6.0.0-6-next.5
|
||||
- @verdaccio/auth@6.0.0-6-next.12
|
||||
- @verdaccio/hooks@6.0.0-6-next.7
|
||||
- @verdaccio/middleware@6.0.0-6-next.12
|
||||
- @verdaccio/store@6.0.0-6-next.13
|
||||
|
||||
## 6.0.0-6-next.14
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 459b6fa7: refactor: search v1 endpoint and local-database
|
||||
|
||||
- refactor search `api v1` endpoint, improve performance
|
||||
- remove usage of `async` dependency https://github.com/verdaccio/verdaccio/issues/1225
|
||||
- refactor method storage class
|
||||
- create new module `core` to reduce the ammount of modules with utilities
|
||||
- use `undici` instead `node-fetch`
|
||||
- use `fastify` instead `express` for functional test
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- plugin storage API changes
|
||||
- remove old search endpoint (return 404)
|
||||
- filter local private packages at plugin level
|
||||
|
||||
The storage api changes for methods `get`, `add`, `remove` as promise base. The `search` methods also changes and recieves a `query` object that contains all query params from the client.
|
||||
|
||||
```ts
|
||||
export interface IPluginStorage<T> extends IPlugin {
|
||||
add(name: string): Promise<void>;
|
||||
remove(name: string): Promise<void>;
|
||||
get(): Promise<any>;
|
||||
init(): Promise<void>;
|
||||
getSecret(): Promise<string>;
|
||||
setSecret(secret: string): Promise<any>;
|
||||
getPackageStorage(packageInfo: string): IPackageStorage;
|
||||
search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]>;
|
||||
saveToken(token: Token): Promise<any>;
|
||||
deleteToken(user: string, tokenKey: string): Promise<any>;
|
||||
readTokens(filter: TokenFilter): Promise<Token[]>;
|
||||
}
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [459b6fa7]
|
||||
- @verdaccio/auth@6.0.0-6-next.11
|
||||
- @verdaccio/config@6.0.0-6-next.8
|
||||
- @verdaccio/commons-api@11.0.0-6-next.4
|
||||
- @verdaccio/core@6.0.0-6-next.1
|
||||
- @verdaccio/hooks@6.0.0-6-next.6
|
||||
- @verdaccio/store@6.0.0-6-next.12
|
||||
- @verdaccio/utils@6.0.0-6-next.6
|
||||
- @verdaccio/middleware@6.0.0-6-next.11
|
||||
- @verdaccio/tarball@11.0.0-6-next.7
|
||||
- @verdaccio/logger@6.0.0-6-next.4
|
||||
|
||||
## 6.0.0-6-next.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [df0da3d6]
|
||||
- @verdaccio/hooks@6.0.0-6-next.5
|
||||
- @verdaccio/auth@6.0.0-6-next.10
|
||||
- @verdaccio/store@6.0.0-6-next.11
|
||||
- @verdaccio/middleware@6.0.0-6-next.10
|
||||
|
||||
## 6.0.0-6-next.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/api",
|
||||
"version": "6.0.0-6-next.12",
|
||||
"version": "6.0.0-6-next.16",
|
||||
"description": "loaders logic",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -25,7 +25,7 @@
|
||||
"verdaccio"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"node": ">=14",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -39,15 +39,16 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@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.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.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",
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.13",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.9",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.2",
|
||||
"@verdaccio/hooks": "workspace:6.0.0-6-next.8",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/middleware": "workspace:6.0.0-6-next.13",
|
||||
"@verdaccio/store": "workspace:6.0.0-6-next.14",
|
||||
"@verdaccio/tarball": "workspace:11.0.0-6-next.8",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.7",
|
||||
"abortcontroller-polyfill": "1.7.3",
|
||||
"cookies": "0.8.0",
|
||||
"debug": "4.3.2",
|
||||
"express": "4.17.1",
|
||||
@@ -56,8 +57,10 @@
|
||||
"semver": "7.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.17",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7",
|
||||
"@types/node": "16.9.1",
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.21",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.9",
|
||||
"@verdaccio/helper": "1.0.0",
|
||||
"body-parser": "1.19.0",
|
||||
"lodash": "4.17.21",
|
||||
"supertest": "6.1.6"
|
||||
|
||||
@@ -3,13 +3,13 @@ import _ from 'lodash';
|
||||
import { Router } from 'express';
|
||||
|
||||
import { media, allow } from '@verdaccio/middleware';
|
||||
import { API_MESSAGE, HTTP_STATUS, DIST_TAGS, VerdaccioError } from '@verdaccio/commons-api';
|
||||
import { constants, VerdaccioError } from '@verdaccio/core';
|
||||
import { Package } from '@verdaccio/types';
|
||||
import { IStorageHandler } from '@verdaccio/store';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';
|
||||
|
||||
export default function (route: Router, auth: IAuth, storage: IStorageHandler): void {
|
||||
export default function (route: Router, auth: IAuth, storage: Storage): void {
|
||||
const can = allow(auth);
|
||||
const tag_package_version = function (
|
||||
req: $RequestExtend,
|
||||
@@ -26,8 +26,8 @@ export default function (route: Router, auth: IAuth, storage: IStorageHandler):
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
return next({ ok: API_MESSAGE.TAG_ADDED });
|
||||
res.status(constants.HTTP_STATUS.CREATED);
|
||||
return next({ ok: constants.API_MESSAGE.TAG_ADDED });
|
||||
});
|
||||
};
|
||||
|
||||
@@ -58,9 +58,9 @@ export default function (route: Router, auth: IAuth, storage: IStorageHandler):
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
res.status(constants.HTTP_STATUS.CREATED);
|
||||
return next({
|
||||
ok: API_MESSAGE.TAG_REMOVED,
|
||||
ok: constants.API_MESSAGE.TAG_REMOVED,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -79,7 +79,7 @@ export default function (route: Router, auth: IAuth, storage: IStorageHandler):
|
||||
return next(err);
|
||||
}
|
||||
|
||||
next(info[DIST_TAGS]);
|
||||
next(info[constants.DIST_TAGS]);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -96,9 +96,9 @@ export default function (route: Router, auth: IAuth, storage: IStorageHandler):
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
res.status(constants.HTTP_STATUS.CREATED);
|
||||
return next({
|
||||
ok: API_MESSAGE.TAG_UPDATED,
|
||||
ok: constants.API_MESSAGE.TAG_UPDATED,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -7,9 +7,10 @@ import {
|
||||
antiLoop,
|
||||
} from '@verdaccio/middleware';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { IStorageHandler } from '@verdaccio/store';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { Config } from '@verdaccio/types';
|
||||
import bodyParser from 'body-parser';
|
||||
import semver from 'semver';
|
||||
|
||||
import whoami from './whoami';
|
||||
import ping from './ping';
|
||||
@@ -23,7 +24,11 @@ import profile from './v1/profile';
|
||||
import token from './v1/token';
|
||||
import v1Search from './v1/search';
|
||||
|
||||
export default function (config: Config, auth: IAuth, storage: IStorageHandler): Router {
|
||||
if (semver.lte(process.version, 'v15.0.0')) {
|
||||
global.AbortController = require('abortcontroller-polyfill/dist/cjs-ponyfill').AbortController;
|
||||
}
|
||||
|
||||
export default function (config: Config, auth: IAuth, storage: Storage): Router {
|
||||
/* eslint new-cap:off */
|
||||
const app = express.Router();
|
||||
/* eslint new-cap:off */
|
||||
@@ -52,19 +57,15 @@ export default function (config: Config, auth: IAuth, storage: IStorageHandler):
|
||||
whoami(app);
|
||||
pkg(app, auth, storage, config);
|
||||
profile(app, auth);
|
||||
search(app, auth, storage);
|
||||
// @deprecated endpoint, 404 by default
|
||||
search(app);
|
||||
user(app, auth, config);
|
||||
distTags(app, auth, storage);
|
||||
publish(app, auth, storage, config);
|
||||
ping(app);
|
||||
stars(app, storage);
|
||||
|
||||
if (config?.flags?.search === true) {
|
||||
v1Search(app, auth, storage);
|
||||
}
|
||||
|
||||
if (config?.flags?.token === true) {
|
||||
token(app, auth, storage, config);
|
||||
}
|
||||
// @ts-ignore
|
||||
v1Search(app, auth, storage);
|
||||
token(app, auth, storage, config);
|
||||
return app;
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@ import { Router } from 'express';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
import { allow } from '@verdaccio/middleware';
|
||||
import { getVersion, ErrorCode } from '@verdaccio/utils';
|
||||
import { HEADERS, DIST_TAGS, API_ERROR } from '@verdaccio/commons-api';
|
||||
import { getVersion } from '@verdaccio/utils';
|
||||
import { HEADERS, DIST_TAGS, API_ERROR, errorUtils } from '@verdaccio/core';
|
||||
import { Config, Package } from '@verdaccio/types';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { IStorageHandler } from '@verdaccio/store';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { convertDistRemoteToLocalTarballUrls } from '@verdaccio/tarball';
|
||||
import { $RequestExtend, $ResponseExtend, $NextFunctionVer } from '../types/custom';
|
||||
|
||||
@@ -34,12 +34,7 @@ const downloadStream = (
|
||||
stream.pipe(res);
|
||||
};
|
||||
|
||||
export default function (
|
||||
route: Router,
|
||||
auth: IAuth,
|
||||
storage: IStorageHandler,
|
||||
config: Config
|
||||
): void {
|
||||
export default function (route: Router, auth: IAuth, storage: Storage, config: Config): void {
|
||||
const can = allow(auth);
|
||||
// TODO: anonymous user?
|
||||
route.get(
|
||||
@@ -85,7 +80,7 @@ export default function (
|
||||
}
|
||||
|
||||
debug('package version not found %o', queryVersion);
|
||||
return next(ErrorCode.getNotFound(`${API_ERROR.VERSION_NOT_EXIST}: ${queryVersion}`));
|
||||
return next(errorUtils.getNotFound(`${API_ERROR.VERSION_NOT_EXIST}: ${queryVersion}`));
|
||||
};
|
||||
|
||||
debug('get package name %o', name);
|
||||
|
||||
@@ -4,14 +4,21 @@ import mime from 'mime';
|
||||
import { Router } from 'express';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
import { API_MESSAGE, HEADERS, DIST_TAGS, API_ERROR, HTTP_STATUS } from '@verdaccio/commons-api';
|
||||
import { validateMetadata, isObject, ErrorCode, hasDiffOneKey } from '@verdaccio/utils';
|
||||
import {
|
||||
API_MESSAGE,
|
||||
HEADERS,
|
||||
DIST_TAGS,
|
||||
API_ERROR,
|
||||
HTTP_STATUS,
|
||||
errorUtils,
|
||||
} from '@verdaccio/core';
|
||||
import { validateMetadata, isObject, hasDiffOneKey } from '@verdaccio/utils';
|
||||
import { media, expectJson, allow } from '@verdaccio/middleware';
|
||||
import { notify } from '@verdaccio/hooks';
|
||||
import { Config, Callback, MergeTags, Version, Package } from '@verdaccio/types';
|
||||
import { Config, Callback, MergeTags, Version, Package, CallbackAction } from '@verdaccio/types';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { IStorageHandler } from '@verdaccio/store';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { $RequestExtend, $ResponseExtend, $NextFunctionVer } from '../types/custom';
|
||||
|
||||
import star from './star';
|
||||
@@ -22,7 +29,7 @@ const debug = buildDebug('verdaccio:api:publish');
|
||||
export default function publish(
|
||||
router: Router,
|
||||
auth: IAuth,
|
||||
storage: IStorageHandler,
|
||||
storage: Storage,
|
||||
config: Config
|
||||
): void {
|
||||
const can = allow(auth);
|
||||
@@ -138,7 +145,7 @@ export default function publish(
|
||||
/**
|
||||
* Publish a package
|
||||
*/
|
||||
export function publishPackage(storage: IStorageHandler, config: Config, auth: IAuth): any {
|
||||
export function publishPackage(storage: Storage, config: Config, auth: IAuth): any {
|
||||
const starApi = star(storage);
|
||||
return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {
|
||||
const packageName = req.params.package;
|
||||
@@ -172,7 +179,7 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I
|
||||
/**
|
||||
* Add new package version in storage
|
||||
*/
|
||||
const createVersion = function (version: string, metadata: Version, cb: Callback): void {
|
||||
const createVersion = function (version: string, metadata: Version, cb: CallbackAction): void {
|
||||
debug('add a new package version %o to storage %o', version, metadata);
|
||||
storage.addVersion(packageName, version, metadata, null, cb);
|
||||
};
|
||||
@@ -180,7 +187,7 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I
|
||||
/**
|
||||
* Add new tags in storage
|
||||
*/
|
||||
const addTags = function (tags: MergeTags, cb: Callback): void {
|
||||
const addTags = function (tags: MergeTags, cb: CallbackAction): void {
|
||||
debug('add new tag %o to storage', packageName);
|
||||
storage.mergeTags(packageName, tags, cb);
|
||||
};
|
||||
@@ -224,7 +231,7 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I
|
||||
// if this happens in normal circumstances, report it as a bug
|
||||
debug('invalid body format');
|
||||
logger.info({ packageName }, `wrong package format on publish a package @{packageName}`);
|
||||
return next(ErrorCode.getBadRequest(API_ERROR.UNSUPORTED_REGISTRY_CALL));
|
||||
return next(errorUtils.getBadRequest(API_ERROR.UNSUPORTED_REGISTRY_CALL));
|
||||
}
|
||||
|
||||
if (error && error.status !== HTTP_STATUS.CONFLICT) {
|
||||
@@ -322,7 +329,7 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I
|
||||
} catch (error: any) {
|
||||
debug('error on publish, bad package format %o', packageName);
|
||||
logger.error({ packageName }, 'error on publish, bad package data for @{packageName}');
|
||||
return next(ErrorCode.getBadData(API_ERROR.BAD_PACKAGE_DATA));
|
||||
return next(errorUtils.getBadData(API_ERROR.BAD_PACKAGE_DATA));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -330,25 +337,27 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I
|
||||
/**
|
||||
* un-publish a package
|
||||
*/
|
||||
export function unPublishPackage(storage: IStorageHandler) {
|
||||
return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {
|
||||
export function unPublishPackage(storage: Storage) {
|
||||
return async function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) {
|
||||
const packageName = req.params.package;
|
||||
|
||||
logger.debug({ packageName }, `unpublishing @{packageName}`);
|
||||
storage.removePackage(packageName, function (err) {
|
||||
try {
|
||||
await storage.removePackage(packageName);
|
||||
} catch (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
return next({ ok: API_MESSAGE.PKG_REMOVED });
|
||||
});
|
||||
}
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
return next({ ok: API_MESSAGE.PKG_REMOVED });
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete tarball
|
||||
*/
|
||||
export function removeTarball(storage: IStorageHandler) {
|
||||
export function removeTarball(storage: Storage) {
|
||||
return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {
|
||||
const packageName = req.params.package;
|
||||
const { filename, revision } = req.params;
|
||||
@@ -374,7 +383,7 @@ export function removeTarball(storage: IStorageHandler) {
|
||||
/**
|
||||
* Adds a new version
|
||||
*/
|
||||
export function addVersion(storage: IStorageHandler) {
|
||||
export function addVersion(storage: Storage) {
|
||||
return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {
|
||||
const { version, tag } = req.params;
|
||||
const packageName = req.params.package;
|
||||
@@ -398,7 +407,7 @@ export function addVersion(storage: IStorageHandler) {
|
||||
/**
|
||||
* uploadPackageTarball
|
||||
*/
|
||||
export function uploadPackageTarball(storage: IStorageHandler) {
|
||||
export function uploadPackageTarball(storage: Storage) {
|
||||
return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {
|
||||
const packageName = req.params.package;
|
||||
const stream = storage.addTarball(packageName, req.params.filename);
|
||||
|
||||
@@ -1,102 +1,11 @@
|
||||
import { HEADERS } from '@verdaccio/commons-api';
|
||||
import { HTTP_STATUS } from '@verdaccio/core';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
|
||||
export default function (route, auth, storage): void {
|
||||
// searching packages
|
||||
route.get('/-/all(/since)?', function (req, res) {
|
||||
let received_end = false;
|
||||
let response_finished = false;
|
||||
let processing_pkgs = 0;
|
||||
let firstPackage = true;
|
||||
|
||||
res.status(200);
|
||||
res.set(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET);
|
||||
|
||||
/*
|
||||
* Offical NPM registry (registry.npmjs.org) no longer return whole database,
|
||||
* They only return packages matched with keyword in `referer: search pkg-name`,
|
||||
* And NPM client will request server in every search.
|
||||
*
|
||||
* The magic number 99999 was sent by NPM registry. Modify it may caused strange
|
||||
* behaviour in the future.
|
||||
*
|
||||
* BTW: NPM will not return result if user-agent does not contain string 'npm',
|
||||
* See: method 'request' in up-storage.js
|
||||
*
|
||||
* If there is no cache in local, NPM will request /-/all, then get response with
|
||||
* _updated: 99999, 'Date' in response header was Mon, 10 Oct 1983 00:12:48 GMT,
|
||||
* this will make NPM always query from server
|
||||
*
|
||||
* Data structure also different, whel request /-/all, response is an object, but
|
||||
* when request /-/all/since, response is an array
|
||||
*/
|
||||
const respShouldBeArray = req.path.endsWith('/since');
|
||||
if (!respShouldBeArray) {
|
||||
res.set('Date', 'Mon, 10 Oct 1983 00:12:48 GMT');
|
||||
}
|
||||
const check_finish = function (): void {
|
||||
if (!received_end) {
|
||||
return;
|
||||
}
|
||||
if (processing_pkgs) {
|
||||
return;
|
||||
}
|
||||
if (response_finished) {
|
||||
return;
|
||||
}
|
||||
response_finished = true;
|
||||
if (respShouldBeArray) {
|
||||
res.end(']\n');
|
||||
} else {
|
||||
res.end('}\n');
|
||||
}
|
||||
};
|
||||
|
||||
if (respShouldBeArray) {
|
||||
res.write('[');
|
||||
} else {
|
||||
res.write('{"_updated":' + 99999);
|
||||
}
|
||||
|
||||
const stream = storage.search(req.query.startkey || 0, { req: req });
|
||||
|
||||
stream.on('data', function each(pkg) {
|
||||
processing_pkgs++;
|
||||
|
||||
auth.allow_access({ packageName: pkg.name }, req.remote_user, function (err, allowed) {
|
||||
processing_pkgs--;
|
||||
|
||||
if (err) {
|
||||
if (err.status && String(err.status).match(/^4\d\d$/)) {
|
||||
// auth plugin returns 4xx user error,
|
||||
// that's equivalent of !allowed basically
|
||||
allowed = false;
|
||||
} else {
|
||||
stream.abort(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (allowed) {
|
||||
if (respShouldBeArray) {
|
||||
res.write(`${firstPackage ? '' : ','}${JSON.stringify(pkg)}\n`);
|
||||
if (firstPackage) {
|
||||
firstPackage = false;
|
||||
}
|
||||
} else {
|
||||
res.write(',\n' + JSON.stringify(pkg.name) + ':' + JSON.stringify(pkg));
|
||||
}
|
||||
}
|
||||
|
||||
check_finish();
|
||||
});
|
||||
});
|
||||
|
||||
stream.on('error', function () {
|
||||
res.socket.destroy();
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
received_end = true;
|
||||
check_finish();
|
||||
});
|
||||
export default function (route): void {
|
||||
// TODO: next major version, remove this
|
||||
route.get('/-/all(/since)?', function (_req, res) {
|
||||
logger.warn('search endpoint has been removed, please use search v1');
|
||||
res.status(HTTP_STATUS.NOT_FOUND);
|
||||
res.json({ error: 'not found, endpoint was removed' });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { USERS, HTTP_STATUS } from '@verdaccio/commons-api';
|
||||
import { USERS, HTTP_STATUS } from '@verdaccio/core';
|
||||
import { Response } from 'express';
|
||||
import _ from 'lodash';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
import { IStorageHandler } from '@verdaccio/store';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { $RequestExtend, $NextFunctionVer } from '../types/custom';
|
||||
|
||||
const debug = buildDebug('verdaccio:api:publish:star');
|
||||
|
||||
export default function (
|
||||
storage: IStorageHandler
|
||||
storage: Storage
|
||||
): (req: $RequestExtend, res: Response, next: $NextFunctionVer) => void {
|
||||
const validateInputs = (newUsers, localUsers, username, isStar): boolean => {
|
||||
const isExistlocalUsers = _.isNil(localUsers[username]) === false;
|
||||
@@ -40,6 +40,7 @@ export default function (
|
||||
};
|
||||
|
||||
debug('get package info package for %o', name);
|
||||
// @ts-ignore
|
||||
storage.getPackage({
|
||||
name,
|
||||
req,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import _ from 'lodash';
|
||||
import { Response, Router } from 'express';
|
||||
|
||||
import { USERS, HTTP_STATUS } from '@verdaccio/commons-api';
|
||||
import { USERS, HTTP_STATUS } from '@verdaccio/core';
|
||||
import { Package } from '@verdaccio/types';
|
||||
|
||||
import { IStorageHandler } from '@verdaccio/store';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { $RequestExtend, $NextFunctionVer } from '../types/custom';
|
||||
|
||||
type Packages = Package[];
|
||||
|
||||
export default function (route: Router, storage: IStorageHandler): void {
|
||||
export default function (route: Router, storage: Storage): void {
|
||||
route.get(
|
||||
'/-/_view/starredByUser',
|
||||
(req: $RequestExtend, res: Response, next: $NextFunctionVer): void => {
|
||||
|
||||
@@ -2,14 +2,14 @@ import _ from 'lodash';
|
||||
import { Response, Router } from 'express';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
import { getAuthenticatedMessage, validatePassword, ErrorCode } from '@verdaccio/utils';
|
||||
import { getAuthenticatedMessage, validatePassword } from '@verdaccio/utils';
|
||||
import { getApiToken } from '@verdaccio/auth';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
import { createRemoteUser } from '@verdaccio/config';
|
||||
|
||||
import { Config, RemoteUser } from '@verdaccio/types';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { API_ERROR, API_MESSAGE, HTTP_STATUS } from '@verdaccio/commons-api';
|
||||
import { API_ERROR, API_MESSAGE, HTTP_STATUS, errorUtils } from '@verdaccio/core';
|
||||
import { $RequestExtend, $NextFunctionVer } from '../types/custom';
|
||||
|
||||
const debug = buildDebug('verdaccio:api:user');
|
||||
@@ -47,7 +47,7 @@ export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
'authenticating for user @{username} failed. Error: @{err.message}'
|
||||
);
|
||||
return next(
|
||||
ErrorCode.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.BAD_USERNAME_PASSWORD)
|
||||
errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.BAD_USERNAME_PASSWORD)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
const token = await getApiToken(auth, config, restoredRemoteUser, password);
|
||||
debug('login: new token');
|
||||
if (!token) {
|
||||
return next(ErrorCode.getUnauthorized());
|
||||
return next(errorUtils.getUnauthorized());
|
||||
}
|
||||
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
@@ -73,7 +73,7 @@ export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
if (validatePassword(password) === false) {
|
||||
debug('adduser: invalid password');
|
||||
// eslint-disable-next-line new-cap
|
||||
return next(ErrorCode.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT()));
|
||||
return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT()));
|
||||
}
|
||||
|
||||
auth.add_user(name, password, async function (err, user): Promise<void> {
|
||||
@@ -84,7 +84,7 @@ export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
// and npm accepts only an 409 error.
|
||||
// So, changing status code here.
|
||||
return next(
|
||||
ErrorCode.getCode(err.status, err.message) || ErrorCode.getConflict(err.message)
|
||||
errorUtils.getCode(err.status, err.message) || errorUtils.getConflict(err.message)
|
||||
);
|
||||
}
|
||||
return next(err);
|
||||
@@ -94,7 +94,7 @@ export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
name && password ? await getApiToken(auth, config, user, password) : undefined;
|
||||
debug('adduser: new token %o', token);
|
||||
if (!token) {
|
||||
return next(ErrorCode.getUnauthorized());
|
||||
return next(errorUtils.getUnauthorized());
|
||||
}
|
||||
|
||||
req.remote_user = user;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import _ from 'lodash';
|
||||
import { Response, Router } from 'express';
|
||||
|
||||
import { API_ERROR, APP_ERROR, HTTP_STATUS, SUPPORT_ERRORS } from '@verdaccio/commons-api';
|
||||
import { ErrorCode, validatePassword } from '@verdaccio/utils';
|
||||
import { API_ERROR, APP_ERROR, HTTP_STATUS, SUPPORT_ERRORS, errorUtils } from '@verdaccio/core';
|
||||
import { validatePassword } from '@verdaccio/utils';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { $RequestExtend, $NextFunctionVer } from '../../types/custom';
|
||||
|
||||
@@ -61,7 +61,7 @@ export default function (route: Router, auth: IAuth): void {
|
||||
if (_.isNil(password) === false) {
|
||||
if (validatePassword(password.new) === false) {
|
||||
/* eslint new-cap:off */
|
||||
return next(ErrorCode.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT()));
|
||||
return next(errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT()));
|
||||
/* eslint new-cap:off */
|
||||
}
|
||||
|
||||
@@ -72,22 +72,22 @@ export default function (route: Router, auth: IAuth): void {
|
||||
(err, isUpdated): $NextFunctionVer => {
|
||||
if (_.isNull(err) === false) {
|
||||
return next(
|
||||
ErrorCode.getCode(err.status, err.message) || ErrorCode.getConflict(err.message)
|
||||
errorUtils.getCode(err.status, err.message) || errorUtils.getConflict(err.message)
|
||||
);
|
||||
}
|
||||
|
||||
if (isUpdated) {
|
||||
return next(buildProfile(req.remote_user.name));
|
||||
}
|
||||
return next(ErrorCode.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR));
|
||||
return next(errorUtils.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
);
|
||||
} else if (_.isNil(tfa) === false) {
|
||||
return next(
|
||||
ErrorCode.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.TFA_DISABLED)
|
||||
errorUtils.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.TFA_DISABLED)
|
||||
);
|
||||
} else {
|
||||
return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, APP_ERROR.PROFILE_ERROR));
|
||||
return next(errorUtils.getCode(HTTP_STATUS.INTERNAL_ERROR, APP_ERROR.PROFILE_ERROR));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,106 +1,81 @@
|
||||
import semver from 'semver';
|
||||
import _ from 'lodash';
|
||||
import buildDebug from 'debug';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { HTTP_STATUS, searchUtils } from '@verdaccio/core';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { Package } from '@verdaccio/types';
|
||||
|
||||
function compileTextSearch(textSearch: string): (pkg: Package) => boolean {
|
||||
const personMatch = (person, search) => {
|
||||
if (typeof person === 'string') {
|
||||
return person.includes(search);
|
||||
}
|
||||
const debug = buildDebug('verdaccio:api:search');
|
||||
|
||||
if (typeof person === 'object') {
|
||||
for (const field of Object.values(person)) {
|
||||
if (typeof field === 'string' && field.includes(search)) {
|
||||
return true;
|
||||
/**
|
||||
* Endpoint for npm search v1
|
||||
* Empty value
|
||||
* - {"objects":[],"total":0,"time":"Sun Jul 25 2021 14:09:11 GMT+0000 (Coordinated Universal Time)"}
|
||||
* req: 'GET /-/v1/search?text=react&size=20&frpom=0&quality=0.65&popularity=0.98&maintenance=0.5'
|
||||
*/
|
||||
export default function (route, auth: IAuth, storage: Storage): void {
|
||||
function checkAccess(pkg: any, auth: any, remoteUser): Promise<Package | null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
auth.allow_access({ packageName: pkg?.package?.name }, remoteUser, function (err, allowed) {
|
||||
if (err) {
|
||||
if (err.status && String(err.status).match(/^4\d\d$/)) {
|
||||
// auth plugin returns 4xx user error,
|
||||
// that's equivalent of !allowed basically
|
||||
allowed = false;
|
||||
return resolve(null);
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
} else {
|
||||
return resolve(allowed ? pkg : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
const matcher = function (q) {
|
||||
const match = q.match(/author:(.*)/);
|
||||
if (match !== null) {
|
||||
return (pkg) => personMatch(pkg.author, match[1]);
|
||||
}
|
||||
|
||||
// TODO: maintainer, keywords, not/is unstable insecure, boost-exact
|
||||
// TODO implement some scoring system for freetext
|
||||
return (pkg) => {
|
||||
return ['name', 'displayName', 'description']
|
||||
.map((k) => pkg[k])
|
||||
.filter((x) => x !== undefined)
|
||||
.some((txt) => txt.includes(q));
|
||||
};
|
||||
};
|
||||
|
||||
const textMatchers = (textSearch || '').split(' ').map(matcher);
|
||||
return (pkg) => textMatchers.every((m) => m(pkg));
|
||||
}
|
||||
|
||||
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] = [
|
||||
'text',
|
||||
'size',
|
||||
'from' /* , 'quality', 'popularity', 'maintenance' */,
|
||||
].map((k) => req.query[k]);
|
||||
|
||||
size = parseInt(size) || 20;
|
||||
from = parseInt(from) || 0;
|
||||
|
||||
const isInteresting = compileTextSearch(text);
|
||||
|
||||
const resultStream = storage.search(0, { req: { query: { local: true } } });
|
||||
const resultBuf = [] as any;
|
||||
let completed = false;
|
||||
|
||||
const sendResponse = (): void => {
|
||||
completed = true;
|
||||
resultStream.destroy();
|
||||
|
||||
const final = resultBuf.slice(from, size).map((pkg) => {
|
||||
return {
|
||||
package: pkg,
|
||||
flags: {
|
||||
unstable: Object.keys(pkg.versions).some((v) => semver.satisfies(v, '^1.0.0'))
|
||||
? undefined
|
||||
: true,
|
||||
},
|
||||
score: {
|
||||
final: 1,
|
||||
detail: {
|
||||
quality: 1,
|
||||
popularity: 1,
|
||||
maintenance: 0,
|
||||
},
|
||||
},
|
||||
searchScore: 100000,
|
||||
};
|
||||
});
|
||||
const response = {
|
||||
});
|
||||
}
|
||||
|
||||
route.get('/-/v1/search', async (req, res, next) => {
|
||||
const { query, url } = req;
|
||||
let [size, from] = ['size', 'from'].map((k) => query[k]);
|
||||
let data;
|
||||
const abort = new AbortController();
|
||||
|
||||
req.on('aborted', () => {
|
||||
abort.abort();
|
||||
});
|
||||
|
||||
size = parseInt(size, 10) || 20;
|
||||
from = parseInt(from, 10) || 0;
|
||||
|
||||
try {
|
||||
data = await storage.searchManager?.search({
|
||||
query,
|
||||
url,
|
||||
abort,
|
||||
});
|
||||
debug('stream finish');
|
||||
const checkAccessPromises: searchUtils.SearchItemPkg[] = await Promise.all(
|
||||
data.map((pkgItem) => {
|
||||
return checkAccess(pkgItem, auth, req.remote_user);
|
||||
})
|
||||
);
|
||||
|
||||
const final: searchUtils.SearchItemPkg[] = checkAccessPromises
|
||||
.filter((i) => !_.isNull(i))
|
||||
.slice(from, size);
|
||||
logger.debug(`search results ${final?.length}`);
|
||||
|
||||
const response: searchUtils.SearchResults = {
|
||||
objects: final,
|
||||
total: final.length,
|
||||
time: new Date().toUTCString(),
|
||||
};
|
||||
|
||||
res.status(200).json(response);
|
||||
};
|
||||
|
||||
resultStream.on('data', (pkg) => {
|
||||
if (!isInteresting(pkg)) {
|
||||
return;
|
||||
}
|
||||
resultBuf.push(pkg);
|
||||
if (!completed && resultBuf.length >= size + from) {
|
||||
sendResponse();
|
||||
}
|
||||
});
|
||||
resultStream.on('end', () => {
|
||||
if (!completed) {
|
||||
sendResponse();
|
||||
}
|
||||
});
|
||||
res.status(HTTP_STATUS.OK).json(response);
|
||||
} catch (error) {
|
||||
logger.error({ error }, 'search endpoint has failed @{error.message}');
|
||||
next(next);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import _ from 'lodash';
|
||||
import { HTTP_STATUS, SUPPORT_ERRORS, getInternalError } from '@verdaccio/commons-api';
|
||||
import { ErrorCode, stringToMD5, mask } from '@verdaccio/utils';
|
||||
import { errorUtils, HTTP_STATUS, SUPPORT_ERRORS } from '@verdaccio/core';
|
||||
import { stringToMD5, mask } from '@verdaccio/utils';
|
||||
import { getApiToken } from '@verdaccio/auth';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
import { Response, Router } from 'express';
|
||||
|
||||
import { Config, RemoteUser, Token } from '@verdaccio/types';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { IStorageHandler } from '@verdaccio/store';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { $RequestExtend, $NextFunctionVer } from '../../types/custom';
|
||||
|
||||
export type NormalizeToken = Token & {
|
||||
@@ -22,12 +22,7 @@ function normalizeToken(token: Token): NormalizeToken {
|
||||
}
|
||||
|
||||
// https://github.com/npm/npm-profile/blob/latest/lib/index.js
|
||||
export default function (
|
||||
route: Router,
|
||||
auth: IAuth,
|
||||
storage: IStorageHandler,
|
||||
config: Config
|
||||
): void {
|
||||
export default function (route: Router, auth: IAuth, storage: Storage, config: Config): void {
|
||||
route.get(
|
||||
'/-/npm/v1/tokens',
|
||||
async function (req: $RequestExtend, res: Response, next: $NextFunctionVer) {
|
||||
@@ -48,10 +43,10 @@ export default function (
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error({ error: error.msg }, 'token list has failed: @{error}');
|
||||
return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message));
|
||||
return next(errorUtils.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message));
|
||||
}
|
||||
}
|
||||
return next(ErrorCode.getUnauthorized());
|
||||
return next(errorUtils.getUnauthorized());
|
||||
}
|
||||
);
|
||||
|
||||
@@ -62,27 +57,27 @@ export default function (
|
||||
const { name } = req.remote_user;
|
||||
|
||||
if (!_.isBoolean(readonly) || !_.isArray(cidr_whitelist)) {
|
||||
return next(ErrorCode.getCode(HTTP_STATUS.BAD_DATA, SUPPORT_ERRORS.PARAMETERS_NOT_VALID));
|
||||
return next(errorUtils.getCode(HTTP_STATUS.BAD_DATA, SUPPORT_ERRORS.PARAMETERS_NOT_VALID));
|
||||
}
|
||||
|
||||
auth.authenticate(name, password, async (err, user: RemoteUser) => {
|
||||
if (err) {
|
||||
const errorCode = err.message ? HTTP_STATUS.UNAUTHORIZED : HTTP_STATUS.INTERNAL_ERROR;
|
||||
return next(ErrorCode.getCode(errorCode, err.message));
|
||||
return next(errorUtils.getCode(errorCode, err.message));
|
||||
}
|
||||
|
||||
req.remote_user = user;
|
||||
|
||||
if (!_.isFunction(storage.saveToken)) {
|
||||
return next(
|
||||
ErrorCode.getCode(HTTP_STATUS.NOT_IMPLEMENTED, SUPPORT_ERRORS.STORAGE_NOT_IMPLEMENT)
|
||||
errorUtils.getCode(HTTP_STATUS.NOT_IMPLEMENTED, SUPPORT_ERRORS.STORAGE_NOT_IMPLEMENT)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const token = await getApiToken(auth, config, user, password);
|
||||
if (!token) {
|
||||
throw getInternalError();
|
||||
throw errorUtils.getInternalError();
|
||||
}
|
||||
|
||||
const key = stringToMD5(token);
|
||||
@@ -118,7 +113,7 @@ export default function (
|
||||
);
|
||||
} catch (error: any) {
|
||||
logger.error({ error: error.msg }, 'token creation has failed: @{error}');
|
||||
return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message));
|
||||
return next(errorUtils.getInternalError(error.message));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -140,10 +135,10 @@ export default function (
|
||||
return next({});
|
||||
} catch (error: any) {
|
||||
logger.error({ error: error.msg }, 'token creation has failed: @{error}');
|
||||
return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message));
|
||||
return next(errorUtils.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message));
|
||||
}
|
||||
}
|
||||
return next(ErrorCode.getUnauthorized());
|
||||
return next(errorUtils.getUnauthorized());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Response, Router } from 'express';
|
||||
import buildDebug from 'debug';
|
||||
import { $RequestExtend, $NextFunctionVer } from '../types/custom';
|
||||
// import { getUnauthorized } from '@verdaccio/commons-api';
|
||||
|
||||
const debug = buildDebug('verdaccio:api:user');
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@ import bodyParser from 'body-parser';
|
||||
|
||||
import { Config, parseConfigFile } from '@verdaccio/config';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { generatePackageMetadata } from '@verdaccio/helper';
|
||||
import { final, handleError, errorReportingMiddleware } from '@verdaccio/middleware';
|
||||
import { Auth, IAuth } from '@verdaccio/auth';
|
||||
import { HEADERS, HEADER_TYPE, HTTP_STATUS, generatePackageMetadata } from '@verdaccio/commons-api';
|
||||
import { HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
|
||||
import apiEndpoints from '../../src';
|
||||
|
||||
const getConf = (conf) => {
|
||||
@@ -42,7 +43,7 @@ export async function initializeServer(configName): Promise<Application> {
|
||||
return app;
|
||||
}
|
||||
|
||||
export function publishVersion(app, configFile, pkgName, version): supertest.Test {
|
||||
export function publishVersion(app, _configFile, pkgName, version): supertest.Test {
|
||||
const pkgMetadata = generatePackageMetadata(pkgName, version);
|
||||
|
||||
return supertest(app)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import supertest from 'supertest';
|
||||
|
||||
import { HEADER_TYPE, HEADERS, HTTP_STATUS } from '@verdaccio/commons-api';
|
||||
import { HEADER_TYPE, HEADERS, HTTP_STATUS } from '@verdaccio/core';
|
||||
import { $ResponseExtend, $RequestExtend } from '../../types/custom';
|
||||
import { initializeServer, publishTaggedVersion, publishVersion } from './_helper';
|
||||
|
||||
@@ -64,7 +64,7 @@ describe('package', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: investigate the 404
|
||||
// FIXME: investigate the 404
|
||||
test.skip('should return a package by dist-tag', async (done) => {
|
||||
// await publishVersion(app, 'package.yaml', 'foo3', '1.0.0');
|
||||
await publishVersion(app, 'package.yaml', 'foo-tagged', '1.0.0');
|
||||
@@ -80,7 +80,7 @@ describe('package', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test.skip('should return 404', async () => {
|
||||
test('should return 404', async () => {
|
||||
return supertest(app)
|
||||
.get('/404-not-found')
|
||||
.set('Accept', HEADERS.JSON)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import supertest from 'supertest';
|
||||
|
||||
import { HEADER_TYPE, HEADERS, HTTP_STATUS } from '@verdaccio/commons-api';
|
||||
import { HEADER_TYPE, HEADERS, HTTP_STATUS } from '@verdaccio/core';
|
||||
import { initializeServer } from './_helper';
|
||||
|
||||
describe('ping', () => {
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { HTTP_STATUS } from '@verdaccio/commons-api';
|
||||
import { HTTP_STATUS } from '@verdaccio/core';
|
||||
import supertest from 'supertest';
|
||||
import {
|
||||
API_ERROR,
|
||||
API_MESSAGE,
|
||||
generatePackageMetadata,
|
||||
HEADER_TYPE,
|
||||
HEADERS,
|
||||
} from '@verdaccio/commons-api';
|
||||
import { API_ERROR, API_MESSAGE, HEADER_TYPE, HEADERS } from '@verdaccio/core';
|
||||
import { generatePackageMetadata } from '@verdaccio/helper';
|
||||
import { $ResponseExtend, $RequestExtend } from '../../types/custom';
|
||||
import { initializeServer, publishVersion } from './_helper';
|
||||
|
||||
|
||||
@@ -2,15 +2,13 @@ import supertest from 'supertest';
|
||||
import _ from 'lodash';
|
||||
|
||||
import {
|
||||
getBadRequest,
|
||||
getConflict,
|
||||
getUnauthorized,
|
||||
errorUtils,
|
||||
HEADERS,
|
||||
HEADER_TYPE,
|
||||
API_MESSAGE,
|
||||
HTTP_STATUS,
|
||||
API_ERROR,
|
||||
} from '@verdaccio/commons-api';
|
||||
} from '@verdaccio/core';
|
||||
|
||||
import { $RequestExtend, $ResponseExtend } from '../../types/custom';
|
||||
import { initializeServer } from './_helper';
|
||||
@@ -28,7 +26,7 @@ const mockAuthenticate = jest.fn(() => (_name, _password, callback): void => {
|
||||
});
|
||||
|
||||
const mockAddUser = jest.fn(() => (_name, _password, callback): void => {
|
||||
return callback(getConflict(API_ERROR.USERNAME_ALREADY_REGISTERED));
|
||||
return callback(errorUtils.getConflict(API_ERROR.USERNAME_ALREADY_REGISTERED));
|
||||
});
|
||||
|
||||
jest.mock('@verdaccio/auth', () => ({
|
||||
@@ -143,7 +141,7 @@ describe('user', () => {
|
||||
}
|
||||
);
|
||||
mockAddUser.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||
return callback(getBadRequest(API_ERROR.USERNAME_PASSWORD_REQUIRED));
|
||||
return callback(errorUtils.getBadRequest(API_ERROR.USERNAME_PASSWORD_REQUIRED));
|
||||
});
|
||||
const credentialsShort = _.cloneDeep(credentials);
|
||||
delete credentialsShort.name;
|
||||
@@ -208,7 +206,7 @@ describe('user', () => {
|
||||
}
|
||||
);
|
||||
mockAuthenticate.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||
return callback(getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
return callback(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
});
|
||||
const credentialsShort = _.cloneDeep(credentials);
|
||||
credentialsShort.password = 'failPassword';
|
||||
@@ -240,7 +238,7 @@ describe('user', () => {
|
||||
}
|
||||
);
|
||||
mockAuthenticate.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||
return callback(getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
return callback(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
});
|
||||
const credentialsShort = _.cloneDeep(credentials);
|
||||
credentialsShort.password = 'failPassword';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import supertest from 'supertest';
|
||||
|
||||
import { HEADERS, HTTP_STATUS } from '@verdaccio/commons-api';
|
||||
import { HEADERS, HTTP_STATUS } from '@verdaccio/core';
|
||||
|
||||
import { $RequestExtend, $ResponseExtend } from '../../types/custom';
|
||||
import { initializeServer } from './_helper';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HTTP_STATUS, API_ERROR } from '@verdaccio/commons-api';
|
||||
import { errorUtils, HTTP_STATUS, API_ERROR } from '@verdaccio/core';
|
||||
import {
|
||||
addVersion,
|
||||
uploadPackageTarball,
|
||||
@@ -183,35 +183,31 @@ describe('Publish endpoints - un-publish package', () => {
|
||||
next = jest.fn();
|
||||
});
|
||||
|
||||
test('should un-publish package successfully', (done) => {
|
||||
test('should un-publish package successfully', async () => {
|
||||
const storage = {
|
||||
removePackage(packageName, cb) {
|
||||
removePackage(packageName) {
|
||||
expect(packageName).toEqual(req.params.package);
|
||||
cb();
|
||||
done();
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
unPublishPackage(storage)(req, res, next);
|
||||
await unPublishPackage(storage)(req, res, next);
|
||||
expect(res.status).toHaveBeenCalledWith(HTTP_STATUS.CREATED);
|
||||
expect(next).toHaveBeenCalledWith({ ok: 'package removed' });
|
||||
});
|
||||
|
||||
test('un-publish failed', (done) => {
|
||||
const error = {
|
||||
message: 'un-publish failed',
|
||||
};
|
||||
test('un-publish failed', async () => {
|
||||
const storage = {
|
||||
removePackage(packageName, cb) {
|
||||
cb(error);
|
||||
done();
|
||||
removePackage(packageName) {
|
||||
expect(packageName).toEqual(req.params.package);
|
||||
return Promise.reject(errorUtils.getInternalError());
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
unPublishPackage(storage)(req, res, next);
|
||||
expect(next).toHaveBeenCalledWith(error);
|
||||
await unPublishPackage(storage)(req, res, next);
|
||||
expect(next).toHaveBeenCalledWith(errorUtils.getInternalError());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"path": "../config"
|
||||
},
|
||||
{
|
||||
"path": "../core/commons-api"
|
||||
"path": "../core/core"
|
||||
},
|
||||
{
|
||||
"path": "../core/tarball"
|
||||
|
||||
@@ -1,5 +1,91 @@
|
||||
# @verdaccio/auth
|
||||
|
||||
## 6.0.0-6-next.13
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 794af76c: Remove Node 12 support
|
||||
|
||||
- We need move to the new `undici` and does not support Node.js 12
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 154b2ecd: refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplications
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [794af76c]
|
||||
- Updated dependencies [154b2ecd]
|
||||
- @verdaccio/config@6.0.0-6-next.9
|
||||
- @verdaccio/core@6.0.0-6-next.2
|
||||
- verdaccio-htpasswd@11.0.0-6-next.9
|
||||
- @verdaccio/loaders@6.0.0-6-next.6
|
||||
- @verdaccio/logger@6.0.0-6-next.6
|
||||
- @verdaccio/utils@6.0.0-6-next.7
|
||||
|
||||
## 6.0.0-6-next.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2c594910]
|
||||
- @verdaccio/logger@6.0.0-6-next.5
|
||||
- @verdaccio/loaders@6.0.0-6-next.5
|
||||
|
||||
## 6.0.0-6-next.11
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 459b6fa7: refactor: search v1 endpoint and local-database
|
||||
|
||||
- refactor search `api v1` endpoint, improve performance
|
||||
- remove usage of `async` dependency https://github.com/verdaccio/verdaccio/issues/1225
|
||||
- refactor method storage class
|
||||
- create new module `core` to reduce the ammount of modules with utilities
|
||||
- use `undici` instead `node-fetch`
|
||||
- use `fastify` instead `express` for functional test
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- plugin storage API changes
|
||||
- remove old search endpoint (return 404)
|
||||
- filter local private packages at plugin level
|
||||
|
||||
The storage api changes for methods `get`, `add`, `remove` as promise base. The `search` methods also changes and recieves a `query` object that contains all query params from the client.
|
||||
|
||||
```ts
|
||||
export interface IPluginStorage<T> extends IPlugin {
|
||||
add(name: string): Promise<void>;
|
||||
remove(name: string): Promise<void>;
|
||||
get(): Promise<any>;
|
||||
init(): Promise<void>;
|
||||
getSecret(): Promise<string>;
|
||||
setSecret(secret: string): Promise<any>;
|
||||
getPackageStorage(packageInfo: string): IPackageStorage;
|
||||
search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]>;
|
||||
saveToken(token: Token): Promise<any>;
|
||||
deleteToken(user: string, tokenKey: string): Promise<any>;
|
||||
readTokens(filter: TokenFilter): Promise<Token[]>;
|
||||
}
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [459b6fa7]
|
||||
- @verdaccio/config@6.0.0-6-next.8
|
||||
- @verdaccio/commons-api@11.0.0-6-next.4
|
||||
- @verdaccio/utils@6.0.0-6-next.6
|
||||
- @verdaccio/loaders@6.0.0-6-next.4
|
||||
- verdaccio-htpasswd@11.0.0-6-next.8
|
||||
- @verdaccio/logger@6.0.0-6-next.4
|
||||
|
||||
## 6.0.0-6-next.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [df0da3d6]
|
||||
- verdaccio-htpasswd@11.0.0-6-next.7
|
||||
- @verdaccio/loaders@6.0.0-6-next.4
|
||||
|
||||
## 6.0.0-6-next.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/auth",
|
||||
"version": "6.0.0-6-next.9",
|
||||
"version": "6.0.0-6-next.13",
|
||||
"description": "logger",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -25,7 +25,7 @@
|
||||
"verdaccio"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"node": ">=14",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -39,20 +39,20 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@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.5",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.2",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.9",
|
||||
"@verdaccio/loaders": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.7",
|
||||
"debug": "4.3.2",
|
||||
"express": "4.17.1",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"lodash": "4.17.21",
|
||||
"verdaccio-htpasswd": "workspace:11.0.0-alpha.6"
|
||||
"verdaccio-htpasswd": "workspace:11.0.0-6-next.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.7",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.7"
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.10",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.9"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
|
||||
@@ -8,10 +8,8 @@ import {
|
||||
TOKEN_BASIC,
|
||||
TOKEN_BEARER,
|
||||
VerdaccioError,
|
||||
getBadRequest,
|
||||
getInternalError,
|
||||
getForbidden,
|
||||
} from '@verdaccio/commons-api';
|
||||
errorUtils,
|
||||
} from '@verdaccio/core';
|
||||
import { loadPlugin } from '@verdaccio/loaders';
|
||||
import { HTPasswd, HTPasswdConfig } from 'verdaccio-htpasswd';
|
||||
|
||||
@@ -29,12 +27,8 @@ import {
|
||||
PluginOptions,
|
||||
} from '@verdaccio/types';
|
||||
|
||||
import { isNil, isFunction } from '@verdaccio/utils';
|
||||
import {
|
||||
getMatchedPackagesSpec,
|
||||
createAnonymousRemoteUser,
|
||||
createRemoteUser,
|
||||
} from '@verdaccio/config';
|
||||
import { getMatchedPackagesSpec, isNil, isFunction } from '@verdaccio/utils';
|
||||
import { createAnonymousRemoteUser, createRemoteUser } from '@verdaccio/config';
|
||||
|
||||
import {
|
||||
getMiddlewareCredentials,
|
||||
@@ -157,7 +151,7 @@ class Auth implements IAuth {
|
||||
const validPlugins = _.filter(this.plugins, (plugin) => isFunction(plugin.changePassword));
|
||||
|
||||
if (_.isEmpty(validPlugins)) {
|
||||
return cb(getInternalError(SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE));
|
||||
return cb(errorUtils.getInternalError(SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE));
|
||||
}
|
||||
|
||||
for (const plugin of validPlugins) {
|
||||
@@ -414,7 +408,7 @@ class Auth implements IAuth {
|
||||
};
|
||||
|
||||
if (this._isRemoteUserValid(req.remote_user)) {
|
||||
debug('jwt has remote user');
|
||||
debug('jwt has a valid authentication header');
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -423,13 +417,13 @@ class Auth implements IAuth {
|
||||
|
||||
const { authorization } = req.headers;
|
||||
if (_.isNil(authorization)) {
|
||||
debug('jwt invalid auth header');
|
||||
debug('jwt, authentication header is missing');
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!isAuthHeaderValid(authorization)) {
|
||||
debug('api middleware auth heather is not valid');
|
||||
return next(getBadRequest(API_ERROR.BAD_AUTH_HEADER));
|
||||
debug('api middleware authentication heather is invalid');
|
||||
return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));
|
||||
}
|
||||
const { secret, security } = this.config;
|
||||
|
||||
@@ -480,7 +474,7 @@ class Auth implements IAuth {
|
||||
} else {
|
||||
// with JWT throw 401
|
||||
debug('jwt invalid token');
|
||||
next(getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
next(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,7 +508,7 @@ class Auth implements IAuth {
|
||||
} else {
|
||||
// we force npm client to ask again with basic authentication
|
||||
debug('legacy invalid header');
|
||||
return next(getBadRequest(API_ERROR.BAD_AUTH_HEADER));
|
||||
return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,7 +542,7 @@ class Auth implements IAuth {
|
||||
}
|
||||
|
||||
if (!isAuthHeaderValid(authorization)) {
|
||||
return next(getBadRequest(API_ERROR.BAD_AUTH_HEADER));
|
||||
return next(errorUtils.getBadRequest(API_ERROR.BAD_AUTH_HEADER));
|
||||
}
|
||||
|
||||
const token = (authorization || '').replace(`${TOKEN_BEARER} `, '');
|
||||
|
||||
@@ -13,12 +13,9 @@ import {
|
||||
TOKEN_BASIC,
|
||||
TOKEN_BEARER,
|
||||
API_ERROR,
|
||||
getForbidden,
|
||||
getUnauthorized,
|
||||
getConflict,
|
||||
getCode,
|
||||
} from '@verdaccio/commons-api';
|
||||
import { VerdaccioError } from '@verdaccio/commons-api';
|
||||
VerdaccioError,
|
||||
errorUtils,
|
||||
} from '@verdaccio/core';
|
||||
|
||||
import { createAnonymousRemoteUser } from '@verdaccio/config';
|
||||
import { TokenEncryption, AESPayload } from './auth';
|
||||
@@ -155,7 +152,7 @@ export function verifyJWTPayload(token: string, secret: string): RemoteUser {
|
||||
// we return an anonymous user to force log in.
|
||||
return createAnonymousRemoteUser();
|
||||
}
|
||||
throw getCode(HTTP_STATUS.UNAUTHORIZED, error.message);
|
||||
throw errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,11 +163,11 @@ export function isAuthHeaderValid(authorization: string): boolean {
|
||||
export function getDefaultPlugins(logger: any): IPluginAuth<Config> {
|
||||
return {
|
||||
authenticate(user: string, password: string, cb: Callback): void {
|
||||
cb(getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
},
|
||||
|
||||
adduser(user: string, password: string, cb: Callback): void {
|
||||
return cb(getConflict(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
return cb(errorUtils.getConflict(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
},
|
||||
|
||||
// FIXME: allow_action and allow_publish should be in the @verdaccio/types
|
||||
@@ -205,9 +202,13 @@ export function allow_action(action: ActionsAllowed, logger): AllowAction {
|
||||
}
|
||||
|
||||
if (name) {
|
||||
callback(getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`));
|
||||
callback(
|
||||
errorUtils.getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`)
|
||||
);
|
||||
} else {
|
||||
callback(getUnauthorized(`authorization required to ${action} package ${pkg.name}`));
|
||||
callback(
|
||||
errorUtils.getUnauthorized(`authorization required to ${action} package ${pkg.name}`)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import path from 'path';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { CHARACTER_ENCODING, TOKEN_BEARER, API_ERROR } from '@verdaccio/commons-api';
|
||||
|
||||
import { configExample } from '@verdaccio/mock';
|
||||
import {
|
||||
Config as AppConfig,
|
||||
@@ -20,7 +18,13 @@ import {
|
||||
} from '@verdaccio/utils';
|
||||
|
||||
import { Config, Security, RemoteUser } from '@verdaccio/types';
|
||||
import { VerdaccioError, getForbidden } from '@verdaccio/commons-api';
|
||||
import {
|
||||
VerdaccioError,
|
||||
CHARACTER_ENCODING,
|
||||
TOKEN_BEARER,
|
||||
API_ERROR,
|
||||
errorUtils,
|
||||
} from '@verdaccio/core';
|
||||
import { setup } from '@verdaccio/logger';
|
||||
import {
|
||||
IAuth,
|
||||
@@ -110,7 +114,7 @@ describe('Auth utilities', () => {
|
||||
test('authentication should fail by default (default)', () => {
|
||||
const plugin = getDefaultPlugins({ trace: jest.fn() });
|
||||
plugin.authenticate('foo', 'bar', (error: any) => {
|
||||
expect(error).toEqual(getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
expect(error).toEqual(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -118,7 +122,7 @@ describe('Auth utilities', () => {
|
||||
const plugin = getDefaultPlugins({ trace: jest.fn() });
|
||||
// @ts-ignore
|
||||
plugin.adduser('foo', 'bar', (error: any) => {
|
||||
expect(error).toEqual(getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
expect(error).toEqual(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ROLES, Config as AppConfig } from '@verdaccio/config';
|
||||
import { setup } from '@verdaccio/logger';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Config } from '@verdaccio/types';
|
||||
import { getInternalError } from '@verdaccio/commons-api';
|
||||
import { errorUtils } from '@verdaccio/core';
|
||||
|
||||
import { Auth } from '../src';
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('AuthTest', () => {
|
||||
|
||||
auth.authenticate('foo', 'bar', callback);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback).toHaveBeenCalledWith(getInternalError());
|
||||
expect(callback).toHaveBeenCalledWith(errorUtils.getInternalError());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
{
|
||||
"path": "../config"
|
||||
},
|
||||
{
|
||||
"path": "../core/commons-api"
|
||||
},
|
||||
{
|
||||
"path": "../core/htpasswd"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,89 @@
|
||||
# @verdaccio/cli
|
||||
|
||||
## 6.0.0-6-next.23
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 794af76c: Remove Node 12 support
|
||||
|
||||
- We need move to the new `undici` and does not support Node.js 12
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 154b2ecd: refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplications
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [794af76c]
|
||||
- Updated dependencies [b702ea36]
|
||||
- Updated dependencies [154b2ecd]
|
||||
- @verdaccio/config@6.0.0-6-next.9
|
||||
- @verdaccio/fastify-migration@6.0.0-6-next.14
|
||||
- @verdaccio/logger@6.0.0-6-next.6
|
||||
- @verdaccio/node-api@6.0.0-6-next.22
|
||||
|
||||
## 6.0.0-6-next.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2c594910]
|
||||
- @verdaccio/logger@6.0.0-6-next.5
|
||||
- @verdaccio/fastify-migration@6.0.0-6-next.13
|
||||
- @verdaccio/node-api@6.0.0-6-next.21
|
||||
|
||||
## 6.0.0-6-next.21
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 459b6fa7: refactor: search v1 endpoint and local-database
|
||||
|
||||
- refactor search `api v1` endpoint, improve performance
|
||||
- remove usage of `async` dependency https://github.com/verdaccio/verdaccio/issues/1225
|
||||
- refactor method storage class
|
||||
- create new module `core` to reduce the ammount of modules with utilities
|
||||
- use `undici` instead `node-fetch`
|
||||
- use `fastify` instead `express` for functional test
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- plugin storage API changes
|
||||
- remove old search endpoint (return 404)
|
||||
- filter local private packages at plugin level
|
||||
|
||||
The storage api changes for methods `get`, `add`, `remove` as promise base. The `search` methods also changes and recieves a `query` object that contains all query params from the client.
|
||||
|
||||
```ts
|
||||
export interface IPluginStorage<T> extends IPlugin {
|
||||
add(name: string): Promise<void>;
|
||||
remove(name: string): Promise<void>;
|
||||
get(): Promise<any>;
|
||||
init(): Promise<void>;
|
||||
getSecret(): Promise<string>;
|
||||
setSecret(secret: string): Promise<any>;
|
||||
getPackageStorage(packageInfo: string): IPackageStorage;
|
||||
search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]>;
|
||||
saveToken(token: Token): Promise<any>;
|
||||
deleteToken(user: string, tokenKey: string): Promise<any>;
|
||||
readTokens(filter: TokenFilter): Promise<Token[]>;
|
||||
}
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [459b6fa7]
|
||||
- @verdaccio/config@6.0.0-6-next.8
|
||||
- @verdaccio/fastify-migration@6.0.0-6-next.12
|
||||
- @verdaccio/node-api@6.0.0-6-next.20
|
||||
- @verdaccio/logger@6.0.0-6-next.4
|
||||
|
||||
## 6.0.0-6-next.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [df0da3d6]
|
||||
- @verdaccio/fastify-migration@6.0.0-6-next.11
|
||||
- @verdaccio/node-api@6.0.0-6-next.19
|
||||
|
||||
## 6.0.0-6-next.19
|
||||
|
||||
### Major Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/cli",
|
||||
"version": "6.0.0-6-next.19",
|
||||
"version": "6.0.0-6-next.23",
|
||||
"author": {
|
||||
"name": "Juan Picado",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
@@ -26,7 +26,7 @@
|
||||
"verdaccio"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"node": ">=14",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"description": "verdaccio CLI",
|
||||
@@ -44,10 +44,10 @@
|
||||
"start": "ts-node src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@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.18",
|
||||
"@verdaccio/fastify-migration": "workspace:6.0.0-6-next.10",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.9",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.6",
|
||||
"@verdaccio/node-api": "workspace:6.0.0-6-next.22",
|
||||
"@verdaccio/fastify-migration": "workspace:6.0.0-6-next.14",
|
||||
"clipanion": "3.0.1",
|
||||
"envinfo": "7.8.1",
|
||||
"kleur": "3.0.3",
|
||||
|
||||
@@ -46,7 +46,9 @@ export class InitCommand extends Command {
|
||||
private initLogger(logConfig: ConfigRuntime) {
|
||||
try {
|
||||
if (logConfig.logs) {
|
||||
process.emitWarning('config.logs is deprecated, rename configuration to "config.log"');
|
||||
process.emitWarning(
|
||||
'config.logs is deprecated, rename configuration to "config.log" in singular'
|
||||
);
|
||||
}
|
||||
// FUTURE: remove fallback when is ready
|
||||
setup(logConfig.log || logConfig.logs);
|
||||
|
||||
@@ -1,5 +1,67 @@
|
||||
# @verdaccio/config
|
||||
|
||||
## 6.0.0-6-next.9
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 794af76c: Remove Node 12 support
|
||||
|
||||
- We need move to the new `undici` and does not support Node.js 12
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 154b2ecd: refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplications
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [794af76c]
|
||||
- Updated dependencies [154b2ecd]
|
||||
- @verdaccio/core@6.0.0-6-next.2
|
||||
- @verdaccio/utils@6.0.0-6-next.7
|
||||
|
||||
## 6.0.0-6-next.8
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 459b6fa7: refactor: search v1 endpoint and local-database
|
||||
|
||||
- refactor search `api v1` endpoint, improve performance
|
||||
- remove usage of `async` dependency https://github.com/verdaccio/verdaccio/issues/1225
|
||||
- refactor method storage class
|
||||
- create new module `core` to reduce the ammount of modules with utilities
|
||||
- use `undici` instead `node-fetch`
|
||||
- use `fastify` instead `express` for functional test
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- plugin storage API changes
|
||||
- remove old search endpoint (return 404)
|
||||
- filter local private packages at plugin level
|
||||
|
||||
The storage api changes for methods `get`, `add`, `remove` as promise base. The `search` methods also changes and recieves a `query` object that contains all query params from the client.
|
||||
|
||||
```ts
|
||||
export interface IPluginStorage<T> extends IPlugin {
|
||||
add(name: string): Promise<void>;
|
||||
remove(name: string): Promise<void>;
|
||||
get(): Promise<any>;
|
||||
init(): Promise<void>;
|
||||
getSecret(): Promise<string>;
|
||||
setSecret(secret: string): Promise<any>;
|
||||
getPackageStorage(packageInfo: string): IPackageStorage;
|
||||
search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]>;
|
||||
saveToken(token: Token): Promise<any>;
|
||||
deleteToken(user: string, tokenKey: string): Promise<any>;
|
||||
readTokens(filter: TokenFilter): Promise<Token[]>;
|
||||
}
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [459b6fa7]
|
||||
- @verdaccio/commons-api@11.0.0-6-next.4
|
||||
- @verdaccio/utils@6.0.0-6-next.6
|
||||
|
||||
## 6.0.0-6-next.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/config",
|
||||
"version": "6.0.0-6-next.7",
|
||||
"version": "6.0.0-6-next.9",
|
||||
"description": "logger",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -26,7 +26,7 @@
|
||||
"verdaccio"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"node": ">=14",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -39,8 +39,8 @@
|
||||
"build": "pnpm run build:js && pnpm run build:types"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "workspace:11.0.0-alpha.3",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.5",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.2",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.7",
|
||||
"debug": "4.3.2",
|
||||
"js-yaml": "3.14.1",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -100,11 +100,6 @@ logs:
|
||||
# { type: file, path: verdaccio.log, level: http}
|
||||
# FIXME: this should be documented
|
||||
# More info about log rotation https://github.com/pinojs/pino/blob/master/docs/help.md#log-rotation
|
||||
flags:
|
||||
# support for npm token command
|
||||
token: false
|
||||
# support for the new v1 search endpoint, functional by incomplete read more on ticket 1732
|
||||
search: false
|
||||
|
||||
# This affect the web and api (not developed yet)
|
||||
i18n:
|
||||
|
||||
@@ -3,7 +3,7 @@ import path from 'path';
|
||||
import _ from 'lodash';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
import { CHARACTER_ENCODING } from '@verdaccio/commons-api';
|
||||
import { CHARACTER_ENCODING } from '@verdaccio/core';
|
||||
import { folderExists, fileExists } from './config-utils';
|
||||
|
||||
const CONFIG_FILE = 'config.yaml';
|
||||
|
||||
@@ -2,8 +2,8 @@ import assert from 'assert';
|
||||
import _ from 'lodash';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
import { generateRandomHexString, isObject } from '@verdaccio/utils';
|
||||
import { APP_ERROR } from '@verdaccio/commons-api';
|
||||
import { getMatchedPackagesSpec, generateRandomHexString, isObject } from '@verdaccio/utils';
|
||||
import { APP_ERROR } from '@verdaccio/core';
|
||||
import {
|
||||
PackageList,
|
||||
Config as AppConfig,
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from '@verdaccio/types';
|
||||
|
||||
import { generateRandomSecretKey } from './token';
|
||||
import { getMatchedPackagesSpec, normalisePackageAccess } from './package-access';
|
||||
import { normalisePackageAccess } from './package-access';
|
||||
import { sanityCheckUplinksProps, uplinkSanityCheck } from './uplinks';
|
||||
import { defaultSecurity } from './security';
|
||||
import { getUserAgent } from './agent';
|
||||
@@ -23,9 +23,6 @@ import serverSettings from './serverSettings';
|
||||
|
||||
const strategicConfigProps = ['uplinks', 'packages'];
|
||||
const allowedEnvConfig = ['http_proxy', 'https_proxy', 'no_proxy'];
|
||||
|
||||
export type MatchedPackage = PackageAccess | void;
|
||||
|
||||
const debug = buildDebug('verdaccio:config');
|
||||
|
||||
export const WEB_TITLE = 'Verdaccio';
|
||||
@@ -99,7 +96,8 @@ class Config implements AppConfig {
|
||||
/**
|
||||
* Check for package spec
|
||||
*/
|
||||
public getMatchedPackagesSpec(pkgName: string): MatchedPackage {
|
||||
public getMatchedPackagesSpec(pkgName: string): PackageAccess | void {
|
||||
// TODO: remove this method and replace by library utils
|
||||
return getMatchedPackagesSpec(pkgName, this.packages);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import assert from 'assert';
|
||||
import _ from 'lodash';
|
||||
import minimatch from 'minimatch';
|
||||
|
||||
import { PackageList, PackageAccess } from '@verdaccio/types';
|
||||
import { ErrorCode } from '@verdaccio/utils';
|
||||
import { MatchedPackage } from './config';
|
||||
|
||||
import { PackageAccess } from '@verdaccio/types';
|
||||
import { errorUtils } from '@verdaccio/core';
|
||||
export interface LegacyPackageList {
|
||||
[key: string]: PackageAccess;
|
||||
}
|
||||
@@ -39,7 +35,7 @@ export function normalizeUserList(groupsList: any): any {
|
||||
} else if (Array.isArray(groupsList)) {
|
||||
result.push(groupsList);
|
||||
} else {
|
||||
throw ErrorCode.getInternalError(
|
||||
throw errorUtils.getInternalError(
|
||||
'CONFIG: bad package acl (array or string expected): ' + JSON.stringify(groupsList)
|
||||
);
|
||||
}
|
||||
@@ -47,15 +43,6 @@ export function normalizeUserList(groupsList: any): any {
|
||||
return _.flatten(result);
|
||||
}
|
||||
|
||||
export function getMatchedPackagesSpec(pkgName: string, packages: PackageList): MatchedPackage {
|
||||
for (const i in packages) {
|
||||
if (minimatch.makeRe(i).exec(pkgName)) {
|
||||
return packages[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
export function normalisePackageAccess(packages: LegacyPackageList): LegacyPackageList {
|
||||
const normalizedPkgs: LegacyPackageList = { ...packages };
|
||||
if (_.isNil(normalizedPkgs['**'])) {
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
import fs from 'fs';
|
||||
import YAML from 'js-yaml';
|
||||
import { APP_ERROR } from '@verdaccio/commons-api';
|
||||
import { APP_ERROR } from '@verdaccio/core';
|
||||
import { ConfigRuntime, ConfigYaml } from '@verdaccio/types';
|
||||
|
||||
/**
|
||||
* Parse a config file from yaml to JSON.
|
||||
* @param configPath the absolute path of the configuration file
|
||||
*/
|
||||
export function parseConfigFile(configPath: string): ConfigRuntime {
|
||||
try {
|
||||
if (/\.ya?ml$/i.test(configPath)) {
|
||||
const yamlConfig = YAML.safeLoad(fs.readFileSync(configPath, 'utf8')) as ConfigYaml;
|
||||
return Object.assign({}, yamlConfig, {
|
||||
configPath,
|
||||
// @deprecated use configPath instead
|
||||
config_path: configPath,
|
||||
});
|
||||
}
|
||||
|
||||
const jsonConfig = require(configPath) as ConfigYaml;
|
||||
return Object.assign({}, jsonConfig, {
|
||||
configPath,
|
||||
// @deprecated use configPath instead
|
||||
config_path: configPath,
|
||||
});
|
||||
} catch (e: any) {
|
||||
@@ -21,6 +29,6 @@ export function parseConfigFile(configPath: string): ConfigRuntime {
|
||||
e.message = APP_ERROR.CONFIG_NOT_VALID;
|
||||
}
|
||||
|
||||
throw new Error(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import assert from 'assert';
|
||||
import { getMatchedPackagesSpec } from '@verdaccio/utils';
|
||||
import { PackageList, UpLinksConfList } from '@verdaccio/types';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { getMatchedPackagesSpec } from './package-access';
|
||||
import { MatchedPackage } from './config';
|
||||
|
||||
export const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
|
||||
export const DEFAULT_UPLINK = 'npmjs';
|
||||
|
||||
@@ -49,11 +47,8 @@ export function sanityCheckUplinksProps(configUpLinks: UpLinksConfList): UpLinks
|
||||
return uplinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an uplink can proxy
|
||||
*/
|
||||
export function hasProxyTo(pkg: string, upLink: string, packages: PackageList): boolean {
|
||||
const matchedPkg: MatchedPackage = getMatchedPackagesSpec(pkg, packages);
|
||||
const matchedPkg = getMatchedPackagesSpec(pkg, packages);
|
||||
const proxyList = typeof matchedPkg !== 'undefined' ? matchedPkg.proxy : [];
|
||||
if (proxyList) {
|
||||
return proxyList.some((curr) => upLink === curr);
|
||||
|
||||
@@ -12,13 +12,13 @@ describe('Package access utilities', () => {
|
||||
test('parse invalid.json', () => {
|
||||
expect(function () {
|
||||
parseConfigFile(parseConfigurationFile('invalid.json'));
|
||||
}).toThrow(/Error/);
|
||||
}).toThrow(/CONFIG: it does not look like a valid config file/);
|
||||
});
|
||||
|
||||
test('parse not-exists.json', () => {
|
||||
expect(function () {
|
||||
parseConfigFile(parseConfigurationFile('not-exists.json'));
|
||||
}).toThrow(/Error/);
|
||||
}).toThrow(/Cannot find module/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,13 +32,13 @@ describe('Package access utilities', () => {
|
||||
test('parse invalid.js', () => {
|
||||
expect(function () {
|
||||
parseConfigFile(parseConfigurationFile('invalid.js'));
|
||||
}).toThrow(/Error/);
|
||||
}).toThrow(/CONFIG: it does not look like a valid config file/);
|
||||
});
|
||||
|
||||
test('parse not-exists.js', () => {
|
||||
expect(function () {
|
||||
parseConfigFile(parseConfigurationFile('not-exists.js'));
|
||||
}).toThrow(/Error/);
|
||||
}).toThrow(/Cannot find module/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -96,9 +96,9 @@ describe('config-path', () => {
|
||||
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');
|
||||
expect(findConfigFile()).toMatch('\\app\\data\\verdaccio\\config.yaml');
|
||||
expect(mockwriteFile).toHaveBeenCalled();
|
||||
expect(mockmkDir).toHaveBeenCalled();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
import {
|
||||
getMatchedPackagesSpec,
|
||||
normalisePackageAccess,
|
||||
PACKAGE_ACCESS,
|
||||
} from '../src/package-access';
|
||||
import { normalisePackageAccess, PACKAGE_ACCESS } from '../src/package-access';
|
||||
import { parseConfigFile } from '../src';
|
||||
import { parseConfigurationFile } from './utils';
|
||||
|
||||
@@ -127,30 +123,4 @@ describe('Package access utilities', () => {
|
||||
expect(_.isArray(all.publish)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMatchedPackagesSpec', () => {
|
||||
test('should test basic config', () => {
|
||||
const { packages } = parseConfigFile(parseConfigurationFile('pkgs-custom'));
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('react', packages).proxy).toMatch('facebook');
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('angular', packages).proxy).toMatch('google');
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('vue', packages).proxy).toMatch('npmjs');
|
||||
// @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-expect-error
|
||||
expect(getMatchedPackagesSpec('react', packages).proxy).toMatch('facebook');
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('angular', packages).proxy).toMatch('google');
|
||||
// @ts-expect-error
|
||||
expect(getMatchedPackagesSpec('@fake/angular', packages).proxy).toMatch('npmjs');
|
||||
expect(getMatchedPackagesSpec('vue', packages)).toBeUndefined();
|
||||
expect(getMatchedPackagesSpec('@scope/vue', packages)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
packages:
|
||||
'react':
|
||||
access: admin
|
||||
publish: admin
|
||||
proxy: facebook
|
||||
'angular':
|
||||
access: admin
|
||||
publish: admin
|
||||
proxy: google
|
||||
'@fake/*':
|
||||
access: $all
|
||||
publish: $authenticated
|
||||
proxy: npmjs
|
||||
@@ -7,9 +7,6 @@
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["src/**/*.test.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../core/commons-api"
|
||||
},
|
||||
{
|
||||
"path": "../utils"
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# @verdaccio/commons-api
|
||||
|
||||
commons api utilities for verdaccio
|
||||
|
||||
[](https://www.npmjs.com/package/@verdaccio/commons-api)
|
||||
[](https://verdaccio.org/docs/en/docker.html)
|
||||
[](https://opencollective.com/verdaccio)
|
||||
[](https://stackshare.io/verdaccio)
|
||||
[](http://chat.verdaccio.org/)
|
||||
[](https://www.npmjs.com/package/@verdaccio/commons-api)
|
||||

|
||||
[](https://crowdin.com/project/verdaccio)
|
||||
|
||||
[](https://twitter.com/verdaccio_npm)
|
||||
[](https://github.com/verdaccio/verdaccio/stargazers)
|
||||
20
packages/core/commons-api/types/lockfile.d.ts
vendored
20
packages/core/commons-api/types/lockfile.d.ts
vendored
@@ -1,20 +0,0 @@
|
||||
declare module 'lockfile' {
|
||||
type Callback = (err?: Error) => void;
|
||||
|
||||
interface LockOptions {
|
||||
wait?: number;
|
||||
pollPeriod?: number;
|
||||
stale?: number;
|
||||
retries?: number;
|
||||
retryWait?: number;
|
||||
}
|
||||
|
||||
interface LockFileExport {
|
||||
lock(fileName: string, opts: LockOptions, cb: Callback): void;
|
||||
unlock(fileName: string, cb: Callback): void;
|
||||
}
|
||||
|
||||
const lockFileExport: LockFileExport;
|
||||
|
||||
export default lockFileExport;
|
||||
}
|
||||
6
packages/core/core/.eslintignore
Normal file
6
packages/core/core/.eslintignore
Normal file
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
coverage/
|
||||
lib/
|
||||
.nyc_output
|
||||
tests-report/
|
||||
build/
|
||||
5
packages/core/core/.eslintrc.json
Normal file
5
packages/core/core/.eslintrc.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"rules": {
|
||||
"@typescript-eslint/no-use-before-define": "off"
|
||||
}
|
||||
}
|
||||
50
packages/core/core/CHANGELOG.md
Normal file
50
packages/core/core/CHANGELOG.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# @verdaccio/core
|
||||
|
||||
## 6.0.0-6-next.2
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 794af76c: Remove Node 12 support
|
||||
|
||||
- We need move to the new `undici` and does not support Node.js 12
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 154b2ecd: refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplications
|
||||
|
||||
## 6.0.0-6-next.1
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 459b6fa7: refactor: search v1 endpoint and local-database
|
||||
|
||||
- refactor search `api v1` endpoint, improve performance
|
||||
- remove usage of `async` dependency https://github.com/verdaccio/verdaccio/issues/1225
|
||||
- refactor method storage class
|
||||
- create new module `core` to reduce the ammount of modules with utilities
|
||||
- use `undici` instead `node-fetch`
|
||||
- use `fastify` instead `express` for functional test
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- plugin storage API changes
|
||||
- remove old search endpoint (return 404)
|
||||
- filter local private packages at plugin level
|
||||
|
||||
The storage api changes for methods `get`, `add`, `remove` as promise base. The `search` methods also changes and recieves a `query` object that contains all query params from the client.
|
||||
|
||||
```ts
|
||||
export interface IPluginStorage<T> extends IPlugin {
|
||||
add(name: string): Promise<void>;
|
||||
remove(name: string): Promise<void>;
|
||||
get(): Promise<any>;
|
||||
init(): Promise<void>;
|
||||
getSecret(): Promise<string>;
|
||||
setSecret(secret: string): Promise<any>;
|
||||
getPackageStorage(packageInfo: string): IPackageStorage;
|
||||
search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]>;
|
||||
saveToken(token: Token): Promise<any>;
|
||||
deleteToken(user: string, tokenKey: string): Promise<any>;
|
||||
readTokens(filter: TokenFilter): Promise<Token[]>;
|
||||
}
|
||||
```
|
||||
19
packages/core/core/README.md
Normal file
19
packages/core/core/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Core
|
||||
|
||||
[](https://circleci.com/gh/ayusharma/@verdaccio/streams)
|
||||
[](https://codecov.io/gh/verdaccio/streams)
|
||||
[](https://www.npmjs.com/package/@verdaccio/streams)
|
||||
[](https://opencollective.com/verdaccio)
|
||||
[](http://chat.verdaccio.org/)
|
||||

|
||||
[](https://www.npmjs.com/package/@verdaccio/streams)
|
||||
|
||||
This project provides an extension of `PassThrough` stream.
|
||||
|
||||
## Detail
|
||||
|
||||
It provides 2 additional methods `abort()` and `done()`. Those implementations are widely use in the verdaccio core for handle `tarballs`.
|
||||
|
||||
## License
|
||||
|
||||
MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@verdaccio/commons-api",
|
||||
"version": "11.0.0-alpha.3",
|
||||
"description": "Commons API utilities for Verdaccio",
|
||||
"name": "@verdaccio/core",
|
||||
"version": "6.0.0-6-next.2",
|
||||
"description": "core utilities",
|
||||
"keywords": [
|
||||
"private",
|
||||
"package",
|
||||
@@ -13,13 +13,19 @@
|
||||
"server",
|
||||
"verdaccio"
|
||||
],
|
||||
"main": "./build/index.js",
|
||||
"types": "./build/index.d.ts",
|
||||
"author": "Juan Picado <juanpicado19@gmail.com>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://verdaccio.org",
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"repository": {
|
||||
"type": "https",
|
||||
"url": "https://github.com/verdaccio/verdaccio",
|
||||
"directory": "packages/core/commons-api"
|
||||
"directory": "packages/core/core"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/verdaccio/verdaccio/issues"
|
||||
@@ -27,22 +33,18 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"main": "build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
"files": [
|
||||
"build"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"dependencies": {
|
||||
"http-errors": "1.8.0",
|
||||
"http-status-codes": "2.1.4"
|
||||
"http-status-codes": "2.1.4",
|
||||
"semver": "7.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.9"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
"test": "cross-env NODE_ENV=test BABEL_ENV=test jest",
|
||||
"type-check": "tsc --noEmit -p tsconfig.build.json",
|
||||
"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",
|
||||
91
packages/core/core/src/constants.ts
Normal file
91
packages/core/core/src/constants.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import httpCodes from 'http-status-codes';
|
||||
|
||||
export const DEFAULT_MIN_LIMIT_PASSWORD = 3;
|
||||
export const TIME_EXPIRATION_24H = '24h';
|
||||
export const TIME_EXPIRATION_7D = '7d';
|
||||
export const DIST_TAGS = 'dist-tags';
|
||||
export const LATEST = 'latest';
|
||||
export const USERS = 'users';
|
||||
export const DEFAULT_USER = 'Anonymous';
|
||||
|
||||
export const HEADER_TYPE = {
|
||||
CONTENT_ENCODING: 'content-encoding',
|
||||
CONTENT_TYPE: 'content-type',
|
||||
CONTENT_LENGTH: 'content-length',
|
||||
ACCEPT_ENCODING: 'accept-encoding',
|
||||
};
|
||||
|
||||
export const CHARACTER_ENCODING = {
|
||||
UTF8: 'utf8',
|
||||
};
|
||||
|
||||
export const TOKEN_BASIC = 'Basic';
|
||||
export const TOKEN_BEARER = 'Bearer';
|
||||
|
||||
export const HEADERS = {
|
||||
ACCEPT: 'Accept',
|
||||
ACCEPT_ENCODING: 'Accept-Encoding',
|
||||
USER_AGENT: 'User-Agent',
|
||||
JSON: 'application/json',
|
||||
CONTENT_TYPE: 'Content-type',
|
||||
CONTENT_LENGTH: 'content-length',
|
||||
TEXT_PLAIN: 'text/plain',
|
||||
TEXT_PLAIN_UTF8: 'text/plain; charset=utf-8',
|
||||
TEXT_HTML_UTF8: 'text/html; charset=utf-8',
|
||||
TEXT_HTML: 'text/html',
|
||||
AUTHORIZATION: 'authorization',
|
||||
// only set with proxy that setup HTTPS
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
|
||||
FORWARDED_PROTO: 'X-Forwarded-Proto',
|
||||
FORWARDED_FOR: 'X-Forwarded-For',
|
||||
FRAMES_OPTIONS: 'X-Frame-Options',
|
||||
CSP: 'Content-Security-Policy',
|
||||
CTO: 'X-Content-Type-Options',
|
||||
XSS: 'X-XSS-Protection',
|
||||
ETAG: 'ETag',
|
||||
JSON_CHARSET: 'application/json; charset=utf-8',
|
||||
OCTET_STREAM: 'application/octet-stream; charset=utf-8',
|
||||
TEXT_CHARSET: 'text/plain; charset=utf-8',
|
||||
WWW_AUTH: 'WWW-Authenticate',
|
||||
GZIP: 'gzip',
|
||||
};
|
||||
|
||||
export const HTTP_STATUS = {
|
||||
OK: httpCodes.OK,
|
||||
CREATED: httpCodes.CREATED,
|
||||
MULTIPLE_CHOICES: httpCodes.MULTIPLE_CHOICES,
|
||||
NOT_MODIFIED: httpCodes.NOT_MODIFIED,
|
||||
BAD_REQUEST: httpCodes.BAD_REQUEST,
|
||||
UNAUTHORIZED: httpCodes.UNAUTHORIZED,
|
||||
FORBIDDEN: httpCodes.FORBIDDEN,
|
||||
NOT_FOUND: httpCodes.NOT_FOUND,
|
||||
CONFLICT: httpCodes.CONFLICT,
|
||||
NOT_IMPLEMENTED: httpCodes.NOT_IMPLEMENTED,
|
||||
UNSUPPORTED_MEDIA: httpCodes.UNSUPPORTED_MEDIA_TYPE,
|
||||
BAD_DATA: httpCodes.UNPROCESSABLE_ENTITY,
|
||||
INTERNAL_ERROR: httpCodes.INTERNAL_SERVER_ERROR,
|
||||
SERVICE_UNAVAILABLE: httpCodes.SERVICE_UNAVAILABLE,
|
||||
LOOP_DETECTED: 508,
|
||||
};
|
||||
|
||||
export const ERROR_CODE = {
|
||||
token_required: 'token is required',
|
||||
};
|
||||
|
||||
export const API_MESSAGE = {
|
||||
PKG_CREATED: 'created new package',
|
||||
PKG_CHANGED: 'package changed',
|
||||
PKG_REMOVED: 'package removed',
|
||||
PKG_PUBLISHED: 'package published',
|
||||
TARBALL_UPLOADED: 'tarball uploaded successfully',
|
||||
TARBALL_REMOVED: 'tarball removed',
|
||||
TAG_UPDATED: 'tags updated',
|
||||
TAG_REMOVED: 'tag removed',
|
||||
TAG_ADDED: 'package tagged',
|
||||
LOGGED_OUT: 'Logged out',
|
||||
};
|
||||
|
||||
export const LOG_STATUS_MESSAGE =
|
||||
"@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}'";
|
||||
export const LOG_VERDACCIO_ERROR = `${LOG_STATUS_MESSAGE}, error: @{!error}`;
|
||||
export const LOG_VERDACCIO_BYTES = `${LOG_STATUS_MESSAGE}, bytes: @{bytes.in}/@{bytes.out}`;
|
||||
@@ -1,91 +1,5 @@
|
||||
import createError, { HttpError } from 'http-errors';
|
||||
import httpCodes from 'http-status-codes';
|
||||
|
||||
export const DEFAULT_MIN_LIMIT_PASSWORD = 3;
|
||||
|
||||
export const HEADER_TYPE = {
|
||||
CONTENT_ENCODING: 'content-encoding',
|
||||
CONTENT_TYPE: 'content-type',
|
||||
CONTENT_LENGTH: 'content-length',
|
||||
ACCEPT_ENCODING: 'accept-encoding',
|
||||
};
|
||||
|
||||
export const HTTP_STATUS = {
|
||||
OK: httpCodes.OK,
|
||||
CREATED: httpCodes.CREATED,
|
||||
MULTIPLE_CHOICES: httpCodes.MULTIPLE_CHOICES,
|
||||
NOT_MODIFIED: httpCodes.NOT_MODIFIED,
|
||||
BAD_REQUEST: httpCodes.BAD_REQUEST,
|
||||
UNAUTHORIZED: httpCodes.UNAUTHORIZED,
|
||||
FORBIDDEN: httpCodes.FORBIDDEN,
|
||||
NOT_FOUND: httpCodes.NOT_FOUND,
|
||||
CONFLICT: httpCodes.CONFLICT,
|
||||
NOT_IMPLEMENTED: httpCodes.NOT_IMPLEMENTED,
|
||||
UNSUPPORTED_MEDIA: httpCodes.UNSUPPORTED_MEDIA_TYPE,
|
||||
BAD_DATA: httpCodes.UNPROCESSABLE_ENTITY,
|
||||
INTERNAL_ERROR: httpCodes.INTERNAL_SERVER_ERROR,
|
||||
SERVICE_UNAVAILABLE: httpCodes.SERVICE_UNAVAILABLE,
|
||||
LOOP_DETECTED: 508,
|
||||
};
|
||||
|
||||
export const CHARACTER_ENCODING = {
|
||||
UTF8: 'utf8',
|
||||
};
|
||||
|
||||
export const ERROR_CODE = {
|
||||
token_required: 'token is required',
|
||||
};
|
||||
|
||||
export const TOKEN_BASIC = 'Basic';
|
||||
export const TOKEN_BEARER = 'Bearer';
|
||||
|
||||
export const HEADERS = {
|
||||
ACCEPT: 'Accept',
|
||||
ACCEPT_ENCODING: 'Accept-Encoding',
|
||||
USER_AGENT: 'User-Agent',
|
||||
JSON: 'application/json',
|
||||
CONTENT_TYPE: 'Content-type',
|
||||
CONTENT_LENGTH: 'content-length',
|
||||
TEXT_PLAIN: 'text/plain',
|
||||
TEXT_PLAIN_UTF8: 'text/plain; charset=utf-8',
|
||||
TEXT_HTML_UTF8: 'text/html; charset=utf-8',
|
||||
TEXT_HTML: 'text/html',
|
||||
AUTHORIZATION: 'authorization',
|
||||
// only set with proxy that setup HTTPS
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
|
||||
FORWARDED_PROTO: 'X-Forwarded-Proto',
|
||||
FORWARDED_FOR: 'X-Forwarded-For',
|
||||
FRAMES_OPTIONS: 'X-Frame-Options',
|
||||
CSP: 'Content-Security-Policy',
|
||||
CTO: 'X-Content-Type-Options',
|
||||
XSS: 'X-XSS-Protection',
|
||||
ETAG: 'ETag',
|
||||
JSON_CHARSET: 'application/json; charset=utf-8',
|
||||
OCTET_STREAM: 'application/octet-stream; charset=utf-8',
|
||||
TEXT_CHARSET: 'text/plain; charset=utf-8',
|
||||
WWW_AUTH: 'WWW-Authenticate',
|
||||
GZIP: 'gzip',
|
||||
};
|
||||
|
||||
export const API_MESSAGE = {
|
||||
PKG_CREATED: 'created new package',
|
||||
PKG_CHANGED: 'package changed',
|
||||
PKG_REMOVED: 'package removed',
|
||||
PKG_PUBLISHED: 'package published',
|
||||
TARBALL_UPLOADED: 'tarball uploaded successfully',
|
||||
TARBALL_REMOVED: 'tarball removed',
|
||||
TAG_UPDATED: 'tags updated',
|
||||
TAG_REMOVED: 'tag removed',
|
||||
TAG_ADDED: 'package tagged',
|
||||
LOGGED_OUT: 'Logged out',
|
||||
};
|
||||
|
||||
export const SUPPORT_ERRORS = {
|
||||
PLUGIN_MISSING_INTERFACE: 'the plugin does not provide implementation of the requested feature',
|
||||
TFA_DISABLED: 'the two-factor authentication is not yet supported',
|
||||
STORAGE_NOT_IMPLEMENT: 'the storage does not support token saving',
|
||||
PARAMETERS_NOT_VALID: 'the parameters are not valid',
|
||||
};
|
||||
import { DEFAULT_MIN_LIMIT_PASSWORD, HTTP_STATUS } from './constants';
|
||||
|
||||
export const API_ERROR = {
|
||||
PASSWORD_SHORT: (passLength = DEFAULT_MIN_LIMIT_PASSWORD): string =>
|
||||
@@ -125,6 +39,13 @@ export const API_ERROR = {
|
||||
USERNAME_ALREADY_REGISTERED: 'username is already registered',
|
||||
};
|
||||
|
||||
export const SUPPORT_ERRORS = {
|
||||
PLUGIN_MISSING_INTERFACE: 'the plugin does not provide implementation of the requested feature',
|
||||
TFA_DISABLED: 'the two-factor authentication is not yet supported',
|
||||
STORAGE_NOT_IMPLEMENT: 'the storage does not support token saving',
|
||||
PARAMETERS_NOT_VALID: 'the parameters are not valid',
|
||||
};
|
||||
|
||||
export const APP_ERROR = {
|
||||
CONFIG_NOT_VALID: 'CONFIG: it does not look like a valid config file',
|
||||
PROFILE_ERROR: 'profile unexpected error',
|
||||
@@ -180,17 +101,3 @@ export function getNotFound(customMessage?: string): VerdaccioError {
|
||||
export function getCode(statusCode: number, customMessage: string): VerdaccioError {
|
||||
return getError(statusCode, customMessage);
|
||||
}
|
||||
|
||||
export const TIME_EXPIRATION_24H = '24h';
|
||||
export const TIME_EXPIRATION_7D = '7d';
|
||||
export const DIST_TAGS = 'dist-tags';
|
||||
export const LATEST = 'latest';
|
||||
export const USERS = 'users';
|
||||
export const DEFAULT_USER = 'Anonymous';
|
||||
|
||||
export const LOG_STATUS_MESSAGE =
|
||||
"@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}'";
|
||||
export const LOG_VERDACCIO_ERROR = `${LOG_STATUS_MESSAGE}, error: @{!error}`;
|
||||
export const LOG_VERDACCIO_BYTES = `${LOG_STATUS_MESSAGE}, bytes: @{bytes.in}/@{bytes.out}`;
|
||||
|
||||
export * from './helpers/pkg';
|
||||
3
packages/core/core/src/file-utils.ts
Normal file
3
packages/core/core/src/file-utils.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const Files = {
|
||||
DatabaseName: '.verdaccio-db.json',
|
||||
};
|
||||
35
packages/core/core/src/index.ts
Normal file
35
packages/core/core/src/index.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import * as searchUtils from './search-utils';
|
||||
import * as streamUtils from './stream-utils';
|
||||
import * as errorUtils from './error-utils';
|
||||
import * as validatioUtils from './validation-utils';
|
||||
import * as constants from './constants';
|
||||
import * as pluginUtils from './plugin-utils';
|
||||
import * as fileUtils from './file-utils';
|
||||
import * as pkgUtils from './pkg-utils';
|
||||
|
||||
export { VerdaccioError, API_ERROR, SUPPORT_ERRORS, APP_ERROR } from './error-utils';
|
||||
export {
|
||||
TOKEN_BASIC,
|
||||
TOKEN_BEARER,
|
||||
HTTP_STATUS,
|
||||
API_MESSAGE,
|
||||
HEADERS,
|
||||
DIST_TAGS,
|
||||
CHARACTER_ENCODING,
|
||||
HEADER_TYPE,
|
||||
LATEST,
|
||||
DEFAULT_MIN_LIMIT_PASSWORD,
|
||||
DEFAULT_USER,
|
||||
USERS,
|
||||
} from './constants';
|
||||
|
||||
export {
|
||||
fileUtils,
|
||||
pkgUtils,
|
||||
searchUtils,
|
||||
streamUtils,
|
||||
errorUtils,
|
||||
validatioUtils,
|
||||
constants,
|
||||
pluginUtils,
|
||||
};
|
||||
0
packages/core/core/src/path-utils.ts
Normal file
0
packages/core/core/src/path-utils.ts
Normal file
64
packages/core/core/src/pkg-utils.ts
Normal file
64
packages/core/core/src/pkg-utils.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { Package } from '@verdaccio/types';
|
||||
import semver from 'semver';
|
||||
import { DIST_TAGS } from './constants';
|
||||
|
||||
/**
|
||||
* Function filters out bad semver versions and sorts the array.
|
||||
* @return {Array} sorted Array
|
||||
*/
|
||||
export function semverSort(listVersions: string[]): string[] {
|
||||
return listVersions
|
||||
.filter(function (x): boolean {
|
||||
if (!semver.parse(x, true)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.sort(semver.compareLoose)
|
||||
.map(String);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest publihsed version of a package.
|
||||
* @param package metadata
|
||||
**/
|
||||
export function getLatest(pkg: Package): string {
|
||||
const listVersions: string[] = Object.keys(pkg.versions);
|
||||
if (listVersions.length < 1) {
|
||||
throw Error('cannot get lastest version of none');
|
||||
}
|
||||
|
||||
const versions: string[] = semverSort(listVersions);
|
||||
const latest: string | undefined = pkg[DIST_TAGS]?.latest ? pkg[DIST_TAGS].latest : versions[0];
|
||||
|
||||
return latest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function gets a local info and an info from uplinks and tries to merge it
|
||||
exported for unit tests only.
|
||||
* @param {*} local
|
||||
* @param {*} upstream
|
||||
* @param {*} config sds
|
||||
*/
|
||||
export function mergeVersions(local: Package, upstream: Package) {
|
||||
// copy new versions to a cache
|
||||
// NOTE: if a certain version was updated, we can't refresh it reliably
|
||||
for (const i in upstream.versions) {
|
||||
if (typeof local.versions[i] === 'undefined') {
|
||||
local.versions[i] = upstream.versions[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (const i in upstream[DIST_TAGS]) {
|
||||
if (local[DIST_TAGS][i] !== upstream[DIST_TAGS][i]) {
|
||||
if (!local[DIST_TAGS][i] || semver.lte(local[DIST_TAGS][i], upstream[DIST_TAGS][i])) {
|
||||
local[DIST_TAGS][i] = upstream[DIST_TAGS][i];
|
||||
}
|
||||
if (i === 'latest' && local[DIST_TAGS][i] === upstream[DIST_TAGS][i]) {
|
||||
// if remote has more fresh package, we should borrow its readme
|
||||
local.readme = upstream.readme;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
packages/core/core/src/plugin-utils.ts
Normal file
23
packages/core/core/src/plugin-utils.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Config, IPackageStorage, Token, TokenFilter } from '@verdaccio/types';
|
||||
import { searchUtils } from '.';
|
||||
|
||||
interface IPlugin {
|
||||
version?: string;
|
||||
// In case a plugin needs to be cleaned up/removed
|
||||
close?(): void;
|
||||
}
|
||||
|
||||
export interface IPluginStorage<T> extends IPlugin {
|
||||
config: T & Config;
|
||||
add(name: string): Promise<void>;
|
||||
remove(name: string): Promise<void>;
|
||||
get(): Promise<any>;
|
||||
init(): Promise<void>;
|
||||
getSecret(): Promise<string>;
|
||||
setSecret(secret: string): Promise<any>;
|
||||
getPackageStorage(packageInfo: string): IPackageStorage;
|
||||
search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]>;
|
||||
saveToken(token: Token): Promise<any>;
|
||||
deleteToken(user: string, tokenKey: string): Promise<any>;
|
||||
readTokens(filter: TokenFilter): Promise<Token[]>;
|
||||
}
|
||||
70
packages/core/core/src/search-utils.ts
Normal file
70
packages/core/core/src/search-utils.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
export type SearchMetrics = {
|
||||
quality: number;
|
||||
popularity: number;
|
||||
maintenance: number;
|
||||
};
|
||||
export type UnStable = {
|
||||
flags?: {
|
||||
// if is false is not be included in search results (majority are stable)
|
||||
unstable?: boolean;
|
||||
};
|
||||
};
|
||||
export type SearchItemPkg = {
|
||||
name: string;
|
||||
scoped?: string;
|
||||
path?: string;
|
||||
time?: number | Date;
|
||||
};
|
||||
|
||||
export type SearchItem = {
|
||||
package: SearchItemPkg;
|
||||
score: Score;
|
||||
} & UnStable;
|
||||
|
||||
export type Score = {
|
||||
final: number;
|
||||
detail: SearchMetrics;
|
||||
};
|
||||
|
||||
export type SearchResults = {
|
||||
objects: SearchItemPkg[];
|
||||
total: number;
|
||||
time: string;
|
||||
};
|
||||
|
||||
type PublisherMaintainer = {
|
||||
username: string;
|
||||
email: string;
|
||||
};
|
||||
|
||||
export type SearchPackageBody = {
|
||||
name: string;
|
||||
scope: string;
|
||||
description: string;
|
||||
author: string | PublisherMaintainer;
|
||||
version: string;
|
||||
keywords: string | string[] | undefined;
|
||||
date: string;
|
||||
links?: {
|
||||
npm: string; // only include placeholder for URL eg: {url}/{packageName}
|
||||
homepage?: string;
|
||||
repository?: string;
|
||||
bugs?: string;
|
||||
};
|
||||
publisher?: any;
|
||||
maintainers?: PublisherMaintainer[];
|
||||
};
|
||||
|
||||
export type SearchPackageItem = {
|
||||
package: SearchPackageBody;
|
||||
score: Score;
|
||||
searchScore?: number;
|
||||
} & UnStable;
|
||||
|
||||
export const UNSCOPED = 'unscoped';
|
||||
|
||||
export type SearchQuery = {
|
||||
text: string;
|
||||
size?: number;
|
||||
from?: number;
|
||||
} & SearchMetrics;
|
||||
109
packages/core/core/src/stream-utils.ts
Normal file
109
packages/core/core/src/stream-utils.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { PassThrough, TransformOptions, Transform } from 'stream';
|
||||
|
||||
export interface IReadTarball {
|
||||
abort?: () => void;
|
||||
}
|
||||
|
||||
export interface IUploadTarball {
|
||||
done?: () => void;
|
||||
abort?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* This stream is used to read tarballs from repository.
|
||||
* @param {*} options
|
||||
* @return {Stream}
|
||||
*/
|
||||
class ReadTarball extends PassThrough implements IReadTarball {
|
||||
/**
|
||||
*
|
||||
* @param {Object} options
|
||||
*/
|
||||
public constructor(options: TransformOptions) {
|
||||
super(options);
|
||||
// called when data is not needed anymore
|
||||
addAbstractMethods(this, 'abort');
|
||||
}
|
||||
|
||||
public abort(): void {}
|
||||
}
|
||||
|
||||
/**
|
||||
* This stream is used to upload tarballs to a repository.
|
||||
* @param {*} options
|
||||
* @return {Stream}
|
||||
*/
|
||||
class UploadTarball extends PassThrough implements IUploadTarball {
|
||||
/**
|
||||
*
|
||||
* @param {Object} options
|
||||
*/
|
||||
public constructor(options: any) {
|
||||
super(options);
|
||||
// called when user closes connection before upload finishes
|
||||
addAbstractMethods(this, 'abort');
|
||||
|
||||
// called when upload finishes successfully
|
||||
addAbstractMethods(this, 'done');
|
||||
}
|
||||
|
||||
public abort(): void {}
|
||||
public done(): void {}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function intercepts abstract calls and replays them allowing.
|
||||
* us to attach those functions after we are ready to do so
|
||||
* @param {*} self
|
||||
* @param {*} name
|
||||
*/
|
||||
// Perhaps someone knows a better way to write this
|
||||
function addAbstractMethods(self: any, name: any): void {
|
||||
self._called_methods = self._called_methods || {};
|
||||
|
||||
self.__defineGetter__(name, function () {
|
||||
return function (): void {
|
||||
self._called_methods[name] = true;
|
||||
};
|
||||
});
|
||||
|
||||
self.__defineSetter__(name, function (fn: any) {
|
||||
delete self[name];
|
||||
|
||||
self[name] = fn;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
if (self._called_methods && self._called_methods[name]) {
|
||||
delete self._called_methods[name];
|
||||
|
||||
self[name]();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a buffer stream to a string.
|
||||
*/
|
||||
const readableToString = async (stream) => {
|
||||
const chunks: Buffer[] = [];
|
||||
for await (let chunk of stream) {
|
||||
chunks.push(Buffer.from(chunk));
|
||||
}
|
||||
const buffer = Buffer.concat(chunks);
|
||||
const str = buffer.toString('utf-8');
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform stream object mode to string
|
||||
**/
|
||||
const transformObjectToString = () => {
|
||||
return new Transform({
|
||||
objectMode: true,
|
||||
transform: (chunk, encoding, callback) => {
|
||||
callback(null, JSON.stringify(chunk));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export { ReadTarball, UploadTarball, readableToString, transformObjectToString };
|
||||
100
packages/core/core/src/validation-utils.ts
Normal file
100
packages/core/core/src/validation-utils.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import assert from 'assert';
|
||||
import { Package } from '@verdaccio/types';
|
||||
import { DIST_TAGS } from './constants';
|
||||
|
||||
export function isPackageNameScoped(name: string): boolean {
|
||||
return name.startsWith('@');
|
||||
}
|
||||
|
||||
/**
|
||||
* From normalize-package-data/lib/fixer.js
|
||||
* @param {*} name the package name
|
||||
* @return {Boolean} whether is valid or not
|
||||
*/
|
||||
export function validateName(name: string): boolean {
|
||||
if (typeof name !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
let normalizedName: string = name.toLowerCase();
|
||||
|
||||
const isScoped: boolean = isPackageNameScoped(name);
|
||||
const scopedName = name.split('/', 2)[1];
|
||||
|
||||
if (isScoped && typeof scopedName !== 'undefined') {
|
||||
normalizedName = scopedName.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Some context about the first regex
|
||||
* - npm used to have a different tarball naming system.
|
||||
* eg: http://registry.npmjs.com/thirty-two
|
||||
* https://registry.npmjs.org/thirty-two/-/thirty-two@0.0.1.tgz
|
||||
* The file name thirty-two@0.0.1.tgz, the version and the pkg name was separated by an at (@)
|
||||
* while nowadays the naming system is based in dashes
|
||||
* https://registry.npmjs.org/verdaccio/-/verdaccio-1.4.0.tgz
|
||||
*
|
||||
* more info here: https://github.com/rlidwka/sinopia/issues/75
|
||||
*/
|
||||
return !(
|
||||
!normalizedName.match(/^[-a-zA-Z0-9_.!~*'()@]+$/) ||
|
||||
normalizedName.startsWith('.') || // ".bin", etc.
|
||||
['node_modules', '__proto__', 'favicon.ico'].includes(normalizedName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a package.
|
||||
* @return {Boolean} whether the package is valid or not
|
||||
*/
|
||||
export function validatePackage(name: string): boolean {
|
||||
const nameList = name.split('/', 2);
|
||||
if (nameList.length === 1) {
|
||||
// normal package
|
||||
return validateName(nameList[0]);
|
||||
}
|
||||
// scoped package
|
||||
return nameList[0][0] === '@' && validateName(nameList[0].slice(1)) && validateName(nameList[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the package metadata, add additional properties whether are missing within
|
||||
* the metadata properties.
|
||||
* @param {*} object
|
||||
* @param {*} name
|
||||
* @return {Object} the object with additional properties as dist-tags ad versions
|
||||
*/
|
||||
export function validateMetadata(object: Package, name: string): Package {
|
||||
assert(isObject(object), 'not a json object');
|
||||
assert.strictEqual(object.name, name);
|
||||
|
||||
if (!isObject(object[DIST_TAGS])) {
|
||||
object[DIST_TAGS] = {};
|
||||
}
|
||||
|
||||
if (!isObject(object['versions'])) {
|
||||
object['versions'] = {};
|
||||
}
|
||||
|
||||
if (!isObject(object['time'])) {
|
||||
object['time'] = {};
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element is an Object
|
||||
* @param {*} obj the element
|
||||
* @return {Boolean}
|
||||
*/
|
||||
export function isObject(obj: any): boolean {
|
||||
if (obj === null || typeof obj === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
(typeof obj === 'object' || typeof obj.prototype === 'undefined') &&
|
||||
Array.isArray(obj) === false
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import _ from 'lodash';
|
||||
import { HTTP_STATUS } from '../src/constants';
|
||||
|
||||
import {
|
||||
getNotFound,
|
||||
VerdaccioError,
|
||||
HTTP_STATUS,
|
||||
getConflict,
|
||||
getBadData,
|
||||
getInternalError,
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
getForbidden,
|
||||
getServiceUnavailable,
|
||||
getCode,
|
||||
} from '../src/index';
|
||||
} from '../src/error-utils';
|
||||
|
||||
describe('testing errors', () => {
|
||||
test('should qualify as an native error', () => {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user