mirror of
https://github.com/coder/code-server.git
synced 2026-04-14 06:24:32 -05:00
Compare commits
40 Commits
bpmct/link
...
v4.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
325181d414 | ||
|
|
7b2b0e0b21 | ||
|
|
ae83e049b9 | ||
|
|
b2ac660763 | ||
|
|
7d5bade76c | ||
|
|
b61a8addcf | ||
|
|
c4d87580ef | ||
|
|
78658f1cf4 | ||
|
|
b0181120d4 | ||
|
|
0e78a147b6 | ||
|
|
3f3a489f33 | ||
|
|
83269ba658 | ||
|
|
2c785779b5 | ||
|
|
506d3f43ed | ||
|
|
1465d8d510 | ||
|
|
b3cf4c32ff | ||
|
|
44d74c170f | ||
|
|
a989e0c387 | ||
|
|
769aceacc3 | ||
|
|
793e4d35ec | ||
|
|
f9402a6318 | ||
|
|
23734d356a | ||
|
|
d7c1894fb4 | ||
|
|
01a0e95174 | ||
|
|
94f378c196 | ||
|
|
e3e9f052c4 | ||
|
|
b26cce589f | ||
|
|
8fc4832722 | ||
|
|
36eae3b9f2 | ||
|
|
3ad618db97 | ||
|
|
c9c5c54cda | ||
|
|
102478bdea | ||
|
|
03c62242ee | ||
|
|
8135d2ecc3 | ||
|
|
177f0ed163 | ||
|
|
25b1340771 | ||
|
|
00224fa73a | ||
|
|
fd643dcbc3 | ||
|
|
79412eb137 | ||
|
|
10f57bac65 |
3
.github/semantic.yaml
vendored
3
.github/semantic.yaml
vendored
@@ -61,3 +61,6 @@ types:
|
||||
# implementations. For example, if a commit adds a fix + test, it's a fix
|
||||
# commit. If a commit is simply bumping coverage, it's a test commit.
|
||||
- test
|
||||
|
||||
# A new release.
|
||||
- release
|
||||
|
||||
77
.github/workflows/ci.yaml
vendored
77
.github/workflows/ci.yaml
vendored
@@ -8,6 +8,13 @@ on:
|
||||
branches:
|
||||
- main
|
||||
|
||||
# Cancel in-progress runs for pull requests when developers push
|
||||
# additional changes, and serialize builds in branches.
|
||||
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Note: if: success() is used in several jobs -
|
||||
# this ensures that it only executes if all previous jobs succeeded.
|
||||
|
||||
@@ -21,10 +28,10 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js v14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "14"
|
||||
|
||||
@@ -63,10 +70,10 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js v14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "14"
|
||||
|
||||
@@ -95,12 +102,12 @@ jobs:
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js v14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "14"
|
||||
|
||||
@@ -177,6 +184,36 @@ jobs:
|
||||
name: npm-package
|
||||
path: ./package.tar.gz
|
||||
|
||||
npm:
|
||||
# the npm-package gets uploaded as an artifact in Build
|
||||
# so we need that to complete before this runs
|
||||
needs: build
|
||||
# This environment "npm" requires someone from
|
||||
# coder/code-server-reviewers to approve the PR before this job runs.
|
||||
environment: npm
|
||||
# Only run if PR comes from base repo
|
||||
# Reason: forks cannot access secrets and this will always fail
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
id: download
|
||||
with:
|
||||
name: "npm-package"
|
||||
path: release-npm-package
|
||||
|
||||
- name: Run ./ci/steps/publish-npm.sh
|
||||
run: yarn publish:npm
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
# NOTE@jsjoeio
|
||||
# NPM_ENVIRONMENT intentionally not set here.
|
||||
# Instead, itis determined in publish-npm.sh script
|
||||
# using GITHUB environment variables
|
||||
|
||||
# TODO: cache building yarn --production
|
||||
# possibly 2m30s of savings(?)
|
||||
# this requires refactoring our release scripts
|
||||
@@ -188,10 +225,10 @@ jobs:
|
||||
container: "centos:7"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js v14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "14"
|
||||
|
||||
@@ -212,7 +249,7 @@ jobs:
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Download npm package
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: npm-package
|
||||
|
||||
@@ -277,10 +314,10 @@ jobs:
|
||||
NODE_VERSION: v14.17.4
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js v14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "14"
|
||||
|
||||
@@ -295,7 +332,7 @@ jobs:
|
||||
PACKAGE: ${{ format('g++-{0}', matrix.prefix) }}
|
||||
|
||||
- name: Download npm package
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: npm-package
|
||||
|
||||
@@ -326,10 +363,10 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js v14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "14"
|
||||
|
||||
@@ -339,7 +376,7 @@ jobs:
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Download npm package
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: npm-package
|
||||
|
||||
@@ -371,10 +408,10 @@ jobs:
|
||||
# since VS Code will load faster due to the bundling.
|
||||
CODE_SERVER_TEST_ENTRY: "./release-packages/code-server-linux-amd64"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js v14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "14"
|
||||
|
||||
@@ -388,7 +425,7 @@ jobs:
|
||||
yarn-build-
|
||||
|
||||
- name: Download release packages
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: release-packages
|
||||
path: ./release-packages
|
||||
@@ -425,10 +462,10 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Run Trivy vulnerability scanner in repo mode
|
||||
#Commit SHA for v0.0.17
|
||||
uses: aquasecurity/trivy-action@9c21d3ca2c14eb35419e2a8b66d1195946d579b8
|
||||
uses: aquasecurity/trivy-action@296212627a1e693efa09c00adc3e03b2ba8edf18
|
||||
with:
|
||||
scan-type: "fs"
|
||||
scan-ref: "."
|
||||
|
||||
9
.github/workflows/codeql-analysis.yml
vendored
9
.github/workflows/codeql-analysis.yml
vendored
@@ -10,6 +10,13 @@ on:
|
||||
# Runs every Monday morning PST
|
||||
- cron: "17 15 * * 1"
|
||||
|
||||
# Cancel in-progress runs for pull requests when developers push
|
||||
# additional changes, and serialize builds in branches.
|
||||
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
@@ -17,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
25
.github/workflows/docker.yaml
vendored
25
.github/workflows/docker.yaml
vendored
@@ -6,13 +6,22 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
release:
|
||||
types: [released]
|
||||
types:
|
||||
- released
|
||||
|
||||
# Cancel in-progress runs for pull requests when developers push
|
||||
# additional changes, and serialize builds in branches.
|
||||
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
docker-images:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
@@ -20,9 +29,13 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Run ./ci/steps/docker-buildx-push.sh
|
||||
run: ./ci/steps/docker-buildx-push.sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
14
.github/workflows/docs-preview.yaml
vendored
14
.github/workflows/docs-preview.yaml
vendored
@@ -17,17 +17,27 @@ permissions:
|
||||
security-events: none
|
||||
statuses: none
|
||||
|
||||
# Cancel in-progress runs for pull requests when developers push
|
||||
# additional changes, and serialize builds in branches.
|
||||
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
name: Docs preview
|
||||
runs-on: ubuntu-20.04
|
||||
environment: CI
|
||||
# Only run if PR comes from base repo
|
||||
# Reason: forks cannot access secrets and this will always fail
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.9.1
|
||||
|
||||
- name: Checkout m
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: coder/m
|
||||
ref: refs/heads/master
|
||||
@@ -36,7 +46,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 14
|
||||
|
||||
|
||||
13
.github/workflows/installer.yml
vendored
13
.github/workflows/installer.yml
vendored
@@ -12,13 +12,20 @@ on:
|
||||
paths:
|
||||
- "install.sh"
|
||||
|
||||
# Cancel in-progress runs for pull requests when developers push
|
||||
# additional changes, and serialize builds in branches.
|
||||
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
ubuntu:
|
||||
name: Test installer on Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install code-server
|
||||
run: ./install.sh
|
||||
@@ -32,7 +39,7 @@ jobs:
|
||||
container: "alpine:3.14"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install curl
|
||||
run: apk add curl
|
||||
@@ -50,7 +57,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install code-server
|
||||
run: ./install.sh
|
||||
|
||||
29
.github/workflows/npm-beta.yaml
vendored
29
.github/workflows/npm-beta.yaml
vendored
@@ -1,29 +0,0 @@
|
||||
name: Publish on npm and tag with "beta"
|
||||
|
||||
on:
|
||||
# Shows the manual trigger in GitHub UI
|
||||
# helpful as a back-up in case the GitHub Actions Workflow fails
|
||||
workflow_dispatch:
|
||||
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
# NOTE: this job requires curl, jq and yarn
|
||||
# All of them are included in ubuntu-latest.
|
||||
npm:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Publish npm package and tag "beta"
|
||||
run: yarn publish:npm
|
||||
env:
|
||||
ENVIRONMENT: "staging"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_TAG: "beta"
|
||||
# Since this only runs on a merge into main, we can't use github.event.number
|
||||
# so we instead use the word "beta" and the PR merge commit SHA
|
||||
PR_NUMBER_AND_COMMIT_SHA: beta-${{ github.sha }}
|
||||
20
.github/workflows/npm-brew.yaml
vendored
20
.github/workflows/npm-brew.yaml
vendored
@@ -8,21 +8,33 @@ on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
# Cancel in-progress runs for pull requests when developers push
|
||||
# additional changes, and serialize builds in branches.
|
||||
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
# NOTE: this job requires curl, jq and yarn
|
||||
# All of them are included in ubuntu-latest.
|
||||
npm:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
id: download
|
||||
with:
|
||||
name: "npm-package"
|
||||
path: release-npm-package
|
||||
|
||||
- name: Publish npm package and tag with "latest"
|
||||
run: yarn publish:npm
|
||||
env:
|
||||
ENVIRONMENT: "production"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_TAG: "latest"
|
||||
NPM_ENVIRONMENT: "production"
|
||||
|
||||
homebrew:
|
||||
# The newest version of code-server needs to be available on npm when this runs
|
||||
@@ -37,7 +49,7 @@ jobs:
|
||||
id: set-up-homebrew
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Configure git
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
|
||||
30
.github/workflows/npm-dev.yaml
vendored
30
.github/workflows/npm-dev.yaml
vendored
@@ -1,30 +0,0 @@
|
||||
name: Publish on npm and tag with PR number
|
||||
|
||||
on:
|
||||
# Shows the manual trigger in GitHub UI
|
||||
# helpful as a back-up in case the GitHub Actions Workflow fails
|
||||
workflow_dispatch:
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
# NOTE: this job requires curl, jq and yarn
|
||||
# All of them are included in ubuntu-latest.
|
||||
npm:
|
||||
# This environment "npm" requires someone from
|
||||
# coder/code-server-reviewers to approve the PR before this job runs.
|
||||
environment: npm
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Run ./ci/steps/publish-npm.sh
|
||||
run: yarn publish:npm
|
||||
env:
|
||||
ENVIRONMENT: "development"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_TAG: ${{ github.event.number }}
|
||||
PR_NUMBER_AND_COMMIT_SHA: ${{ github.event.number }}-${{ github.event.pull_request.head.sha }}
|
||||
21
.github/workflows/scripts.yml
vendored
21
.github/workflows/scripts.yml
vendored
@@ -14,6 +14,25 @@ on:
|
||||
- "**.sh"
|
||||
- "**.bats"
|
||||
|
||||
permissions:
|
||||
actions: none
|
||||
checks: none
|
||||
contents: read
|
||||
deployments: none
|
||||
issues: none
|
||||
packages: none
|
||||
pull-requests: none
|
||||
repository-projects: none
|
||||
security-events: none
|
||||
statuses: none
|
||||
|
||||
# Cancel in-progress runs for pull requests when developers push
|
||||
# additional changes, and serialize builds in branches.
|
||||
# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-concurrency-to-cancel-any-in-progress-job-or-run
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Run script unit tests
|
||||
@@ -22,7 +41,7 @@ jobs:
|
||||
container: "alpine:3.14"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install test utilities
|
||||
run: apk add bats checkbashisms
|
||||
|
||||
61
CHANGELOG.md
61
CHANGELOG.md
@@ -22,15 +22,54 @@ VS Code v99.99.999
|
||||
|
||||
## [Unreleased](https://github.com/coder/code-server/releases)
|
||||
|
||||
VS Code v0.00.0
|
||||
Code v0.00.0
|
||||
|
||||
### Changed
|
||||
|
||||
- Add here
|
||||
|
||||
## [4.1.0](https://github.com/coder/code-server/releases/tag/v4.1.0) - 2022-03-03
|
||||
|
||||
Code v1.63.0
|
||||
|
||||
### Added
|
||||
|
||||
- Support for injecting GitHub token into Code so extensions can make use of it.
|
||||
This can be done with the `GITHUB_TOKEN` environment variable or `github-auth`
|
||||
in the config file.
|
||||
- New flag `--socket-mode` allows setting the mode (file permissions) of the
|
||||
socket created when using `--socket`.
|
||||
- The version of Code bundled with code-server now appears when using the
|
||||
`--version` flag. For example: `4.0.2 5cdfe74686aa73e023f8354a9a6014eb30caa7dd with Code 1.63.0`.
|
||||
If you have been parsing this flag for the version you might want to use
|
||||
`--version --json` instead as doing that will be more stable.
|
||||
|
||||
### Changed
|
||||
|
||||
- The workspace or folder passed on the CLI will now use the same redirect
|
||||
method that the last opened workspace or folder uses. This means if you use
|
||||
something like `code-server /path/to/dir` you will now get a query parameter
|
||||
added (like so: `my-domain.tld?folder=/path/to/dir`), making it easier to edit
|
||||
by hand and making it consistent with the last opened and menu open behaviors.
|
||||
- The folder/workspace query parameter no longer has encoded slashes, making
|
||||
them more readable and editable by hand. This was only affecting the last
|
||||
opened behavior, not opens from the menu.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix web sockets not connecting when using `--cert`.
|
||||
- Prevent workspace state collisions when opening a workspace that shares the
|
||||
same file path with another workspace on a different machine that shares the
|
||||
same domain. This was causing files opened in one workspace to be "re-"opened
|
||||
in the other workspace when the other workspace is opened.
|
||||
- Pin the Express version which should make installing from npm work again.
|
||||
- Propagate signals to code-server in the Docker image which means it should
|
||||
stop more quickly and gracefully.
|
||||
- Fix missing argon binaries in the standalone releases on arm machines.
|
||||
|
||||
## [4.0.2](https://github.com/coder/code-server/releases/tag/v4.0.2) - 2022-01-27
|
||||
|
||||
VS Code v1.63.0
|
||||
Code v1.63.0
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -41,7 +80,7 @@ VS Code v1.63.0
|
||||
|
||||
## [4.0.1](https://github.com/coder/code-server/releases/tag/v4.0.1) - 2022-01-04
|
||||
|
||||
VS Code v1.63.0
|
||||
Code v1.63.0
|
||||
|
||||
code-server has been rebased on upstream's newly open-sourced server
|
||||
implementation (#4414).
|
||||
@@ -57,7 +96,7 @@ implementation (#4414).
|
||||
settings file (we rely on the already-existing query object instead).
|
||||
- The marketplace override environment variables `SERVICE_URL` and `ITEM_URL`
|
||||
have been replaced with a single `EXTENSIONS_GALLERY` variable that
|
||||
corresponds to `extensionsGallery` in VS Code's `product.json`.
|
||||
corresponds to `extensionsGallery` in Code's `product.json`.
|
||||
|
||||
### Added
|
||||
|
||||
@@ -79,11 +118,11 @@ implementation (#4414).
|
||||
|
||||
## [3.12.0](https://github.com/coder/code-server/releases/tag/v3.12.0) - 2021-09-15
|
||||
|
||||
VS Code v1.60.0
|
||||
Code v1.60.0
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade VS Code to 1.60.0.
|
||||
- Upgrade Code to 1.60.0.
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -99,7 +138,7 @@ Undocumented (see releases page).
|
||||
|
||||
## [3.10.2](https://github.com/coder/code-server/releases/tag/v3.10.2) - 2021-05-21
|
||||
|
||||
VS Code v1.56.1
|
||||
Code v1.56.1
|
||||
|
||||
### Added
|
||||
|
||||
@@ -115,7 +154,7 @@ VS Code v1.56.1
|
||||
|
||||
## [3.10.1](https://github.com/coder/code-server/releases/tag/v3.10.1) - 2021-05-17
|
||||
|
||||
VS Code v1.56.1
|
||||
Code v1.56.1
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -129,13 +168,13 @@ VS Code v1.56.1
|
||||
|
||||
## [3.10.0](https://github.com/coder/code-server/releases/tag/v3.10.0) - 2021-05-10
|
||||
|
||||
VS Code v1.56.0
|
||||
Code v1.56.0
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to VS Code 1.56.0 (#3269).
|
||||
- Update to Code 1.56.0 (#3269).
|
||||
- Minor connections refactor (#3178). Improves connection stability.
|
||||
- Use ptyHostService (#3308). This brings us closer to upstream VS Code.
|
||||
- Use ptyHostService (#3308). This brings us closer to upstream Code.
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# This is due to an upstream issue with RHEL7/CentOS 7 comptability with node-argon2
|
||||
# See: https://github.com/cdr/code-server/pull/3422#pullrequestreview-677765057
|
||||
export npm_config_build_from_source=true
|
||||
|
||||
main() {
|
||||
cd "$(dirname "${0}")/../.."
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ detect_arch() {
|
||||
}
|
||||
|
||||
ARCH="${NPM_CONFIG_ARCH:-$(detect_arch)}"
|
||||
# This is due to an upstream issue with RHEL7/CentOS 7 comptability with node-argon2
|
||||
# See: https://github.com/cdr/code-server/pull/3422#pullrequestreview-677765057
|
||||
export npm_config_build_from_source=true
|
||||
|
||||
main() {
|
||||
# Grabs the major version of node from $npm_config_user_agent which looks like
|
||||
|
||||
@@ -15,9 +15,9 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 2.0.1
|
||||
version: 2.2.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
appVersion: 4.0.2
|
||||
appVersion: 4.1.0
|
||||
|
||||
@@ -21,6 +21,7 @@ spec:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }}
|
||||
{{- if .Values.hostnameOverride }}
|
||||
hostname: {{ .Values.hostnameOverride }}
|
||||
{{- end }}
|
||||
|
||||
@@ -18,6 +18,9 @@ metadata:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.ingressClassName }}
|
||||
ingressClassName: {{ .Values.ingress.ingressClassName }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
|
||||
@@ -6,10 +6,15 @@ replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: codercom/code-server
|
||||
tag: '4.0.2'
|
||||
tag: '4.1.0'
|
||||
pullPolicy: Always
|
||||
|
||||
# Specifies one or more secrets to be used when pulling images from a
|
||||
# private container repository
|
||||
# https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry
|
||||
imagePullSecrets: []
|
||||
# - name: registry-creds
|
||||
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
hostnameOverride: ""
|
||||
@@ -35,13 +40,12 @@ service:
|
||||
ingress:
|
||||
enabled: false
|
||||
#annotations:
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
#hosts:
|
||||
# - host: code-server.example.loc
|
||||
# paths:
|
||||
# - /
|
||||
|
||||
ingressClassName: ""
|
||||
#tls:
|
||||
# - secretName: code-server
|
||||
# hosts:
|
||||
|
||||
@@ -18,4 +18,4 @@ if [ "${DOCKER_USER-}" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
dumb-init /usr/bin/code-server "$@"
|
||||
exec dumb-init /usr/bin/code-server "$@"
|
||||
|
||||
@@ -21,12 +21,12 @@ main() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# NOTE: we need to make sure cdrci/homebrew-core
|
||||
# NOTE: we need to make sure coderci/homebrew-core
|
||||
# is up-to-date
|
||||
# otherwise, brew bump-formula-pr will use an
|
||||
# outdated base
|
||||
echo "Cloning cdrci/homebrew-core"
|
||||
git clone https://github.com/cdrci/homebrew-core.git
|
||||
echo "Cloning coderci/homebrew-core"
|
||||
git clone https://github.com/coderci/homebrew-core.git
|
||||
|
||||
# Make sure the git clone step is successful
|
||||
if directory_exists "homebrew-core"; then
|
||||
@@ -57,7 +57,7 @@ main() {
|
||||
echo "Merging in latest Homebrew/homebrew-core changes"
|
||||
git merge upstream/master
|
||||
|
||||
echo "Pushing changes to cdrci/homebrew-core fork on GitHub"
|
||||
echo "Pushing changes to coderci/homebrew-core fork on GitHub"
|
||||
|
||||
# GIT_ASKPASS lets us use the password when pushing without revealing it in the process list
|
||||
# See: https://serverfault.com/a/912788
|
||||
@@ -86,7 +86,7 @@ main() {
|
||||
# Export the variables so git sees them
|
||||
export HOMEBREW_GITHUB_API_TOKEN="$HOMEBREW_GITHUB_API_TOKEN"
|
||||
export GIT_ASKPASS="$PATH_TO_ASKPASS"
|
||||
git push https://cdr-oss@github.com/cdr-oss/homebrew-core.git --all
|
||||
git push https://coder-oss@github.com/coder-oss/homebrew-core.git --all
|
||||
|
||||
# Find the docs for bump-formula-pr here
|
||||
# https://github.com/Homebrew/brew/blob/master/Library/Homebrew/dev-cmd/bump-formula-pr.rb#L18
|
||||
|
||||
@@ -1,36 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# See if this version already exists on Docker Hub.
|
||||
function version_exists() {
|
||||
local output
|
||||
output=$(curl --silent "https://index.docker.io/v1/repositories/codercom/code-server/tags/$VERSION")
|
||||
if [[ $output == "Tag not found" ]]; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
# ci/lib.sh sets VERSION and provides download_artifact here
|
||||
source ./ci/lib.sh
|
||||
|
||||
if version_exists; then
|
||||
echo "$VERSION is already pushed"
|
||||
return
|
||||
fi
|
||||
|
||||
# Download the release-packages artifact
|
||||
download_artifact release-packages ./release-packages
|
||||
|
||||
# Login to Docker
|
||||
if [[ ${CI-} ]]; then
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
fi
|
||||
|
||||
docker buildx bake -f ci/release-image/docker-bake.hcl --push
|
||||
}
|
||||
|
||||
|
||||
@@ -21,20 +21,6 @@ main() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## Environment
|
||||
# This string is used to determine how we should tag the npm release.
|
||||
# Environment can be one of three choices:
|
||||
# "development" - this means we tag with the PR number, allowing
|
||||
# a developer to install this version with `yarn add code-server@<pr-number>`
|
||||
# "staging" - this means we tag with `beta`, allowing
|
||||
# a developer to install this version with `yarn add code-server@beta`
|
||||
# "production" - this means we tag with `latest` (default), allowing
|
||||
# a developer to install this version with `yarn add code-server@latest`
|
||||
if ! is_env_var_set "ENVIRONMENT"; then
|
||||
echo "ENVIRONMENT is not set. Cannot determine npm tag without ENVIRONMENT."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## Publishing Information
|
||||
# All the variables below are used to determine how we should publish
|
||||
# the npm package. We also use this information for bumping the version.
|
||||
@@ -47,22 +33,52 @@ main() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We need TAG to know what to publish under on npm
|
||||
# Options are "latest", "beta", or "<pr number >"
|
||||
# See Environment comments above to know when each is used.
|
||||
if ! is_env_var_set "NPM_TAG"; then
|
||||
echo "NPM_TAG is not set. This is needed for tagging the npm release."
|
||||
# We use this to grab the PR_NUMBER
|
||||
if ! is_env_var_set "GITHUB_REF"; then
|
||||
echo "GITHUB_REF is not set. Are you running this locally? We rely on values provided by GitHub."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "using tag: $NPM_TAG"
|
||||
# We use this when setting NPM_VERSION
|
||||
if ! is_env_var_set "GITHUB_SHA"; then
|
||||
echo "GITHUB_SHA is not set. Are you running this locally? We rely on values provided by GitHub."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We use this to determine the NPM_ENVIRONMENT
|
||||
if ! is_env_var_set "GITHUB_EVENT_NAME"; then
|
||||
echo "GITHUB_EVENT_NAME is not set. Are you running this locally? We rely on values provided by GitHub."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# This allows us to publish to npm in CI workflows
|
||||
if [[ ${CI-} ]]; then
|
||||
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
|
||||
fi
|
||||
|
||||
download_artifact npm-package ./release-npm-package
|
||||
## Environment
|
||||
# This string is used to determine how we should tag the npm release.
|
||||
# Environment can be one of three choices:
|
||||
# "development" - this means we tag with the PR number, allowing
|
||||
# a developer to install this version with `yarn add code-server@<pr-number>`
|
||||
# "staging" - this means we tag with `beta`, allowing
|
||||
# a developer to install this version with `yarn add code-server@beta`
|
||||
# "production" - this means we tag with `latest` (default), allowing
|
||||
# a developer to install this version with `yarn add code-server@latest`
|
||||
if ! is_env_var_set "NPM_ENVIRONMENT"; then
|
||||
echo "NPM_ENVIRONMENT is not set. Determining in script based on GITHUB environment variables."
|
||||
|
||||
if [[ "$GITHUB_EVENT_NAME" == 'push' && "$GITHUB_REF" == 'refs/heads/main' ]]; then
|
||||
NPM_ENVIRONMENT="staging"
|
||||
else
|
||||
NPM_ENVIRONMENT="development"
|
||||
fi
|
||||
|
||||
echo "Using npm environment: $NPM_ENVIRONMENT"
|
||||
fi
|
||||
|
||||
# NOTE@jsjoeio - this script assumes we have the artifact downloaded on disk
|
||||
# That happens in CI as a step before we run this.
|
||||
# https://github.com/actions/upload-artifact/issues/38
|
||||
tar -xzf release-npm-package/package.tar.gz
|
||||
|
||||
@@ -74,22 +90,40 @@ main() {
|
||||
# We only need to run npm version for "development" and "staging".
|
||||
# This is because our release:prep script automatically bumps the version
|
||||
# in the package.json and we commit it as part of the release PR.
|
||||
if [[ "$ENVIRONMENT" == "production" ]]; then
|
||||
if [[ "$NPM_ENVIRONMENT" == "production" ]]; then
|
||||
NPM_VERSION="$VERSION"
|
||||
# This means the npm version will be published as "stable"
|
||||
# and installed when a user runs `yarn install code-server`
|
||||
NPM_TAG="latest"
|
||||
else
|
||||
COMMIT_SHA="$GITHUB_SHA"
|
||||
echo "Not a production environment"
|
||||
echo "Found environment: $ENVIRONMENT"
|
||||
echo "Found environment: $NPM_ENVIRONMENT"
|
||||
echo "Manually bumping npm version..."
|
||||
|
||||
if ! is_env_var_set "PR_NUMBER_AND_COMMIT_SHA"; then
|
||||
echo "PR_NUMBER_AND_COMMIT_SHA is not set. This is needed for setting the npm version in non-production environments."
|
||||
exit 1
|
||||
if [[ "$NPM_ENVIRONMENT" == "staging" ]]; then
|
||||
NPM_VERSION="$VERSION-beta-$COMMIT_SHA"
|
||||
# This means the npm version will be tagged with "beta"
|
||||
# and installed when a user runs `yarn install code-server@beta`
|
||||
NPM_TAG="beta"
|
||||
fi
|
||||
|
||||
if [[ "$NPM_ENVIRONMENT" == "development" ]]; then
|
||||
# Source: https://github.com/actions/checkout/issues/58#issuecomment-614041550
|
||||
PR_NUMBER=$(echo "$GITHUB_REF" | awk 'BEGIN { FS = "/" } ; { print $3 }')
|
||||
NPM_VERSION="$VERSION-$PR_NUMBER-$COMMIT_SHA"
|
||||
# This means the npm version will be tagged with "<pr number>"
|
||||
# and installed when a user runs `yarn install code-server@<pr number>`
|
||||
NPM_TAG="$PR_NUMBER"
|
||||
fi
|
||||
|
||||
echo "using tag: $NPM_TAG"
|
||||
|
||||
# We modify the version in the package.json
|
||||
# to be the current version + the PR number + commit SHA
|
||||
# or we use current version + beta + commit SHA
|
||||
# Example: "version": "4.0.1-4769-ad7b23cfe6ffd72914e34781ef7721b129a23040"
|
||||
NPM_VERSION="$VERSION-$PR_NUMBER_AND_COMMIT_SHA"
|
||||
# Example: "version": "4.0.1-beta-ad7b23cfe6ffd72914e34781ef7721b129a23040"
|
||||
pushd release
|
||||
# NOTE:@jsjoeio
|
||||
# I originally tried to use `yarn version` but ran into issues and abandoned it.
|
||||
|
||||
@@ -34,7 +34,6 @@ as well as share our workflow for maintaining the project.
|
||||
Current maintainers:
|
||||
|
||||
- @code-asher
|
||||
- @TeffenEllis
|
||||
- @jsjoeio
|
||||
|
||||
Occasionally, other Coder employees may step in time to time to assist with code-server.
|
||||
@@ -220,12 +219,13 @@ This is currently automated with the release process.
|
||||
The VS Code portion of code-server lives under [`coder/vscode`](https://github.com/coder/vscode). To update VS Code for code-server, follow these steps:
|
||||
|
||||
1. `git checkout -b vscode-update` - Create a new branch locally based off `main`
|
||||
2. `git fetch upstream` - Fetch upstream (VS Code)'s latest `main` branch
|
||||
3. `git merge upstream/main` - Merge it locally
|
||||
1. If there are merge conflicts, fix them locally
|
||||
2. `git fetch upstream` - Fetch upstream (VS Code)'s latest branches
|
||||
3. `git merge upstream/release/1.64` - Merge it locally
|
||||
1. replace `1.64` with the version you're upgrading to
|
||||
1. If there are merge conflicts, commit first, then fix them locally.
|
||||
4. Open a PR merging your branch (`vscode-update`) into `main` and add the code-server review team
|
||||
|
||||
Ideally, our fork stays as close to upstream as possible. See the differences between our fork and upstream [here](https://github.com/microsoft/vscode/compare/main...cdr:main).
|
||||
Ideally, our fork stays as close to upstream as possible. See the differences between our fork and upstream [here](https://github.com/microsoft/vscode/compare/main...coder:main).
|
||||
|
||||
## Testing
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# code-server
|
||||
|
||||
[](https://github.com/coder/code-server/discussions) [](https://cdr.co/join-community) [](https://twitter.com/coderhq) [](https://codecov.io/gh/coder/code-server) [](https://github.com/coder/code-server/tree/v4.0.2/docs)
|
||||
[](https://github.com/coder/code-server/discussions) [](https://coder.com/community) [](https://twitter.com/coderhq) [](https://codecov.io/gh/coder/code-server) [](https://github.com/coder/code-server/tree/v4.1.0/docs)
|
||||
|
||||
Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and
|
||||
access it in the browser.
|
||||
|
||||
@@ -26,8 +26,8 @@ We use the following tools to help us stay on top of vulnerability mitigation.
|
||||
|
||||
Coder sponsors the development and maintenance of the code-server project. We will fix security issues within 90 days of receiving a report and publish the fix in a subsequent release. The code-server project does not provide backports or patch releases for security issues at this time.
|
||||
|
||||
| Version | Supported |
|
||||
| ----------------------------------------------------- | ------------------ |
|
||||
| Version | Supported |
|
||||
| ------------------------------------------------------- | ------------------ |
|
||||
| [Latest](https://github.com/coder/code-server/releases) | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
@@ -60,6 +60,6 @@ As `code-server` is based on VS Code, you can follow the steps described on Duck
|
||||
code-server --enable-proposed-api genuitecllc.codetogether
|
||||
```
|
||||
|
||||
Another option would be to add a value in code-server's [config file](https://coder.com/docs/code-server/v4.0.2/FAQ#how-does-the-config-file-work).
|
||||
Another option would be to add a value in code-server's [config file](https://coder.com/docs/code-server/v4.1.0/FAQ#how-does-the-config-file-work).
|
||||
|
||||
3. Refresh code-server and navigate to the CodeTogether icon in the sidebar to host or join a coding session.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# code-server Helm Chart
|
||||
|
||||
[](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) [](https://img.shields.io/badge/Type-application-informational?style=flat-square) [](https://img.shields.io/badge/AppVersion-4.0.2-informational?style=flat-square)
|
||||
[](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) [](https://img.shields.io/badge/Type-application-informational?style=flat-square) [](https://img.shields.io/badge/AppVersion-4.1.0-informational?style=flat-square)
|
||||
|
||||
[code-server](https://github.com/coder/code-server) code-server is VS Code running
|
||||
on a remote server, accessible through the browser.
|
||||
@@ -73,7 +73,7 @@ and their default values.
|
||||
| hostnameOverride | string | `""` |
|
||||
| image.pullPolicy | string | `"Always"` |
|
||||
| image.repository | string | `"codercom/code-server"` |
|
||||
| image.tag | string | `"4.0.2"` |
|
||||
| image.tag | string | `"4.1.0"` |
|
||||
| imagePullSecrets | list | `[]` |
|
||||
| ingress.enabled | bool | `false` |
|
||||
| nameOverride | string | `""` |
|
||||
|
||||
@@ -7,5 +7,5 @@ for accessing your IDE out of the box.
|
||||
|
||||
```console
|
||||
$ code-server --link
|
||||
Proxying code-server, you can access your IDE at https://example.cdr.co
|
||||
Proxying code-server, you can access your IDE at https://example.coder.co
|
||||
```
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"versions": ["v4.0.2"],
|
||||
"versions": ["v4.1.0"],
|
||||
"routes": [
|
||||
{
|
||||
"title": "Home",
|
||||
|
||||
@@ -33,7 +33,7 @@ new Compute Engine VM instance:
|
||||
4. Choose the **region** that's closest to you based on [GCP
|
||||
ping](https://gcping.com/).
|
||||
5. Choose a **zone** (any option is fine).
|
||||
6. We recommend choose an **E2 series instance** from the [general-purpose
|
||||
6. We recommend choosing an **E2 series instance** from the [general-purpose
|
||||
family](https://cloud.google.com/compute/docs/machine-types#general_purpose).
|
||||
7. Change the instance type to **custom** and set at least **2 cores** and **2
|
||||
GB of RAM**. You can add more resources if desired, though you can also edit
|
||||
|
||||
12
package.json
12
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-server",
|
||||
"license": "MIT",
|
||||
"version": "4.0.2",
|
||||
"version": "4.1.0",
|
||||
"description": "Run VS Code on a remote server.",
|
||||
"homepage": "https://github.com/coder/code-server",
|
||||
"bugs": {
|
||||
@@ -17,7 +17,7 @@
|
||||
"release:github-draft": "./ci/build/release-github-draft.sh",
|
||||
"release:github-assets": "./ci/build/release-github-assets.sh",
|
||||
"release:prep": "./ci/build/release-prep.sh",
|
||||
"test:e2e": "./ci/dev/test-e2e.sh",
|
||||
"test:e2e": "VSCODE_IPC_HOOK_CLI= ./ci/dev/test-e2e.sh",
|
||||
"test:standalone-release": "./ci/build/test-standalone-release.sh",
|
||||
"test:unit": "./ci/dev/test-unit.sh --forceExit --detectOpenHandles",
|
||||
"test:scripts": "./ci/dev/test-scripts.sh",
|
||||
@@ -78,18 +78,18 @@
|
||||
"vfile-message": "^2.0.2",
|
||||
"tar": "^6.1.9",
|
||||
"path-parse": "^1.0.7",
|
||||
"vm2": "^3.9.4",
|
||||
"follow-redirects": "^1.14.7",
|
||||
"vm2": "^3.9.6",
|
||||
"follow-redirects": "^1.14.8",
|
||||
"node-fetch": "^2.6.7",
|
||||
"nanoid": "^3.1.31"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coder/logger": "1.1.16",
|
||||
"@node-rs/argon2": "^1.0.5",
|
||||
"argon2": "^0.28.0",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"env-paths": "^2.2.0",
|
||||
"express": "^5.0.0-alpha.8",
|
||||
"express": "5.0.0-alpha.8",
|
||||
"http-proxy": "^1.18.0",
|
||||
"httpolyglot": "^0.1.2",
|
||||
"js-yaml": "^4.0.0",
|
||||
|
||||
@@ -11,7 +11,7 @@ import { disposer } from "./http"
|
||||
import { isNodeJSErrnoException } from "./util"
|
||||
import { handleUpgrade } from "./wsRouter"
|
||||
|
||||
type ListenOptions = Pick<DefaultedArgs, "socket" | "port" | "host">
|
||||
type ListenOptions = Pick<DefaultedArgs, "socket-mode" | "socket" | "port" | "host">
|
||||
|
||||
export interface App extends Disposable {
|
||||
/** Handles regular HTTP requests. */
|
||||
@@ -22,7 +22,7 @@ export interface App extends Disposable {
|
||||
server: http.Server
|
||||
}
|
||||
|
||||
const listen = (server: http.Server, { host, port, socket }: ListenOptions) => {
|
||||
const listen = (server: http.Server, { host, port, socket, "socket-mode": mode }: ListenOptions) => {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
server.on("error", reject)
|
||||
|
||||
@@ -31,7 +31,16 @@ const listen = (server: http.Server, { host, port, socket }: ListenOptions) => {
|
||||
server.off("error", reject)
|
||||
server.on("error", (err) => util.logError(logger, "http server error", err))
|
||||
|
||||
resolve()
|
||||
if (socket && mode) {
|
||||
fs.chmod(socket, mode)
|
||||
.then(resolve)
|
||||
.catch((err) => {
|
||||
util.logError(logger, "socket chmod", err)
|
||||
reject(err)
|
||||
})
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
|
||||
if (socket) {
|
||||
|
||||
@@ -3,15 +3,7 @@ import { promises as fs } from "fs"
|
||||
import yaml from "js-yaml"
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
import {
|
||||
canConnect,
|
||||
generateCertificate,
|
||||
generatePassword,
|
||||
humanPath,
|
||||
paths,
|
||||
isNodeJSErrnoException,
|
||||
isFile,
|
||||
} from "./util"
|
||||
import { canConnect, generateCertificate, generatePassword, humanPath, paths, isNodeJSErrnoException } from "./util"
|
||||
|
||||
const DEFAULT_SOCKET_PATH = path.join(os.tmpdir(), "vscode-ipc")
|
||||
|
||||
@@ -64,6 +56,7 @@ export interface UserProvidedArgs {
|
||||
open?: boolean
|
||||
"bind-addr"?: string
|
||||
socket?: string
|
||||
"socket-mode"?: string
|
||||
version?: boolean
|
||||
"proxy-domain"?: string[]
|
||||
"reuse-window"?: boolean
|
||||
@@ -87,6 +80,7 @@ export interface UserProvidedArgs {
|
||||
"locate-extension"?: string[]
|
||||
"show-versions"?: boolean
|
||||
category?: string
|
||||
"github-auth"?: string
|
||||
}
|
||||
|
||||
interface Option<T> {
|
||||
@@ -182,6 +176,7 @@ const options: Options<Required<UserProvidedArgs>> = {
|
||||
port: { type: "number", description: "" },
|
||||
|
||||
socket: { type: "string", path: true, description: "Path to a socket (bind-addr will be ignored)." },
|
||||
"socket-mode": { type: "string", description: "File mode of the socket." },
|
||||
version: { type: "boolean", short: "v", description: "Display version information." },
|
||||
_: { type: "string[]" },
|
||||
|
||||
@@ -205,6 +200,10 @@ const options: Options<Required<UserProvidedArgs>> = {
|
||||
},
|
||||
"uninstall-extension": { type: "string[]", description: "Uninstall a VS Code extension by id." },
|
||||
"show-versions": { type: "boolean", description: "Show VS Code extension versions." },
|
||||
"github-auth": {
|
||||
type: "string",
|
||||
description: "GitHub authentication token (can only be passed in via $GITHUB_TOKEN or the config file).",
|
||||
},
|
||||
"proxy-domain": { type: "string[]", description: "Domain used for proxying ports." },
|
||||
"ignore-last-opened": {
|
||||
type: "boolean",
|
||||
@@ -229,7 +228,7 @@ const options: Options<Required<UserProvidedArgs>> = {
|
||||
type: OptionalString,
|
||||
description: `
|
||||
Securely bind code-server via our cloud service with the passed name. You'll get a URL like
|
||||
https://hostname-username.cdr.co at which you can easily access your code-server instance.
|
||||
https://hostname-username.coder.co at which you can easily access your code-server instance.
|
||||
Authorization is done via GitHub.
|
||||
`,
|
||||
deprecated: true,
|
||||
@@ -336,6 +335,10 @@ export const parse = (
|
||||
throw new Error("--hashed-password can only be set in the config file or passed in via $HASHED_PASSWORD")
|
||||
}
|
||||
|
||||
if (key === "github-auth" && !opts?.configFile) {
|
||||
throw new Error("--github-auth can only be set in the config file or passed in via $GITHUB_TOKEN")
|
||||
}
|
||||
|
||||
const option = options[key]
|
||||
if (option.type === "boolean") {
|
||||
;(args[key] as boolean) = true
|
||||
@@ -409,7 +412,12 @@ export const parse = (
|
||||
|
||||
logger.debug(() => [
|
||||
`parsed ${opts?.configFile ? "config" : "command line"}`,
|
||||
field("args", { ...args, password: undefined }),
|
||||
field("args", {
|
||||
...args,
|
||||
password: args.password ? "<redacted>" : undefined,
|
||||
"hashed-password": args["hashed-password"] ? "<redacted>" : undefined,
|
||||
"github-auth": args["github-auth"] ? "<redacted>" : undefined,
|
||||
}),
|
||||
])
|
||||
|
||||
return args
|
||||
@@ -434,7 +442,7 @@ export interface DefaultedArgs extends ConfigArgs {
|
||||
"extensions-dir": string
|
||||
"user-data-dir": string
|
||||
/* Positional arguments. */
|
||||
_: []
|
||||
_: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -507,6 +515,7 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
|
||||
args.host = "localhost"
|
||||
args.port = 0
|
||||
args.socket = undefined
|
||||
args["socket-mode"] = undefined
|
||||
args.cert = undefined
|
||||
args.auth = AuthType.None
|
||||
}
|
||||
@@ -530,9 +539,14 @@ export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: Config
|
||||
usingEnvPassword = false
|
||||
}
|
||||
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
args["github-auth"] = process.env.GITHUB_TOKEN
|
||||
}
|
||||
|
||||
// Ensure they're not readable by child processes.
|
||||
delete process.env.PASSWORD
|
||||
delete process.env.HASHED_PASSWORD
|
||||
delete process.env.GITHUB_TOKEN
|
||||
|
||||
// Filter duplicate proxy domains and remove any leading `*.`.
|
||||
const proxyDomains = new Set((args["proxy-domain"] || []).map((d) => d.replace(/^\*\./, "")))
|
||||
@@ -751,25 +765,9 @@ export const shouldOpenInExistingInstance = async (args: UserProvidedArgs): Prom
|
||||
* Convert our arguments to VS Code server arguments.
|
||||
*/
|
||||
export const toVsCodeArgs = async (args: DefaultedArgs): Promise<CodeServerLib.ServerParsedArgs> => {
|
||||
let workspace = ""
|
||||
let folder = ""
|
||||
if (args._.length) {
|
||||
const lastEntry = path.resolve(args._[args._.length - 1])
|
||||
const entryIsFile = await isFile(lastEntry)
|
||||
if (entryIsFile && path.extname(lastEntry) === ".code-workspace") {
|
||||
workspace = lastEntry
|
||||
} else if (!entryIsFile) {
|
||||
folder = lastEntry
|
||||
}
|
||||
// Otherwise it is a regular file. Spawning VS Code with a file is not yet
|
||||
// supported but it can be done separately after code-server spawns.
|
||||
}
|
||||
|
||||
return {
|
||||
"connection-token": "0000",
|
||||
...args,
|
||||
workspace,
|
||||
folder,
|
||||
"accept-server-license-terms": true,
|
||||
/** Type casting. */
|
||||
help: !!args.help,
|
||||
|
||||
@@ -17,13 +17,35 @@ export function getPackageJson(relativePath: string): JSONSchemaForNPMPackageJso
|
||||
}
|
||||
|
||||
const pkg = getPackageJson("../../package.json")
|
||||
const codePkg = getPackageJson("../../vendor/modules/code-oss-dev/package.json")
|
||||
|
||||
export const pkgName = pkg.name || "code-server"
|
||||
export const version = pkg.version || "development"
|
||||
export const commit = pkg.commit || "development"
|
||||
export const rootPath = path.resolve(__dirname, "../..")
|
||||
export const vsRootPath = path.join(rootPath, "vendor/modules/code-oss-dev")
|
||||
export const codeVersion = codePkg.version || "development"
|
||||
export const tmpdir = path.join(os.tmpdir(), "code-server")
|
||||
export const isDevMode = commit === "development"
|
||||
export const httpProxyUri =
|
||||
process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy
|
||||
|
||||
/**
|
||||
* getVersionString returns a human-readable version string suitable
|
||||
* for outputting to the console.
|
||||
*/
|
||||
export function getVersionString(): string {
|
||||
return [version, commit, "with Code", codeVersion].join(" ")
|
||||
}
|
||||
|
||||
/**
|
||||
* getVersionJsonString returns a machine-readable version string
|
||||
* suitable for outputting to the console.
|
||||
*/
|
||||
export function getVersionJsonString(): string {
|
||||
return JSON.stringify({
|
||||
codeServer: version,
|
||||
commit,
|
||||
vscode: codeVersion,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { logger } from "@coder/logger"
|
||||
import { optionDescriptions, parse, readConfigFile, setDefaults, shouldOpenInExistingInstance } from "./cli"
|
||||
import { commit, version } from "./constants"
|
||||
import { getVersionString, getVersionJsonString } from "./constants"
|
||||
import { openInExistingInstance, runCodeServer, runVsCodeCli, shouldSpawnCliProcess } from "./main"
|
||||
import { isChild, wrapper } from "./wrapper"
|
||||
|
||||
@@ -24,7 +24,7 @@ async function entry(): Promise<void> {
|
||||
const args = await setDefaults(cliArgs, configArgs)
|
||||
|
||||
if (args.help) {
|
||||
console.log("code-server", version, commit)
|
||||
console.log("code-server", getVersionString())
|
||||
console.log("")
|
||||
console.log(`Usage: code-server [options] [path]`)
|
||||
console.log(` - Opening a directory: code-server ./path/to/your/project`)
|
||||
@@ -39,15 +39,9 @@ async function entry(): Promise<void> {
|
||||
|
||||
if (args.version) {
|
||||
if (args.json) {
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
codeServer: version,
|
||||
commit,
|
||||
vscode: require("../../vendor/modules/code-oss-dev/package.json").version,
|
||||
}),
|
||||
)
|
||||
console.log(getVersionJsonString())
|
||||
} else {
|
||||
console.log(version, commit)
|
||||
console.log(getVersionString())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -138,6 +138,21 @@ export const relativeRoot = (originalUrl: string): string => {
|
||||
return normalize("./" + (depth > 1 ? "../".repeat(depth - 1) : ""))
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to construct a redirect path based on
|
||||
* an Express Request, query and a path to redirect to.
|
||||
*
|
||||
* Redirect path is relative to `/${to}`.
|
||||
*/
|
||||
export const constructRedirectPath = (req: express.Request, query: qs.ParsedQs, to: string): string => {
|
||||
const relativePath = normalize(`${relativeRoot(req.originalUrl)}/${to}`, true)
|
||||
// %2f or %2F are both equalivent to an encoded slash /
|
||||
const queryString = qs.stringify(query).replace(/%2[fF]/g, "/")
|
||||
const redirectPath = `${relativePath}${queryString ? `?${queryString}` : ""}`
|
||||
|
||||
return redirectPath
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect relatively to `/${to}`. Query variables on the current URI will be
|
||||
* preserved. `to` should be a simple path without any query parameters
|
||||
@@ -156,9 +171,7 @@ export const redirect = (
|
||||
}
|
||||
})
|
||||
|
||||
const relativePath = normalize(`${relativeRoot(req.originalUrl)}/${to}`, true)
|
||||
const queryString = qs.stringify(query)
|
||||
const redirectPath = `${relativePath}${queryString ? `?${queryString}` : ""}`
|
||||
const redirectPath = constructRedirectPath(req, query, to)
|
||||
logger.debug(`redirecting from ${req.originalUrl} to ${redirectPath}`)
|
||||
res.redirect(redirectPath)
|
||||
}
|
||||
@@ -196,7 +209,7 @@ export const getCookieDomain = (host: string, proxyDomains: string[]): string |
|
||||
// default NGINX does this).
|
||||
!host.includes(".")
|
||||
) {
|
||||
logger.debug("no valid cookie doman", field("host", host))
|
||||
logger.debug("no valid cookie domain", field("host", host))
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -206,7 +219,7 @@ export const getCookieDomain = (host: string, proxyDomains: string[]): string |
|
||||
}
|
||||
})
|
||||
|
||||
logger.debug("got cookie doman", field("host", host))
|
||||
logger.debug("got cookie domain", field("host", host))
|
||||
return host || undefined
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { logger } from "@coder/logger"
|
||||
import * as express from "express"
|
||||
import * as path from "path"
|
||||
import { WebsocketRequest } from "../../../typings/pluginapi"
|
||||
import { logError } from "../../common/util"
|
||||
import { toVsCodeArgs } from "../cli"
|
||||
import { isDevMode } from "../constants"
|
||||
import { authenticated, ensureAuthenticated, redirect, self } from "../http"
|
||||
import { loadAMDModule } from "../util"
|
||||
import { SocketProxyProvider } from "../socket"
|
||||
import { isFile, loadAMDModule } from "../util"
|
||||
import { Router as WsRouter } from "../wsRouter"
|
||||
import { errorHandler } from "./errors"
|
||||
|
||||
@@ -13,6 +15,7 @@ export class CodeServerRouteWrapper {
|
||||
/** Assigned in `ensureCodeServerLoaded` */
|
||||
private _codeServerMain!: CodeServerLib.IServerAPI
|
||||
private _wsRouterWrapper = WsRouter()
|
||||
private _socketProxyProvider = new SocketProxyProvider()
|
||||
public router = express.Router()
|
||||
|
||||
public get wsRouter() {
|
||||
@@ -23,6 +26,9 @@ export class CodeServerRouteWrapper {
|
||||
|
||||
private $root: express.Handler = async (req, res, next) => {
|
||||
const isAuthenticated = await authenticated(req)
|
||||
const NO_FOLDER_OR_WORKSPACE_QUERY = !req.query.folder && !req.query.workspace
|
||||
// Ew means the workspace was closed so clear the last folder/workspace.
|
||||
const FOLDER_OR_WORKSPACE_WAS_CLOSED = req.query.ew
|
||||
|
||||
if (!isAuthenticated) {
|
||||
const to = self(req)
|
||||
@@ -31,25 +37,38 @@ export class CodeServerRouteWrapper {
|
||||
})
|
||||
}
|
||||
|
||||
const { query } = await req.settings.read()
|
||||
if (query) {
|
||||
// Ew means the workspace was closed so clear the last folder/workspace.
|
||||
if (req.query.ew) {
|
||||
delete query.folder
|
||||
delete query.workspace
|
||||
}
|
||||
if (NO_FOLDER_OR_WORKSPACE_QUERY && !FOLDER_OR_WORKSPACE_WAS_CLOSED) {
|
||||
const settings = await req.settings.read()
|
||||
const lastOpened = settings.query || {}
|
||||
// This flag disables the last opened behavior
|
||||
const IGNORE_LAST_OPENED = req.args["ignore-last-opened"]
|
||||
const HAS_LAST_OPENED_FOLDER_OR_WORKSPACE = lastOpened.folder || lastOpened.workspace
|
||||
const HAS_FOLDER_OR_WORKSPACE_FROM_CLI = req.args._.length > 0
|
||||
const to = self(req)
|
||||
|
||||
let folder = undefined
|
||||
let workspace = undefined
|
||||
|
||||
// Redirect to the last folder/workspace if nothing else is opened.
|
||||
if (
|
||||
!req.query.folder &&
|
||||
!req.query.workspace &&
|
||||
(query.folder || query.workspace) &&
|
||||
!req.args["ignore-last-opened"] // This flag disables this behavior.
|
||||
) {
|
||||
const to = self(req)
|
||||
if (HAS_LAST_OPENED_FOLDER_OR_WORKSPACE && !IGNORE_LAST_OPENED) {
|
||||
folder = lastOpened.folder
|
||||
workspace = lastOpened.workspace
|
||||
} else if (HAS_FOLDER_OR_WORKSPACE_FROM_CLI) {
|
||||
const lastEntry = path.resolve(req.args._[req.args._.length - 1])
|
||||
const entryIsFile = await isFile(lastEntry)
|
||||
const IS_WORKSPACE_FILE = entryIsFile && path.extname(lastEntry) === ".code-workspace"
|
||||
|
||||
if (IS_WORKSPACE_FILE) {
|
||||
workspace = lastEntry
|
||||
} else if (!entryIsFile) {
|
||||
folder = lastEntry
|
||||
}
|
||||
}
|
||||
|
||||
if (folder || workspace) {
|
||||
return redirect(req, res, to, {
|
||||
folder: query.folder,
|
||||
workspace: query.workspace,
|
||||
folder,
|
||||
workspace,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -77,9 +96,10 @@ export class CodeServerRouteWrapper {
|
||||
}
|
||||
|
||||
private $proxyWebsocket = async (req: WebsocketRequest) => {
|
||||
this._codeServerMain.handleUpgrade(req, req.socket)
|
||||
const wrappedSocket = await this._socketProxyProvider.createProxy(req.ws)
|
||||
this._codeServerMain.handleUpgrade(req, wrappedSocket)
|
||||
|
||||
req.socket.resume()
|
||||
req.ws.resume()
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -130,5 +150,6 @@ export class CodeServerRouteWrapper {
|
||||
|
||||
dispose() {
|
||||
this._codeServerMain?.dispose()
|
||||
this._socketProxyProvider.stop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { logger } from "@coder/logger"
|
||||
import * as argon2 from "@node-rs/argon2"
|
||||
import * as argon2 from "argon2"
|
||||
import * as cp from "child_process"
|
||||
import * as crypto from "crypto"
|
||||
import envPaths from "env-paths"
|
||||
@@ -157,12 +156,7 @@ export const generatePassword = async (length = 24): Promise<string> => {
|
||||
* Used to hash the password.
|
||||
*/
|
||||
export const hash = async (password: string): Promise<string> => {
|
||||
try {
|
||||
return await argon2.hash(password)
|
||||
} catch (error: any) {
|
||||
logger.error(error)
|
||||
return ""
|
||||
}
|
||||
return await argon2.hash(password)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,12 +166,7 @@ export const isHashMatch = async (password: string, hash: string) => {
|
||||
if (password === "" || hash === "" || !hash.startsWith("$")) {
|
||||
return false
|
||||
}
|
||||
try {
|
||||
return await argon2.verify(hash, password)
|
||||
} catch (error: any) {
|
||||
logger.error(error)
|
||||
return false
|
||||
}
|
||||
return await argon2.verify(hash, password)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,10 +9,16 @@ import { CodeServer, CodeServerPage } from "./models/CodeServer"
|
||||
*
|
||||
* If `includeCredentials` is `true` page requests will be authenticated.
|
||||
*/
|
||||
export const describe = (name: string, includeCredentials: boolean, fn: (codeServer: CodeServer) => void) => {
|
||||
export const describe = (
|
||||
name: string,
|
||||
includeCredentials: boolean,
|
||||
codeServerArgs: string[],
|
||||
codeServerEnv: NodeJS.ProcessEnv,
|
||||
fn: (codeServer: CodeServer) => void,
|
||||
) => {
|
||||
test.describe(name, () => {
|
||||
// This will spawn on demand so nothing is necessary on before.
|
||||
const codeServer = new CodeServer(name)
|
||||
const codeServer = new CodeServer(name, codeServerArgs, codeServerEnv)
|
||||
|
||||
// Kill code-server after the suite has ended. This may happen even without
|
||||
// doing it explicitly but it seems prudent to be sure.
|
||||
@@ -36,6 +42,9 @@ export const describe = (name: string, includeCredentials: boolean, fn: (codeSer
|
||||
authenticated: includeCredentials,
|
||||
// This provides a cookie that authenticates with code-server.
|
||||
storageState: includeCredentials ? storageState : {},
|
||||
// NOTE@jsjoeio some tests use --cert which uses a self-signed certificate
|
||||
// without this option, those tests will fail.
|
||||
ignoreHTTPSErrors: true,
|
||||
})
|
||||
|
||||
fn(codeServer)
|
||||
@@ -61,8 +70,8 @@ export const test = base.extend<TestFixtures>({
|
||||
// made too). In these cases just accept.
|
||||
page.on("dialog", (d) => d.accept())
|
||||
|
||||
const codeServerPage = new CodeServerPage(codeServer, page)
|
||||
await codeServerPage.setup(authenticated)
|
||||
const codeServerPage = new CodeServerPage(codeServer, page, authenticated)
|
||||
await codeServerPage.navigate()
|
||||
await use(codeServerPage)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,6 +1,45 @@
|
||||
import * as cp from "child_process"
|
||||
import { promises as fs } from "fs"
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
import * as util from "util"
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
import { CodeServer } from "./models/CodeServer"
|
||||
|
||||
describe("code-server", true, [], {}, () => {
|
||||
// TODO@asher: Generalize this? Could be nice if we were to ever need
|
||||
// multiple migration tests in other suites.
|
||||
const instances = new Map<string, CodeServer>()
|
||||
test.afterAll(async () => {
|
||||
const procs = Array.from(instances.values())
|
||||
instances.clear()
|
||||
await Promise.all(procs.map((cs) => cs.close()))
|
||||
})
|
||||
|
||||
/**
|
||||
* Spawn a specific version of code-server using the install script.
|
||||
*/
|
||||
const spawn = async (version: string, dir?: string): Promise<CodeServer> => {
|
||||
let instance = instances.get(version)
|
||||
if (!instance) {
|
||||
await util.promisify(cp.exec)(`./install.sh --method standalone --version ${version}`, {
|
||||
cwd: path.join(__dirname, "../.."),
|
||||
})
|
||||
|
||||
instance = new CodeServer(
|
||||
"code-server@" + version,
|
||||
["--auth=none"],
|
||||
{ VSCODE_DEV: "" },
|
||||
dir,
|
||||
`${os.homedir()}/.local/lib/code-server-${version}`,
|
||||
)
|
||||
|
||||
instances.set(version, instance)
|
||||
}
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
describe("CodeServer", true, () => {
|
||||
test("should navigate to home page", async ({ codeServerPage }) => {
|
||||
// We navigate codeServer before each test
|
||||
// and we start the test with a storage state
|
||||
@@ -24,4 +63,58 @@ describe("CodeServer", true, () => {
|
||||
await codeServerPage.focusTerminal()
|
||||
expect(await codeServerPage.page.isVisible("#terminal")).toBe(true)
|
||||
})
|
||||
|
||||
test("should open a file", async ({ codeServerPage }) => {
|
||||
const dir = await codeServerPage.workspaceDir
|
||||
const file = path.join(dir, "foo")
|
||||
await fs.writeFile(file, "bar")
|
||||
await codeServerPage.openFile(file)
|
||||
})
|
||||
|
||||
test("should migrate state to avoid collisions", async ({ codeServerPage }) => {
|
||||
// This can take a very long time in development because of how long pages
|
||||
// take to load and we are doing a lot of that here.
|
||||
test.slow()
|
||||
|
||||
const dir = await codeServerPage.workspaceDir
|
||||
const files = [path.join(dir, "foo"), path.join(dir, "bar")]
|
||||
await Promise.all(
|
||||
files.map((file) => {
|
||||
return fs.writeFile(file, path.basename(file))
|
||||
}),
|
||||
)
|
||||
|
||||
// Open a file in the latest instance.
|
||||
await codeServerPage.openFile(files[0])
|
||||
await codeServerPage.stateFlush()
|
||||
|
||||
// Open a file in an older version of code-server. It should not see the
|
||||
// file opened in the new instance since the database has a different
|
||||
// name. This must be accessed through the proxy so it shares the same
|
||||
// domain and can write to the same database.
|
||||
const cs = await spawn("4.0.2", dir)
|
||||
const address = new URL(await cs.address())
|
||||
await codeServerPage.navigate("/proxy/" + address.port + "/")
|
||||
await codeServerPage.openFile(files[1])
|
||||
expect(await codeServerPage.tabIsVisible(files[0])).toBe(false)
|
||||
await codeServerPage.stateFlush()
|
||||
|
||||
// Move back to latest code-server. We should see the file we previously
|
||||
// opened with it but not the old code-server file because the new instance
|
||||
// already created its own database on this path and will avoid migrating.
|
||||
await codeServerPage.navigate()
|
||||
await codeServerPage.waitForTab(files[0])
|
||||
expect(await codeServerPage.tabIsVisible(files[1])).toBe(false)
|
||||
|
||||
// Open a new path in latest code-server. This one should migrate the
|
||||
// database from old code-server but see nothing from the new database
|
||||
// created on the root.
|
||||
await codeServerPage.navigate("/vscode")
|
||||
await codeServerPage.waitForTab(files[1])
|
||||
expect(await codeServerPage.tabIsVisible(files[0])).toBe(false)
|
||||
// Should still be open after a reload.
|
||||
await codeServerPage.navigate("/vscode")
|
||||
await codeServerPage.waitForTab(files[1])
|
||||
expect(await codeServerPage.tabIsVisible(files[0])).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
import * as path from "path"
|
||||
import { describe, test } from "./baseFixture"
|
||||
|
||||
describe("Extensions", true, () => {
|
||||
function runTestExtensionTests() {
|
||||
// This will only work if the test extension is loaded into code-server.
|
||||
test("should have access to VSCODE_PROXY_URI", async ({ codeServerPage }) => {
|
||||
const address = await codeServerPage.address()
|
||||
|
||||
await codeServerPage.executeCommandViaMenus("code-server: Get proxy URI")
|
||||
|
||||
await codeServerPage.page.waitForSelector(`text=${address}/proxy/{port}`)
|
||||
await codeServerPage.page.waitForSelector(`text=${address}/proxy/{{port}}`)
|
||||
})
|
||||
}
|
||||
|
||||
const flags = ["--extensions-dir", path.join(__dirname, "./extensions")]
|
||||
|
||||
describe("Extensions", true, flags, {}, () => {
|
||||
runTestExtensionTests()
|
||||
})
|
||||
|
||||
describe("Extensions with --cert", true, [...flags, "--cert"], {}, () => {
|
||||
runTestExtensionTests()
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "code-server-extension",
|
||||
"description": "code-server test extension",
|
||||
"version": "0.0.1",
|
||||
"publisher": "cdr",
|
||||
"publisher": "coder",
|
||||
"activationEvents": [
|
||||
"onCommand:codeServerTest.proxyUri"
|
||||
],
|
||||
|
||||
38
test/e2e/github.test.ts
Normal file
38
test/e2e/github.test.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { test as base } from "@playwright/test"
|
||||
import { describe, expect, test } from "./baseFixture"
|
||||
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
describe("GitHub token", true, [], {}, () => {
|
||||
test("should be logged in to pull requests extension", async ({ codeServerPage }) => {
|
||||
await codeServerPage.exec("git init")
|
||||
await codeServerPage.exec("git remote add origin https://github.com/coder/code-server")
|
||||
await codeServerPage.installExtension("GitHub.vscode-pull-request-github")
|
||||
await codeServerPage.executeCommandViaMenus("View: Show Github")
|
||||
await codeServerPage.page.click("text=Sign in")
|
||||
await codeServerPage.page.click("text=Allow")
|
||||
// It should ask to select an account, one of which will be the one we
|
||||
// pre-injected.
|
||||
expect(await codeServerPage.page.isVisible("text=Select an account")).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("No GitHub token", true, [], { GITHUB_TOKEN: "" }, () => {
|
||||
test("should not be logged in to pull requests extension", async ({ codeServerPage }) => {
|
||||
await codeServerPage.exec("git init")
|
||||
await codeServerPage.exec("git remote add origin https://github.com/coder/code-server")
|
||||
await codeServerPage.installExtension("GitHub.vscode-pull-request-github")
|
||||
await codeServerPage.executeCommandViaMenus("View: Show Github")
|
||||
await codeServerPage.page.click("text=Sign in")
|
||||
await codeServerPage.page.click("text=Allow")
|
||||
// Since there is no account it will ask directly for the token (because
|
||||
// we are on localhost; otherwise it would initiate the oauth flow).
|
||||
expect(await codeServerPage.page.isVisible("text=GitHub Personal Access Token")).toBe(false)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
base.describe("GitHub token", () => {
|
||||
base.skip("skipped because GITHUB_TOKEN is not set", () => {
|
||||
// Playwright will not show this without a function.
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
// This test is to make sure the globalSetup works as expected
|
||||
// meaning globalSetup ran and stored the storageState
|
||||
describe("globalSetup", true, () => {
|
||||
describe("globalSetup", true, [], {}, () => {
|
||||
test("should keep us logged in using the storageState", async ({ codeServerPage }) => {
|
||||
// Make sure the editor actually loaded
|
||||
expect(await codeServerPage.isEditorVisible()).toBe(true)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { PASSWORD } from "../utils/constants"
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
describe("login", false, () => {
|
||||
describe("login", false, [], {}, () => {
|
||||
test("should see the login page", async ({ codeServerPage }) => {
|
||||
// It should send us to the login page
|
||||
expect(await codeServerPage.page.title()).toBe("code-server login")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// NOTE@jsjoeio commenting out until we can figure out what's wrong
|
||||
// import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
// describe("logout", true, () => {
|
||||
// describe("logout", true, [], {}, () => {
|
||||
// test("should be able logout", async ({ codeServerPage }) => {
|
||||
// // Recommended by Playwright for async navigation
|
||||
// // https://github.com/microsoft/playwright/issues/1987#issuecomment-620182151
|
||||
|
||||
@@ -3,7 +3,8 @@ import * as cp from "child_process"
|
||||
import { promises as fs } from "fs"
|
||||
import * as path from "path"
|
||||
import { Page } from "playwright"
|
||||
import { logError } from "../../../src/common/util"
|
||||
import * as util from "util"
|
||||
import { logError, plural } from "../../../src/common/util"
|
||||
import { onLine } from "../../../src/node/util"
|
||||
import { PASSWORD, workspaceDir } from "../../utils/constants"
|
||||
import { idleTimer, tmpdir } from "../../utils/helpers"
|
||||
@@ -13,14 +14,21 @@ interface CodeServerProcess {
|
||||
address: string
|
||||
}
|
||||
|
||||
class CancelToken {
|
||||
class Context {
|
||||
private _canceled = false
|
||||
private _done = false
|
||||
public canceled(): boolean {
|
||||
return this._canceled
|
||||
}
|
||||
public done(): void {
|
||||
this._done = true
|
||||
}
|
||||
public cancel(): void {
|
||||
this._canceled = true
|
||||
}
|
||||
public finish(): boolean {
|
||||
return this._done
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,7 +39,13 @@ export class CodeServer {
|
||||
public readonly logger: Logger
|
||||
private closed = false
|
||||
|
||||
constructor(name: string) {
|
||||
constructor(
|
||||
name: string,
|
||||
private readonly args: string[],
|
||||
private readonly env: NodeJS.ProcessEnv,
|
||||
private readonly _workspaceDir: Promise<string> | string | undefined,
|
||||
private readonly entry = process.env.CODE_SERVER_TEST_ENTRY || ".",
|
||||
) {
|
||||
this.logger = logger.named(name)
|
||||
}
|
||||
|
||||
@@ -47,12 +61,22 @@ export class CodeServer {
|
||||
return address
|
||||
}
|
||||
|
||||
/**
|
||||
* The workspace directory code-server opens with.
|
||||
*/
|
||||
get workspaceDir(): Promise<string> {
|
||||
if (!this._workspaceDir) {
|
||||
this._workspaceDir = tmpdir(workspaceDir)
|
||||
}
|
||||
return this._workspaceDir
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a random workspace and seed it with settings.
|
||||
*/
|
||||
private async createWorkspace(): Promise<string> {
|
||||
const dir = await tmpdir(workspaceDir)
|
||||
await fs.mkdir(path.join(dir, "User"))
|
||||
const dir = await this.workspaceDir
|
||||
await fs.mkdir(path.join(dir, "User"), { recursive: true })
|
||||
await fs.writeFile(
|
||||
path.join(dir, "User/settings.json"),
|
||||
JSON.stringify({
|
||||
@@ -73,34 +97,33 @@ export class CodeServer {
|
||||
const dir = await this.createWorkspace()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.logger.debug("spawning")
|
||||
const proc = cp.spawn(
|
||||
"node",
|
||||
[
|
||||
process.env.CODE_SERVER_TEST_ENTRY || ".",
|
||||
// Using port zero will spawn on a random port.
|
||||
"--bind-addr",
|
||||
"127.0.0.1:0",
|
||||
// Setting the XDG variables would be easier and more thorough but the
|
||||
// modules we import ignores those variables for non-Linux operating
|
||||
// systems so use these flags instead.
|
||||
"--config",
|
||||
path.join(dir, "config.yaml"),
|
||||
"--user-data-dir",
|
||||
dir,
|
||||
"--extensions-dir",
|
||||
path.join(__dirname, "../extensions"),
|
||||
// The last argument is the workspace to open.
|
||||
dir,
|
||||
],
|
||||
{
|
||||
cwd: path.join(__dirname, "../../.."),
|
||||
env: {
|
||||
...process.env,
|
||||
PASSWORD,
|
||||
},
|
||||
const args = [
|
||||
this.entry,
|
||||
"--extensions-dir",
|
||||
path.join(dir, "extensions"),
|
||||
...this.args,
|
||||
// Using port zero will spawn on a random port.
|
||||
"--bind-addr",
|
||||
"127.0.0.1:0",
|
||||
// Setting the XDG variables would be easier and more thorough but the
|
||||
// modules we import ignores those variables for non-Linux operating
|
||||
// systems so use these flags instead.
|
||||
"--config",
|
||||
path.join(dir, "config.yaml"),
|
||||
"--user-data-dir",
|
||||
dir,
|
||||
// The last argument is the workspace to open.
|
||||
dir,
|
||||
]
|
||||
this.logger.debug("spawning `node " + args.join(" ") + "`")
|
||||
const proc = cp.spawn("node", args, {
|
||||
cwd: path.join(__dirname, "../../.."),
|
||||
env: {
|
||||
...process.env,
|
||||
...this.env,
|
||||
PASSWORD,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
const timer = idleTimer("Failed to extract address; did the format change?", reject)
|
||||
|
||||
@@ -111,7 +134,7 @@ export class CodeServer {
|
||||
})
|
||||
|
||||
proc.on("close", (code) => {
|
||||
const error = new Error("closed unexpectedly")
|
||||
const error = new Error("code-server closed unexpectedly")
|
||||
if (!this.closed) {
|
||||
this.logger.error(error.message, field("code", code))
|
||||
}
|
||||
@@ -128,7 +151,7 @@ export class CodeServer {
|
||||
timer.reset()
|
||||
|
||||
// Log the line without the timestamp.
|
||||
this.logger.trace(line.replace(/\[.+\]/, ""))
|
||||
this.logger.debug(line.replace(/\[.+\]/, ""))
|
||||
if (resolved) {
|
||||
return
|
||||
}
|
||||
@@ -169,7 +192,11 @@ export class CodeServer {
|
||||
export class CodeServerPage {
|
||||
private readonly editorSelector = "div.monaco-workbench"
|
||||
|
||||
constructor(private readonly codeServer: CodeServer, public readonly page: Page) {
|
||||
constructor(
|
||||
private readonly codeServer: CodeServer,
|
||||
public readonly page: Page,
|
||||
private readonly authenticated: boolean,
|
||||
) {
|
||||
this.page.on("console", (message) => {
|
||||
this.codeServer.logger.debug(message)
|
||||
})
|
||||
@@ -183,11 +210,25 @@ export class CodeServerPage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to code-server.
|
||||
* The workspace directory code-server opens with.
|
||||
*/
|
||||
async navigate() {
|
||||
const address = await this.codeServer.address()
|
||||
await this.page.goto(address, { waitUntil: "networkidle" })
|
||||
get workspaceDir() {
|
||||
return this.codeServer.workspaceDir
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a code-server endpoint (root by default). Then wait for the
|
||||
* editor to become available.
|
||||
*/
|
||||
async navigate(endpoint = "/") {
|
||||
const to = new URL(endpoint, await this.codeServer.address())
|
||||
await this.page.goto(to.toString(), { waitUntil: "networkidle" })
|
||||
|
||||
// Only reload editor if authenticated. Otherwise we'll get stuck
|
||||
// reloading the login page.
|
||||
if (this.authenticated) {
|
||||
await this.reloadUntilEditorIsReady()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,6 +313,29 @@ export class CodeServerPage {
|
||||
await this.page.waitForSelector("textarea.xterm-helper-textarea")
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a file by using menus.
|
||||
*/
|
||||
async openFile(file: string) {
|
||||
await this.navigateMenus(["File", "Open File"])
|
||||
await this.navigateQuickInput([path.basename(file)])
|
||||
await this.waitForTab(file)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a tab to open for the specified file.
|
||||
*/
|
||||
async waitForTab(file: string): Promise<void> {
|
||||
return this.page.waitForSelector(`.tab :text("${path.basename(file)}")`)
|
||||
}
|
||||
|
||||
/**
|
||||
* See if the specified tab is open.
|
||||
*/
|
||||
async tabIsVisible(file: string): Promise<void> {
|
||||
return this.page.isVisible(`.tab :text("${path.basename(file)}")`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to the command palette via menus then execute a command by typing
|
||||
* it then clicking the match from the results.
|
||||
@@ -286,13 +350,45 @@ export class CodeServerPage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate through the specified set of menus. If it fails it will keep
|
||||
* trying.
|
||||
* Navigate through the items in the selector. `open` is a function that will
|
||||
* open the menu/popup containing the items through which to navigation.
|
||||
*/
|
||||
async navigateMenus(menus: string[]) {
|
||||
const navigate = async (cancelToken: CancelToken) => {
|
||||
const steps: Array<() => Promise<unknown>> = [() => this.page.waitForSelector(`${menuSelector}:focus-within`)]
|
||||
for (const menu of menus) {
|
||||
async navigateItems(items: string[], selector: string, open?: (selector: string) => void): Promise<void> {
|
||||
const logger = this.codeServer.logger.named(selector)
|
||||
|
||||
/**
|
||||
* If the selector loses focus or gets removed this will resolve with false,
|
||||
* signaling we need to try again.
|
||||
*/
|
||||
const openThenWaitClose = async (ctx: Context) => {
|
||||
if (open) {
|
||||
await open(selector)
|
||||
}
|
||||
this.codeServer.logger.debug(`watching ${selector}`)
|
||||
try {
|
||||
await this.page.waitForSelector(`${selector}:not(:focus-within)`)
|
||||
} catch (error) {
|
||||
if (!ctx.done()) {
|
||||
this.codeServer.logger.debug(`${selector} navigation: ${error.message || error}`)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* This will step through each item, aborting and returning false if
|
||||
* canceled or if any navigation step has an error which signals we need to
|
||||
* try again.
|
||||
*/
|
||||
const navigate = async (ctx: Context) => {
|
||||
const steps: Array<{ fn: () => Promise<unknown>; name: string }> = [
|
||||
{
|
||||
fn: () => this.page.waitForSelector(`${selector}:focus-within`),
|
||||
name: "focus",
|
||||
},
|
||||
]
|
||||
|
||||
for (const item of items) {
|
||||
// Normally these will wait for the item to be visible and then execute
|
||||
// the action. The problem is that if the menu closes these will still
|
||||
// be waiting and continue to execute once the menu is visible again,
|
||||
@@ -300,56 +396,102 @@ export class CodeServerPage {
|
||||
// if the old promise clicks logout before the new one can). By
|
||||
// splitting them into two steps each we can cancel before running the
|
||||
// action.
|
||||
steps.push(() => this.page.hover(`text=${menu}`, { trial: true }))
|
||||
steps.push(() => this.page.hover(`text=${menu}`, { force: true }))
|
||||
steps.push(() => this.page.click(`text=${menu}`, { trial: true }))
|
||||
steps.push(() => this.page.click(`text=${menu}`, { force: true }))
|
||||
steps.push({
|
||||
fn: () => this.page.hover(`${selector} :text("${item}")`, { trial: true }),
|
||||
name: `${item}:hover:trial`,
|
||||
})
|
||||
steps.push({
|
||||
fn: () => this.page.hover(`${selector} :text("${item}")`, { force: true }),
|
||||
name: `${item}:hover:force`,
|
||||
})
|
||||
steps.push({
|
||||
fn: () => this.page.click(`${selector} :text("${item}")`, { trial: true }),
|
||||
name: `${item}:click:trial`,
|
||||
})
|
||||
steps.push({
|
||||
fn: () => this.page.click(`${selector} :text("${item}")`, { force: true }),
|
||||
name: `${item}:click:force`,
|
||||
})
|
||||
}
|
||||
|
||||
for (const step of steps) {
|
||||
await step()
|
||||
if (cancelToken.canceled()) {
|
||||
this.codeServer.logger.debug("menu navigation canceled")
|
||||
try {
|
||||
logger.debug(`navigation step: ${step.name}`)
|
||||
await step.fn()
|
||||
if (ctx.canceled()) {
|
||||
logger.debug("navigation canceled")
|
||||
return false
|
||||
}
|
||||
} catch (error) {
|
||||
logger.debug(`navigation: ${error.message || error}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const menuSelector = '[aria-label="Application Menu"]'
|
||||
const open = async () => {
|
||||
await this.page.click(menuSelector)
|
||||
await this.page.waitForSelector(`${menuSelector}:not(:focus-within)`)
|
||||
return false
|
||||
// We are seeing the menu closing after opening if we open it too soon and
|
||||
// the picker getting recreated in the middle of trying to select an item.
|
||||
// To counter this we will keep trying to navigate through the items every
|
||||
// time we lose focus or there is an error.
|
||||
let attempts = 1
|
||||
let context = new Context()
|
||||
while (!(await Promise.race([openThenWaitClose(), navigate(context)]))) {
|
||||
++attempts
|
||||
logger.debug("closed, retrying (${attempt}/∞)")
|
||||
context.cancel()
|
||||
context = new Context()
|
||||
}
|
||||
|
||||
// TODO: Starting in 1.57 something closes the menu after opening it if we
|
||||
// open it too soon. To counter that we'll watch for when the menu loses
|
||||
// focus and when/if it does we'll try again.
|
||||
// I tried using the classic menu but it doesn't show up at all for some
|
||||
// reason. I also tried toggle but the menu disappears after toggling.
|
||||
let retryCount = 0
|
||||
let cancelToken = new CancelToken()
|
||||
while (!(await Promise.race([open(), navigate(cancelToken)]))) {
|
||||
this.codeServer.logger.debug("menu was closed, retrying")
|
||||
++retryCount
|
||||
cancelToken.cancel()
|
||||
cancelToken = new CancelToken()
|
||||
}
|
||||
|
||||
this.codeServer.logger.debug(`menu navigation retries: ${retryCount}`)
|
||||
context.finish()
|
||||
logger.debug(`navigation took ${attempts} ${plural(attempts, "attempt")}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to code-server then reloads until the editor is ready.
|
||||
*
|
||||
* It is recommended to run setup before using this model in any tests.
|
||||
* Navigate through a currently opened "quick input" widget, retrying on
|
||||
* failure.
|
||||
*/
|
||||
async setup(authenticated: boolean) {
|
||||
await this.navigate()
|
||||
// If we aren't authenticated we'll see a login page so we can't wait until
|
||||
// the editor is ready.
|
||||
if (authenticated) {
|
||||
await this.reloadUntilEditorIsReady()
|
||||
}
|
||||
async navigateQuickInput(items: string[]): Promise<void> {
|
||||
await this.navigateItems(items, ".quick-input-widget")
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate through the menu, retrying on failure.
|
||||
*/
|
||||
async navigateMenus(menus: string[]): Promise<void> {
|
||||
await this.navigateItems(menus, '[aria-label="Application Menu"]', async (selector) => {
|
||||
await this.page.click(selector)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command in the root of the instance's workspace directory.
|
||||
*/
|
||||
async exec(command: string): Promise<void> {
|
||||
await util.promisify(cp.exec)(command, {
|
||||
cwd: await this.workspaceDir,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Install an extension by ID to the instance's temporary extension
|
||||
* directory.
|
||||
*/
|
||||
async installExtension(id: string): Promise<void> {
|
||||
const dir = path.join(await this.workspaceDir, "extensions")
|
||||
await util.promisify(cp.exec)(`node . --install-extension ${id} --extensions-dir ${dir}`, {
|
||||
cwd: path.join(__dirname, "../../.."),
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for state to be flushed to the database.
|
||||
*/
|
||||
async stateFlush(): Promise<void> {
|
||||
// If we reload too quickly VS Code will be unable to save the state changes
|
||||
// so wait until those have been written to the database. It flushes every
|
||||
// five seconds so we need to wait at least that long.
|
||||
// TODO@asher: There must be a better way.
|
||||
await this.page.waitForTimeout(5500)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
describe("Open Help > About", true, () => {
|
||||
describe("Open Help > About", true, [], {}, () => {
|
||||
test("should see code-server version in about dialog", async ({ codeServerPage }) => {
|
||||
// Open using the menu.
|
||||
await codeServerPage.navigateMenus(["Help", "About"])
|
||||
|
||||
@@ -4,7 +4,7 @@ import util from "util"
|
||||
import { clean, tmpdir } from "../utils/helpers"
|
||||
import { describe, expect, test } from "./baseFixture"
|
||||
|
||||
describe("Integrated Terminal", true, () => {
|
||||
describe("Integrated Terminal", true, [], {}, () => {
|
||||
const testName = "integrated-terminal"
|
||||
test.beforeAll(async () => {
|
||||
await clean(testName)
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
"license": "MIT",
|
||||
"#": "We must put jest in a sub-directory otherwise VS Code somehow picks up the types and generates conflicts with mocha.",
|
||||
"devDependencies": {
|
||||
"@jest-mock/express": "^1.4.5",
|
||||
"@playwright/test": "^1.16.3",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/jsdom": "^16.2.13",
|
||||
"@types/node-fetch": "^2.5.8",
|
||||
"@types/supertest": "^2.0.11",
|
||||
"@types/wtfnode": "^0.7.0",
|
||||
"argon2": "^0.28.0",
|
||||
"jest": "^27.3.1",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"jsdom": "^16.4.0",
|
||||
@@ -19,6 +21,7 @@
|
||||
},
|
||||
"resolutions": {
|
||||
"ansi-regex": "^5.0.1",
|
||||
"argon2/@mapbox/node-pre-gyp/tar": "^6.1.9",
|
||||
"set-value": "^4.0.1",
|
||||
"tmpl": "^1.0.5",
|
||||
"path-parse": "^1.0.7",
|
||||
|
||||
@@ -107,6 +107,18 @@ describe("createApp", () => {
|
||||
app.dispose()
|
||||
})
|
||||
|
||||
it("should change the file mode of a socket", async () => {
|
||||
const defaultArgs = await setDefaults({
|
||||
socket: tmpFilePath,
|
||||
"socket-mode": "777",
|
||||
})
|
||||
|
||||
const app = await createApp(defaultArgs)
|
||||
|
||||
expect((await promises.stat(tmpFilePath)).mode & 0o777).toBe(0o777)
|
||||
app.dispose()
|
||||
})
|
||||
|
||||
it("should create an https server if args.cert exists", async () => {
|
||||
const testCertificate = await generateCertificate("localhost")
|
||||
const cert = new OptionalString(testCertificate.cert)
|
||||
|
||||
@@ -73,6 +73,8 @@ describe("parser", () => {
|
||||
|
||||
"--socket=mumble",
|
||||
|
||||
"--socket-mode=777",
|
||||
|
||||
"3",
|
||||
|
||||
["--user-data-dir", "path/to/user/dir"],
|
||||
@@ -110,6 +112,7 @@ describe("parser", () => {
|
||||
open: true,
|
||||
port: 8081,
|
||||
socket: path.resolve("mumble"),
|
||||
"socket-mode": "777",
|
||||
verbose: true,
|
||||
version: true,
|
||||
"bind-addr": "192.169.0.1:8080",
|
||||
@@ -269,7 +272,9 @@ describe("parser", () => {
|
||||
})
|
||||
|
||||
it("should override with --link", async () => {
|
||||
const args = parse("--cert test --cert-key test --socket test --host 0.0.0.0 --port 8888 --link test".split(" "))
|
||||
const args = parse(
|
||||
"--cert test --cert-key test --socket test --socket-mode 777 --host 0.0.0.0 --port 8888 --link test".split(" "),
|
||||
)
|
||||
const defaultArgs = await setDefaults(args)
|
||||
expect(defaultArgs).toEqual({
|
||||
...defaults,
|
||||
@@ -282,6 +287,7 @@ describe("parser", () => {
|
||||
cert: undefined,
|
||||
"cert-key": path.resolve("test"),
|
||||
socket: undefined,
|
||||
"socket-mode": undefined,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -313,6 +319,19 @@ describe("parser", () => {
|
||||
})
|
||||
})
|
||||
|
||||
it("should use env var github token", async () => {
|
||||
process.env.GITHUB_TOKEN = "ga-foo"
|
||||
const args = parse([])
|
||||
expect(args).toEqual({})
|
||||
|
||||
const defaultArgs = await setDefaults(args)
|
||||
expect(defaultArgs).toEqual({
|
||||
...defaults,
|
||||
"github-auth": "ga-foo",
|
||||
})
|
||||
expect(process.env.GITHUB_TOKEN).toBe(undefined)
|
||||
})
|
||||
|
||||
it("should error if password passed in", () => {
|
||||
expect(() => parse(["--password", "supersecret123"])).toThrowError(
|
||||
"--password can only be set in the config file or passed in via $PASSWORD",
|
||||
@@ -325,6 +344,12 @@ describe("parser", () => {
|
||||
)
|
||||
})
|
||||
|
||||
it("should error if github-auth passed in", () => {
|
||||
expect(() => parse(["--github-auth", "fdas423fs8a"])).toThrowError(
|
||||
"--github-auth can only be set in the config file or passed in via $GITHUB_TOKEN",
|
||||
)
|
||||
})
|
||||
|
||||
it("should filter proxy domains", async () => {
|
||||
const args = parse(["--proxy-domain", "*.coder.com", "--proxy-domain", "coder.com", "--proxy-domain", "coder.org"])
|
||||
expect(args).toEqual({
|
||||
@@ -361,6 +386,24 @@ describe("parser", () => {
|
||||
"$argon2i$v=19$m=4096,t=3,p=1$0qr/o+0t00hsbjfqcksfdq$ofcm4rl6o+b7oxpua4qlxubypbbpsf+8l531u7p9hyy",
|
||||
})
|
||||
})
|
||||
it("should throw an error for invalid config values", async () => {
|
||||
const fakePath = "/fake-config-path"
|
||||
const expectedErrMsg = `error reading ${fakePath}: `
|
||||
|
||||
expect(() =>
|
||||
parse(["--foo"], {
|
||||
configFile: fakePath,
|
||||
}),
|
||||
).toThrowError(expectedErrMsg)
|
||||
})
|
||||
it("should ignore optional strings set to false", async () => {
|
||||
expect(parse(["--cert=false"])).toEqual({})
|
||||
})
|
||||
it("should use last flag", async () => {
|
||||
expect(parse(["--port", "8081", "--port", "8082"])).toEqual({
|
||||
port: 8082,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("cli", () => {
|
||||
@@ -689,29 +732,6 @@ describe("toVsCodeArgs", () => {
|
||||
it("should convert empty args", async () => {
|
||||
expect(await toVsCodeArgs(await setDefaults(parse([])))).toStrictEqual({
|
||||
...vscodeDefaults,
|
||||
folder: "",
|
||||
workspace: "",
|
||||
})
|
||||
})
|
||||
|
||||
it("should convert with workspace", async () => {
|
||||
const workspace = path.join(await tmpdir(testName), "test.code-workspace")
|
||||
await fs.writeFile(workspace, "foobar")
|
||||
expect(await toVsCodeArgs(await setDefaults(parse([workspace])))).toStrictEqual({
|
||||
...vscodeDefaults,
|
||||
workspace,
|
||||
folder: "",
|
||||
_: [workspace],
|
||||
})
|
||||
})
|
||||
|
||||
it("should convert with folder", async () => {
|
||||
const folder = await tmpdir(testName)
|
||||
expect(await toVsCodeArgs(await setDefaults(parse([folder])))).toStrictEqual({
|
||||
...vscodeDefaults,
|
||||
folder,
|
||||
workspace: "",
|
||||
_: [folder],
|
||||
})
|
||||
})
|
||||
|
||||
@@ -720,8 +740,6 @@ describe("toVsCodeArgs", () => {
|
||||
await fs.writeFile(file, "foobar")
|
||||
expect(await toVsCodeArgs(await setDefaults(parse([file])))).toStrictEqual({
|
||||
...vscodeDefaults,
|
||||
folder: "",
|
||||
workspace: "",
|
||||
_: [file],
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { logger } from "@coder/logger"
|
||||
import { mockLogger } from "../../utils/helpers"
|
||||
import * as semver from "semver"
|
||||
|
||||
describe("constants", () => {
|
||||
let constants: typeof import("../../../src/node/constants")
|
||||
@@ -13,9 +14,15 @@ describe("constants", () => {
|
||||
commit: "f6b2be2838f4afb217c2fd8f03eafedd8d55ef9b",
|
||||
}
|
||||
|
||||
const mockCodePackageJson = {
|
||||
name: "mock-code-oss-dev",
|
||||
version: "1.2.3",
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
mockLogger()
|
||||
jest.mock("../../../package.json", () => mockPackageJson, { virtual: true })
|
||||
jest.mock("../../../vendor/modules/code-oss-dev/package.json", () => mockCodePackageJson, { virtual: true })
|
||||
constants = require("../../../src/node/constants")
|
||||
})
|
||||
|
||||
@@ -24,12 +31,48 @@ describe("constants", () => {
|
||||
jest.resetModules()
|
||||
})
|
||||
|
||||
it("should provide the package name", () => {
|
||||
expect(constants.pkgName).toBe(mockPackageJson.name)
|
||||
})
|
||||
|
||||
it("should provide the commit", () => {
|
||||
expect(constants.commit).toBe(mockPackageJson.commit)
|
||||
})
|
||||
|
||||
it("should return the package.json version", () => {
|
||||
expect(constants.version).toBe(mockPackageJson.version)
|
||||
|
||||
// Ensure the version is parseable as semver and equal
|
||||
const actual = semver.parse(constants.version)
|
||||
const expected = semver.parse(mockPackageJson.version)
|
||||
expect(actual).toBeTruthy()
|
||||
expect(actual).toStrictEqual(expected)
|
||||
})
|
||||
|
||||
it("should include embedded Code version information", () => {
|
||||
expect(constants.codeVersion).toBe(mockCodePackageJson.version)
|
||||
|
||||
// Ensure the version is parseable as semver and equal
|
||||
const actual = semver.parse(constants.codeVersion)
|
||||
const expected = semver.parse(mockCodePackageJson.version)
|
||||
expect(actual).toBeTruthy()
|
||||
expect(actual).toStrictEqual(expected)
|
||||
})
|
||||
|
||||
it("should return a human-readable version string", () => {
|
||||
expect(constants.getVersionString()).toStrictEqual(
|
||||
`${mockPackageJson.version} ${mockPackageJson.commit} with Code ${mockCodePackageJson.version}`,
|
||||
)
|
||||
})
|
||||
|
||||
it("should return a machine-readable version string", () => {
|
||||
expect(constants.getVersionJsonString()).toStrictEqual(
|
||||
JSON.stringify({
|
||||
codeServer: mockPackageJson.version,
|
||||
commit: mockPackageJson.commit,
|
||||
vscode: mockCodePackageJson.version,
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
describe("getPackageJson", () => {
|
||||
@@ -47,6 +90,9 @@ describe("constants", () => {
|
||||
// so to get the root package.json we need to use ../../
|
||||
const packageJson = constants.getPackageJson("../../package.json")
|
||||
expect(packageJson).toStrictEqual(mockPackageJson)
|
||||
|
||||
const codePackageJson = constants.getPackageJson("../../vendor/modules/code-oss-dev/package.json")
|
||||
expect(codePackageJson).toStrictEqual(mockCodePackageJson)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -55,9 +101,13 @@ describe("constants", () => {
|
||||
const mockPackageJson = {
|
||||
name: "mock-code-server",
|
||||
}
|
||||
const mockCodePackageJson = {
|
||||
name: "mock-code-oss-dev",
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
jest.mock("../../../package.json", () => mockPackageJson, { virtual: true })
|
||||
jest.mock("../../../vendor/modules/code-oss-dev/package.json", () => mockCodePackageJson, { virtual: true })
|
||||
constants = require("../../../src/node/constants")
|
||||
})
|
||||
|
||||
@@ -69,8 +119,24 @@ describe("constants", () => {
|
||||
it("version should return 'development'", () => {
|
||||
expect(constants.version).toBe("development")
|
||||
})
|
||||
|
||||
it("commit should return 'development'", () => {
|
||||
expect(constants.commit).toBe("development")
|
||||
})
|
||||
|
||||
it("should return a human-readable version string", () => {
|
||||
// this string is not super useful
|
||||
expect(constants.getVersionString()).toStrictEqual("development development with Code development")
|
||||
})
|
||||
|
||||
it("should return a machine-readable version string", () => {
|
||||
expect(constants.getVersionJsonString()).toStrictEqual(
|
||||
JSON.stringify({
|
||||
codeServer: "development",
|
||||
commit: "development",
|
||||
vscode: "development",
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { relativeRoot } from "../../../src/node/http"
|
||||
import { getMockReq } from "@jest-mock/express"
|
||||
import { constructRedirectPath, relativeRoot } from "../../../src/node/http"
|
||||
|
||||
describe("http", () => {
|
||||
it("should construct a relative path to the root", () => {
|
||||
@@ -9,3 +10,46 @@ describe("http", () => {
|
||||
expect(relativeRoot("/foo/bar/")).toStrictEqual("./../..")
|
||||
})
|
||||
})
|
||||
|
||||
describe("constructRedirectPath", () => {
|
||||
it("should preserve slashes in queryString so they are human-readable", () => {
|
||||
const mockReq = getMockReq({
|
||||
originalUrl: "localhost:8080",
|
||||
})
|
||||
const mockQueryParams = { folder: "/Users/jp/dev/coder" }
|
||||
const mockTo = ""
|
||||
const actual = constructRedirectPath(mockReq, mockQueryParams, mockTo)
|
||||
const expected = "./?folder=/Users/jp/dev/coder"
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
it("should use an empty string if no query params", () => {
|
||||
const mockReq = getMockReq({
|
||||
originalUrl: "localhost:8080",
|
||||
})
|
||||
const mockQueryParams = {}
|
||||
const mockTo = ""
|
||||
const actual = constructRedirectPath(mockReq, mockQueryParams, mockTo)
|
||||
const expected = "./"
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
it("should append the 'to' path relative to the originalUrl", () => {
|
||||
const mockReq = getMockReq({
|
||||
originalUrl: "localhost:8080",
|
||||
})
|
||||
const mockQueryParams = {}
|
||||
const mockTo = "vscode"
|
||||
const actual = constructRedirectPath(mockReq, mockQueryParams, mockTo)
|
||||
const expected = "./vscode"
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
it("should append append queryParams after 'to' path", () => {
|
||||
const mockReq = getMockReq({
|
||||
originalUrl: "localhost:8080",
|
||||
})
|
||||
const mockQueryParams = { folder: "/Users/jp/dev/coder" }
|
||||
const mockTo = "vscode"
|
||||
const actual = constructRedirectPath(mockReq, mockQueryParams, mockTo)
|
||||
const expected = "./vscode?folder=/Users/jp/dev/coder"
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
import { promises as fs } from "fs"
|
||||
import { Response } from "node-fetch"
|
||||
import * as path from "path"
|
||||
import { clean, tmpdir } from "../../../utils/helpers"
|
||||
import * as httpserver from "../../../utils/httpserver"
|
||||
import * as integration from "../../../utils/integration"
|
||||
|
||||
interface WorkbenchConfig {
|
||||
folderUri?: {
|
||||
path: string
|
||||
}
|
||||
workspaceUri?: {
|
||||
path: string
|
||||
}
|
||||
}
|
||||
|
||||
describe("vscode", () => {
|
||||
let codeServer: httpserver.HttpServer | undefined
|
||||
|
||||
@@ -39,7 +29,7 @@ describe("vscode", () => {
|
||||
expect(resp.status).toBe(200)
|
||||
const html = await resp.text()
|
||||
const url = new URL(resp.url) // Check there were no redirections.
|
||||
expect(url.pathname + decodeURIComponent(url.search)).toBe(route)
|
||||
expect(url.pathname + url.search).toBe(route)
|
||||
switch (route) {
|
||||
case "/":
|
||||
case "/vscode/":
|
||||
@@ -52,52 +42,25 @@ describe("vscode", () => {
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Get the workbench config from the provided response.
|
||||
*/
|
||||
const getConfig = async (resp: Response): Promise<WorkbenchConfig> => {
|
||||
expect(resp.status).toBe(200)
|
||||
const html = await resp.text()
|
||||
const match = html.match(/<meta id="vscode-workbench-web-configuration" data-settings="(.+)">/)
|
||||
if (!match || !match[1]) {
|
||||
throw new Error("Unable to find workbench configuration")
|
||||
}
|
||||
const config = match[1].replace(/"/g, '"')
|
||||
try {
|
||||
return JSON.parse(config)
|
||||
} catch (error) {
|
||||
console.error("Failed to parse workbench configuration", config)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
it("should redirect to the passed in workspace using human-readable query", async () => {
|
||||
const workspace = path.join(await tmpdir(testName), "test.code-workspace")
|
||||
await fs.writeFile(workspace, "")
|
||||
codeServer = await integration.setup(["--auth=none", workspace], "")
|
||||
|
||||
it("should have no default folder or workspace", async () => {
|
||||
codeServer = await integration.setup(["--auth=none"], "")
|
||||
|
||||
const config = await getConfig(await codeServer.fetch("/"))
|
||||
expect(config.folderUri).toBeUndefined()
|
||||
expect(config.workspaceUri).toBeUndefined()
|
||||
const resp = await codeServer.fetch("/")
|
||||
const url = new URL(resp.url)
|
||||
expect(url.pathname).toBe("/")
|
||||
expect(url.search).toBe(`?workspace=${workspace}`)
|
||||
})
|
||||
|
||||
it("should have a default folder", async () => {
|
||||
const defaultDir = await tmpdir(testName)
|
||||
codeServer = await integration.setup(["--auth=none", defaultDir], "")
|
||||
it("should redirect to the passed in folder using human-readable query", async () => {
|
||||
const folder = await tmpdir(testName)
|
||||
codeServer = await integration.setup(["--auth=none", folder], "")
|
||||
|
||||
// At first it will load the directory provided on the command line.
|
||||
const config = await getConfig(await codeServer.fetch("/"))
|
||||
expect(config.folderUri?.path).toBe(defaultDir)
|
||||
expect(config.workspaceUri).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should have a default workspace", async () => {
|
||||
const defaultWorkspace = path.join(await tmpdir(testName), "test.code-workspace")
|
||||
await fs.writeFile(defaultWorkspace, "")
|
||||
codeServer = await integration.setup(["--auth=none", defaultWorkspace], "")
|
||||
|
||||
// At first it will load the workspace provided on the command line.
|
||||
const config = await getConfig(await codeServer.fetch("/"))
|
||||
expect(config.folderUri).toBeUndefined()
|
||||
expect(config.workspaceUri?.path).toBe(defaultWorkspace)
|
||||
const resp = await codeServer.fetch("/")
|
||||
const url = new URL(resp.url)
|
||||
expect(url.pathname).toBe("/")
|
||||
expect(url.search).toBe(`?folder=${folder}`)
|
||||
})
|
||||
|
||||
it("should redirect to last query folder/workspace", async () => {
|
||||
@@ -105,6 +68,7 @@ describe("vscode", () => {
|
||||
|
||||
const folder = await tmpdir(testName)
|
||||
const workspace = path.join(await tmpdir(testName), "test.code-workspace")
|
||||
await fs.writeFile(workspace, "")
|
||||
let resp = await codeServer.fetch("/", undefined, {
|
||||
folder,
|
||||
workspace,
|
||||
@@ -118,7 +82,7 @@ describe("vscode", () => {
|
||||
resp = await codeServer.fetch(route)
|
||||
const url = new URL(resp.url)
|
||||
expect(url.pathname).toBe(route)
|
||||
expect(decodeURIComponent(url.search)).toBe(`?folder=${folder}&workspace=${workspace}`)
|
||||
expect(url.search).toBe(`?folder=${folder}&workspace=${workspace}`)
|
||||
await resp.text()
|
||||
}
|
||||
|
||||
@@ -126,13 +90,24 @@ describe("vscode", () => {
|
||||
resp = await codeServer.fetch("/", undefined, { ew: "true" })
|
||||
let url = new URL(resp.url)
|
||||
expect(url.pathname).toBe("/")
|
||||
expect(decodeURIComponent(url.search)).toBe("?ew=true")
|
||||
expect(url.search).toBe("?ew=true")
|
||||
await resp.text()
|
||||
|
||||
resp = await codeServer.fetch("/")
|
||||
url = new URL(resp.url)
|
||||
expect(url.pathname).toBe("/")
|
||||
expect(decodeURIComponent(url.search)).toBe("")
|
||||
expect(url.search).toBe("")
|
||||
await resp.text()
|
||||
})
|
||||
|
||||
it("should do nothing when nothing is passed in", async () => {
|
||||
codeServer = await integration.setup(["--auth=none"], "")
|
||||
|
||||
let resp = await codeServer.fetch("/", undefined)
|
||||
|
||||
expect(resp.status).toBe(200)
|
||||
const url = new URL(resp.url)
|
||||
expect(url.search).toBe("")
|
||||
await resp.text()
|
||||
})
|
||||
|
||||
@@ -141,6 +116,8 @@ describe("vscode", () => {
|
||||
|
||||
const folder = await tmpdir(testName)
|
||||
const workspace = path.join(await tmpdir(testName), "test.code-workspace")
|
||||
await fs.writeFile(workspace, "")
|
||||
|
||||
let resp = await codeServer.fetch("/", undefined, {
|
||||
folder,
|
||||
workspace,
|
||||
@@ -152,7 +129,7 @@ describe("vscode", () => {
|
||||
resp = await codeServer.fetch("/")
|
||||
const url = new URL(resp.url)
|
||||
expect(url.pathname).toBe("/")
|
||||
expect(decodeURIComponent(url.search)).toBe("")
|
||||
expect(url.search).toBe("")
|
||||
await resp.text()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { logger } from "@coder/logger"
|
||||
import * as http from "http"
|
||||
import { AddressInfo } from "net"
|
||||
import * as path from "path"
|
||||
import { SettingsProvider, UpdateSettings } from "../../../src/node/settings"
|
||||
import { LatestResponse, UpdateProvider } from "../../../src/node/update"
|
||||
import { clean, mockLogger, tmpdir } from "../../utils/helpers"
|
||||
import { clean, isAddressInfo, mockLogger, tmpdir } from "../../utils/helpers"
|
||||
|
||||
describe("update", () => {
|
||||
let version = "1.0.0"
|
||||
@@ -23,6 +25,46 @@ describe("update", () => {
|
||||
return response.end(JSON.stringify(latest))
|
||||
}
|
||||
|
||||
if (request.url === "/reject-status-code") {
|
||||
response.writeHead(500)
|
||||
return response.end("rejected status code test")
|
||||
}
|
||||
|
||||
if (request.url === "/no-location-header") {
|
||||
response.writeHead(301, "testing", {
|
||||
location: "",
|
||||
})
|
||||
return response.end("rejected status code test")
|
||||
}
|
||||
|
||||
if (request.url === "/with-location-header") {
|
||||
response.writeHead(301, "testing", {
|
||||
location: "/latest",
|
||||
})
|
||||
|
||||
return response.end()
|
||||
}
|
||||
|
||||
// Checks if url matches /redirect/${number}
|
||||
// with optional trailing slash
|
||||
const match = request.url.match(/\/redirect\/([0-9]+)\/?$/)
|
||||
if (match) {
|
||||
if (request.url === "/redirect/0") {
|
||||
response.writeHead(200)
|
||||
return response.end("done")
|
||||
}
|
||||
|
||||
// Subtract 1 from the current redirect number
|
||||
// i.e. /redirect/10 -> /redirect/9 -> /redirect/8
|
||||
const currentRedirectNumber = parseInt(match[1])
|
||||
const newRedirectNumber = currentRedirectNumber - 1
|
||||
|
||||
response.writeHead(302, "testing", {
|
||||
location: `/redirect/${String(newRedirectNumber)}`,
|
||||
})
|
||||
return response.end("")
|
||||
}
|
||||
|
||||
// Anything else is a 404.
|
||||
response.writeHead(404)
|
||||
response.end("not found")
|
||||
@@ -37,6 +79,7 @@ describe("update", () => {
|
||||
}
|
||||
|
||||
let _provider: UpdateProvider | undefined
|
||||
let _address: string | AddressInfo | null
|
||||
const provider = (): UpdateProvider => {
|
||||
if (!_provider) {
|
||||
throw new Error("Update provider has not been created")
|
||||
@@ -62,12 +105,12 @@ describe("update", () => {
|
||||
})
|
||||
})
|
||||
|
||||
const address = server.address()
|
||||
if (!address || typeof address === "string" || !address.port) {
|
||||
_address = server.address()
|
||||
if (!isAddressInfo(_address)) {
|
||||
throw new Error("unexpected address")
|
||||
}
|
||||
|
||||
_provider = new UpdateProvider(`http://${address.address}:${address.port}/latest`, _settings)
|
||||
_provider = new UpdateProvider(`http://${_address?.address}:${_address?.port}/latest`, _settings)
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
@@ -75,6 +118,7 @@ describe("update", () => {
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
spy = []
|
||||
})
|
||||
|
||||
@@ -170,4 +214,61 @@ describe("update", () => {
|
||||
expect(update.checked < Date.now() && update.checked >= now).toEqual(true)
|
||||
expect(update.version).toStrictEqual("unknown")
|
||||
})
|
||||
|
||||
it("should reject if response has status code 500", async () => {
|
||||
if (isAddressInfo(_address)) {
|
||||
const mockURL = `http://${_address.address}:${_address.port}/reject-status-code`
|
||||
const provider = new UpdateProvider(mockURL, settings())
|
||||
const update = await provider.getUpdate(true)
|
||||
|
||||
expect(update.version).toBe("unknown")
|
||||
expect(logger.error).toHaveBeenCalled()
|
||||
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
|
||||
identifier: "error",
|
||||
value: `${mockURL}: 500`,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it("should reject if no location header provided", async () => {
|
||||
if (isAddressInfo(_address)) {
|
||||
const mockURL = `http://${_address.address}:${_address.port}/no-location-header`
|
||||
const provider = new UpdateProvider(mockURL, settings())
|
||||
const update = await provider.getUpdate(true)
|
||||
|
||||
expect(update.version).toBe("unknown")
|
||||
expect(logger.error).toHaveBeenCalled()
|
||||
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
|
||||
identifier: "error",
|
||||
value: `received redirect with no location header`,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it("should resolve the request with response.headers.location", async () => {
|
||||
version = "4.1.1"
|
||||
if (isAddressInfo(_address)) {
|
||||
const mockURL = `http://${_address.address}:${_address.port}/with-location-header`
|
||||
const provider = new UpdateProvider(mockURL, settings())
|
||||
const update = await provider.getUpdate(true)
|
||||
|
||||
expect(logger.error).not.toHaveBeenCalled()
|
||||
expect(update.version).toBe("4.1.1")
|
||||
}
|
||||
})
|
||||
|
||||
it("should reject if more than 10 redirects", async () => {
|
||||
if (isAddressInfo(_address)) {
|
||||
const mockURL = `http://${_address.address}:${_address.port}/redirect/11`
|
||||
const provider = new UpdateProvider(mockURL, settings())
|
||||
const update = await provider.getUpdate(true)
|
||||
|
||||
expect(update.version).toBe("unknown")
|
||||
expect(logger.error).toHaveBeenCalled()
|
||||
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
|
||||
identifier: "error",
|
||||
value: `reached max redirects`,
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -104,6 +104,10 @@ describe("hash", () => {
|
||||
const hashed = await util.hash(plainTextPassword)
|
||||
expect(hashed).not.toBe(plainTextPassword)
|
||||
})
|
||||
it("should return a hash for an empty string", async () => {
|
||||
const hashed = await util.hash("")
|
||||
expect(hashed).not.toBe("")
|
||||
})
|
||||
})
|
||||
|
||||
describe("isHashMatch", () => {
|
||||
@@ -137,16 +141,16 @@ describe("isHashMatch", () => {
|
||||
const actual = await util.isHashMatch(password, _hash)
|
||||
expect(actual).toBe(false)
|
||||
})
|
||||
it("should return false if the hash doesn't start with a $", async () => {
|
||||
it("should return false and not throw an error if the hash doesn't start with a $", async () => {
|
||||
const password = "hellowpasssword"
|
||||
const _hash = "n2i$v=19$m=4096,t=3,p=1$EAoczTxVki21JDfIZpTUxg$rkXgyrW4RDGoDYrxBFD4H2DlSMEhP4h+Api1hXnGnFY"
|
||||
expect(async () => await util.isHashMatch(password, _hash)).not.toThrow()
|
||||
expect(await util.isHashMatch(password, _hash)).toBe(false)
|
||||
})
|
||||
it("should return false if the password and hash don't match", async () => {
|
||||
it("should reject the promise and throw if error", async () => {
|
||||
const password = "hellowpasssword"
|
||||
const _hash = "$ar2i"
|
||||
const actual = await util.isHashMatch(password, _hash)
|
||||
expect(actual).toBe(false)
|
||||
expect(async () => await util.isHashMatch(password, _hash)).rejects.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -105,3 +105,17 @@ export function idleTimer(message: string, reject: (error: Error) => void, delay
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function which returns a boolean indicating whether
|
||||
* the given address is AddressInfo and has .address
|
||||
* and a .port property.
|
||||
*/
|
||||
export function isAddressInfo(address: unknown): address is net.AddressInfo {
|
||||
return (
|
||||
address !== null &&
|
||||
typeof address !== "string" &&
|
||||
(address as net.AddressInfo).port !== undefined &&
|
||||
(address as net.AddressInfo).address !== undefined
|
||||
)
|
||||
}
|
||||
|
||||
197
test/yarn.lock
197
test/yarn.lock
@@ -478,6 +478,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
|
||||
integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
|
||||
|
||||
"@jest-mock/express@^1.4.5":
|
||||
version "1.4.5"
|
||||
resolved "https://registry.yarnpkg.com/@jest-mock/express/-/express-1.4.5.tgz#437db24ccd505d88f8c0d73e8593fa3cd6eb273b"
|
||||
integrity sha512-bERM1jnutyH7VMahdaOHAKy7lgX47zJ7+RTz2eMz0wlCttd9CkhsKFEyoWmJBSz/ow0nVj3lCuRqLem4QDYFkQ==
|
||||
|
||||
"@jest/console@^27.4.6":
|
||||
version "27.4.6"
|
||||
resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.4.6.tgz#0742e6787f682b22bdad56f9db2a8a77f6a86107"
|
||||
@@ -647,6 +652,26 @@
|
||||
"@types/yargs" "^16.0.0"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@mapbox/node-pre-gyp@^1.0.8":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz#32abc8a5c624bc4e46c43d84dfb8b26d33a96f58"
|
||||
integrity sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==
|
||||
dependencies:
|
||||
detect-libc "^1.0.3"
|
||||
https-proxy-agent "^5.0.0"
|
||||
make-dir "^3.1.0"
|
||||
node-fetch "^2.6.5"
|
||||
nopt "^5.0.0"
|
||||
npmlog "^5.0.1"
|
||||
rimraf "^3.0.2"
|
||||
semver "^7.3.5"
|
||||
tar "^6.1.11"
|
||||
|
||||
"@phc/format@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@phc/format/-/format-1.0.0.tgz#b5627003b3216dc4362125b13f48a4daa76680e4"
|
||||
integrity sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==
|
||||
|
||||
"@playwright/test@^1.16.3":
|
||||
version "1.17.2"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.17.2.tgz#0c67e329a28ffe43a79dc15a0e139dadd9cb250f"
|
||||
@@ -865,6 +890,11 @@ abab@^2.0.3, abab@^2.0.5:
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
|
||||
integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
acorn-globals@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
|
||||
@@ -934,6 +964,29 @@ anymatch@^3.0.3:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
"aproba@^1.0.3 || ^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
|
||||
integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
|
||||
|
||||
are-we-there-yet@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c"
|
||||
integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==
|
||||
dependencies:
|
||||
delegates "^1.0.0"
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
argon2@^0.28.0:
|
||||
version "0.28.4"
|
||||
resolved "https://registry.yarnpkg.com/argon2/-/argon2-0.28.4.tgz#af6df523b839a78b3cfbfdbfa789ffa2c6672d9f"
|
||||
integrity sha512-WsfqiDp/tf5+eieLc1+S7RtO7Y3cAiZQ1F6GIaskENoJy/6xuCN5WGBIc8dG7QVPDavy6jUSads8zwZTtrHVag==
|
||||
dependencies:
|
||||
"@mapbox/node-pre-gyp" "^1.0.8"
|
||||
"@phc/format" "^1.0.0"
|
||||
node-addon-api "^4.3.0"
|
||||
opencollective-postinstall "^2.0.3"
|
||||
|
||||
argparse@^1.0.7:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||
@@ -1129,6 +1182,11 @@ char-regex@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
|
||||
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
|
||||
|
||||
chownr@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
|
||||
integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
|
||||
|
||||
ci-info@^3.2.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2"
|
||||
@@ -1182,6 +1240,11 @@ color-name@~1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-support@^1.1.2:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
|
||||
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
|
||||
|
||||
colors@1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
|
||||
@@ -1209,6 +1272,11 @@ concat-map@0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
console-control-strings@^1.0.0, console-control-strings@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
||||
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
|
||||
|
||||
convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
|
||||
@@ -1307,6 +1375,16 @@ delayed-stream@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
delegates@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||
|
||||
detect-libc@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
|
||||
|
||||
detect-newline@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
|
||||
@@ -1521,6 +1599,13 @@ formidable@^2.0.1:
|
||||
once "1.4.0"
|
||||
qs "6.9.3"
|
||||
|
||||
fs-minipass@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
|
||||
integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
@@ -1536,6 +1621,21 @@ function-bind@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
gauge@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395"
|
||||
integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==
|
||||
dependencies:
|
||||
aproba "^1.0.3 || ^2.0.0"
|
||||
color-support "^1.1.2"
|
||||
console-control-strings "^1.0.0"
|
||||
has-unicode "^2.0.1"
|
||||
object-assign "^4.1.1"
|
||||
signal-exit "^3.0.0"
|
||||
string-width "^4.2.3"
|
||||
strip-ansi "^6.0.1"
|
||||
wide-align "^1.1.2"
|
||||
|
||||
gensync@^1.0.0-beta.2:
|
||||
version "1.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||
@@ -1609,6 +1709,11 @@ has-symbols@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
|
||||
integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
|
||||
|
||||
has-unicode@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
||||
integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
|
||||
|
||||
has@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
@@ -2338,7 +2443,7 @@ lru-cache@^6.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
make-dir@^3.0.0:
|
||||
make-dir@^3.0.0, make-dir@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
|
||||
integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
|
||||
@@ -2409,6 +2514,26 @@ minimist@^1.2.5:
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
minipass@^3.0.0:
|
||||
version "3.1.6"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee"
|
||||
integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
minizlib@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
|
||||
integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
yallist "^4.0.0"
|
||||
|
||||
mkdirp@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
@@ -2424,6 +2549,11 @@ natural-compare@^1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
|
||||
|
||||
node-addon-api@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
|
||||
integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
|
||||
|
||||
node-fetch@2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
@@ -2436,6 +2566,13 @@ node-fetch@^2.6.1:
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.6.5:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-int64@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
||||
@@ -2446,6 +2583,13 @@ node-releases@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
|
||||
integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==
|
||||
|
||||
nopt@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
|
||||
integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
normalize-path@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
@@ -2458,11 +2602,26 @@ npm-run-path@^4.0.1:
|
||||
dependencies:
|
||||
path-key "^3.0.0"
|
||||
|
||||
npmlog@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0"
|
||||
integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==
|
||||
dependencies:
|
||||
are-we-there-yet "^2.0.0"
|
||||
console-control-strings "^1.1.0"
|
||||
gauge "^3.0.0"
|
||||
set-blocking "^2.0.0"
|
||||
|
||||
nwsapi@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
|
||||
integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==
|
||||
|
||||
object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-inspect@^1.9.0:
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
|
||||
@@ -2506,6 +2665,11 @@ open@^8.3.0:
|
||||
is-docker "^2.1.1"
|
||||
is-wsl "^2.2.0"
|
||||
|
||||
opencollective-postinstall@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259"
|
||||
integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==
|
||||
|
||||
optionator@^0.8.1:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
|
||||
@@ -2802,6 +2966,11 @@ semver@^6.0.0, semver@^6.3.0:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
set-blocking@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
set-value@^4.0.1:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/set-value/-/set-value-4.1.0.tgz#aa433662d87081b75ad88a4743bd450f044e7d09"
|
||||
@@ -2831,6 +3000,11 @@ side-channel@^1.0.4:
|
||||
get-intrinsic "^1.0.2"
|
||||
object-inspect "^1.9.0"
|
||||
|
||||
signal-exit@^3.0.0:
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
||||
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
|
||||
|
||||
signal-exit@^3.0.2, signal-exit@^3.0.3:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af"
|
||||
@@ -2918,7 +3092,7 @@ string-length@^4.0.1:
|
||||
char-regex "^1.0.2"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
string-width@^4.1.0, string-width@^4.2.0:
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@@ -3015,6 +3189,18 @@ symbol-tree@^3.2.4:
|
||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
|
||||
|
||||
tar@^6.1.11, tar@^6.1.9:
|
||||
version "6.1.11"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
|
||||
integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
|
||||
dependencies:
|
||||
chownr "^2.0.0"
|
||||
fs-minipass "^2.0.0"
|
||||
minipass "^3.0.0"
|
||||
minizlib "^2.1.1"
|
||||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
terminal-link@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994"
|
||||
@@ -3204,6 +3390,13 @@ which@^2.0.1:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wide-align@^1.1.2:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
|
||||
integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
|
||||
dependencies:
|
||||
string-width "^1.0.2 || 2 || 3 || 4"
|
||||
|
||||
word-wrap@~1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
||||
|
||||
2
vendor/package.json
vendored
2
vendor/package.json
vendored
@@ -7,6 +7,6 @@
|
||||
"postinstall": "./postinstall.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"code-oss-dev": "coder/vscode#d4f09b4df0d23ead4389b4a69c6fad86ac358892"
|
||||
"code-oss-dev": "coder/vscode#94384412221f432c15bb679315c49964925090be"
|
||||
}
|
||||
}
|
||||
|
||||
4
vendor/yarn.lock
vendored
4
vendor/yarn.lock
vendored
@@ -274,9 +274,9 @@ clone-response@^1.0.2:
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
code-oss-dev@coder/vscode#d4f09b4df0d23ead4389b4a69c6fad86ac358892:
|
||||
code-oss-dev@coder/vscode#94384412221f432c15bb679315c49964925090be:
|
||||
version "1.63.0"
|
||||
resolved "https://codeload.github.com/coder/vscode/tar.gz/d4f09b4df0d23ead4389b4a69c6fad86ac358892"
|
||||
resolved "https://codeload.github.com/coder/vscode/tar.gz/94384412221f432c15bb679315c49964925090be"
|
||||
dependencies:
|
||||
"@microsoft/applicationinsights-web" "^2.6.4"
|
||||
"@parcel/watcher" "2.0.3"
|
||||
|
||||
281
yarn.lock
281
yarn.lock
@@ -235,89 +235,20 @@
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
|
||||
integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
|
||||
|
||||
"@node-rs/argon2-android-arm-eabi@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-1.0.5.tgz#3e290b1ed5c403f98059bee0380394a915c6020d"
|
||||
integrity sha512-gRRQGxo/k4sYpybFP5Ss79KfIkspqeC2EdicGfl1Kpd/h3YSH+32QL1UNPzeHPx00MCjFeefnt1bI/hocND22w==
|
||||
|
||||
"@node-rs/argon2-android-arm64@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-android-arm64/-/argon2-android-arm64-1.0.5.tgz#72c5c6cdb5ba8c73438ac1bf0ad6a9da9bf8b15a"
|
||||
integrity sha512-f4kLb4BW8cTbde64BEEfSGL5febnsrD+zfPkSgWYRfaiKrGbp0O8DT2KICL+Jkh/4lMRRsgS8n8+pcp68dZK0A==
|
||||
|
||||
"@node-rs/argon2-darwin-arm64@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-1.0.5.tgz#2c04416956789538f413458154076b0a9516bd11"
|
||||
integrity sha512-QwK8RJscTK09r+mB/QEMxvtkEIjWxfx7p7rW7xFAEYWUEt3ztClEDcKqReFJN9EidNBaANMIzmMLwd5GVCxqNg==
|
||||
|
||||
"@node-rs/argon2-darwin-x64@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-darwin-x64/-/argon2-darwin-x64-1.0.5.tgz#ef68ba7939344c441249f6d42b4821901b9280f2"
|
||||
integrity sha512-P2fDqZU6isyEK7HviC22ccriGP5t2yWZ9jJtkPCyTj0JJooEUwdJDcPezIzJPYoiiV/gMS2LIyAVCWaqG05FEQ==
|
||||
|
||||
"@node-rs/argon2-freebsd-x64@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-freebsd-x64/-/argon2-freebsd-x64-1.0.5.tgz#e2f72e655f955c75a2900182fd533eecdcbb68ad"
|
||||
integrity sha512-nMp+XoA9Me0/JMP3zN7+XUlmVVaMx1fjR6sVIqnswBAHk9WkUBA2mTTleyXroTFXifnsu7o7K4cOZq1bNap1VA==
|
||||
|
||||
"@node-rs/argon2-linux-arm-gnueabihf@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-linux-arm-gnueabihf/-/argon2-linux-arm-gnueabihf-1.0.5.tgz#2823d42a093194a920870a18f40375db6064b903"
|
||||
integrity sha512-mpyUFFze0WhV6FP5Ms1mFL8ABhoVeEw/a2AquTNtwQgMzWvp4Jcjo81fXZ+LP3pzgcrQUQqyDosf7EKC6BnPCA==
|
||||
|
||||
"@node-rs/argon2-linux-arm64-gnu@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-linux-arm64-gnu/-/argon2-linux-arm64-gnu-1.0.5.tgz#0f3799dca9b4cae7757f8241fd9b36f05762aa0c"
|
||||
integrity sha512-XRVEX5/WHGN2UxSvBDi0pAQxZ7q5oCvyb9aDJBjmEcXvwwnm+292N6NKG0suC6N4nmGoy1iy5EWvZnnDecU1tg==
|
||||
|
||||
"@node-rs/argon2-linux-arm64-musl@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-linux-arm64-musl/-/argon2-linux-arm64-musl-1.0.5.tgz#a1e3a9a0d949c008734f5e51c4be0e6fd9a315d8"
|
||||
integrity sha512-kciIicrBlPaCwlOabTuCgbAMtHnGNi4Tdf4tVhx+NtdC8elZYa4yzRXZQhPTkekM06bmHCh/qIlB+herVe8fWw==
|
||||
|
||||
"@node-rs/argon2-linux-x64-gnu@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-linux-x64-gnu/-/argon2-linux-x64-gnu-1.0.5.tgz#aa1b9c4eb90807cf6cce5939de58a22a5fe325c4"
|
||||
integrity sha512-uKIL5qap0YyYXTJAbHcuHFMvNHQF8F4tE00B/dlRQNjQl/FurXvBtzE3aN77zMIMI2bEMsG9OKEGD9JzDEhKVw==
|
||||
|
||||
"@node-rs/argon2-linux-x64-musl@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-linux-x64-musl/-/argon2-linux-x64-musl-1.0.5.tgz#ac3b075911ef9489f4d487014801cda26171bcb8"
|
||||
integrity sha512-KFkHW1slATnnfH5fHuryOhJS2k7aU9hwb5oZlwVoUHrQ9SE5leXcbgaTDyq1+uu4zE21nPB499EOXFxkKLdQWA==
|
||||
|
||||
"@node-rs/argon2-win32-arm64-msvc@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-win32-arm64-msvc/-/argon2-win32-arm64-msvc-1.0.5.tgz#9fcb64dd936306d637e460433321d8af8a618243"
|
||||
integrity sha512-tL/ClEzxAGOAu1ItiUV5zAnkRk8QcNKjLke85Rm7VxANoOQoM+nVtpV9KUdXHHBbTwucBkoJKZiklNyoT0GWrA==
|
||||
|
||||
"@node-rs/argon2-win32-ia32-msvc@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-win32-ia32-msvc/-/argon2-win32-ia32-msvc-1.0.5.tgz#3289a3777ca3584a71a1e0436d7011cb9bbb734d"
|
||||
integrity sha512-GFPmzdIBBPhdC8QJtO07vi9J/fAnF+W+4VhBpmdo370FWgD6jXJZV6X6Zj/v14suG2DsJrP5JAq6/iT4NM9piA==
|
||||
|
||||
"@node-rs/argon2-win32-x64-msvc@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2-win32-x64-msvc/-/argon2-win32-x64-msvc-1.0.5.tgz#6a05e9fd5926a6faa99374ad4fce3fec5f887b2e"
|
||||
integrity sha512-bao8NPLd8/49jROzl0g8cH//oP4nKk3lwhhWJ8entz1c6Gm49oAKSeGEzjnh9bUCJXLTkwqxgvlkw30QgMeqHA==
|
||||
|
||||
"@node-rs/argon2@^1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/argon2/-/argon2-1.0.5.tgz#d864c2801447a5e1125a470b36a702730c65816f"
|
||||
integrity sha512-lWnG4nNEGMosKbEuhZzHIS/S4tanxVkBXDlEslMj5gx4ibIcpxklJZKD6hUEdBp8YnIfiyzA340bWVbD4SPhbg==
|
||||
optionalDependencies:
|
||||
"@node-rs/argon2-android-arm-eabi" "1.0.5"
|
||||
"@node-rs/argon2-android-arm64" "1.0.5"
|
||||
"@node-rs/argon2-darwin-arm64" "1.0.5"
|
||||
"@node-rs/argon2-darwin-x64" "1.0.5"
|
||||
"@node-rs/argon2-freebsd-x64" "1.0.5"
|
||||
"@node-rs/argon2-linux-arm-gnueabihf" "1.0.5"
|
||||
"@node-rs/argon2-linux-arm64-gnu" "1.0.5"
|
||||
"@node-rs/argon2-linux-arm64-musl" "1.0.5"
|
||||
"@node-rs/argon2-linux-x64-gnu" "1.0.5"
|
||||
"@node-rs/argon2-linux-x64-musl" "1.0.5"
|
||||
"@node-rs/argon2-win32-arm64-msvc" "1.0.5"
|
||||
"@node-rs/argon2-win32-ia32-msvc" "1.0.5"
|
||||
"@node-rs/argon2-win32-x64-msvc" "1.0.5"
|
||||
"@mapbox/node-pre-gyp@^1.0.8":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz#32abc8a5c624bc4e46c43d84dfb8b26d33a96f58"
|
||||
integrity sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==
|
||||
dependencies:
|
||||
detect-libc "^1.0.3"
|
||||
https-proxy-agent "^5.0.0"
|
||||
make-dir "^3.1.0"
|
||||
node-fetch "^2.6.5"
|
||||
nopt "^5.0.0"
|
||||
npmlog "^5.0.1"
|
||||
rimraf "^3.0.2"
|
||||
semver "^7.3.5"
|
||||
tar "^6.1.11"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.4":
|
||||
version "2.1.4"
|
||||
@@ -340,6 +271,11 @@
|
||||
"@nodelib/fs.scandir" "2.1.4"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@phc/format@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@phc/format/-/format-1.0.0.tgz#b5627003b3216dc4362125b13f48a4daa76680e4"
|
||||
integrity sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==
|
||||
|
||||
"@schemastore/package@^0.0.6":
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@schemastore/package/-/package-0.0.6.tgz#9a76713da1c7551293b7e72e4f387f802bfd5d81"
|
||||
@@ -649,6 +585,11 @@ JSONStream@^1.3.5:
|
||||
jsonparse "^1.2.0"
|
||||
through ">=2.2.7 <3"
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
accepts@~1.3.5, accepts@~1.3.7:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
||||
@@ -662,11 +603,21 @@ acorn-jsx@^5.3.1:
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
|
||||
integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
|
||||
|
||||
acorn-walk@^8.2.0:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
||||
|
||||
acorn@^7.4.0:
|
||||
version "7.4.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||
|
||||
acorn@^8.7.0:
|
||||
version "8.7.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
|
||||
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
|
||||
|
||||
agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
|
||||
@@ -725,11 +676,34 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
|
||||
"aproba@^1.0.3 || ^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
|
||||
integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
|
||||
|
||||
are-we-there-yet@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c"
|
||||
integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==
|
||||
dependencies:
|
||||
delegates "^1.0.0"
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
arg@^4.1.0:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
||||
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||
|
||||
argon2@^0.28.0:
|
||||
version "0.28.4"
|
||||
resolved "https://registry.yarnpkg.com/argon2/-/argon2-0.28.4.tgz#af6df523b839a78b3cfbfdbfa789ffa2c6672d9f"
|
||||
integrity sha512-WsfqiDp/tf5+eieLc1+S7RtO7Y3cAiZQ1F6GIaskENoJy/6xuCN5WGBIc8dG7QVPDavy6jUSads8zwZTtrHVag==
|
||||
dependencies:
|
||||
"@mapbox/node-pre-gyp" "^1.0.8"
|
||||
"@phc/format" "^1.0.0"
|
||||
node-addon-api "^4.3.0"
|
||||
opencollective-postinstall "^2.0.3"
|
||||
|
||||
argparse@^1.0.7:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||
@@ -1066,6 +1040,11 @@ color-name@~1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-support@^1.1.2:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
|
||||
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
|
||||
|
||||
colorette@^1.2.1, colorette@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
|
||||
@@ -1096,6 +1075,11 @@ concat-map@0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
console-control-strings@^1.0.0, console-control-strings@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
||||
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
|
||||
|
||||
content-disposition@0.5.3:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
|
||||
@@ -1253,6 +1237,11 @@ degenerator@^3.0.1:
|
||||
esprima "^4.0.0"
|
||||
vm2 "^3.9.3"
|
||||
|
||||
delegates@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||
|
||||
depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
@@ -1263,6 +1252,11 @@ destroy@~1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||
|
||||
detect-libc@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
|
||||
|
||||
diff@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
@@ -1735,7 +1729,7 @@ execall@^2.0.0:
|
||||
dependencies:
|
||||
clone-regexp "^2.1.0"
|
||||
|
||||
express@^5.0.0-alpha.8:
|
||||
express@5.0.0-alpha.8:
|
||||
version "5.0.0-alpha.8"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-5.0.0-alpha.8.tgz#b9dd3a568eab791e3391db47f9e6ab91e61b13fe"
|
||||
integrity sha512-PL8wTLgaNOiq7GpXt187/yWHkrNSfbr4H0yy+V0fpqJt5wpUzBi9DprAkwGKBFOqWHylJ8EyPy34V5u9YArfng==
|
||||
@@ -1895,10 +1889,10 @@ flatted@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469"
|
||||
integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
|
||||
|
||||
follow-redirects@^1.0.0, follow-redirects@^1.14.7:
|
||||
version "1.14.7"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
|
||||
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
|
||||
follow-redirects@^1.0.0, follow-redirects@^1.14.8:
|
||||
version "1.14.8"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
|
||||
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
|
||||
|
||||
format@^0.2.0:
|
||||
version "0.2.2"
|
||||
@@ -1959,6 +1953,21 @@ functional-red-black-tree@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
|
||||
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
|
||||
|
||||
gauge@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395"
|
||||
integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==
|
||||
dependencies:
|
||||
aproba "^1.0.3 || ^2.0.0"
|
||||
color-support "^1.1.2"
|
||||
console-control-strings "^1.0.0"
|
||||
has-unicode "^2.0.1"
|
||||
object-assign "^4.1.1"
|
||||
signal-exit "^3.0.0"
|
||||
string-width "^4.2.3"
|
||||
strip-ansi "^6.0.1"
|
||||
wide-align "^1.1.2"
|
||||
|
||||
gensync@^1.0.0-beta.2:
|
||||
version "1.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||
@@ -2140,6 +2149,11 @@ has-tostringtag@^1.0.0:
|
||||
dependencies:
|
||||
has-symbols "^1.0.2"
|
||||
|
||||
has-unicode@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
||||
integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
|
||||
|
||||
has@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
@@ -2726,6 +2740,13 @@ lru-cache@^6.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
make-dir@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
|
||||
integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
|
||||
dependencies:
|
||||
semver "^6.0.0"
|
||||
|
||||
make-error@^1.1.1:
|
||||
version "1.3.6"
|
||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||
@@ -2955,7 +2976,12 @@ netmask@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7"
|
||||
integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==
|
||||
|
||||
node-fetch@^2.6.1, node-fetch@^2.6.7:
|
||||
node-addon-api@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
|
||||
integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
|
||||
|
||||
node-fetch@^2.6.1, node-fetch@^2.6.5, node-fetch@^2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||
@@ -2967,6 +2993,13 @@ node-releases@^1.1.71:
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
|
||||
integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==
|
||||
|
||||
nopt@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
|
||||
integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0, normalize-package-data@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.1.tgz#98dc56dfe6755d99b1c53f046e1e3d2dde55a1c7"
|
||||
@@ -2987,11 +3020,26 @@ normalize-selector@^0.2.0:
|
||||
resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03"
|
||||
integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=
|
||||
|
||||
npmlog@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0"
|
||||
integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==
|
||||
dependencies:
|
||||
are-we-there-yet "^2.0.0"
|
||||
console-control-strings "^1.1.0"
|
||||
gauge "^3.0.0"
|
||||
set-blocking "^2.0.0"
|
||||
|
||||
num2fraction@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
|
||||
integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=
|
||||
|
||||
object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-inspect@^1.11.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1"
|
||||
@@ -3046,6 +3094,11 @@ once@^1.3.0:
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
opencollective-postinstall@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259"
|
||||
integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==
|
||||
|
||||
optionator@^0.8.1:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
|
||||
@@ -3516,7 +3569,7 @@ readable-stream@1.1.x:
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readable-stream@^3.1.1:
|
||||
readable-stream@^3.1.1, readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
@@ -3697,7 +3750,7 @@ safe-compare@^1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
semver@^6.3.0:
|
||||
semver@^6.0.0, semver@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
@@ -3738,6 +3791,11 @@ serve-static@1.14.1:
|
||||
parseurl "~1.3.3"
|
||||
send "0.17.1"
|
||||
|
||||
set-blocking@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
setprototypeof@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
|
||||
@@ -3779,6 +3837,11 @@ side-channel@^1.0.4:
|
||||
get-intrinsic "^1.0.2"
|
||||
object-inspect "^1.9.0"
|
||||
|
||||
signal-exit@^3.0.0:
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
||||
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
|
||||
|
||||
signal-exit@^3.0.2:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||
@@ -3911,6 +3974,15 @@ stream-events@^1.0.5:
|
||||
dependencies:
|
||||
stubs "^3.0.0"
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
|
||||
@@ -3955,6 +4027,13 @@ strip-ansi@^6.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^5.0.0"
|
||||
|
||||
strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-bom@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
|
||||
@@ -4086,7 +4165,7 @@ table@^6.0.9, table@^6.6.0:
|
||||
string-width "^4.2.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
tar@^6.1.9:
|
||||
tar@^6.1.11, tar@^6.1.9:
|
||||
version "6.1.11"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
|
||||
integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
|
||||
@@ -4460,10 +4539,13 @@ vfile@^4.0.0:
|
||||
unist-util-stringify-position "^2.0.0"
|
||||
vfile-message "^2.0.0"
|
||||
|
||||
vm2@^3.9.3, vm2@^3.9.4:
|
||||
version "3.9.5"
|
||||
resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.5.tgz#5288044860b4bbace443101fcd3bddb2a0aa2496"
|
||||
integrity sha512-LuCAHZN75H9tdrAiLFf030oW7nJV5xwNMuk1ymOZwopmuK3d2H4L1Kv4+GFHgarKiLfXXLFU+7LDABHnwOkWng==
|
||||
vm2@^3.9.3, vm2@^3.9.6:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.7.tgz#bb87aa677c97c61e23a6cb6547e44e990517a6f6"
|
||||
integrity sha512-g/GZ7V0Mlmch3eDVOATvAXr1GsJNg6kQ5PjvYy3HbJMCRn5slNbo/u73Uy7r5yUej1cRa3ZjtoVwcWSQuQ/fow==
|
||||
dependencies:
|
||||
acorn "^8.7.0"
|
||||
acorn-walk "^8.2.0"
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
@@ -4503,6 +4585,13 @@ which@^2.0.1, which@^2.0.2:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wide-align@^1.1.2:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
|
||||
integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
|
||||
dependencies:
|
||||
string-width "^1.0.2 || 2 || 3 || 4"
|
||||
|
||||
word-wrap@^1.2.3, word-wrap@~1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
||||
|
||||
Reference in New Issue
Block a user