Compare commits
33 Commits
@verdaccio
...
@verdaccio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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,6 +115,7 @@
|
||||
"proud-jobs-hope",
|
||||
"red-chefs-float",
|
||||
"red-yaks-sell",
|
||||
"rich-badgers-begin",
|
||||
"rich-ghosts-rule",
|
||||
"shaggy-carrots-unite",
|
||||
"shaggy-parrots-smash",
|
||||
@@ -138,6 +140,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
|
||||
---
|
||||
|
||||
@@ -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
|
||||
|
||||
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
|
||||
18
.github/workflows/website.yml
vendored
18
.github/workflows/website.yml
vendored
@@ -14,15 +14,15 @@ jobs:
|
||||
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:
|
||||
@@ -37,10 +37,12 @@ jobs:
|
||||
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 +54,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 +100,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/**/*
|
||||
|
||||
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,9 +5,9 @@
|
||||
"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.49",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.49",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.49",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.17",
|
||||
"yaml": "2.1.1",
|
||||
"debug": "4.3.4",
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -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.`);
|
||||
});
|
||||
});
|
||||
88
e2e/ui/cypress/e2e/publish.cy.ts
Normal file
88
e2e/ui/cypress/e2e/publish.cy.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
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.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.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.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();
|
||||
});
|
||||
});
|
||||
37
e2e/ui/cypress/support/commands.ts
Normal file
37
e2e/ui/cypress/support/commands.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/* 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.get('#login--dialog-username').type(user);
|
||||
cy.get('#login--dialog-password').type(password);
|
||||
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.49",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.49",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.49",
|
||||
"@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,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
38
package.json
38
package.json
@@ -15,11 +15,11 @@
|
||||
"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",
|
||||
@@ -33,7 +33,7 @@
|
||||
"@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.3",
|
||||
"@babel/preset-react": "7.18.6",
|
||||
"@babel/preset-typescript": "7.18.6",
|
||||
"@babel/register": "7.18.9",
|
||||
@@ -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.62",
|
||||
"@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.1.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.3",
|
||||
"cross-env": "7.0.3",
|
||||
"debug": "4.3.4",
|
||||
"detect-secrets": "1.0.6",
|
||||
"jest-diff": "29.0.3",
|
||||
"jest-diff": "29.1.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.1.1",
|
||||
"jest-environment-jsdom": "29.1.1",
|
||||
"jest-environment-jsdom-global": "3.1.2",
|
||||
"jest-environment-node": "29.0.3",
|
||||
"jest-environment-node": "29.1.1",
|
||||
"jest-junit": "12.3.0",
|
||||
"kleur": "3.0.3",
|
||||
"lint-staged": "11.2.6",
|
||||
@@ -100,7 +101,7 @@
|
||||
"selfsigned": "1.10.14",
|
||||
"supertest": "6.2.4",
|
||||
"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,22 @@
|
||||
# @verdaccio/api
|
||||
|
||||
## 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.32",
|
||||
"description": "loaders logic",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -39,13 +39,13 @@
|
||||
},
|
||||
"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",
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.28",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.49",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.49",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.17",
|
||||
"@verdaccio/middleware": "workspace:6.0.0-6-next.28",
|
||||
"@verdaccio/store": "workspace:6.0.0-6-next.29",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.17",
|
||||
"abortcontroller-polyfill": "1.7.3",
|
||||
"cookies": "0.8.0",
|
||||
"debug": "4.3.4",
|
||||
@@ -56,10 +56,10 @@
|
||||
"semver": "7.3.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "16.11.60",
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.37",
|
||||
"@types/node": "16.11.62",
|
||||
"@verdaccio/server": "workspace:6.0.0-6-next.38",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.17",
|
||||
"@verdaccio/test-helper": "workspace:2.0.0-6-next.5",
|
||||
"@verdaccio/test-helper": "workspace:2.0.0-6-next.6",
|
||||
"supertest": "6.2.4",
|
||||
"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) {
|
||||
|
||||
@@ -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,16 @@
|
||||
# @verdaccio/auth
|
||||
|
||||
## 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.28",
|
||||
"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.49",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.49",
|
||||
"@verdaccio/loaders": "workspace:6.0.0-6-next.18",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.17",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.17",
|
||||
"debug": "4.3.4",
|
||||
"express": "4.18.1",
|
||||
"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.19"
|
||||
},
|
||||
"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,14 @@
|
||||
# @verdaccio/cli
|
||||
|
||||
## 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.49",
|
||||
"author": {
|
||||
"name": "Juan Picado",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
@@ -44,10 +44,10 @@
|
||||
"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.49",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.49",
|
||||
"@verdaccio/logger": "workspace:6.0.0-6-next.17",
|
||||
"@verdaccio/node-api": "workspace:6.0.0-6-next.49",
|
||||
"clipanion": "3.1.0",
|
||||
"envinfo": "7.8.1",
|
||||
"kleur": "3.0.3",
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
{
|
||||
"path": "../config"
|
||||
},
|
||||
{
|
||||
"path": "../core/cli-ui"
|
||||
},
|
||||
{
|
||||
"path": "../core/core"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @verdaccio/config
|
||||
|
||||
## 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.49",
|
||||
"description": "logger",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -39,8 +39,8 @@
|
||||
"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.49",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.17",
|
||||
"debug": "4.3.4",
|
||||
"yaml": "2.1.1",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# @verdaccio/core
|
||||
|
||||
## 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.49",
|
||||
"description": "core utilities",
|
||||
"keywords": [
|
||||
"private",
|
||||
@@ -39,16 +39,19 @@
|
||||
"semver": "7.3.7",
|
||||
"ajv": "8.11.0",
|
||||
"process-warning": "1.0.0",
|
||||
"core-js": "3.25.2"
|
||||
"core-js": "3.25.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lodash": "4.17.21",
|
||||
"typedoc": "0.23.15",
|
||||
"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,14 @@
|
||||
# Change Log
|
||||
|
||||
## 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.18",
|
||||
"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.49",
|
||||
"@verdaccio/url": "workspace:11.0.0-6-next.15",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.17",
|
||||
"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.62",
|
||||
"typedoc": "0.23.15"
|
||||
},
|
||||
"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;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { Config, Logger } from '../configuration';
|
||||
|
||||
export class Plugin<T> {
|
||||
public constructor(config: T, options: PluginOptions) {}
|
||||
}
|
||||
|
||||
export interface IPlugin<T> {
|
||||
// TODO: not used on core yet
|
||||
version?: string;
|
||||
}
|
||||
|
||||
export interface PluginOptions {
|
||||
config: Config;
|
||||
logger: Logger;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import { Manifest } from '../manifest';
|
||||
import { IPlugin } from './commons';
|
||||
|
||||
export interface IPluginStorageFilter<T> extends IPlugin<T> {
|
||||
filterMetadata(packageInfo: Manifest): Promise<Manifest>;
|
||||
}
|
||||
@@ -1,31 +1 @@
|
||||
import { RemoteUser } from '../commons';
|
||||
import { AllowAccess } from '../configuration';
|
||||
import { PackageAccess } from '../manifest';
|
||||
import { AuthAccessCallback, AuthCallback } from './auth';
|
||||
import { IPlugin } from './commons';
|
||||
|
||||
export interface IPluginAuth<T> extends IPlugin<T> {
|
||||
/**
|
||||
* @param props user from Application component
|
||||
*/
|
||||
authenticate(user: string, password: string, cb: AuthCallback): void;
|
||||
adduser?(user: string, password: string, cb: AuthCallback): void;
|
||||
changePassword?(user: string, password: string, newPassword: string, cb: AuthCallback): void;
|
||||
allow_publish?(user: RemoteUser, pkg: T & PackageAccess, cb: AuthAccessCallback): void;
|
||||
allow_access?(user: RemoteUser, pkg: T & PackageAccess, cb: AuthAccessCallback): void;
|
||||
allow_unpublish?(user: RemoteUser, pkg: T & PackageAccess, cb: AuthAccessCallback): void;
|
||||
allow_publish?(user: RemoteUser, pkg: AllowAccess & PackageAccess, cb: AuthAccessCallback): void;
|
||||
allow_access?(user: RemoteUser, pkg: AllowAccess & PackageAccess, cb: AuthAccessCallback): void;
|
||||
allow_unpublish?(
|
||||
user: RemoteUser,
|
||||
pkg: AllowAccess & PackageAccess,
|
||||
cb: AuthAccessCallback
|
||||
): void;
|
||||
apiJWTmiddleware?(helpers: any): Function;
|
||||
}
|
||||
|
||||
export * from './auth';
|
||||
export * from './storage';
|
||||
export * from './middleware';
|
||||
export * from './commons';
|
||||
export * from './filter';
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Config } from '../configuration';
|
||||
import { IBasicAuth } from './auth';
|
||||
import { IPlugin } from './commons';
|
||||
|
||||
// TODO: convert to generic storage should come from implementation
|
||||
export interface IPluginMiddleware<T, K> extends IPlugin<T> {
|
||||
register_middlewares(app: any, auth: IBasicAuth<T>, storage: K): void;
|
||||
}
|
||||
@@ -1,17 +1,8 @@
|
||||
import { PassThrough, PipelinePromise, Readable, Stream, Writable } from 'stream';
|
||||
|
||||
import { Callback, CallbackAction, StringValue } from '../commons';
|
||||
import { Config, Logger } from '../configuration';
|
||||
import { Manifest, MergeTags, Token, Version } from '../manifest';
|
||||
import { IPlugin } from './commons';
|
||||
import { Callback, CallbackAction } from '../commons';
|
||||
import { Manifest, Token } from '../manifest';
|
||||
|
||||
export type StorageList = string[];
|
||||
|
||||
export interface LocalStorage {
|
||||
list: any;
|
||||
secret: string;
|
||||
}
|
||||
|
||||
export interface ILocalStorage {
|
||||
add(name: string): void;
|
||||
remove(name: string): void;
|
||||
@@ -53,43 +44,3 @@ export type StorageUpdateCallback = (data: Manifest, cb: CallbackAction) => void
|
||||
export type StorageWriteCallback = (name: string, json: Manifest, callback: Callback) => void;
|
||||
export type PackageTransformer = (pkg: Manifest) => Manifest;
|
||||
export type ReadPackageCallback = (err: any | null, data?: Manifest) => void;
|
||||
|
||||
export interface ILocalPackageManager {
|
||||
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 }): Promise<Readable>;
|
||||
createPackage(name: string, manifest: Manifest): Promise<void>;
|
||||
writeTarball(tarballName: string, { signal }): 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 type IPackageStorage = ILocalPackageManager | void;
|
||||
|
||||
export type IPluginStorage<T> = ILocalData<T>;
|
||||
export type IPackageStorageManager = ILocalPackageManager;
|
||||
|
||||
/**
|
||||
* @deprecated use @verdaccio/core pluginUtils instead
|
||||
*/
|
||||
interface ILocalData<T> extends IPlugin<T>, ITokenActions {
|
||||
logger: Logger;
|
||||
config: T;
|
||||
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;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user