Compare commits

...

50 Commits

Author SHA1 Message Date
github-actions[bot]
b970102bfc chore: update versions (6-next) (#2456)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2021-10-15 23:13:06 +02:00
Juan Picado
b702ea3631 abort search request support for proxy (#2474)
* update undici

* abort search request support for proxy
2021-10-15 23:00:30 +02:00
Juan Picado
794af76c50 Remove Node 12 support (v6.x) (#2473) 2021-10-15 18:49:47 +02:00
Oscar Dominguez
6218d7723d refactor(ci): fix typo in filename (#2471) 2021-10-14 08:14:05 +02:00
Leonardo Metzger
b261741ef6 refactor: Remove some FIXME annotations (#2465)
* refactor: Remove the @ts-ignore in middleware-utils

* refactor: Remove __mocks__ imports in local-storage package

Co-authored-by: Juan Picado <juanpicado19@gmail.com>
2021-10-03 14:21:01 +02:00
Juan Picado
61add32bff ci: avoid crowdin step is mandatory (#2466)
* avoid crowdin step is mandatory

* make it fail

* split step

* split step

* try again

* try again

* restore key

* add comment

* improve wording

* test something

* test something

* restore key
2021-10-03 14:04:24 +02:00
Andreas Opferkuch
b753b4010f website: Improve docs link discoverability (#2462)
... by flipping the underline behavior within articles
2021-10-01 17:51:04 +02:00
Juan Picado
c168b4e47a chore: update benchmark version 2021-09-26 10:39:45 +02:00
Juan Picado
3a7f81ab0c chore: delete changelog
now is located in verdaccio package
2021-09-26 08:21:44 +02:00
Juan Picado
154b2ecd34 refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplication (#2455)
* migrate api package

* migrate auth

* migrate config

* refactor: remove @verdaccio/commons-api in favor @verdaccio/core

* fix lint

* relocate pkg

* relocate pkg

* fix tsconfig
2021-09-26 00:08:00 +02:00
github-actions[bot]
cd7947adbc chore: update versions (6-next) (#2450)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2021-09-25 17:44:58 +02:00
Juan Picado
5fed1955a9 refactor: rematch as web state storage for UI (#2447)
* trying rematch

refactor: rematch for store packages

migrate login to rematch

Update packages/plugins/ui-theme/src/store/store.ts

Co-authored-by: Sergio Moreno <sergiomorenoalbert@gmail.com>

hide temporary

fix test for login

migrate package download resource

fix tests

* add missing fixture

* migrate detail page support

* fix tests

* migrate search

* migrate search

* clean up tests

* remove tags

* fix lint

* add changeset

* fix: search model typings

* add type

* types

* apply suggestions

Co-authored-by: Sergio Moreno <22656541+semoal@users.noreply.github.com>
2021-09-25 17:35:03 +02:00
Juan Picado
9dbf73e955 remove typedoc dep, not need it now to fix the changesets 2021-09-19 21:34:38 +02:00
Zameer Haque
2c594910d8 fix: do not throw multiple logger deprecation warning if using default logger config (#2446) 2021-09-19 20:20:46 +02:00
Juan Picado
90818700a3 rename translation file (#2445)
avoid ui translations are being uploaded
2021-09-18 12:45:27 +02:00
Juan Picado
7af1e6cc84 update readme 2021-09-18 11:46:15 +02:00
Juan Picado
757bded72e improve ci syn translations 2021-09-18 10:01:22 +02:00
Juan Picado
1b9bf35c87 add steps to add new languages to ui contributing guidelines 2021-09-18 09:43:14 +02:00
Juan Picado
eb2afc4d6d sync translations on merge in master 2021-09-18 09:20:24 +02:00
Juan Picado
5be013a059 update contributing guidelines and chat reference 2021-09-18 09:07:22 +02:00
Juan Picado
8d6d6097c6 refactor: using ui translations from crowdin (#2442)
* refactor: using ui translations from crowdin

* move tasks

* fix tests
2021-09-17 21:19:50 +02:00
Juan Picado
531289f59d update ui crowdin assets 2021-09-17 07:41:11 +02:00
Juan Picado
5e784d1188 refactor: one single file for i18n conf ui (#2440)
* refactor: one single file for i18n conf ui

* add test for crowdin

* cleanup

* space
2021-09-17 07:17:34 +02:00
Juan Picado
7dde848d0c refactor: replace flag icons with library (#2439)
* feat: simplify i18n translations config and flags

* fix icons

* lint

* update test
2021-09-16 21:46:56 +02:00
Justin Johansson
71874de027 build: upgrade to husky@7.0.2 & configure for lint-staged (#2436) 2021-09-16 07:03:57 +02:00
Joon du Randt
f13dacef9c Updated config map param name in helm example (#2435) 2021-09-14 20:38:50 +02:00
Juan Picado
761f1696f2 update e2e page docs 2021-09-13 22:14:09 +02:00
Juan Picado
f412e8f8d6 Update README.md 2021-09-13 20:56:55 +02:00
rvo
f5fd7bf5bf docs(docker): spelling and minor grammar fix (#2434) 2021-09-12 21:23:02 +02:00
Juan Picado
3d26a8190c eslint deps (#2433)
* eslint deps

* Update pnpm-lock.yaml
2021-09-12 20:33:24 +02:00
Juan Picado
e50410a875 feat: fastify search endpoint v1 without auth and format (#2432) 2021-09-12 17:12:47 +02:00
Juan Picado
60d7b35d88 refactor: search logic to storage pkg (#2431)
* refactor: search logic to storage pkg

* add test

* update undici

* add tests

* Update ci.yml

* fix ci

* fix tests

* fix ci

* fix tests

* fix ci

* restore some deps

* Update Version.test.tsx

* disable debug
2021-09-12 16:21:19 +02:00
Juan Picado
1042f9bf76 update benchmark with v6.0.0-6-next.23 2021-09-08 20:32:38 +02:00
github-actions[bot]
e10637f0f3 chore: update versions (6-next) (#2427)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2021-09-08 19:33:09 +02:00
Juan Picado
459b6fa72b refactor: search v1 endpoint and local-database (#2340)
* Refactor local-storage async

refactor local storage search stream

Remove async from local-storage, refactor search with streams

refactor search with undici fetch

finish search refactor

stream multiple request to single stream

refactor storage types

remove async dependency #1225

add score and refactor metadata

remove old search async

fix missing stream local data

clean up

clean up

refactor folder search

format

fix some test

fix issue on publish

filter preview

update ci

delete package folder refactor

refactor get packages methods

fix tests

fix lock file

add changeset

fix test windows

disable some test

update package json versions

* fix merge

* fix e2e cli

* restore e2e

* Update process.ts

* Update process.ts

* add improvement

* format

* Update utils.ts

* test

* test

* Update search.spec.ts

* Update search.spec.ts

* Update search.spec.ts

* test

* Update ci.yml

* clean up

* fix tests

* Update tags.ts

* Update index.spec.ts

* document changeset

* format
2021-09-08 19:06:37 +02:00
Juan Picado
10868ed434 chore: bump up website version 2021-09-08 07:05:25 +02:00
Juan Picado
ada8165f98 website: add video channel logo access 2021-09-08 07:04:35 +02:00
Juan Picado
57755f31ba docs: update talks document 2021-09-08 06:56:59 +02:00
Snyk bot
9e29bf8890 fix: docker-examples/v5/reverse_proxy/nginx_relative/nginx_ssl/Dockerfile to reduce vulnerabilities (#2417)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-DEBIAN10-GLIBC-1315333
- https://snyk.io/vuln/SNYK-DEBIAN10-OPENSSL-1569403
- https://snyk.io/vuln/SNYK-DEBIAN10-OPENSSL-1569403
- https://snyk.io/vuln/SNYK-DEBIAN10-OPENSSL-1569406
- https://snyk.io/vuln/SNYK-DEBIAN10-OPENSSL-1569406
2021-09-04 17:02:22 +02:00
Snyk bot
e2a67bafbe fix: docker-examples/v4/reverse_proxy/nginx/relative_path/nginx_ssl/Dockerfile to reduce vulnerabilities (#2416)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-DEBIAN10-GLIBC-1315333
- https://snyk.io/vuln/SNYK-DEBIAN10-OPENSSL-1569403
- https://snyk.io/vuln/SNYK-DEBIAN10-OPENSSL-1569403
- https://snyk.io/vuln/SNYK-DEBIAN10-OPENSSL-1569406
- https://snyk.io/vuln/SNYK-DEBIAN10-OPENSSL-1569406
2021-09-04 17:02:09 +02:00
Justin Johansson
7c9561b019 Indiescripter/last misc deps update for now (#2422)
* build: update @babel/* devDeps

* build(ui-theme): update terser-webpack-plugin devDep

* build(e2e-cli): update npm & pnpm latest deps published yesterday

* build(ui-theme): update react-router-dom devDep

* build(standalone/ui-theme): update webpack devDev published today

* build(memory): update memfs dep published yesterday

* build(active-directory): update dep activedirectory2 major version

* build: remove currently unused devDep @types/lowdb

* build(fastify-migration/hooks/local-storage/mock/node-api/verdaccio-htpasswd): update dep core-js

* build: remove @commitlint/* devDeps no longer used in master

* build(ui-theme): update @testing-library/react devDep major version
2021-09-04 14:33:45 +02:00
Juan Picado
ed3677a5b6 fix format 2021-09-04 10:35:32 +02:00
Juan Picado
055544238a Update README.md 2021-09-04 10:31:46 +02:00
Juan Picado
4937dba06e Update README.md 2021-09-04 10:30:28 +02:00
Justin Johansson
3e65791564 Indiescripter/upgrade website docusaurus (#2414)
* build(website): update @docusaurus/* deps & devDeps to v2.0.0-beta.6

* build(website): update devDeps esbuild (patch), sass (minor)

* build: pin some innocuous devDeps versions to restart GH CI
2021-09-04 10:29:15 +02:00
Juan Picado
cf1b6cdb04 allow workflow_dispatch on benchmark 2021-09-04 09:57:30 +02:00
Juan Picado
ca86082e08 fix benchmarks 2021-09-04 09:54:38 +02:00
Juan Picado
ef60e83d6c update benchmarks settings 2021-09-04 09:32:18 +02:00
github-actions[bot]
ff1822c961 chore: update versions (6-next) (#2419) 2021-09-04 08:59:14 +02:00
Justin Johansson
df0da3d699 fix(core/hooks/mock/node-api): add missing core-js dep (#2418) 2021-09-04 08:47:57 +02:00
455 changed files with 13279 additions and 12229 deletions

View File

@@ -7,7 +7,7 @@
"version": 3, "proposals": true
},
"targets": {
"node": 12
"node": 14
}
}
],

View 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[]>;
}
```

View 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

View 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

View File

@@ -0,0 +1,5 @@
---
'@verdaccio/ui-theme': minor
---
feat: integrate rematch for ui state storage

View 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

View File

@@ -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",

View 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

View File

@@ -0,0 +1,5 @@
---
'@verdaccio/logger': patch
---
do not show deprecation warning on default logger config

View File

@@ -9,3 +9,5 @@ static/
website/
wiki/
dist/
docs/
test/functional/store/*

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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
View File

@@ -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
View File

@@ -0,0 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
#./node_modules/.bin/lint-staged
npm run husky:pre-commit

2
.npmrc
View File

@@ -1,5 +1,5 @@
always-auth = true
recursive-install = true
registry = https://registry.verdaccio.org
loglevel=warn
loglevel=info
fetch-retries="10"

2
.nvmrc
View File

@@ -1 +1 @@
14
16

View File

@@ -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
View File

@@ -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,

View File

@@ -2,7 +2,7 @@
{
"files.exclude": {
"**/.nyc_output": true,
"**/build": true,
"**/build": false,
"**/coverage": true,
".idea": true,
"storage_default_storage": true,

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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 \

View File

@@ -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**.
[![beerjscrb](https://cdn.verdaccio.dev/readme/react-finland-2021-jpicado.jpeg)](https://react-finland.fi/schedule/#testing-the-integrity-of-your-react-components-by-publishing-in-a-private-registry)
[![beerjscrb](https://cdn.verdaccio.dev/readme/react-finland-2021-jpicado.jpeg)](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 | [![jetbrain](assets/thanks/jetbrains/logo.png)](https://www.jetbrains.com/) | JetBrains provides licenses for products for active maintainers, renewable yearly |
| Crowdin | [![crowdin](assets/thanks/crowdin/logo.png)](https://crowdin.com/) | Crowdin provides platform for translations |
| BrowserStack | [![browserstack](https://cdn.verdaccio.dev/readme/browserstack_logo.png)](https://www.browserstack.com/) | BrowserStack provides plan to run End to End testing for the UI |
| Netlify | [![netlify](https://www.netlify.com/img/global/badges/netlify-color-accent.svg)](https://www.netlify.com/) | Netlify provides pro plan for website deployment |
| Algolia | [![algolia](https://cdn.verdaccio.dev/sponsor/logo/algolia/logo.png)](https://algolia.com/) | Algolia provides search services for the website |
| Docker | [![docker](https://cdn.verdaccio.dev/sponsor/logo/docker/docker.png)](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
[![backers](https://opencollective.com/verdaccio/backers.svg?width=890)](https://opencollective.com/verdaccio#backers)
## Special Thanks
Thanks to the following companies to help us to achieve our goals providing free open source licenses.
[![jetbrain](assets/thanks/jetbrains/logo.png)](https://www.jetbrains.com/)
[![crowdin](assets/thanks/crowdin/logo.png)](https://crowdin.com/)
[![browserstack](https://cdn.verdaccio.dev/readme/browserstack_logo.png)](https://www.browserstack.com/)
[![netlify](https://www.netlify.com/img/global/badges/netlify-color-accent.svg)](https://www.netlify.com/)
[![algolia](https://cdn.verdaccio.dev/sponsor/logo/algolia/logo.png)](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)

View File

@@ -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%',
}
]
]

View File

@@ -1,4 +1,4 @@
FROM nginx
FROM nginx:1
COPY cert.crt /etc/nginx/cert.crt
COPY cert.key /etc/nginx/cert.key

View File

@@ -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",

View File

@@ -1,4 +1,4 @@
FROM nginx
FROM nginx:1
COPY cert.crt /etc/nginx/cert.crt
COPY cert.key /etc/nginx/cert.key

View File

@@ -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.

View File

@@ -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.

View File

@@ -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"

View File

@@ -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

View File

@@ -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"

View File

@@ -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,
});
}
);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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' });
});
}

View File

@@ -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,

View File

@@ -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 => {

View File

@@ -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;

View File

@@ -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));
}
}
);

View File

@@ -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;
}
});
}

View File

@@ -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());
}
);
}

View File

@@ -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');

View File

@@ -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)

View File

@@ -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)

View File

@@ -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', () => {

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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());
});
});

View File

@@ -14,7 +14,7 @@
"path": "../config"
},
{
"path": "../core/commons-api"
"path": "../core/core"
},
{
"path": "../core/tarball"

View File

@@ -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

View File

@@ -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",

View File

@@ -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} `, '');

View File

@@ -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}`)
);
}
};
}

View File

@@ -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));
});
});
});

View File

@@ -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());
});
});

View File

@@ -10,9 +10,6 @@
{
"path": "../config"
},
{
"path": "../core/commons-api"
},
{
"path": "../core/htpasswd"
},

View File

@@ -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

View File

@@ -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",

View File

@@ -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);

View File

@@ -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

View File

@@ -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",

View File

@@ -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:

View File

@@ -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';

View File

@@ -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);
}

View File

@@ -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['**'])) {

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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/);
});
});
});

View File

@@ -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();
});
}
});

View File

@@ -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();
});
});
});

View File

@@ -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

View File

@@ -7,9 +7,6 @@
"include": ["src/**/*.ts"],
"exclude": ["src/**/*.test.ts"],
"references": [
{
"path": "../core/commons-api"
},
{
"path": "../utils"
}

View File

@@ -1,15 +0,0 @@
# @verdaccio/commons-api
commons api utilities for verdaccio
[![verdaccio (latest)](https://img.shields.io/npm/v/@verdaccio/commons-api/latest.svg)](https://www.npmjs.com/package/@verdaccio/commons-api)
[![docker pulls](https://img.shields.io/docker/pulls/verdaccio/verdaccio.svg?maxAge=43200)](https://verdaccio.org/docs/en/docker.html)
[![backers](https://opencollective.com/verdaccio/tiers/backer/badge.svg?label=Backer&color=brightgreen)](https://opencollective.com/verdaccio)
[![stackshare](https://img.shields.io/badge/Follow%20on-StackShare-blue.svg?logo=stackshare&style=flat)](https://stackshare.io/verdaccio)
[![discord](https://img.shields.io/discord/388674437219745793.svg)](http://chat.verdaccio.org/)
[![node](https://img.shields.io/node/v/@verdaccio/commons-api/latest.svg)](https://www.npmjs.com/package/@verdaccio/commons-api)
![MIT](https://img.shields.io/github/license/mashape/apistatus.svg)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/verdaccio/localized.svg)](https://crowdin.com/project/verdaccio)
[![Twitter followers](https://img.shields.io/twitter/follow/verdaccio_npm.svg?style=social&label=Follow)](https://twitter.com/verdaccio_npm)
[![Github](https://img.shields.io/github/stars/verdaccio/verdaccio.svg?style=social&label=Stars)](https://github.com/verdaccio/verdaccio/stargazers)

View File

@@ -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;
}

View File

@@ -0,0 +1,6 @@
node_modules
coverage/
lib/
.nyc_output
tests-report/
build/

View File

@@ -0,0 +1,5 @@
{
"rules": {
"@typescript-eslint/no-use-before-define": "off"
}
}

View 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[]>;
}
```

View File

@@ -0,0 +1,19 @@
# Core
[![CircleCI](https://circleci.com/gh/verdaccio/streams.svg?style=svg)](https://circleci.com/gh/ayusharma/@verdaccio/streams)
[![codecov](https://codecov.io/gh/verdaccio/streams/branch/master/graph/badge.svg)](https://codecov.io/gh/verdaccio/streams)
[![verdaccio (latest)](https://img.shields.io/npm/v/@verdaccio/streams/latest.svg)](https://www.npmjs.com/package/@verdaccio/streams)
[![backers](https://opencollective.com/verdaccio/tiers/backer/badge.svg?label=Backer&color=brightgreen)](https://opencollective.com/verdaccio)
[![discord](https://img.shields.io/discord/388674437219745793.svg)](http://chat.verdaccio.org/)
![MIT](https://img.shields.io/github/license/mashape/apistatus.svg)
[![node](https://img.shields.io/node/v/@verdaccio/streams/latest.svg)](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)

View File

@@ -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",

View 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}`;

View File

@@ -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';

View File

@@ -0,0 +1,3 @@
export const Files = {
DatabaseName: '.verdaccio-db.json',
};

View 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,
};

View File

View 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;
}
}
}
}

View 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[]>;
}

View 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;

View 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 };

View 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
);
}

View File

@@ -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