Compare commits
46 Commits
@verdaccio
...
@verdaccio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
554020ec70 | ||
|
|
1e5cef8211 | ||
|
|
7cbd4736c6 | ||
|
|
15f3fba094 | ||
|
|
a2ac67147d | ||
|
|
ebec9354b0 | ||
|
|
173b07f627 | ||
|
|
e217709f31 | ||
|
|
8d86ec764f | ||
|
|
b4cc80017e | ||
|
|
cbae6e52aa | ||
|
|
48e4c4308c | ||
|
|
dc5b09616d | ||
|
|
d22673c61d | ||
|
|
2f835ac09e | ||
|
|
852324c321 | ||
|
|
54606976c3 | ||
|
|
484ecae3d2 | ||
|
|
235d350dc1 | ||
|
|
af90e35cd1 | ||
|
|
791988a9aa | ||
|
|
64cfedb805 | ||
|
|
bf36b9477c | ||
|
|
737684e592 | ||
|
|
e6fc774d44 | ||
|
|
1adb22553a | ||
|
|
93dd256b21 | ||
|
|
404ab31e06 | ||
|
|
8897bdeb5d | ||
|
|
717a36dd94 | ||
|
|
25e0d4cb67 | ||
|
|
7ab5f0167e | ||
|
|
07488a9ddb | ||
|
|
96d7295e55 | ||
|
|
af7d493b80 | ||
|
|
9d93a9a6b2 | ||
|
|
4d44a91d89 | ||
|
|
52be1eccb0 | ||
|
|
00942e6d20 | ||
|
|
0041d9407d | ||
|
|
3dc8591e26 | ||
|
|
ce013d2fcc | ||
|
|
6ad13de884 | ||
|
|
0783eeec1e | ||
|
|
d4e6a6e2bf | ||
|
|
0ebac198ce |
@@ -3,7 +3,6 @@
|
||||
'@verdaccio/auth': major
|
||||
'@verdaccio/cli': major
|
||||
'@verdaccio/config': major
|
||||
'@verdaccio/commons-api': major
|
||||
'@verdaccio/core': major
|
||||
'@verdaccio/local-storage': major
|
||||
'@verdaccio/server-fastify': major
|
||||
@@ -19,7 +18,6 @@
|
||||
'@verdaccio/server': major
|
||||
'@verdaccio/store': major
|
||||
'@verdaccio/eslint-config': major
|
||||
'@verdaccio/dev-types': major
|
||||
'@verdaccio/utils': major
|
||||
'verdaccio': major
|
||||
'@verdaccio/web': major
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
'@verdaccio/server': major
|
||||
'@verdaccio/cli-standalone': major
|
||||
'@verdaccio/store': major
|
||||
'@verdaccio/dev-types': major
|
||||
'@verdaccio/utils': major
|
||||
'verdaccio': major
|
||||
'@verdaccio/web': major
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
'@verdaccio/auth': major
|
||||
'@verdaccio/cli': major
|
||||
'@verdaccio/config': major
|
||||
'@verdaccio/commons-api': major
|
||||
'@verdaccio/file-locking': major
|
||||
'verdaccio-htpasswd': major
|
||||
'@verdaccio/local-storage': major
|
||||
@@ -25,7 +24,6 @@
|
||||
'@verdaccio/proxy': major
|
||||
'@verdaccio/server': major
|
||||
'@verdaccio/store': major
|
||||
'@verdaccio/dev-types': major
|
||||
'@verdaccio/utils': major
|
||||
'verdaccio': major
|
||||
'@verdaccio/web': major
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
'@verdaccio/auth': major
|
||||
'@verdaccio/cli': major
|
||||
'@verdaccio/config': major
|
||||
'@verdaccio/commons-api': major
|
||||
'@verdaccio/file-locking': major
|
||||
'verdaccio-htpasswd': major
|
||||
'@verdaccio/local-storage': major
|
||||
@@ -19,7 +18,6 @@
|
||||
'@verdaccio/proxy': major
|
||||
'@verdaccio/server': major
|
||||
'@verdaccio/store': major
|
||||
'@verdaccio/dev-types': major
|
||||
'@verdaccio/utils': major
|
||||
'verdaccio': major
|
||||
'@verdaccio/web': major
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
'@verdaccio/auth': patch
|
||||
'@verdaccio/cli': patch
|
||||
'@verdaccio/config': patch
|
||||
'@verdaccio/commons-api': patch
|
||||
'@verdaccio/file-locking': patch
|
||||
'verdaccio-htpasswd': patch
|
||||
'@verdaccio/readme': patch
|
||||
@@ -26,7 +25,6 @@
|
||||
'verdaccio-memory': patch
|
||||
'@verdaccio/proxy': patch
|
||||
'@verdaccio/store': patch
|
||||
'@verdaccio/dev-types': patch
|
||||
'@verdaccio/utils': patch
|
||||
'verdaccio': patch
|
||||
'@verdaccio/web': patch
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
'@verdaccio/auth': minor
|
||||
'@verdaccio/cli': minor
|
||||
'@verdaccio/config': minor
|
||||
'@verdaccio/commons-api': minor
|
||||
'@verdaccio/file-locking': minor
|
||||
'verdaccio-htpasswd': minor
|
||||
'@verdaccio/local-storage': minor
|
||||
@@ -26,7 +25,6 @@
|
||||
'@verdaccio/proxy': minor
|
||||
'@verdaccio/server': minor
|
||||
'@verdaccio/store': minor
|
||||
'@verdaccio/dev-types': minor
|
||||
'@verdaccio/utils': minor
|
||||
'verdaccio': minor
|
||||
'@verdaccio/web': minor
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
'@verdaccio/auth': minor
|
||||
'@verdaccio/cli': minor
|
||||
'@verdaccio/config': minor
|
||||
'@verdaccio/commons-api': minor
|
||||
'@verdaccio/file-locking': minor
|
||||
'verdaccio-htpasswd': minor
|
||||
'@verdaccio/local-storage': minor
|
||||
@@ -19,7 +18,6 @@
|
||||
'@verdaccio/proxy': minor
|
||||
'@verdaccio/server': minor
|
||||
'@verdaccio/store': minor
|
||||
'@verdaccio/dev-types': minor
|
||||
'@verdaccio/utils': minor
|
||||
'verdaccio': minor
|
||||
'@verdaccio/web': minor
|
||||
|
||||
@@ -54,7 +54,8 @@
|
||||
"@verdaccio/local-publish": "0.0.1",
|
||||
"@verdaccio/e2e-cli-npm9": "1.0.1-6-next.5",
|
||||
"@verdaccio/e2e-ui": "2.0.0-6-next.3",
|
||||
"customprefix-auth": "0.0.1"
|
||||
"customprefix-auth": "0.0.1",
|
||||
"@verdaccio/crowdin-translations": "1.0.0"
|
||||
},
|
||||
"changesets": [
|
||||
"afraid-mice-obey",
|
||||
@@ -114,12 +115,14 @@
|
||||
"proud-jobs-hope",
|
||||
"red-chefs-float",
|
||||
"red-yaks-sell",
|
||||
"rich-badgers-begin",
|
||||
"rich-ghosts-rule",
|
||||
"shaggy-carrots-unite",
|
||||
"shaggy-parrots-smash",
|
||||
"shiny-chefs-heal",
|
||||
"shy-ducks-cover",
|
||||
"slow-carrots-relate",
|
||||
"slow-snails-sniff",
|
||||
"smart-apricots-kneel",
|
||||
"smart-beds-cross",
|
||||
"smooth-owls-pump",
|
||||
@@ -138,6 +141,7 @@
|
||||
"tiny-seals-join",
|
||||
"tricky-taxis-watch",
|
||||
"two-dolls-check",
|
||||
"unlucky-hairs-wonder",
|
||||
"wild-jokes-beam",
|
||||
"witty-ties-speak"
|
||||
]
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
'@verdaccio/auth': patch
|
||||
'@verdaccio/cli': patch
|
||||
'@verdaccio/config': patch
|
||||
'@verdaccio/commons-api': patch
|
||||
'@verdaccio/file-locking': patch
|
||||
'verdaccio-htpasswd': patch
|
||||
'@verdaccio/local-storage': patch
|
||||
@@ -19,7 +18,6 @@
|
||||
'@verdaccio/proxy': patch
|
||||
'@verdaccio/server': patch
|
||||
'@verdaccio/store': patch
|
||||
'@verdaccio/dev-types': patch
|
||||
'@verdaccio/utils': patch
|
||||
'verdaccio': patch
|
||||
'@verdaccio/web': patch
|
||||
|
||||
9
.changeset/rich-badgers-begin.md
Normal file
9
.changeset/rich-badgers-begin.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@verdaccio/api': minor
|
||||
'@verdaccio/url': minor
|
||||
'@verdaccio/store': minor
|
||||
'@verdaccio/test-helper': minor
|
||||
'verdaccio': minor
|
||||
---
|
||||
|
||||
refactor: npm star command support reimplemented
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
'@verdaccio/types': major
|
||||
'@verdaccio/ui-theme': major
|
||||
'@verdaccio/dev-types': major
|
||||
'@verdaccio/web': major
|
||||
'@verdaccio/e2e-ui': major
|
||||
---
|
||||
|
||||
7
.changeset/slow-snails-sniff.md
Normal file
7
.changeset/slow-snails-sniff.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@verdaccio/api': patch
|
||||
'@verdaccio/ui-theme': patch
|
||||
'@verdaccio/web': patch
|
||||
---
|
||||
|
||||
fix: improve abort request search
|
||||
@@ -3,7 +3,6 @@
|
||||
'@verdaccio/auth': patch
|
||||
'@verdaccio/cli': patch
|
||||
'@verdaccio/config': patch
|
||||
'@verdaccio/commons-api': patch
|
||||
'@verdaccio/file-locking': patch
|
||||
'verdaccio-htpasswd': patch
|
||||
'@verdaccio/local-storage': patch
|
||||
@@ -18,7 +17,6 @@
|
||||
'@verdaccio/proxy': patch
|
||||
'@verdaccio/server': patch
|
||||
'@verdaccio/store': patch
|
||||
'@verdaccio/dev-types': patch
|
||||
'@verdaccio/utils': patch
|
||||
'verdaccio': patch
|
||||
---
|
||||
|
||||
5
.changeset/unlucky-hairs-wonder.md
Normal file
5
.changeset/unlucky-hairs-wonder.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@verdaccio/ui-theme': patch
|
||||
---
|
||||
|
||||
feat: Display publication time on sidebar
|
||||
18
.github/workflows/benchmark.yml
vendored
18
.github/workflows/benchmark.yml
vendored
@@ -18,8 +18,8 @@ jobs:
|
||||
name: Prepare build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
- name: install pnpm
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: install dependencies
|
||||
run: pnpm install
|
||||
- name: Cache .pnpm-store
|
||||
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -65,8 +65,8 @@ jobs:
|
||||
name: Benchmark autocannon
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
- uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 # tag=v3
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
- name: install pnpm
|
||||
# require fixed version
|
||||
run: sudo npm i pnpm@latest-6 -g
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -126,8 +126,8 @@ jobs:
|
||||
name: Benchmark hyperfine
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
- uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 # tag=v3
|
||||
@@ -138,7 +138,7 @@ jobs:
|
||||
- name: install pnpm
|
||||
# require fixed version
|
||||
run: sudo npm i pnpm@latest-6 -g
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
7
.github/workflows/changesets.yml
vendored
7
.github/workflows/changesets.yml
vendored
@@ -20,12 +20,12 @@ jobs:
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'verdaccio/verdaccio'
|
||||
steps:
|
||||
- name: checkout code repository
|
||||
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: setup node.js
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version: 14
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
@@ -47,8 +47,7 @@ jobs:
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.REGISTRY_AUTH_TOKEN }}
|
||||
- name: crowdin download
|
||||
env:
|
||||
CROWDIN_VERDACCIO_PROJECT_ID: ${{ secrets.CROWDIN_VERDACCIO_PROJECT_ID }}
|
||||
env:
|
||||
CROWDIN_VERDACCIO_API_KEY: ${{ secrets.CROWDIN_VERDACCIO_API_KEY }}
|
||||
CONTEXT: production
|
||||
run: pnpm crowdin:download
|
||||
|
||||
130
.github/workflows/ci-windows.yml
vendored
Normal file
130
.github/workflows/ci-windows.yml
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
name: CI windows
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '5 0 * * SUN'
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-latest
|
||||
name: setup verdaccio
|
||||
services:
|
||||
verdaccio:
|
||||
image: verdaccio/verdaccio:nightly-master
|
||||
ports:
|
||||
- 4873:4873
|
||||
env:
|
||||
NODE_ENV: production
|
||||
steps:
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Node
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- name: set store
|
||||
run: |
|
||||
mkdir ~/.pnpm-store
|
||||
pnpm config set store-dir ~/.pnpm-store
|
||||
- name: Install
|
||||
run: pnpm recursive install --frozen-lockfile --registry http://localhost:4873
|
||||
- name: Cache .pnpm-store
|
||||
uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
pnpm-
|
||||
lint:
|
||||
runs-on: windows-latest
|
||||
name: Lint
|
||||
needs: prepare
|
||||
steps:
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Node
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
- name: Install
|
||||
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts
|
||||
- name: Lint
|
||||
run: pnpm lint
|
||||
format:
|
||||
runs-on: windows-latest
|
||||
name: Format
|
||||
needs: prepare
|
||||
steps:
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Use Node
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
- name: Install
|
||||
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts
|
||||
- name: Lint
|
||||
run: pnpm format:check
|
||||
build:
|
||||
needs: [format, lint]
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [windows-latest]
|
||||
node_version: [18]
|
||||
name: ${{ matrix.os }} / Node ${{ matrix.node_version }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Use Node ${{ matrix.node_version }}
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
- name: Install
|
||||
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts --registry http://localhost:4873
|
||||
- name: build
|
||||
run: pnpm build
|
||||
- name: Test
|
||||
run: pnpm test
|
||||
ci-e2e-ui:
|
||||
needs: [format, lint]
|
||||
runs-on: windows-latest
|
||||
name: UI Test E2E
|
||||
steps:
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
- name: Install
|
||||
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --registry http://localhost:4873
|
||||
- name: build
|
||||
run: pnpm build
|
||||
- name: Test UI
|
||||
run: pnpm test:e2e:ui
|
||||
# env:
|
||||
# DEBUG: verdaccio:e2e*
|
||||
37
.github/workflows/ci.yml
vendored
37
.github/workflows/ci.yml
vendored
@@ -27,9 +27,9 @@ jobs:
|
||||
env:
|
||||
NODE_ENV: production
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Node
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
- name: Install
|
||||
run: pnpm recursive install --frozen-lockfile --registry http://localhost:4873
|
||||
- name: Cache .pnpm-store
|
||||
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -52,14 +52,14 @@ jobs:
|
||||
name: Lint
|
||||
needs: prepare
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Node
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -72,14 +72,14 @@ jobs:
|
||||
name: Format
|
||||
needs: prepare
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Use Node
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -97,14 +97,14 @@ jobs:
|
||||
name: ${{ matrix.os }} / Node ${{ matrix.node_version }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Use Node ${{ matrix.node_version }}
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -119,13 +119,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: UI Test E2E
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -143,13 +143,13 @@ jobs:
|
||||
name: synchronize translations
|
||||
if: (github.event_name == 'push' && github.ref == 'refs/heads/master') || github.event_name == 'workflow_dispatch'
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -162,7 +162,6 @@ jobs:
|
||||
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
|
||||
|
||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@86f3159a697a097a813ad9bfa0002412d97690a4 # tag=v2
|
||||
uses: github/codeql-action/init@807578363a7869ca324a79039e6db9c843e0e100 # tag=v2
|
||||
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@86f3159a697a097a813ad9bfa0002412d97690a4 # tag=v2
|
||||
uses: github/codeql-action/autobuild@807578363a7869ca324a79039e6db9c843e0e100 # tag=v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -56,4 +56,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@86f3159a697a097a813ad9bfa0002412d97690a4 # tag=v2
|
||||
uses: github/codeql-action/analyze@807578363a7869ca324a79039e6db9c843e0e100 # tag=v2
|
||||
|
||||
2
.github/workflows/docker-publish.yml
vendored
2
.github/workflows/docker-publish.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- uses: docker/setup-qemu-action@27d0a4f181a40b142cce983c5393082c365d1480 # tag=v1
|
||||
- uses: docker/setup-buildx-action@v1
|
||||
with:
|
||||
|
||||
26
.github/workflows/e2e-ci.yml
vendored
26
.github/workflows/e2e-ci.yml
vendored
@@ -15,9 +15,9 @@ jobs:
|
||||
env:
|
||||
NODE_ENV: production
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Use Node
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
- name: Install
|
||||
run: pnpm recursive install --frozen-lockfile --reporter=silence --ignore-scripts --registry http://localhost:4873
|
||||
- name: Cache .pnpm-store
|
||||
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.run_id }}-${{ github.sha }}
|
||||
@@ -39,14 +39,14 @@ jobs:
|
||||
needs: [prepare]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- name: Use Node 16
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.run_id }}-${{ github.sha }}
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
- name: build
|
||||
run: pnpm build
|
||||
- name: Cache packages
|
||||
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
id: cache-packages
|
||||
with:
|
||||
path: ./packages/
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
restore-keys: |
|
||||
packages-
|
||||
# - name: Cache test
|
||||
# uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
# uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
# id: cache-test
|
||||
# with:
|
||||
# path: ./e2e/
|
||||
@@ -79,23 +79,23 @@ jobs:
|
||||
name: ${{ matrix.pkg }} / ${{ matrix.os }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
- uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install pnpm
|
||||
run: npm i pnpm@6.32.15 -g
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.run_id }}-${{ github.sha }}
|
||||
- name: Install
|
||||
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts --registry http://localhost:4873
|
||||
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
- uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: ./packages/
|
||||
key: pkg-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.run_id }}-${{ github.sha }}
|
||||
# - uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
# - uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
# with:
|
||||
# path: ./e2e/
|
||||
# key: test-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.run_id }}-${{ github.sha }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: contributors
|
||||
name: static data
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -15,13 +15,13 @@ jobs:
|
||||
name: Run script
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
- uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version: 17.x
|
||||
node-version: 18.x
|
||||
- name: install pnpm
|
||||
run: sudo npm i pnpm@latest-6 -g
|
||||
- name: set store
|
||||
@@ -32,17 +32,23 @@ jobs:
|
||||
run: pnpm config set registry https://registry.verdaccio.org
|
||||
- name: install dependencies
|
||||
run: pnpm install
|
||||
- name: Build Translations percentage
|
||||
run: pnpm build --filter "@verdaccio/crowdin-translations"
|
||||
- name: update contributors
|
||||
run: pnpm run contributors
|
||||
env:
|
||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: update translations
|
||||
run: pnpm run translations
|
||||
env:
|
||||
TOKEN: ${{ secrets.CROWDIN_VERDACCIO_API_KEY }}
|
||||
- name: format
|
||||
run: pnpm format
|
||||
- name: Commit & Push changes
|
||||
uses: actions-js/push@a52398fac807b0c1e5f1492c969b477c8560a0ba # tag=v1.3
|
||||
with:
|
||||
github_token: ${{ secrets.TOKEN_VERDACCIOBOT_GITHUB }}
|
||||
message: "chore: updated contributors list"
|
||||
message: "chore: updated static data"
|
||||
branch: master
|
||||
author_email: verdaccio.npm@gmail.com
|
||||
author_name: verdacciobot
|
||||
21
.github/workflows/website.yml
vendored
21
.github/workflows/website.yml
vendored
@@ -8,21 +8,22 @@ on:
|
||||
- './.github/workflows/website.yml'
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
|
||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||
|
||||
- name: Use Node 16
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
|
||||
uses: actions/setup-node@969bd2663942d722d85b6a8626225850c2f7be4b # tag=v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Cache pnpm modules
|
||||
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
env:
|
||||
cache-name: cache-pnpm-modules
|
||||
with:
|
||||
@@ -31,16 +32,18 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.node-version }}-
|
||||
|
||||
- uses: pnpm/action-setup@10693b3829bf86eb2572aef5f3571dcf5ca9287d # tag=v2.2.2
|
||||
- uses: pnpm/action-setup@c3b53f6a16e57305370b4ae5a540c2077a1d50dd # tag=v2.2.4
|
||||
with:
|
||||
version: 6.32.15
|
||||
run_install: |
|
||||
- recursive: true
|
||||
args: [--frozen-lockfile]
|
||||
- name: Build Plugins
|
||||
run: pnpm build --filter "docusaurus-plugin-contributors"
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
- name: Build Translations percentage
|
||||
run: pnpm build --filter "@verdaccio/crowdin-translations"
|
||||
- name: Cache Docusaurus Build
|
||||
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
|
||||
uses: actions/cache@56461b9eb0f8438fd15c7a9968e3c9ebb18ceff1 # tag=v3
|
||||
with:
|
||||
path: website/node_modules/.cache/webpack
|
||||
key: cache/webpack-${{github.ref}}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
@@ -52,8 +55,8 @@ jobs:
|
||||
- name: Build Production
|
||||
if: (github.event_name == 'push' && github.ref == 'refs/heads/master') || github.event_name == 'workflow_dispatch'
|
||||
env:
|
||||
CROWDIN_VERDACCIO_PROJECT_ID: ${{ secrets.CROWDIN_VERDACCIO_PROJECT_ID }}
|
||||
CROWDIN_VERDACCIO_API_KEY: ${{ secrets.CROWDIN_VERDACCIO_API_KEY }}
|
||||
SENTRY_KEY: ${{ secrets.SENTRY_KEY }}
|
||||
CONTEXT: production
|
||||
run: pnpm netlify:build:production --filter ...@verdaccio/website
|
||||
|
||||
@@ -98,7 +101,7 @@ jobs:
|
||||
|
||||
- name: Format lighthouse score
|
||||
id: format_lighthouse_score
|
||||
uses: actions/github-script@c713e510dbd7d213d92d41b7a7805a986f4c5c66 # tag=v6
|
||||
uses: actions/github-script@7dff1a87643417cf3b95bb10b29f4c4bc60d8ebd # tag=v6
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
|
||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -49,5 +49,11 @@ api-results*.json
|
||||
.clinic/
|
||||
|
||||
#docs
|
||||
./api
|
||||
**/docs/**
|
||||
website/docs/api/**/*.md
|
||||
website/docs/api/**/*.yml
|
||||
!website/docs/api/index.md
|
||||
packages/**/docs
|
||||
|
||||
# cypress
|
||||
e2e/ui/cypress/videos/**/*
|
||||
e2e/ui/cypress/screenshots/**/*
|
||||
|
||||
226
CONTRIBUTING.md
226
CONTRIBUTING.md
@@ -1,59 +1,33 @@
|
||||
# Contributing
|
||||
|
||||
> Any change matters, whatever the size, just do it.
|
||||
> This guidelines refers to the main (`master`) that host the v6.x, if you want to contribute to `5.x` please read the following [link](https://github.com/verdaccio/verdaccio/blob/5.x/CONTRIBUTING.md).
|
||||
|
||||
We're happy that you're considering contributing! To help, we've prepared these
|
||||
guidelines for you:
|
||||
We're happy that you're considering contributing!
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
- [Contributing](#contributing)
|
||||
- [How Do I Contribute?](#how-do-i-contribute)
|
||||
- [Development Setup](#development-setup)
|
||||
- [Building the project](#building-the-project)
|
||||
- [Running test](#running-test)
|
||||
- [Running and debugging](#running-and-debugging)
|
||||
- [Debugging compiled code](#debugging-compiled-code)
|
||||
- [Reporting Bugs](#reporting-bugs)
|
||||
- [Read the documentation](#read-the-documentation)
|
||||
- [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)
|
||||
- [Make Changes and Commit](#make-changes-and-commit)
|
||||
- [Caveats](#caveats)
|
||||
- [Before Commit](#before-commit)
|
||||
- [Commit Guidelines](#commit-guidelines)
|
||||
- [Adding a changeset](#adding-a-changeset)
|
||||
- [Update Tests](#update-tests)
|
||||
- [Develop Plugins](#develop-plugins)
|
||||
To help you getting started we've prepared these guidelines for you, any change matter, just do it:
|
||||
|
||||
## How Do I Contribute?
|
||||
|
||||
There are many ways to contribute:
|
||||
|
||||
- Report a bug
|
||||
- Request a feature you think would be great for Verdaccio
|
||||
- Fix bugs
|
||||
- Test and triage bugs reported by others
|
||||
- Work on requested/approved features
|
||||
- Improve the codebase (linting, naming, comments, test descriptions, etc...)
|
||||
- [Report a bug](#reporting-bugs)
|
||||
- [Request a feature you think would be great for Verdaccio](#feature-request)
|
||||
- [Fixing bugs](https://github.com/verdaccio/verdaccio/issues?q=is%3Aopen+is%3Aissue+label%3A%22issue%3A+bug%22)
|
||||
- [Test and triage bugs reported by others](https://github.com/verdaccio/verdaccio/issues?q=is%3Aopen+is%3Aissue+label%3Aissue_needs_triage)
|
||||
- [Working on requested/approved features](https://github.com/verdaccio/verdaccio/issues?q=is%3Aopen+is%3Aissue+label%3A%22topic%3A+feature+request%22+)
|
||||
- [Improve the codebase (linting, naming, comments, test descriptions, etc...)](https://github.com/verdaccio/verdaccio/discussions/1461)
|
||||
- Improve code coverage for unit testing for every module, [end to end](https://github.com/verdaccio/verdaccio/tree/master/e2e/cli) or [UI test](https://github.com/verdaccio/verdaccio/tree/master/e2e/ui) (with cypress).
|
||||
|
||||
The Verdaccio project is split into several areas:
|
||||
The Verdaccio project is split into several areas, the first three hosted in the main repository:
|
||||
|
||||
- **Core**: The [core](https://github.com/verdaccio/verdaccio) is the main repository, built with **Node.js**.
|
||||
- **Website**: we use [**Docusaurus**](https://docusaurus.io/) for the **website** and if you are familiar with this technology, you might become the official webmaster.
|
||||
- **User Interface**: The [user Interface](https://github.com/verdaccio/ui) is based in **react** and **material-ui** and looking for front-end contributors.
|
||||
- **Kubernetes and Helm**: Ts the official repository for the [**Helm chart**](https://github.com/verdaccio/charts).
|
||||
|
||||
> There are other areas to contribute, like documentation, translation which are
|
||||
> not hosted on this repo but check the last section of this notes for further
|
||||
> information.
|
||||
> There are other areas to contribute, like [documentation](https://github.com/verdaccio/verdaccio/tree/master/website/docs) or [translations](#translations}).
|
||||
|
||||
## Development Setup
|
||||
## Prepare local setup {#local-setup}
|
||||
|
||||
Verdaccio uses [pnpm](https://pnpm.io) as the package manager for development in this repository.
|
||||
|
||||
@@ -144,7 +118,7 @@ To run the application from the source code, ensure the project has been built w
|
||||
- `pnpm website`: Build the website, for more commands to run the _website_, run `cd website` and then `pnpm serve`, website will run on port `3000`.
|
||||
- `pnpm docker`: Build the docker image. Requires `docker` command available in your system.
|
||||
|
||||
#### Debugging compiled code
|
||||
#### Debugging compiled code {#debugging-compiled-code}
|
||||
|
||||
Currently you can only run pre-compiled packages in debug mode. To enable debug
|
||||
while running add the `verdaccio` namespace using the `DEBUG` environment
|
||||
@@ -164,13 +138,50 @@ DEBUG=verdaccio:plugin:* node packages/verdaccio/debug/bootstrap.js
|
||||
The debug code is intended to analyze what is happening under the hood and none
|
||||
of the output is sent to the logger module.
|
||||
|
||||
## Reporting Bugs
|
||||
> [See the full guide how to debug with Verdaccio](https://github.com/verdaccio/verdaccio/wiki/Debugging-Verdaccio)
|
||||
|
||||
#### Testing your changes in a local registry {#testing-local-registry}
|
||||
|
||||
Once you have perform your changes in the code base, the build and tests passes you can publish a local version:
|
||||
|
||||
- Ensure you have build all modules (or the one you have modified)
|
||||
- Run `pnpm local:publish:release` to launch a local registry and publish all packages into it. This command will be alive until server is killed (Control Key + C)
|
||||
|
||||
```
|
||||
pnpm build
|
||||
pnpm local:publish:release
|
||||
```
|
||||
|
||||
The last step consist on install globally the package from the local registry which runs on the default port (4873).
|
||||
|
||||
```
|
||||
npm i -g verdaccio --registry=http://localhost:4873
|
||||
verdaccio
|
||||
```
|
||||
|
||||
If you perform more changes in the source code, repeat this process, there is not _hot reloading_ support.
|
||||
|
||||
## Feature Request {#feature-request}
|
||||
|
||||
New feature requests are welcome. Analyse whether the idea fits within scope of the project. Adding in context and the use-case will really help!
|
||||
|
||||
**Please provide:**
|
||||
|
||||
- Create a [discussion](https://github.com/verdaccio/verdaccio/discussions/new).
|
||||
- A detailed description the advantages of your request.
|
||||
- Whether or not it's compatible with `npm`, `pnpm` and [_yarn classic_
|
||||
](https://github.com/yarnpkg/yarn) or [_yarn modern_
|
||||
](https://github.com/yarnpkg/berry).
|
||||
- A potential implementation or design
|
||||
- Whatever else is on your mind! 🤓
|
||||
|
||||
## Reporting Bugs {#reporting-bugs}
|
||||
|
||||
**Bugs are considered features that are not working as described in
|
||||
documentation.**
|
||||
|
||||
If you've found a bug in Verdaccio **that isn't a security risk**, please file
|
||||
a report in our [issue tracker](https://github.com/verdaccio/verdaccio/issues).
|
||||
a report in our [issue tracker](https://github.com/verdaccio/verdaccio/issues), if you think a potential vulnerability please read the [security policy](https://verdaccio.org/community/security) .
|
||||
|
||||
> **NOTE: Verdaccio still does not support all npm commands. Some were not
|
||||
> considered important and others have not been requested yet.**
|
||||
@@ -189,7 +200,7 @@ a report in our [issue tracker](https://github.com/verdaccio/verdaccio/issues).
|
||||
If you intend to report a **security** issue, please follow our [Security policy
|
||||
guidelines](https://github.com/verdaccio/verdaccio/security/policy).
|
||||
|
||||
### Issue Search
|
||||
### Issues {#issues}
|
||||
|
||||
Before reporting a bug please:
|
||||
|
||||
@@ -201,53 +212,21 @@ In case any of those match with your search, up-vote it (using GitHub reactions)
|
||||
or add additional helpful details to the existing issue to show that it's
|
||||
affecting multiple people.
|
||||
|
||||
### Chat
|
||||
### Contributing support
|
||||
|
||||
Questions can be asked via [Discord](https://discord.gg/7qWJxBf)
|
||||
|
||||
**Please use the `#help` channel.**
|
||||
**Please use the `#contribute` channel.**
|
||||
|
||||
## Translations
|
||||
## Development Guidelines {#development-guidelines}
|
||||
|
||||
All translations are provided by the `crowdin` platform:
|
||||
[https://translate.verdaccio.org/](https://translate.verdaccio.org/)
|
||||
It's recommended use a UNIX system for local development, Windows should works fine for development, but is not daily tested could not be perfect. To ensure a fast code review and merge, please follow the next guidelines:
|
||||
|
||||
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.
|
||||
Any contribution gives you the right to be part of this organization as _collaborator_ and your avatar will be automatically added to the [contributors page](https://verdaccio.org/contributors).
|
||||
|
||||
If a language is not listed, ask for it in the [Discord](https://discord.gg/7qWJxBf) channel #contribute channel.
|
||||
## Pull Request {#pull-request}
|
||||
|
||||
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
|
||||
the project. Adding in context and the use-case will really help!
|
||||
|
||||
**Please provide:**
|
||||
|
||||
- A detailed description the advantages of your request
|
||||
- Whether or not it's compatible with `npm`, `pnpm` and [_yarn classic_
|
||||
](https://github.com/yarnpkg/yarn) or [_yarn modern_
|
||||
](https://github.com/yarnpkg/berry).
|
||||
- A potential implementation or design
|
||||
- Whatever else is on your mind! 🤓
|
||||
|
||||
## Contributing Guidelines
|
||||
|
||||
It's very exciting to become a Verdaccio contributor 🙌🏼. To ensure a fast code
|
||||
review and merge, please follow the next guidelines:
|
||||
|
||||
> Any contribution gives you the right to be part of this organization as
|
||||
> _collaborator_.
|
||||
|
||||
### Submitting a Pull Request
|
||||
### Submitting a Pull Request {#submit-pull-request}
|
||||
|
||||
The following are the steps you should follow when creating a pull request.
|
||||
Subsequent pull requests only need to follow step 3 and beyond.
|
||||
@@ -275,10 +254,10 @@ Feel free to commit as much times you want in your branch, but keep on mind on
|
||||
this repository we `git squash` on merge by default, as we like to maintain a
|
||||
clean git history.
|
||||
|
||||
#### Before Commit
|
||||
#### Before Push {#before-push}
|
||||
|
||||
Before committing, **you must ensure there are no linting errors and
|
||||
all tests pass.** To do this, run these commands before creating the PR:
|
||||
Before committing or push, **you must ensure there are no linting errors and
|
||||
all tests passes**. To do verify, run these commands before creating the PR:
|
||||
|
||||
```bash
|
||||
pnpm lint
|
||||
@@ -292,40 +271,11 @@ pnpm test
|
||||
|
||||
All good? Perfect! You should create the pull request.
|
||||
|
||||
#### Commit Guidelines
|
||||
#### Commit Guidelines {#commits}
|
||||
|
||||
For example:
|
||||
On a pull request, commit messages are not important, please focus on document properly the pull request content. The commit message will be taken from the pull request title, it is recommended to use lowercase format.
|
||||
|
||||
- `feat: A new feature`
|
||||
- `fix: A bug fix`
|
||||
|
||||
A commit of the type feat introduces a new feature to the codebase (this
|
||||
correlates with MINOR in semantic versioning).
|
||||
|
||||
e.g.:
|
||||
|
||||
```
|
||||
feat: xxxxxxxxxx
|
||||
```
|
||||
|
||||
A commit of the type fix patches a bug in your codebase (this correlates with
|
||||
PATCH in semantic versioning).
|
||||
|
||||
e.g.:
|
||||
|
||||
```
|
||||
fix: xxxxxxxxxxx
|
||||
```
|
||||
|
||||
Commits types such as as `docs:`,`style:`,`refactor:`,`perf:`,`test:` and
|
||||
`chore:` are valid but have no effect on versioning: **please use them!**
|
||||
|
||||
All commits message are going to be validated when they are created using
|
||||
_husky_ hooks.
|
||||
|
||||
> Please try to provide one single commit to help a clean and easy merge process
|
||||
|
||||
### Adding a changeset
|
||||
### Adding a changeset {#changeset}
|
||||
|
||||
We use [changesets](https://github.com/atlassian/changesets) in order to
|
||||
generate a detailed Changelog as possible.
|
||||
@@ -407,7 +357,25 @@ If you need help with how testing works, please [refer to the following guide
|
||||
**If you are introducing new features, you MUST include new tests. PRs for
|
||||
features without tests will not be merged.**
|
||||
|
||||
## Develop Plugins
|
||||
## Translations {#translations}
|
||||
|
||||
All translations are provided by the **[crowdin](http://crowdin.com)** 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.
|
||||
|
||||
## Develop Plugins {#develop-plugins}
|
||||
|
||||
Plugins are add-ons that extend the functionality of the application.
|
||||
|
||||
@@ -420,25 +388,3 @@ If you want to develop your own plugin:
|
||||
3. You are free to host your plugin in your repository
|
||||
4. Provide a detailed description of your plugin to help users understand how to
|
||||
use it
|
||||
|
||||
## Testing your changes in a local registry
|
||||
|
||||
Once you have perform your changes in the code base, the build and tests passes you can publish a local version:
|
||||
|
||||
- Ensure you have build all modules (or the one you have modified)
|
||||
- Run `pnpm local:publish:release` to launch a local registry and publish all packages into it. This command will be alive until server is killed (Control Key + C)
|
||||
|
||||
```
|
||||
pnpm build
|
||||
pnpm local:publish:release
|
||||
```
|
||||
|
||||
The last step consist on install globally the package from the local registry.
|
||||
|
||||
```
|
||||
npm i -g verdaccio --registry=http://localhost:4873
|
||||
|
||||
verdaccio
|
||||
```
|
||||
|
||||
If you perform more changes in the source code, repeat this process, there is not _hot reloading_ support.
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/jotadeveloper/"><img src="https://avatars0.githubusercontent.com/u/558752?v=4" width="100px;" alt=""/><br /><sub><b>Juan Picado</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=juanpicado" title="Documentation">📖</a> <a href="https://github.com/verdaccio/verdaccio/commits?author=juanpicado" title="Code">💻</a> <a href="#infra-juanpicado" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#eventOrganizing-juanpicado" title="Event Organizing">📋</a> <a href="#blog-juanpicado" title="Blogposts">📝</a> <a href="#maintenance-juanpicado" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://github.com/sergiohgz"><img src="https://avatars3.githubusercontent.com/u/14012309?v=4" width="100px;" alt=""/><br /><sub><b>Sergio Herrera</b></sub></a><br /><a href="#infra-sergiohgz" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-sergiohgz" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://daniel-ruf.de/"><img src="https://avatars1.githubusercontent.com/u/827205?v=4" width="100px;" alt=""/><br /><sub><b>Daniel Ruf</b></sub></a><br /><a href="#security-DanielRuf" title="Security">🛡️</a> <a href="#infra-DanielRuf" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-DanielRuf" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://priscilawebdev.github.io/priscilaoliveira/"><img src="https://avatars1.githubusercontent.com/u/29228205?v=4" width="100px;" alt=""/><br /><sub><b>Priscila Oliveira</b></sub></a><br /><a href="#design-priscilawebdev" title="Design">🎨</a> <a href="https://github.com/verdaccio/verdaccio/commits?author=priscilawebdev" title="Code">💻</a> <a href="#maintenance-priscilawebdev" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="http://ayusharma.github.io/"><img src="https://avatars0.githubusercontent.com/u/6918450?v=4" width="100px;" alt=""/><br /><sub><b>Ayush Sharma</b></sub></a><br /><a href="#infra-ayusharma" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/verdaccio/verdaccio/commits?author=ayusharma" title="Code">💻</a> <a href="#design-ayusharma" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/trentearl"><img src="https://avatars2.githubusercontent.com/u/802857?v=4" width="100px;" alt=""/><br /><sub><b>Trent Earl</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=trentearl" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jmwilkinson"><img src="https://avatars0.githubusercontent.com/u/17836030?v=4" width="100px;" alt=""/><br /><sub><b>jmwilkinson</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=jmwilkinson" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/bufferoverflow"><img src="https://avatars2.githubusercontent.com/u/378909?v=4" width="100px;" alt=""/><br /><sub><b>Roger Meier</b></sub></a><br /><a href="#plugin-bufferoverflow" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="https://ghuser.io/jamesgeorge007"><img src="https://avatars2.githubusercontent.com/u/25279263?v=4" width="100px;" alt=""/><br /><sub><b>James George</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=jamesgeorge007" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/AvailCat"><img src="https://avatars3.githubusercontent.com/u/19658647?v=4" width="100px;" alt=""/><br /><sub><b>AvailCat</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=AvailCat" title="Code">💻</a> <a href="#infra-AvailCat" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-AvailCat" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://www.luciusgaitan.com/"><img src="https://avatars0.githubusercontent.com/u/5970350?v=4" width="100px;" alt=""/><br /><sub><b>Lucius Gaitán</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=lgaitan" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ramonornela"><img src="https://avatars1.githubusercontent.com/u/187946?v=4" width="100px;" alt=""/><br /><sub><b>Ramon Henrique Ornelas</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=ramonornela" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://people.freebsd.org/~mi/resume/"><img src="https://avatars1.githubusercontent.com/u/1486340?v=4" width="100px;" alt=""/><br /><sub><b>UnitedMarsupials-zz</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=UnitedMarsupials-zz" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.codingintrigue.co.uk/"><img src="https://avatars0.githubusercontent.com/u/9048902?v=4" width="100px;" alt=""/><br /><sub><b>Ryan Graham</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=ryan-codingintrigue" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/coolsp"><img src="https://avatars1.githubusercontent.com/u/1246647?v=4" width="100px;" alt=""/><br /><sub><b>coolsp</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=coolsp" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://ashishsurana.in/"><img src="https://avatars0.githubusercontent.com/u/5610944?v=4" width="100px;" alt=""/><br /><sub><b>Ashish Surana</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=ashishsurana" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/buffaybu"><img src="https://avatars3.githubusercontent.com/u/2025661?v=4" width="100px;" alt=""/><br /><sub><b>Wang Yifei</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=buffaybu" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://twitter.com/liran_tal"><img src="https://avatars1.githubusercontent.com/u/316371?v=4" width="100px;" alt=""/><br /><sub><b>Liran Tal</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=lirantal" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/brenordr"><img src="https://avatars2.githubusercontent.com/u/19731692?v=4" width="100px;" alt=""/><br /><sub><b>Breno Rodrigues</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=brenordr" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jachstet-sea"><img src="https://avatars0.githubusercontent.com/u/7993508?v=4" width="100px;" alt=""/><br /><sub><b>jachstet-sea</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=jachstet-sea" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://patrik.votocek.cz/"><img src="https://avatars1.githubusercontent.com/u/112567?v=4" width="100px;" alt=""/><br /><sub><b>Patrik Votoček</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=Vrtak-CZ" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/monkeywithacupcake"><img src="https://avatars3.githubusercontent.com/u/7316730?v=4" width="100px;" alt=""/><br /><sub><b>jess</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=monkeywithacupcake" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/toolsofraj"><img src="https://avatars0.githubusercontent.com/u/2507152?v=4" width="100px;" alt=""/><br /><sub><b>toolsofraj</b></sub></a><br /><a href="https://github.com/verdaccio/verdaccio/commits?author=toolsofraj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ddhp"><img src="https://avatars1.githubusercontent.com/u/1715380?v=4" width="100px;" alt=""/><br /><sub><b>Jian-Chen Chen (jesse)</b></sub></a><br /><a href="#translation-ddhp" title="Translation">🌍</a> <a href="https://github.com/verdaccio/verdaccio/commits?author=ddhp" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.4 KiB |
29
crowdin.yaml
29
crowdin.yaml
@@ -1,20 +1,19 @@
|
||||
project_id_env: CROWDIN_VERDACCIO_PROJECT_ID
|
||||
project_id: 295539
|
||||
api_token_env: CROWDIN_VERDACCIO_API_KEY
|
||||
# token local testing
|
||||
# api_token: token_secret
|
||||
|
||||
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%',
|
||||
},
|
||||
{
|
||||
source: '/website/docs/**/*',
|
||||
translation: '/website/i18n/%locale%/docusaurus-plugin-content-docs/current/**/%original_file_name%',
|
||||
}
|
||||
]
|
||||
- source: /packages/plugins/ui-theme/src/i18n/crowdin/*.json
|
||||
translation: '/packages/plugins/ui-theme/src/i18n/download_translations/%locale%/%original_file_name%'
|
||||
- source: /website/i18n/en/**/*
|
||||
translation: '/website/i18n/%locale%/**/%original_file_name%'
|
||||
- source: /website/docs/**/*
|
||||
translation: '/website/i18n/%locale%/docusaurus-plugin-content-docs/current/**/%original_file_name%'
|
||||
ignore: [/website/docs/api/**/*]
|
||||
- source: /website/versioned_docs/**/*
|
||||
translation: /website/i18n/%locale%/docusaurus-plugin-content-docs/**/%original_file_name%
|
||||
ignore: [/website/versioned_docs/version-5.x/api/**/*]
|
||||
|
||||
3
docs/plugins.md
Normal file
3
docs/plugins.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## Developing plugins
|
||||
|
||||
TBA
|
||||
@@ -3,4 +3,4 @@
|
||||
This folder is composed of two strategies:
|
||||
|
||||
- E2E for CLI
|
||||
- E2E for the UI (puppeteer)
|
||||
- E2E for the UI (cypress)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
| deprecate | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| ping | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| search | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| star | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| dist-tag | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
|
||||
> notes:
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
"main": "./build/index.js",
|
||||
"types": "./build/index.d.ts",
|
||||
"devDependencies": {
|
||||
"verdaccio": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.48",
|
||||
"verdaccio": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.17",
|
||||
"yaml": "2.1.1",
|
||||
"yaml": "2.1.3",
|
||||
"debug": "4.3.4",
|
||||
"fs-extra": "10.1.0",
|
||||
"got": "11.8.5",
|
||||
|
||||
69
e2e/cli/e2e-npm6/star.spec.ts
Normal file
69
e2e/cli/e2e-npm6/star.spec.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
addRegistry,
|
||||
initialSetup,
|
||||
npmUtils,
|
||||
prepareGenericEmptyProject,
|
||||
} from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('star a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/foo']])('should star a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await npmUtils.publish(npm, tempFolder, pkgName, registry);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should unstar a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await npmUtils.publish(npm, tempFolder, pkgName, registry);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
|
||||
const resp1 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'unstar',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp1.stdout).toEqual(`☆ ${pkgName}`);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
||||
69
e2e/cli/e2e-npm7/star.spec.ts
Normal file
69
e2e/cli/e2e-npm7/star.spec.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
addRegistry,
|
||||
initialSetup,
|
||||
npmUtils,
|
||||
prepareGenericEmptyProject,
|
||||
} from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('star a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/foo']])('should star a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await npmUtils.publish(npm, tempFolder, pkgName, registry);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should unstar a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await npmUtils.publish(npm, tempFolder, pkgName, registry);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
|
||||
const resp1 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'unstar',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp1.stdout).toEqual(`☆ ${pkgName}`);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
||||
69
e2e/cli/e2e-npm8/star.spec.ts
Normal file
69
e2e/cli/e2e-npm8/star.spec.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
addRegistry,
|
||||
initialSetup,
|
||||
npmUtils,
|
||||
prepareGenericEmptyProject,
|
||||
} from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('star a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/foo']])('should star a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await npmUtils.publish(npm, tempFolder, pkgName, registry);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should unstar a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await npmUtils.publish(npm, tempFolder, pkgName, registry);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
|
||||
const resp1 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'unstar',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp1.stdout).toEqual(`☆ ${pkgName}`);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,7 @@
|
||||
"version": "1.0.1-6-next.5",
|
||||
"dependencies": {
|
||||
"@verdaccio/test-cli-commons": "workspace:1.0.1-6-next.5",
|
||||
"npm": "9.0.0-pre.2"
|
||||
"npm": "9.0.0-pre.5"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
|
||||
69
e2e/cli/e2e-npm9/star.spec.ts
Normal file
69
e2e/cli/e2e-npm9/star.spec.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
addRegistry,
|
||||
initialSetup,
|
||||
npmUtils,
|
||||
prepareGenericEmptyProject,
|
||||
} from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('star a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/foo']])('should star a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await npmUtils.publish(npm, tempFolder, pkgName, registry);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should unstar a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await npmUtils.publish(npm, tempFolder, pkgName, registry);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
|
||||
const resp1 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'unstar',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp1.stdout).toEqual(`☆ ${pkgName}`);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
||||
69
e2e/cli/e2e-pnpm6/star.spec.ts
Normal file
69
e2e/cli/e2e-pnpm6/star.spec.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
addRegistry,
|
||||
initialSetup,
|
||||
pnpmUtils,
|
||||
prepareGenericEmptyProject,
|
||||
} from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { pnpm } from './utils';
|
||||
|
||||
describe('star a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/foo']])('should star a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await pnpmUtils.publish(pnpm, tempFolder, pkgName, registry);
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should unstar a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await pnpmUtils.publish(pnpm, tempFolder, pkgName, registry);
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
|
||||
const resp1 = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'unstar',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp1.stdout).toEqual(`☆ ${pkgName}`);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
||||
69
e2e/cli/e2e-pnpm7/star.spec.ts
Normal file
69
e2e/cli/e2e-pnpm7/star.spec.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
addRegistry,
|
||||
initialSetup,
|
||||
pnpmUtils,
|
||||
prepareGenericEmptyProject,
|
||||
} from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { pnpm } from './utils';
|
||||
|
||||
describe('star a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/foo']])('should star a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await pnpmUtils.publish(pnpm, tempFolder, pkgName, registry);
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should unstar a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await pnpmUtils.publish(pnpm, tempFolder, pkgName, registry);
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'star',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toEqual(`★ ${pkgName}`);
|
||||
|
||||
const resp1 = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'unstar',
|
||||
pkgName,
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp1.stdout).toEqual(`☆ ${pkgName}`);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,7 @@
|
||||
"version": "1.0.1-6-next.5",
|
||||
"dependencies": {
|
||||
"@verdaccio/test-cli-commons": "workspace:1.0.1-6-next.5",
|
||||
"@yarnpkg/cli-dist": "3.2.3"
|
||||
"@yarnpkg/cli-dist": "3.2.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"globals": {
|
||||
"VERDACCIO_API_URL": true,
|
||||
"__DEBUG__": true
|
||||
},
|
||||
"env": {
|
||||
"browser": true
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
# @verdaccio/e2e-ui
|
||||
|
||||
## 2.0.0-6-next.3
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 000d4374: feat: upgrade to material ui 5
|
||||
|
||||
## 1.1.0-6-next.2
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 154b2ecd: refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplications
|
||||
|
||||
## 1.1.0-6-next.1
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 1b217fd3: Some verdaccio modules depend on 'mkdirp' library which provides recursive directory creation functionality.
|
||||
NodeJS can do this out of the box since v.10.12. The last commit in 'mkdirp' was made in early 2016, and it's mid 2021 now.
|
||||
Time to stick with a built-in library solution!
|
||||
|
||||
- All 'mkdirp' calls are replaced with appropriate 'fs' calls.
|
||||
|
||||
## 1.0.1-alpha.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fecbb9be: chore: add release step to private regisry on merge changeset pr
|
||||
@@ -7,3 +7,7 @@
|
||||
- Check navigation
|
||||
- Check sidebar
|
||||
- Check protected packages works
|
||||
|
||||
## Contribute
|
||||
|
||||
More tests could be added to verify UI works as expected.
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
const { join } = require('path');
|
||||
const { fileUtils } = require('@verdaccio/core');
|
||||
const { parseConfigFile } = require('@verdaccio/config');
|
||||
const { Registry, ServerQuery } = require('verdaccio');
|
||||
|
||||
describe('basic functionality', () => {
|
||||
let registry1;
|
||||
let page;
|
||||
beforeAll(async () => {
|
||||
const configProtected = parseConfigFile(join(__dirname, './config/config.yaml'));
|
||||
const registry1storage = await fileUtils.createTempStorageFolder('storage-1');
|
||||
const protectedRegistry = await Registry.fromConfigToPath({
|
||||
...configProtected,
|
||||
storage: registry1storage,
|
||||
});
|
||||
registry1 = new Registry(protectedRegistry.configPath);
|
||||
await registry1.init();
|
||||
|
||||
const query1 = new ServerQuery(registry1.getRegistryUrl());
|
||||
await query1.createUser('test', 'test');
|
||||
|
||||
page = await global.__BROWSER__.newPage();
|
||||
await page.goto(`http://0.0.0.0:${registry1.getPort()}`);
|
||||
// eslint-disable-next-line no-console
|
||||
page.on('console', (msg) => console.log('PAGE LOG:', msg.text()));
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await page.close();
|
||||
registry1.stop();
|
||||
});
|
||||
|
||||
// this might be increased based on the delays included in all test
|
||||
jest.setTimeout(20000);
|
||||
|
||||
test('should display title', async () => {
|
||||
const text = await page.title();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
expect(text).toContain('verdaccio-server-e2e');
|
||||
});
|
||||
|
||||
test('should match title with no packages published', async () => {
|
||||
const text = await page.evaluate(() => document.querySelector('#help-card__title').textContent);
|
||||
expect(text).toMatch('No Package Published Yet.');
|
||||
});
|
||||
|
||||
test('should match title with first step', async () => {
|
||||
const text = await page.evaluate(() => document.querySelector('#help-card').textContent);
|
||||
expect(text).toContain(`npm adduser --registry http://0.0.0.0:${registry1.getPort()}`);
|
||||
});
|
||||
|
||||
test('should match title with second step', async () => {
|
||||
const text = await page.evaluate(() => document.querySelector('#help-card').textContent);
|
||||
expect(text).toContain(`npm publish --registry http://0.0.0.0:${registry1.getPort()}`);
|
||||
});
|
||||
|
||||
test('should go to 404 page', async () => {
|
||||
await page.goto(`http://0.0.0.0:${registry1.getPort()}/-/web/detail/@verdaccio/not-found`);
|
||||
await page.waitForTimeout(500);
|
||||
const text = await page.evaluate(() => document.querySelector('.not-found-text').textContent);
|
||||
expect(text).toMatch("Sorry, we couldn't find it...");
|
||||
});
|
||||
});
|
||||
60
e2e/ui/cypress.config.ts
Normal file
60
e2e/ui/cypress.config.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { defineConfig } from 'cypress';
|
||||
import { join } from 'path';
|
||||
import { Registry, ServerQuery } from 'verdaccio';
|
||||
|
||||
import { parseConfigFile } from '@verdaccio/config';
|
||||
import { HEADERS, fileUtils } from '@verdaccio/core';
|
||||
import { generatePackageMetadata } from '@verdaccio/test-helper';
|
||||
|
||||
let registry1;
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
setupNodeEvents(on) {
|
||||
on('before:run', async () => {
|
||||
const configProtected = parseConfigFile(join(__dirname, './config/config.yaml'));
|
||||
const registry1storage = await fileUtils.createTempStorageFolder('storage-1');
|
||||
const protectedRegistry = await Registry.fromConfigToPath({
|
||||
...configProtected,
|
||||
storage: registry1storage,
|
||||
});
|
||||
registry1 = new Registry(protectedRegistry.configPath, {
|
||||
createUser: true,
|
||||
credentials: { user: 'test', password: 'test' },
|
||||
});
|
||||
await registry1.init();
|
||||
});
|
||||
|
||||
on('after:run', async () => {
|
||||
registry1.stop();
|
||||
});
|
||||
|
||||
on('task', {
|
||||
publishScoped() {
|
||||
const scopedPackageMetadata = generatePackageMetadata('pkg-scoped', '1.0.6');
|
||||
const server = new ServerQuery(registry1.getRegistryUrl());
|
||||
server
|
||||
.putPackage(scopedPackageMetadata.name, scopedPackageMetadata, {
|
||||
[HEADERS.AUTHORIZATION]: `Bearer ${registry1.getToken()}`,
|
||||
})
|
||||
.then(() => {});
|
||||
return null;
|
||||
},
|
||||
publishProtected({ pkgName }) {
|
||||
const protectedPackageMetadata = generatePackageMetadata(pkgName, '5.0.5');
|
||||
const server = new ServerQuery(registry1.getRegistryUrl());
|
||||
server
|
||||
.putPackage(protectedPackageMetadata.name, protectedPackageMetadata, {
|
||||
[HEADERS.AUTHORIZATION]: `Bearer ${registry1.getToken()}`,
|
||||
})
|
||||
.then(() => {});
|
||||
},
|
||||
registry() {
|
||||
return {
|
||||
registryUrl: registry1.getRegistryUrl(),
|
||||
port: registry1.getPort(),
|
||||
};
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
30
e2e/ui/cypress/e2e/home.cy.ts
Normal file
30
e2e/ui/cypress/e2e/home.cy.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
describe('home spec', () => {
|
||||
let ctx: any = {};
|
||||
beforeEach(async () => {
|
||||
// @ts-expect-error
|
||||
const registry = await cy.task('registry');
|
||||
ctx.url = registry.registryUrl;
|
||||
});
|
||||
|
||||
it('title should be correct', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.location('pathname').should('include', '/');
|
||||
cy.title().should('eq', 'verdaccio-server-e2e');
|
||||
});
|
||||
|
||||
it('should match title with no packages published', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.getByTestId('help-card').contains('No Package Published Yet.');
|
||||
});
|
||||
|
||||
it('should display instructions on help card', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.getByTestId('help-card').contains(`npm adduser --registry ${ctx.url}`);
|
||||
cy.getByTestId('help-card').contains(`npm publish --registry ${ctx.url}`);
|
||||
});
|
||||
|
||||
it('should go to 404 page', () => {
|
||||
cy.visit(`${ctx.url}/-/web/detail/@verdaccio/not-found`);
|
||||
cy.getByTestId('404').contains(`Sorry, we couldn't find it.`);
|
||||
});
|
||||
});
|
||||
91
e2e/ui/cypress/e2e/publish.cy.ts
Normal file
91
e2e/ui/cypress/e2e/publish.cy.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
describe('publish spec', () => {
|
||||
let ctx: any = {};
|
||||
const credentials = { user: 'test', password: 'test' };
|
||||
beforeEach(async () => {
|
||||
// @ts-expect-error
|
||||
const registry = await cy.task('registry');
|
||||
ctx.url = registry.registryUrl;
|
||||
cy.intercept('POST', '/-/verdaccio/sec/login').as('sign');
|
||||
cy.intercept('GET', '/-/verdaccio/data/packages').as('pkgs');
|
||||
cy.intercept('GET', '/-/verdaccio/data/sidebar/pkg-scoped').as('sidebar');
|
||||
cy.intercept('GET', '/-/verdaccio/data/package/readme/pkg-scoped').as('readme');
|
||||
cy.task('publishScoped', { pkgName: 'pkg-protected' });
|
||||
});
|
||||
|
||||
it('should have one published package', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.login(credentials.user, credentials.password);
|
||||
cy.wait('@sign');
|
||||
cy.getByTestId('package-title').should('have.length', 1);
|
||||
});
|
||||
|
||||
it('should navigate to page detail', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.login(credentials.user, credentials.password);
|
||||
cy.wait('@sign');
|
||||
cy.wait('@pkgs');
|
||||
cy.wait(300);
|
||||
cy.getByTestId('package-title').click();
|
||||
cy.wait('@sidebar');
|
||||
cy.wait('@readme');
|
||||
});
|
||||
|
||||
it('should have readme content', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.login(credentials.user, credentials.password);
|
||||
cy.wait('@sign');
|
||||
cy.wait('@pkgs');
|
||||
cy.getByTestId('package-title').click();
|
||||
cy.wait('@sidebar');
|
||||
cy.wait('@readme');
|
||||
cy.get('.markdown-body').should('have.length', 1);
|
||||
cy.contains('.markdown-body', /test/);
|
||||
});
|
||||
|
||||
it('should click on dependencies tab', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.login(credentials.user, credentials.password);
|
||||
cy.wait('@sign');
|
||||
cy.wait('@pkgs');
|
||||
cy.wait(300);
|
||||
cy.getByTestId('package-title').click();
|
||||
cy.wait('@sidebar');
|
||||
cy.wait('@readme');
|
||||
cy.getByTestId('dependencies-tab').click();
|
||||
cy.wait(100);
|
||||
cy.getByTestId('dependencies').should('have.length', 1);
|
||||
cy.getByTestId('verdaccio')
|
||||
.children()
|
||||
.invoke('text')
|
||||
.should('match', /verdaccio/);
|
||||
cy.screenshot();
|
||||
});
|
||||
|
||||
it('should click on versions tab', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.login(credentials.user, credentials.password);
|
||||
cy.wait('@sign');
|
||||
cy.wait('@pkgs');
|
||||
cy.wait(300);
|
||||
cy.getByTestId('package-title').click();
|
||||
cy.wait('@sidebar');
|
||||
cy.wait('@readme');
|
||||
cy.getByTestId('versions-tab').click();
|
||||
cy.getByTestId('tag-latest').children().invoke('text').should('match', /1.0.6/);
|
||||
cy.screenshot();
|
||||
});
|
||||
|
||||
it('should click on uplinks tab', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.login(credentials.user, credentials.password);
|
||||
cy.wait('@sign');
|
||||
cy.wait('@pkgs');
|
||||
cy.wait(300);
|
||||
cy.getByTestId('package-title').click();
|
||||
cy.wait('@sidebar');
|
||||
cy.wait('@readme');
|
||||
cy.getByTestId('uplinks-tab').click();
|
||||
cy.getByTestId('no-uplinks').should('be.visible');
|
||||
cy.screenshot();
|
||||
});
|
||||
});
|
||||
31
e2e/ui/cypress/e2e/signin.cy.ts
Normal file
31
e2e/ui/cypress/e2e/signin.cy.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
describe('sign spec', () => {
|
||||
let ctx: any = {};
|
||||
const credentials = { user: 'test', password: 'test' };
|
||||
beforeEach(async () => {
|
||||
// @ts-expect-error
|
||||
const registry = await cy.task('registry');
|
||||
ctx.url = registry.registryUrl;
|
||||
cy.intercept('POST', '/-/verdaccio/sec/login').as('sign');
|
||||
});
|
||||
|
||||
it('should login user', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.login(credentials.user, credentials.password);
|
||||
cy.wait('@sign');
|
||||
cy.getByTestId('logInDialogIcon').click();
|
||||
cy.wait(100);
|
||||
cy.getByTestId('greetings-label').contains(credentials.user);
|
||||
});
|
||||
|
||||
it('should logout an user', () => {
|
||||
cy.visit(ctx.url);
|
||||
cy.login(credentials.user, credentials.password);
|
||||
cy.wait('@sign');
|
||||
cy.getByTestId('logInDialogIcon').click();
|
||||
cy.wait(100);
|
||||
cy.getByTestId('logOutDialogIcon').click();
|
||||
cy.screenshot();
|
||||
cy.getByTestId('header--button-login').contains('Login');
|
||||
cy.screenshot();
|
||||
});
|
||||
});
|
||||
40
e2e/ui/cypress/support/commands.ts
Normal file
40
e2e/ui/cypress/support/commands.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/* eslint-disable no-undef */
|
||||
// / <reference types="cypress" />;
|
||||
|
||||
Cypress.Commands.add('getByTestId', (selector, ...args) => {
|
||||
return cy.get(`[data-testid=${selector}]`, ...args);
|
||||
});
|
||||
|
||||
// -- This is a parent command --
|
||||
Cypress.Commands.add('login', (user, password) => {
|
||||
cy.getByTestId('header--button-login').click();
|
||||
cy.wait(300);
|
||||
cy.get('#login--dialog-username').type(user);
|
||||
cy.wait(200);
|
||||
cy.get('#login--dialog-password').type(password);
|
||||
cy.wait(500);
|
||||
cy.get('#login--dialog-button-submit').click();
|
||||
});
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
//
|
||||
// declare global {
|
||||
// namespace Cypress {
|
||||
// interface Chainable {
|
||||
// login(email: string, password: string): Chainable<void>
|
||||
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
19
e2e/ui/cypress/support/e2e.ts
Normal file
19
e2e/ui/cypress/support/e2e.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// ***********************************************************
|
||||
// This example support/e2e.ts is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
@@ -1,36 +0,0 @@
|
||||
export const credentials = { user: 'test', password: 'test' };
|
||||
|
||||
export const clickElement = async function (page, selector, options = { delay: 100 }) {
|
||||
const button = await page.$(selector);
|
||||
await button.focus();
|
||||
await button.click(options);
|
||||
};
|
||||
|
||||
export const evaluateSignIn = async function (page, matchText = 'Login') {
|
||||
const text = await page.evaluate(() => {
|
||||
return document.querySelector('button[data-testid="header--button-login"]')?.textContent;
|
||||
});
|
||||
|
||||
expect(text).toMatch(matchText);
|
||||
};
|
||||
|
||||
export const getPackages = async function (page) {
|
||||
return await page.$$('.package-title');
|
||||
};
|
||||
|
||||
export const logIn = async function (page) {
|
||||
await clickElement(page, 'div[data-testid="dialogContentLogin"]');
|
||||
const userInput = await page.$('#login--dialog-username');
|
||||
expect(userInput).not.toBeNull();
|
||||
const passInput = await page.$('#login--dialog-password');
|
||||
expect(passInput).not.toBeNull();
|
||||
await userInput.type(credentials.user, { delay: 100 });
|
||||
await passInput.type(credentials.password, { delay: 100 });
|
||||
await passInput.dispose();
|
||||
// click on log in
|
||||
const loginButton = await page.$('#login--dialog-button-submit');
|
||||
expect(loginButton).toBeDefined();
|
||||
await loginButton.focus();
|
||||
await loginButton.click({ delay: 100 });
|
||||
await page.waitForTimeout(500);
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
const config = require('../../jest/config');
|
||||
|
||||
module.exports = Object.assign({}, config, {
|
||||
verbose: false,
|
||||
collectCoverage: false,
|
||||
globalSetup: './pre-setup.js',
|
||||
globalTeardown: './teardown.js',
|
||||
});
|
||||
@@ -3,17 +3,15 @@
|
||||
"name": "@verdaccio/e2e-ui",
|
||||
"version": "2.0.0-6-next.3",
|
||||
"devDependencies": {
|
||||
"verdaccio": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/test-helper": "workspace:2.0.0-6-next.5",
|
||||
"verdaccio": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/test-helper": "workspace:2.0.0-6-next.6",
|
||||
"debug": "4.3.4",
|
||||
"colorette": "2.0.19",
|
||||
"lodash": "^4.17.21",
|
||||
"puppeteer": "17.1.3",
|
||||
"rimraf": "3.0.2"
|
||||
"cypress": "10.10.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest --runInBand"
|
||||
"cypress:open": "cypress open",
|
||||
"test": "cypress run"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
const { join } = require('path');
|
||||
const { generatePackageMetadata } = require('@verdaccio/test-helper');
|
||||
const { fileUtils, HEADERS } = require('@verdaccio/core');
|
||||
const { parseConfigFile } = require('@verdaccio/config');
|
||||
const { Registry, ServerQuery } = require('verdaccio');
|
||||
const { getPackages } = require('./helper');
|
||||
|
||||
const protectedPackageMetadata = generatePackageMetadata('pkg-protected', '5.0.5');
|
||||
const scopedPackageMetadata = generatePackageMetadata('pkg-scoped', '1.0.6');
|
||||
|
||||
describe('publish package', () => {
|
||||
let registry1;
|
||||
let page;
|
||||
beforeAll(async () => {
|
||||
const configProtected = parseConfigFile(join(__dirname, './config/config.yaml'));
|
||||
const registry1storage = await fileUtils.createTempStorageFolder('storage-1');
|
||||
const protectedRegistry = await Registry.fromConfigToPath({
|
||||
...configProtected,
|
||||
storage: registry1storage,
|
||||
});
|
||||
registry1 = new Registry(protectedRegistry.configPath, { createUser: true });
|
||||
await registry1.init();
|
||||
|
||||
const query1 = new ServerQuery(registry1.getRegistryUrl());
|
||||
await query1.createUser('test', 'test');
|
||||
|
||||
page = await global.__BROWSER__.newPage();
|
||||
await page.goto(`http://0.0.0.0:${registry1.getPort()}`);
|
||||
// eslint-disable-next-line no-console
|
||||
page.on('console', (msg) => console.log('PAGE LOG:', msg.text()));
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await page.close();
|
||||
registry1.stop();
|
||||
});
|
||||
|
||||
// this might be increased based on the delays included in all test
|
||||
jest.setTimeout(20000);
|
||||
|
||||
test('should publish a package', async () => {
|
||||
const server = new ServerQuery(registry1.getRegistryUrl());
|
||||
await server.putPackage(scopedPackageMetadata.name, scopedPackageMetadata, {
|
||||
[HEADERS.AUTHORIZATION]: `Bearer ${registry1.getToken()}`,
|
||||
});
|
||||
await page.waitForTimeout(1000);
|
||||
await page.reload();
|
||||
await page.waitForTimeout(1000);
|
||||
const packagesList = await getPackages(page);
|
||||
expect(packagesList).toHaveLength(1);
|
||||
});
|
||||
//
|
||||
|
||||
test('should navigate to the package detail', async () => {
|
||||
const packagesList = await getPackages(page);
|
||||
const firstPackage = packagesList[0];
|
||||
await firstPackage.click({ delay: 200 });
|
||||
await page.waitForTimeout(1000);
|
||||
const readmeText = await page.evaluate(
|
||||
() => document.querySelector('.markdown-body').textContent
|
||||
);
|
||||
|
||||
expect(readmeText).toMatch('test');
|
||||
});
|
||||
|
||||
test('should contains last sync information', async () => {
|
||||
const versionList = await page.$$('.sidebar-info .detail-info');
|
||||
expect(versionList).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should display dependencies tab', async () => {
|
||||
const dependenciesTab = await page.$$('#dependencies-tab');
|
||||
expect(dependenciesTab).toHaveLength(1);
|
||||
await dependenciesTab[0].click({ delay: 200 });
|
||||
await page.waitForTimeout(1000);
|
||||
const tags = await page.$$('.dep-tag');
|
||||
const tag = tags[0];
|
||||
const label = await page.evaluate((el) => el.innerText, tag);
|
||||
expect(label).toMatch('verdaccio@');
|
||||
});
|
||||
|
||||
test('should display version tab', async () => {
|
||||
const versionsTab = await page.$$('#versions-tab');
|
||||
expect(versionsTab).toHaveLength(1);
|
||||
await versionsTab[0].click({ delay: 200 });
|
||||
await page.waitForTimeout(1000);
|
||||
const versionItems = await page.$$('.version-item');
|
||||
expect(versionItems).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('should display uplinks tab', async () => {
|
||||
const upLinksTab = await page.$$('#uplinks-tab');
|
||||
expect(upLinksTab).toHaveLength(1);
|
||||
await upLinksTab[0].click({ delay: 200 });
|
||||
await page.waitForTimeout(1000);
|
||||
});
|
||||
|
||||
test('should display readme tab', async () => {
|
||||
const readmeTab = await page.$$('#readme-tab');
|
||||
expect(readmeTab).toHaveLength(1);
|
||||
await readmeTab[0].click({ delay: 200 });
|
||||
await page.waitForTimeout(1000);
|
||||
});
|
||||
|
||||
test('should publish a second package', async () => {
|
||||
await page.goto(`http://0.0.0.0:${registry1.getPort()}`);
|
||||
await page.waitForTimeout(500);
|
||||
const server = new ServerQuery(registry1.getRegistryUrl());
|
||||
await server.putPackage(protectedPackageMetadata.name, protectedPackageMetadata, {
|
||||
[HEADERS.AUTHORIZATION]: `Bearer ${registry1.getToken()}`,
|
||||
});
|
||||
await page.waitForTimeout(500);
|
||||
await page.reload();
|
||||
await page.waitForTimeout(500);
|
||||
const packagesList = await getPackages(page);
|
||||
expect(packagesList).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
@@ -1,80 +0,0 @@
|
||||
const { join } = require('path');
|
||||
const { fileUtils } = require('@verdaccio/core');
|
||||
const { parseConfigFile } = require('@verdaccio/config');
|
||||
const { Registry, ServerQuery } = require('verdaccio');
|
||||
const { clickElement, logIn } = require('./helper');
|
||||
|
||||
describe('sign in user', () => {
|
||||
let registry1;
|
||||
let page;
|
||||
beforeAll(async () => {
|
||||
const configProtected = parseConfigFile(join(__dirname, './config/config.yaml'));
|
||||
const registry1storage = await fileUtils.createTempStorageFolder('storage-1');
|
||||
const protectedRegistry = await Registry.fromConfigToPath({
|
||||
...configProtected,
|
||||
storage: registry1storage,
|
||||
});
|
||||
registry1 = new Registry(protectedRegistry.configPath);
|
||||
await registry1.init();
|
||||
|
||||
const query1 = new ServerQuery(registry1.getRegistryUrl());
|
||||
await query1.createUser('test', 'test');
|
||||
|
||||
page = await global.__BROWSER__.newPage();
|
||||
await page.goto(`http://0.0.0.0:${registry1.getPort()}`);
|
||||
// eslint-disable-next-line no-console
|
||||
page.on('console', (msg) => console.log('PAGE LOG:', msg.text()));
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await page.close();
|
||||
registry1.stop();
|
||||
});
|
||||
|
||||
// this might be increased based on the delays included in all test
|
||||
jest.setTimeout(20000);
|
||||
|
||||
const evaluateSignIn = async function (matchText = 'Login') {
|
||||
const text = await page.evaluate(() => {
|
||||
return document.querySelector('button[data-testid="header--button-login"]').textContent;
|
||||
});
|
||||
|
||||
expect(text).toMatch(matchText);
|
||||
};
|
||||
|
||||
test('should match button Login to sign in', async () => {
|
||||
await evaluateSignIn();
|
||||
});
|
||||
|
||||
test('should click on sign in button', async () => {
|
||||
const signInButton = await page.$('button[data-testid="header--button-login"]');
|
||||
await signInButton.click();
|
||||
await page.waitForTimeout(1000);
|
||||
const signInDialog = await page.$('#login--dialog');
|
||||
expect(signInDialog).not.toBeNull();
|
||||
const closeButton = await page.$('button[data-testid="close-login-dialog-button"]');
|
||||
await closeButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
});
|
||||
|
||||
test('should log in an user', async () => {
|
||||
// we open the dialog
|
||||
await logIn(page);
|
||||
// verify if logged in
|
||||
const accountButton = await page.$('#header--button-account');
|
||||
expect(accountButton).toBeDefined();
|
||||
// check whether user is logged
|
||||
const buttonLogout = await page.$('#logOutDialogIcon');
|
||||
expect(buttonLogout).toBeDefined();
|
||||
});
|
||||
|
||||
test('should logout an user', async () => {
|
||||
await page.waitForTimeout(10000);
|
||||
// we assume the user is logged already
|
||||
await clickElement(page, '#header--button-account', { delay: 500 });
|
||||
await page.waitForTimeout(1000);
|
||||
await clickElement(page, '#logOutDialogIcon > span', { delay: 500 });
|
||||
await page.waitForTimeout(1000);
|
||||
await evaluateSignIn();
|
||||
});
|
||||
});
|
||||
18
e2e/ui/tsconfig.json
Normal file
18
e2e/ui/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "../../tsconfig.reference.json",
|
||||
"include": ["./cypress/**/*.ts", "./*.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../packages/core/core"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/verdaccio"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/config"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/tools/helpers"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,7 +10,7 @@ module.exports = {
|
||||
coveragePathIgnorePatterns: ['node_modules', 'fixtures'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
lines: 90,
|
||||
lines: 85,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
48
package.json
48
package.json
@@ -15,17 +15,17 @@
|
||||
"url": "https://opencollective.com/verdaccio"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.18.10",
|
||||
"@babel/core": "7.19.1",
|
||||
"@babel/cli": "7.19.3",
|
||||
"@babel/core": "7.19.3",
|
||||
"@babel/node": "7.19.1",
|
||||
"@babel/plugin-proposal-class-properties": "7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "7.19.1",
|
||||
"@babel/plugin-proposal-decorators": "7.19.3",
|
||||
"@babel/plugin-proposal-export-namespace-from": "7.18.9",
|
||||
"@babel/plugin-proposal-function-sent": "7.18.6",
|
||||
"@babel/plugin-proposal-json-strings": "7.18.6",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6",
|
||||
"@babel/plugin-proposal-numeric-separator": "7.18.6",
|
||||
"@babel/plugin-proposal-object-rest-spread": "7.18.9",
|
||||
"@babel/plugin-proposal-object-rest-spread": "7.19.4",
|
||||
"@babel/plugin-proposal-optional-chaining": "7.18.9",
|
||||
"@babel/plugin-proposal-throw-expressions": "7.18.6",
|
||||
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
||||
@@ -33,15 +33,15 @@
|
||||
"@babel/plugin-transform-async-to-generator": "7.18.6",
|
||||
"@babel/plugin-transform-classes": "7.19.0",
|
||||
"@babel/plugin-transform-runtime": "7.19.1",
|
||||
"@babel/preset-env": "7.19.1",
|
||||
"@babel/preset-env": "7.19.4",
|
||||
"@babel/preset-react": "7.18.6",
|
||||
"@babel/preset-typescript": "7.18.6",
|
||||
"@babel/register": "7.18.9",
|
||||
"@babel/runtime": "7.19.0",
|
||||
"@babel/runtime": "7.19.4",
|
||||
"@dianmora/contributors": "5.0.0",
|
||||
"@changesets/changelog-github": "0.4.6",
|
||||
"@changesets/changelog-github": "0.4.7",
|
||||
"@changesets/cli": "2.24.4",
|
||||
"@changesets/get-dependents-graph": "1.3.3",
|
||||
"@changesets/get-dependents-graph": "1.3.4",
|
||||
"@crowdin/cli": "3.8.1",
|
||||
"@trivago/prettier-plugin-sort-imports": "3.3.0",
|
||||
"@types/async": "3.2.15",
|
||||
@@ -49,45 +49,46 @@
|
||||
"@types/express": "4.17.14",
|
||||
"@types/http-errors": "1.8.2",
|
||||
"@types/jest": "27.5.2",
|
||||
"@types/lodash": "4.14.185",
|
||||
"@types/lodash": "4.14.186",
|
||||
"@types/mime": "2.0.3",
|
||||
"@types/minimatch": "3.0.5",
|
||||
"@types/node": "16.11.60",
|
||||
"@types/node": "16.11.65",
|
||||
"@types/jsonwebtoken": "8.5.9",
|
||||
"@types/request": "2.48.8",
|
||||
"@types/semver": "7.3.12",
|
||||
"@types/node-fetch": "2.6.2",
|
||||
"@types/supertest": "2.0.12",
|
||||
"@types/testing-library__jest-dom": "5.14.5",
|
||||
"@types/validator": "13.7.6",
|
||||
"@types/validator": "13.7.7",
|
||||
"@types/webpack": "5.28.0",
|
||||
"@types/webpack-env": "1.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.37.0",
|
||||
"@typescript-eslint/parser": "5.37.0",
|
||||
"@verdaccio/benchmark": "workspace:*",
|
||||
"@verdaccio/crowdin-translations": "workspace:*",
|
||||
"@verdaccio/eslint-config": "workspace:*",
|
||||
"@verdaccio/types": "workspace:*",
|
||||
"@verdaccio/ui-theme": "workspace:*",
|
||||
"autocannon": "7.10.0",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-jest": "29.0.3",
|
||||
"babel-jest": "29.2.0",
|
||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||
"babel-plugin-emotion": "10.2.2",
|
||||
"concurrently": "6.5.1",
|
||||
"core-js": "3.25.2",
|
||||
"core-js": "3.25.5",
|
||||
"cross-env": "7.0.3",
|
||||
"debug": "4.3.4",
|
||||
"detect-secrets": "1.0.6",
|
||||
"jest-diff": "29.0.3",
|
||||
"jest-diff": "29.2.0",
|
||||
"eslint": "8.23.1",
|
||||
"fs-extra": "10.1.0",
|
||||
"husky": "7.0.4",
|
||||
"in-publish": "2.0.1",
|
||||
"jest": "29.0.3",
|
||||
"jest-environment-jsdom": "29.0.3",
|
||||
"jest": "29.2.0",
|
||||
"jest-environment-jsdom": "29.2.0",
|
||||
"jest-environment-jsdom-global": "3.1.2",
|
||||
"jest-environment-node": "29.0.3",
|
||||
"jest-environment-node": "29.2.0",
|
||||
"jest-junit": "12.3.0",
|
||||
"kleur": "3.0.3",
|
||||
"lint-staged": "11.2.6",
|
||||
@@ -98,9 +99,9 @@
|
||||
"prettier": "2.7.1",
|
||||
"rimraf": "3.0.2",
|
||||
"selfsigned": "1.10.14",
|
||||
"supertest": "6.2.4",
|
||||
"supertest": "6.3.0",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "4.8.3",
|
||||
"typescript": "4.8.4",
|
||||
"update-ts-references": "2.4.1",
|
||||
"verdaccio-audit": "workspace:*",
|
||||
"verdaccio-auth-memory": "workspace:*",
|
||||
@@ -110,7 +111,7 @@
|
||||
"scripts": {
|
||||
"prepare": "husky install",
|
||||
"husky:pre-commit": "lint-staged",
|
||||
"clean": "pnpm run clean",
|
||||
"clean": "pnpm run clean --filter=./packages",
|
||||
"build": "pnpm run build --filter=./packages && pnpm run build --filter=./e2e",
|
||||
"docker": "docker build -t verdaccio/verdaccio:local . --no-cache",
|
||||
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,yml,yaml,md}\"",
|
||||
@@ -141,6 +142,7 @@
|
||||
"ci:publish": "changeset publish",
|
||||
"ts:ref": "update-ts-references --discardComments",
|
||||
"website": "pnpm build --filter ...@verdaccio/website",
|
||||
"translations": "local-crowdin-api translations",
|
||||
"crowdin:upload": "crowdin upload sources --auto-update --config ./crowdin.yaml",
|
||||
"crowdin:download": "crowdin download --verbose --config ./crowdin.yaml",
|
||||
"crowdin:sync": "pnpm crowdin:upload && pnpm crowdin:download --verbose",
|
||||
@@ -149,6 +151,12 @@
|
||||
"local:publish": "cross-env npm_config_registry=http://localhost:4873 pnpm ci:publish",
|
||||
"local:publish:release": "concurrently \"pnpm local:registry\" \"pnpm local:publish\""
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"got": "11.8.5",
|
||||
"p-cancelable": "2.1.1"
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.5",
|
||||
"pnpm": ">=6.32.3 <7.0.0"
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# @verdaccio/api
|
||||
|
||||
## 6.0.0-6-next.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b4cc8001: fix: improve abort request search
|
||||
- @verdaccio/core@6.0.0-6-next.50
|
||||
- @verdaccio/config@6.0.0-6-next.50
|
||||
- @verdaccio/auth@6.0.0-6-next.29
|
||||
- @verdaccio/logger@6.0.0-6-next.18
|
||||
- @verdaccio/middleware@6.0.0-6-next.29
|
||||
- @verdaccio/store@6.0.0-6-next.30
|
||||
- @verdaccio/utils@6.0.0-6-next.18
|
||||
|
||||
## 6.0.0-6-next.32
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ce013d2f: refactor: npm star command support reimplemented
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ce013d2f]
|
||||
- @verdaccio/store@6.0.0-6-next.29
|
||||
- @verdaccio/core@6.0.0-6-next.49
|
||||
- @verdaccio/config@6.0.0-6-next.49
|
||||
- @verdaccio/auth@6.0.0-6-next.28
|
||||
- @verdaccio/logger@6.0.0-6-next.17
|
||||
- @verdaccio/middleware@6.0.0-6-next.28
|
||||
- @verdaccio/utils@6.0.0-6-next.17
|
||||
|
||||
## 6.0.0-6-next.31
|
||||
|
||||
### Major Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/api",
|
||||
"version": "6.0.0-6-next.31",
|
||||
"version": "6.0.0-6-next.33",
|
||||
"description": "loaders logic",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -39,28 +39,28 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.27",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.16",
|
||||
"@verdaccio/middleware": "workspace:6.0.0-6-next.27",
|
||||
"@verdaccio/store": "workspace:6.0.0-6-next.28",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.16",
|
||||
"abortcontroller-polyfill": "1.7.3",
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.29",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.18",
|
||||
"@verdaccio/middleware": "workspace:6.0.0-6-next.29",
|
||||
"@verdaccio/store": "workspace:6.0.0-6-next.30",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.18",
|
||||
"abortcontroller-polyfill": "1.7.5",
|
||||
"cookies": "0.8.0",
|
||||
"debug": "4.3.4",
|
||||
"body-parser": "1.20.0",
|
||||
"express": "4.18.1",
|
||||
"body-parser": "1.20.1",
|
||||
"express": "4.18.2",
|
||||
"lodash": "4.17.21",
|
||||
"mime": "2.6.0",
|
||||
"semver": "7.3.7"
|
||||
"semver": "7.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "16.11.60",
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.37",
|
||||
"@types/node": "16.11.65",
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.39",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.17",
|
||||
"@verdaccio/test-helper": "workspace:2.0.0-6-next.5",
|
||||
"supertest": "6.2.4",
|
||||
"@verdaccio/test-helper": "workspace:2.0.0-6-next.6",
|
||||
"supertest": "6.3.0",
|
||||
"nock": "13.2.9",
|
||||
"mockdate": "3.0.5"
|
||||
},
|
||||
|
||||
@@ -2,14 +2,14 @@ import { Router } from 'express';
|
||||
import _ from 'lodash';
|
||||
import mime from 'mime';
|
||||
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Auth } from '@verdaccio/auth';
|
||||
import { constants, errorUtils } from '@verdaccio/core';
|
||||
import { allow, media } from '@verdaccio/middleware';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
|
||||
import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';
|
||||
|
||||
export default function (route: Router, auth: IAuth, storage: Storage): void {
|
||||
export default function (route: Router, auth: Auth, storage: Storage): void {
|
||||
const can = allow(auth);
|
||||
const addTagPackageVersionMiddleware = async function (
|
||||
req: $RequestExtend,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import bodyParser from 'body-parser';
|
||||
import express, { Router } from 'express';
|
||||
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Auth } from '@verdaccio/auth';
|
||||
import {
|
||||
antiLoop,
|
||||
encodeScopePackage,
|
||||
@@ -24,7 +24,7 @@ import v1Search from './v1/search';
|
||||
import token from './v1/token';
|
||||
import whoami from './whoami';
|
||||
|
||||
export default function (config: Config, auth: IAuth, storage: Storage): Router {
|
||||
export default function (config: Config, auth: Auth, storage: Storage): Router {
|
||||
/* eslint new-cap:off */
|
||||
const app = express.Router();
|
||||
/* eslint new-cap:off */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import buildDebug from 'debug';
|
||||
import { Router } from 'express';
|
||||
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Auth } from '@verdaccio/auth';
|
||||
import { HEADERS, HEADER_TYPE, stringUtils } from '@verdaccio/core';
|
||||
import { allow } from '@verdaccio/middleware';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
@@ -10,7 +10,7 @@ import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/cust
|
||||
|
||||
const debug = buildDebug('verdaccio:api:package');
|
||||
|
||||
export default function (route: Router, auth: IAuth, storage: Storage): void {
|
||||
export default function (route: Router, auth: Auth, storage: Storage): void {
|
||||
const can = allow(auth);
|
||||
|
||||
route.get(
|
||||
|
||||
@@ -2,7 +2,7 @@ import buildDebug from 'debug';
|
||||
import { Router } from 'express';
|
||||
import mime from 'mime';
|
||||
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Auth } from '@verdaccio/auth';
|
||||
import { API_MESSAGE, HTTP_STATUS } from '@verdaccio/core';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
import { allow, expectJson, media } from '@verdaccio/middleware';
|
||||
@@ -11,7 +11,6 @@ import { Storage } from '@verdaccio/store';
|
||||
import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';
|
||||
|
||||
// import star from './star';
|
||||
// import { isPublishablePackage, isRelatedToDeprecation } from './utils';
|
||||
|
||||
const debug = buildDebug('verdaccio:api:publish');
|
||||
|
||||
@@ -93,7 +92,7 @@ const debug = buildDebug('verdaccio:api:publish');
|
||||
}
|
||||
*
|
||||
*/
|
||||
export default function publish(router: Router, auth: IAuth, storage: Storage): void {
|
||||
export default function publish(router: Router, auth: Auth, storage: Storage): void {
|
||||
const can = allow(auth);
|
||||
router.put(
|
||||
'/:package',
|
||||
@@ -177,17 +176,17 @@ export default function publish(router: Router, auth: IAuth, storage: Storage):
|
||||
export function publishPackage(storage: Storage): any {
|
||||
return async function (
|
||||
req: $RequestExtend,
|
||||
_res: $ResponseExtend,
|
||||
res: $ResponseExtend,
|
||||
next: $NextFunctionVer
|
||||
): Promise<void> {
|
||||
const ac = new AbortController();
|
||||
const packageName = req.params.package;
|
||||
const { revision } = req.params;
|
||||
const metadata = req.body;
|
||||
const username = req?.remote_user?.name;
|
||||
|
||||
try {
|
||||
debug('publishing %s', packageName);
|
||||
await storage.updateManifest(metadata, {
|
||||
const message = await storage.updateManifest(metadata, {
|
||||
name: packageName,
|
||||
revision,
|
||||
signal: ac.signal,
|
||||
@@ -196,16 +195,15 @@ export function publishPackage(storage: Storage): any {
|
||||
protocol: req.protocol,
|
||||
// @ts-ignore
|
||||
headers: req.headers,
|
||||
username,
|
||||
},
|
||||
});
|
||||
_res.status(HTTP_STATUS.CREATED);
|
||||
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
|
||||
return next({
|
||||
// TODO: this could be also Package Updated based on the
|
||||
// action, deprecate, star, publish new version, or create a package
|
||||
// the message some return from the method
|
||||
ok: API_MESSAGE.PKG_CREATED,
|
||||
success: true,
|
||||
ok: message,
|
||||
});
|
||||
} catch (err: any) {
|
||||
// TODO: review if we need the abort controller here
|
||||
|
||||
@@ -2,7 +2,7 @@ import buildDebug from 'debug';
|
||||
import { Response, Router } from 'express';
|
||||
|
||||
import { getApiToken } from '@verdaccio/auth';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Auth } from '@verdaccio/auth';
|
||||
import { createRemoteUser } from '@verdaccio/config';
|
||||
import { API_ERROR, API_MESSAGE, HTTP_STATUS, errorUtils, validatioUtils } from '@verdaccio/core';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
@@ -13,7 +13,7 @@ import { $NextFunctionVer, $RequestExtend } from '../types/custom';
|
||||
|
||||
const debug = buildDebug('verdaccio:api:user');
|
||||
|
||||
export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
export default function (route: Router, auth: Auth, config: Config): void {
|
||||
route.get(
|
||||
'/-/user/:org_couchdb_user',
|
||||
function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {
|
||||
@@ -41,7 +41,7 @@ export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
*
|
||||
* @export
|
||||
* @param {Router} route
|
||||
* @param {IAuth} auth
|
||||
* @param {Auth} auth
|
||||
* @param {Config} config
|
||||
*/
|
||||
route.put(
|
||||
@@ -67,7 +67,7 @@ export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
);
|
||||
}
|
||||
|
||||
const restoredRemoteUser: RemoteUser = createRemoteUser(name, user.groups || []);
|
||||
const restoredRemoteUser: RemoteUser = createRemoteUser(name, user?.groups || []);
|
||||
const token = await getApiToken(auth, config, restoredRemoteUser, password);
|
||||
debug('login: new token');
|
||||
if (!token) {
|
||||
@@ -112,7 +112,9 @@ export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
}
|
||||
|
||||
const token =
|
||||
name && password ? await getApiToken(auth, config, user, password) : undefined;
|
||||
name && password
|
||||
? await getApiToken(auth, config, user as RemoteUser, password)
|
||||
: undefined;
|
||||
if (token) {
|
||||
debug('adduser: new token %o', mask(token as string, 4));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Response, Router } from 'express';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Auth } from '@verdaccio/auth';
|
||||
import {
|
||||
API_ERROR,
|
||||
APP_ERROR,
|
||||
@@ -25,7 +25,7 @@ export interface Profile {
|
||||
fullname: string;
|
||||
}
|
||||
|
||||
export default function (route: Router, auth: IAuth, config: Config): void {
|
||||
export default function (route: Router, auth: Auth, config: Config): void {
|
||||
function buildProfile(name: string): Profile {
|
||||
return {
|
||||
tfa: false,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import buildDebug from 'debug';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Auth } from '@verdaccio/auth';
|
||||
import { HTTP_STATUS, searchUtils } from '@verdaccio/core';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
@@ -15,7 +15,7 @@ const debug = buildDebug('verdaccio:api:search');
|
||||
* - {"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 {
|
||||
export default function (route, auth: Auth, storage: Storage): void {
|
||||
function checkAccess(pkg: any, auth: any, remoteUser): Promise<Manifest | null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
auth.allow_access({ packageName: pkg?.package?.name }, remoteUser, function (err, allowed) {
|
||||
@@ -41,7 +41,8 @@ export default function (route, auth: IAuth, storage: Storage): void {
|
||||
let data;
|
||||
const abort = new AbortController();
|
||||
|
||||
req.on('aborted', () => {
|
||||
req.socket.on('close', function () {
|
||||
debug('search web aborted');
|
||||
abort.abort();
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Response, Router } from 'express';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { getApiToken } from '@verdaccio/auth';
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Auth } from '@verdaccio/auth';
|
||||
import { HTTP_STATUS, SUPPORT_ERRORS, errorUtils } from '@verdaccio/core';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
@@ -23,7 +23,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: Storage, config: Config): void {
|
||||
export default function (route: Router, auth: Auth, storage: Storage, config: Config): void {
|
||||
route.get(
|
||||
'/-/npm/v1/tokens',
|
||||
async function (req: $RequestExtend, res: Response, next: $NextFunctionVer) {
|
||||
@@ -61,7 +61,7 @@ export default function (route: Router, auth: IAuth, storage: Storage, config: C
|
||||
return next(errorUtils.getCode(HTTP_STATUS.BAD_DATA, SUPPORT_ERRORS.PARAMETERS_NOT_VALID));
|
||||
}
|
||||
|
||||
auth.authenticate(name, password, async (err, user: RemoteUser) => {
|
||||
auth.authenticate(name, password, async (err, user?: RemoteUser) => {
|
||||
if (err) {
|
||||
const errorCode = err.message ? HTTP_STATUS.UNAUTHORIZED : HTTP_STATUS.INTERNAL_ERROR;
|
||||
return next(errorUtils.getCode(errorCode, err.message));
|
||||
@@ -76,7 +76,7 @@ export default function (route: Router, auth: IAuth, storage: Storage, config: C
|
||||
}
|
||||
|
||||
try {
|
||||
const token = await getApiToken(auth, config, user, password);
|
||||
const token = await getApiToken(auth, config, user as RemoteUser, password);
|
||||
if (!token) {
|
||||
throw errorUtils.getInternalError();
|
||||
}
|
||||
|
||||
@@ -160,13 +160,13 @@ describe('publish', () => {
|
||||
decodeURIComponent(pkgName),
|
||||
'1.0.1-patch'
|
||||
).expect(HTTP_STATUS.CREATED);
|
||||
expect(response.body.ok).toEqual(API_MESSAGE.PKG_CREATED);
|
||||
expect(response.body.ok).toEqual(API_MESSAGE.PKG_CHANGED);
|
||||
const response2 = await publishVersion(
|
||||
app,
|
||||
decodeURIComponent(pkgName),
|
||||
'1.0.2-patch'
|
||||
).expect(HTTP_STATUS.CREATED);
|
||||
expect(response2.body.ok).toEqual(API_MESSAGE.PKG_CREATED);
|
||||
expect(response2.body.ok).toEqual(API_MESSAGE.PKG_CHANGED);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# @verdaccio/auth
|
||||
|
||||
## 6.0.0-6-next.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/core@6.0.0-6-next.50
|
||||
- @verdaccio/config@6.0.0-6-next.50
|
||||
- @verdaccio/loaders@6.0.0-6-next.19
|
||||
- @verdaccio/logger@6.0.0-6-next.18
|
||||
- verdaccio-htpasswd@11.0.0-6-next.20
|
||||
- @verdaccio/utils@6.0.0-6-next.18
|
||||
|
||||
## 6.0.0-6-next.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/core@6.0.0-6-next.49
|
||||
- @verdaccio/config@6.0.0-6-next.49
|
||||
- @verdaccio/loaders@6.0.0-6-next.18
|
||||
- @verdaccio/logger@6.0.0-6-next.17
|
||||
- verdaccio-htpasswd@11.0.0-6-next.19
|
||||
- @verdaccio/utils@6.0.0-6-next.17
|
||||
|
||||
## 6.0.0-6-next.27
|
||||
|
||||
### Major Changes
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "@verdaccio/auth",
|
||||
"version": "6.0.0-6-next.27",
|
||||
"version": "6.0.0-6-next.29",
|
||||
"description": "logger",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
"types": "./build/index.d.ts",
|
||||
"author": {
|
||||
"name": "Juan Picado",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
@@ -39,16 +39,16 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/loaders": "workspace:6.0.0-6-next.17",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.16",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.16",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/loaders": "workspace:6.0.0-6-next.19",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.18",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.18",
|
||||
"debug": "4.3.4",
|
||||
"express": "4.18.1",
|
||||
"express": "4.18.2",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"lodash": "4.17.21",
|
||||
"verdaccio-htpasswd": "workspace:11.0.0-6-next.18"
|
||||
"verdaccio-htpasswd": "workspace:11.0.0-6-next.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.17"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import buildDebug from 'debug';
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import { NextFunction, Request, RequestHandler, Response } from 'express';
|
||||
import _ from 'lodash';
|
||||
import { HTPasswd } from 'verdaccio-htpasswd';
|
||||
|
||||
@@ -11,18 +11,17 @@ import {
|
||||
TOKEN_BEARER,
|
||||
VerdaccioError,
|
||||
errorUtils,
|
||||
pluginUtils,
|
||||
} from '@verdaccio/core';
|
||||
import { asyncLoadPlugin } from '@verdaccio/loaders';
|
||||
import { logger } from '@verdaccio/logger';
|
||||
import {
|
||||
AllowAccess,
|
||||
AuthPluginPackage,
|
||||
Callback,
|
||||
Config,
|
||||
IPluginAuth,
|
||||
JWTSignOptions,
|
||||
Logger,
|
||||
PackageAccess,
|
||||
PluginOptions,
|
||||
RemoteUser,
|
||||
Security,
|
||||
} from '@verdaccio/types';
|
||||
@@ -41,20 +40,8 @@ import {
|
||||
verifyJWTPayload,
|
||||
} from './utils';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const LoggerApi = require('@verdaccio/logger');
|
||||
|
||||
const debug = buildDebug('verdaccio:auth');
|
||||
|
||||
export interface IBasicAuth<T> {
|
||||
config: T & Config;
|
||||
authenticate(user: string, password: string, cb: Callback): void;
|
||||
invalidateToken?(token: string): Promise<void>;
|
||||
changePassword(user: string, password: string, newPassword: string, cb: Callback): void;
|
||||
allow_access(pkg: AuthPluginPackage, user: RemoteUser, callback: Callback): void;
|
||||
add_user(user: string, password: string, cb: Callback): any;
|
||||
}
|
||||
|
||||
export interface TokenEncryption {
|
||||
jwtEncrypt(user: RemoteUser, signOptions: JWTSignOptions): Promise<string>;
|
||||
aesEncrypt(buf: string): string | void;
|
||||
@@ -64,36 +51,22 @@ export interface AESPayload {
|
||||
user: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export type $RequestExtend = Request & { remote_user?: any; log: Logger };
|
||||
export type $ResponseExtend = Response & { cookies?: any };
|
||||
export type $NextFunctionVer = NextFunction & any;
|
||||
|
||||
export interface IAuthMiddleware {
|
||||
apiJWTmiddleware(): $NextFunctionVer;
|
||||
webUIJWTmiddleware(): $NextFunctionVer;
|
||||
}
|
||||
|
||||
export interface IAuth extends IBasicAuth<Config>, IAuthMiddleware, TokenEncryption {
|
||||
config: Config;
|
||||
logger: Logger;
|
||||
secret: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
plugins: any[];
|
||||
allow_unpublish(pkg: AuthPluginPackage, user: RemoteUser, callback: Callback): void;
|
||||
invalidateToken(token: string): Promise<void>;
|
||||
init(): Promise<void>;
|
||||
}
|
||||
export type $RequestExtend = Request & { remote_user?: any; log: Logger };
|
||||
export type $ResponseExtend = Response & { cookies?: any };
|
||||
export type $NextFunctionVer = NextFunction & any;
|
||||
|
||||
class Auth implements IAuth {
|
||||
class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
|
||||
public config: Config;
|
||||
public logger: Logger;
|
||||
public secret: string;
|
||||
public plugins: IPluginAuth<Config>[];
|
||||
public plugins: pluginUtils.Auth<Config>[];
|
||||
|
||||
public constructor(config: Config) {
|
||||
this.config = config;
|
||||
this.logger = LoggerApi.logger.child({ sub: 'auth' });
|
||||
this.secret = config.secret;
|
||||
this.plugins = [];
|
||||
if (!this.secret) {
|
||||
@@ -102,7 +75,7 @@ class Auth implements IAuth {
|
||||
}
|
||||
|
||||
public async init() {
|
||||
let plugins = await this.loadPlugin();
|
||||
let plugins = (await this.loadPlugin()) as pluginUtils.Auth<unknown>[];
|
||||
debug('auth plugins found %s', plugins.length);
|
||||
if (!plugins || plugins.length === 0) {
|
||||
plugins = this.loadDefaultPlugin();
|
||||
@@ -114,33 +87,40 @@ class Auth implements IAuth {
|
||||
|
||||
private loadDefaultPlugin() {
|
||||
debug('load default auth plugin');
|
||||
const pluginOptions: PluginOptions = {
|
||||
const pluginOptions: pluginUtils.PluginOptions = {
|
||||
config: this.config,
|
||||
logger: this.logger,
|
||||
logger,
|
||||
};
|
||||
let authPlugin;
|
||||
try {
|
||||
authPlugin = new HTPasswd({ file: './htpasswd' }, pluginOptions as any as PluginOptions);
|
||||
authPlugin = new HTPasswd(
|
||||
{ file: './htpasswd' },
|
||||
pluginOptions as any as pluginUtils.PluginOptions
|
||||
);
|
||||
} catch (error: any) {
|
||||
debug('error on loading auth htpasswd plugin stack: %o', error);
|
||||
logger.info({}, 'no auth plugin has been found');
|
||||
return [];
|
||||
}
|
||||
|
||||
return [authPlugin];
|
||||
}
|
||||
|
||||
private async loadPlugin(): Promise<IPluginAuth<Config>[]> {
|
||||
return asyncLoadPlugin<IPluginAuth<Config>>(
|
||||
private async loadPlugin() {
|
||||
return asyncLoadPlugin<pluginUtils.Auth<unknown>>(
|
||||
this.config.auth,
|
||||
{
|
||||
config: this.config,
|
||||
logger: this.logger,
|
||||
logger,
|
||||
},
|
||||
(plugin: IPluginAuth<Config>): boolean => {
|
||||
(plugin): boolean => {
|
||||
const { authenticate, allow_access, allow_publish } = plugin;
|
||||
|
||||
// @ts-ignore
|
||||
return authenticate || allow_access || allow_publish;
|
||||
return (
|
||||
typeof authenticate !== 'undefined' ||
|
||||
typeof allow_access !== 'undefined' ||
|
||||
typeof allow_publish !== 'undefined'
|
||||
);
|
||||
},
|
||||
this.config?.serverSettings?.pluginPrefix
|
||||
);
|
||||
@@ -148,7 +128,7 @@ class Auth implements IAuth {
|
||||
|
||||
private _applyDefaultPlugins(): void {
|
||||
// TODO: rename to applyFallbackPluginMethods
|
||||
this.plugins.push(getDefaultPlugins(this.logger));
|
||||
this.plugins.push(getDefaultPlugins(logger));
|
||||
}
|
||||
|
||||
public changePassword(
|
||||
@@ -171,7 +151,7 @@ class Auth implements IAuth {
|
||||
debug('updating password for %o', username);
|
||||
plugin.changePassword!(username, password, newPassword, (err, profile): void => {
|
||||
if (err) {
|
||||
this.logger.error(
|
||||
logger.error(
|
||||
{ username, err },
|
||||
`An error has been produced
|
||||
updating the password for @{username}. Error: @{err.message}`
|
||||
@@ -192,17 +172,21 @@ class Auth implements IAuth {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public authenticate(username: string, password: string, cb: Callback): void {
|
||||
public authenticate(
|
||||
username: string,
|
||||
password: string,
|
||||
cb: (error: VerdaccioError | null, user?: RemoteUser) => void
|
||||
): void {
|
||||
const plugins = this.plugins.slice(0);
|
||||
(function next(): void {
|
||||
const plugin = plugins.shift() as IPluginAuth<Config>;
|
||||
const plugin = plugins.shift() as pluginUtils.Auth<Config>;
|
||||
|
||||
if (isFunction(plugin.authenticate) === false) {
|
||||
return next();
|
||||
}
|
||||
|
||||
debug('authenticating %o', username);
|
||||
plugin.authenticate(username, password, function (err, groups): void {
|
||||
plugin.authenticate(username, password, function (err: VerdaccioError | null, groups): void {
|
||||
if (err) {
|
||||
debug('authenticating for user %o failed. Error: %o', username, err?.message);
|
||||
return cb(err);
|
||||
@@ -233,37 +217,42 @@ class Auth implements IAuth {
|
||||
})();
|
||||
}
|
||||
|
||||
public add_user(user: string, password: string, cb: Callback): void {
|
||||
public add_user(
|
||||
user: string,
|
||||
password: string,
|
||||
cb: (error: VerdaccioError | null, user?: RemoteUser) => void
|
||||
): void {
|
||||
const self = this;
|
||||
const plugins = this.plugins.slice(0);
|
||||
debug('add user %o', user);
|
||||
|
||||
(function next(): void {
|
||||
const plugin = plugins.shift() as IPluginAuth<Config>;
|
||||
let method = 'adduser';
|
||||
if (isFunction(plugin[method]) === false) {
|
||||
method = 'add_user';
|
||||
self.logger.warn(
|
||||
'the plugin method add_user in the auth plugin is deprecated and will' +
|
||||
' be removed in next major release, notify to the plugin author'
|
||||
);
|
||||
}
|
||||
|
||||
if (isFunction(plugin[method]) === false) {
|
||||
const plugin = plugins.shift() as pluginUtils.Auth<Config>;
|
||||
if (typeof plugin.adduser !== 'function') {
|
||||
next();
|
||||
} else {
|
||||
// p.add_user() execution
|
||||
plugin[method](user, password, function (err, ok): void {
|
||||
if (err) {
|
||||
debug('the user %o could not being added. Error: %o', user, err?.message);
|
||||
return cb(err);
|
||||
// @ts-expect-error future major (7.x) should remove this section
|
||||
if (typeof plugin.adduser === 'undefined' && typeof plugin.add_user === 'function') {
|
||||
throw errorUtils.getInternalError(
|
||||
'add_user method not longer supported, rename to adduser'
|
||||
);
|
||||
}
|
||||
|
||||
plugin.adduser(
|
||||
user,
|
||||
password,
|
||||
function (err: VerdaccioError | null, ok?: boolean | string): void {
|
||||
if (err) {
|
||||
debug('the user %o could not being added. Error: %o', user, err?.message);
|
||||
return cb(err);
|
||||
}
|
||||
if (ok) {
|
||||
debug('the user %o has been added', user);
|
||||
return self.authenticate(user, password, cb);
|
||||
}
|
||||
next();
|
||||
}
|
||||
if (ok) {
|
||||
debug('the user %o has been added', user);
|
||||
return self.authenticate(user, password, cb);
|
||||
}
|
||||
next();
|
||||
});
|
||||
);
|
||||
}
|
||||
})();
|
||||
}
|
||||
@@ -272,27 +261,27 @@ class Auth implements IAuth {
|
||||
* Allow user to access a package.
|
||||
*/
|
||||
public allow_access(
|
||||
{ packageName, packageVersion }: AuthPluginPackage,
|
||||
{ packageName, packageVersion }: pluginUtils.AuthPluginPackage,
|
||||
user: RemoteUser,
|
||||
callback: Callback
|
||||
callback: pluginUtils.AccessCallback
|
||||
): void {
|
||||
const plugins = this.plugins.slice(0);
|
||||
const pkgAllowAcces: AllowAccess = { name: packageName, version: packageVersion };
|
||||
const pkgAllowAccess: AllowAccess = { name: packageName, version: packageVersion };
|
||||
const pkg = Object.assign(
|
||||
{},
|
||||
pkgAllowAcces,
|
||||
pkgAllowAccess,
|
||||
getMatchedPackagesSpec(packageName, this.config.packages)
|
||||
) as AllowAccess & PackageAccess;
|
||||
debug('allow access for %o', packageName);
|
||||
|
||||
(function next(): void {
|
||||
const plugin: IPluginAuth<Config> = plugins.shift() as IPluginAuth<Config>;
|
||||
const plugin: pluginUtils.Auth<unknown> = plugins.shift() as pluginUtils.Auth<unknown>;
|
||||
|
||||
if (_.isNil(plugin) || isFunction(plugin.allow_access) === false) {
|
||||
return next();
|
||||
}
|
||||
|
||||
plugin.allow_access!(user, pkg, function (err, ok: boolean): void {
|
||||
plugin.allow_access!(user, pkg, function (err: VerdaccioError | null, ok?: boolean): void {
|
||||
if (err) {
|
||||
debug('forbidden access for %o. Error: %o', packageName, err?.message);
|
||||
return callback(err);
|
||||
@@ -309,7 +298,7 @@ class Auth implements IAuth {
|
||||
}
|
||||
|
||||
public allow_unpublish(
|
||||
{ packageName, packageVersion }: AuthPluginPackage,
|
||||
{ packageName, packageVersion }: pluginUtils.AuthPluginPackage,
|
||||
user: RemoteUser,
|
||||
callback: Callback
|
||||
): void {
|
||||
@@ -354,7 +343,7 @@ class Auth implements IAuth {
|
||||
* Allow user to publish a package.
|
||||
*/
|
||||
public allow_publish(
|
||||
{ packageName, packageVersion }: AuthPluginPackage,
|
||||
{ packageName, packageVersion }: pluginUtils.AuthPluginPackage,
|
||||
user: RemoteUser,
|
||||
callback: Callback
|
||||
): void {
|
||||
@@ -362,42 +351,35 @@ class Auth implements IAuth {
|
||||
const pkg = Object.assign(
|
||||
{ name: packageName, version: packageVersion },
|
||||
getMatchedPackagesSpec(packageName, this.config.packages)
|
||||
);
|
||||
) as any;
|
||||
debug('allow publish for %o init | plugins: %o', packageName, plugins.length);
|
||||
|
||||
(function next(): void {
|
||||
const plugin = plugins.shift();
|
||||
|
||||
if (isFunction(plugin?.allow_publish) === false) {
|
||||
if (typeof plugin?.allow_publish !== 'function') {
|
||||
debug('allow publish for %o plugin does not implement allow_publish', packageName);
|
||||
return next();
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
plugin.allow_publish(
|
||||
user,
|
||||
// @ts-ignore
|
||||
pkg,
|
||||
// @ts-ignore
|
||||
(err: VerdaccioError, ok: boolean): void => {
|
||||
if (_.isNil(err) === false && _.isError(err)) {
|
||||
debug('forbidden publish for %o', packageName);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
debug('allowed publish for %o', packageName);
|
||||
return callback(null, ok);
|
||||
}
|
||||
|
||||
debug('allow publish skip validation for %o', packageName);
|
||||
next(); // cb(null, false) causes next plugin to roll
|
||||
plugin.allow_publish(user, pkg, (err: VerdaccioError | null, ok?: boolean): void => {
|
||||
if (_.isNil(err) === false && _.isError(err)) {
|
||||
debug('forbidden publish for %o', packageName);
|
||||
return callback(err);
|
||||
}
|
||||
);
|
||||
|
||||
if (ok) {
|
||||
debug('allowed publish for %o', packageName);
|
||||
return callback(null, ok);
|
||||
}
|
||||
|
||||
debug('allow publish skip validation for %o', packageName);
|
||||
next(); // cb(null, false) causes next plugin to roll
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
public apiJWTmiddleware(): Function {
|
||||
public apiJWTmiddleware(): RequestHandler {
|
||||
debug('jwt middleware');
|
||||
const plugins = this.plugins.slice(0);
|
||||
const helpers = { createAnonymousRemoteUser, createRemoteUser };
|
||||
@@ -407,10 +389,11 @@ class Auth implements IAuth {
|
||||
}
|
||||
}
|
||||
|
||||
return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {
|
||||
// @ts-ignore
|
||||
return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction) => {
|
||||
req.pause();
|
||||
|
||||
const next = function (err: VerdaccioError | void): void {
|
||||
const next = function (err?: VerdaccioError): any {
|
||||
req.resume();
|
||||
// uncomment this to reject users with bad auth headers
|
||||
// return _next.apply(null, arguments)
|
||||
@@ -419,6 +402,7 @@ class Auth implements IAuth {
|
||||
if (err) {
|
||||
req.remote_user.error = err.message;
|
||||
}
|
||||
|
||||
return _next();
|
||||
};
|
||||
|
||||
@@ -469,7 +453,7 @@ class Auth implements IAuth {
|
||||
const credentials = convertPayloadToBase64(token).toString();
|
||||
const { user, password } = parseBasicPayload(credentials) as AESPayload;
|
||||
debug('authenticating %o', user);
|
||||
this.authenticate(user, password, (err, user): void => {
|
||||
this.authenticate(user, password, (err: VerdaccioError | null, user): void => {
|
||||
if (!err) {
|
||||
debug('generating a remote user');
|
||||
req.remote_user = user;
|
||||
@@ -529,14 +513,15 @@ class Auth implements IAuth {
|
||||
}
|
||||
}
|
||||
|
||||
private _isRemoteUserValid(remote_user: RemoteUser): boolean {
|
||||
return _.isUndefined(remote_user) === false && _.isUndefined(remote_user.name) === false;
|
||||
private _isRemoteUserValid(remote_user?: RemoteUser): boolean {
|
||||
return _.isUndefined(remote_user) === false && _.isUndefined(remote_user?.name) === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT middleware for WebUI
|
||||
*/
|
||||
public webUIJWTmiddleware(): Function {
|
||||
public webUIJWTmiddleware(): RequestHandler {
|
||||
// @ts-ignore
|
||||
return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => {
|
||||
if (this._isRemoteUserValid(req.remote_user)) {
|
||||
return _next();
|
||||
@@ -567,7 +552,7 @@ class Auth implements IAuth {
|
||||
return next();
|
||||
}
|
||||
|
||||
let credentials;
|
||||
let credentials: RemoteUser | undefined;
|
||||
try {
|
||||
credentials = verifyJWTPayload(token, this.config.secret);
|
||||
} catch (err: any) {
|
||||
@@ -575,9 +560,8 @@ class Auth implements IAuth {
|
||||
}
|
||||
|
||||
if (this._isRemoteUserValid(credentials)) {
|
||||
const { name, groups } = credentials;
|
||||
// $FlowFixMe
|
||||
req.remote_user = createRemoteUser(name, groups);
|
||||
const { name, groups } = credentials as RemoteUser;
|
||||
req.remote_user = createRemoteUser(name as string, groups);
|
||||
} else {
|
||||
req.remote_user = createAnonymousRemoteUser();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export { Auth, IAuth, TokenEncryption, IBasicAuth } from './auth';
|
||||
export { Auth, TokenEncryption } from './auth';
|
||||
export * from './utils';
|
||||
export * from './legacy-token';
|
||||
export * from './jwt-token';
|
||||
|
||||
@@ -9,15 +9,9 @@ import {
|
||||
TOKEN_BEARER,
|
||||
VerdaccioError,
|
||||
errorUtils,
|
||||
pluginUtils,
|
||||
} from '@verdaccio/core';
|
||||
import {
|
||||
AuthPackageAllow,
|
||||
Callback,
|
||||
Config,
|
||||
IPluginAuth,
|
||||
RemoteUser,
|
||||
Security,
|
||||
} from '@verdaccio/types';
|
||||
import { AuthPackageAllow, Config, Logger, RemoteUser, Security } from '@verdaccio/types';
|
||||
|
||||
import { AESPayload, TokenEncryption } from './auth';
|
||||
import { verifyPayload } from './jwt-token';
|
||||
@@ -161,13 +155,18 @@ export function isAuthHeaderValid(authorization: string): boolean {
|
||||
return authorization.split(' ').length === 2;
|
||||
}
|
||||
|
||||
export function getDefaultPlugins(logger: any): IPluginAuth<Config> {
|
||||
/**
|
||||
* Return a default configuration for authentication if none is provided.
|
||||
* @param logger {Logger}
|
||||
* @returns object of default implementations.
|
||||
*/
|
||||
export function getDefaultPlugins(logger: Logger): pluginUtils.Auth<Config> {
|
||||
return {
|
||||
authenticate(user: string, password: string, cb: Callback): void {
|
||||
authenticate(_user: string, _password: string, cb: pluginUtils.AuthCallback): void {
|
||||
cb(errorUtils.getForbidden(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
},
|
||||
|
||||
adduser(user: string, password: string, cb: Callback): void {
|
||||
adduser(_user: string, _password: string, cb: pluginUtils.AuthUserCallback): void {
|
||||
return cb(errorUtils.getConflict(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
},
|
||||
|
||||
@@ -182,7 +181,7 @@ export function getDefaultPlugins(logger: any): IPluginAuth<Config> {
|
||||
|
||||
export type ActionsAllowed = 'publish' | 'unpublish' | 'access';
|
||||
|
||||
export function allow_action(action: ActionsAllowed, logger): AllowAction {
|
||||
export function allow_action(action: ActionsAllowed, logger: Logger): AllowAction {
|
||||
return function allowActionCallback(
|
||||
user: RemoteUser,
|
||||
pkg: AuthPackageAllow,
|
||||
@@ -217,7 +216,7 @@ export function allow_action(action: ActionsAllowed, logger): AllowAction {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export function handleSpecialUnpublish(logger): any {
|
||||
export function handleSpecialUnpublish(logger: Logger): any {
|
||||
return function (user: RemoteUser, pkg: AuthPackageAllow, callback: AllowActionCallback): void {
|
||||
const action = 'unpublish';
|
||||
// verify whether the unpublish prop has been defined
|
||||
|
||||
@@ -24,7 +24,6 @@ import type { AllowActionCallbackResponse } from '@verdaccio/utils';
|
||||
import {
|
||||
ActionsAllowed,
|
||||
Auth,
|
||||
IAuth,
|
||||
aesDecrypt,
|
||||
allow_action,
|
||||
getApiToken,
|
||||
@@ -70,7 +69,7 @@ describe('Auth utilities', () => {
|
||||
methodNotBeenCalled: string
|
||||
): Promise<string> {
|
||||
const config: Config = getConfig(configFileName, secret);
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
// @ts-ignore
|
||||
const spy = jest.spyOn(auth, methodToSpy);
|
||||
@@ -409,7 +408,7 @@ describe('Auth utilities', () => {
|
||||
test.concurrent('should return empty credential corrupted payload', async () => {
|
||||
const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
|
||||
const config: Config = getConfig('security-legacy', secret);
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
const token = auth.aesEncrypt(null);
|
||||
const security: Security = config.security;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import path from 'path';
|
||||
|
||||
import { IAuth } from '@verdaccio/auth';
|
||||
import { Config as AppConfig, ROLES, getDefaultConfig } from '@verdaccio/config';
|
||||
import { errorUtils } from '@verdaccio/core';
|
||||
import { setup } from '@verdaccio/logger';
|
||||
@@ -9,14 +8,14 @@ import { Config } from '@verdaccio/types';
|
||||
import { Auth } from '../src';
|
||||
import { authPluginFailureConf, authPluginPassThrougConf, authProfileConf } from './helper/plugin';
|
||||
|
||||
setup([]);
|
||||
setup({});
|
||||
|
||||
describe('AuthTest', () => {
|
||||
test('should init correctly', async () => {
|
||||
const config: Config = new AppConfig({ ...authProfileConf });
|
||||
config.checkSecretKey('12345');
|
||||
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
expect(auth).toBeDefined();
|
||||
});
|
||||
@@ -25,7 +24,7 @@ describe('AuthTest', () => {
|
||||
const config: Config = new AppConfig({ ...authProfileConf, auth: undefined });
|
||||
config.checkSecretKey('12345');
|
||||
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
expect(auth).toBeDefined();
|
||||
});
|
||||
@@ -35,7 +34,7 @@ describe('AuthTest', () => {
|
||||
test('should be a success login', async () => {
|
||||
const config: Config = new AppConfig({ ...authProfileConf });
|
||||
config.checkSecretKey('12345');
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
expect(auth).toBeDefined();
|
||||
|
||||
@@ -62,7 +61,7 @@ describe('AuthTest', () => {
|
||||
test('should be a fail on login', async () => {
|
||||
const config: Config = new AppConfig(authPluginFailureConf);
|
||||
config.checkSecretKey('12345');
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
expect(auth).toBeDefined();
|
||||
|
||||
@@ -81,7 +80,7 @@ describe('AuthTest', () => {
|
||||
test('should skip falsy values', async () => {
|
||||
const config: Config = new AppConfig({ ...authPluginPassThrougConf });
|
||||
config.checkSecretKey('12345');
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
expect(auth).toBeDefined();
|
||||
|
||||
@@ -101,7 +100,7 @@ describe('AuthTest', () => {
|
||||
test('should error truthy non-array', async () => {
|
||||
const config: Config = new AppConfig({ ...authPluginPassThrougConf });
|
||||
config.checkSecretKey('12345');
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
expect(auth).toBeDefined();
|
||||
|
||||
@@ -119,7 +118,7 @@ describe('AuthTest', () => {
|
||||
test('should skip empty array', async () => {
|
||||
const config: Config = new AppConfig({ ...authPluginPassThrougConf });
|
||||
config.checkSecretKey('12345');
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
expect(auth).toBeDefined();
|
||||
|
||||
@@ -136,7 +135,7 @@ describe('AuthTest', () => {
|
||||
test('should accept valid array', async () => {
|
||||
const config: Config = new AppConfig({ ...authPluginPassThrougConf });
|
||||
config.checkSecretKey('12345');
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
expect(auth).toBeDefined();
|
||||
|
||||
@@ -165,7 +164,7 @@ describe('AuthTest', () => {
|
||||
},
|
||||
});
|
||||
config.checkSecretKey('12345');
|
||||
const auth: IAuth = new Auth(config);
|
||||
const auth: Auth = new Auth(config);
|
||||
await auth.init();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build"
|
||||
"outDir": "./build",
|
||||
"noImplicitAny": false
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["src/**/*.test.ts"]
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
"extends": "../../tsconfig.reference",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build"
|
||||
"outDir": "./build",
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["src/**/*.test.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../config"
|
||||
},
|
||||
{
|
||||
"path": "../core/htpasswd"
|
||||
"path": "../plugins/htpasswd"
|
||||
},
|
||||
{
|
||||
"path": "../core/core"
|
||||
},
|
||||
{
|
||||
"path": "../loaders"
|
||||
@@ -19,9 +22,6 @@
|
||||
{
|
||||
"path": "../logger"
|
||||
},
|
||||
{
|
||||
"path": "../mock"
|
||||
},
|
||||
{
|
||||
"path": "../utils"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# @verdaccio/cli
|
||||
|
||||
## 6.0.0-6-next.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/node-api@6.0.0-6-next.50
|
||||
- @verdaccio/core@6.0.0-6-next.50
|
||||
- @verdaccio/config@6.0.0-6-next.50
|
||||
- @verdaccio/logger@6.0.0-6-next.18
|
||||
|
||||
## 6.0.0-6-next.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/node-api@6.0.0-6-next.49
|
||||
- @verdaccio/core@6.0.0-6-next.49
|
||||
- @verdaccio/config@6.0.0-6-next.49
|
||||
- @verdaccio/logger@6.0.0-6-next.17
|
||||
|
||||
## 6.0.0-6-next.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/cli",
|
||||
"version": "6.0.0-6-next.48",
|
||||
"version": "6.0.0-6-next.50",
|
||||
"author": {
|
||||
"name": "Juan Picado",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
@@ -44,14 +44,14 @@
|
||||
"start": "ts-node src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.16",
|
||||
"@verdaccio/node-api": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.18",
|
||||
"@verdaccio/node-api": "workspace:6.0.0-6-next.50",
|
||||
"clipanion": "3.1.0",
|
||||
"envinfo": "7.8.1",
|
||||
"kleur": "3.0.3",
|
||||
"semver": "7.3.7"
|
||||
"semver": "7.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ts-node": "10.9.1"
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
{
|
||||
"path": "../config"
|
||||
},
|
||||
{
|
||||
"path": "../core/cli-ui"
|
||||
},
|
||||
{
|
||||
"path": "../core/core"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @verdaccio/config
|
||||
|
||||
## 6.0.0-6-next.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/core@6.0.0-6-next.50
|
||||
- @verdaccio/utils@6.0.0-6-next.18
|
||||
|
||||
## 6.0.0-6-next.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/core@6.0.0-6-next.49
|
||||
- @verdaccio/utils@6.0.0-6-next.17
|
||||
|
||||
## 6.0.0-6-next.48
|
||||
|
||||
### Major Changes
|
||||
|
||||
@@ -1,72 +1,5 @@
|
||||
# @verdaccio/config
|
||||
|
||||
[](https://opencollective.com/verdaccio)
|
||||
[](https://stackshare.io/verdaccio)
|
||||
[](https://github.com/verdaccio/verdaccio/blob/master/LICENSE)
|
||||
[](https://crowdin.com/project/verdaccio)
|
||||
[](https://www.tickgit.com/browse?repo=github.com/verdaccio/verdaccio)
|
||||
|
||||
[](https://twitter.com/verdaccio_npm)
|
||||
[](https://github.com/verdaccio/verdaccio/stargazers)
|
||||
|
||||
## Donations
|
||||
|
||||
Verdaccio is run by **volunteers**; nobody is working full-time on it. If you find this project to be useful and would like to support its development, consider making a donation - **your logo might end up in this readme.** 😉
|
||||
|
||||
**[Donate](https://opencollective.com/verdaccio)** 💵👍🏻 starting from _\$1/month_ or just one single contribution.
|
||||
|
||||
## Report a vulnerability
|
||||
|
||||
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).
|
||||
|
||||
## Open Collective Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/verdaccio#sponsor)]
|
||||
|
||||
[](https://opencollective.com/verdaccio/sponsor/0/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/1/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/2/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/3/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/4/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/5/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/6/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/7/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/8/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/9/website)
|
||||
|
||||
## Open Collective Backers
|
||||
|
||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/verdaccio#backer)]
|
||||
|
||||
[](https://opencollective.com/verdaccio#backers)
|
||||
|
||||
## Special Thanks
|
||||
|
||||
Thanks to the following companies to help us to achieve our goals providing free open source licenses.
|
||||
|
||||
[](https://www.jetbrains.com/)
|
||||
[](https://crowdin.com/)
|
||||
[](https://balsamiq.com/)
|
||||
|
||||
## Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
|
||||
[](../../graphs/contributors)
|
||||
|
||||
### FAQ / Contact / Troubleshoot
|
||||
|
||||
If you have any issue you can try the following options, do no desist to ask or check our issues database, perhaps someone has asked already what you are looking for.
|
||||
|
||||
- [Blog](https://verdaccio.org/blog/)
|
||||
- [Donations](https://opencollective.com/verdaccio)
|
||||
- [Reporting an issue](https://github.com/verdaccio/verdaccio/blob/master/CONTRIBUTING.md#reporting-a-bug)
|
||||
- [Running discussions](https://github.com/verdaccio/verdaccio/issues?q=is%3Aissue+is%3Aopen+label%3Adiscuss)
|
||||
- [Chat](http://chat.verdaccio.org/)
|
||||
- [Logos](https://verdaccio.org/docs/en/logo)
|
||||
- [Docker Examples](https://github.com/verdaccio/docker-examples)
|
||||
- [FAQ](https://github.com/verdaccio/verdaccio/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Aquestion%20)
|
||||
|
||||
### License
|
||||
|
||||
Verdaccio is [MIT licensed](https://github.com/verdaccio/verdaccio/blob/master/LICENSE)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/config",
|
||||
"version": "6.0.0-6-next.48",
|
||||
"version": "6.0.0-6-next.50",
|
||||
"description": "logger",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -39,10 +39,10 @@
|
||||
"build": "pnpm run build:js && pnpm run build:types"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.16",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.18",
|
||||
"debug": "4.3.4",
|
||||
"yaml": "2.1.1",
|
||||
"yaml": "2.1.3",
|
||||
"lodash": "4.17.21",
|
||||
"minimatch": "3.1.2",
|
||||
"yup": "0.32.11"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# @verdaccio/core
|
||||
|
||||
## 6.0.0-6-next.50
|
||||
|
||||
## 6.0.0-6-next.49
|
||||
|
||||
## 6.0.0-6-next.48
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/core",
|
||||
"version": "6.0.0-6-next.48",
|
||||
"version": "6.0.0-6-next.50",
|
||||
"description": "core utilities",
|
||||
"keywords": [
|
||||
"private",
|
||||
@@ -36,19 +36,22 @@
|
||||
"dependencies": {
|
||||
"http-errors": "1.8.1",
|
||||
"http-status-codes": "2.2.0",
|
||||
"semver": "7.3.7",
|
||||
"semver": "7.3.8",
|
||||
"ajv": "8.11.0",
|
||||
"process-warning": "1.0.0",
|
||||
"core-js": "3.25.2"
|
||||
"core-js": "3.25.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lodash": "4.17.21",
|
||||
"typedoc": "0.23.16",
|
||||
"typedoc-plugin-missing-exports": "latest",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.17"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
"test": "jest",
|
||||
"type-check": "tsc --noEmit -p tsconfig.build.json",
|
||||
"build:docs": "typedoc --options ./typedoc.json --tsconfig 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",
|
||||
|
||||
@@ -1,24 +1,174 @@
|
||||
import { Config, IPackageStorage, Token, TokenFilter } from '@verdaccio/types';
|
||||
import { Express, RequestHandler } from 'express';
|
||||
import { Readable, Writable } from 'stream';
|
||||
|
||||
import { searchUtils } from '.';
|
||||
import {
|
||||
AllowAccess,
|
||||
Callback,
|
||||
Config,
|
||||
Logger,
|
||||
Manifest,
|
||||
PackageAccess,
|
||||
RemoteUser,
|
||||
Token,
|
||||
TokenFilter,
|
||||
} from '@verdaccio/types';
|
||||
|
||||
interface IPlugin {
|
||||
version?: string;
|
||||
// In case a plugin needs to be cleaned up/removed
|
||||
close?(): void;
|
||||
import { VerdaccioError, searchUtils } from '.';
|
||||
|
||||
export interface AuthPluginPackage {
|
||||
packageName: string;
|
||||
packageVersion?: string;
|
||||
tag?: string;
|
||||
}
|
||||
export interface PluginOptions {
|
||||
config: Config;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
export interface IPluginStorage<T> extends IPlugin {
|
||||
config: T & Config;
|
||||
/**
|
||||
* The base plugin class, set of utilities for developing
|
||||
* plugins.
|
||||
* @alpha
|
||||
* */
|
||||
export class Plugin<PluginConfig> {
|
||||
static version = 1;
|
||||
public readonly version: number;
|
||||
public readonly config: PluginConfig | unknown;
|
||||
public readonly options: PluginOptions;
|
||||
public constructor(config: PluginConfig, options: PluginOptions) {
|
||||
this.version = Plugin.version;
|
||||
this.config = config;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
}
|
||||
export interface StorageHandler {
|
||||
logger: Logger;
|
||||
deletePackage(fileName: string): Promise<void>;
|
||||
removePackage(): Promise<void>;
|
||||
// next packages migration (this list is meant to replace the callback parent functions)
|
||||
updatePackage(
|
||||
packageName: string,
|
||||
handleUpdate: (manifest: Manifest) => Promise<Manifest>
|
||||
): Promise<Manifest>;
|
||||
readPackage(name: string): Promise<Manifest>;
|
||||
savePackage(pkgName: string, value: Manifest): Promise<void>;
|
||||
readTarball(pkgName: string, { signal }: { signal: AbortSignal }): Promise<Readable>;
|
||||
createPackage(name: string, manifest: Manifest): Promise<void>;
|
||||
writeTarball(tarballName: string, { signal }: { signal: AbortSignal }): Promise<Writable>;
|
||||
// verify if tarball exist in the storage
|
||||
hasTarball(fileName: string): Promise<boolean>;
|
||||
// verify if package exist in the storage
|
||||
hasPackage(): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface Storage<PluginConfig> extends Plugin<PluginConfig> {
|
||||
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;
|
||||
getPackageStorage(packageInfo: string): StorageHandler;
|
||||
search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]>;
|
||||
saveToken(token: Token): Promise<any>;
|
||||
deleteToken(user: string, tokenKey: string): Promise<any>;
|
||||
readTokens(filter: TokenFilter): Promise<Token[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allow add additional middleware to the application.
|
||||
*
|
||||
* ```ts
|
||||
* import express, { Request, Response } from 'express';
|
||||
*
|
||||
* class Middleware extends Plugin {
|
||||
* // instances of auth and storage are injected
|
||||
* register_middlewares(app, auth, storage) {
|
||||
* const router = express.Router();
|
||||
* router.post('/my-endpoint', (req: Request, res: Response): void => {
|
||||
res.status(200).end();
|
||||
});
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* const [plugin] = await asyncLoadPlugin(...);
|
||||
* plugin.register_middlewares(app, auth, storage);
|
||||
* ```
|
||||
*/
|
||||
export interface ExpressMiddleware<PluginConfig, Storage, Auth> extends Plugin<PluginConfig> {
|
||||
register_middlewares(app: Express, auth: Auth, storage: Storage): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* dasdsa
|
||||
*/
|
||||
export type AuthCallback = (error: VerdaccioError | null, groups?: string[] | false) => void;
|
||||
|
||||
export type AuthAccessCallback = (error: VerdaccioError | null, access?: boolean) => void;
|
||||
export type AuthUserCallback = (error: VerdaccioError | null, access?: boolean | string) => void;
|
||||
export type AuthChangePasswordCallback = (error: VerdaccioError | null, access?: boolean) => void;
|
||||
export type AccessCallback = (error: VerdaccioError | null, ok?: boolean) => void;
|
||||
export interface Auth<T> extends Plugin<T> {
|
||||
/**
|
||||
* Handles the authenticated method.
|
||||
* ```ts
|
||||
* class Auth {
|
||||
public authenticate(user: string, password: string, done: AuthCallback): void {
|
||||
if (!password) {
|
||||
return done(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
}
|
||||
// always return an array of users
|
||||
return done(null, [user]);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
authenticate(user: string, password: string, cb: AuthCallback): void;
|
||||
/**
|
||||
* Handles the authenticated method.
|
||||
* ```ts
|
||||
* class Auth {
|
||||
public adduser(user: string, password: string, done: AuthCallback): void {
|
||||
if (!password) {
|
||||
return done(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||
}
|
||||
// return boolean
|
||||
return done(null, true);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
adduser?(user: string, password: string, cb: AuthUserCallback): void;
|
||||
changePassword?(
|
||||
user: string,
|
||||
password: string,
|
||||
newPassword: string,
|
||||
cb: AuthChangePasswordCallback
|
||||
): void;
|
||||
allow_publish?(user: RemoteUser, pkg: T & PackageAccess, cb: AuthAccessCallback): void;
|
||||
allow_publish?(user: RemoteUser, pkg: AllowAccess & PackageAccess, cb: AuthAccessCallback): void;
|
||||
allow_access?(user: RemoteUser, pkg: T & PackageAccess, cb: AccessCallback): void;
|
||||
allow_access?(user: RemoteUser, pkg: AllowAccess & PackageAccess, cb: AccessCallback): void;
|
||||
allow_unpublish?(user: RemoteUser, pkg: T & PackageAccess, cb: AuthAccessCallback): void;
|
||||
allow_unpublish?(
|
||||
user: RemoteUser,
|
||||
pkg: AllowAccess & PackageAccess,
|
||||
cb: AuthAccessCallback
|
||||
): void;
|
||||
apiJWTmiddleware?(helpers: any): RequestHandler;
|
||||
}
|
||||
|
||||
export interface IBasicAuth {
|
||||
authenticate(user: string, password: string, cb: Callback): void;
|
||||
invalidateToken?(token: string): Promise<void>;
|
||||
changePassword(user: string, password: string, newPassword: string, cb: Callback): void;
|
||||
allow_access(pkg: AuthPluginPackage, user: RemoteUser, callback: Callback): void;
|
||||
add_user(user: string, password: string, cb: Callback): any;
|
||||
}
|
||||
|
||||
export interface ManifestFilter<T> extends Plugin<T> {
|
||||
filterMetadata(packageInfo: Manifest): Promise<Manifest>;
|
||||
}
|
||||
|
||||
@@ -1,90 +1,9 @@
|
||||
import { PassThrough, Transform, TransformOptions } 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]();
|
||||
}
|
||||
});
|
||||
}
|
||||
import { Readable, Transform } from 'stream';
|
||||
|
||||
/**
|
||||
* Converts a buffer stream to a string.
|
||||
*/
|
||||
const readableToString = async (stream) => {
|
||||
const readableToString = async (stream: Readable) => {
|
||||
const chunks: Buffer[] = [];
|
||||
for await (let chunk of stream) {
|
||||
chunks.push(Buffer.from(chunk));
|
||||
@@ -106,4 +25,4 @@ const transformObjectToString = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export { ReadTarball, UploadTarball, readableToString, transformObjectToString };
|
||||
export { readableToString, transformObjectToString };
|
||||
|
||||
@@ -29,7 +29,7 @@ export function getByQualityPriorityValue(headerValue: string | undefined | null
|
||||
}
|
||||
return acc;
|
||||
}, [] as any)
|
||||
.sort(function (a, b) {
|
||||
.sort(function (a: number[], b: number[]) {
|
||||
return b[1] - a[1];
|
||||
});
|
||||
return header[0];
|
||||
|
||||
@@ -45,6 +45,6 @@ warningInstance.create(
|
||||
'multiple addresses will be deprecated in the next major, only use one'
|
||||
);
|
||||
|
||||
export function emit(code, a?: string, b?: string, c?: string) {
|
||||
export function emit(code: string, a?: string, b?: string, c?: string) {
|
||||
warningInstance.emit(code, a, b, c);
|
||||
}
|
||||
|
||||
@@ -1,34 +1,8 @@
|
||||
import { Stream } from 'stream';
|
||||
|
||||
import { ReadTarball, UploadTarball, readableToString } from '../src/stream-utils';
|
||||
import { readableToString } from '../src/stream-utils';
|
||||
|
||||
describe('mystreams', () => {
|
||||
test('should delay events on ReadTarball abort', (cb) => {
|
||||
const readTballStream = new ReadTarball({});
|
||||
readTballStream.abort();
|
||||
setTimeout(function () {
|
||||
readTballStream.abort = function (): void {
|
||||
cb();
|
||||
};
|
||||
readTballStream.abort = function (): never {
|
||||
throw Error('fail');
|
||||
};
|
||||
}, 10);
|
||||
});
|
||||
|
||||
test('should delay events on UploadTarball abort', (cb) => {
|
||||
const uploadTballStream = new UploadTarball({});
|
||||
uploadTballStream.abort();
|
||||
setTimeout(function () {
|
||||
uploadTballStream.abort = function (): void {
|
||||
cb();
|
||||
};
|
||||
uploadTballStream.abort = function (): never {
|
||||
throw Error('fail');
|
||||
};
|
||||
}, 10);
|
||||
});
|
||||
|
||||
test('readableToString single string', async () => {
|
||||
expect(await readableToString(Stream.Readable.from('foo'))).toEqual('foo');
|
||||
});
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build"
|
||||
"outDir": "./build",
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["src/**/*.test.ts"]
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build",
|
||||
"composite": true,
|
||||
"declaration": true
|
||||
"declaration": true,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["src/**/*.test.ts"]
|
||||
|
||||
5
packages/core/core/typedoc.json
Normal file
5
packages/core/core/typedoc.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://typedoc.org/schema.json",
|
||||
"entryPoints": ["src/index.ts"],
|
||||
"sort": ["source-order"]
|
||||
}
|
||||
@@ -1,5 +1,22 @@
|
||||
# Change Log
|
||||
|
||||
## 11.0.0-6-next.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/core@6.0.0-6-next.50
|
||||
- @verdaccio/url@11.0.0-6-next.16
|
||||
- @verdaccio/utils@6.0.0-6-next.18
|
||||
|
||||
## 11.0.0-6-next.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ce013d2f]
|
||||
- @verdaccio/url@11.0.0-6-next.15
|
||||
- @verdaccio/core@6.0.0-6-next.49
|
||||
- @verdaccio/utils@6.0.0-6-next.17
|
||||
|
||||
## 11.0.0-6-next.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/tarball",
|
||||
"version": "11.0.0-6-next.17",
|
||||
"version": "11.0.0-6-next.19",
|
||||
"description": "tarball utilities resolver",
|
||||
"keywords": [
|
||||
"private",
|
||||
@@ -35,9 +35,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "4.3.4",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.48",
|
||||
"@verdaccio/url": "workspace:11.0.0-6-next.14",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.16",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.50",
|
||||
"@verdaccio/url": "workspace:11.0.0-6-next.16",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.18",
|
||||
"lodash": "4.17.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,26 +1,3 @@
|
||||
# @verdaccio/types
|
||||
|
||||
TypeScript definitions for Verdaccio plugins and internal code.
|
||||
|
||||
### Usage
|
||||
|
||||
```ts
|
||||
import type {ILocalData, LocalStorage, Logger, Config} from '@verdaccio/types';
|
||||
|
||||
class LocalData implements ILocalData {
|
||||
path: string;
|
||||
logger: Logger;
|
||||
data: LocalStorage;
|
||||
config: Config;
|
||||
locked: boolean;
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Run docs
|
||||
|
||||
Generate the package types documentation at `./docs` folder.
|
||||
|
||||
```bash
|
||||
pnpm build:docs
|
||||
```
|
||||
|
||||
@@ -36,14 +36,13 @@
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
"test": "pnpm type-check",
|
||||
"build:docs": "typedoc --options ./typedoc.json --excludeExternals --tsconfig tsconfig.build.json",
|
||||
"build:docs": "typedoc --options ./typedoc.json --tsconfig tsconfig.build.json",
|
||||
"type-check": "tsc --noEmit -p tsconfig.build.json",
|
||||
"build": "tsc --emitDeclarationOnly -p tsconfig.build.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "16.11.60",
|
||||
"typedoc": "beta",
|
||||
"typedoc-plugin-missing-exports": "1.0.0"
|
||||
"@types/node": "16.11.65",
|
||||
"typedoc": "0.23.16"
|
||||
},
|
||||
"typedoc": {
|
||||
"entryPoint": "./src/types.ts",
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface RemoteUser {
|
||||
export type StringValue = string | void | null;
|
||||
|
||||
// FIXME: error should be export type `VerdaccioError = HttpError & { code: number };`
|
||||
// instead of AuthError
|
||||
// instead of VerdaccioError
|
||||
// but this type is on @verdaccio/core and cannot be used here yet (I don't know why)
|
||||
export interface HttpError extends Error {
|
||||
status: number;
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Callback, HttpError, RemoteUser } from '../commons';
|
||||
import { Config } from '../configuration';
|
||||
|
||||
export interface AuthPluginPackage {
|
||||
packageName: string;
|
||||
packageVersion?: string;
|
||||
tag?: string;
|
||||
}
|
||||
|
||||
export type AuthError = HttpError & { code: number };
|
||||
export type AuthAccessCallback = (error: AuthError | null, access: boolean) => void;
|
||||
export type AuthCallback = (error: AuthError | null, groups: string[] | false) => void;
|
||||
|
||||
// @deprecated use IBasicAuth from @verdaccio/auth
|
||||
export interface IBasicAuth<T> {
|
||||
config: T & Config;
|
||||
aesEncrypt(buf: Buffer): Buffer;
|
||||
authenticate(user: string, password: string, cb: Callback): void;
|
||||
changePassword(user: string, password: string, newPassword: string, cb: Callback): void;
|
||||
allow_access(pkg: AuthPluginPackage, user: RemoteUser, callback: Callback): void;
|
||||
add_user(user: string, password: string, cb: Callback): any;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user