diff --git a/.eslintrc.yaml b/.eslintrc.yaml
deleted file mode 100644
index 738b0ee2050a..000000000000
--- a/.eslintrc.yaml
+++ /dev/null
@@ -1,44 +0,0 @@
-parser: "@typescript-eslint/parser"
-env:
- browser: true
- es6: true # Map, etc.
- mocha: true
- node: true
-
-parserOptions:
- ecmaVersion: 2018
- sourceType: module
-
-extends:
- - eslint:recommended
- - plugin:@typescript-eslint/recommended
- - plugin:import/recommended
- - plugin:import/typescript
- - plugin:prettier/recommended
- - prettier # Removes eslint rules that conflict with prettier.
- - prettier/@typescript-eslint # Remove conflicts again.
-
-rules:
- # Sometimes you need to add args to implement a function signature even
- # if they are unused.
- "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }]
- # For overloads.
- no-dupe-class-members: off
- "@typescript-eslint/no-use-before-define": off
- "@typescript-eslint/no-non-null-assertion": off
- "@typescript-eslint/ban-types": off
- "@typescript-eslint/no-var-requires": off
- "@typescript-eslint/explicit-module-boundary-types": off
- "@typescript-eslint/no-explicit-any": off
- eqeqeq: error
- import/order:
- [error, { alphabetize: { order: "asc" }, groups: [["builtin", "external", "internal"], "parent", "sibling"] }]
- no-async-promise-executor: off
- # This isn't a real module, just types, which apparently doesn't resolve.
- import/no-unresolved: [error, { ignore: ["express-serve-static-core"] }]
-
-settings:
- # Does not work with CommonJS unfortunately.
- import/ignore:
- - env-paths
- - xdg-basedir
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 000000000000..793a923d16eb
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,2 @@
+# Prettier 3.4.2
+9b0340a09276f93c054d705d1b9a5f24cc5dbc97
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000000..dc5caf936908
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.afdesign filter=lfs diff=lfs merge=lfs -text
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index ee281990ca73..04718d97bc09 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,3 +1,7 @@
-* @code-asher @nhooyr
+* @coder/code-server
-ci/helm-chart @Matthew-Beckett @alexgorbatchev
+ci/helm-chart/ @Matthew-Beckett @alexgorbatchev
+
+docs/install.md @GNUxeava
+
+src/node/i18n/locales/zh-cn.json @zhaozhiming
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
deleted file mode 100644
index a9d70644b214..000000000000
--- a/.github/ISSUE_TEMPLATE/bug-report.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-name: Bug report
-about: Report a bug and help us improve
-title: ""
-labels: ""
-assignees: ""
----
-
-
-
-- Web Browser:
-- Local OS:
-- Remote OS:
-- Remote Architecture:
-- `code-server --version`:
diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml
new file mode 100644
index 000000000000..c43d5c65e23b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.yml
@@ -0,0 +1,126 @@
+name: Bug report
+description: File a bug report
+labels: ["bug", "triage"]
+body:
+ - type: checkboxes
+ attributes:
+ label: Is there an existing issue for this?
+ description: Please search to see if an issue already exists for the bug you encountered.
+ options:
+ - label: I have searched the existing issues
+ required: true
+
+ - type: textarea
+ attributes:
+ label: OS/Web Information
+ description: |
+ examples:
+ - **Web Browser**: Chrome
+ - **Local OS**: macOS
+ - **Remote OS**: Ubuntu
+ - **Remote Architecture**: amd64
+ - **`code-server --version`**: 4.0.1
+
+ Please do not just put "latest" for the version.
+ value: |
+ - Web Browser:
+ - Local OS:
+ - Remote OS:
+ - Remote Architecture:
+ - `code-server --version`:
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Steps to Reproduce
+ description: |
+ Please describe exactly how to reproduce the bug. For example:
+ 1. Open code-server in Firefox
+ 2. Install extension `foo.bar` from the extensions sidebar
+ 3. Run command `foo.bar.baz`
+ value: |
+ 1.
+ 2.
+ 3.
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Expected
+ description: What should happen?
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Actual
+ description: What actually happens?
+ validations:
+ required: true
+
+ - type: textarea
+ id: logs
+ attributes:
+ label: Logs
+ description: Run code-server with the --verbose flag and then paste any relevant logs from the server, from the browser console and/or the browser network tab. For issues with installation, include installation logs (i.e. output of `npm install -g code-server`).
+ render: shell
+
+ - type: textarea
+ attributes:
+ label: Screenshot/Video
+ description: Please include a screenshot, gif or screen recording of your issue.
+ validations:
+ required: false
+
+ - type: dropdown
+ attributes:
+ label: Does this bug reproduce in native VS Code?
+ description: If the bug reproduces in native VS Code, submit the issue upstream instead (https://github.com/microsoft/vscode).
+ options:
+ - Yes, this is also broken in native VS Code
+ - No, this works as expected in native VS Code
+ - This cannot be tested in native VS Code
+ - I did not test native VS Code
+ validations:
+ required: true
+
+ - type: dropdown
+ attributes:
+ label: Does this bug reproduce in VS Code web?
+ description: If the bug reproduces in VS Code web, submit the issue upstream instead (https://github.com/microsoft/vscode). You can run VS Code web with `code serve-web` (this is not the same as vscode.dev).
+ options:
+ - Yes, this is also broken in VS Code web
+ - No, this works as expected in VS Code web
+ - This cannot be tested in VS Code web
+ - I did not test VS Code web
+ validations:
+ required: true
+
+ - type: dropdown
+ attributes:
+ label: Does this bug reproduce in GitHub Codespaces?
+ description: If the bug reproduces in GitHub Codespaces, submit the issue upstream instead (https://github.com/microsoft/vscode).
+ options:
+ - Yes, this is also broken in GitHub Codespaces
+ - No, this works as expected in GitHub Codespaces
+ - This cannot be tested in GitHub Codespaces
+ - I did not test GitHub Codespaces
+ validations:
+ required: true
+
+ - type: checkboxes
+ attributes:
+ label: Are you accessing code-server over a secure context?
+ description: code-server relies on service workers (which only work in secure contexts) for many features. Double-check that you are using a secure context like HTTPS or localhost.
+ options:
+ - label: I am using a secure context.
+ required: false
+
+ - type: textarea
+ attributes:
+ label: Notes
+ description: Please include any addition notes that will help us resolve this issue.
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 2f567fce310b..e24498346339 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,8 +1,8 @@
blank_issues_enabled: false
contact_links:
- - name: Question
- url: https://github.com/cdr/code-server/discussions/new?category_id=22503114
+ - name: Question?
+ url: https://github.com/coder/code-server/discussions/new?category_id=22503114
about: Ask the community for help on our GitHub Discussions board
- - name: Chat
- about: Need immediate help or just want to talk? Hop in our Slack
+ - name: code-server Slack Community
+ about: Need immediate help or just want to talk? Hop in our Slack. Note - this Slack is not actively monitored by code-server maintainers.
url: https://cdr.co/join-community
diff --git a/.github/ISSUE_TEMPLATE/doc.md b/.github/ISSUE_TEMPLATE/doc.md
index ba63b11bdf8f..75240e7f7631 100644
--- a/.github/ISSUE_TEMPLATE/doc.md
+++ b/.github/ISSUE_TEMPLATE/doc.md
@@ -1,7 +1,11 @@
---
name: Documentation improvement
about: Suggest a documentation improvement
-title: ""
labels: "docs"
-assignees: ""
---
+
+## What is your suggestion?
+
+## How will this improve the docs?
+
+## Are you interested in submitting a PR for this?
diff --git a/.github/ISSUE_TEMPLATE/extension-request.md b/.github/ISSUE_TEMPLATE/extension-request.md
deleted file mode 100644
index 5ed3e159ce8f..000000000000
--- a/.github/ISSUE_TEMPLATE/extension-request.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-name: Extension request
-about: Request an extension missing from the code-server marketplace
-title: ""
-labels: extension-request
-assignees: cmoog
----
-
-
-
-- [ ] Extension name:
-- [ ] Extension GitHub or homepage:
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
index 3f7411eefb6b..89837e3441e6 100644
--- a/.github/ISSUE_TEMPLATE/feature-request.md
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -1,13 +1,13 @@
---
name: Feature request
-about: Suggest an idea
-title: ""
-labels: feature
-assignees: ""
+about: Suggest an idea to improve code-server
+labels: enhancement
---
-
+## Why do you want this feature?
+
+## Are there any workarounds to get this functionality today?
+
+## Are you interested in submitting a PR for this?
diff --git a/.github/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE.md
similarity index 65%
rename from .github/pull_request_template.md
rename to .github/PULL_REQUEST_TEMPLATE.md
index 4cdeac9f7b66..e240a5f49c8d 100644
--- a/.github/pull_request_template.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -2,5 +2,7 @@
Please link to the issue this PR solves.
If there is no existing issue, please first create one unless the fix is minor.
-Please make sure the base of your PR is the master branch!
+Please make sure the base of your PR is the default branch!
-->
+
+Fixes #
diff --git a/.github/codecov.yml b/.github/codecov.yml
new file mode 100644
index 000000000000..c2e23821411d
--- /dev/null
+++ b/.github/codecov.yml
@@ -0,0 +1,31 @@
+codecov:
+ require_ci_to_pass: yes
+ allow_coverage_offsets: True
+
+coverage:
+ precision: 2
+ round: down
+ range: "40...70"
+ status:
+ patch: off
+ notify:
+ slack:
+ default:
+ url: secret:v1::tXC7VwEIKYjNU8HRgRv2GdKOSCt5UzpykKZb+o1eCDqBgb2PEqwE3A26QUPYMLo4BO2qtrJhFIvwhUvlPwyzDCNGoNiuZfXr0UeZZ0y1TcZu672R/NBNMwEPO/e1Ye0pHxjzKHnuH7HqbjFucox/RBQLtiL3J56SWGE3JtbkC6o=
+ threshold: 1%
+ only_pulls: false
+ branches:
+ - "main"
+
+parsers:
+ gcov:
+ branch_detection:
+ conditional: yes
+ loop: yes
+ method: no
+ macro: no
+
+comment:
+ layout: "reach,diff,flags,files,footer"
+ behavior: default
+ require_changes: no
diff --git a/.github/codeql-config.yml b/.github/codeql-config.yml
new file mode 100644
index 000000000000..9f98cc2a62b1
--- /dev/null
+++ b/.github/codeql-config.yml
@@ -0,0 +1 @@
+name: "code-server CodeQL config"
diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml
new file mode 100644
index 000000000000..87513b7cee1d
--- /dev/null
+++ b/.github/dependabot.yaml
@@ -0,0 +1,31 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "monthly"
+ time: "06:00"
+ timezone: "America/Chicago"
+ labels: []
+ commit-message:
+ prefix: "chore"
+
+ - package-ecosystem: "npm"
+ directory: "/"
+ schedule:
+ interval: "monthly"
+ time: "06:00"
+ timezone: "America/Chicago"
+ commit-message:
+ prefix: "chore"
+ labels: []
+ ignore:
+ # Ignore patch updates for all dependencies
+ - dependency-name: "*"
+ update-types:
+ - version-update:semver-patch
+ # Ignore major updates to Node.js types, because they need to
+ # correspond to the Node.js engine version
+ - dependency-name: "@types/node"
+ update-types:
+ - version-update:semver-major
diff --git a/.github/lock.yml b/.github/lock.yml
deleted file mode 100644
index 2dfb6cf38862..000000000000
--- a/.github/lock.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
-
-# Number of days of inactivity before a closed issue or pull request is locked
-daysUntilLock: 90
-
-# Skip issues and pull requests created before a given timestamp. Timestamp must
-# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
-skipCreatedBefore: false
-
-# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
-exemptLabels: []
-
-# Label to add before locking, such as `outdated`. Set to `false` to disable
-lockLabel: false
-
-# Comment to post before locking. Set to `false` to disable
-lockComment: >
- This thread has been automatically locked since there has not been
- any recent activity after it was closed. Please open a new issue for
- related bugs.
-
-# Assign `resolved` as the reason for locking. Set to `false` to disable
-setLockReason: true
-# Limit to only `issues` or `pulls`
-# only: issues
-
-# Optionally, specify configuration settings just for `issues` or `pulls`
-# issues:
-# exemptLabels:
-# - help-wanted
-# lockLabel: outdated
-
-# pulls:
-# daysUntilLock: 30
-
-# Repository to extend settings from
-# _extends: repo
diff --git a/.github/semantic.yaml b/.github/semantic.yaml
new file mode 100644
index 000000000000..55d345cc2ac9
--- /dev/null
+++ b/.github/semantic.yaml
@@ -0,0 +1,66 @@
+###############################################################################
+# This file configures "Semantic Pull Requests", which is documented here:
+# https://github.com/zeke/semantic-pull-requests
+###############################################################################
+
+# Scopes are optionally supplied after a 'type'. For example, in
+#
+# feat(docs): autostart ui
+#
+# '(docs)' is the scope. Scopes are used to signify where the change occurred.
+scopes:
+ # docs: changes to the code-server documentation.
+ - docs
+
+ # vendor: changes to vendored dependencies.
+ - vendor
+
+ # deps: changes to code-server's dependencies.
+ - deps
+
+ # cs: changes to code specific to code-server.
+ - cs
+
+ # cli: changes to the command-line interface.
+ - cli
+
+# We only check that the PR title is semantic. The PR title is automatically
+# applied to the "Squash & Merge" flow as the suggested commit message, so this
+# should suffice unless someone drastically alters the message in that flow.
+titleOnly: true
+
+# Types are the 'tag' types in a commit or PR title. For example, in
+#
+# chore: fix thing
+#
+# 'chore' is the type.
+types:
+ # A build of any kind.
+ - build
+
+ # A user-facing change that corrects a defect in code-server.
+ - fix
+
+ # Any code task that is ignored for changelog purposes. Examples include
+ # devbin scripts and internal-only configurations.
+ - chore
+
+ # Any work performed on CI.
+ - ci
+
+ # Work that directly implements or supports the implementation of a feature.
+ - feat
+
+ # A refactor changes code structure without any behavioral change.
+ - refactor
+
+ # A git revert for any style of commit.
+ - revert
+
+ # Adding tests of any kind. Should be separate from feature or fix
+ # 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
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 000000000000..945de5a3e12a
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,12 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 180
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 5
+# Label to apply when stale.
+staleLabel: stale
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ recent activity. It will be closed if no activity occurs in the next 5 days.
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
new file mode 100644
index 000000000000..def1c5c8201b
--- /dev/null
+++ b/.github/workflows/build.yaml
@@ -0,0 +1,299 @@
+name: Build
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ 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' }}
+
+jobs:
+ changes:
+ runs-on: ubuntu-latest
+ outputs:
+ ci: ${{ steps.filter.outputs.ci }}
+ code: ${{ steps.filter.outputs.code }}
+ deps: ${{ steps.filter.outputs.deps }}
+ docs: ${{ steps.filter.outputs.docs }}
+ helm: ${{ steps.filter.outputs.helm }}
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3
+ id: filter
+ with:
+ filters: |
+ ci:
+ - ".github/**"
+ - "ci/**"
+ docs:
+ - "docs/**"
+ - "README.md"
+ - "CHANGELOG.md"
+ helm:
+ - "ci/helm-chart/**"
+ code:
+ - "src/**"
+ - "test/**"
+ deps:
+ - "lib/**"
+ - "patches/**"
+ - "package-lock.json"
+ - "test/package-lock.json"
+ - id: debug
+ run: |
+ echo "${{ toJSON(steps.filter )}}"
+
+ prettier:
+ name: Run prettier check
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ test/package-lock.json
+ - run: SKIP_SUBMODULE_DEPS=1 npm ci
+ - run: npx prettier --check .
+
+ doctoc:
+ name: Doctoc markdown files
+ runs-on: ubuntu-22.04
+ needs: changes
+ if: needs.changes.outputs.docs == 'true'
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ test/package-lock.json
+ - run: SKIP_SUBMODULE_DEPS=1 npm ci
+ - run: npm run doctoc
+
+ lint-helm:
+ name: Lint Helm chart
+ runs-on: ubuntu-22.04
+ needs: changes
+ if: needs.changes.outputs.helm == 'true'
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ version: "v3.19.2"
+ - run: helm plugin install https://github.com/instrumenta/helm-kubeval
+ - run: helm kubeval ci/helm-chart
+
+ lint-ts:
+ name: Lint TypeScript files
+ runs-on: ubuntu-22.04
+ needs: changes
+ if: needs.changes.outputs.code == 'true'
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ test/package-lock.json
+ - run: SKIP_SUBMODULE_DEPS=1 npm ci
+ - run: npm run lint:ts
+
+ lint-actions:
+ name: Lint GitHub Actions
+ runs-on: ubuntu-latest
+ needs: changes
+ if: needs.changes.outputs.ci == 'true'
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - name: Check workflow files
+ run: |
+ bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.7.9
+ ./actionlint -color -shellcheck= -ignore "softprops/action-gh-release"
+ shell: bash
+
+ test-unit:
+ name: Run unit tests
+ runs-on: ubuntu-22.04
+ needs: changes
+ if: needs.changes.outputs.code == 'true'
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ test/package-lock.json
+ - run: SKIP_SUBMODULE_DEPS=1 npm ci
+ - run: npm run test:unit
+ - uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5
+ if: success()
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+
+ build:
+ name: linux-x64
+ runs-on: ubuntu-22.04
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ DISABLE_V8_COMPILE_CACHE: 1
+ VERSION: 0.0.0
+ VSCODE_TARGET: linux-x64
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ ELECTRON_SKIP_BINARY_DOWNLOAD: 1
+ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
+
+ steps:
+ - run: sudo apt update && sudo apt install -y libkrb5-dev
+ - uses: awalsh128/cache-apt-pkgs-action@2c09a5e66da6c8016428a2172bd76e5e4f14bb17 # latest
+ with:
+ packages: quilt
+ version: 1.0
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ submodules: true
+ - run: quilt push -a
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ test/package-lock.json
+ - run: SKIP_SUBMODULE_DEPS=1 npm ci
+ - run: npm run build
+ # Get Code's git hash. When this changes it means the content is
+ # different and we need to rebuild.
+ - name: Get latest lib/vscode rev
+ id: vscode-rev
+ run: echo "rev=$(git rev-parse HEAD:./lib/vscode)" >> $GITHUB_OUTPUT
+ # We need to rebuild when we have a new version of Code, when any of the
+ # patches changed, or when the code-server version changes (since it gets
+ # embedded into the code). Use VSCODE_CACHE_VERSION to force a rebuild.
+ - name: Fetch prebuilt linux-x64 Code package from cache
+ id: cache-vscode
+ uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ with:
+ path: lib/vscode-reh-web-linux-x64
+ key: vscode-linux-x64-package-${{ secrets.VSCODE_CACHE_VERSION }}-${{ steps.vscode-rev.outputs.rev }}-${{ hashFiles('patches/*.diff', 'ci/build/build-vscode.sh') }}
+ - name: Build vscode
+ if: steps.cache-vscode.outputs.cache-hit != 'true'
+ run: |
+ pushd lib/vscode
+ npm ci
+ popd
+ npm run build:vscode
+ # Push up an artifact containing the linux-x64 release.
+ - run: KEEP_MODULES=1 npm run release
+ - run: tar -czf package.tar.gz release
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
+ with:
+ name: linux-x64-package
+ path: ./package.tar.gz
+
+ test-e2e:
+ name: Run e2e tests
+ runs-on: ubuntu-22.04
+ env:
+ LOG_LEVEL: debug
+ needs: [changes, build]
+ if: needs.changes.outputs.code == 'true' || needs.changes.outputs.deps == 'true' || needs.changes.outputs.ci == 'true'
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ test/package-lock.json
+ - run: SKIP_SUBMODULE_DEPS=1 npm ci
+ - name: Install Playwright OS dependencies
+ run: |
+ ./test/node_modules/.bin/playwright install-deps
+ ./test/node_modules/.bin/playwright install
+
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
+ with:
+ name: linux-x64-package
+ - run: tar -xzf package.tar.gz
+
+ - run: CODE_SERVER_TEST_ENTRY=./release npm run test:e2e
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
+ if: always()
+ with:
+ name: failed-test-videos
+ path: ./test/test-results
+
+ test-e2e-proxy:
+ name: Run e2e tests behind proxy
+ runs-on: ubuntu-22.04
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ LOG_LEVEL: debug
+ needs: [changes, build]
+ if: needs.changes.outputs.code == 'true' || needs.changes.outputs.deps == 'true' || needs.changes.outputs.ci == 'true'
+
+ steps:
+ - name: Cache Caddy
+ uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
+ id: caddy-cache
+ with:
+ path: |
+ ~/.cache/caddy
+ key: cache-caddy-2.5.2
+ - name: Install Caddy
+ if: steps.caddy-cache.outputs.cache-hit != 'true'
+ run: |
+ gh release download v2.5.2 --repo caddyserver/caddy --pattern "caddy_2.5.2_linux_amd64.tar.gz"
+ mkdir -p ~/.cache/caddy
+ tar -xzf caddy_2.5.2_linux_amd64.tar.gz --directory ~/.cache/caddy
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ test/package-lock.json
+ - run: SKIP_SUBMODULE_DEPS=1 npm ci
+ - name: Install Playwright OS dependencies
+ run: |
+ ./test/node_modules/.bin/playwright install-deps
+ ./test/node_modules/.bin/playwright install
+
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
+ with:
+ name: linux-x64-package
+ - run: tar -xzf package.tar.gz
+
+ - run: ~/.cache/caddy/caddy start --config ./ci/Caddyfile
+ - run: CODE_SERVER_TEST_ENTRY=./release npm run test:e2e:proxy
+ - run: ~/.cache/caddy/caddy stop --config ./ci/Caddyfile
+ if: always()
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
+ if: always()
+ with:
+ name: failed-test-videos-proxy
+ path: ./test/test-results
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
deleted file mode 100644
index a265c98ef5e8..000000000000
--- a/.github/workflows/ci.yaml
+++ /dev/null
@@ -1,146 +0,0 @@
-name: ci
-
-on: [push]
-
-jobs:
- fmt:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v1
- - name: Run ./ci/steps/fmt.sh
- uses: ./ci/images/debian10
- with:
- args: ./ci/steps/fmt.sh
-
- lint:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v1
- - name: Run ./ci/steps/lint.sh
- uses: ./ci/images/debian10
- with:
- args: ./ci/steps/lint.sh
-
- test:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v1
- - name: Run ./ci/steps/test.sh
- uses: ./ci/images/debian10
- with:
- args: ./ci/steps/test.sh
-
- release:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v1
- - name: Run ./ci/steps/release.sh
- uses: ./ci/images/debian10
- with:
- args: ./ci/steps/release.sh
- - name: Upload npm package artifact
- uses: actions/upload-artifact@v2
- with:
- name: npm-package
- path: ./release-npm-package
-
- linux-amd64:
- needs: release
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v1
- - name: Download npm package
- uses: actions/download-artifact@v2
- with:
- name: npm-package
- path: ./release-npm-package
- - name: Run ./ci/steps/release-packages.sh
- uses: ./ci/images/centos7
- with:
- args: ./ci/steps/release-packages.sh
- - name: Upload release artifacts
- uses: actions/upload-artifact@v2
- with:
- name: release-packages
- path: ./release-packages
-
- linux-arm64:
- needs: release
- runs-on: ubuntu-arm64-latest
- steps:
- - uses: actions/checkout@v1
- - name: Download npm package
- uses: actions/download-artifact@v2
- with:
- name: npm-package
- path: ./release-npm-package
- - name: Run ./ci/steps/release-packages.sh
- uses: ./ci/images/centos7
- with:
- args: ./ci/steps/release-packages.sh
- - name: Upload release artifacts
- uses: actions/upload-artifact@v2
- with:
- name: release-packages
- path: ./release-packages
-
- macos-amd64:
- needs: release
- runs-on: macos-latest
- steps:
- - uses: actions/checkout@v1
- - name: Download npm package
- uses: actions/download-artifact@v2
- with:
- name: npm-package
- path: ./release-npm-package
- - run: ./ci/steps/release-packages.sh
- env:
- # Otherwise we get rate limited when fetching the ripgrep binary.
- # For whatever reason only MacOS needs it.
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Upload release artifacts
- uses: actions/upload-artifact@v2
- with:
- name: release-packages
- path: ./release-packages
-
- docker-amd64:
- runs-on: ubuntu-latest
- needs: linux-amd64
- steps:
- - uses: actions/checkout@v1
- - name: Download release package
- uses: actions/download-artifact@v2
- with:
- name: release-packages
- path: ./release-packages
- - name: Run ./ci/steps/build-docker-image.sh
- uses: ./ci/images/debian10
- with:
- args: ./ci/steps/build-docker-image.sh
- - name: Upload release image
- uses: actions/upload-artifact@v2
- with:
- name: release-images
- path: ./release-images
-
- docker-arm64:
- runs-on: ubuntu-arm64-latest
- needs: linux-arm64
- steps:
- - uses: actions/checkout@v1
- - name: Download release package
- uses: actions/download-artifact@v2
- with:
- name: release-packages
- path: ./release-packages
- - name: Run ./ci/steps/build-docker-image.sh
- uses: ./ci/images/centos7
- with:
- args: ./ci/steps/build-docker-image.sh
- - name: Upload release image
- uses: actions/upload-artifact@v2
- with:
- name: release-images
- path: ./release-images
diff --git a/.github/workflows/installer.yaml b/.github/workflows/installer.yaml
new file mode 100644
index 000000000000..a77a5fd61919
--- /dev/null
+++ b/.github/workflows/installer.yaml
@@ -0,0 +1,76 @@
+name: Installer integration
+
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - "install.sh"
+ - ".github/workflows/installer.yaml"
+ pull_request:
+ branches:
+ - main
+ paths:
+ - "install.sh"
+ - ".github/workflows/installer.yaml"
+
+# 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' }}
+
+permissions:
+ contents: read
+
+jobs:
+ ubuntu:
+ name: Test installer on Ubuntu
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+
+ - name: Install code-server
+ run: ./install.sh
+
+ - name: Test code-server was installed globally
+ run: code-server --help
+
+ alpine:
+ name: Test installer on Alpine
+ runs-on: ubuntu-latest
+ container: "alpine:3.17"
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+
+ - name: Install curl
+ run: apk add curl
+
+ - name: Add user
+ run: adduser coder --disabled-password
+
+ # Standalone should work without root.
+ - name: Test standalone to a non-existent prefix
+ run: su coder -c "./install.sh --method standalone --prefix /tmp/does/not/yet/exist"
+
+ # We do not actually have Alpine standalone builds so running code-server
+ # will not work.
+ - name: Test code-server was installed to prefix
+ run: test -f /tmp/does/not/yet/exist/bin/code-server
+
+ macos:
+ name: Test installer on macOS
+ runs-on: macos-latest
+
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+
+ - name: Install code-server
+ run: ./install.sh
+
+ - name: Test code-server was installed globally
+ run: code-server --help
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index 74540651f564..690a4faca492 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -1,31 +1,167 @@
-name: publish
+name: Publish code-server
on:
+ # Shows the manual trigger in GitHub UI
+ # helpful as a back-up in case the GitHub Actions Workflow fails
+ workflow_dispatch:
+ inputs:
+ version:
+ type: string
+ required: true
+
release:
- types: [published]
+ 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:
npm:
runs-on: ubuntu-latest
+ env:
+ TAG: ${{ inputs.version || github.ref_name }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+ NPM_ENVIRONMENT: "production"
+
steps:
- - uses: actions/checkout@v1
- - name: Run ./ci/steps/publish-npm.sh
- uses: ./ci/images/debian10
+ - name: Set version to tag without leading v
+ run: |
+ echo "VERSION=${TAG#v}" >> $GITHUB_ENV
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+
+ - uses: robinraju/release-downloader@28fc21f50d76778e7023361aa1f863e717d3d56f # v1.13
+ with:
+ repository: "coder/code-server"
+ tag: ${{ env.TAG }}
+ fileName: "package.tar.gz"
+ out-file-path: "release-npm-package"
+
+ - run: tar -xzf release-npm-package/package.tar.gz
+ - run: |
+ echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
+ pushd release
+ npm publish --tag latest --access public
+
+ aur:
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ env:
+ GH_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
+ TAG: ${{ inputs.version || github.ref_name }}
+
+ steps:
+ - name: Set version to tag without leading v
+ run: |
+ echo "VERSION=${TAG#v}" >> $GITHUB_ENV
+
+ - name: Checkout code-server-aur repo
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ repository: "cdrci/code-server-aur"
+ token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
+ ref: "master"
+
+ - name: Configure git
+ run: |
+ git config --global user.name cdrci
+ git config --global user.email opensource@coder.com
+
+ - name: Fetch and reset master
+ run: |
+ git remote add upstream https://github.com/coder/code-server-aur.git
+ git fetch upstream
+ git reset --hard upstream/master
+ git push --force
+
+ - name: Validate package
+ uses: heyhusen/archlinux-package-action@c9f94059ccbebe8710d31d582f33ef4e84fe575c # v3.0.0
with:
- args: ./ci/steps/publish-npm.sh
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+ pkgver: ${{ env.VERSION }}
+ updpkgsums: true
+ srcinfo: true
+
+ - name: Open PR
+ run: |
+ git checkout -b update-version-${{ env.VERSION }}
+ git add .
+ git commit -m "chore: updating version to ${{ env.VERSION }}"
+ git push -u origin $(git branch --show)
+ gh pr create --repo coder/code-server-aur --title "chore: bump version to ${{ env.VERSION }}" --body "PR opened by @$GITHUB_ACTOR" --assignee $GITHUB_ACTOR
docker:
runs-on: ubuntu-latest
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ TAG: ${{ inputs.version || github.ref_name }}
+
steps:
- - uses: actions/checkout@v1
- - name: Run ./ci/steps/push-docker-manifest.sh
- uses: ./ci/images/debian10
- with:
- args: ./ci/steps/push-docker-manifest.sh
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
- DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
+ - name: Set version to tag without leading v
+ run: |
+ echo "VERSION=${TAG#v}" >> $GITHUB_ENV
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
+ - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
+
+ - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
+ - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - uses: robinraju/release-downloader@28fc21f50d76778e7023361aa1f863e717d3d56f # v1.13
+ with:
+ repository: "coder/code-server"
+ tag: v${{ env.VERSION }}
+ fileName: "*.deb"
+ out-file-path: "release-packages"
+ - uses: robinraju/release-downloader@28fc21f50d76778e7023361aa1f863e717d3d56f # v1.13
+ with:
+ repository: "coder/code-server"
+ tag: v${{ env.VERSION }}
+ fileName: "*.rpm"
+ out-file-path: "release-packages"
+
+ - run: npm run publish:docker
+
+ repo:
+ runs-on: ubuntu-latest
+ env:
+ GH_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
+ TAG: ${{ inputs.version || github.ref_name }}
+ needs: docker
+
+ steps:
+ - name: Set version to tag without leading v
+ run: |
+ echo "VERSION=${TAG#v}" >> $GITHUB_ENV
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+
+ - run: ./ci/build/update-repo.sh
+
+ - name: Open PR
+ run: |
+ git config --global user.name cdrci
+ git config --global user.email opensource@coder.com
+ git checkout -b "helm/$VERSION"
+ git add .
+ git commit -m "Update to $VERSION"
+ git push -u origin "$(git branch --show)"
+ gh pr create \
+ --repo coder/code-server \
+ --body-file .cache/checklist \
+ --title "Update to $VERSION"
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
new file mode 100644
index 000000000000..49f8d543425e
--- /dev/null
+++ b/.github/workflows/release.yaml
@@ -0,0 +1,197 @@
+name: Draft release
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ type: string
+ required: true
+ pull_request_target:
+ types:
+ - closed
+ branches:
+ - main
+
+permissions:
+ contents: write # For creating releases.
+ discussions: write # For creating a discussion.
+
+# Cancel in-progress runs for pull requests when developers push
+# additional changes
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+
+jobs:
+ package-linux:
+ name: ${{ format('linux-{0}', matrix.vscode_arch) }}
+ runs-on: ubuntu-22.04
+ if: >-
+ (github.event_name == 'workflow_dispatch') ||
+ (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true && startsWith(github.head_ref, 'update/'))
+
+ strategy:
+ matrix:
+ include:
+ - npm_arch: x64
+ vscode_arch: x64
+ package_arch: amd64
+ - npm_arch: arm64
+ vscode_arch: arm64
+ package_arch: arm64
+ - npm_arch: arm
+ vscode_arch: armhf
+ package_arch: armv7l
+
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ ELECTRON_SKIP_BINARY_DOWNLOAD: 1
+ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
+ TAG: ${{ inputs.version || github.event.pull_request.head.ref || github.ref_name }}
+ # Set release package name.
+ ARCH: ${{ matrix.package_arch }}
+ # Cross-compile target.
+ VSCODE_ARCH: ${{ matrix.vscode_arch }}
+ npm_config_arch: ${{ matrix.npm_arch }}
+ # Ensure native modules are built from source to avoid prebuilds and use
+ # the correct version of glibc.
+ npm_config_build_from_source: true
+ # Gulp target name.
+ # TODO: Pull from VSCODE_ARCH instead.
+ VSCODE_TARGET: ${{ format('linux-{0}', matrix.vscode_arch) }}
+
+ steps:
+ - run: sudo apt update && sudo apt install -y libkrb5-dev
+ - uses: awalsh128/cache-apt-pkgs-action@2c09a5e66da6c8016428a2172bd76e5e4f14bb17 # latest
+ with:
+ packages: quilt
+ version: 1.0
+ - name: Install nfpm
+ run: |
+ mkdir -p ~/.local/bin
+ curl -sSfL https://github.com/goreleaser/nfpm/releases/download/v2.3.1/nfpm_2.3.1_`uname -s`_`uname -m`.tar.gz | tar -C ~/.local/bin -zxv nfpm
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
+
+ - name: Strip update/ and v from tag
+ run: |
+ version=${TAG#update/}
+ echo "VERSION=${version#v}" >> $GITHUB_ENV
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ submodules: true
+ - run: quilt push -a
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ test/package-lock.json
+
+ - name: Build
+ run: |
+ cd lib/vscode/build
+ npm ci
+ cd ..
+ source ./build/azure-pipelines/linux/setup-env.sh
+ # Run preinstall script before root dependencies are installed
+ # so that v8 headers are patched correctly for native modules.
+ node build/npm/preinstall.ts
+ cd ../..
+ npm ci
+ npm run build
+ npm run build:vscode
+
+ # Platform-agnostic NPM package.
+ - run: npm run release
+ if: ${{ matrix.vscode_arch == 'x64' }}
+ - run: tar -czf package.tar.gz release
+ if: ${{ matrix.vscode_arch == 'x64' }}
+ - run: |
+ sed "/^## Unreleased/,/^## / ! d" CHANGELOG.md | head -n -2 | tail -n +3 > .cache/release-notes
+ if: ${{ matrix.vscode_arch == 'x64' }}
+ - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
+ if: ${{ matrix.vscode_arch == 'x64' }}
+ with:
+ draft: true
+ discussion_category_name: "📣 Announcements"
+ files: package.tar.gz
+ tag_name: v${{ env.VERSION }}
+ name: v${{ env.VERSION }}
+ body_path: .cache/release-notes
+
+ # Platform-specific release.
+ - run: KEEP_MODULES=1 npm run release
+ - run: npm run package
+ - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
+ with:
+ draft: true
+ discussion_category_name: "📣 Announcements"
+ files: ./release-packages/*
+ tag_name: v${{ env.VERSION }}
+ name: v${{ env.VERSION }}
+
+ package-macos:
+ name: ${{ matrix.vscode_target }}
+ runs-on: ${{ matrix.os }}
+ if: >-
+ (github.event_name == 'workflow_dispatch') ||
+ (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true && startsWith(github.head_ref, 'update/'))
+ strategy:
+ matrix:
+ include:
+ - os: macos-15-intel
+ vscode_target: darwin-x64
+ - os: macos-latest
+ vscode_target: darwin-arm64
+ env:
+ VSCODE_TARGET: ${{ matrix.vscode_target }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ TAG: ${{ inputs.version || github.ref_name }}
+ # Ensure native modules are built from source to avoid prebuilds.
+ npm_config_build_from_source: true
+
+ steps:
+ # The version of node-gyp we use depends on distutils but it was removed
+ # in Python 3.12. It seems to be fixed in the latest node-gyp so when we
+ # next update Node we can probably remove this. For now, install
+ # setuptools since it contains distutils.
+ - run: brew install python-setuptools quilt
+ - name: Install nfpm
+ run: |
+ mkdir -p ~/.local/bin
+ curl -sSfL https://github.com/goreleaser/nfpm/releases/download/v2.3.1/nfpm_2.3.1_`uname -s`_`uname -m`.tar.gz | tar -C ~/.local/bin -zxv nfpm
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
+
+ - name: Strip update/ and v from tag
+ run: |
+ version=${TAG#update/}
+ echo "VERSION=${version#v}" >> $GITHUB_ENV
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ submodules: true
+ - run: quilt push -a
+ - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ test/package-lock.json
+
+ - run: npm ci
+ - run: npm run build
+ - run: npm run build:vscode
+ - run: KEEP_MODULES=1 npm run release
+ - run: npm run test:native
+
+ - run: npm run package
+ - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
+ with:
+ draft: true
+ discussion_category_name: "📣 Announcements"
+ files: ./release-packages/*
+ tag_name: v${{ env.VERSION }}
+ name: v${{ env.VERSION }}
diff --git a/.github/workflows/scripts.yaml b/.github/workflows/scripts.yaml
new file mode 100644
index 000000000000..4ebef47ea875
--- /dev/null
+++ b/.github/workflows/scripts.yaml
@@ -0,0 +1,67 @@
+name: Script unit tests
+
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - "**.sh"
+ - "**.bats"
+ pull_request:
+ branches:
+ - main
+ paths:
+ - "**.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
+ runs-on: ubuntu-latest
+ # This runs on Alpine to make sure we're testing with actual sh.
+ container: "alpine:3.17"
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+
+ - name: Install test utilities
+ run: apk add bats checkbashisms
+
+ - name: Check Bashisms
+ run: checkbashisms ./install.sh
+
+ - name: Run script unit tests
+ run: ./ci/dev/test-scripts.sh
+
+ lint:
+ name: Lint shell files
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+
+ - name: Install lint utilities
+ run: sudo apt install shellcheck
+
+ - name: Lint shell files
+ run: ./ci/dev/lint-scripts.sh
diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml
new file mode 100644
index 000000000000..ba4bcbba5da1
--- /dev/null
+++ b/.github/workflows/security.yaml
@@ -0,0 +1,92 @@
+name: Security
+
+on:
+ push:
+ branches: [main]
+ paths:
+ - "package.json"
+ pull_request:
+ paths:
+ - "package.json"
+ schedule:
+ # 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.
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+
+jobs:
+ audit:
+ name: Audit node modules
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ fetch-depth: 0
+
+ - name: Install Node.js
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version-file: .node-version
+
+ - name: Audit npm for vulnerabilities
+ run: npm audit
+ if: success()
+
+ trivy-scan-repo:
+ name: Scan repo with Trivy
+ permissions:
+ contents: read # for actions/checkout to fetch code
+ security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
+ runs-on: ubuntu-22.04
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ fetch-depth: 0
+
+ - name: Run Trivy vulnerability scanner in repo mode
+ uses: aquasecurity/trivy-action@314ff8b43182423b84c50b1670b0e10f858f2d98 # latest
+ with:
+ scan-type: "fs"
+ scan-ref: "."
+ ignore-unfixed: true
+ format: "template"
+ template: "@/contrib/sarif.tpl"
+ output: "trivy-repo-results.sarif"
+ severity: "HIGH,CRITICAL"
+
+ - name: Upload Trivy scan results to GitHub Security tab
+ uses: github/codeql-action/upload-sarif@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4
+ with:
+ sarif_file: "trivy-repo-results.sarif"
+
+ codeql-analyze:
+ permissions:
+ actions: read # for github/codeql-action/init to get workflow details
+ contents: read # for actions/checkout to fetch code
+ security-events: write # for github/codeql-action/autobuild to send a status report
+ name: Analyze with CodeQL
+ runs-on: ubuntu-22.04
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4
+ with:
+ config-file: ./.github/codeql-config.yml
+ languages: javascript
+
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4
diff --git a/.github/workflows/trivy-docker.yaml b/.github/workflows/trivy-docker.yaml
new file mode 100644
index 000000000000..98a8d8c4063f
--- /dev/null
+++ b/.github/workflows/trivy-docker.yaml
@@ -0,0 +1,63 @@
+name: Trivy Nightly Docker Scan
+
+on:
+ # Run scans if the workflow is modified, in order to test the
+ # workflow itself. This results in some spurious notifications,
+ # but seems okay for testing.
+ pull_request:
+ branches:
+ - main
+ paths:
+ - .github/workflows/trivy-docker.yaml
+
+ # Run scans against master whenever changes are merged.
+ push:
+ branches:
+ - main
+ paths:
+ - .github/workflows/trivy-docker.yaml
+
+ schedule:
+ - cron: "15 10 * * *"
+
+ workflow_dispatch:
+
+permissions:
+ actions: none
+ checks: none
+ contents: read
+ deployments: none
+ issues: none
+ packages: none
+ pull-requests: none
+ repository-projects: none
+ security-events: write
+ 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 }}
+
+jobs:
+ trivy-scan-image:
+ runs-on: ubuntu-22.04
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+
+ - name: Run Trivy vulnerability scanner in image mode
+ uses: aquasecurity/trivy-action@314ff8b43182423b84c50b1670b0e10f858f2d98 # latest
+ with:
+ image-ref: "docker.io/codercom/code-server:latest"
+ ignore-unfixed: true
+ format: "sarif"
+ output: "trivy-image-results.sarif"
+ severity: "HIGH,CRITICAL"
+
+ - name: Upload Trivy scan results to GitHub Security tab
+ uses: github/codeql-action/upload-sarif@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4
+ with:
+ sarif_file: "trivy-image-results.sarif"
diff --git a/.github/workflows/update.yaml b/.github/workflows/update.yaml
new file mode 100644
index 000000000000..3ea12c5d9e07
--- /dev/null
+++ b/.github/workflows/update.yaml
@@ -0,0 +1,72 @@
+name: Update code-server
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ type: string
+ required: true
+ schedule:
+ - cron: "0 16,21 * * *"
+
+jobs:
+ update:
+ runs-on: ubuntu-latest
+ env:
+ TAG: ${{ inputs.version }}
+ GH_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
+
+ steps:
+ - name: Fetch latest tag
+ if: env.TAG == ''
+ run: |
+ tag=$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/microsoft/vscode/releases/latest)
+ tag="${tag#https://github.com/microsoft/vscode/releases/tag/}"
+ echo "TAG=$tag" >> $GITHUB_ENV
+
+ - name: Remove leading v from tag
+ run: |
+ echo "VERSION=${TAG#v}" >> $GITHUB_ENV
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ submodules: true
+
+ - name: Check current version
+ id: check
+ run: |
+ commit="$(git -C lib/vscode rev-parse HEAD)"
+ if [[ $(git -C lib/vscode ls-remote --tags | grep "$commit") == */"$VERSION" ]] ; then
+ echo "$VERSION update has already been merged into $(git rev-parse --abbrev-ref HEAD)"
+ echo done=true >> $GITHUB_OUTPUT
+ elif git ls-remote --exit-code --heads origin "update/$VERSION" ; then
+ echo "There is already a PR for updating to $VERSION"
+ echo done=true >> $GITHUB_OUTPUT
+ else
+ echo "$VERSION update has not started yet"
+ echo done=false >> $GITHUB_OUTPUT
+ fi
+
+ - uses: awalsh128/cache-apt-pkgs-action@2c09a5e66da6c8016428a2172bd76e5e4f14bb17 # latest
+ if: steps.check.outputs.done == 'false'
+ with:
+ packages: quilt
+ version: 1.0
+
+ - run: ./ci/build/update-vscode.sh
+ if: steps.check.outputs.done == 'false'
+
+ - name: Open PR
+ if: steps.check.outputs.done == 'false'
+ run: |
+ git config --global user.name cdrci
+ git config --global user.email opensource@coder.com
+ git checkout -b "update/$VERSION"
+ git add .
+ git commit -m "Update Code to $VERSION"
+ git push -u origin "$(git branch --show)"
+ gh pr create \
+ --repo coder/code-server \
+ --title "Update Code to $VERSION" \
+ --body-file .cache/checklist \
+ --draft
diff --git a/.gitignore b/.gitignore
index 4929c46fb26a..7fea491b82ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,24 @@
.tsbuildinfo
.cache
-dist*
-out*
+/out*/
release/
-release-npm-package/
-release-standalone/
release-packages/
release-gcp/
release-images/
node_modules
-node-*
/plugins
/lib/coder-cloud-agent
.home
+coverage
+**/.DS_Store
+*.bak
+
+# Code packages itself here.
+/lib/vscode-reh-web-*
+
+# Failed e2e test videos are saved here
+test/test-results
+
+# Quilt's internal data.
+/.pc
+/patches/*.diff~
diff --git a/.gitmodules b/.gitmodules
index f2cdafc7aef4..9854a1b1dd30 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,3 @@
[submodule "lib/vscode"]
path = lib/vscode
url = https://github.com/microsoft/vscode
- ignore = dirty
diff --git a/.ignore b/.ignore
deleted file mode 100644
index a65b41774ad5..000000000000
--- a/.ignore
+++ /dev/null
@@ -1 +0,0 @@
-lib
diff --git a/.node-version b/.node-version
new file mode 100644
index 000000000000..32a2d7bd80d1
--- /dev/null
+++ b/.node-version
@@ -0,0 +1 @@
+22.22.1
diff --git a/.nvmrc b/.nvmrc
new file mode 120000
index 000000000000..070266a2687d
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+.node-version
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 000000000000..40cfb028f4d0
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,8 @@
+lib
+release-packages
+release
+helm-chart
+test/scripts
+test/e2e/extensions/test-extension
+.pc
+package-lock.json
diff --git a/.prettierrc.yaml b/.prettierrc.yaml
index a0634116d20d..b6114bf4613b 100644
--- a/.prettierrc.yaml
+++ b/.prettierrc.yaml
@@ -2,3 +2,5 @@ printWidth: 120
semi: false
trailingComma: all
arrowParens: always
+singleQuote: false
+useTabs: false
diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml
deleted file mode 100644
index af5c94bc4f3e..000000000000
--- a/.stylelintrc.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-extends:
- - stylelint-config-recommended
diff --git a/.tours/contributing.tour b/.tours/contributing.tour
new file mode 100644
index 000000000000..aaff2b500c99
--- /dev/null
+++ b/.tours/contributing.tour
@@ -0,0 +1,151 @@
+{
+ "$schema": "https://aka.ms/codetour-schema",
+ "title": "Contributing",
+ "steps": [
+ {
+ "directory": "src",
+ "line": 1,
+ "description": "Hello world! code-server's source code lives here in `src` (see the explorer). It's broadly arranged into browser code, Node code, and code shared between both."
+ },
+ {
+ "file": "src/node/entry.ts",
+ "line": 157,
+ "description": "code-server begins execution here. CLI arguments are parsed, special flags like --help are handled, then the HTTP server is started."
+ },
+ {
+ "file": "src/node/cli.ts",
+ "line": 28,
+ "description": "This describes all of the code-server CLI options and how they will be parsed."
+ },
+ {
+ "file": "src/node/cli.ts",
+ "line": 233,
+ "description": "Here's the actual CLI parser."
+ },
+ {
+ "file": "src/node/settings.ts",
+ "line": 1,
+ "description": "code-server maintains a settings file that is read and written here."
+ },
+ {
+ "file": "src/node/app.ts",
+ "line": 11,
+ "description": "The core of code-server are HTTP and web socket servers which are created here. They provide authentication, file access, an API, and serve web-based applications like VS Code."
+ },
+ {
+ "file": "src/node/wsRouter.ts",
+ "line": 38,
+ "description": "This is an analog to Express's Router that handles web socket routes."
+ },
+ {
+ "file": "src/node/http.ts",
+ "line": 1,
+ "description": "This file provides various HTTP utility functions."
+ },
+ {
+ "file": "src/node/coder_cloud.ts",
+ "line": 9,
+ "description": "The cloud agent spawned here provides the --link functionality."
+ },
+ {
+ "file": "src/node/heart.ts",
+ "line": 7,
+ "description": "code-server's heart beats to indicate recent activity.\n\nAlso documented here: [https://github.com/coder/code-server/blob/main/docs/FAQ.md#heartbeat-file](https://github.com/coder/code-server/blob/main/docs/FAQ.md#heartbeat-file)"
+ },
+ {
+ "file": "src/node/socket.ts",
+ "line": 13,
+ "description": "We pass sockets to child processes, however we can't pass TLS sockets so when code-server is handling TLS (via --cert) we use this to create a proxy that can be passed to the child."
+ },
+ {
+ "directory": "src/node/routes",
+ "line": 1,
+ "description": "code-server's routes live here in `src/node/routes` (see the explorer)."
+ },
+ {
+ "file": "src/node/routes/index.ts",
+ "line": 123,
+ "description": "The architecture of code-server allows it to be extended with applications via plugins. Each application is registered at its own route and handles requests at and below that route. Currently we have only VS Code (although it is not yet actually split out into a plugin)."
+ },
+ {
+ "file": "src/node/plugin.ts",
+ "line": 103,
+ "description": "The previously mentioned plugins are loaded here."
+ },
+ {
+ "file": "src/node/routes/apps.ts",
+ "line": 12,
+ "description": "This provides a list of the applications registered with code-server."
+ },
+ {
+ "file": "src/node/routes/domainProxy.ts",
+ "line": 18,
+ "description": "code-server provides a built-in proxy to help in developing web-based applications. This is the code for the domain-based proxy.\n\nAlso documented here: [https://github.com/coder/code-server/blob/main/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/coder/code-server/blob/main/docs/FAQ.md#how-do-i-securely-access-web-services)"
+ },
+ {
+ "file": "src/node/routes/pathProxy.ts",
+ "line": 19,
+ "description": "Here is the path-based version of the proxy.\n\nAlso documented here: [https://github.com/coder/code-server/blob/main/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/coder/code-server/blob/main/docs/FAQ.md#how-do-i-securely-access-web-services)"
+ },
+ {
+ "file": "src/node/proxy.ts",
+ "line": 4,
+ "description": "Both the domain and path proxy use the single proxy instance created here."
+ },
+ {
+ "file": "src/node/routes/health.ts",
+ "line": 5,
+ "description": "A simple endpoint that lets you see if code-server is up.\n\nAlso documented here: [https://github.com/coder/code-server/blob/main/docs/FAQ.md#healthz-endpoint](https://github.com/coder/code-server/blob/main/docs/FAQ.md#healthz-endpoint)"
+ },
+ {
+ "file": "src/node/routes/login.ts",
+ "line": 46,
+ "description": "code-server supports a password-based login here."
+ },
+ {
+ "file": "src/node/routes/static.ts",
+ "line": 16,
+ "description": "This serves static assets. Anything under the code-server directory can be fetched. Anything outside requires authentication."
+ },
+ {
+ "file": "src/node/routes/update.ts",
+ "line": 10,
+ "description": "This endpoint lets you query for the latest code-server version. It's used to power the update popup you see in VS Code."
+ },
+ {
+ "file": "src/node/routes/vscode.ts",
+ "line": 15,
+ "description": "This is the endpoint that serves VS Code's HTML, handles VS Code's websockets, and handles a few VS Code-specific endpoints for fetching static files."
+ },
+ {
+ "file": "src/node/vscode.ts",
+ "line": 13,
+ "description": "The actual VS Code spawn and initialization is handled here. VS Code runs in a separate child process. We communicate via IPC and by passing it web sockets."
+ },
+ {
+ "file": "src/browser/serviceWorker.ts",
+ "line": 1,
+ "description": "The service worker only exists to provide PWA functionality."
+ },
+ {
+ "directory": "src/browser/pages",
+ "line": 1,
+ "description": "HTML, CSS, and JavaScript for each page lives in here `src/browser/pages` (see the explorer). Currently our HTML uses a simple search and replace template system with variables that {{LOOK_LIKE_THIS}}."
+ },
+ {
+ "file": "src/browser/pages/vscode.html",
+ "line": 1,
+ "description": "The VS Code HTML is based off VS Code's own `workbench.html`."
+ },
+ {
+ "directory": "src/browser/media",
+ "line": 1,
+ "description": "Static images and the manifest live here in `src/browser/media` (see the explorer)."
+ },
+ {
+ "directory": "lib/vscode",
+ "line": 1,
+ "description": "code-server makes use of VS Code's frontend web/remote support. Most of the modifications implement the remote server since that portion of the code is closed source and not released with VS Code.\n\nWe also have a few bug fixes and have added some features (like client-side extensions). See [https://github.com/coder/code-server/blob/main/docs/CONTRIBUTING.md#modifications-to-vs-code](https://github.com/coder/code-server/blob/main/docs/CONTRIBUTING.md#modifications-to-vs-code) for a list.\n\nWe make an effort to keep the modifications as few as possible."
+ }
+ ]
+}
diff --git a/.tours/start-development.tour b/.tours/start-development.tour
new file mode 100644
index 000000000000..999adba06125
--- /dev/null
+++ b/.tours/start-development.tour
@@ -0,0 +1,26 @@
+{
+ "$schema": "https://aka.ms/codetour-schema",
+ "title": "Start Development",
+ "steps": [
+ {
+ "file": "package.json",
+ "line": 31,
+ "description": "## Commands\n\nTo start developing, make sure you have Node 16+ and the [required dependencies](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites) installed. Then, run the following commands:\n\n1. Install dependencies:\n>> npm\n\n3. Start development mode (and watch for changes):\n>> npm run watch"
+ },
+ {
+ "file": "src/node/app.ts",
+ "line": 68,
+ "description": "## Visit the web server\n\nIf all goes well, you should see something like this in your terminal. code-server should be live in development mode.\n\n---\n```bash\n[2020-12-09T21:03:37.156Z] info code-server 3.7.4 development\n[2020-12-09T21:03:37.157Z] info Using user-data-dir ~/.local/share/code-server\n[2020-12-09T21:03:37.165Z] info Using config file ~/.config/code-server/config.yaml\n[2020-12-09T21:03:37.165Z] info HTTP server listening on http://127.0.0.1:8080 \n[2020-12-09T21:03:37.165Z] info - Authentication is enabled\n[2020-12-09T21:03:37.165Z] info - Using password from ~/.config/code-server/config.yaml\n[2020-12-09T21:03:37.165Z] info - Not serving HTTPS\n```\n\n---\n\nIf you have the default configuration, you can access it at [http://localhost:8080](http://localhost:8080)."
+ },
+ {
+ "file": "src/browser/pages/login.html",
+ "line": 26,
+ "description": "## Make a change\n\nThis is the login page, let's make a change and see it update on our web server! Perhaps change the text :)\n\n```html\n
Modifying the login page 👨🏼💻
\n```\n\nReminder, you can likely preview at [http://localhost:8080](http://localhost:8080)"
+ },
+ {
+ "file": "src/node/app.ts",
+ "line": 62,
+ "description": "## That's it!\n\n\nThat's all there is to it! When this tour ends, your terminal session may stop, but just use `npm run watch` to start developing from here on out!\n\n\nIf you haven't already, be sure to check out these resources:\n- [Tour: Contributing](command:codetour.startTourByTitle?[\"Contributing\"])\n- [Docs: FAQ.md](https://github.com/coder/code-server/blob/main/docs/FAQ.md)\n- [Docs: CONTRIBUTING.md](https://github.com/coder/code-server/blob/main/docs/CONTRIBUTING.md)\n- [Community: GitHub Discussions](https://github.com/coder/code-server/discussions)\n- [Community: Slack](https://community.coder.com)"
+ }
+ ]
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000000..d58496da7ad1
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,1416 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+
+
+## Unreleased
+
+## [4.121.0](https://github.com/coder/code-server/releases/tag/v4.121.0) - 2026-05-20
+
+Code v1.121.0
+
+### Changed
+
+- Update to Code 1.121.0
+
+## [4.118.0](https://github.com/coder/code-server/releases/tag/v4.118.0) - 2026-05-06
+
+Code v1.118.0
+
+### Changed
+
+- Update to Code 1.118.0
+
+## [4.117.0](https://github.com/coder/code-server/releases/tag/v4.117.0) - 2026-04-22
+
+Code v1.117.0
+
+### Changed
+
+- Update to Code 1.117.0
+
+## [4.116.0](https://github.com/coder/code-server/releases/tag/v4.116.0) - 2026-04-16
+
+Code v1.116.0
+
+### Changed
+
+- Update to Code 1.116.0
+
+## [4.115.0](https://github.com/coder/code-server/releases/tag/v4.115.0) - 2026-04-08
+
+Code v1.115.0
+
+### Changed
+
+- Update to Code 1.115.0
+
+## [4.114.1](https://github.com/coder/code-server/releases/tag/v4.114.1) - 2026-04-06
+
+Code v1.114.0
+
+### Changed
+
+- Ensure native modules are built from source so they use the correct version of
+ glibc. This should bring down the requirement from 2.34 back down to 2.28.
+
+## [4.114.0](https://github.com/coder/code-server/releases/tag/v4.114.0) - 2026-04-04
+
+Code v1.114.0
+
+### Changed
+
+- Update to Code 1.114.0.
+
+## [4.113.1](https://github.com/coder/code-server/releases/tag/v4.113.1) - 2026-04-03
+
+Code v1.113.0
+
+This is a re-release of v4.113.0 but with the correct Node binaries for arm64
+and armv7l. Previously they were packaging the amd64 Node binary due to a
+mistake while refactoring CI to use more of the upstream build scripts.
+
+## [4.113.0](https://github.com/coder/code-server/releases/tag/v4.113.0) - 2026-04-02
+
+Code v1.113.0
+
+### Changed
+
+- Update to Code 1.113.0
+
+## [4.112.0](https://github.com/coder/code-server/releases/tag/v4.112.0) - 2026-03-19
+
+Code v1.112.0
+
+### Changed
+
+- Update to Code 1.112.0
+
+## [4.111.0](https://github.com/coder/code-server/releases/tag/v4.111.0) - 2026-03-11
+
+Code v1.111.0
+
+### Changed
+
+- Update to Code 1.111.0
+- `--app-name` now affects the error page title.
+
+## [4.110.1](https://github.com/coder/code-server/releases/tag/v4.110.1) - 2026-03-10
+
+Code v1.110.1
+
+### Changed
+
+- Update to Code 1.110.1
+
+## [4.110.0](https://github.com/coder/code-server/releases/tag/v4.110.0) - 2026-03-09
+
+Code v1.110.0
+
+### Changed
+
+- Update to Code 1.110.0
+
+## [4.109.5](https://github.com/coder/code-server/releases/tag/v4.109.5) - 2026-03-02
+
+Code v1.109.5
+
+### Changed
+
+- Update to Code 1.109.5
+
+## [4.109.2](https://github.com/coder/code-server/releases/tag/v4.109.2) - 2026-02-12
+
+Code v1.109.2
+
+### Changed
+
+- Update to Code 1.109.2
+
+## [4.109.0](https://github.com/coder/code-server/releases/tag/v4.109.0) - 2026-02-12
+
+Code v1.109.0
+
+### Changed
+
+- Update to Code 1.109.0
+
+## [4.108.2](https://github.com/coder/code-server/releases/tag/v4.108.2) - 2026-01-26
+
+Code v1.108.2
+
+### Changed
+
+- Update to Code 1.108.2
+
+## [4.108.1](https://github.com/coder/code-server/releases/tag/v4.108.1) - 2026-01-16
+
+Code v1.108.1
+
+### Changed
+
+- Update to Code 1.108.1
+
+## [4.108.0](https://github.com/coder/code-server/releases/tag/v4.108.0) - 2026-01-12
+
+Code v1.108.0
+
+### Changed
+
+- Update to Code 1.108.0
+
+## [4.107.1](https://github.com/coder/code-server/releases/tag/v4.107.1) - 2026-01-09
+
+Code v1.107.1
+
+### Changed
+
+- Update to Code 1.107.1
+
+## [4.107.0](https://github.com/coder/code-server/releases/tag/v4.107.0) - 2026-12-17
+
+Code v1.107.0
+
+### Changed
+
+- Update to Code 1.107.0
+
+### Added
+
+- New `--cookie-suffix` flag that can be used to add a suffix to the cookie when
+ using the built-in password authentication. You can use this to avoid
+ collisions with other instances of code-server.
+- Support a new property `authorizationHeaderToken` on the extension gallery
+ configuration. This will be added to marketplace requests as a bearer token
+ using the `Authorization` header.
+
+## [4.106.3](https://github.com/coder/code-server/releases/tag/v4.106.3) - 2025-12-01
+
+Code v1.106.3
+
+### Changed
+
+- Update to Code 1.106.3
+
+## [4.106.2](https://github.com/coder/code-server/releases/tag/v4.106.2) - 2025-11-19
+
+Code v1.106.2
+
+### Changed
+
+- Update to Code 1.106.2
+
+## [4.106.0](https://github.com/coder/code-server/releases/tag/v4.106.0) - 2025-11-19
+
+Code v1.106.0
+
+### Changed
+
+- Update to Code 1.106.0
+
+## [4.105.1](https://github.com/coder/code-server/releases/tag/v4.105.1) - 2025-10-20
+
+Code v1.105.1
+
+### Changed
+
+- Update to Code 1.105.1
+
+## [4.105.0](https://github.com/coder/code-server/releases/tag/v4.105.0) - 2025-10-17
+
+Code v1.105.0
+
+### Changed
+
+- Update to Code 1.105.0
+
+## [4.104.3](https://github.com/coder/code-server/releases/tag/v4.104.3) - 2025-10-07
+
+Code v1.104.3
+
+### Changed
+
+- Update to Code 1.104.3.
+
+## [4.104.2](https://github.com/coder/code-server/releases/tag/v4.104.2) - 2025-09-26
+
+Code v1.104.2
+
+### Changed
+
+- Update to Code 1.104.2.
+
+## [4.104.1](https://github.com/coder/code-server/releases/tag/v4.104.1) - 2025-09-19
+
+Code v1.104.1
+
+### Changed
+
+- Update to Code 1.104.1.
+
+## [4.104.0](https://github.com/coder/code-server/releases/tag/v4.104.0) - 2025-09-15
+
+Code v1.104.0
+
+### Fixed
+
+- Fix "extension not found" errors from Open VSX when trying to install the
+ latest version of an extension.
+
+### Changed
+
+- Update to Code 1.104.0.
+
+## [4.103.2](https://github.com/coder/code-server/releases/tag/v4.103.2) - 2025-08-25
+
+Code v1.103.2
+
+### Changed
+
+- Update to Code 1.103.2.
+
+## [4.103.1](https://github.com/coder/code-server/releases/tag/v4.103.1) - 2025-08-15
+
+Code v1.103.1
+
+### Changed
+
+- Update to Code 1.103.1.
+
+## [4.103.0](https://github.com/coder/code-server/releases/tag/v4.103.0) - 2025-08-12
+
+Code v1.103.0
+
+### Changed
+
+- Update to Code 1.103.0.
+
+## [4.102.2](https://github.com/coder/code-server/releases/tag/v4.102.2) - 2025-07-24
+
+Code v1.102.2
+
+### Changed
+
+- Update to Code 1.102.2.
+
+## [4.102.1](https://github.com/coder/code-server/releases/tag/v4.102.1) - 2025-07-17
+
+Code v1.102.1
+
+### Changed
+
+- Update to Code 1.102.1.
+
+## [4.102.0](https://github.com/coder/code-server/releases/tag/v4.102.0) - 2025-07-16
+
+Code v1.102.0
+
+### Changed
+
+- Update to Code 1.102.0.
+
+### Added
+
+- Custom strings can be configured using the `--i18n` flag set to a JSON
+ file. This can be used for either translation (and can be used alongside
+ `--locale`) or for customizing the strings. See
+ [./src/node/i18n/locales/en.json](./src/node/i18n/locales/en.json) for the
+ available keys.
+
+## [4.101.2](https://github.com/coder/code-server/releases/tag/v4.101.2) - 2025-06-25
+
+Code v1.101.2
+
+### Changed
+
+- Update to Code 1.101.2.
+
+### Fixed
+
+- Fix web views not loading due to 401 when requesting the service worker.
+
+## [4.101.1](https://github.com/coder/code-server/releases/tag/v4.101.1) - 2025-06-20
+
+Code v1.101.1
+
+### Changed
+
+- Update to Code 1.101.1.
+
+## [4.101.0](https://github.com/coder/code-server/releases/tag/v4.101.0) - 2025-06-20
+
+Code v1.101.0
+
+### Changed
+
+- Update to Code 1.101.0.
+
+## [4.100.3](https://github.com/coder/code-server/releases/tag/v4.100.3) - 2025-06-03
+
+Code v1.100.3
+
+### Changed
+
+- Update to Code 1.100.3.
+
+## [4.100.2](https://github.com/coder/code-server/releases/tag/v4.100.2) - 2025-05-15
+
+Code v1.100.2
+
+### Changed
+
+- Update to Code 1.100.2.
+
+## [4.100.1](https://github.com/coder/code-server/releases/tag/v4.100.1) - 2025-05-13
+
+Code v1.100.1
+
+### Changed
+
+- Update to Code 1.100.1.
+
+## [4.100.0](https://github.com/coder/code-server/releases/tag/v4.100.0) - 2025-05-12
+
+Code v1.100.0
+
+### Added
+
+- Trusted domains for links can now be set at run-time by configuring
+ `linkProtectionTrustedDomains` in the `lib/vscode/product.json` file or via
+ the `--link-protection-trusted-domains` flag.
+
+### Changed
+
+- Update to Code 1.100.0.
+- Disable extension signature verification, which previously was skipped by
+ default (the package used for verification is not available to OSS builds of
+ VS Code) but now reportedly throws hard errors making it impossible to install
+ extensions.
+
+### Fixed
+
+- Flags with repeatable options now work via the config file.
+
+## [4.99.4](https://github.com/coder/code-server/releases/tag/v4.99.4) - 2025-05-02
+
+Code v1.99.3
+
+### Security
+
+- Validate that ports in the path proxy are numbers, to prevent proxying to
+ arbitrary domains.
+
+## [4.99.3](https://github.com/coder/code-server/releases/tag/v4.99.3) - 2025-04-17
+
+Code v1.99.3
+
+### Added
+
+- Added `--skip-auth-preflight` flag to let preflight requests through the
+ proxy.
+
+### Changed
+
+- Update to Code 1.99.3.
+
+## [4.99.2](https://github.com/coder/code-server/releases/tag/v4.99.2) - 2025-04-10
+
+Code v1.99.2
+
+### Changed
+
+- Update to Code 1.99.2.
+
+## [4.99.1](https://github.com/coder/code-server/releases/tag/v4.99.1) - 2025-04-08
+
+Code v1.99.1
+
+### Changed
+
+- Update to Code 1.99.1.
+
+## [4.99.0](https://github.com/coder/code-server/releases/tag/v4.99.0) - 2025-04-07
+
+Code v1.99.0
+
+### Changed
+
+- Update to Code 1.99.0.
+
+## [4.98.0](https://github.com/coder/code-server/releases/tag/v4.98.0) - 2025-03-07
+
+Code v1.98.0
+
+### Changed
+
+- Update to Code 1.98.0.
+
+## [4.97.2](https://github.com/coder/code-server/releases/tag/v4.96.4) - 2025-02-18
+
+Code v1.97.2
+
+### Added
+
+- Added back macOS amd64 builds.
+
+### Changed
+
+- Update to Code 1.97.2.
+- Softened dark mode login page colors.
+
+## [4.96.4](https://github.com/coder/code-server/releases/tag/v4.96.4) - 2025-01-20
+
+Code v1.96.4
+
+### Changed
+
+- Update to Code 1.96.4.
+
+## [4.96.2](https://github.com/coder/code-server/releases/tag/v4.96.2) - 2024-12-20
+
+Code v1.96.2
+
+### Changed
+
+- Update to Code 1.96.2.
+
+## [4.96.1](https://github.com/coder/code-server/releases/tag/v4.96.1) - 2024-12-18
+
+Code v1.96.1
+
+### Added
+
+- Dark color scheme for login and error pages.
+
+### Changed
+
+- Update to Code 1.96.1.
+
+## [4.95.3](https://github.com/coder/code-server/releases/tag/v4.95.3) - 2024-11-18
+
+Code v1.95.3
+
+### Changed
+
+- Update to Code 1.95.3.
+
+## [4.95.2](https://github.com/coder/code-server/releases/tag/v4.95.2) - 2024-11-12
+
+Code v1.95.2
+
+### Changed
+
+- Update to Code 1.95.2.
+
+## [4.95.1](https://github.com/coder/code-server/releases/tag/v4.95.1) - 2024-11-06
+
+Code v1.95.1
+
+### Changed
+
+- Update to Code 1.95.1.
+
+## [4.93.1](https://github.com/coder/code-server/releases/tag/v4.93.1) - 2024-09-23
+
+Code v1.93.1
+
+### Changed
+
+- Updated to Code 1.93.1.
+
+### Added
+
+- Added `--abs-proxy-base-path` flag for when code-server is not at the root.
+
+## [4.92.2](https://github.com/coder/code-server/releases/tag/v4.92.2) - 2024-08-19
+
+Code v1.92.2
+
+### Breaking changes
+
+- Dropped a patch that changed the compile target from es2022 to es2020 because
+ it no longer works with the way VS Code uses static properties. This may break
+ older browsers, so those browsers will either have to be updated or use an
+ older version of code-server.
+
+### Changed
+
+- Updated to Code 1.92.2.
+
+## [4.91.0](https://github.com/coder/code-server/releases/tag/v4.91.0) - 2024-07-10
+
+Code v1.91.0
+
+### Changed
+
+- Updated to Code 1.91.0.
+
+## [4.90.3](https://github.com/coder/code-server/releases/tag/v4.90.3) - 2024-06-21
+
+Code v1.90.2
+
+### Changed
+
+- Updated to Code 1.90.2.
+
+### Fixed
+
+- When the log gets rotated it will no longer incorrectly be moved to a new
+ directory created in the current working directory named with a date.
+ Instead, the file itself is prepended with the date and kept in the same
+ directory, as originally intended.
+
+## [4.90.2](https://github.com/coder/code-server/releases/tag/v4.90.2) - 2024-06-14
+
+Code v1.90.1
+
+### Changed
+
+- Updated to Code 1.90.1.
+
+## [4.90.1](https://github.com/coder/code-server/releases/tag/v4.90.1) - 2024-06-12
+
+Code v1.90.0
+
+### Fixed
+
+- Cache a call to get CPU information used in telemetry that could result in a
+ lack responsiveness if it was particularly slow.
+
+## [4.90.0](https://github.com/coder/code-server/releases/tag/v4.90.0) - 2024-06-11
+
+Code v1.90.0
+
+### Changed
+
+- Updated to Code 1.90.0.
+- Updated Node to 20.11.1.
+
+### Added
+
+- Send contents to the clipboard in the integrated terminal by piping to
+ `code-server --stdin-to-clipboard` or `code-server -c`.
+
+ You may want to make this an alias:
+
+ ```
+ alias xclip="code-server --stdin-to-clipboard"
+ echo -n "hello world" | xclip
+ ```
+
+## [4.89.1](https://github.com/coder/code-server/releases/tag/v4.89.1) - 2024-04-14
+
+Code v1.89.1
+
+### Changed
+
+- Updated to Code 1.89.1.
+
+## [4.89.0](https://github.com/coder/code-server/releases/tag/v4.89.0) - 2024-04-08
+
+Code v1.89.0
+
+### Changed
+
+- Updated to Code 1.89.0.
+
+## [4.23.1](https://github.com/coder/code-server/releases/tag/v4.23.1) - 2024-04-15
+
+Code v1.88.1
+
+### Changed
+
+- Updated to Code 1.88.1.
+
+## [4.23.0](https://github.com/coder/code-server/releases/tag/v4.23.0) - 2024-04-08
+
+Code v1.88.0
+
+### Changed
+
+- Updated to Code 1.88.0.
+- Updated Node to 18.18.2.
+
+### Fixed
+
+- Fix masking the exit code when failing to install extensions on the command
+ line outside the integrated terminal. Installing extensions inside the
+ integrated terminal still masks the exit code and is an upstream bug.
+
+## [4.22.1](https://github.com/coder/code-server/releases/tag/v4.22.1) - 2024-03-14
+
+Code v1.87.2
+
+### Changed
+
+- Updated to Code 1.87.2.
+- Enable keep-alive for proxy agent.
+
+## [4.22.0](https://github.com/coder/code-server/releases/tag/v4.22.0) - 2024-03-03
+
+Code v1.87.0
+
+### Changed
+
+- Updated to Code 1.87.0.
+
+## [4.21.2](https://github.com/coder/code-server/releases/tag/v4.21.2) - 2024-02-28
+
+Code v1.86.2
+
+### Changed
+
+- Updated to Code 1.86.2.
+
+## [4.21.1](https://github.com/coder/code-server/releases/tag/v4.21.1) - 2024-02-09
+
+Code v1.86.1
+
+### Changed
+
+- Updated to Code 1.86.1.
+- Updated to Node 18.17.1.
+
+### Added
+
+- Docker images for Fedora and openSUSE.
+
+## [4.21.0](https://github.com/coder/code-server/releases/tag/v4.21.0) - 2024-02-05
+
+Code v1.86.0
+
+### Changed
+
+- Updated to Code 1.86.0.
+
+## [4.20.1](https://github.com/coder/code-server/releases/tag/v4.20.1) - 2024-01-22
+
+Code v1.85.2
+
+### Changed
+
+- Updated to Code 1.85.2.
+
+### Fixed
+
+- Query variables are no longer double-encoded when going over the path proxy.
+
+## [4.20.0](https://github.com/coder/code-server/releases/tag/v4.20.0) - 2023-12-21
+
+Code v1.85.1
+
+### Added
+
+- New flag `--disable-file-uploads` to disable uploading files to the remote by
+ drag and drop and to disable opening local files via the "show local" button
+ in the file open prompt. Note that you can still open local files by drag and
+ dropping the file onto the editor pane.
+- Added `wget` to the release image.
+
+### Changed
+
+- Updated to Code 1.85.1.
+- The `--disable-file-downloads` flag will now disable the "show local" button
+ in the file save prompt as well.
+- Debian release image updated to use Bookworm.
+
+## [4.19.1](https://github.com/coder/code-server/releases/tag/v4.19.1) - 2023-11-29
+
+Code v1.84.2
+
+### Fixed
+
+- Fixed an issue where parts of the editor would not load (like the file
+ explorer, source control, etc) when using a workspace file.
+
+## [4.19.0](https://github.com/coder/code-server/releases/tag/v4.19.0) - 2023-11-18
+
+Code v1.84.2
+
+### Changed
+
+- Updated to Code 1.84.2.
+
+## [4.18.0](https://github.com/coder/code-server/releases/tag/v4.18.0) - 2023-10-20
+
+Code v1.83.1
+
+### Changed
+
+- Updated to Code 1.83.1.
+
+## [4.17.1](https://github.com/coder/code-server/releases/tag/v4.17.1) - 2023-09-29
+
+Code v1.82.2
+
+### Fixed
+
+- Make secret storage persistent. For example, logging in with GitHub should
+ persist between browser refreshes and code-server restarts.
+- Issues with argon2 on arm builds should be fixed now.
+
+## [4.17.0](https://github.com/coder/code-server/releases/tag/v4.17.0) - 2023-09-22
+
+Code v1.82.2
+
+### Added
+
+- Japanese locale.
+- `CODE_SERVER_HOST` environment variable.
+
+### Changed
+
+- Update to Code 1.82.2. This includes an update to Node 18, which also means
+ that the minimum glibc is now 2.28. If you need to maintain a lower glibc then
+ you can take a version of Node 18 that is compiled with a lower glibc and use
+ that to build code-server (or at a minimum rebuild the native modules).
+- Display paths to config files in full rather than abbreviated. If you have
+ trouble with the password not working please update and make sure the
+ displayed config paths are what you expect.
+
+### Fixed
+
+- Fix some dependency issues for the standalone arm64 and armv7l releases. If
+ you had issues with missing or failing modules please try these new builds.
+
+## [4.16.1](https://github.com/coder/code-server/releases/tag/v4.16.1) - 2023-07-31
+
+Code v1.80.2
+
+### Changed
+
+- Updated to Code 1.80.2.
+
+## [4.16.0](https://github.com/coder/code-server/releases/tag/v4.16.0) - 2023-07-28
+
+Code v1.80.1
+
+### Added
+
+- `--disable-proxy` flag. This disables the domain and path proxies but it does
+ not disable the ports panel in Code. That can be disabled by using
+ `remote.autoForwardPorts=false` in your settings.
+
+## [4.15.0](https://github.com/coder/code-server/releases/tag/v4.15.0) - 2023-07-21
+
+Code v1.80.1
+
+### Changed
+
+- Updated to Code 1.80.1.
+
+### Added
+
+- `--trusted-origin` flag for specifying origins that you trust but do not
+ control (for example a reverse proxy).
+
+Code v1.79.2
+
+## [4.14.1](https://github.com/coder/code-server/releases/tag/v4.14.1) - 2023-06-26
+
+Code v1.79.2
+
+### Security
+
+- Remove extra write permissions on the Node binary bundled with the linux-amd64
+ tarball. If you extract the tar without a umask this could mean the Node
+ binary would be unexpectedly writable.
+
+### Fixed
+
+- Inability to launch multiple instances of code-server for different users.
+
+### Added
+
+- `--session-socket` CLI flag to configure the location of the session socket.
+ By default it will be placed in `/code-server-ipc.sock`.
+
+## [4.14.0](https://github.com/coder/code-server/releases/tag/v4.14.0) - 2023-06-16
+
+Code v1.79.2
+
+### Added
+
+- `--domain-proxy` now supports `{{port}}` and `{{host}}` template variables.
+
+### Changed
+
+- Updated to Code 1.79.2
+- Files opened from an external terminal will now open in the most closely
+ related window rather than in the last opened window.
+
+## [4.13.0](https://github.com/coder/code-server/releases/tag/v4.13.0) - 2023-05-19
+
+Code v1.78.2
+
+### Changed
+
+- Updated to Code 1.78.2.
+
+### Fixed
+
+- Proxying files that contain non-ASCII characters.
+- Origin check when X-Forwarded-Host contains comma-separated hosts.
+
+## [4.12.0](https://github.com/coder/code-server/releases/tag/v4.12.0) - 2023-04-21
+
+Code v1.77.3
+
+### Changed
+
+- Updated to Code 1.77.3
+- Ports panel will use domain-based proxy (instead of the default path-based
+ proxy) when set via --proxy-domain.
+- Apply --app-name to the PWA title.
+
+### Added
+
+- Thai translation for login page.
+- Debug logs around the origin security check. If you are getting forbidden
+ errors on web sockets please run code-server with `--log debug` to see why the
+ requests are being blocked.
+
+## [4.11.0](https://github.com/coder/code-server/releases/tag/v4.11.0) - 2023-03-16
+
+Code v1.76.1
+
+### Changed
+
+- Updated to Code 1.76.1
+
+## [4.10.1](https://github.com/coder/code-server/releases/tag/v4.10.1) - 2023-03-04
+
+Code v1.75.1
+
+### Security
+
+Added an origin check to web sockets to prevent cross-site hijacking attacks on
+users using older or niche browser that do not support SameSite cookies and
+attacks across sub-domains that share the same root domain.
+
+The check requires the host header to be set so if you use a reverse proxy
+ensure it forwards that information otherwise web sockets will be blocked.
+
+## [4.10.0](https://github.com/coder/code-server/releases/tag/v4.10.0) - 2023-02-15
+
+Code v1.75.1
+
+### Changed
+
+- Updated to Code 1.75.1
+
+### Removed
+
+- Removed `--link` (was deprecated over thirteen months ago in 4.0.1).
+
+## [4.9.1](https://github.com/coder/code-server/releases/tag/v4.9.1) - 2022-12-15
+
+Code v1.73.1
+
+### Changed
+
+- Updated a couple steps in the build and release process to ensure we're using
+ `npm` and `yarn` consistently depending on the step.
+
+### Fixed
+
+- Fixed an issue with code-server version not displaying in the Help > About window.
+- Fixed terminal not loading on macOS clients.
+
+## [4.9.0](https://github.com/coder/code-server/releases/tag/v4.9.0) - 2022-12-06
+
+Code v1.73.1
+
+### Changed
+
+- Upgraded to Code 1.73.1
+
+### Added
+
+- `/security.txt` added as a route with info on our security policy information thanks to @ghuntley
+
+### Fixed
+
+- Installing on majaro images should now work thanks to @MrPeacockNLB for
+ adding the `--noconfirm` flag in `install.sh`
+
+### Known Issues
+
+- `--cert` on Ubuntu 22.04: OpenSSL v3 is used which breaks `pem` meaning the
+ `--cert` feature will not work. [Reference](https://github.com/adobe/fetch/pull/318#issuecomment-1306070259)
+
+## [4.8.3](https://github.com/coder/code-server/releases/tag/v4.8.3) - 2022-11-07
+
+Code v1.72.1
+
+### Added
+
+- install script now supports arch-like (i.e. manjaro, endeavourous, etc.)
+ architectures
+
+### Changed
+
+- Updated text in the Getting Started page.
+
+## [4.8.2](https://github.com/coder/code-server/releases/tag/v4.8.2) - 2022-11-02
+
+Code v1.72.1
+
+### Added
+
+- New text in the Getting Started page with info about
+ `coder/coder`. This is enabled by default but can be disabled by passing the CLI
+ flag `--disable-getting-started-override` or setting
+ `CS_DISABLE_GETTING_STARTED_OVERRIDE=1` or
+ `CS_DISABLE_GETTING_STARTED_OVERRIDE=true`.
+
+## [4.8.1](https://github.com/coder/code-server/releases/tag/v4.8.1) - 2022-10-28
+
+Code v1.72.1
+
+### Fixed
+
+- Fixed CSP error introduced in 4.8.0 that caused issues with webviews and most
+ extensions.
+
+## [4.8.0](https://github.com/coder/code-server/releases/tag/v4.8.0) - 2022-10-24
+
+Code v1.72.1
+
+### Added
+
+- Support for the Ports panel which leverages code-server's built-in proxy. It
+ also uses `VSCODE_PROXY_URI` where `{{port}}` is replace when forwarding a port.
+ Example: `VSCODE_PROXY_URI=https://{{port}}.kyle.dev` would forward an
+ application running on localhost:3000 to https://3000.kyle.dev
+- Support for `--disable-workspace-trust` CLI flag
+- Support for `--goto` flag to open file @ line:column
+- Added Ubuntu-based images for Docker releases. If you run into issues with
+ `PATH` being overwritten in Docker please try the Ubuntu image as this is a
+ problem in the Debian base image.
+
+### Changed
+
+- Updated Code to 1.72.1
+
+### Fixed
+
+- Enabled `BROWSER` environment variable
+- Patched `asExternalUri` to work so now extensions run inside code-server can use it
+
+## [4.7.1](https://github.com/coder/code-server/releases/tag/v4.7.1) - 2022-09-30
+
+Code v1.71.2
+
+### Changed
+
+- Updated Code to 1.71.2
+
+### Fixed
+
+- Fixed install script not upgrading code-server when already installed on RPM-based machines
+- Fixed install script failing to gain root permissions on FreeBSD
+
+## [4.7.0](https://github.com/coder/code-server/releases/tag/v4.7.0) - 2022-09-09
+
+Code v1.71.0
+
+### Changed
+
+- Updated Code to 1.71.0
+
+### Removed
+
+- Dropped heartbeat patch because it was implemented upstream
+
+### Fixed
+
+- Add flags --unsafe-perm --legacy-peer-deps in `npm-postinstall.sh` which ensures installing with npm works correctly
+
+## [4.6.1](https://github.com/coder/code-server/releases/tag/v4.6.1) - 2022-09-31
+
+Code v1.70.2
+
+### Changed
+
+- Updated Code to 1.70.2
+- Updated `argon2` to 0.29.0 which should fix issues on FreeBSD
+- Updated docs to suggest using `npm` instead of `yarn`
+
+### Removed
+
+- Dropped database migration patch affected to 4.0.2 versions and earlier.
+
+### Fixed
+
+- Fixed preservation of `process.execArgv` which means you can pass `--prof` to profile code-server
+
+## [4.6.0](https://github.com/coder/code-server/releases/tag/v4.6.0) - 2022-08-17
+
+Code v1.70.1
+
+### Changed
+
+- Updated Code to 1.70.1.
+
+### Added
+
+- Added a heartbeat to sockets. This should prevent them from getting closed by
+ reverse proxy timeouts when idle like NGINX's default 60-second timeout.
+
+### Fixed
+
+- Fixed logout option appearing even when authentication is disabled.
+
+## [4.5.2](https://github.com/coder/code-server/releases/tag/v4.5.2) - 2022-08-15
+
+Code v1.68.1
+
+### Security
+
+- Fixed the proxy route not performing authentication. For example if you were
+ to run a development HTTP server using `python -m http.server 8000` then it
+ would be accessible at `my.domain/proxy/8000/` without any authentication.
+
+ If all of the following apply to you please update as soon as possible:
+ - You run code-server with the built-in password authentication.
+ - You run unprotected HTTP services on ports accessible by code-server.
+
+### Changed
+
+- Invoking `code-server` in the integrated terminal will now use the script that
+ comes with upstream Code. This means flags like `--wait` will be
+ automatically supported now. However the upstream script only has the ability
+ to interact with the running code-server and cannot spawn new instances. If
+ you need to spawn a new code-server from the integrated terminal please
+ specify the full path to code-server's usual script (for example
+ `/usr/bin/code-server`).
+
+### Fixed
+
+- Invoking `code-server` in the integrated terminal will now work instead of
+ erroring about not finding Node.
+
+## [4.5.1](https://github.com/coder/code-server/releases/tag/v4.5.1) - 2022-07-18
+
+Code v1.68.1
+
+### Changed
+
+- We now use `release/v<0.0.0>` for the release branch name so it doesn't
+ conflict with the tag name
+- Added `.prettierignore` to ignore formatting files in `lib/vscode`
+
+### Added
+
+- Allow more comprehensive affinity config in Helm chart
+- Added custom message in Homebrew PR to make sure code-server maintainers are
+ tagged
+- Allow setting `priorityClassName` via Helm chart
+- Added troubleshooting docs to `CONTRIBUTING.md`
+
+### Fixed
+
+- Removed default memory limit which was set via `NODE_OPTIONS`
+- Changed output in pipe to make it easier to debug code-server when doing live
+ edits
+- Fixed display-language patch to use correct path which broke in 4.5.0
+- Fixed multiple code-server windows opening when using the code-server CLI in
+ the Integrated Terminal
+- Fixed Integrated Terminal not working when web base was not the root path
+
+### Security
+
+- Updated `glob-parent` version in dependencies
+
+## [4.5.0](https://github.com/coder/code-server/releases/tag/v4.5.0) - 2022-06-29
+
+Code v1.68.1
+
+### Changed
+
+- Updated codecov to use codecov uploader
+- Moved integration tests to Jest
+- Fixed docker release to only download .deb
+- Upgraded to Code 1.68.1
+- Install `nfpm` from GitHub
+- Upgraded to TypeScript 4.6
+
+### Added
+
+- Added tests for `open`, `isWsl`, `handlePasswordValidation`
+- Provided alternate image registry to dockerhub
+- Allowed users to have scripts run on container with `ENTRYPOINTD` environment
+ variable
+
+### Fixed
+
+- Fixed open CLI command to work on macOS
+
+## [4.4.0](https://github.com/coder/code-server/releases/tag/v4.4.0) - 2022-05-06
+
+Code v1.66.2
+
+### Changed
+
+- Refactored methods in `Heart` class and made `Heart.beat()` async to make
+ testing easier.
+- Upgraded to Code 1.66.2.
+
+### Added
+
+- Added back telemetry patch which was removed in the Code reachitecture.
+- Added support to use `true` for `CS_DISABLE_FILE_DOWNLOADS` environment
+ variable. This means you can disable file downloads by setting
+ `CS_DISABLE_FILE_DOWNLOADS` to `true` or `1`.
+- Added tests for `Heart` class.
+
+### Fixed
+
+- Fixed installation issue in AUR after LICENSE rename.
+- Fixed issue with listening on IPv6 addresses.
+- Fixed issue with Docker publish action not being able to find artifacts. Now
+ it downloads the release assets from the release.
+
+## [4.3.0](https://github.com/coder/code-server/releases/tag/v4.3.0) - 2022-04-14
+
+Code v1.65.2
+
+### Changed
+
+- Excluded .deb files from release Docker image which drops the compressed and
+ uncompressed size by 58% and 34%.
+- Upgraded to Code 1.65.2.
+
+### Added
+
+- Added a new CLI flag called `--disable-file-downloads` which allows you to
+ disable the "Download..." option that shows in the UI when right-clicking on a
+ file. This can also set by running `CS_DISABLE_FILE_DOWNLOADS=1`.
+- Aligned the dependencies for binary and npm release artifacts.
+
+### Fixed
+
+- Fixed the code-server version from not displaying in the Help > About dialog.
+- Fixed issues with the TypeScript and JavaScript Language Features Extension
+ failing to activate.
+- Fixed missing files in ipynb extension.
+- Fixed the homebrew release workflow.
+- Fixed the Docker release workflow from not always publishing version tags.
+
+## [4.2.0](https://github.com/coder/code-server/releases/tag/v4.2.0) - 2022-03-22
+
+Code v1.64.2
+
+### Added
+
+- Added tests for `handleArgsSocketCatchError`, `setDefaults` and
+ `optionDescriptions`.
+
+### Changed
+
+- We switched from using the fork `coder/vscode` to a submodule of
+ `microsoft/vscode` + patches managed by `quilt` for how Code sits inside the
+ code-server codebase.
+- Upgraded to Code 1.64.2.
+
+### Fixed
+
+- Update popup notification through `--disable-update-check` is now fixed.
+- Fixed PWA icons not loading on iPad
+- Fixed the homebrew release process. Our `cdrci` bot should now automatically
+ update the version as part of the release pipeline.
+- Fixed titleBar color setting being ignored in PWA.
+
+### Security
+
+- Updated to `minimist-list`.
+- Updated `cloud-agent` to `v0.2.4` which uses `nhooyr.io/webscoket` `v1.8.7`.
+
+## [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
+
+Code v1.63.0
+
+### Fixed
+
+- Unset the `BROWSER` environment variable. This fixes applications that hard
+ exit when trying to spawn the helper script `BROWSER` points to because the
+ file is missing. While we do include the script now we are leaving the
+ variable omitted because the script does not work yet.
+
+## [4.0.1](https://github.com/coder/code-server/releases/tag/v4.0.1) - 2022-01-04
+
+Code v1.63.0
+
+code-server has been rebased on upstream's newly open-sourced server
+implementation (#4414).
+
+### Changed
+
+- Web socket compression has been made the default (when supported). This means
+ the `--enable` flag will no longer take `permessage-deflate` as an option.
+- The static endpoint can no longer reach outside code-server. However the
+ vscode-remote-resource endpoint still can.
+- OpenVSX has been made the default marketplace.
+- The last opened folder/workspace is no longer stored separately in the
+ 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 Code's `product.json`.
+
+### Added
+
+- `VSCODE_PROXY_URI` env var for use in the terminal and extensions.
+
+### Removed
+
+- Extra extension directories have been removed. The `--extra-extensions-dir`
+ and `--extra-builtin-extensions-dir` flags will no longer be accepted.
+- The `--install-source` flag has been removed.
+
+### Deprecated
+
+- `--link` is now deprecated (#4562).
+
+### Security
+
+- We fixed a XSS vulnerability by escaping HTML from messages in the error page (#4430).
+
+## [3.12.0](https://github.com/coder/code-server/releases/tag/v3.12.0) - 2021-09-15
+
+Code v1.60.0
+
+### Changed
+
+- Upgrade Code to 1.60.0.
+
+### Fixed
+
+- Fix logout when using a base path (#3608).
+
+## [3.11.1](https://github.com/coder/code-server/releases/tag/v3.11.1) - 2021-08-06
+
+Undocumented (see releases page).
+
+## [3.11.0](https://github.com/coder/code-server/releases/tag/v3.11.0) - 2021-06-14
+
+Undocumented (see releases page).
+
+## [3.10.2](https://github.com/coder/code-server/releases/tag/v3.10.2) - 2021-05-21
+
+Code v1.56.1
+
+### Added
+
+- Support `extraInitContainers` in helm chart values (#3393).
+
+### Changed
+
+- Change `extraContainers` to support templating in helm chart (#3393).
+
+### Fixed
+
+- Fix "Open Folder" on welcome page (#3437).
+
+## [3.10.1](https://github.com/coder/code-server/releases/tag/v3.10.1) - 2021-05-17
+
+Code v1.56.1
+
+### Fixed
+
+- Check the logged user instead of $USER (#3330).
+- Fix broken node_modules.asar symlink in npm package (#3355).
+- Update cloud agent to fix version issue (#3342).
+
+### Changed
+
+- Use xdgBasedir.runtime instead of tmp (#3304).
+
+## [3.10.0](https://github.com/coder/code-server/releases/tag/v3.10.0) - 2021-05-10
+
+Code v1.56.0
+
+### Changed
+
+- Update to Code 1.56.0 (#3269).
+- Minor connections refactor (#3178). Improves connection stability.
+- Use ptyHostService (#3308). This brings us closer to upstream Code.
+
+### Added
+
+- Add flag for toggling permessage-deflate (#3286). The default is off so
+ compression will no longer be used by default. Use the --enable flag to
+ toggle it back on.
+
+### Fixed
+
+- Make rate limiter not count against successful logins (#3141).
+- Refactor logout (#3277). This fixes logging out in some scenarios.
+- Make sure directories exist (#3309). This fixes some errors on startup.
+
+### Security
+
+- Update dependencies with CVEs (#3223).
+
+## Previous versions
+
+This was added with `3.10.0`, which means any previous versions are not
+documented in the changelog.
+
+To see those, please visit the [Releases page](https://github.com/coder/code-server/releases).
diff --git a/LICENSE.txt b/LICENSE
similarity index 100%
rename from LICENSE.txt
rename to LICENSE
diff --git a/README.md b/README.md
deleted file mode 100644
index dd5532d16c04..000000000000
--- a/README.md
+++ /dev/null
@@ -1,70 +0,0 @@
-# code-server · [](https://github.com/cdr/code-server/discussions) [](https://cdr.co/join-community) [](https://twitter.com/coderhq)
-
-Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and access it in the browser.
-
-
-
-## Highlights
-
-- Code on any device with a consistent development environment
-- Use cloud servers to speed up tests, compilations, downloads, and more
-- Preserve battery life when you're on the go; all intensive tasks run on your server
-
-## Getting Started
-
-There are two ways to get started:
-
-1. Using the [install script](./install.sh), which automates most of the process. The script uses the system package manager (if possible)
-2. Manually installing code-server; see [Installation](./doc/install.md) for instructions applicable to most use cases
-
-If you choose to use the install script, you can preview what occurs during the install process:
-
-```bash
-curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
-```
-
-To install, run:
-
-```bash
-curl -fsSL https://code-server.dev/install.sh | sh
-```
-
-When done, the install script prints out instructions for running and starting code-server.
-
-We also have an in-depth [setup and configuration](./doc/guide.md) guide.
-
-### Alpha Program 🐣
-
-We're working on a cloud platform that makes deploying and managing code-server easier.
-Consider updating to the latest version and running code-server with our experimental flag `--link` if you don't want to worry about
-
-- TLS
-- Authentication
-- Port Forwarding
-
-```bash
-$ code-server --link
-Proxying code-server to Coder Cloud, you can access your IDE at https://valmar-jon.cdr.co
-```
-
-## FAQ
-
-See [./doc/FAQ.md](./doc/FAQ.md).
-
-## Want to help?
-
-See [CONTRIBUTING](./doc/CONTRIBUTING.md) for details.
-
-## Hiring
-
-We ([@cdr](https://github.com/cdr)) are looking for engineers to help [maintain
-code-server](https://jobs.lever.co/coder/e40becde-2cbd-4885-9029-e5c7b0a734b8), innovate on open source, and streamline dev workflows.
-
-Our main office is in Austin, Texas. Remote is ok as long as
-you're in North America or Europe.
-
-Please get in [touch](mailto:jobs@coder.com) with your resume/GitHub if interested.
-
-## For Organizations
-
-Visit [our website](https://coder.com) for more information about remote development for your organization or enterprise.
diff --git a/ci/Caddyfile b/ci/Caddyfile
new file mode 100644
index 000000000000..52e4da6da281
--- /dev/null
+++ b/ci/Caddyfile
@@ -0,0 +1,15 @@
+{
+ admin localhost:4444
+}
+:8000 {
+ @portLocalhost path_regexp port ^/([0-9]+)\/ide
+ handle @portLocalhost {
+ uri strip_prefix {re.port.1}/ide
+ reverse_proxy localhost:{re.port.1}
+ }
+
+ handle {
+ respond "Bad hostname" 400
+ }
+
+}
diff --git a/ci/README.md b/ci/README.md
deleted file mode 100644
index 3448f9e3541b..000000000000
--- a/ci/README.md
+++ /dev/null
@@ -1,148 +0,0 @@
-# ci
-
-This directory contains scripts used for code-server's continuous integration infrastructure.
-
-Some of these scripts contain more detailed documentation and options
-in header comments.
-
-Any file or directory in this subdirectory should be documented here.
-
-- [./ci/lib.sh](./lib.sh)
- - Contains code duplicated across these scripts.
-
-## Publishing a release
-
-Make sure you have `$GITHUB_TOKEN` set and [hub](https://github.com/github/hub) installed.
-
-1. Update the version of code-server and make a PR.
- 1. Update in `package.json`
- 2. Update in [./doc/install.md](../doc/install.md)
- 3. Update in [./ci/helm-chart/README.md](../ci/helm-chart/README.md)
- - Remember to update the chart version as well on top of appVersion in `Chart.yaml`.
-2. GitHub actions will generate the `npm-package`, `release-packages` and `release-images` artifacts.
- 1. You do not have to wait for these.
-3. Run `yarn release:github-draft` to create a GitHub draft release from the template with
- the updated version.
- 1. Summarize the major changes in the release notes and link to the relevant issues.
-4. Wait for the artifacts in step 2 to build.
-5. Run `yarn release:github-assets` to download the `release-packages` artifact.
- - It will upload them to the draft release.
-6. Run some basic sanity tests on one of the released packages.
- - Especially make sure the terminal works fine.
-7. Make sure the github release tag is the commit with the artifacts. This is a bug in
- `hub` where uploading assets in step 5 will break the tag.
-8. Publish the release and merge the PR.
- 1. CI will automatically grab the artifacts and then:
- 1. Publish the NPM package from `npm-package`.
- 2. Publish the Docker Hub image from `release-images`.
-9. Update the AUR package.
- - Instructions on updating the AUR package are at [cdr/code-server-aur](https://github.com/cdr/code-server-aur).
-10. Wait for the npm package to be published.
-11. Update the homebrew package.
- - Send a pull request to [homebrew-core](https://github.com/Homebrew/homebrew-core) with the URL in the [formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/code-server.rb) updated.
-
-## dev
-
-This directory contains scripts used for the development of code-server.
-
-- [./ci/dev/image](./dev/image)
- - See [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md) for docs on the development container.
-- [./ci/dev/fmt.sh](./dev/fmt.sh) (`yarn fmt`)
- - Runs formatters.
-- [./ci/dev/lint.sh](./dev/lint.sh) (`yarn lint`)
- - Runs linters.
-- [./ci/dev/test.sh](./dev/test.sh) (`yarn test`)
- - Runs tests.
-- [./ci/dev/ci.sh](./dev/ci.sh) (`yarn ci`)
- - Runs `yarn fmt`, `yarn lint` and `yarn test`.
-- [./ci/dev/vscode.sh](./dev/vscode.sh) (`yarn vscode`)
- - Ensures [./lib/vscode](../lib/vscode) is cloned, patched and dependencies are installed.
-- [./ci/dev/patch-vscode.sh](./dev/patch-vscode.sh) (`yarn vscode:patch`)
- - Applies [./ci/dev/vscode.patch](./dev/vscode.patch) to [./lib/vscode](../lib/vscode).
-- [./ci/dev/diff-vscode.sh](./dev/diff-vscode.sh) (`yarn vscode:diff`)
- - Diffs [./lib/vscode](../lib/vscode) into [./ci/dev/vscode.patch](./dev/vscode.patch).
-- [./ci/dev/vscode.patch](./dev/vscode.patch)
- - Our patch of VS Code, see [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md#vs-code-patch).
- - Generate it with `yarn vscode:diff` and apply with `yarn vscode:patch`.
-- [./ci/dev/watch.ts](./dev/watch.ts) (`yarn watch`)
- - Starts a process to build and launch code-server and restart on any code changes.
- - Example usage in [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md).
-
-## build
-
-This directory contains the scripts used to build and release code-server.
-You can disable minification by setting `MINIFY=`.
-
-- [./ci/build/build-code-server.sh](./build/build-code-server.sh) (`yarn build`)
- - Builds code-server into `./out` and bundles the frontend into `./dist`.
-- [./ci/build/build-vscode.sh](./build/build-vscode.sh) (`yarn build:vscode`)
- - Builds vscode into `./lib/vscode/out-vscode`.
-- [./ci/build/build-release.sh](./build/build-release.sh) (`yarn release`)
- - Bundles the output of the above two scripts into a single node module at `./release`.
-- [./ci/build/build-standalone-release.sh](./build/build-standalone-release.sh) (`yarn release:standalone`)
- - Requires a node module already built into `./release` with the above script.
- - Will build a standalone release with node and node_modules bundled into `./release-standalone`.
-- [./ci/build/clean.sh](./build/clean.sh) (`yarn clean`)
- - Removes all build artifacts.
- - Will also `git reset --hard lib/vscode`.
- - Useful to do a clean build.
-- [./ci/build/code-server.sh](./build/code-server.sh)
- - Copied into standalone releases to run code-server with the bundled node binary.
-- [./ci/build/test-standalone-release.sh](./build/test-standalone-release.sh) (`yarn test:standalone-release`)
- - Ensures code-server in the `./release-standalone` directory works by installing an extension.
-- [./ci/build/build-packages.sh](./build/build-packages.sh) (`yarn package`)
- - Packages `./release-standalone` into a `.tar.gz` archive in `./release-packages`.
- - If on linux, [nfpm](https://github.com/goreleaser/nfpm) is used to generate `.deb` and `.rpm`.
-- [./ci/build/nfpm.yaml](./build/nfpm.yaml)
- - Used to configure [nfpm](https://github.com/goreleaser/nfpm) to generate `.deb` and `.rpm`.
-- [./ci/build/code-server-nfpm.sh](./build/code-server-nfpm.sh)
- - Entrypoint script for code-server for `.deb` and `.rpm`.
-- [./ci/build/code-server.service](./build/code-server.service)
- - systemd user service packaged into the `.deb` and `.rpm`.
-- [./ci/build/release-github-draft.sh](./build/release-github-draft.sh) (`yarn release:github-draft`)
- - Uses [hub](https://github.com/github/hub) to create a draft release with a template description.
-- [./ci/build/release-github-assets.sh](./build/release-github-assets.sh) (`yarn release:github-assets`)
- - Downloads the release-package artifacts for the current commit from CI.
- - Uses [hub](https://github.com/github/hub) to upload the artifacts to the release
- specified in `package.json`.
-- [./ci/build/npm-postinstall.sh](./build/npm-postinstall.sh)
- - Post install script for the npm package.
- - Bundled by`yarn release`.
-
-## release-image
-
-This directory contains the release docker container image.
-
-- [./release-image/build.sh](./release-image/build.sh)
- - Builds the release container with the tag `codercom/code-server-$ARCH:$VERSION`.
- - Assumes debian releases are ready in `./release-packages`.
-
-## images
-
-This directory contains the images for CI.
-
-## steps
-
-This directory contains the scripts used in CI.
-Helps avoid clobbering the CI configuration.
-
-- [./steps/fmt.sh](./steps/fmt.sh)
- - Runs `yarn fmt` after ensuring VS Code is patched.
-- [./steps/lint.sh](./steps/lint.sh)
- - Runs `yarn lint` after ensuring VS Code is patched.
-- [./steps/test.sh](./steps/test.sh)
- - Runs `yarn test` after ensuring VS Code is patched.
-- [./steps/release.sh](./steps/release.sh)
- - Runs the release process.
- - Generates the npm package at `./release`.
-- [./steps/release-packages.sh](./steps/release-packages.sh)
- - Takes the output of the previous script and generates a standalone release and
- release packages into `./release-packages`.
-- [./steps/publish-npm.sh](./steps/publish-npm.sh)
- - Grabs the `npm-package` release artifact for the current commit and publishes it on npm.
-- [./steps/build-docker-image.sh](./steps/build-docker-image.sh)
- - Builds the docker image and then saves it into `./release-images/code-server-$ARCH-$VERSION.tar`.
-- [./steps/push-docker-manifest.sh](./steps/push-docker-manifest.sh)
- - Loads all images in `./release-images` and then builds and pushes a multi architecture
- docker manifest for the amd64 and arm64 images to `codercom/code-server:$VERSION` and
- `codercom/code-server:latest`.
diff --git a/ci/build/build-code-server.sh b/ci/build/build-code-server.sh
index 0aff035af254..df86f2d97a18 100755
--- a/ci/build/build-code-server.sh
+++ b/ci/build/build-code-server.sh
@@ -3,9 +3,6 @@ set -euo pipefail
# Builds code-server into out and the frontend into dist.
-# MINIFY controls whether parcel minifies dist.
-MINIFY=${MINIFY-true}
-
main() {
cd "$(dirname "${0}")/../.."
@@ -17,21 +14,6 @@ main() {
sed -i.bak "1s;^;#!/usr/bin/env node\n;" out/node/entry.js && rm out/node/entry.js.bak
chmod +x out/node/entry.js
fi
-
- if ! [ -f ./lib/coder-cloud-agent ]; then
- OS="$(uname | tr '[:upper:]' '[:lower:]')"
- curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent
- chmod +x ./lib/coder-cloud-agent
- fi
-
- parcel build \
- --public-url "." \
- --out-dir dist \
- $([[ $MINIFY ]] || echo --no-minify) \
- src/browser/register.ts \
- src/browser/serviceWorker.ts \
- src/browser/pages/login.ts \
- src/browser/pages/vscode.ts
}
main "$@"
diff --git a/ci/build/build-lib.sh b/ci/build/build-lib.sh
new file mode 100755
index 000000000000..520276c1bfc3
--- /dev/null
+++ b/ci/build/build-lib.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+# This is a library which contains functions used inside ci/build
+#
+# We separated it into it's own file so that we could easily unit test
+# these functions and helpers.
+
+# On some CPU architectures (notably node/uname "armv7l", default on Raspberry Pis),
+# different package managers have different labels for the same CPU (deb=armhf, rpm=armhfp).
+# This function returns the overriden arch on platforms
+# with alternate labels, or the same arch otherwise.
+get_nfpm_arch() {
+ local PKG_FORMAT="${1:-}"
+ local ARCH="${2:-}"
+
+ case "$ARCH" in
+ armv7l)
+ if [ "$PKG_FORMAT" = "deb" ]; then
+ echo armhf
+ elif [ "$PKG_FORMAT" = "rpm" ]; then
+ echo armhfp
+ fi
+ ;;
+ *)
+ echo "$ARCH"
+ ;;
+ esac
+}
diff --git a/ci/build/build-packages.sh b/ci/build/build-packages.sh
index a5ef794e5a88..35b27a558edc 100755
--- a/ci/build/build-packages.sh
+++ b/ci/build/build-packages.sh
@@ -1,12 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
-# Packages code-server for the current OS and architecture into ./release-packages.
-# This script assumes that a standalone release is built already into ./release-standalone
+# Given a release found in $RELEASE_PATH, generate a deb, rpm, and tarball each
+# named after $ARCH (derived from uname -m but can be overridden for
+# cross-compilation) and $OS (derived from uname and cannot be overridden) and
+# place them in ./release-packages and ./release-gcp.
main() {
cd "$(dirname "${0}")/../.."
source ./ci/lib.sh
+ source ./ci/build/build-lib.sh
+
+ VERSION=$(jq -r .version "$RELEASE_PATH/package.json")
+ export VERSION # for nfpm to use
mkdir -p release-packages
@@ -20,9 +26,9 @@ main() {
release_archive() {
local release_name="code-server-$VERSION-$OS-$ARCH"
if [[ $OS == "linux" ]]; then
- tar -czf "release-packages/$release_name.tar.gz" --transform "s/^\.\/release-standalone/$release_name/" ./release-standalone
+ tar -czf "release-packages/$release_name.tar.gz" --owner=0 --group=0 --transform "s/^$RELEASE_PATH/$release_name/" "$RELEASE_PATH"
else
- tar -czf "release-packages/$release_name.tar.gz" -s "/^release-standalone/$release_name/" release-standalone
+ tar -czf "release-packages/$release_name.tar.gz" -s "/^$RELEASE_PATH/$release_name/" "$RELEASE_PATH"
fi
echo "done (release-packages/$release_name)"
@@ -40,11 +46,20 @@ release_gcp() {
# Generates deb and rpm packages.
release_nfpm() {
local nfpm_config
+
+ export NFPM_ARCH
+
+ NFPM_ARCH="$(get_nfpm_arch deb "$ARCH")"
nfpm_config="$(envsubst < ./ci/build/nfpm.yaml)"
+ echo "Building deb"
+ echo "$nfpm_config" | head --lines=4
+ nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server_${VERSION}_${NFPM_ARCH}.deb"
- # The underscores are convention for .deb.
- nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server_${VERSION}_$ARCH.deb"
- nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server-$VERSION-$ARCH.rpm"
+ NFPM_ARCH="$(get_nfpm_arch rpm "$ARCH")"
+ nfpm_config="$(envsubst < ./ci/build/nfpm.yaml)"
+ echo "Building rpm"
+ echo "$nfpm_config" | head --lines=4
+ nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server-$VERSION-$NFPM_ARCH.rpm"
}
main "$@"
diff --git a/ci/build/build-release.sh b/ci/build/build-release.sh
index 3b88ed7e9d62..9ded35f98ccb 100755
--- a/ci/build/build-release.sh
+++ b/ci/build/build-release.sh
@@ -1,101 +1,175 @@
#!/usr/bin/env bash
set -euo pipefail
-# This script requires vscode to be built with matching MINIFY.
+# Once both code-server and VS Code have been built, use this script to copy
+# them into a single directory (./release), prepare the package.json and
+# product.json, and add shrinkwraps. This results in a generic NPM package that
+# we can publish to NPM.
-# MINIFY controls whether minified vscode is bundled.
+# MINIFY controls whether minified VS Code is bundled. It must match the value
+# used when VS Code was built.
MINIFY="${MINIFY-true}"
-# KEEP_MODULES controls whether the script cleans all node_modules requiring a yarn install
-# to run first.
+# node_modules are not copied by default. Set KEEP_MODULES=1 to copy them.
+# Note these modules will be for the platform that built them, making the result
+# no longer generic (it can still be published though as the modules will be
+# ignored when pushing).
KEEP_MODULES="${KEEP_MODULES-0}"
main() {
cd "$(dirname "${0}")/../.."
+
source ./ci/lib.sh
VSCODE_SRC_PATH="lib/vscode"
VSCODE_OUT_PATH="$RELEASE_PATH/lib/vscode"
+ create_shrinkwraps
+
mkdir -p "$RELEASE_PATH"
bundle_code_server
bundle_vscode
- rsync README.md "$RELEASE_PATH"
- rsync LICENSE.txt "$RELEASE_PATH"
+ rsync ./docs/README.md "$RELEASE_PATH"
+ rsync LICENSE "$RELEASE_PATH"
rsync ./lib/vscode/ThirdPartyNotices.txt "$RELEASE_PATH"
- # code-server exports types which can be imported and used by plugins. Those
- # types import ipc.d.ts but it isn't included in the final vscode build so
- # we'll copy it ourselves here.
- mkdir -p "$RELEASE_PATH/lib/vscode/src/vs/server"
- rsync ./lib/vscode/src/vs/server/ipc.d.ts "$RELEASE_PATH/lib/vscode/src/vs/server"
+ if [ "$KEEP_MODULES" = 1 ]; then
+ # Copy the code-server launcher.
+ mkdir -p "$RELEASE_PATH/bin"
+ rsync ./ci/build/code-server.sh "$RELEASE_PATH/bin/code-server"
+ chmod 755 "$RELEASE_PATH/bin/code-server"
+
+ # Delete the extra bin scripts.
+ rm "$RELEASE_PATH/lib/vscode/bin/remote-cli/code-darwin.sh"
+ rm "$RELEASE_PATH/lib/vscode/bin/remote-cli/code-linux.sh"
+ rm "$RELEASE_PATH/lib/vscode/bin/helpers/browser-darwin.sh"
+ rm "$RELEASE_PATH/lib/vscode/bin/helpers/browser-linux.sh"
+ if [ "$OS" != windows ] ; then
+ rm "$RELEASE_PATH/lib/vscode/bin/remote-cli/code.cmd"
+ rm "$RELEASE_PATH/lib/vscode/bin/helpers/browser.cmd"
+ fi
+ fi
}
bundle_code_server() {
- rsync out dist "$RELEASE_PATH"
+ rsync out "$RELEASE_PATH"
# For source maps and images.
mkdir -p "$RELEASE_PATH/src/browser"
rsync src/browser/media/ "$RELEASE_PATH/src/browser/media"
mkdir -p "$RELEASE_PATH/src/browser/pages"
rsync src/browser/pages/*.html "$RELEASE_PATH/src/browser/pages"
+ rsync src/browser/pages/*.css "$RELEASE_PATH/src/browser/pages"
rsync src/browser/robots.txt "$RELEASE_PATH/src/browser"
# Adds the commit to package.json
- jq --slurp '.[0] * .[1]' package.json <(
+ jq --slurp '(.[0] | del(.scripts,.jest,.devDependencies)) * .[1]' package.json <(
cat << EOF
{
+ "version": "$(jq -r .codeServerVersion "./lib/vscode-reh-web-$VSCODE_TARGET/product.json")",
"commit": "$(git rev-parse HEAD)",
"scripts": {
- "postinstall": "./postinstall.sh"
+ "postinstall": "sh ./postinstall.sh"
}
}
EOF
) > "$RELEASE_PATH/package.json"
- rsync yarn.lock "$RELEASE_PATH"
- rsync ci/build/npm-postinstall.sh "$RELEASE_PATH/postinstall.sh"
+ mv npm-shrinkwrap.json "$RELEASE_PATH"
if [ "$KEEP_MODULES" = 1 ]; then
- rsync node_modules/ "$RELEASE_PATH/node_modules"
- mkdir -p "$RELEASE_PATH/lib"
- rsync ./lib/coder-cloud-agent "$RELEASE_PATH/lib"
+ local rsync_opts=(-a)
+ if [[ ${DEBUG-} = 1 ]]; then
+ rsync_opts+=(-vh)
+ fi
+ # If we build from source, exclude the prebuilds.
+ if [[ ${npm_config_build_from_source-} = true ]]; then
+ rsync_opts+=(--exclude /argon2/prebuilds)
+ fi
+ rsync "${rsync_opts[@]}" node_modules/ "$RELEASE_PATH/node_modules"
+ # Remove dev dependencies.
+ pushd "$RELEASE_PATH"
+ npm prune --production
+ popd
fi
+
+ rsync ci/build/npm-postinstall.sh "$RELEASE_PATH/postinstall.sh"
}
bundle_vscode() {
mkdir -p "$VSCODE_OUT_PATH"
- rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH"
- rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
-
- rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
- if [ "$KEEP_MODULES" = 0 ]; then
- rm -Rf "$VSCODE_OUT_PATH/extensions/node_modules"
- else
- rsync "$VSCODE_SRC_PATH/node_modules/" "$VSCODE_OUT_PATH/node_modules"
+
+ local rsync_opts=(-a)
+ if [[ ${DEBUG-} = 1 ]]; then
+ rsync_opts+=(-vh)
fi
- rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions"
- rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions"
- rsync "$VSCODE_SRC_PATH/extensions/postinstall.js" "$VSCODE_OUT_PATH/extensions"
- mkdir -p "$VSCODE_OUT_PATH/resources/linux"
- rsync "$VSCODE_SRC_PATH/resources/linux/code.png" "$VSCODE_OUT_PATH/resources/linux/code.png"
+ # Some extensions have a .gitignore which excludes their built source from the
+ # npm package so exclude any .gitignore files.
+ rsync_opts+=(--exclude .gitignore)
- # Adds the commit and date to product.json
- jq --slurp '.[0] * .[1]' "$VSCODE_SRC_PATH/product.json" <(
- cat << EOF
- {
- "commit": "$(git rev-parse HEAD)",
- "date": $(jq -n 'now | todate')
- }
-EOF
- ) > "$VSCODE_OUT_PATH/product.json"
+ # Exclude Node since we want to place it in a directory above.
+ rsync_opts+=(--exclude /node)
+
+ # Exclude Node modules. Note that these will already only include production
+ # dependencies, so if we do keep them there is no need to do any
+ # post-processing to remove dev dependencies.
+ if [[ $KEEP_MODULES = 0 ]]; then
+ rsync_opts+=(--exclude node_modules)
+ fi
+
+ rsync "${rsync_opts[@]}" "./lib/vscode-reh-web-$VSCODE_TARGET/" "$VSCODE_OUT_PATH"
+
+ # Copy the Node binary.
+ if [[ $KEEP_MODULES = 1 ]]; then
+ cp "./lib/vscode-reh-web-$VSCODE_TARGET/node" "$RELEASE_PATH/lib"
+ fi
+
+ # Merge the package.json for the web/remote server so we can include
+ # dependencies, since we want to ship this via NPM.
+ jq --slurp '.[0] * .[1]' \
+ "$VSCODE_SRC_PATH/remote/package.json" \
+ "$VSCODE_OUT_PATH/package.json" > "$VSCODE_OUT_PATH/package.json.merged"
+ mv "$VSCODE_OUT_PATH/package.json.merged" "$VSCODE_OUT_PATH/package.json"
+ cp "$VSCODE_SRC_PATH/remote/npm-shrinkwrap.json" "$VSCODE_OUT_PATH/npm-shrinkwrap.json"
+
+ # Include global extension dependencies as well.
+ rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions/package.json"
+ cp "$VSCODE_SRC_PATH/extensions/npm-shrinkwrap.json" "$VSCODE_OUT_PATH/extensions/npm-shrinkwrap.json"
+ rsync "$VSCODE_SRC_PATH/extensions/postinstall.mjs" "$VSCODE_OUT_PATH/extensions/postinstall.mjs"
+}
- # We remove the scripts field so that later on we can run
- # yarn to fetch node_modules if necessary without build scripts running.
- # We cannot use --no-scripts because we still want dependent package scripts to run.
- jq 'del(.scripts)' < "$VSCODE_SRC_PATH/package.json" > "$VSCODE_OUT_PATH/package.json"
+create_shrinkwraps() {
+ # package-lock.json files (used to ensure deterministic versions of
+ # dependencies) are not packaged when publishing to the NPM registry.
+ #
+ # To ensure deterministic dependency versions (even when code-server is
+ # installed with NPM), we create an npm-shrinkwrap.json file from the
+ # currently installed node_modules. This ensures the versions used from
+ # development (that the package-lock.json guarantees) are also the ones
+ # installed by end-users. These will include devDependencies, but those will
+ # be ignored when installing globally (for code-server), and because we use
+ # --omit=dev (for VS Code).
+
+ # We first generate the shrinkwrap file for code-server itself - which is the
+ # current directory.
+ cp package-lock.json package-lock.json.temp
+ npm shrinkwrap
+ mv package-lock.json.temp package-lock.json
+
+ # Then the shrinkwrap files for the bundled VS Code.
+ pushd "$VSCODE_SRC_PATH/remote/"
+ cp package-lock.json package-lock.json.temp
+ npm shrinkwrap
+ mv package-lock.json.temp package-lock.json
+ popd
+
+ pushd "$VSCODE_SRC_PATH/extensions/"
+ cp package-lock.json package-lock.json.temp
+ npm shrinkwrap
+ mv package-lock.json.temp package-lock.json
+ popd
}
main "$@"
diff --git a/ci/build/build-standalone-release.sh b/ci/build/build-standalone-release.sh
deleted file mode 100755
index df6cdc56f198..000000000000
--- a/ci/build/build-standalone-release.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "${0}")/../.."
- source ./ci/lib.sh
-
- rsync "$RELEASE_PATH/" "$RELEASE_PATH-standalone"
- RELEASE_PATH+=-standalone
-
- # We cannot find the path to node from $PATH because yarn shims a script to ensure
- # we use the same version it's using so we instead run a script with yarn that
- # will print the path to node.
- local node_path
- node_path="$(yarn -s node <<< 'console.info(process.execPath)')"
-
- mkdir -p "$RELEASE_PATH/bin"
- rsync ./ci/build/code-server.sh "$RELEASE_PATH/bin/code-server"
- rsync "$node_path" "$RELEASE_PATH/lib/node"
-
- ln -s "./bin/code-server" "$RELEASE_PATH/code-server"
- ln -s "./lib/node" "$RELEASE_PATH/node"
-
- cd "$RELEASE_PATH"
- yarn --production --frozen-lockfile
-}
-
-main "$@"
diff --git a/ci/build/build-vscode.sh b/ci/build/build-vscode.sh
index a7368db3af84..871a801aa30f 100755
--- a/ci/build/build-vscode.sh
+++ b/ci/build/build-vscode.sh
@@ -6,16 +6,154 @@ set -euo pipefail
# MINIFY controls whether a minified version of vscode is built.
MINIFY=${MINIFY-true}
+fix-bin-script() {
+ local script="lib/vscode-reh-web-$VSCODE_TARGET/bin/$1"
+ sed -i.bak "s/@@VERSION@@/$(vscode_version)/g" "$script"
+ sed -i.bak "s/@@COMMIT@@/$BUILD_SOURCEVERSION/g" "$script"
+ sed -i.bak "s/@@APPNAME@@/code-server/g" "$script"
+
+ # Fix Node path on Darwin and Linux.
+ # We do not want expansion here; this text should make it to the file as-is.
+ # shellcheck disable=SC2016
+ sed -i.bak 's/^ROOT=\(.*\)$/VSROOT=\1\nROOT="$(dirname "$(dirname "$VSROOT")")"/g' "$script"
+ sed -i.bak 's/ROOT\/out/VSROOT\/out/g' "$script"
+ # We do not want expansion here; this text should make it to the file as-is.
+ # shellcheck disable=SC2016
+ sed -i.bak 's/$ROOT\/node/${NODE_EXEC_PATH:-$ROOT\/lib\/node}/g' "$script"
+
+ # Fix Node path on Windows.
+ sed -i.bak 's/^set ROOT_DIR=\(.*\)$/set ROOT_DIR=%~dp0..\\..\\..\\..\r\nset VSROOT_DIR=\1/g' "$script"
+ sed -i.bak 's/%ROOT_DIR%\\out/%VSROOT_DIR%\\out/g' "$script"
+
+ chmod +x "$script"
+ rm "$script.bak"
+}
+
+copy-bin-script() {
+ cp "lib/vscode/resources/server/bin/$1" "lib/vscode-reh-web-$VSCODE_TARGET/bin/$1"
+ fix-bin-script "$1"
+}
+
main() {
cd "$(dirname "${0}")/../.."
- cd lib/vscode
- yarn gulp compile-build
- yarn gulp compile-extensions-build
- yarn gulp optimize --gulpfile ./coder.js
- if [[ $MINIFY ]]; then
- yarn gulp minify --gulpfile ./coder.js
+ source ./ci/lib.sh
+
+ # Set the commit Code will embed into the product.json. We need to do this
+ # since Code tries to get the commit from the `.git` directory which will fail
+ # as it is a submodule.
+ #
+ # Also, we use code-server's commit rather than VS Code's otherwise it would
+ # not update when only our patch files change, and that will cause caching
+ # issues where the browser keeps using outdated code.
+ export BUILD_SOURCEVERSION
+ BUILD_SOURCEVERSION=$(git rev-parse HEAD)
+
+ pushd lib/vscode
+
+ if [[ ! ${VERSION-} ]]; then
+ echo "VERSION not set. Please set before running this script:"
+ echo "VERSION='0.0.0' npm run build:vscode"
+ exit 1
+ fi
+
+ # Add the date, our name, links, enable telemetry (this just makes telemetry
+ # available; telemetry can still be disabled by flag or setting), and
+ # configure trusted extensions (since some, like github.copilot-chat, never
+ # ask to be trusted and this is the only way to get auth working).
+ #
+ # This needs to be done before building as Code will read this file and embed
+ # it into the client-side code.
+ git checkout product.json # Reset in case the script exited early.
+ cp product.json product.original.json # Since jq has no inline edit.
+ jq --slurp '.[0] * .[1]' product.original.json <(
+ cat << EOF
+ {
+ "enableTelemetry": true,
+ "quality": "stable",
+ "codeServerVersion": "$VERSION",
+ "nameShort": "code-server",
+ "nameLong": "code-server",
+ "applicationName": "code-server",
+ "dataFolderName": ".code-server",
+ "win32MutexName": "codeserver",
+ "licenseUrl": "https://github.com/coder/code-server/blob/main/LICENSE",
+ "win32DirName": "code-server",
+ "win32NameVersion": "code-server",
+ "win32AppUserModelId": "coder.code-server",
+ "win32ShellNameShort": "c&ode-server",
+ "darwinBundleIdentifier": "com.coder.code.server",
+ "linuxIconName": "com.coder.code.server",
+ "reportIssueUrl": "https://github.com/coder/code-server/issues/new",
+ "documentationUrl": "https://go.microsoft.com/fwlink/?LinkID=533484#vscode",
+ "keyboardShortcutsUrlMac": "https://go.microsoft.com/fwlink/?linkid=832143",
+ "keyboardShortcutsUrlLinux": "https://go.microsoft.com/fwlink/?linkid=832144",
+ "keyboardShortcutsUrlWin": "https://go.microsoft.com/fwlink/?linkid=832145",
+ "introductoryVideosUrl": "https://go.microsoft.com/fwlink/?linkid=832146",
+ "tipsAndTricksUrl": "https://go.microsoft.com/fwlink/?linkid=852118",
+ "newsletterSignupUrl": "https://www.research.net/r/vsc-newsletter",
+ "linkProtectionTrustedDomains": [
+ "https://open-vsx.org"
+ ],
+ "trustedExtensionAuthAccess": [
+ "vscode.git", "vscode.github",
+ "github.vscode-pull-request-github",
+ "github.copilot", "github.copilot-chat"
+ ],
+ "aiConfig": {
+ "ariaKey": "code-server"
+ }
+ }
+EOF
+ ) > product.json
+
+
+ VSCODE_QUALITY=stable npm run gulp compile-copilot-extension-full-build
+
+ npm run gulp core-ci
+ npm run gulp "vscode-reh-web-$VSCODE_TARGET${MINIFY:+-min}-ci"
+
+ # Reset so if you develop after building you will not be stuck with the wrong
+ # commit (the dev client will use `oss-dev` but the dev server will still use
+ # product.json which will have `stable-$commit`).
+ git checkout product.json
+
+ popd
+
+ pushd "lib/vscode-reh-web-$VSCODE_TARGET"
+ # Make sure Code took the version we set in the environment variable. Not
+ # having a version will break display languages.
+ if ! jq -e .commit product.json; then
+ echo "'commit' is missing from product.json"
+ exit 1
fi
+ popd
+
+ # Set vars and fix paths.
+ case $OS in
+ windows)
+ fix-bin-script remote-cli/code.cmd
+ fix-bin-script helpers/browser.cmd
+ ;;
+ *)
+ fix-bin-script remote-cli/code-server
+ fix-bin-script helpers/browser.sh
+ ;;
+ esac
+
+ # Include bin scripts for other platforms so we can use the right one in the
+ # NPM post-install.
+
+ # These provide a `code-server` command in the integrated terminal to open
+ # files in the current instance.
+ copy-bin-script remote-cli/code-darwin.sh
+ copy-bin-script remote-cli/code-linux.sh
+ copy-bin-script remote-cli/code.cmd
+
+ # These provide a way for terminal applications to open browser windows.
+ copy-bin-script helpers/browser-darwin.sh
+ copy-bin-script helpers/browser-linux.sh
+ copy-bin-script helpers/browser.cmd
}
main "$@"
diff --git a/ci/build/clean.sh b/ci/build/clean.sh
index b80632278e03..9d90836a36f6 100755
--- a/ci/build/clean.sh
+++ b/ci/build/clean.sh
@@ -6,11 +6,6 @@ main() {
source ./ci/lib.sh
git clean -Xffd
-
- pushd lib/vscode
- git clean -xffd
- git reset --hard
- popd
}
main "$@"
diff --git a/ci/build/code-server.sh b/ci/build/code-server.sh
index deb36ac31c33..801835ea843b 100755
--- a/ci/build/code-server.sh
+++ b/ci/build/code-server.sh
@@ -5,20 +5,12 @@ set -eu
# Runs code-server with the bundled node binary.
_realpath() {
- # See https://github.com/cdr/code-server/issues/1537 on why no realpath or readlink -f.
+ # See https://github.com/coder/code-server/issues/1537 on why no realpath or readlink -f.
script="$1"
cd "$(dirname "$script")"
while [ -L "$(basename "$script")" ]; do
- if [ -L "./node" ] && [ -L "./code-server" ] &&
- [ -f "package.json" ] &&
- cat package.json | grep -q '^ "name": "code-server",$'; then
- echo "***** Please use the script in bin/code-server instead!" >&2
- echo "***** This script will soon be removed!" >&2
- echo "***** See the release notes at https://github.com/cdr/code-server/releases/tag/v3.4.0" >&2
- fi
-
script="$(readlink "$(basename "$script")")"
cd "$(dirname "$script")"
done
diff --git a/ci/build/nfpm.yaml b/ci/build/nfpm.yaml
index 9c3202d23384..4b0ee371a2eb 100644
--- a/ci/build/nfpm.yaml
+++ b/ci/build/nfpm.yaml
@@ -1,19 +1,25 @@
name: "code-server"
-arch: "${ARCH}"
+arch: "${NFPM_ARCH}"
platform: "linux"
version: "v${VERSION}"
section: "devel"
priority: "optional"
-maintainer: "Anmol Sethi "
+maintainer: "Joe Previte "
description: |
Run VS Code in the browser.
vendor: "Coder"
-homepage: "https://github.com/cdr/code-server"
+homepage: "https://github.com/coder/code-server"
license: "MIT"
-files:
- ./ci/build/code-server-nfpm.sh: /usr/bin/code-server
- ./ci/build/code-server@.service: /usr/lib/systemd/system/code-server@.service
- # Only included for backwards compat with previous releases that shipped
- # the user service. See #1997
- ./ci/build/code-server-user.service: /usr/lib/systemd/user/code-server.service
- ./release-standalone/**/*: "/usr/lib/code-server/"
+
+contents:
+ - src: ./ci/build/code-server-nfpm.sh
+ dst: /usr/bin/code-server
+
+ - src: ./ci/build/code-server@.service
+ dst: /usr/lib/systemd/system/code-server@.service
+
+ - src: ./ci/build/code-server-user.service
+ dst: /usr/lib/systemd/user/code-server.service
+
+ - src: ./release/*
+ dst: /usr/lib/code-server
diff --git a/ci/build/npm-postinstall.sh b/ci/build/npm-postinstall.sh
index 743b549ff9e3..9476722648f8 100755
--- a/ci/build/npm-postinstall.sh
+++ b/ci/build/npm-postinstall.sh
@@ -1,55 +1,148 @@
#!/usr/bin/env sh
set -eu
+# Copied from ../lib.sh except we do not rename Darwin and we do not need to
+# detect Alpine.
+os() {
+ osname=$(uname | tr '[:upper:]' '[:lower:]')
+ case $osname in
+ cygwin* | mingw*) osname="windows" ;;
+ esac
+ echo "$osname"
+}
+
+# Create a symlink at $2 pointing to $1 on any platform. Anything that
+# currently exists at $2 will be deleted.
+symlink() {
+ source="$1"
+ dest="$2"
+ rm -rf "$dest"
+ case $OS in
+ windows) mklink /J "$dest" "$source" ;;
+ *) ln -s "$source" "$dest" ;;
+ esac
+}
+
+# Make a symlink at bin/$1/$3 pointing to the platform-specific version of the
+# script in $2. The extension of the link will be .cmd for Windows otherwise it
+# will be whatever is in $4 (or no extension if $4 is not set).
+symlink_bin_script() {
+ oldpwd="$(pwd)"
+ cd "bin/$1"
+ source="$2"
+ dest="$3"
+ ext="${4-}"
+ case $OS in
+ windows) symlink "$source.cmd" "$dest.cmd" ;;
+ darwin | macos) symlink "$source-darwin.sh" "$dest$ext" ;;
+ *) symlink "$source-linux.sh" "$dest$ext" ;;
+ esac
+ cd "$oldpwd"
+}
+
+command_exists() {
+ if [ ! "$1" ]; then return 1; fi
+ command -v "$@" > /dev/null
+}
+
+is_root() {
+ if command_exists id && [ "$(id -u)" = 0 ]; then
+ return 0
+ fi
+ return 1
+}
+
+OS="$(os)"
+
main() {
# Grabs the major version of node from $npm_config_user_agent which looks like
# yarn/1.21.1 npm/? node/v14.2.0 darwin x64
major_node_version=$(echo "$npm_config_user_agent" | sed -n 's/.*node\/v\([^.]*\).*/\1/p')
- if [ "$major_node_version" -lt 12 ]; then
- echo "code-server currently requires at least node v12"
- echo "We have detected that you are on node v$major_node_version"
- echo "See https://github.com/cdr/code-server/issues/1633"
- exit 1
+
+ if [ -n "${FORCE_NODE_VERSION:-}" ]; then
+ echo "WARNING: Overriding required Node.js version to v$FORCE_NODE_VERSION"
+ echo "This could lead to broken functionality, and is unsupported."
+ echo "USE AT YOUR OWN RISK!"
fi
- case "${npm_config_user_agent-}" in npm*)
- # We are running under npm.
- if [ "${npm_config_unsafe_perm-}" != "true" ]; then
- echo "Please pass --unsafe-perm to npm to install code-server"
- echo "Otherwise the postinstall script does not have permissions to run"
- echo "See https://docs.npmjs.com/misc/config#unsafe-perm"
- echo "See https://stackoverflow.com/questions/49084929/npm-sudo-global-installation-unsafe-perm"
- exit 1
+ if [ "$major_node_version" -ne "${FORCE_NODE_VERSION:-22}" ]; then
+ echo "ERROR: code-server currently requires node v22."
+ if [ -n "$FORCE_NODE_VERSION" ]; then
+ echo "However, you have overrided the version check to use v$FORCE_NODE_VERSION."
fi
- ;;
- esac
+ echo "We have detected that you are on node v$major_node_version"
+ echo "You can override this version check by setting \$FORCE_NODE_VERSION,"
+ echo "but configurations that do not use the same node version are unsupported."
+ exit 1
+ fi
- OS="$(uname | tr '[:upper:]' '[:lower:]')"
- if curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent; then
- chmod +x ./lib/coder-cloud-agent
- else
- echo "Failed to download cloud agent; --link will not work"
+ # Under npm, if we are running as root, we need --unsafe-perm otherwise
+ # post-install scripts will not have sufficient permissions to do their thing.
+ if is_root; then
+ case "${npm_config_user_agent-}" in npm*)
+ if [ "${npm_config_unsafe_perm-}" != "true" ]; then
+ echo "Please pass --unsafe-perm to npm to install code-server"
+ echo "Otherwise post-install scripts will not have permissions to run"
+ echo "See https://docs.npmjs.com/misc/config#unsafe-perm"
+ echo "See https://stackoverflow.com/questions/49084929/npm-sudo-global-installation-unsafe-perm"
+ exit 1
+ fi
+ ;;
+ esac
fi
- if ! vscode_yarn; then
+ if ! vscode_install; then
echo "You may not have the required dependencies to build the native modules."
- echo "Please see https://github.com/cdr/code-server/blob/master/doc/npm.md"
+ echo "Please see https://github.com/coder/code-server/blob/main/docs/npm.md"
exit 1
fi
+
+ if [ -n "${FORCE_NODE_VERSION:-}" ]; then
+ echo "WARNING: The required Node.js version was overriden to v$FORCE_NODE_VERSION"
+ echo "This could lead to broken functionality, and is unsupported."
+ echo "USE AT YOUR OWN RISK!"
+ fi
}
-vscode_yarn() {
+install_with_yarn_or_npm() {
+ echo "User agent: ${npm_config_user_agent-none}"
+ # For development we enforce npm, but for installing the package as an
+ # end-user we want to keep using whatever package manager is in use.
+ case "${npm_config_user_agent-}" in
+ npm*)
+ if ! npm install --unsafe-perm --omit=dev; then
+ return 1
+ fi
+ ;;
+ yarn*)
+ if ! yarn --production --frozen-lockfile --no-default-rc; then
+ return 1
+ fi
+ ;;
+ *)
+ echo "Could not determine which package manager is being used to install code-server"
+ exit 1
+ ;;
+ esac
+ return 0
+}
+
+vscode_install() {
+ echo 'Installing Code dependencies...'
cd lib/vscode
- yarn --production --frozen-lockfile
+ if ! install_with_yarn_or_npm; then
+ return 1
+ fi
+
+ symlink_bin_script remote-cli code code-server
+ symlink_bin_script helpers browser browser .sh
+
cd extensions
- yarn --production --frozen-lockfile
- for ext in */; do
- ext="${ext%/}"
- echo "extensions/$ext: installing dependencies"
- cd "$ext"
- yarn --production --frozen-lockfile
- cd "$OLDPWD"
- done
+ if ! install_with_yarn_or_npm; then
+ return 1
+ fi
+
+ return 0
}
main "$@"
diff --git a/ci/build/release-github-assets.sh b/ci/build/release-github-assets.sh
deleted file mode 100755
index 7fba67703fe5..000000000000
--- a/ci/build/release-github-assets.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-# Downloads the release artifacts from CI for the current
-# commit and then uploads them to the release with the version
-# in package.json.
-# You will need $GITHUB_TOKEN set.
-
-main() {
- cd "$(dirname "$0")/../.."
- source ./ci/lib.sh
-
- download_artifact release-packages ./release-packages
- local assets=(./release-packages/code-server*"$VERSION"*{.tar.gz,.deb,.rpm})
- for i in "${!assets[@]}"; do
- assets[$i]="--attach=${assets[$i]}"
- done
- EDITOR=true hub release edit --draft "${assets[@]}" "v$VERSION"
-}
-
-main "$@"
diff --git a/ci/build/release-github-draft.sh b/ci/build/release-github-draft.sh
deleted file mode 100755
index d311dbb656d4..000000000000
--- a/ci/build/release-github-draft.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-# Creates a draft release with the template for the version in package.json
-
-main() {
- cd "$(dirname "$0")/../.."
- source ./ci/lib.sh
-
- hub release create \
- --file - \
- -t "$(git rev-parse HEAD)" \
- --draft "${assets[@]}" "v$VERSION" << EOF
-v$VERSION
-
-VS Code v$(vscode_version)
-
-# New Features
- - ⭐ Summarize new features here with references to issues
-
-## Bug Fixes
- - ⭐ Summarize bug fixes here with references to issues
-
-Cheers! 🍻
-EOF
-}
-
-main "$@"
diff --git a/ci/build/test-standalone-release.sh b/ci/build/test-standalone-release.sh
deleted file mode 100755
index 5f5656486dff..000000000000
--- a/ci/build/test-standalone-release.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-# Makes sure the release works.
-# This is to make sure we don't have Node version errors or any other
-# compilation-related errors.
-main() {
- cd "$(dirname "${0}")/../.."
-
- local EXTENSIONS_DIR
- EXTENSIONS_DIR="$(mktemp -d)"
-
- echo "Testing standalone release."
-
- ./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension ms-python.python
- local installed_extensions
- installed_extensions="$(./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)"
- # We use grep as ms-python.python may have dependency extensions that change.
- if ! echo "$installed_extensions" | grep -q "ms-python.python"; then
- echo "Unexpected output from listing extensions:"
- echo "$installed_extensions"
- exit 1
- fi
-
- echo "Standalone release works correctly."
-}
-
-main "$@"
diff --git a/ci/build/update-repo.sh b/ci/build/update-repo.sh
new file mode 100755
index 000000000000..bc8bf522d50e
--- /dev/null
+++ b/ci/build/update-repo.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+set -Eeuo pipefail
+
+function update_helm() {
+ local current
+ current=$(yq .version ci/helm-chart/Chart.yaml)
+ local next
+ next=$(semver "$current" -i minor)
+ echo "Bumping version from $current to $next..."
+ sed -i.bak "s/^version: $current\$/version: $next/" ci/helm-chart/Chart.yaml
+
+ echo "Setting app version and image to $version..."
+ sed -i.bak "s/^appVersion: .\+\$/appVersion: $version/" ci/helm-chart/Chart.yaml
+ sed -i.bak "s/^ tag: .\+\$/ tag: '$version'/" ci/helm-chart/values.yaml
+}
+
+function update_changelog() {
+ local date
+ date=$(printf '%(%Y-%m-%d)T\n' -1)
+ local link="https://github.com/coder/code-server/releases/tag/v$version"
+ sed -i.bak "s|## Unreleased|## Unreleased\n\n## [$version]($link) - $date|" CHANGELOG.md
+}
+
+function main() {
+ cd "$(dirname "${0}")/../.."
+
+ source ./ci/lib.sh
+
+ local version=${VERSION:-$(git describe --tags)}
+ version="${version#v}"
+
+ declare -a steps
+
+ steps+=(
+ "Update Helm chart" "update_helm"
+ "Update changelog" "update_changelog"
+ )
+
+ run-steps "${steps[@]}"
+
+ # This step is always manual.
+ echo "- [ ] https://github.com/coder/code-server-aur/pulls" >> .cache/checklist
+}
+
+main "$@"
diff --git a/ci/build/update-vscode.sh b/ci/build/update-vscode.sh
new file mode 100755
index 000000000000..e0fff4886ba3
--- /dev/null
+++ b/ci/build/update-vscode.sh
@@ -0,0 +1,155 @@
+#!/usr/bin/env bash
+
+set -Eeuo pipefail
+
+function unapply_patches() {
+ local -i exit_code=0
+ quiet quilt pop -af || exit_code=$?
+ case $exit_code in
+ # Sucessfully unapplied.
+ 0) ;;
+ # No more patches to unapply.
+ 2) ;;
+ # Some error.
+ *) return $exit_code ;;
+ esac
+}
+
+function update_vscode() {
+ pushd lib/vscode
+ if ! git checkout 2>&1 "$target_vscode_version" ; then
+ echo "$target_vscode_version does not exist locally, fetching..."
+ git fetch --all --prune --tags
+ echo "Checking out $target_vscode_version again..."
+ git checkout "$target_vscode_version"
+ fi
+ popd
+}
+
+function refresh_patches() {
+ local -i exit_code=0
+ while quiet quilt push ; ! (( exit_code=$? )) ; do
+ quilt refresh
+ done
+ case $exit_code in
+ # No more patches to apply.
+ 2) ;;
+ # Some error.
+ *) return $exit_code ;;
+ esac
+}
+
+function update_node() {
+ local node_version
+ node_version=$(cat .node-version)
+ if [[ $node_version == "$target_node_version" ]] ; then
+ echo "Already set to $target_node_version"
+ else
+ echo "Updating from $node_version to $target_node_version..."
+ echo "$target_node_version" > .node-version
+ fi
+}
+
+function get-webview-script-hash() {
+ local html
+ html=$(<"$1")
+ local start_tag='"
+ html=${html##*"$start_tag"}
+ html=${html%%"$end_tag"*}
+ echo -n "$html" | openssl sha256 -binary | openssl base64
+}
+
+function update_csp() {
+ local current
+ current=$(quilt top 2>/dev/null || echo "")
+ local patch_action=""
+ echo "Currently at ${current:-base}"
+ if [[ $current != */webview.diff ]] ; then
+ echo "Moving to patches/webview.diff..."
+ local -i exit_code=0
+ if quilt applied 2>/dev/null | grep --quiet webview.diff ; then
+ quiet quilt pop webview || exit_code=$?
+ patch_action=pop
+ else
+ quiet quilt push webview || exit_code=$?
+ patch_action=push
+ fi
+ case $exit_code in
+ # Successfully moved.
+ 0) ;;
+ # Some error.
+ *) return $exit_code ;;
+ esac
+ fi
+
+ local file=lib/vscode/src/vs/workbench/contrib/webview/browser/pre/index.html
+ local hash
+ hash=$(get-webview-script-hash "$file")
+ echo "Calculated hash as $hash"
+ # Use octothorpe as a delimiter since the hash may contain a slash.
+ sed -i.bak "s#script-src 'sha256-[^']\+'#script-src 'sha256-$hash'#" "$file"
+ quilt refresh
+
+ if [[ $patch_action != "" ]] ; then
+ echo "Moving back to ${current:-base}..."
+ case $patch_action in
+ pop) quiet quilt push "$current" ;;
+ push) quiet quilt pop "${current:--a}" ;;
+ esac
+ fi
+}
+
+function add_changelog() {
+ local file=CHANGELOG.md
+ if grep --quiet "Code $target_vscode_version" "$file" ; then
+ echo "Changelog for $target_vscode_version already exists"
+ else
+ # TODO: This is not exactly robust. In particular, it needs to handle if
+ # there is already a "changed" section.
+ sed -i.bak "s/## Unreleased/## Unreleased\n\nCode v$target_vscode_version\n\n### Changed\n\n- Update to Code $target_vscode_version/" "$file"
+ fi
+}
+
+function main() {
+ cd "$(dirname "${0}")/../.."
+
+ source ./ci/lib.sh
+
+ local target_node_version
+ target_node_version=$(grep target lib/vscode/remote/.npmrc | awk -F= '{print $2}' | tr -d '"')
+
+ declare -a steps
+
+ # If version is not set, assume we are already at the target version and the
+ # user is just trying to resolve conflics.
+ local target_vscode_version
+ if [[ ${VERSION-} ]] ; then
+ # Removing patches only needs to be done locally; in CI we start from a
+ # fresh clone each time.
+ if [[ ! ${CI-} ]] ; then
+ steps+=("Unapplying patches" "unapply_patches")
+ fi
+ target_vscode_version="${VERSION#v}"
+ steps+=(
+ "Update Code to $target_vscode_version" "update_vscode"
+ "Refresh Code patches" "refresh_patches"
+ )
+ else
+ target_vscode_version="$(git -C lib/vscode describe --tags --exact-match)"
+ echo "Detected Code version $target_vscode_version"
+ fi
+
+ steps+=(
+ "Set Node version to $target_node_version" "update_node"
+ "Update CSP webview hash" "update_csp"
+ "Add changelog note" "add_changelog"
+ )
+
+ run-steps "${steps[@]}"
+
+ # This step is always manual.
+ echo "- [ ] Verify changelog" >> .cache/checklist
+}
+
+main "$@"
diff --git a/ci/dev/diff-vscode.sh b/ci/dev/diff-vscode.sh
deleted file mode 100755
index 38f7cb563416..000000000000
--- a/ci/dev/diff-vscode.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- cd ./lib/vscode
- git add -A
- git diff HEAD --full-index > ../../ci/dev/vscode.patch
-}
-
-main "$@"
diff --git a/ci/dev/doctoc.sh b/ci/dev/doctoc.sh
new file mode 100755
index 000000000000..39930f21e0b5
--- /dev/null
+++ b/ci/dev/doctoc.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+main() {
+ cd "$(dirname "$0")/../.."
+
+ doctoc --title '# FAQ' docs/FAQ.md > /dev/null
+ doctoc --title '# Setup Guide' docs/guide.md > /dev/null
+ doctoc --title '# Install' docs/install.md > /dev/null
+ doctoc --title '# npm Install Requirements' docs/npm.md > /dev/null
+ doctoc --title '# Contributing' docs/CONTRIBUTING.md > /dev/null
+ doctoc --title '# Maintaining' docs/MAINTAINING.md > /dev/null
+ doctoc --title '# Contributor Covenant Code of Conduct' docs/CODE_OF_CONDUCT.md > /dev/null
+ doctoc --title '# iPad' docs/ipad.md > /dev/null
+ doctoc --title '# Termux' docs/termux.md > /dev/null
+
+ if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then
+ echo "Files need generation or are formatted incorrectly:"
+ git -c color.ui=always status | grep --color=no '\[31m'
+ echo "Please run the following locally:"
+ echo " npm run doctoc"
+ exit 1
+ fi
+}
+
+main "$@"
diff --git a/ci/dev/fmt.sh b/ci/dev/fmt.sh
deleted file mode 100755
index ce9d7518b8a3..000000000000
--- a/ci/dev/fmt.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- shfmt -i 2 -w -sr $(git ls-files "*.sh")
-
- local prettierExts
- prettierExts=(
- "*.js"
- "*.ts"
- "*.tsx"
- "*.html"
- "*.json"
- "*.css"
- "*.md"
- "*.toml"
- "*.yaml"
- "*.yml"
- )
- prettier --write --loglevel=warn $(
- git ls-files "${prettierExts[@]}" | grep -v 'helm-chart'
- )
-
- doctoc --title '# FAQ' doc/FAQ.md > /dev/null
- doctoc --title '# Setup Guide' doc/guide.md > /dev/null
- doctoc --title '# Install' doc/install.md > /dev/null
- doctoc --title '# npm Install Requirements' doc/npm.md > /dev/null
- doctoc --title '# Contributing' doc/CONTRIBUTING.md > /dev/null
- doctoc --title '# iPad' doc/ipad.md > /dev/null
-
- if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then
- echo "Files need generation or are formatted incorrectly:"
- git -c color.ui=always status | grep --color=no '\[31m'
- echo "Please run the following locally:"
- echo " yarn fmt"
- exit 1
- fi
-}
-
-main "$@"
diff --git a/ci/dev/gen_icons.sh b/ci/dev/gen_icons.sh
new file mode 100755
index 000000000000..39d509bc4f4b
--- /dev/null
+++ b/ci/dev/gen_icons.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+set -eu
+
+# Generate icons from a single favicon.svg. favicon.svg should have no fill
+# colors set.
+main() {
+ cd src/browser/media
+
+ # We need .ico for backwards compatibility. The other two are the only icon
+ # sizes required by Chrome and we use them for stuff like apple-touch-icon as
+ # well. https://web.dev/add-manifest/
+ #
+ # This should be enough and we can always add more if there are problems.
+ #
+ # -quiet to avoid https://github.com/ImageMagick/ImageMagick/issues/884
+ # -background defaults to white but we want it transparent.
+ # -density somehow makes the image both sharper and smaller in file size.
+ #
+ # https://imagemagick.org/script/command-line-options.php#background
+ convert -quiet -background transparent \
+ -resize 256x256 -density 256x256 \
+ favicon.svg favicon.ico
+
+ # Generate PWA icons. There should be enough padding to support masking.
+ convert -quiet -border 60x60 -bordercolor white -background white \
+ -resize 192x192 -density 192x192 \
+ favicon.svg pwa-icon-maskable-192.png
+ convert -quiet -border 160x160 -bordercolor white -background white \
+ -resize 512x512 -density 512x512 \
+ favicon.svg pwa-icon-maskable-512.png
+
+ # Generate non-maskable PWA icons.
+ magick pwa-icon-maskable-192.png \
+ \( +clone -threshold 101% -fill white -draw "roundRectangle 0,0 %[fx:int(w)],%[fx:int(h)] 50,50" \) \
+ -channel-fx "| gray=>alpha" \
+ pwa-icon-192.png
+ magick pwa-icon-maskable-512.png \
+ \( +clone -threshold 101% -fill white -draw "roundRectangle 0,0 %[fx:int(w)],%[fx:int(h)] 100,100" \) \
+ -channel-fx "| gray=>alpha" \
+ pwa-icon-512.png
+
+ # The following adds dark mode support for the favicon as
+ # favicon-dark-support.svg There is no similar capability for pwas or .ico so
+ # we can only add support to the svg.
+ favicon_dark_style=""
+ cp favicon.svg favicon-dark-support.svg
+ sed "s% favicon-dark-support.svg
+}
+
+main "$@"
diff --git a/ci/dev/image/run.sh b/ci/dev/image/run.sh
deleted file mode 100755
index 3d5e15dd61f5..000000000000
--- a/ci/dev/image/run.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../../.."
- source ./ci/lib.sh
- mkdir -p .home
-
- docker run \
- -it \
- --rm \
- -v "$PWD:/src" \
- -e HOME="/src/.home" \
- -e USER="coder" \
- -e GITHUB_TOKEN \
- -e KEEP_MODULES \
- -e MINIFY \
- -w /src \
- -p 127.0.0.1:8080:8080 \
- -u "$(id -u):$(id -g)" \
- -e CI \
- "$(docker_build ./ci/images/"${IMAGE-debian10}")" \
- "$@"
-}
-
-docker_build() {
- docker build "$@" >&2
- docker build -q "$@"
-}
-
-main "$@"
diff --git a/ci/dev/lint-scripts.sh b/ci/dev/lint-scripts.sh
new file mode 100755
index 000000000000..742030affc62
--- /dev/null
+++ b/ci/dev/lint-scripts.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+main() {
+ cd "$(dirname "$0")/../.."
+ shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files '*.sh' | grep -v 'lib/vscode')
+}
+
+main "$@"
diff --git a/ci/dev/lint.sh b/ci/dev/lint.sh
deleted file mode 100755
index 6acae73ad3e0..000000000000
--- a/ci/dev/lint.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js")
- stylelint $(git ls-files "*.css")
- tsc --noEmit
- shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh")
- if command -v helm && helm kubeval --help > /dev/null; then
- helm kubeval ci/helm-chart
- fi
-}
-
-main "$@"
diff --git a/ci/dev/patch-vscode.sh b/ci/dev/patch-vscode.sh
deleted file mode 100755
index cdc2691ad978..000000000000
--- a/ci/dev/patch-vscode.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- cd ./lib/vscode
- git apply ../../ci/dev/vscode.patch
-}
-
-main "$@"
diff --git a/ci/dev/postinstall.sh b/ci/dev/postinstall.sh
new file mode 100755
index 000000000000..63aad7bcf985
--- /dev/null
+++ b/ci/dev/postinstall.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Install dependencies in $1.
+install-deps() {
+ local args=()
+ if [[ ${CI-} ]]; then
+ args+=(ci)
+ else
+ args+=(install)
+ fi
+ # If there is no package.json then npm will look upward and end up installing
+ # from the root resulting in an infinite loop (this can happen if you have not
+ # checked out the submodule yet for example).
+ if [[ ! -f "$1/package.json" ]]; then
+ echo "$1/package.json is missing; did you run git submodule update --init?"
+ exit 1
+ fi
+ pushd "$1"
+ echo "Installing dependencies for $PWD"
+ npm "${args[@]}"
+ popd
+}
+
+main() {
+ cd "$(dirname "$0")/../.."
+ source ./ci/lib.sh
+
+ install-deps test
+ install-deps test/e2e/extensions/test-extension
+ # We don't need these when running the integration tests
+ # so you can pass SKIP_SUBMODULE_DEPS
+ if [[ ! ${SKIP_SUBMODULE_DEPS-} ]]; then
+ install-deps lib/vscode
+ fi
+}
+
+main "$@"
diff --git a/ci/dev/preinstall.js b/ci/dev/preinstall.js
new file mode 100644
index 000000000000..9c4240d89696
--- /dev/null
+++ b/ci/dev/preinstall.js
@@ -0,0 +1,3 @@
+if (process.env.npm_execpath.includes("yarn")) {
+ throw new Error("`yarn` is no longer supported; please use `npm install` instead")
+}
diff --git a/ci/dev/test-e2e.sh b/ci/dev/test-e2e.sh
new file mode 100755
index 000000000000..fa748823974e
--- /dev/null
+++ b/ci/dev/test-e2e.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+help() {
+ echo >&2 " You can build with 'npm run watch' or you can build a release"
+ echo >&2 " For example: 'npm run build && npm run build:vscode && KEEP_MODULES=1 npm run release'"
+ echo >&2 " Then 'CODE_SERVER_TEST_ENTRY=./release npm run test:e2e'"
+ echo >&2 " You can manually run that release with 'node ./release'"
+}
+
+main() {
+ cd "$(dirname "$0")/../.."
+
+ source ./ci/lib.sh
+
+ pushd test/e2e/extensions/test-extension
+ echo "Building test extension"
+ npm run build
+ popd
+
+ local dir="$PWD"
+ if [[ ! ${CODE_SERVER_TEST_ENTRY-} ]]; then
+ echo "Set CODE_SERVER_TEST_ENTRY to test another build of code-server"
+ else
+ pushd "$CODE_SERVER_TEST_ENTRY"
+ dir="$PWD"
+ popd
+ fi
+
+ echo "Testing build in '$dir'"
+
+ # Simple sanity checks to see that we've built. There could still be things
+ # wrong (native modules version issues, incomplete build, etc).
+ if [[ ! -d $dir/out ]]; then
+ echo >&2 "No code-server build detected"
+ help
+ exit 1
+ fi
+
+ if [[ ! -d $dir/lib/vscode/out ]]; then
+ echo >&2 "No VS Code build detected"
+ help
+ exit 1
+ fi
+
+ cd test
+ ./node_modules/.bin/playwright test "$@"
+}
+
+main "$@"
diff --git a/ci/dev/test-integration.sh b/ci/dev/test-integration.sh
new file mode 100755
index 000000000000..36d87de8ad6d
--- /dev/null
+++ b/ci/dev/test-integration.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+help() {
+ echo >&2 " You can build the release with 'KEEP_MODULES=1 npm run release'"
+ echo >&2 " Or you can pass in a custom path."
+ echo >&2 " CODE_SERVER_PATH='/var/tmp/coder/code-server/bin/code-server' npm run test:integration"
+}
+
+# Make sure a code-server release works. You can pass in the path otherwise it
+# will look for $RELEASE_PATH in the current directory.
+#
+# This is to make sure we don't have Node version errors or any other
+# compilation-related errors.
+main() {
+ cd "$(dirname "$0")/../.."
+
+ source ./ci/lib.sh
+
+ local path="$RELEASE_PATH/bin/code-server"
+ if [[ ! ${CODE_SERVER_PATH-} ]]; then
+ echo "Set CODE_SERVER_PATH to test another build of code-server"
+ else
+ path="$CODE_SERVER_PATH"
+ fi
+
+ echo "Running tests with code-server binary: '$path'"
+
+ if [[ ! -f $path ]]; then
+ echo >&2 "No code-server build detected"
+ echo >&2 "Looked in $path"
+ help
+ exit 1
+ fi
+
+ CODE_SERVER_PATH="$path" ./test/node_modules/.bin/jest "$@" --coverage=false --testRegex "./test/integration" --testPathIgnorePatterns "./test/integration/fixtures"
+}
+
+main "$@"
diff --git a/ci/dev/test-native.sh b/ci/dev/test-native.sh
new file mode 100755
index 000000000000..8e91f9a63e3b
--- /dev/null
+++ b/ci/dev/test-native.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+help() {
+ echo >&2 " You can build the release with 'KEEP_MODULES=1 npm run release'"
+ echo >&2 " Or you can pass in a custom path."
+ echo >&2 " CODE_SERVER_PATH='/var/tmp/coder/code-server/bin/code-server' npm run test:integration"
+}
+
+# Make sure a code-server release works. You can pass in the path otherwise it
+# will look for $RELEASE_PATH in the current directory.
+#
+# This is to make sure we don't have Node version errors or any other
+# compilation-related errors.
+main() {
+ cd "$(dirname "$0")/../.."
+
+ source ./ci/lib.sh
+
+ local path="$RELEASE_PATH/bin/code-server"
+ if [[ ! ${CODE_SERVER_PATH-} ]]; then
+ echo "Set CODE_SERVER_PATH to test another build of code-server"
+ else
+ path="$CODE_SERVER_PATH"
+ fi
+
+ echo "Running tests with code-server binary: '$path'"
+
+ if [[ ! -f $path ]]; then
+ echo >&2 "No code-server build detected"
+ echo >&2 "Looked in $path"
+ help
+ exit 1
+ fi
+
+ CODE_SERVER_PATH="$path" ./test/node_modules/.bin/jest "$@" --coverage=false --testRegex "./test/integration/help.test.ts"
+}
+
+main "$@"
diff --git a/ci/dev/ci.sh b/ci/dev/test-scripts.sh
similarity index 71%
rename from ci/dev/ci.sh
rename to ci/dev/test-scripts.sh
index e92682864174..ebe1efa8ed22 100755
--- a/ci/dev/ci.sh
+++ b/ci/dev/test-scripts.sh
@@ -3,10 +3,7 @@ set -euo pipefail
main() {
cd "$(dirname "$0")/../.."
-
- yarn fmt
- yarn lint
- yarn test
+ bats ./test/scripts
}
main "$@"
diff --git a/ci/dev/test-unit.sh b/ci/dev/test-unit.sh
new file mode 100755
index 000000000000..15fd2030ea59
--- /dev/null
+++ b/ci/dev/test-unit.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+main() {
+ cd "$(dirname "$0")/../.."
+
+ source ./ci/lib.sh
+
+ # We must keep jest in a sub-directory. See ../../test/package.json for more
+ # information. We must also run it from the root otherwise coverage will not
+ # include our source files.
+ ./test/node_modules/.bin/jest "$@" --testRegex "./test/unit/.*ts"
+}
+
+main "$@"
diff --git a/ci/dev/test.sh b/ci/dev/test.sh
deleted file mode 100755
index 9922a9c84c4d..000000000000
--- a/ci/dev/test.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- cd test/test-plugin
- make -s out/index.js
- cd "$OLDPWD"
- mocha -r ts-node/register ./test/*.test.ts "$@"
-}
-
-main "$@"
diff --git a/ci/dev/vscode.patch b/ci/dev/vscode.patch
deleted file mode 100644
index f6af1c2279b8..000000000000
--- a/ci/dev/vscode.patch
+++ /dev/null
@@ -1,4102 +0,0 @@
-diff --git a/.gitignore b/.gitignore
-index b7f5b58c8ede171be547c56b61ce76f79a3accc3..856fbd8c67460fe099d7fbee1475e906b500f053 100644
---- a/.gitignore
-+++ b/.gitignore
-@@ -25,7 +25,6 @@ out-vscode-reh-web-pkg/
- out-vscode-web/
- out-vscode-web-min/
- out-vscode-web-pkg/
--src/vs/server
- resources/server
- build/node_modules
- coverage/
-diff --git a/.yarnrc b/.yarnrc
-deleted file mode 100644
-index d97527dab46aa4e7aa2df386bda3a8b4f93fcb80..0000000000000000000000000000000000000000
---- a/.yarnrc
-+++ /dev/null
-@@ -1,3 +0,0 @@
--disturl "https://electronjs.org/headers"
--target "9.3.3"
--runtime "electron"
-diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js
-index 5f367d1f0777d2cb46ad47e376337900733981b5..ba74af1d61a00ce42020418126e62879397f57bf 100644
---- a/build/gulpfile.reh.js
-+++ b/build/gulpfile.reh.js
-@@ -44,6 +44,7 @@ BUILD_TARGETS.forEach(({ platform, arch }) => {
- });
-
- function getNodeVersion() {
-+ return process.versions.node;
- const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8');
- const target = /^target "(.*)"$/m.exec(yarnrc)[1];
- return target;
-diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts
-index dac71c814798ecfac99750be856078e043d239bf..6edd7ea56baef7cd9f87a9020df32d3b8519b615 100644
---- a/build/lib/extensions.ts
-+++ b/build/lib/extensions.ts
-@@ -70,7 +70,7 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream {
- if (isWebPacked) {
- input = updateExtensionPackageJSON(input, (data: any) => {
- delete data.scripts;
-- delete data.dependencies;
-+ // https://github.com/cdr/code-server/pull/2041#issuecomment-685910322
- delete data.devDependencies;
- if (data.main) {
- data.main = data.main.replace('/out/', /dist/);
-diff --git a/build/lib/node.ts b/build/lib/node.ts
-index 64397034461b1661f82007c141cbf4c039a3b722..c53dccf4dc0a99122ed96cf10c2eb632bb25059e 100644
---- a/build/lib/node.ts
-+++ b/build/lib/node.ts
-@@ -4,13 +4,10 @@
- *--------------------------------------------------------------------------------------------*/
-
- import * as path from 'path';
--import * as fs from 'fs';
-
- const root = path.dirname(path.dirname(__dirname));
--const yarnrcPath = path.join(root, 'remote', '.yarnrc');
--const yarnrc = fs.readFileSync(yarnrcPath, 'utf8');
--const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)![1];
-+const version = process.versions.node;
- const node = process.platform === 'win32' ? 'node.exe' : 'node';
- const nodePath = path.join(root, '.build', 'node', `v${version}`, `${process.platform}-${process.arch}`, node);
-
--console.log(nodePath);
-\ No newline at end of file
-+console.log(nodePath);
-diff --git a/build/lib/util.ts b/build/lib/util.ts
-index c0a0d9619d736c6558b0b91e6c7537c1a06cc947..48853bc6201a602cadbef47a8f46281be93421e9 100644
---- a/build/lib/util.ts
-+++ b/build/lib/util.ts
-@@ -336,6 +336,7 @@ export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise {
- }
-
- export function getElectronVersion(): string {
-+ return process.versions.node;
- const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8');
- const target = /^target "(.*)"$/m.exec(yarnrc)![1];
- return target;
-diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js
-index 8f8b0019a7792a993fbd6bf95b013b596aa2935a..ea054c725bea2eec342e12b07314241aa18a4951 100644
---- a/build/npm/postinstall.js
-+++ b/build/npm/postinstall.js
-@@ -33,10 +33,11 @@ function yarnInstall(location, opts) {
-
- yarnInstall('extensions'); // node modules shared by all extensions
-
--if (!(process.platform === 'win32' && (process.arch === 'arm64' || process.env['npm_config_arch'] === 'arm64'))) {
-- yarnInstall('remote'); // node modules used by vscode server
-- yarnInstall('remote/web'); // node modules used by vscode web
--}
-+// NOTE@coder: Skip these dependencies since we don't use them.
-+// if (!(process.platform === 'win32' && (process.arch === 'arm64' || process.env['npm_config_arch'] === 'arm64'))) {
-+// yarnInstall('remote'); // node modules used by vscode server
-+// yarnInstall('remote/web'); // node modules used by vscode web
-+// }
-
- const allExtensionFolders = fs.readdirSync('extensions');
- const extensions = allExtensionFolders.filter(e => {
-@@ -69,9 +70,9 @@ runtime "${runtime}"`;
- }
-
- yarnInstall(`build`); // node modules required for build
--yarnInstall('test/automation'); // node modules required for smoketest
--yarnInstall('test/smoke'); // node modules required for smoketest
--yarnInstall('test/integration/browser'); // node modules required for integration
-+// yarnInstall('test/automation'); // node modules required for smoketest
-+// yarnInstall('test/smoke'); // node modules required for smoketest
-+// yarnInstall('test/integration/browser'); // node modules required for integration
- yarnInstallBuildDependencies(); // node modules for watching, specific to host node version, not electron
-
- cp.execSync('git config pull.rebase true');
-diff --git a/build/npm/preinstall.js b/build/npm/preinstall.js
-index cb88d37adefd4882f61a2711fdd7f72b89e1a6e3..6b3253af0a3a0aa4d75456379ef1c00f4cb98d13 100644
---- a/build/npm/preinstall.js
-+++ b/build/npm/preinstall.js
-@@ -8,8 +8,9 @@ let err = false;
- const majorNodeVersion = parseInt(/^(\d+)\./.exec(process.versions.node)[1]);
-
- if (majorNodeVersion < 10 || majorNodeVersion >= 13) {
-- console.error('\033[1;31m*** Please use node >=10 and <=12.\033[0;0m');
-- err = true;
-+ // We are ok building above Node 12.
-+ // console.error('\033[1;31m*** Please use node >=10 and <=12.\033[0;0m');
-+ // err = true;
- }
-
- const cp = require('child_process');
-diff --git a/coder.js b/coder.js
-new file mode 100644
-index 0000000000000000000000000000000000000000..df5b42cba463b6c0043aebbc835f852f1284aa36
---- /dev/null
-+++ b/coder.js
-@@ -0,0 +1,64 @@
-+// This must be ran from VS Code's root.
-+const gulp = require("gulp");
-+const path = require("path");
-+const _ = require("underscore");
-+const buildfile = require("./src/buildfile");
-+const common = require("./build/lib/optimize");
-+const util = require("./build/lib/util");
-+const deps = require("./build/dependencies");
-+
-+const vscodeEntryPoints = _.flatten([
-+ buildfile.entrypoint("vs/workbench/workbench.web.api"),
-+ buildfile.entrypoint("vs/server/entry"),
-+ buildfile.base,
-+ buildfile.workbenchWeb,
-+ buildfile.workerExtensionHost,
-+ buildfile.workerNotebook,
-+ buildfile.keyboardMaps,
-+ buildfile.entrypoint("vs/platform/files/node/watcher/unix/watcherApp", ["vs/css", "vs/nls"]),
-+ buildfile.entrypoint("vs/platform/files/node/watcher/nsfw/watcherApp", ["vs/css", "vs/nls"]),
-+ buildfile.entrypoint("vs/workbench/services/extensions/node/extensionHostProcess", ["vs/css", "vs/nls"]),
-+]);
-+
-+const vscodeResources = [
-+ "out-build/vs/server/fork.js",
-+ "!out-build/vs/server/doc/**",
-+ "out-build/vs/workbench/services/extensions/worker/extensionHostWorkerMain.js",
-+ "out-build/bootstrap.js",
-+ "out-build/bootstrap-fork.js",
-+ "out-build/bootstrap-amd.js",
-+ 'out-build/bootstrap-node.js',
-+ "out-build/paths.js",
-+ 'out-build/vs/**/*.{svg,png,html,ttf}',
-+ "!out-build/vs/code/browser/workbench/*.html",
-+ '!out-build/vs/code/electron-browser/**',
-+ "out-build/vs/base/common/performance.js",
-+ "out-build/vs/base/node/languagePacks.js",
-+ 'out-build/vs/base/browser/ui/codicons/codicon/**',
-+ "out-build/vs/workbench/browser/media/*-theme.css",
-+ "out-build/vs/workbench/contrib/debug/**/*.json",
-+ "out-build/vs/workbench/contrib/externalTerminal/**/*.scpt",
-+ "out-build/vs/workbench/contrib/webview/browser/pre/*.js",
-+ "out-build/vs/**/markdown.css",
-+ "out-build/vs/workbench/contrib/tasks/**/*.json",
-+ "out-build/vs/platform/files/**/*.md",
-+ "!**/test/**"
-+];
-+
-+gulp.task("optimize", gulp.series(
-+ util.rimraf("out-vscode"),
-+ common.optimizeTask({
-+ src: "out-build",
-+ entryPoints: vscodeEntryPoints,
-+ resources: vscodeResources,
-+ loaderConfig: common.loaderConfig(),
-+ out: "out-vscode",
-+ inlineAmdImages: true,
-+ bundleInfo: undefined
-+ }),
-+));
-+
-+gulp.task("minify", gulp.series(
-+ util.rimraf("out-vscode-min"),
-+ common.minifyTask("out-vscode")
-+));
-diff --git a/extensions/postinstall.js b/extensions/postinstall.js
-index da4fa3e9d0443d679dfbab1000b434af2ae01afd..50f3e1144f8057883dea8b91ec2f7073458dbd94 100644
---- a/extensions/postinstall.js
-+++ b/extensions/postinstall.js
-@@ -24,6 +24,9 @@ function processRoot() {
- rimraf.sync(filePath);
- }
- }
-+
-+ // Delete .bin so it doesn't contain broken symlinks that trip up nfpm.
-+ rimraf.sync(path.join(__dirname, 'node_modules', '.bin'));
- }
-
- function processLib() {
-diff --git a/extensions/typescript-language-features/src/utils/platform.ts b/extensions/typescript-language-features/src/utils/platform.ts
-index 2d754bf4054713f53beed030f9211b33532c1b4b..708b7e40a662e4ca93420992bf7a5af0c62ea5b2 100644
---- a/extensions/typescript-language-features/src/utils/platform.ts
-+++ b/extensions/typescript-language-features/src/utils/platform.ts
-@@ -6,6 +6,6 @@
- import * as vscode from 'vscode';
-
- export function isWeb(): boolean {
-- // @ts-expect-error
-+ // NOTE@coder: Remove unused ts-expect-error directive which causes tsc to error.
- return typeof navigator !== 'undefined' && vscode.env.uiKind === vscode.UIKind.Web;
- }
-diff --git a/package.json b/package.json
-index 28f8a69a2a91f9cb9f4dbd73ed3e689b2b3afe84..b5f5b10004d3e36092a30f685938a606b333c465 100644
---- a/package.json
-+++ b/package.json
-@@ -46,7 +46,11 @@
- "watch-web": "gulp watch-web --max_old_space_size=4095",
- "eslint": "eslint -c .eslintrc.json --rulesdir ./build/lib/eslint --ext .ts --ext .js ./src/vs ./extensions"
- },
-+ "dependencies_comment": "Move rimraf to dependencies because it is used in the postinstall script.",
- "dependencies": {
-+ "@coder/logger": "^1.1.12",
-+ "@coder/node-browser": "^1.0.8",
-+ "@coder/requirefs": "^1.1.5",
- "applicationinsights": "1.0.8",
- "chokidar": "3.4.3",
- "graceful-fs": "4.2.3",
-@@ -60,6 +64,7 @@
- "native-keymap": "2.2.0",
- "native-watchdog": "1.3.0",
- "node-pty": "0.10.0-beta17",
-+ "rimraf": "^2.2.8",
- "spdlog": "^0.11.1",
- "sudo-prompt": "9.1.1",
- "tas-client-umd": "0.1.2",
-@@ -161,7 +166,6 @@
- "pump": "^1.0.1",
- "queue": "3.0.6",
- "rcedit": "^1.1.0",
-- "rimraf": "^2.2.8",
- "sinon": "^1.17.2",
- "source-map": "^0.4.4",
- "style-loader": "^1.0.0",
-@@ -193,5 +197,8 @@
- "windows-foreground-love": "0.2.0",
- "windows-mutex": "0.3.0",
- "windows-process-tree": "0.2.4"
-+ },
-+ "resolutions": {
-+ "minimist": "^1.2.5"
- }
- }
-diff --git a/product.json b/product.json
-index 7cab6d1b9f3b84bfc703856e93773a293fd198cf..31d3d5a943192eee791e1121415b436dc1ed3822 100644
---- a/product.json
-+++ b/product.json
-@@ -20,7 +20,7 @@
- "darwinBundleIdentifier": "com.visualstudio.code.oss",
- "linuxIconName": "com.visualstudio.code.oss",
- "licenseFileName": "LICENSE.txt",
-- "reportIssueUrl": "https://github.com/microsoft/vscode/issues/new",
-+ "reportIssueUrl": "https://github.com/cdr/code-server/issues/new",
- "urlProtocol": "code-oss",
- "extensionAllowedProposedApi": [
- "ms-vscode.vscode-js-profile-flame",
-diff --git a/remote/.yarnrc b/remote/.yarnrc
-deleted file mode 100644
-index c1a32ce532afa501fb19bdbcf6bcb0ec151ecd99..0000000000000000000000000000000000000000
---- a/remote/.yarnrc
-+++ /dev/null
-@@ -1,3 +0,0 @@
--disturl "http://nodejs.org/dist"
--target "12.14.1"
--runtime "node"
-diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts
-index f475b10e5e81d5c2511d8d36ca5fa30a54bc415a..e9a30b2cd2a7848241d9a430c28faccb51efdb9b 100644
---- a/src/vs/base/common/network.ts
-+++ b/src/vs/base/common/network.ts
-@@ -113,16 +113,17 @@ class RemoteAuthoritiesImpl {
- if (host && host.indexOf(':') !== -1) {
- host = `[${host}]`;
- }
-- const port = this._ports[authority];
-+ // const port = this._ports[authority];
- const connectionToken = this._connectionTokens[authority];
- let query = `path=${encodeURIComponent(uri.path)}`;
- if (typeof connectionToken === 'string') {
- query += `&tkn=${encodeURIComponent(connectionToken)}`;
- }
-+ // NOTE@coder: Changed this to work against the current path.
- return URI.from({
- scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,
-- authority: `${host}:${port}`,
-- path: `/vscode-remote-resource`,
-+ authority: window.location.host,
-+ path: `${window.location.pathname.replace(/\/+$/, '')}/vscode-remote-resource`,
- query
- });
- }
-diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts
-index 3361d83be5b7c3d08bdbfbe6947942a4695882c6..69ead8484e042bbad7075659f8e47f074bc217e4 100644
---- a/src/vs/base/common/platform.ts
-+++ b/src/vs/base/common/platform.ts
-@@ -71,6 +71,18 @@ if (typeof navigator === 'object' && !isElectronRenderer) {
- _isWeb = true;
- _locale = navigator.language;
- _language = _locale;
-+
-+ // NOTE@coder: Make languages work.
-+ const el = typeof document !== 'undefined' && document.getElementById('vscode-remote-nls-configuration');
-+ const rawNlsConfig = el && el.getAttribute('data-settings');
-+ if (rawNlsConfig) {
-+ try {
-+ const nlsConfig: NLSConfig = JSON.parse(rawNlsConfig);
-+ _locale = nlsConfig.locale;
-+ _translationsConfigFile = nlsConfig._translationsConfigFile;
-+ _language = nlsConfig.availableLanguages['*'] || LANGUAGE_DEFAULT;
-+ } catch (error) { /* Oh well. */ }
-+ }
- }
-
- // Native environment
-diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts
-index 17895a8510bca40924524dc107c33305c4783c45..ba019b43084e3998ab399108968c3c765a79eb32 100644
---- a/src/vs/base/common/processes.ts
-+++ b/src/vs/base/common/processes.ts
-@@ -112,6 +112,7 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve
- /^VSCODE_.+$/,
- /^SNAP(|_.*)$/,
- /^GDK_PIXBUF_.+$/,
-+ /^CODE_SERVER_.+$/,
- ];
- const envKeys = Object.keys(env);
- envKeys
-diff --git a/src/vs/base/common/uriIpc.ts b/src/vs/base/common/uriIpc.ts
-index ef2291d49b13c9c995afc90eab9c92afabc2b3b4..29b2f9dfc2b7fa998ac1188db06dee95419fcd5b 100644
---- a/src/vs/base/common/uriIpc.ts
-+++ b/src/vs/base/common/uriIpc.ts
-@@ -5,6 +5,7 @@
-
- import { URI, UriComponents } from 'vs/base/common/uri';
- import { MarshalledObject } from 'vs/base/common/marshalling';
-+import { Schemas } from './network';
-
- export interface IURITransformer {
- transformIncoming(uri: UriComponents): UriComponents;
-@@ -31,29 +32,35 @@ function toJSON(uri: URI): UriComponents {
-
- export class URITransformer implements IURITransformer {
-
-- private readonly _uriTransformer: IRawURITransformer;
--
-- constructor(uriTransformer: IRawURITransformer) {
-- this._uriTransformer = uriTransformer;
-+ constructor(private readonly remoteAuthority: string) {
- }
-
-+ // NOTE@coder: Coming in from the browser it'll be vscode-remote so it needs
-+ // to be transformed into file.
- public transformIncoming(uri: UriComponents): UriComponents {
-- const result = this._uriTransformer.transformIncoming(uri);
-- return (result === uri ? uri : toJSON(URI.from(result)));
-+ return uri.scheme === Schemas.vscodeRemote
-+ ? toJSON(URI.file(uri.path))
-+ : uri;
- }
-
-+ // NOTE@coder: Going out to the browser it'll be file so it needs to be
-+ // transformed into vscode-remote.
- public transformOutgoing(uri: UriComponents): UriComponents {
-- const result = this._uriTransformer.transformOutgoing(uri);
-- return (result === uri ? uri : toJSON(URI.from(result)));
-+ return uri.scheme === Schemas.file
-+ ? toJSON(URI.from({ authority: this.remoteAuthority, scheme: Schemas.vscodeRemote, path: uri.path }))
-+ : uri;
- }
-
- public transformOutgoingURI(uri: URI): URI {
-- const result = this._uriTransformer.transformOutgoing(uri);
-- return (result === uri ? uri : URI.from(result));
-+ return uri.scheme === Schemas.file
-+ ? URI.from({ authority: this.remoteAuthority, scheme: Schemas.vscodeRemote, path:uri.path })
-+ : uri;
- }
-
- public transformOutgoingScheme(scheme: string): string {
-- return this._uriTransformer.transformOutgoingScheme(scheme);
-+ return scheme === Schemas.file
-+ ? Schemas.vscodeRemote
-+ : scheme;
- }
- }
-
-@@ -152,4 +159,4 @@ export function transformAndReviveIncomingURIs(obj: T, transformer: IURITrans
- return obj;
- }
- return result;
--}
-\ No newline at end of file
-+}
-diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js
-index 2c64061da7b01aef0bfe3cec851da232ca9461c8..c0ef8faedd406c38bf9c55bbbdbbb060046492d9 100644
---- a/src/vs/base/node/languagePacks.js
-+++ b/src/vs/base/node/languagePacks.js
-@@ -128,7 +128,10 @@ function factory(nodeRequire, path, fs, perf) {
- function getLanguagePackConfigurations(userDataPath) {
- const configFile = path.join(userDataPath, 'languagepacks.json');
- try {
-- return nodeRequire(configFile);
-+ // NOTE@coder: Swapped require with readFile since require is cached and
-+ // we don't restart the server-side portion of code-server when the
-+ // language changes.
-+ return JSON.parse(fs.readFileSync(configFile, "utf8"));
- } catch (err) {
- // Do nothing. If we can't read the file we have no
- // language pack config.
-diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts
-index 0ef8b9dc81419b53b27cf111fb206d72ba56bada..62a79602a831bca0dc62ad57dc10a9375f8b9cdb 100644
---- a/src/vs/code/browser/workbench/workbench.ts
-+++ b/src/vs/code/browser/workbench/workbench.ts
-@@ -17,6 +17,7 @@ import { isStandalone } from 'vs/base/browser/browser';
- import { localize } from 'vs/nls';
- import { Schemas } from 'vs/base/common/network';
- import product from 'vs/platform/product/common/product';
-+import { encodePath } from 'vs/server/node/util';
-
- function doCreateUri(path: string, queryValues: Map): URI {
- let query: string | undefined = undefined;
-@@ -309,12 +310,18 @@ class WorkspaceProvider implements IWorkspaceProvider {
-
- // Folder
- else if (isFolderToOpen(workspace)) {
-- targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${encodeURIComponent(workspace.folderUri.toString())}`;
-+ const target = workspace.folderUri.scheme === Schemas.vscodeRemote
-+ ? encodePath(workspace.folderUri.path)
-+ : encodeURIComponent(workspace.folderUri.toString());
-+ targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${target}`;
- }
-
- // Workspace
- else if (isWorkspaceToOpen(workspace)) {
-- targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${encodeURIComponent(workspace.workspaceUri.toString())}`;
-+ const target = workspace.workspaceUri.scheme === Schemas.vscodeRemote
-+ ? encodePath(workspace.workspaceUri.path)
-+ : encodeURIComponent(workspace.workspaceUri.toString());
-+ targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${target}`;
- }
-
- // Append payload if any
-@@ -404,7 +411,22 @@ class WindowIndicator implements IWindowIndicator {
- throw new Error('Missing web configuration element');
- }
-
-- const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = JSON.parse(configElementAttribute);
-+ const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = {
-+ webviewEndpoint: `${window.location.origin}${window.location.pathname.replace(/\/+$/, '')}/webview`,
-+ ...JSON.parse(configElementAttribute),
-+ };
-+
-+ // Strip the protocol from the authority if it exists.
-+ const normalizeAuthority = (authority: string): string => authority.replace(/^https?:\/\//, "");
-+ if (config.remoteAuthority) {
-+ (config as any).remoteAuthority = normalizeAuthority(config.remoteAuthority);
-+ }
-+ if (config.workspaceUri && config.workspaceUri.authority) {
-+ config.workspaceUri.authority = normalizeAuthority(config.workspaceUri.authority);
-+ }
-+ if (config.folderUri && config.folderUri.authority) {
-+ config.folderUri.authority = normalizeAuthority(config.folderUri.authority);
-+ }
-
- // Revive static extension locations
- if (Array.isArray(config.staticExtensions)) {
-@@ -416,40 +438,7 @@ class WindowIndicator implements IWindowIndicator {
- // Find workspace to open and payload
- let foundWorkspace = false;
- let workspace: IWorkspace;
-- let payload = Object.create(null);
--
-- const query = new URL(document.location.href).searchParams;
-- query.forEach((value, key) => {
-- switch (key) {
--
-- // Folder
-- case WorkspaceProvider.QUERY_PARAM_FOLDER:
-- workspace = { folderUri: URI.parse(value) };
-- foundWorkspace = true;
-- break;
--
-- // Workspace
-- case WorkspaceProvider.QUERY_PARAM_WORKSPACE:
-- workspace = { workspaceUri: URI.parse(value) };
-- foundWorkspace = true;
-- break;
--
-- // Empty
-- case WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW:
-- workspace = undefined;
-- foundWorkspace = true;
-- break;
--
-- // Payload
-- case WorkspaceProvider.QUERY_PARAM_PAYLOAD:
-- try {
-- payload = JSON.parse(value);
-- } catch (error) {
-- console.error(error); // possible invalid JSON
-- }
-- break;
-- }
-- });
-+ let payload = config.workspaceProvider?.payload || Object.create(null);
-
- // If no workspace is provided through the URL, check for config attribute from server
- if (!foundWorkspace) {
-diff --git a/src/vs/platform/environment/common/argv.ts b/src/vs/platform/environment/common/argv.ts
-index 409bb7e1960c9c06485a6f6d7f39b2efce451d56..f27b651c49ea3fc92b03e31eb64c1cf27c7e4433 100644
---- a/src/vs/platform/environment/common/argv.ts
-+++ b/src/vs/platform/environment/common/argv.ts
-@@ -7,6 +7,8 @@
- * A list of command line arguments we support natively.
- */
- export interface NativeParsedArgs {
-+ 'extra-extensions-dir'?: string[];
-+ 'extra-builtin-extensions-dir'?: string[];
- _: string[];
- 'folder-uri'?: string[]; // undefined or array of 1 or more
- 'file-uri'?: string[]; // undefined or array of 1 or more
-diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts
-index 21b4d719cec1a724bbad407aeec38db9eb8d6f5a..edf46f097bf11bfb8883d38d38ee78b735f35b3f 100644
---- a/src/vs/platform/environment/common/environment.ts
-+++ b/src/vs/platform/environment/common/environment.ts
-@@ -122,6 +122,8 @@ export interface INativeEnvironmentService extends IEnvironmentService {
- extensionsPath?: string;
- extensionsDownloadPath: string;
- builtinExtensionsPath: string;
-+ extraExtensionPaths: string[]
-+ extraBuiltinExtensionPaths: string[]
-
- // --- Smoke test support
- driverHandle?: string;
-diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts
-index 149e6ffb41a82f1a69cf37f105a31872ad4af8b4..ed99aab42b31bc2ab804391b6e3f4c7ff67d9259 100644
---- a/src/vs/platform/environment/node/argv.ts
-+++ b/src/vs/platform/environment/node/argv.ts
-@@ -54,6 +54,8 @@ export const OPTIONS: OptionDescriptions> = {
- 'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") },
- 'extensions-download-dir': { type: 'string' },
- 'builtin-extensions-dir': { type: 'string' },
-+ 'extra-builtin-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra builtin extension directory.' },
-+ 'extra-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra user extension directory.' },
- 'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") },
- 'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") },
- 'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") },
-@@ -318,4 +320,3 @@ export function buildHelpMessage(productName: string, executableName: string, ve
- export function buildVersionMessage(version: string | undefined, commit: string | undefined): string {
- return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`;
- }
--
-diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts
-index 80f68fb1decfd1c4fa1bcc30840900240df83f76..d4478b0000a511af11647876a536b8147163f9f8 100644
---- a/src/vs/platform/environment/node/environmentService.ts
-+++ b/src/vs/platform/environment/node/environmentService.ts
-@@ -138,6 +138,13 @@ export class NativeEnvironmentService implements INativeEnvironmentService {
- return resources.joinPath(this.userHome, product.dataFolderName, 'extensions').fsPath;
- }
-
-+ @memoize get extraExtensionPaths(): string[] {
-+ return (this._args['extra-extensions-dir'] || []).map((p) => parsePathArg(p, process));
-+ }
-+ @memoize get extraBuiltinExtensionPaths(): string[] {
-+ return (this._args['extra-builtin-extensions-dir'] || []).map((p) => parsePathArg(p, process));
-+ }
-+
- @memoize
- get extensionDevelopmentLocationURI(): URI[] | undefined {
- const s = this._args.extensionDevelopmentPath;
-diff --git a/src/vs/platform/extensionManagement/node/extensionsScanner.ts b/src/vs/platform/extensionManagement/node/extensionsScanner.ts
-index aee65f8eddbfbce3e42362be9590c98d46f2ace5..dc891fba7c7af3ace02b0091ef858bea59e754c6 100644
---- a/src/vs/platform/extensionManagement/node/extensionsScanner.ts
-+++ b/src/vs/platform/extensionManagement/node/extensionsScanner.ts
-@@ -91,7 +91,7 @@ export class ExtensionsScanner extends Disposable {
- }
-
- async scanAllUserExtensions(): Promise {
-- return this.scanExtensionsInDir(this.extensionsPath, ExtensionType.User);
-+ return this.scanExtensionsInDirs(this.extensionsPath, this.environmentService.extraExtensionPaths, ExtensionType.User);
- }
-
- async extractUserExtension(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, token: CancellationToken): Promise {
-@@ -236,7 +236,13 @@ export class ExtensionsScanner extends Disposable {
-
- private async scanExtensionsInDir(dir: string, type: ExtensionType): Promise {
- const limiter = new Limiter(10);
-- const extensionsFolders = await pfs.readdir(dir);
-+ const extensionsFolders = await pfs.readdir(dir)
-+ .catch((error) => {
-+ if (error.code !== 'ENOENT') {
-+ throw error;
-+ }
-+ return [];
-+ });
- const extensions = await Promise.all(extensionsFolders.map(extensionFolder => limiter.queue(() => this.scanExtension(extensionFolder, dir, type))));
- return extensions.filter(e => e && e.identifier);
- }
-@@ -266,7 +272,7 @@ export class ExtensionsScanner extends Disposable {
- }
-
- private async scanDefaultSystemExtensions(): Promise {
-- const result = await this.scanExtensionsInDir(this.systemExtensionsPath, ExtensionType.System);
-+ const result = await this.scanExtensionsInDirs(this.systemExtensionsPath, this.environmentService.extraBuiltinExtensionPaths, ExtensionType.System);
- this.logService.trace('Scanned system extensions:', result.length);
- return result;
- }
-@@ -370,4 +376,9 @@ export class ExtensionsScanner extends Disposable {
- }
- });
- }
-+
-+ private async scanExtensionsInDirs(dir: string, dirs: string[], type: ExtensionType): Promise{
-+ const results = await Promise.all([dir, ...dirs].map((path) => this.scanExtensionsInDir(path, type)));
-+ return results.reduce((flat, current) => flat.concat(current), []);
-+ }
- }
-diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts
-index 2bea85740cb3e00c955ec0f7aa46d5f9bb8d5dc8..c0953d7b73178fc4a7b030246a5281609c3dfce6 100644
---- a/src/vs/platform/product/common/product.ts
-+++ b/src/vs/platform/product/common/product.ts
-@@ -37,6 +37,12 @@ if (isWeb || typeof require === 'undefined' || typeof require.__$__nodeRequire !
- ],
- });
- }
-+ // NOTE@coder: Add the ability to inject settings from the server.
-+ const el = document.getElementById('vscode-remote-product-configuration');
-+ const rawProductConfiguration = el && el.getAttribute('data-settings');
-+ if (rawProductConfiguration) {
-+ Object.assign(product, JSON.parse(rawProductConfiguration));
-+ }
- }
-
- // Native (non-sandboxed)
-diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts
-index 333e5b24b05c96e8d44e9025b7a777e6989de9e7..b13572327a6e91592eedea9bcb1e580397f5c224 100644
---- a/src/vs/platform/product/common/productService.ts
-+++ b/src/vs/platform/product/common/productService.ts
-@@ -32,6 +32,8 @@ export type ConfigurationSyncStore = {
- };
-
- export interface IProductConfiguration {
-+ readonly codeServerVersion?: string;
-+
- readonly version: string;
- readonly date?: string;
- readonly quality?: string;
-diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts
-index 3715cbb8e6ee41c3d9b5090918d243b723ae2d00..c65de8ad37e727d66da97a8f8b170cbcef87181b 100644
---- a/src/vs/platform/remote/browser/browserSocketFactory.ts
-+++ b/src/vs/platform/remote/browser/browserSocketFactory.ts
-@@ -208,7 +208,8 @@ export class BrowserSocketFactory implements ISocketFactory {
- }
-
- connect(host: string, port: number, query: string, callback: IConnectCallback): void {
-- const socket = this._webSocketFactory.create(`ws://${host}:${port}/?${query}&skipWebSocketFrames=false`);
-+ // NOTE@coder: Modified to work against the current path.
-+ const socket = this._webSocketFactory.create(`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}${window.location.pathname}?${query}&skipWebSocketFrames=false`);
- const errorListener = socket.onError((err) => callback(err, undefined));
- socket.onOpen(() => {
- errorListener.dispose();
-@@ -216,6 +217,3 @@ export class BrowserSocketFactory implements ISocketFactory {
- });
- }
- }
--
--
--
-diff --git a/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts
-index fdd5890c69f72025b94913380f0d226226e8c8fb..e084236526b38c1144d47b8b3000b367c3207fe8 100644
---- a/src/vs/platform/remote/common/remoteAgentConnection.ts
-+++ b/src/vs/platform/remote/common/remoteAgentConnection.ts
-@@ -93,7 +93,7 @@ async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptio
- options.socketFactory.connect(
- options.host,
- options.port,
-- `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`,
-+ `type=${connectionTypeToString(connectionType)}&reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`,
- (err: any, socket: ISocket | undefined) => {
- if (err || !socket) {
- options.logService.error(`${logPrefix} socketFactory.connect() failed. Error:`);
-diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts
-index ab3fd347b69f8a3d9b96e706cd87c911b8ffed6b..9d351037b577f9f1edfd18ae9b3c48a211f4467f 100644
---- a/src/vs/platform/storage/browser/storageService.ts
-+++ b/src/vs/platform/storage/browser/storageService.ts
-@@ -122,8 +122,8 @@ export class BrowserStorageService extends Disposable implements IStorageService
- return this.getStorage(scope).getNumber(key, fallbackValue);
- }
-
-- store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void {
-- this.getStorage(scope).set(key, value);
-+ store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise {
-+ return this.getStorage(scope).set(key, value);
- }
-
- remove(key: string, scope: StorageScope): void {
-diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts
-index 6611f1dae42055f69a55c1c154d9475f11cd4d0a..d598d4909d5ff6d1614e4a038b1865e1f9a4e963 100644
---- a/src/vs/platform/storage/common/storage.ts
-+++ b/src/vs/platform/storage/common/storage.ts
-@@ -85,7 +85,7 @@ export interface IStorageService {
- * The scope argument allows to define the scope of the storage
- * operation to either the current workspace only or all workspaces.
- */
-- store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void;
-+ store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise | void;
-
- /**
- * Delete an element stored under the provided key from storage.
-diff --git a/src/vs/platform/storage/node/storageService.ts b/src/vs/platform/storage/node/storageService.ts
-index 096b9e23493539c9937940a56e555d95bbae38d9..ef37e614004f550f7b64eacd362f6894fc523a42 100644
---- a/src/vs/platform/storage/node/storageService.ts
-+++ b/src/vs/platform/storage/node/storageService.ts
-@@ -201,8 +201,8 @@ export class NativeStorageService extends Disposable implements IStorageService
- return this.getStorage(scope).getNumber(key, fallbackValue);
- }
-
-- store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void {
-- this.getStorage(scope).set(key, value);
-+ store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise {
-+ return this.getStorage(scope).set(key, value);
- }
-
- remove(key: string, scope: StorageScope): void {
-diff --git a/src/vs/server/browser/client.ts b/src/vs/server/browser/client.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..3c0703b7174ad792a4b42841e96ee93765d71601
---- /dev/null
-+++ b/src/vs/server/browser/client.ts
-@@ -0,0 +1,189 @@
-+import { Emitter } from 'vs/base/common/event';
-+import { URI } from 'vs/base/common/uri';
-+import { localize } from 'vs/nls';
-+import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
-+import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
-+import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
-+import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
-+import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
-+import { Registry } from 'vs/platform/registry/common/platform';
-+import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
-+import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
-+import { INodeProxyService, NodeProxyChannelClient } from 'vs/server/common/nodeProxy';
-+import { TelemetryChannelClient } from 'vs/server/common/telemetry';
-+import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
-+import { LocalizationsService } from 'vs/workbench/services/localizations/electron-browser/localizationsService';
-+import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
-+import { Options } from 'vs/server/ipc.d';
-+import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
-+
-+class TelemetryService extends TelemetryChannelClient {
-+ public constructor(
-+ @IRemoteAgentService remoteAgentService: IRemoteAgentService,
-+ ) {
-+ super(remoteAgentService.getConnection()!.getChannel('telemetry'));
-+ }
-+}
-+
-+/**
-+ * Remove extra slashes in a URL.
-+ */
-+export const normalize = (url: string, keepTrailing = false): string => {
-+ return url.replace(/\/\/+/g, "/").replace(/\/+$/, keepTrailing ? "/" : "");
-+};
-+
-+/**
-+ * Get options embedded in the HTML.
-+ */
-+export const getOptions = (): T => {
-+ try {
-+ return JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!);
-+ } catch (error) {
-+ return {} as T;
-+ }
-+};
-+
-+const options = getOptions();
-+
-+const TELEMETRY_SECTION_ID = 'telemetry';
-+Registry.as(Extensions.Configuration).registerConfiguration({
-+ 'id': TELEMETRY_SECTION_ID,
-+ 'order': 110,
-+ 'type': 'object',
-+ 'title': localize('telemetryConfigurationTitle', 'Telemetry'),
-+ 'properties': {
-+ 'telemetry.enableTelemetry': {
-+ 'type': 'boolean',
-+ 'description': localize('telemetry.enableTelemetry', 'Enable usage data and errors to be sent to a Microsoft online service.'),
-+ 'default': !options.disableTelemetry,
-+ 'tags': ['usesOnlineServices']
-+ }
-+ }
-+});
-+
-+class NodeProxyService extends NodeProxyChannelClient implements INodeProxyService {
-+ private readonly _onClose = new Emitter();
-+ public readonly onClose = this._onClose.event;
-+ private readonly _onDown = new Emitter();
-+ public readonly onDown = this._onDown.event;
-+ private readonly _onUp = new Emitter();
-+ public readonly onUp = this._onUp.event;
-+
-+ public constructor(
-+ @IRemoteAgentService remoteAgentService: IRemoteAgentService,
-+ ) {
-+ super(remoteAgentService.getConnection()!.getChannel('nodeProxy'));
-+ remoteAgentService.getConnection()!.onDidStateChange((state) => {
-+ switch (state.type) {
-+ case PersistentConnectionEventType.ConnectionGain:
-+ return this._onUp.fire();
-+ case PersistentConnectionEventType.ConnectionLost:
-+ return this._onDown.fire();
-+ case PersistentConnectionEventType.ReconnectionPermanentFailure:
-+ return this._onClose.fire();
-+ }
-+ });
-+ }
-+}
-+
-+registerSingleton(ILocalizationsService, LocalizationsService);
-+registerSingleton(INodeProxyService, NodeProxyService);
-+registerSingleton(ITelemetryService, TelemetryService);
-+
-+/**
-+ * This is called by vs/workbench/browser/web.main.ts after the workbench has
-+ * been initialized so we can initialize our own client-side code.
-+ */
-+export const initialize = async (services: ServiceCollection): Promise => {
-+ const event = new CustomEvent('ide-ready');
-+ window.dispatchEvent(event);
-+
-+ if (parent) {
-+ // Tell the parent loading has completed.
-+ parent.postMessage({ event: 'loaded' }, window.location.origin);
-+
-+ // Proxy or stop proxing events as requested by the parent.
-+ const listeners = new Map void>();
-+ window.addEventListener('message', (parentEvent) => {
-+ const eventName = parentEvent.data.bind || parentEvent.data.unbind;
-+ if (eventName) {
-+ const oldListener = listeners.get(eventName);
-+ if (oldListener) {
-+ document.removeEventListener(eventName, oldListener);
-+ }
-+ }
-+
-+ if (parentEvent.data.bind && parentEvent.data.prop) {
-+ const listener = (event: Event) => {
-+ parent.postMessage({
-+ event: parentEvent.data.event,
-+ [parentEvent.data.prop]: event[parentEvent.data.prop as keyof Event]
-+ }, window.location.origin);
-+ };
-+ listeners.set(parentEvent.data.bind, listener);
-+ document.addEventListener(parentEvent.data.bind, listener);
-+ }
-+ });
-+ }
-+
-+ if (!window.isSecureContext) {
-+ (services.get(INotificationService) as INotificationService).notify({
-+ severity: Severity.Warning,
-+ message: 'code-server is being accessed over an insecure domain. Web views, the clipboard, and other functionality will not work as expected.',
-+ actions: {
-+ primary: [{
-+ id: 'understand',
-+ label: 'I understand',
-+ tooltip: '',
-+ class: undefined,
-+ enabled: true,
-+ checked: true,
-+ dispose: () => undefined,
-+ run: () => {
-+ return Promise.resolve();
-+ }
-+ }],
-+ }
-+ });
-+ }
-+
-+ // This will be used to set the background color while VS Code loads.
-+ const theme = (services.get(IStorageService) as IStorageService).get("colorThemeData", StorageScope.GLOBAL);
-+ if (theme) {
-+ localStorage.setItem("colorThemeData", theme);
-+ }
-+};
-+
-+export interface Query {
-+ [key: string]: string | undefined;
-+}
-+
-+/**
-+ * Split a string up to the delimiter. If the delimiter doesn't exist the first
-+ * item will have all the text and the second item will be an empty string.
-+ */
-+export const split = (str: string, delimiter: string): [string, string] => {
-+ const index = str.indexOf(delimiter);
-+ return index !== -1 ? [str.substring(0, index).trim(), str.substring(index + 1)] : [str, ''];
-+};
-+
-+/**
-+ * Return the URL modified with the specified query variables. It's pretty
-+ * stupid so it probably doesn't cover any edge cases. Undefined values will
-+ * unset existing values. Doesn't allow duplicates.
-+ */
-+export const withQuery = (url: string, replace: Query): string => {
-+ const uri = URI.parse(url);
-+ const query = { ...replace };
-+ uri.query.split('&').forEach((kv) => {
-+ const [key, value] = split(kv, '=');
-+ if (!(key in query)) {
-+ query[key] = value;
-+ }
-+ });
-+ return uri.with({
-+ query: Object.keys(query)
-+ .filter((k) => typeof query[k] !== 'undefined')
-+ .map((k) => `${k}=${query[k]}`).join('&'),
-+ }).toString(true);
-+};
-diff --git a/src/vs/server/browser/extHostNodeProxy.ts b/src/vs/server/browser/extHostNodeProxy.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..5dd5406befcb593ad6366d9e98f46485ed14fbc0
---- /dev/null
-+++ b/src/vs/server/browser/extHostNodeProxy.ts
-@@ -0,0 +1,51 @@
-+import { Emitter } from 'vs/base/common/event';
-+import { UriComponents } from 'vs/base/common/uri';
-+import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
-+import { ExtHostNodeProxyShape, MainContext, MainThreadNodeProxyShape } from 'vs/workbench/api/common/extHost.protocol';
-+import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
-+
-+export class ExtHostNodeProxy implements ExtHostNodeProxyShape {
-+ _serviceBrand: any;
-+
-+ private readonly _onMessage = new Emitter();
-+ public readonly onMessage = this._onMessage.event;
-+ private readonly _onClose = new Emitter();
-+ public readonly onClose = this._onClose.event;
-+ private readonly _onDown = new Emitter();
-+ public readonly onDown = this._onDown.event;
-+ private readonly _onUp = new Emitter();
-+ public readonly onUp = this._onUp.event;
-+
-+ private readonly proxy: MainThreadNodeProxyShape;
-+
-+ constructor(@IExtHostRpcService rpc: IExtHostRpcService) {
-+ this.proxy = rpc.getProxy(MainContext.MainThreadNodeProxy);
-+ }
-+
-+ public $onMessage(message: string): void {
-+ this._onMessage.fire(message);
-+ }
-+
-+ public $onClose(): void {
-+ this._onClose.fire();
-+ }
-+
-+ public $onUp(): void {
-+ this._onUp.fire();
-+ }
-+
-+ public $onDown(): void {
-+ this._onDown.fire();
-+ }
-+
-+ public send(message: string): void {
-+ this.proxy.$send(message);
-+ }
-+
-+ public async fetchExtension(extensionUri: UriComponents): Promise {
-+ return this.proxy.$fetchExtension(extensionUri).then(b => b.buffer);
-+ }
-+}
-+
-+export interface IExtHostNodeProxy extends ExtHostNodeProxy { }
-+export const IExtHostNodeProxy = createDecorator('IExtHostNodeProxy');
-diff --git a/src/vs/server/browser/mainThreadNodeProxy.ts b/src/vs/server/browser/mainThreadNodeProxy.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..21a139288e5b8f56016491879d69d01da929decb
---- /dev/null
-+++ b/src/vs/server/browser/mainThreadNodeProxy.ts
-@@ -0,0 +1,55 @@
-+import { VSBuffer } from 'vs/base/common/buffer';
-+import { IDisposable } from 'vs/base/common/lifecycle';
-+import { FileAccess } from 'vs/base/common/network';
-+import { URI, UriComponents } from 'vs/base/common/uri';
-+import { INodeProxyService } from 'vs/server/common/nodeProxy';
-+import { ExtHostContext, IExtHostContext, MainContext, MainThreadNodeProxyShape } from 'vs/workbench/api/common/extHost.protocol';
-+import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
-+
-+@extHostNamedCustomer(MainContext.MainThreadNodeProxy)
-+export class MainThreadNodeProxy implements MainThreadNodeProxyShape {
-+ private disposed = false;
-+ private disposables = [];
-+
-+ constructor(
-+ extHostContext: IExtHostContext,
-+ @INodeProxyService private readonly proxyService: INodeProxyService,
-+ ) {
-+ if (!extHostContext.remoteAuthority) { // HACK: A terrible way to detect if running in the worker.
-+ const proxy = extHostContext.getProxy(ExtHostContext.ExtHostNodeProxy);
-+ this.disposables = [
-+ this.proxyService.onMessage((message: string) => proxy.$onMessage(message)),
-+ this.proxyService.onClose(() => proxy.$onClose()),
-+ this.proxyService.onDown(() => proxy.$onDown()),
-+ this.proxyService.onUp(() => proxy.$onUp()),
-+ ];
-+ }
-+ }
-+
-+ $send(message: string): void {
-+ if (!this.disposed) {
-+ this.proxyService.send(message);
-+ }
-+ }
-+
-+ async $fetchExtension(extensionUri: UriComponents): Promise {
-+ const fetchUri = URI.from({
-+ scheme: window.location.protocol.replace(':', ''),
-+ authority: window.location.host,
-+ // Use FileAccess to get the static base path.
-+ path: FileAccess.asBrowserUri("", require).path,
-+ query: `tar=${encodeURIComponent(extensionUri.path)}`,
-+ });
-+ const response = await fetch(fetchUri.toString(true));
-+ if (response.status !== 200) {
-+ throw new Error(`Failed to download extension "${module}"`);
-+ }
-+ return VSBuffer.wrap(new Uint8Array(await response.arrayBuffer()));
-+ }
-+
-+ dispose(): void {
-+ this.disposables.forEach((d) => d.dispose());
-+ this.disposables = [];
-+ this.disposed = true;
-+ }
-+}
-diff --git a/src/vs/server/browser/worker.ts b/src/vs/server/browser/worker.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..1d47ede49b76b1774329269ab5c86fedb5712c19
---- /dev/null
-+++ b/src/vs/server/browser/worker.ts
-@@ -0,0 +1,48 @@
-+import { Client } from '@coder/node-browser';
-+import { fromTar } from '@coder/requirefs';
-+import { URI } from 'vs/base/common/uri';
-+import { ILogService } from 'vs/platform/log/common/log';
-+import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator';
-+import { IExtHostNodeProxy } from './extHostNodeProxy';
-+
-+export const loadCommonJSModule = async (
-+ module: URI,
-+ activationTimesBuilder: ExtensionActivationTimesBuilder,
-+ nodeProxy: IExtHostNodeProxy,
-+ logService: ILogService,
-+ vscode: any,
-+): Promise => {
-+ const client = new Client(nodeProxy, { logger: logService });
-+ const [buffer, init] = await Promise.all([
-+ nodeProxy.fetchExtension(module),
-+ client.handshake(),
-+ ]);
-+ const rfs = fromTar(buffer);
-+ (self).global = self;
-+ rfs.provide('vscode', vscode);
-+ Object.keys(client.modules).forEach((key) => {
-+ const mod = (client.modules as any)[key];
-+ if (key === 'process') {
-+ (self).process = mod;
-+ (self).process.env = init.env;
-+ return;
-+ }
-+
-+ rfs.provide(key, mod);
-+ switch (key) {
-+ case 'buffer':
-+ (self).Buffer = mod.Buffer;
-+ break;
-+ case 'timers':
-+ (self).setImmediate = mod.setImmediate;
-+ break;
-+ }
-+ });
-+
-+ try {
-+ activationTimesBuilder.codeLoadingStart();
-+ return rfs.require('.');
-+ } finally {
-+ activationTimesBuilder.codeLoadingStop();
-+ }
-+};
-diff --git a/src/vs/server/common/nodeProxy.ts b/src/vs/server/common/nodeProxy.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..14b9de879ceab4c1976770fa7810d276c5aa3e36
---- /dev/null
-+++ b/src/vs/server/common/nodeProxy.ts
-@@ -0,0 +1,47 @@
-+import { ReadWriteConnection } from '@coder/node-browser';
-+import { Event } from 'vs/base/common/event';
-+import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
-+import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
-+
-+export const INodeProxyService = createDecorator('nodeProxyService');
-+
-+export interface INodeProxyService extends ReadWriteConnection {
-+ _serviceBrand: any;
-+ send(message: string): void;
-+ onMessage: Event;
-+ onUp: Event;
-+ onClose: Event;
-+ onDown: Event;
-+}
-+
-+export class NodeProxyChannel implements IServerChannel {
-+ constructor(private service: INodeProxyService) {}
-+
-+ listen(_: unknown, event: string): Event {
-+ switch (event) {
-+ case 'onMessage': return this.service.onMessage;
-+ }
-+ throw new Error(`Invalid listen ${event}`);
-+ }
-+
-+ async call(_: unknown, command: string, args?: any): Promise {
-+ switch (command) {
-+ case 'send': return this.service.send(args[0]);
-+ }
-+ throw new Error(`Invalid call ${command}`);
-+ }
-+}
-+
-+export class NodeProxyChannelClient {
-+ _serviceBrand: any;
-+
-+ public readonly onMessage: Event;
-+
-+ constructor(private readonly channel: IChannel) {
-+ this.onMessage = this.channel.listen('onMessage');
-+ }
-+
-+ public send(data: string): void {
-+ this.channel.call('send', [data]);
-+ }
-+}
-diff --git a/src/vs/server/common/telemetry.ts b/src/vs/server/common/telemetry.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..4ea6d95d36aaac07dbd4d0e16ab3c1bba255f683
---- /dev/null
-+++ b/src/vs/server/common/telemetry.ts
-@@ -0,0 +1,65 @@
-+import { ITelemetryData } from 'vs/base/common/actions';
-+import { Event } from 'vs/base/common/event';
-+import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
-+import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
-+import { ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
-+
-+export class TelemetryChannel implements IServerChannel {
-+ constructor(private service: ITelemetryService) {}
-+
-+ listen(_: unknown, event: string): Event {
-+ throw new Error(`Invalid listen ${event}`);
-+ }
-+
-+ call(_: unknown, command: string, args?: any): Promise {
-+ switch (command) {
-+ case 'publicLog': return this.service.publicLog(args[0], args[1], args[2]);
-+ case 'publicLog2': return this.service.publicLog2(args[0], args[1], args[2]);
-+ case 'publicLogError': return this.service.publicLogError(args[0], args[1]);
-+ case 'publicLogError2': return this.service.publicLogError2(args[0], args[1]);
-+ case 'setEnabled': return Promise.resolve(this.service.setEnabled(args[0]));
-+ case 'getTelemetryInfo': return this.service.getTelemetryInfo();
-+ case 'setExperimentProperty': return Promise.resolve(this.service.setExperimentProperty(args[0], args[1]));
-+ }
-+ throw new Error(`Invalid call ${command}`);
-+ }
-+}
-+
-+export class TelemetryChannelClient implements ITelemetryService {
-+ _serviceBrand: any;
-+
-+ // These don't matter; telemetry is sent to the Node side which decides
-+ // whether to send the telemetry event.
-+ public isOptedIn = true;
-+ public sendErrorTelemetry = true;
-+
-+ constructor(private readonly channel: IChannel) {}
-+
-+ public publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise {
-+ return this.channel.call('publicLog', [eventName, data, anonymizeFilePaths]);
-+ }
-+
-+ public publicLog2 = never, T extends GDPRClassification = never>(eventName: string, data?: StrictPropertyCheck, anonymizeFilePaths?: boolean): Promise {
-+ return this.channel.call('publicLog2', [eventName, data, anonymizeFilePaths]);
-+ }
-+
-+ public publicLogError(errorEventName: string, data?: ITelemetryData): Promise {
-+ return this.channel.call('publicLogError', [errorEventName, data]);
-+ }
-+
-+ public publicLogError2 = never, T extends GDPRClassification = never>(eventName: string, data?: StrictPropertyCheck): Promise {
-+ return this.channel.call('publicLogError2', [eventName, data]);
-+ }
-+
-+ public setEnabled(value: boolean): void {
-+ this.channel.call('setEnable', [value]);
-+ }
-+
-+ public getTelemetryInfo(): Promise {
-+ return this.channel.call('getTelemetryInfo');
-+ }
-+
-+ public setExperimentProperty(name: string, value: string): void {
-+ this.channel.call('setExperimentProperty', [name, value]);
-+ }
-+}
-diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..8482c48bae007ed6b39183001ae2cc6d140fcd50
---- /dev/null
-+++ b/src/vs/server/entry.ts
-@@ -0,0 +1,79 @@
-+import { field } from '@coder/logger';
-+import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
-+import { CodeServerMessage, VscodeMessage } from 'vs/server/ipc';
-+import { logger } from 'vs/server/node/logger';
-+import { enableCustomMarketplace } from 'vs/server/node/marketplace';
-+import { Vscode } from 'vs/server/node/server';
-+
-+setUnexpectedErrorHandler((error) => logger.warn(error instanceof Error ? error.message : error));
-+enableCustomMarketplace();
-+
-+/**
-+ * Ensure we control when the process exits.
-+ */
-+const exit = process.exit;
-+process.exit = function(code?: number) {
-+ logger.warn(`process.exit() was prevented: ${code || 'unknown code'}.`);
-+} as (code?: number) => never;
-+
-+// Kill VS Code if the parent process dies.
-+if (typeof process.env.CODE_SERVER_PARENT_PID !== 'undefined') {
-+ const parentPid = parseInt(process.env.CODE_SERVER_PARENT_PID, 10);
-+ setInterval(() => {
-+ try {
-+ process.kill(parentPid, 0); // Throws an exception if the process doesn't exist anymore.
-+ } catch (e) {
-+ exit();
-+ }
-+ }, 5000);
-+} else {
-+ logger.error('no parent process');
-+ exit(1);
-+}
-+
-+const vscode = new Vscode();
-+const send = (message: VscodeMessage): void => {
-+ if (!process.send) {
-+ throw new Error('not spawned with IPC');
-+ }
-+ process.send(message);
-+};
-+
-+// Wait for the init message then start up VS Code. Subsequent messages will
-+// return new workbench options without starting a new instance.
-+process.on('message', async (message: CodeServerMessage, socket) => {
-+ logger.debug('got message from code-server', field('type', message.type));
-+ logger.trace('code-server message content', field('message', message));
-+ switch (message.type) {
-+ case 'init':
-+ try {
-+ const options = await vscode.initialize(message.options);
-+ send({ type: 'options', id: message.id, options });
-+ } catch (error) {
-+ logger.error(error.message);
-+ logger.error(error.stack);
-+ exit(1);
-+ }
-+ break;
-+ case 'cli':
-+ try {
-+ await vscode.cli(message.args);
-+ exit(0);
-+ } catch (error) {
-+ logger.error(error.message);
-+ logger.error(error.stack);
-+ exit(1);
-+ }
-+ break;
-+ case 'socket':
-+ vscode.handleWebSocket(socket, message.query);
-+ break;
-+ }
-+});
-+if (!process.send) {
-+ logger.error('not spawned with IPC');
-+ exit(1);
-+} else {
-+ // This lets the parent know the child is ready to receive messages.
-+ send({ type: 'ready' });
-+}
-diff --git a/src/vs/server/fork.js b/src/vs/server/fork.js
-new file mode 100644
-index 0000000000000000000000000000000000000000..56331ff1fc32bbd82e769aaecb551e427f798ec3
---- /dev/null
-+++ b/src/vs/server/fork.js
-@@ -0,0 +1,3 @@
-+// This must be a JS file otherwise when it gets compiled it turns into AMD
-+// syntax which will not work without the right loader.
-+require('../../bootstrap-amd').load('vs/server/entry');
-diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..6ce56bec114a6d8daf5dd3ded945ea78fc72a5c6
---- /dev/null
-+++ b/src/vs/server/ipc.d.ts
-@@ -0,0 +1,131 @@
-+/**
-+ * External interfaces for integration into code-server over IPC. No vs imports
-+ * should be made in this file.
-+ */
-+export interface Options {
-+ disableTelemetry: boolean
-+}
-+
-+export interface InitMessage {
-+ type: 'init';
-+ id: string;
-+ options: VscodeOptions;
-+}
-+
-+export type Query = { [key: string]: string | string[] | undefined | Query | Query[] };
-+
-+export interface SocketMessage {
-+ type: 'socket';
-+ query: Query;
-+}
-+
-+export interface CliMessage {
-+ type: 'cli';
-+ args: Args;
-+}
-+
-+export interface OpenCommandPipeArgs {
-+ type: 'open';
-+ fileURIs?: string[];
-+ folderURIs: string[];
-+ forceNewWindow?: boolean;
-+ diffMode?: boolean;
-+ addMode?: boolean;
-+ gotoLineMode?: boolean;
-+ forceReuseWindow?: boolean;
-+ waitMarkerFilePath?: string;
-+}
-+
-+export type CodeServerMessage = InitMessage | SocketMessage | CliMessage;
-+
-+export interface ReadyMessage {
-+ type: 'ready';
-+}
-+
-+export interface OptionsMessage {
-+ id: string;
-+ type: 'options';
-+ options: WorkbenchOptions;
-+}
-+
-+export type VscodeMessage = ReadyMessage | OptionsMessage;
-+
-+export interface StartPath {
-+ url: string;
-+ workspace: boolean;
-+}
-+
-+export interface Args {
-+ 'user-data-dir'?: string;
-+
-+ 'enable-proposed-api'?: string[];
-+ 'extensions-dir'?: string;
-+ 'builtin-extensions-dir'?: string;
-+ 'extra-extensions-dir'?: string[];
-+ 'extra-builtin-extensions-dir'?: string[];
-+
-+ locale?: string
-+
-+ log?: string;
-+ verbose?: boolean;
-+
-+ _: string[];
-+}
-+
-+export interface VscodeOptions {
-+ readonly args: Args;
-+ readonly remoteAuthority: string;
-+ readonly startPath?: StartPath;
-+}
-+
-+export interface VscodeOptionsMessage extends VscodeOptions {
-+ readonly id: string;
-+}
-+
-+export interface UriComponents {
-+ readonly scheme: string;
-+ readonly authority: string;
-+ readonly path: string;
-+ readonly query: string;
-+ readonly fragment: string;
-+}
-+
-+export interface NLSConfiguration {
-+ locale: string;
-+ availableLanguages: {
-+ [key: string]: string;
-+ };
-+ pseudo?: boolean;
-+ _languagePackSupport?: boolean;
-+}
-+
-+export interface WorkbenchOptions {
-+ readonly workbenchWebConfiguration: {
-+ readonly remoteAuthority?: string;
-+ readonly folderUri?: UriComponents;
-+ readonly workspaceUri?: UriComponents;
-+ readonly logLevel?: number;
-+ readonly workspaceProvider?: {
-+ payload: [
-+ ["userDataPath", string],
-+ ["enableProposedApi", string],
-+ ];
-+ };
-+ };
-+ readonly remoteUserDataUri: UriComponents;
-+ readonly productConfiguration: {
-+ codeServerVersion?: string;
-+ readonly extensionsGallery?: {
-+ readonly serviceUrl: string;
-+ readonly itemUrl: string;
-+ readonly controlUrl: string;
-+ readonly recommendationsUrl: string;
-+ };
-+ };
-+ readonly nlsConfiguration: NLSConfiguration;
-+ readonly commit: string;
-+}
-+
-+export interface WorkbenchOptionsMessage {
-+ id: string;
-+}
-diff --git a/src/vs/server/node/channel.ts b/src/vs/server/node/channel.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..693174ee0d21353c3a08a42fd30eaad1e95c3b9d
---- /dev/null
-+++ b/src/vs/server/node/channel.ts
-@@ -0,0 +1,897 @@
-+import { field, logger } from '@coder/logger';
-+import { Server } from '@coder/node-browser';
-+import * as os from 'os';
-+import * as path from 'path';
-+import { VSBuffer } from 'vs/base/common/buffer';
-+import { CancellationTokenSource } from 'vs/base/common/cancellation';
-+import { Emitter, Event } from 'vs/base/common/event';
-+import { IDisposable } from 'vs/base/common/lifecycle';
-+import * as platform from 'vs/base/common/platform';
-+import * as resources from 'vs/base/common/resources';
-+import { ReadableStreamEventPayload } from 'vs/base/common/stream';
-+import { URI, UriComponents } from 'vs/base/common/uri';
-+import { transformOutgoingURIs } from 'vs/base/common/uriIpc';
-+import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
-+import { IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics';
-+import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
-+import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
-+import { FileDeleteOptions, FileOpenOptions, FileOverwriteOptions, FileReadStreamOptions, FileType, FileWriteOptions, IStat, IWatchOptions } from 'vs/platform/files/common/files';
-+import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
-+import { ILogService } from 'vs/platform/log/common/log';
-+import product from 'vs/platform/product/common/product';
-+import { IRemoteAgentEnvironment, RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
-+import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
-+import { INodeProxyService } from 'vs/server/common/nodeProxy';
-+import { getTranslations } from 'vs/server/node/nls';
-+import { getUriTransformer } from 'vs/server/node/util';
-+import { IFileChangeDto } from 'vs/workbench/api/common/extHost.protocol';
-+import { IEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
-+import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
-+import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
-+import * as terminal from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel';
-+import { IShellLaunchConfig, ITerminalEnvironment, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
-+import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
-+import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
-+import { getSystemShell } from 'vs/workbench/contrib/terminal/node/terminal';
-+import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
-+import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
-+import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
-+import { ExtensionScanner, ExtensionScannerInput } from 'vs/workbench/services/extensions/node/extensionPoints';
-+
-+/**
-+ * Extend the file provider to allow unwatching.
-+ */
-+class Watcher extends DiskFileSystemProvider {
-+ public readonly watches = new Map();
-+
-+ public dispose(): void {
-+ this.watches.forEach((w) => w.dispose());
-+ this.watches.clear();
-+ super.dispose();
-+ }
-+
-+ public _watch(req: number, resource: URI, opts: IWatchOptions): void {
-+ this.watches.set(req, this.watch(resource, opts));
-+ }
-+
-+ public unwatch(req: number): void {
-+ this.watches.get(req)!.dispose();
-+ this.watches.delete(req);
-+ }
-+}
-+
-+export class FileProviderChannel implements IServerChannel, IDisposable {
-+ private readonly provider: DiskFileSystemProvider;
-+ private readonly watchers = new Map();
-+
-+ public constructor(
-+ private readonly environmentService: INativeEnvironmentService,
-+ private readonly logService: ILogService,
-+ ) {
-+ this.provider = new DiskFileSystemProvider(this.logService);
-+ }
-+
-+ public listen(context: RemoteAgentConnectionContext, event: string, args?: any): Event {
-+ switch (event) {
-+ case 'filechange': return this.filechange(context, args[0]);
-+ case 'readFileStream': return this.readFileStream(args[0], args[1]);
-+ }
-+
-+ throw new Error(`Invalid listen '${event}'`);
-+ }
-+
-+ private filechange(context: RemoteAgentConnectionContext, session: string): Event {
-+ const emitter = new Emitter({
-+ onFirstListenerAdd: () => {
-+ const provider = new Watcher(this.logService);
-+ this.watchers.set(session, provider);
-+ const transformer = getUriTransformer(context.remoteAuthority);
-+ provider.onDidChangeFile((events) => {
-+ emitter.fire(events.map((event) => ({
-+ ...event,
-+ resource: transformer.transformOutgoing(event.resource),
-+ })));
-+ });
-+ provider.onDidErrorOccur((event) => this.logService.error(event));
-+ },
-+ onLastListenerRemove: () => {
-+ this.watchers.get(session)!.dispose();
-+ this.watchers.delete(session);
-+ },
-+ });
-+
-+ return emitter.event;
-+ }
-+
-+ private readFileStream(resource: UriComponents, opts: FileReadStreamOptions): Event> {
-+ const cts = new CancellationTokenSource();
-+ const fileStream = this.provider.readFileStream(this.transform(resource), opts, cts.token);
-+ const emitter = new Emitter>({
-+ onFirstListenerAdd: () => {
-+ fileStream.on('data', (data) => emitter.fire(VSBuffer.wrap(data)));
-+ fileStream.on('error', (error) => emitter.fire(error));
-+ fileStream.on('end', () => emitter.fire('end'));
-+ },
-+ onLastListenerRemove: () => cts.cancel(),
-+ });
-+
-+ return emitter.event;
-+ }
-+
-+ public call(_: unknown, command: string, args?: any): Promise {
-+ switch (command) {
-+ case 'stat': return this.stat(args[0]);
-+ case 'open': return this.open(args[0], args[1]);
-+ case 'close': return this.close(args[0]);
-+ case 'read': return this.read(args[0], args[1], args[2]);
-+ case 'readFile': return this.readFile(args[0]);
-+ case 'write': return this.write(args[0], args[1], args[2], args[3], args[4]);
-+ case 'writeFile': return this.writeFile(args[0], args[1], args[2]);
-+ case 'delete': return this.delete(args[0], args[1]);
-+ case 'mkdir': return this.mkdir(args[0]);
-+ case 'readdir': return this.readdir(args[0]);
-+ case 'rename': return this.rename(args[0], args[1], args[2]);
-+ case 'copy': return this.copy(args[0], args[1], args[2]);
-+ case 'watch': return this.watch(args[0], args[1], args[2], args[3]);
-+ case 'unwatch': return this.unwatch(args[0], args[1]);
-+ }
-+
-+ throw new Error(`Invalid call '${command}'`);
-+ }
-+
-+ public dispose(): void {
-+ this.watchers.forEach((w) => w.dispose());
-+ this.watchers.clear();
-+ }
-+
-+ private async stat(resource: UriComponents): Promise {
-+ return this.provider.stat(this.transform(resource));
-+ }
-+
-+ private async open(resource: UriComponents, opts: FileOpenOptions): Promise {
-+ return this.provider.open(this.transform(resource), opts);
-+ }
-+
-+ private async close(fd: number): Promise {
-+ return this.provider.close(fd);
-+ }
-+
-+ private async read(fd: number, pos: number, length: number): Promise<[VSBuffer, number]> {
-+ const buffer = VSBuffer.alloc(length);
-+ const bytesRead = await this.provider.read(fd, pos, buffer.buffer, 0, length);
-+ return [buffer, bytesRead];
-+ }
-+
-+ private async readFile(resource: UriComponents): Promise {
-+ return VSBuffer.wrap(await this.provider.readFile(this.transform(resource)));
-+ }
-+
-+ private write(fd: number, pos: number, buffer: VSBuffer, offset: number, length: number): Promise {
-+ return this.provider.write(fd, pos, buffer.buffer, offset, length);
-+ }
-+
-+ private writeFile(resource: UriComponents, buffer: VSBuffer, opts: FileWriteOptions): Promise {
-+ return this.provider.writeFile(this.transform(resource), buffer.buffer, opts);
-+ }
-+
-+ private async delete(resource: UriComponents, opts: FileDeleteOptions): Promise {
-+ return this.provider.delete(this.transform(resource), opts);
-+ }
-+
-+ private async mkdir(resource: UriComponents): Promise {
-+ return this.provider.mkdir(this.transform(resource));
-+ }
-+
-+ private async readdir(resource: UriComponents): Promise<[string, FileType][]> {
-+ return this.provider.readdir(this.transform(resource));
-+ }
-+
-+ private async rename(resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise {
-+ return this.provider.rename(this.transform(resource), URI.from(target), opts);
-+ }
-+
-+ private copy(resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise {
-+ return this.provider.copy(this.transform(resource), URI.from(target), opts);
-+ }
-+
-+ private async watch(session: string, req: number, resource: UriComponents, opts: IWatchOptions): Promise {
-+ this.watchers.get(session)!._watch(req, this.transform(resource), opts);
-+ }
-+
-+ private async unwatch(session: string, req: number): Promise {
-+ this.watchers.get(session)!.unwatch(req);
-+ }
-+
-+ private transform(resource: UriComponents): URI {
-+ // Used for walkthrough content.
-+ if (/^\/static[^/]*\//.test(resource.path)) {
-+ return URI.file(this.environmentService.appRoot + resource.path.replace(/^\/static[^/]*\//, '/'));
-+ // Used by the webview service worker to load resources.
-+ } else if (resource.path === '/vscode-resource' && resource.query) {
-+ try {
-+ const query = JSON.parse(resource.query);
-+ if (query.requestResourcePath) {
-+ return URI.file(query.requestResourcePath);
-+ }
-+ } catch (error) { /* Carry on. */ }
-+ }
-+ return URI.from(resource);
-+ }
-+}
-+
-+// See ../../workbench/services/remote/common/remoteAgentEnvironmentChannel.ts
-+export class ExtensionEnvironmentChannel implements IServerChannel {
-+ public constructor(
-+ private readonly environment: INativeEnvironmentService,
-+ private readonly log: ILogService,
-+ private readonly telemetry: ITelemetryService,
-+ private readonly connectionToken: string,
-+ ) {}
-+
-+ public listen(_: unknown, event: string): Event {
-+ throw new Error(`Invalid listen '${event}'`);
-+ }
-+
-+ public async call(context: any, command: string, args: any): Promise {
-+ switch (command) {
-+ case 'getEnvironmentData':
-+ return transformOutgoingURIs(
-+ await this.getEnvironmentData(),
-+ getUriTransformer(context.remoteAuthority),
-+ );
-+ case 'scanExtensions':
-+ return transformOutgoingURIs(
-+ await this.scanExtensions(args.language),
-+ getUriTransformer(context.remoteAuthority),
-+ );
-+ case 'getDiagnosticInfo': return this.getDiagnosticInfo();
-+ case 'disableTelemetry': return this.disableTelemetry();
-+ case 'logTelemetry': return this.logTelemetry(args[0], args[1]);
-+ case 'flushTelemetry': return this.flushTelemetry();
-+ }
-+ throw new Error(`Invalid call '${command}'`);
-+ }
-+
-+ private async getEnvironmentData(): Promise {
-+ return {
-+ pid: process.pid,
-+ connectionToken: this.connectionToken,
-+ appRoot: URI.file(this.environment.appRoot),
-+ settingsPath: this.environment.settingsResource,
-+ logsPath: URI.file(this.environment.logsPath),
-+ extensionsPath: URI.file(this.environment.extensionsPath!),
-+ extensionHostLogsPath: URI.file(path.join(this.environment.logsPath, 'extension-host')),
-+ globalStorageHome: this.environment.globalStorageHome,
-+ workspaceStorageHome: this.environment.workspaceStorageHome,
-+ userHome: this.environment.userHome,
-+ os: platform.OS,
-+ };
-+ }
-+
-+ private async scanExtensions(language: string): Promise {
-+ const translations = await getTranslations(language, this.environment.userDataPath);
-+
-+ const scanMultiple = (isBuiltin: boolean, isUnderDevelopment: boolean, paths: string[]): Promise => {
-+ return Promise.all(paths.map((path) => {
-+ return ExtensionScanner.scanExtensions(new ExtensionScannerInput(
-+ product.version,
-+ product.commit,
-+ language,
-+ !!process.env.VSCODE_DEV,
-+ path,
-+ isBuiltin,
-+ isUnderDevelopment,
-+ translations,
-+ ), this.log);
-+ }));
-+ };
-+
-+ const scanBuiltin = async (): Promise => {
-+ return scanMultiple(true, false, [this.environment.builtinExtensionsPath, ...this.environment.extraBuiltinExtensionPaths]);
-+ };
-+
-+ const scanInstalled = async (): Promise => {
-+ return scanMultiple(false, true, [this.environment.extensionsPath!, ...this.environment.extraExtensionPaths]);
-+ };
-+
-+ return Promise.all([scanBuiltin(), scanInstalled()]).then((allExtensions) => {
-+ const uniqueExtensions = new Map();
-+ allExtensions.forEach((multipleExtensions) => {
-+ multipleExtensions.forEach((extensions) => {
-+ extensions.forEach((extension) => {
-+ const id = ExtensionIdentifier.toKey(extension.identifier);
-+ if (uniqueExtensions.has(id)) {
-+ const oldPath = uniqueExtensions.get(id)!.extensionLocation.fsPath;
-+ const newPath = extension.extensionLocation.fsPath;
-+ this.log.warn(`${oldPath} has been overridden ${newPath}`);
-+ }
-+ uniqueExtensions.set(id, {
-+ ...extension,
-+ // Force extensions that should run on the client due to latency
-+ // issues.
-+ extensionKind: extension.identifier.value === 'vscodevim.vim'
-+ ? [ 'web' ]
-+ : extension.extensionKind,
-+ });
-+ });
-+ });
-+ });
-+ return Array.from(uniqueExtensions.values());
-+ });
-+ }
-+
-+ private getDiagnosticInfo(): Promise {
-+ throw new Error('not implemented');
-+ }
-+
-+ private async disableTelemetry(): Promise {
-+ this.telemetry.setEnabled(false);
-+ }
-+
-+ private async logTelemetry(eventName: string, data: ITelemetryData): Promise {
-+ this.telemetry.publicLog(eventName, data);
-+ }
-+
-+ private async flushTelemetry(): Promise {
-+ // We always send immediately at the moment.
-+ }
-+}
-+
-+export class NodeProxyService implements INodeProxyService {
-+ public _serviceBrand = undefined;
-+
-+ public readonly server: Server;
-+
-+ private readonly _onMessage = new Emitter();
-+ public readonly onMessage = this._onMessage.event;
-+ private readonly _$onMessage = new Emitter();
-+ public readonly $onMessage = this._$onMessage.event;
-+ public readonly _onDown = new Emitter();
-+ public readonly onDown = this._onDown.event;
-+ public readonly _onUp = new Emitter();
-+ public readonly onUp = this._onUp.event;
-+
-+ // Unused because the server connection will never permanently close.
-+ private readonly _onClose = new Emitter();
-+ public readonly onClose = this._onClose.event;
-+
-+ public constructor() {
-+ // TODO: down/up
-+ this.server = new Server({
-+ onMessage: this.$onMessage,
-+ onClose: this.onClose,
-+ onDown: this.onDown,
-+ onUp: this.onUp,
-+ send: (message: string): void => {
-+ this._onMessage.fire(message);
-+ }
-+ });
-+ }
-+
-+ public send(message: string): void {
-+ this._$onMessage.fire(message);
-+ }
-+}
-+
-+class VariableResolverService extends AbstractVariableResolverService {
-+ constructor(
-+ remoteAuthority: string,
-+ args: terminal.ICreateTerminalProcessArguments,
-+ env: platform.IProcessEnvironment,
-+ ) {
-+ super({
-+ getFolderUri: (name: string): URI | undefined => {
-+ const folder = args.workspaceFolders.find((f) => f.name === name);
-+ return folder && URI.revive(folder.uri);
-+ },
-+ getWorkspaceFolderCount: (): number => {
-+ return args.workspaceFolders.length;
-+ },
-+ // In ../../workbench/contrib/terminal/common/remoteTerminalChannel.ts it
-+ // looks like there are `config:` entries which must be for this? Not sure
-+ // how/if the URI comes into play though.
-+ getConfigurationValue: (_: URI, section: string): string | undefined => {
-+ return args.resolvedVariables[`config:${section}`];
-+ },
-+ getExecPath: (): string | undefined => {
-+ // Assuming that resolverEnv is just for use in the resolver and not for
-+ // the terminal itself.
-+ return (args.resolverEnv && args.resolverEnv['VSCODE_EXEC_PATH']) || env['VSCODE_EXEC_PATH'];
-+ },
-+ // This is just a guess; this is the only file-related thing we're sent
-+ // and none of these resolver methods seem to get called so I don't know
-+ // how to test.
-+ getFilePath: (): string | undefined => {
-+ const resource = transformIncoming(remoteAuthority, args.activeFileResource);
-+ if (!resource) {
-+ return undefined;
-+ }
-+ // See ../../editor/standalone/browser/simpleServices.ts;
-+ // `BaseConfigurationResolverService` calls `getUriLabel` from there.
-+ if (resource.scheme === 'file') {
-+ return resource.fsPath;
-+ }
-+ return resource.path;
-+ },
-+ // It looks like these are set here although they aren't on the types:
-+ // ../../workbench/contrib/terminal/common/remoteTerminalChannel.ts
-+ getSelectedText: (): string | undefined => {
-+ return args.resolvedVariables.selectedText;
-+ },
-+ getLineNumber: (): string | undefined => {
-+ return args.resolvedVariables.selectedText;
-+ },
-+ }, undefined, env);
-+ }
-+}
-+
-+class Terminal {
-+ private readonly process: TerminalProcess;
-+ private _pid: number = -1;
-+ private _title: string = "";
-+ public readonly workspaceId: string;
-+ public readonly workspaceName: string;
-+ private readonly persist: boolean;
-+
-+ private readonly _onDispose = new Emitter();
-+ public get onDispose(): Event { return this._onDispose.event; }
-+
-+ // These are replayed when a client reconnects.
-+ private cols: number;
-+ private rows: number;
-+ private replayData: string[] = [];
-+ // This is based on string length and is pretty arbitrary.
-+ private readonly maxReplayData = 10000;
-+ private totalReplayData = 0;
-+
-+ // According to the release notes the terminals are supposed to dispose after
-+ // a short timeout; in our case we'll use 48 hours so you can get them back
-+ // the next day or over the weekend.
-+ private disposeTimeout: NodeJS.Timeout | undefined;
-+ private disposeDelay = 48 * 60 * 60 * 1000;
-+
-+ private buffering = false;
-+ private readonly _onEvent = new Emitter({
-+ // Don't bind to data until something is listening.
-+ onFirstListenerAdd: () => {
-+ logger.debug('Terminal bound', field('id', this.id));
-+ if (!this.buffering) {
-+ this.buffering = true;
-+ this.bufferer.startBuffering(this.id, this.process.onProcessData);
-+ }
-+ },
-+
-+ // Replay stored events.
-+ onFirstListenerDidAdd: () => {
-+ // We only need to replay if the terminal is being reconnected which is
-+ // true if there is a dispose timeout.
-+ if (typeof this.disposeTimeout !== "undefined") {
-+ return;
-+ }
-+
-+ clearTimeout(this.disposeTimeout);
-+ this.disposeTimeout = undefined;
-+
-+ logger.debug('Terminal replaying', field('id', this.id));
-+ this._onEvent.fire({
-+ type: 'replay',
-+ events: [{
-+ cols: this.cols,
-+ rows: this.rows,
-+ data: this.replayData.join(""),
-+ }]
-+ });
-+ },
-+
-+ onLastListenerRemove: () => {
-+ logger.debug('Terminal unbound', field('id', this.id));
-+ if (!this.persist) { // Used by debug consoles.
-+ this.dispose();
-+ } else {
-+ this.disposeTimeout = setTimeout(() => {
-+ this.dispose();
-+ }, this.disposeDelay);
-+ }
-+ }
-+ });
-+
-+ public get onEvent(): Event { return this._onEvent.event; }
-+
-+ // Buffer to reduce the number of messages going to the renderer.
-+ private readonly bufferer = new TerminalDataBufferer((_, data) => {
-+ this._onEvent.fire({
-+ type: 'data',
-+ data,
-+ });
-+
-+ // No need to store data if we aren't persisting.
-+ if (!this.persist) {
-+ return;
-+ }
-+
-+ this.replayData.push(data);
-+ this.totalReplayData += data.length;
-+
-+ let overflow = this.totalReplayData - this.maxReplayData;
-+ if (overflow <= 0) {
-+ return;
-+ }
-+
-+ // Drop events until doing so would put us under budget.
-+ let deleteCount = 0;
-+ for (; deleteCount < this.replayData.length
-+ && this.replayData[deleteCount].length <= overflow; ++deleteCount) {
-+ overflow -= this.replayData[deleteCount].length;
-+ }
-+
-+ if (deleteCount > 0) {
-+ this.replayData.splice(0, deleteCount);
-+ }
-+
-+ // Dropping any more events would put us under budget; trim the first event
-+ // instead if still over budget.
-+ if (overflow > 0 && this.replayData.length > 0) {
-+ this.replayData[0] = this.replayData[0].substring(overflow);
-+ }
-+
-+ this.totalReplayData = this.replayData.reduce((p, c) => p + c.length, 0);
-+ });
-+
-+ public get pid(): number {
-+ return this._pid;
-+ }
-+
-+ public get title(): string {
-+ return this._title;
-+ }
-+
-+ public constructor(
-+ public readonly id: number,
-+ config: IShellLaunchConfig & { cwd: string },
-+ args: terminal.ICreateTerminalProcessArguments,
-+ env: platform.IProcessEnvironment,
-+ logService: ILogService,
-+ ) {
-+ this.workspaceId = args.workspaceId;
-+ this.workspaceName = args.workspaceName;
-+
-+ this.cols = args.cols;
-+ this.rows = args.rows;
-+
-+ // TODO: Don't persist terminals until we make it work with things like
-+ // htop, vim, etc.
-+ // this.persist = args.shouldPersistTerminal;
-+ this.persist = false;
-+
-+ this.process = new TerminalProcess(
-+ config,
-+ config.cwd,
-+ this.cols,
-+ this.rows,
-+ env,
-+ process.env as platform.IProcessEnvironment, // Environment used for `findExecutable`.
-+ false, // windowsEnableConpty: boolean,
-+ logService,
-+ );
-+
-+ // The current pid and title aren't exposed so they have to be tracked.
-+ this.process.onProcessReady((event) => {
-+ this._pid = event.pid;
-+ this._onEvent.fire({
-+ type: 'ready',
-+ pid: event.pid,
-+ cwd: event.cwd,
-+ });
-+ });
-+
-+ this.process.onProcessTitleChanged((title) => {
-+ this._title = title;
-+ this._onEvent.fire({
-+ type: 'titleChanged',
-+ title,
-+ });
-+ });
-+
-+ this.process.onProcessExit((exitCode) => {
-+ logger.debug('Terminal exited', field('id', this.id), field('code', exitCode));
-+ this._onEvent.fire({
-+ type: 'exit',
-+ exitCode,
-+ });
-+ this.dispose();
-+ });
-+
-+ // TODO: I think `execCommand` must have something to do with running
-+ // commands on the terminal that will do things in VS Code but we already
-+ // have that functionality via a socket so I'm not sure what this is for.
-+ // type: 'execCommand';
-+ // reqId: number;
-+ // commandId: string;
-+ // commandArgs: any[];
-+
-+ // TODO: Maybe this is to ask if the terminal is currently attached to
-+ // anything? But we already know that on account of whether anything is
-+ // listening to our event emitter.
-+ // type: 'orphan?';
-+ }
-+
-+ public dispose() {
-+ logger.debug('Terminal disposing', field('id', this.id));
-+ this._onEvent.dispose();
-+ this.bufferer.dispose();
-+ this.process.dispose();
-+ this.process.shutdown(true);
-+ this._onDispose.fire();
-+ this._onDispose.dispose();
-+ }
-+
-+ public shutdown(immediate: boolean): void {
-+ return this.process.shutdown(immediate);
-+ }
-+
-+ public getCwd(): Promise {
-+ return this.process.getCwd();
-+ }
-+
-+ public getInitialCwd(): Promise {
-+ return this.process.getInitialCwd();
-+ }
-+
-+ public start(): Promise {
-+ return this.process.start();
-+ }
-+
-+ public input(data: string): void {
-+ return this.process.input(data);
-+ }
-+
-+ public resize(cols: number, rows: number): void {
-+ this.cols = cols;
-+ this.rows = rows;
-+ return this.process.resize(cols, rows);
-+ }
-+}
-+
-+// References: - ../../workbench/api/node/extHostTerminalService.ts
-+// - ../../workbench/contrib/terminal/browser/terminalProcessManager.ts
-+export class TerminalProviderChannel implements IServerChannel, IDisposable {
-+ private readonly terminals = new Map();
-+ private id = 0;
-+
-+ public constructor (private readonly logService: ILogService) {
-+
-+ }
-+
-+ public listen(_: RemoteAgentConnectionContext, event: string, args?: any): Event {
-+ switch (event) {
-+ case '$onTerminalProcessEvent': return this.onTerminalProcessEvent(args);
-+ }
-+
-+ throw new Error(`Invalid listen '${event}'`);
-+ }
-+
-+ private onTerminalProcessEvent(args: terminal.IOnTerminalProcessEventArguments): Event {
-+ return this.getTerminal(args.id).onEvent;
-+ }
-+
-+ public call(context: RemoteAgentConnectionContext, command: string, args?: any): Promise {
-+ switch (command) {
-+ case '$createTerminalProcess': return this.createTerminalProcess(context.remoteAuthority, args);
-+ case '$startTerminalProcess': return this.startTerminalProcess(args);
-+ case '$sendInputToTerminalProcess': return this.sendInputToTerminalProcess(args);
-+ case '$shutdownTerminalProcess': return this.shutdownTerminalProcess(args);
-+ case '$resizeTerminalProcess': return this.resizeTerminalProcess(args);
-+ case '$getTerminalInitialCwd': return this.getTerminalInitialCwd(args);
-+ case '$getTerminalCwd': return this.getTerminalCwd(args);
-+ case '$sendCommandResultToTerminalProcess': return this.sendCommandResultToTerminalProcess(args);
-+ case '$orphanQuestionReply': return this.orphanQuestionReply(args[0]);
-+ case '$listTerminals': return this.listTerminals(args[0]);
-+ }
-+
-+ throw new Error(`Invalid call '${command}'`);
-+ }
-+
-+ public dispose(): void {
-+ this.terminals.forEach((t) => t.dispose());
-+ }
-+
-+ private async createTerminalProcess(remoteAuthority: string, args: terminal.ICreateTerminalProcessArguments): Promise {
-+ const terminalId = this.id++;
-+ logger.debug('Creating terminal', field('id', terminalId), field("terminals", this.terminals.size));
-+
-+ const shellLaunchConfig: IShellLaunchConfig = {
-+ name: args.shellLaunchConfig.name,
-+ executable: args.shellLaunchConfig.executable,
-+ args: args.shellLaunchConfig.args,
-+ // TODO: Should we transform if it's a string as well? The incoming
-+ // transform only takes `UriComponents` so I suspect it's not necessary.
-+ cwd: typeof args.shellLaunchConfig.cwd !== "string"
-+ ? transformIncoming(remoteAuthority, args.shellLaunchConfig.cwd)
-+ : args.shellLaunchConfig.cwd,
-+ env: args.shellLaunchConfig.env,
-+ };
-+
-+ const activeWorkspaceUri = transformIncoming(remoteAuthority, args.activeWorkspaceFolder?.uri);
-+ const activeWorkspace = activeWorkspaceUri && args.activeWorkspaceFolder ? {
-+ ...args.activeWorkspaceFolder,
-+ uri: activeWorkspaceUri,
-+ toResource: (relativePath: string) => resources.joinPath(activeWorkspaceUri, relativePath),
-+ } : undefined;
-+
-+ const resolverService = new VariableResolverService(remoteAuthority, args, process.env as platform.IProcessEnvironment);
-+ const resolver = terminalEnvironment.createVariableResolver(activeWorkspace, resolverService);
-+
-+ const getDefaultShellAndArgs = (): { executable: string; args: string[] | string } => {
-+ if (shellLaunchConfig.executable) {
-+ const executable = resolverService.resolve(activeWorkspace, shellLaunchConfig.executable);
-+ let resolvedArgs: string[] | string = [];
-+ if (shellLaunchConfig.args && Array.isArray(shellLaunchConfig.args)) {
-+ for (const arg of shellLaunchConfig.args) {
-+ resolvedArgs.push(resolverService.resolve(activeWorkspace, arg));
-+ }
-+ } else if (shellLaunchConfig.args) {
-+ resolvedArgs = resolverService.resolve(activeWorkspace, shellLaunchConfig.args);
-+ }
-+ return { executable, args: resolvedArgs };
-+ }
-+
-+ const executable = terminalEnvironment.getDefaultShell(
-+ (key) => args.configuration[key],
-+ args.isWorkspaceShellAllowed,
-+ getSystemShell(platform.platform),
-+ process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
-+ process.env.windir,
-+ resolver,
-+ this.logService,
-+ false, // useAutomationShell
-+ );
-+
-+ const resolvedArgs = terminalEnvironment.getDefaultShellArgs(
-+ (key) => args.configuration[key],
-+ args.isWorkspaceShellAllowed,
-+ false, // useAutomationShell
-+ resolver,
-+ this.logService,
-+ );
-+
-+ return { executable, args: resolvedArgs };
-+ };
-+
-+ const getInitialCwd = (): string => {
-+ return terminalEnvironment.getCwd(
-+ shellLaunchConfig,
-+ os.homedir(),
-+ resolver,
-+ activeWorkspaceUri,
-+ args.configuration['terminal.integrated.cwd'],
-+ this.logService,
-+ );
-+ };
-+
-+ // Use a separate var so Typescript recognizes these properties are no
-+ // longer undefined.
-+ const resolvedShellLaunchConfig = {
-+ ...shellLaunchConfig,
-+ ...getDefaultShellAndArgs(),
-+ cwd: getInitialCwd(),
-+ };
-+
-+ logger.debug('Resolved shell launch configuration', field('id', terminalId));
-+
-+ // Use instead of `terminal.integrated.env.${platform}` to make types work.
-+ const getEnvFromConfig = (): terminal.ISingleTerminalConfiguration => {
-+ if (platform.isWindows) {
-+ return args.configuration['terminal.integrated.env.windows'];
-+ } else if (platform.isMacintosh) {
-+ return args.configuration['terminal.integrated.env.osx'];
-+ }
-+ return args.configuration['terminal.integrated.env.linux'];
-+ };
-+
-+ const getNonInheritedEnv = async (): Promise => {
-+ const env = await getMainProcessParentEnv();
-+ env.VSCODE_IPC_HOOK_CLI = process.env['VSCODE_IPC_HOOK_CLI']!;
-+ return env;
-+ };
-+
-+ const env = terminalEnvironment.createTerminalEnvironment(
-+ shellLaunchConfig,
-+ getEnvFromConfig(),
-+ resolver,
-+ args.isWorkspaceShellAllowed,
-+ product.version,
-+ args.configuration['terminal.integrated.detectLocale'],
-+ args.configuration['terminal.integrated.inheritEnv'] !== false
-+ ? process.env as platform.IProcessEnvironment
-+ : await getNonInheritedEnv()
-+ );
-+
-+ // Apply extension environment variable collections to the environment.
-+ if (!shellLaunchConfig.strictEnv) {
-+ // They come in an array and in serialized format.
-+ const envVariableCollections = new Map();
-+ for (const [k, v] of args.envVariableCollections) {
-+ envVariableCollections.set(k, { map: deserializeEnvironmentVariableCollection(v) });
-+ }
-+ const mergedCollection = new MergedEnvironmentVariableCollection(envVariableCollections);
-+ mergedCollection.applyToProcessEnvironment(env);
-+ }
-+
-+ logger.debug('Resolved terminal environment', field('id', terminalId));
-+
-+ const terminal = new Terminal(terminalId, resolvedShellLaunchConfig, args, env, this.logService);
-+ this.terminals.set(terminalId, terminal);
-+ logger.debug('Created terminal', field('id', terminalId));
-+ terminal.onDispose(() => this.terminals.delete(terminalId));
-+
-+ return {
-+ terminalId,
-+ resolvedShellLaunchConfig,
-+ };
-+ }
-+
-+ private getTerminal(id: number): Terminal {
-+ const terminal = this.terminals.get(id);
-+ if (!terminal) {
-+ throw new Error(`terminal with id ${id} does not exist`);
-+ }
-+ return terminal;
-+ }
-+
-+ private async startTerminalProcess(args: terminal.IStartTerminalProcessArguments): Promise {
-+ return this.getTerminal(args.id).start();
-+ }
-+
-+ private async sendInputToTerminalProcess(args: terminal.ISendInputToTerminalProcessArguments): Promise {
-+ return this.getTerminal(args.id).input(args.data);
-+ }
-+
-+ private async shutdownTerminalProcess(args: terminal.IShutdownTerminalProcessArguments): Promise {
-+ return this.getTerminal(args.id).shutdown(args.immediate);
-+ }
-+
-+ private async resizeTerminalProcess(args: terminal.IResizeTerminalProcessArguments): Promise {
-+ return this.getTerminal(args.id).resize(args.cols, args.rows);
-+ }
-+
-+ private async getTerminalInitialCwd(args: terminal.IGetTerminalInitialCwdArguments): Promise {
-+ return this.getTerminal(args.id).getInitialCwd();
-+ }
-+
-+ private async getTerminalCwd(args: terminal.IGetTerminalCwdArguments): Promise {
-+ return this.getTerminal(args.id).getCwd();
-+ }
-+
-+ private async sendCommandResultToTerminalProcess(_: terminal.ISendCommandResultToTerminalProcessArguments): Promise {
-+ // NOTE: Not required unless we implement the `execCommand` event, see above.
-+ throw new Error('not implemented');
-+ }
-+
-+ private async orphanQuestionReply(_: terminal.IOrphanQuestionReplyArgs): Promise {
-+ // NOTE: Not required unless we implement the `orphan?` event, see above.
-+ throw new Error('not implemented');
-+ }
-+
-+ private async listTerminals(_: terminal.IListTerminalsArgs): Promise {
-+ // TODO: args.isInitialization. Maybe this is to have slightly different
-+ // behavior when first listing terminals but I don't know what you'd want to
-+ // do differently. Maybe it's to reset the terminal dispose timeouts or
-+ // something like that, but why not do it each time you list?
-+ return Promise.all(Array.from(this.terminals).map(async ([id, terminal]) => {
-+ const cwd = await terminal.getCwd();
-+ return {
-+ id,
-+ pid: terminal.pid,
-+ title: terminal.title,
-+ cwd,
-+ workspaceId: terminal.workspaceId,
-+ workspaceName: terminal.workspaceName,
-+ };
-+ }));
-+ }
-+}
-+
-+function transformIncoming(remoteAuthority: string, uri: UriComponents | undefined): URI | undefined {
-+ const transformer = getUriTransformer(remoteAuthority);
-+ return uri ? URI.revive(transformer.transformIncoming(uri)) : uri;
-+}
-diff --git a/src/vs/server/node/connection.ts b/src/vs/server/node/connection.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..93062cadc627c61e0829c27a72894b81e6a0e039
---- /dev/null
-+++ b/src/vs/server/node/connection.ts
-@@ -0,0 +1,171 @@
-+import { field, Logger, logger } from '@coder/logger';
-+import * as cp from 'child_process';
-+import { VSBuffer } from 'vs/base/common/buffer';
-+import { Emitter } from 'vs/base/common/event';
-+import { FileAccess } from 'vs/base/common/network';
-+import { ISocket } from 'vs/base/parts/ipc/common/ipc.net';
-+import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
-+import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
-+import { getNlsConfiguration } from 'vs/server/node/nls';
-+import { Protocol } from 'vs/server/node/protocol';
-+
-+export abstract class Connection {
-+ private readonly _onClose = new Emitter();
-+ public readonly onClose = this._onClose.event;
-+ private disposed = false;
-+ private _offline: number | undefined;
-+
-+ public constructor(protected protocol: Protocol, public readonly token: string) {}
-+
-+ public get offline(): number | undefined {
-+ return this._offline;
-+ }
-+
-+ public reconnect(socket: ISocket, buffer: VSBuffer): void {
-+ this._offline = undefined;
-+ this.doReconnect(socket, buffer);
-+ }
-+
-+ public dispose(): void {
-+ if (!this.disposed) {
-+ this.disposed = true;
-+ this.doDispose();
-+ this._onClose.fire();
-+ }
-+ }
-+
-+ protected setOffline(): void {
-+ if (!this._offline) {
-+ this._offline = Date.now();
-+ }
-+ }
-+
-+ /**
-+ * Set up the connection on a new socket.
-+ */
-+ protected abstract doReconnect(socket: ISocket, buffer: VSBuffer): void;
-+ protected abstract doDispose(): void;
-+}
-+
-+/**
-+ * Used for all the IPC channels.
-+ */
-+export class ManagementConnection extends Connection {
-+ public constructor(protected protocol: Protocol, token: string) {
-+ super(protocol, token);
-+ protocol.onClose(() => this.dispose()); // Explicit close.
-+ protocol.onSocketClose(() => this.setOffline()); // Might reconnect.
-+ }
-+
-+ protected doDispose(): void {
-+ this.protocol.sendDisconnect();
-+ this.protocol.dispose();
-+ this.protocol.getUnderlyingSocket().destroy();
-+ }
-+
-+ protected doReconnect(socket: ISocket, buffer: VSBuffer): void {
-+ this.protocol.beginAcceptReconnection(socket, buffer);
-+ this.protocol.endAcceptReconnection();
-+ }
-+}
-+
-+export class ExtensionHostConnection extends Connection {
-+ private process?: cp.ChildProcess;
-+ private readonly logger: Logger;
-+
-+ public constructor(
-+ locale:string, protocol: Protocol, buffer: VSBuffer, token: string,
-+ private readonly environment: INativeEnvironmentService,
-+ ) {
-+ super(protocol, token);
-+ this.logger = logger.named("exthost", field("token", token));
-+ this.protocol.dispose();
-+ this.spawn(locale, buffer).then((p) => this.process = p);
-+ this.protocol.getUnderlyingSocket().pause();
-+ }
-+
-+ protected doDispose(): void {
-+ if (this.process) {
-+ this.process.kill();
-+ }
-+ this.protocol.getUnderlyingSocket().destroy();
-+ }
-+
-+ protected doReconnect(socket: ISocket, buffer: VSBuffer): void {
-+ // This is just to set the new socket.
-+ this.protocol.beginAcceptReconnection(socket, null);
-+ this.protocol.dispose();
-+ this.sendInitMessage(buffer);
-+ }
-+
-+ private sendInitMessage(buffer: VSBuffer): void {
-+ const socket = this.protocol.getUnderlyingSocket();
-+ socket.pause();
-+ this.logger.trace('Sending socket');
-+ this.process!.send({ // Process must be set at this point.
-+ type: 'VSCODE_EXTHOST_IPC_SOCKET',
-+ initialDataChunk: (buffer.buffer as Buffer).toString('base64'),
-+ skipWebSocketFrames: this.protocol.getSocket() instanceof NodeSocket,
-+ }, socket);
-+ }
-+
-+ private async spawn(locale: string, buffer: VSBuffer): Promise {
-+ this.logger.trace('Getting NLS configuration...');
-+ const config = await getNlsConfiguration(locale, this.environment.userDataPath);
-+ this.logger.trace('Spawning extension host...');
-+ const proc = cp.fork(
-+ FileAccess.asFileUri('bootstrap-fork', require).fsPath,
-+ [ '--type=extensionHost' ],
-+ {
-+ env: {
-+ ...process.env,
-+ AMD_ENTRYPOINT: 'vs/workbench/services/extensions/node/extensionHostProcess',
-+ PIPE_LOGGING: 'true',
-+ VERBOSE_LOGGING: 'true',
-+ VSCODE_EXTHOST_WILL_SEND_SOCKET: 'true',
-+ VSCODE_HANDLES_UNCAUGHT_ERRORS: 'true',
-+ VSCODE_LOG_STACK: 'false',
-+ VSCODE_LOG_LEVEL: process.env.LOG_LEVEL,
-+ VSCODE_NLS_CONFIG: JSON.stringify(config),
-+ },
-+ silent: true,
-+ },
-+ );
-+
-+ proc.on('error', (error) => {
-+ this.logger.error('Exited unexpectedly', field('error', error));
-+ this.dispose();
-+ });
-+ proc.on('exit', (code) => {
-+ this.logger.trace('Exited', field('code', code));
-+ this.dispose();
-+ });
-+ if (proc.stdout && proc.stderr) {
-+ proc.stdout.setEncoding('utf8').on('data', (d) => this.logger.info(d));
-+ proc.stderr.setEncoding('utf8').on('data', (d) => this.logger.error(d));
-+ }
-+
-+ proc.on('message', (event) => {
-+ switch (event && event.type) {
-+ case '__$console':
-+ const severity = (this.logger)[event.severity] || 'info';
-+ (this.logger)[severity]('console', field('arguments', event.arguments));
-+ break;
-+ case 'VSCODE_EXTHOST_DISCONNECTED':
-+ this.logger.trace('Going offline');
-+ this.setOffline();
-+ break;
-+ case 'VSCODE_EXTHOST_IPC_READY':
-+ this.logger.trace('Got ready message');
-+ this.sendInitMessage(buffer);
-+ break;
-+ default:
-+ this.logger.error('Unexpected message', field("event", event));
-+ break;
-+ }
-+ });
-+
-+ this.logger.trace('Waiting for handshake...');
-+ return proc;
-+ }
-+}
-diff --git a/src/vs/server/node/insights.ts b/src/vs/server/node/insights.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..a0ece345f28f06afb2af12fe4901ad228b2475a4
---- /dev/null
-+++ b/src/vs/server/node/insights.ts
-@@ -0,0 +1,124 @@
-+import * as appInsights from 'applicationinsights';
-+import * as https from 'https';
-+import * as http from 'http';
-+import * as os from 'os';
-+
-+class Channel {
-+ public get _sender() {
-+ throw new Error('unimplemented');
-+ }
-+ public get _buffer() {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public setUseDiskRetryCaching(): void {
-+ throw new Error('unimplemented');
-+ }
-+ public send(): void {
-+ throw new Error('unimplemented');
-+ }
-+ public triggerSend(): void {
-+ throw new Error('unimplemented');
-+ }
-+}
-+
-+export class TelemetryClient {
-+ public context: any = undefined;
-+ public commonProperties: any = undefined;
-+ public config: any = {};
-+
-+ public channel: any = new Channel();
-+
-+ public addTelemetryProcessor(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public clearTelemetryProcessors(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public runTelemetryProcessors(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public trackTrace(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public trackMetric(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public trackException(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public trackRequest(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public trackDependency(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public track(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public trackNodeHttpRequestSync(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public trackNodeHttpRequest(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public trackNodeHttpDependency(): void {
-+ throw new Error('unimplemented');
-+ }
-+
-+ public trackEvent(options: appInsights.Contracts.EventTelemetry): void {
-+ if (!options.properties) {
-+ options.properties = {};
-+ }
-+ if (!options.measurements) {
-+ options.measurements = {};
-+ }
-+
-+ try {
-+ const cpus = os.cpus();
-+ options.measurements.cores = cpus.length;
-+ options.properties['common.cpuModel'] = cpus[0].model;
-+ } catch (error) {}
-+
-+ try {
-+ options.measurements.memoryFree = os.freemem();
-+ options.measurements.memoryTotal = os.totalmem();
-+ } catch (error) {}
-+
-+ try {
-+ options.properties['common.shell'] = os.userInfo().shell;
-+ options.properties['common.release'] = os.release();
-+ options.properties['common.arch'] = os.arch();
-+ } catch (error) {}
-+
-+ try {
-+ const url = process.env.TELEMETRY_URL || 'https://v1.telemetry.coder.com/track';
-+ const request = (/^http:/.test(url) ? http : https).request(url, {
-+ method: 'POST',
-+ headers: {
-+ 'Content-Type': 'application/json',
-+ },
-+ });
-+ request.on('error', () => { /* We don't care. */ });
-+ request.write(JSON.stringify(options));
-+ request.end();
-+ } catch (error) {}
-+ }
-+
-+ public flush(options: { callback: (v: string) => void }): void {
-+ if (options.callback) {
-+ options.callback('');
-+ }
-+ }
-+}
-diff --git a/src/vs/server/node/ipc.ts b/src/vs/server/node/ipc.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..5e560eb46e6a0a18c91e440c655ac0d44b09b6dd
---- /dev/null
-+++ b/src/vs/server/node/ipc.ts
-@@ -0,0 +1,61 @@
-+import * as cp from 'child_process';
-+import { Emitter } from 'vs/base/common/event';
-+
-+enum ControlMessage {
-+ okToChild = 'ok>',
-+ okFromChild = 'ok<',
-+}
-+
-+interface RelaunchMessage {
-+ type: 'relaunch';
-+ version: string;
-+}
-+
-+export type Message = RelaunchMessage;
-+
-+class IpcMain {
-+ protected readonly _onMessage = new Emitter();
-+ public readonly onMessage = this._onMessage.event;
-+
-+ public handshake(child?: cp.ChildProcess): Promise {
-+ return new Promise((resolve, reject) => {
-+ const target = child || process;
-+ if (!target.send) {
-+ throw new Error('Not spawned with IPC enabled');
-+ }
-+ target.on('message', (message) => {
-+ if (message === child ? ControlMessage.okFromChild : ControlMessage.okToChild) {
-+ target.removeAllListeners();
-+ target.on('message', (msg) => this._onMessage.fire(msg));
-+ if (child) {
-+ target.send!(ControlMessage.okToChild);
-+ }
-+ resolve();
-+ }
-+ });
-+ if (child) {
-+ child.once('error', reject);
-+ child.once('exit', (code) => {
-+ const error = new Error(`Unexpected exit with code ${code}`);
-+ (error as any).code = code;
-+ reject(error);
-+ });
-+ } else {
-+ target.send(ControlMessage.okFromChild);
-+ }
-+ });
-+ }
-+
-+ public relaunch(version: string): void {
-+ this.send({ type: 'relaunch', version });
-+ }
-+
-+ private send(message: Message): void {
-+ if (!process.send) {
-+ throw new Error('Not a child process with IPC enabled');
-+ }
-+ process.send(message);
-+ }
-+}
-+
-+export const ipcMain = new IpcMain();
-diff --git a/src/vs/server/node/logger.ts b/src/vs/server/node/logger.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..2a39c524aaa1b4031e04a631842f30b6fec3d98a
---- /dev/null
-+++ b/src/vs/server/node/logger.ts
-@@ -0,0 +1,2 @@
-+import { logger as baseLogger } from '@coder/logger';
-+export const logger = baseLogger.named('vscode');
-diff --git a/src/vs/server/node/marketplace.ts b/src/vs/server/node/marketplace.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..8956fc40d48448b9932036c4c286464881807338
---- /dev/null
-+++ b/src/vs/server/node/marketplace.ts
-@@ -0,0 +1,174 @@
-+import * as fs from 'fs';
-+import * as path from 'path';
-+import * as tarStream from 'tar-stream';
-+import * as util from 'util';
-+import { CancellationToken } from 'vs/base/common/cancellation';
-+import { mkdirp } from 'vs/base/node/pfs';
-+import * as vszip from 'vs/base/node/zip';
-+import * as nls from 'vs/nls';
-+import product from 'vs/platform/product/common/product';
-+
-+// We will be overriding these, so keep a reference to the original.
-+const vszipExtract = vszip.extract;
-+const vszipBuffer = vszip.buffer;
-+
-+export interface IExtractOptions {
-+ overwrite?: boolean;
-+ /**
-+ * Source path within the TAR/ZIP archive. Only the files
-+ * contained in this path will be extracted.
-+ */
-+ sourcePath?: string;
-+}
-+
-+export interface IFile {
-+ path: string;
-+ contents?: Buffer | string;
-+ localPath?: string;
-+}
-+
-+export const tar = async (tarPath: string, files: IFile[]): Promise => {
-+ const pack = tarStream.pack();
-+ const chunks: Buffer[] = [];
-+ const ended = new Promise((resolve) => {
-+ pack.on('end', () => resolve(Buffer.concat(chunks)));
-+ });
-+ pack.on('data', (chunk: Buffer) => chunks.push(chunk));
-+ for (let i = 0; i < files.length; i++) {
-+ const file = files[i];
-+ pack.entry({ name: file.path }, file.contents);
-+ }
-+ pack.finalize();
-+ await util.promisify(fs.writeFile)(tarPath, await ended);
-+ return tarPath;
-+};
-+
-+export const extract = async (archivePath: string, extractPath: string, options: IExtractOptions = {}, token: CancellationToken): Promise => {
-+ try {
-+ await extractTar(archivePath, extractPath, options, token);
-+ } catch (error) {
-+ if (error.toString().includes('Invalid tar header')) {
-+ await vszipExtract(archivePath, extractPath, options, token);
-+ }
-+ }
-+};
-+
-+export const buffer = (targetPath: string, filePath: string): Promise => {
-+ return new Promise(async (resolve, reject) => {
-+ try {
-+ let done: boolean = false;
-+ await extractAssets(targetPath, new RegExp(filePath), (assetPath: string, data: Buffer) => {
-+ if (path.normalize(assetPath) === path.normalize(filePath)) {
-+ done = true;
-+ resolve(data);
-+ }
-+ });
-+ if (!done) {
-+ throw new Error('couldn\'t find asset ' + filePath);
-+ }
-+ } catch (error) {
-+ if (error.toString().includes('Invalid tar header')) {
-+ vszipBuffer(targetPath, filePath).then(resolve).catch(reject);
-+ } else {
-+ reject(error);
-+ }
-+ }
-+ });
-+};
-+
-+const extractAssets = async (tarPath: string, match: RegExp, callback: (path: string, data: Buffer) => void): Promise => {
-+ return new Promise((resolve, reject): void => {
-+ const extractor = tarStream.extract();
-+ const fail = (error: Error) => {
-+ extractor.destroy();
-+ reject(error);
-+ };
-+ extractor.once('error', fail);
-+ extractor.on('entry', async (header, stream, next) => {
-+ const name = header.name;
-+ if (match.test(name)) {
-+ extractData(stream).then((data) => {
-+ callback(name, data);
-+ next();
-+ }).catch(fail);
-+ } else {
-+ stream.on('end', () => next());
-+ stream.resume(); // Just drain it.
-+ }
-+ });
-+ extractor.on('finish', resolve);
-+ fs.createReadStream(tarPath).pipe(extractor);
-+ });
-+};
-+
-+const extractData = (stream: NodeJS.ReadableStream): Promise => {
-+ return new Promise((resolve, reject): void => {
-+ const fileData: Buffer[] = [];
-+ stream.on('error', reject);
-+ stream.on('end', () => resolve(Buffer.concat(fileData)));
-+ stream.on('data', (data) => fileData.push(data));
-+ });
-+};
-+
-+const extractTar = async (tarPath: string, targetPath: string, options: IExtractOptions = {}, token: CancellationToken): Promise => {
-+ return new Promise((resolve, reject): void => {
-+ const sourcePathRegex = new RegExp(options.sourcePath ? `^${options.sourcePath}` : '');
-+ const extractor = tarStream.extract();
-+ const fail = (error: Error) => {
-+ extractor.destroy();
-+ reject(error);
-+ };
-+ extractor.once('error', fail);
-+ extractor.on('entry', async (header, stream, next) => {
-+ const nextEntry = (): void => {
-+ stream.on('end', () => next());
-+ stream.resume();
-+ };
-+
-+ const rawName = path.normalize(header.name);
-+ if (token.isCancellationRequested || !sourcePathRegex.test(rawName)) {
-+ return nextEntry();
-+ }
-+
-+ const fileName = rawName.replace(sourcePathRegex, '');
-+ const targetFileName = path.join(targetPath, fileName);
-+ if (/\/$/.test(fileName)) {
-+ return mkdirp(targetFileName).then(nextEntry);
-+ }
-+
-+ const dirName = path.dirname(fileName);
-+ const targetDirName = path.join(targetPath, dirName);
-+ if (targetDirName.indexOf(targetPath) !== 0) {
-+ return fail(new Error(nls.localize('invalid file', 'Error extracting {0}. Invalid file.', fileName)));
-+ }
-+
-+ await mkdirp(targetDirName, undefined);
-+
-+ const fstream = fs.createWriteStream(targetFileName, { mode: header.mode });
-+ fstream.once('close', () => next());
-+ fstream.once('error', fail);
-+ stream.pipe(fstream);
-+ });
-+ extractor.once('finish', resolve);
-+ fs.createReadStream(tarPath).pipe(extractor);
-+ });
-+};
-+
-+/**
-+ * Override original functionality so we can use a custom marketplace with
-+ * either tars or zips.
-+ */
-+export const enableCustomMarketplace = (): void => {
-+ (product).extensionsGallery = { // Use `any` to override readonly.
-+ serviceUrl: process.env.SERVICE_URL || 'https://extensions.coder.com/api',
-+ itemUrl: process.env.ITEM_URL || '',
-+ controlUrl: '',
-+ recommendationsUrl: '',
-+ ...(product.extensionsGallery || {}),
-+ };
-+
-+ const target = vszip as typeof vszip;
-+ target.zip = tar;
-+ target.extract = extract;
-+ target.buffer = buffer;
-+};
-diff --git a/src/vs/server/node/nls.ts b/src/vs/server/node/nls.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..3d428a57d31f29c40f9c3ce45f715b443badf4e9
---- /dev/null
-+++ b/src/vs/server/node/nls.ts
-@@ -0,0 +1,88 @@
-+import * as fs from 'fs';
-+import * as path from 'path';
-+import * as util from 'util';
-+import { getPathFromAmdModule } from 'vs/base/common/amd';
-+import * as lp from 'vs/base/node/languagePacks';
-+import product from 'vs/platform/product/common/product';
-+import { Translations } from 'vs/workbench/services/extensions/common/extensionPoints';
-+
-+const configurations = new Map>();
-+const metadataPath = path.join(getPathFromAmdModule(require, ''), 'nls.metadata.json');
-+
-+export const isInternalConfiguration = (config: lp.NLSConfiguration): config is lp.InternalNLSConfiguration => {
-+ return config && !!(config)._languagePackId;
-+};
-+
-+const DefaultConfiguration = {
-+ locale: 'en',
-+ availableLanguages: {},
-+};
-+
-+export const getNlsConfiguration = async (locale: string, userDataPath: string): Promise => {
-+ const id = `${locale}: ${userDataPath}`;
-+ if (!configurations.has(id)) {
-+ configurations.set(id, new Promise(async (resolve) => {
-+ const config = product.commit && await util.promisify(fs.exists)(metadataPath)
-+ ? await lp.getNLSConfiguration(product.commit, userDataPath, metadataPath, locale)
-+ : DefaultConfiguration;
-+ if (isInternalConfiguration(config)) {
-+ config._languagePackSupport = true;
-+ }
-+ // If the configuration has no results keep trying since code-server
-+ // doesn't restart when a language is installed so this result would
-+ // persist (the plugin might not be installed yet or something).
-+ if (config.locale !== 'en' && config.locale !== 'en-us' && Object.keys(config.availableLanguages).length === 0) {
-+ configurations.delete(id);
-+ }
-+ resolve(config);
-+ }));
-+ }
-+ return configurations.get(id)!;
-+};
-+
-+export const getTranslations = async (locale: string, userDataPath: string): Promise => {
-+ const config = await getNlsConfiguration(locale, userDataPath);
-+ if (isInternalConfiguration(config)) {
-+ try {
-+ return JSON.parse(await util.promisify(fs.readFile)(config._translationsConfigFile, 'utf8'));
-+ } catch (error) { /* Nothing yet. */}
-+ }
-+ return {};
-+};
-+
-+export const getLocaleFromConfig = async (userDataPath: string): Promise => {
-+ const files = ['locale.json', 'argv.json'];
-+ for (let i = 0; i < files.length; ++i) {
-+ try {
-+ const localeConfigUri = path.join(userDataPath, 'User', files[i]);
-+ const content = stripComments(await util.promisify(fs.readFile)(localeConfigUri, 'utf8'));
-+ return JSON.parse(content).locale;
-+ } catch (error) { /* Ignore. */ }
-+ }
-+ return 'en';
-+};
-+
-+// Taken from src/main.js in the main VS Code source.
-+const stripComments = (content: string): string => {
-+ const regexp = /('(?:[^\\']*(?:\\.)?)*')|('(?:[^\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g;
-+
-+ return content.replace(regexp, (match, _m1, _m2, m3, m4) => {
-+ // Only one of m1, m2, m3, m4 matches
-+ if (m3) {
-+ // A block comment. Replace with nothing
-+ return '';
-+ } else if (m4) {
-+ // A line comment. If it ends in \r?\n then keep it.
-+ const length_1 = m4.length;
-+ if (length_1 > 2 && m4[length_1 - 1] === '\n') {
-+ return m4[length_1 - 2] === '\r' ? '\r\n' : '\n';
-+ }
-+ else {
-+ return '';
-+ }
-+ } else {
-+ // We match a string
-+ return match;
-+ }
-+ });
-+};
-diff --git a/src/vs/server/node/protocol.ts b/src/vs/server/node/protocol.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..0d9310038c0ca378579652d89bc8ac84924213db
---- /dev/null
-+++ b/src/vs/server/node/protocol.ts
-@@ -0,0 +1,91 @@
-+import { field } from '@coder/logger';
-+import * as net from 'net';
-+import { VSBuffer } from 'vs/base/common/buffer';
-+import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
-+import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
-+import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from 'vs/platform/remote/common/remoteAgentConnection';
-+import { logger } from 'vs/server/node/logger';
-+
-+export interface SocketOptions {
-+ readonly reconnectionToken: string;
-+ readonly reconnection: boolean;
-+ readonly skipWebSocketFrames: boolean;
-+}
-+
-+export class Protocol extends PersistentProtocol {
-+ public constructor(socket: net.Socket, public readonly options: SocketOptions) {
-+ super(
-+ options.skipWebSocketFrames
-+ ? new NodeSocket(socket)
-+ : new WebSocketNodeSocket(new NodeSocket(socket)),
-+ );
-+ }
-+
-+ public getUnderlyingSocket(): net.Socket {
-+ const socket = this.getSocket();
-+ return socket instanceof NodeSocket
-+ ? socket.socket
-+ : (socket as WebSocketNodeSocket).socket.socket;
-+ }
-+
-+ /**
-+ * Perform a handshake to get a connection request.
-+ */
-+ public handshake(): Promise {
-+ logger.trace('Protocol handshake', field('token', this.options.reconnectionToken));
-+ return new Promise((resolve, reject) => {
-+ const timeout = setTimeout(() => {
-+ logger.error('Handshake timed out', field('token', this.options.reconnectionToken));
-+ reject(new Error("timed out"));
-+ }, 10000); // Matches the client timeout.
-+
-+ const handler = this.onControlMessage((rawMessage) => {
-+ try {
-+ const raw = rawMessage.toString();
-+ logger.trace('Protocol message', field('token', this.options.reconnectionToken), field('message', raw));
-+ const message = JSON.parse(raw);
-+ switch (message.type) {
-+ case 'auth':
-+ return this.authenticate(message);
-+ case 'connectionType':
-+ handler.dispose();
-+ clearTimeout(timeout);
-+ return resolve(message);
-+ default:
-+ throw new Error('Unrecognized message type');
-+ }
-+ } catch (error) {
-+ handler.dispose();
-+ clearTimeout(timeout);
-+ reject(error);
-+ }
-+ });
-+
-+ // Kick off the handshake in case we missed the client's opening shot.
-+ // TODO: Investigate why that message seems to get lost.
-+ this.authenticate();
-+ });
-+ }
-+
-+ /**
-+ * TODO: This ignores the authentication process entirely for now.
-+ */
-+ private authenticate(_?: AuthRequest): void {
-+ this.sendMessage({ type: 'sign', data: '' });
-+ }
-+
-+ /**
-+ * TODO: implement.
-+ */
-+ public tunnel(): void {
-+ throw new Error('Tunnel is not implemented yet');
-+ }
-+
-+ /**
-+ * Send a handshake message. In the case of the extension host, it just sends
-+ * back a debug port.
-+ */
-+ public sendMessage(message: HandshakeMessage | { debugPort?: number } ): void {
-+ this.sendControl(VSBuffer.fromString(JSON.stringify(message)));
-+ }
-+}
-diff --git a/src/vs/server/node/server.ts b/src/vs/server/node/server.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..c10a5a3a6771a94b2cbcb699bb1261051c71e08b
---- /dev/null
-+++ b/src/vs/server/node/server.ts
-@@ -0,0 +1,302 @@
-+import { field } from '@coder/logger';
-+import * as fs from 'fs';
-+import * as net from 'net';
-+import * as path from 'path';
-+import { Emitter } from 'vs/base/common/event';
-+import { Schemas } from 'vs/base/common/network';
-+import { URI } from 'vs/base/common/uri';
-+import { getMachineId } from 'vs/base/node/id';
-+import { ClientConnectionEvent, createChannelReceiver, IPCServer, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
-+import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner';
-+import { main } from "vs/code/node/cliProcessMain";
-+import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
-+import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
-+import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
-+import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
-+import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
-+import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
-+import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
-+import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
-+import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
-+import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
-+import { IFileService } from 'vs/platform/files/common/files';
-+import { FileService } from 'vs/platform/files/common/fileService';
-+import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
-+import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
-+import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
-+import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
-+import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
-+import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
-+import { getLogLevel, ILoggerService, ILogService } from 'vs/platform/log/common/log';
-+import { LoggerChannel } from 'vs/platform/log/common/logIpc';
-+import { LoggerService } from 'vs/platform/log/node/loggerService';
-+import { SpdLogService } from 'vs/platform/log/node/spdlogService';
-+import product from 'vs/platform/product/common/product';
-+import { IProductService } from 'vs/platform/product/common/productService';
-+import { ConnectionType, ConnectionTypeRequest } from 'vs/platform/remote/common/remoteAgentConnection';
-+import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
-+import { IRequestService } from 'vs/platform/request/common/request';
-+import { RequestChannel } from 'vs/platform/request/common/requestIpc';
-+import { RequestService } from 'vs/platform/request/node/requestService';
-+import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
-+import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
-+import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender';
-+import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
-+import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
-+import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
-+import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
-+import { INodeProxyService, NodeProxyChannel } from 'vs/server/common/nodeProxy';
-+import { TelemetryChannel } from 'vs/server/common/telemetry';
-+import { Query, VscodeOptions, WorkbenchOptions } from 'vs/server/ipc';
-+import { ExtensionEnvironmentChannel, FileProviderChannel, NodeProxyService, TerminalProviderChannel } from 'vs/server/node/channel';
-+import { Connection, ExtensionHostConnection, ManagementConnection } from 'vs/server/node/connection';
-+import { TelemetryClient } from 'vs/server/node/insights';
-+import { logger } from 'vs/server/node/logger';
-+import { getLocaleFromConfig, getNlsConfiguration } from 'vs/server/node/nls';
-+import { Protocol } from 'vs/server/node/protocol';
-+import { getUriTransformer } from 'vs/server/node/util';
-+import { REMOTE_TERMINAL_CHANNEL_NAME } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel';
-+import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from "vs/workbench/services/remote/common/remoteAgentFileSystemChannel";
-+import { RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService';
-+
-+export class Vscode {
-+ public readonly _onDidClientConnect = new Emitter();
-+ public readonly onDidClientConnect = this._onDidClientConnect.event;
-+ private readonly ipc = new IPCServer(this.onDidClientConnect);
-+
-+ private readonly maxExtraOfflineConnections = 0;
-+ private readonly connections = new Map>();
-+
-+ private readonly services = new ServiceCollection();
-+ private servicesPromise?: Promise;
-+
-+ public async cli(args: NativeParsedArgs): Promise {
-+ return main(args);
-+ }
-+
-+ public async initialize(options: VscodeOptions): Promise {
-+ const transformer = getUriTransformer(options.remoteAuthority);
-+ if (!this.servicesPromise) {
-+ this.servicesPromise = this.initializeServices(options.args);
-+ }
-+ await this.servicesPromise;
-+ const environment = this.services.get(IEnvironmentService) as INativeEnvironmentService;
-+ const startPath = options.startPath;
-+ const parseUrl = (url: string): URI => {
-+ // This might be a fully-specified URL or just a path.
-+ try {
-+ return URI.parse(url, true);
-+ } catch (error) {
-+ return URI.from({
-+ scheme: Schemas.vscodeRemote,
-+ authority: options.remoteAuthority,
-+ path: url,
-+ });
-+ }
-+ };
-+ return {
-+ workbenchWebConfiguration: {
-+ workspaceUri: startPath && startPath.workspace ? parseUrl(startPath.url) : undefined,
-+ folderUri: startPath && !startPath.workspace ? parseUrl(startPath.url) : undefined,
-+ remoteAuthority: options.remoteAuthority,
-+ logLevel: getLogLevel(environment),
-+ workspaceProvider: {
-+ payload: [
-+ ["userDataPath", environment.userDataPath],
-+ ["enableProposedApi", JSON.stringify(options.args["enable-proposed-api"] || [])]
-+ ],
-+ },
-+ },
-+ remoteUserDataUri: transformer.transformOutgoing(URI.file(environment.userDataPath)),
-+ productConfiguration: product,
-+ nlsConfiguration: await getNlsConfiguration(environment.args.locale || await getLocaleFromConfig(environment.userDataPath), environment.userDataPath),
-+ commit: product.commit || 'development',
-+ };
-+ }
-+
-+ public async handleWebSocket(socket: net.Socket, query: Query): Promise {
-+ if (!query.reconnectionToken) {
-+ throw new Error('Reconnection token is missing from query parameters');
-+ }
-+ const protocol = new Protocol(socket, {
-+ reconnectionToken: query.reconnectionToken,
-+ reconnection: query.reconnection === 'true',
-+ skipWebSocketFrames: query.skipWebSocketFrames === 'true',
-+ });
-+ try {
-+ await this.connect(await protocol.handshake(), protocol);
-+ } catch (error) {
-+ protocol.sendMessage({ type: 'error', reason: error.message });
-+ protocol.dispose();
-+ protocol.getSocket().dispose();
-+ }
-+ return true;
-+ }
-+
-+ private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise {
-+ if (product.commit && message.commit !== product.commit) {
-+ logger.warn(`Version mismatch (${message.commit} instead of ${product.commit})`);
-+ }
-+
-+ switch (message.desiredConnectionType) {
-+ case ConnectionType.ExtensionHost:
-+ case ConnectionType.Management:
-+ if (!this.connections.has(message.desiredConnectionType)) {
-+ this.connections.set(message.desiredConnectionType, new Map());
-+ }
-+ const connections = this.connections.get(message.desiredConnectionType)!;
-+
-+ const ok = async () => {
-+ return message.desiredConnectionType === ConnectionType.ExtensionHost
-+ ? { debugPort: await this.getDebugPort() }
-+ : { type: 'ok' };
-+ };
-+
-+ const token = protocol.options.reconnectionToken;
-+ if (protocol.options.reconnection && connections.has(token)) {
-+ protocol.sendMessage(await ok());
-+ const buffer = protocol.readEntireBuffer();
-+ protocol.dispose();
-+ return connections.get(token)!.reconnect(protocol.getSocket(), buffer);
-+ } else if (protocol.options.reconnection || connections.has(token)) {
-+ throw new Error(protocol.options.reconnection
-+ ? 'Unrecognized reconnection token'
-+ : 'Duplicate reconnection token'
-+ );
-+ }
-+
-+ logger.debug('New connection', field('token', token));
-+ protocol.sendMessage(await ok());
-+
-+ let connection: Connection;
-+ if (message.desiredConnectionType === ConnectionType.Management) {
-+ connection = new ManagementConnection(protocol, token);
-+ this._onDidClientConnect.fire({
-+ protocol, onDidClientDisconnect: connection.onClose,
-+ });
-+ // TODO: Need a way to match clients with a connection. For now
-+ // dispose everything which only works because no extensions currently
-+ // utilize long-running proxies.
-+ (this.services.get(INodeProxyService) as NodeProxyService)._onUp.fire();
-+ connection.onClose(() => (this.services.get(INodeProxyService) as NodeProxyService)._onDown.fire());
-+ } else {
-+ const buffer = protocol.readEntireBuffer();
-+ connection = new ExtensionHostConnection(
-+ message.args ? message.args.language : 'en',
-+ protocol, buffer, token,
-+ this.services.get(IEnvironmentService) as INativeEnvironmentService,
-+ );
-+ }
-+ connections.set(token, connection);
-+ connection.onClose(() => {
-+ logger.debug('Connection closed', field('token', token));
-+ connections.delete(token);
-+ });
-+ this.disposeOldOfflineConnections(connections);
-+ break;
-+ case ConnectionType.Tunnel: return protocol.tunnel();
-+ default: throw new Error('Unrecognized connection type');
-+ }
-+ }
-+
-+ private disposeOldOfflineConnections(connections: Map): void {
-+ const offline = Array.from(connections.values())
-+ .filter((connection) => typeof connection.offline !== 'undefined');
-+ for (let i = 0, max = offline.length - this.maxExtraOfflineConnections; i < max; ++i) {
-+ logger.debug('Disposing offline connection', field("token", offline[i].token));
-+ offline[i].dispose();
-+ }
-+ }
-+
-+ private async initializeServices(args: NativeParsedArgs): Promise {
-+ const environmentService = new NativeEnvironmentService(args);
-+ // https://github.com/cdr/code-server/issues/1693
-+ fs.mkdirSync(environmentService.globalStorageHome.fsPath, { recursive: true });
-+
-+ const logService = new SpdLogService(RemoteExtensionLogFileName, environmentService.logsPath, getLogLevel(environmentService));
-+ const fileService = new FileService(logService);
-+ fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(logService));
-+
-+ const piiPaths = [
-+ path.join(environmentService.userDataPath, 'clp'), // Language packs.
-+ environmentService.appRoot,
-+ environmentService.extensionsPath,
-+ environmentService.builtinExtensionsPath,
-+ ...environmentService.extraExtensionPaths,
-+ ...environmentService.extraBuiltinExtensionPaths,
-+ ];
-+
-+ this.ipc.registerChannel('logger', new LoggerChannel(logService));
-+ this.ipc.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel());
-+
-+ this.services.set(ILogService, logService);
-+ this.services.set(IEnvironmentService, environmentService);
-+ this.services.set(INativeEnvironmentService, environmentService);
-+ this.services.set(ILoggerService, new SyncDescriptor(LoggerService));
-+
-+ const configurationService = new ConfigurationService(environmentService.settingsResource, fileService);
-+ await configurationService.initialize();
-+ this.services.set(IConfigurationService, configurationService);
-+
-+ this.services.set(IRequestService, new SyncDescriptor(RequestService));
-+ this.services.set(IFileService, fileService);
-+ this.services.set(IProductService, { _serviceBrand: undefined, ...product });
-+
-+ const machineId = await getMachineId();
-+
-+ await new Promise((resolve) => {
-+ const instantiationService = new InstantiationService(this.services);
-+
-+ instantiationService.invokeFunction((accessor) => {
-+ instantiationService.createInstance(LogsDataCleaner);
-+
-+ let telemetryService: ITelemetryService;
-+ if (!environmentService.disableTelemetry) {
-+ telemetryService = new TelemetryService({
-+ appender: combinedAppender(
-+ new AppInsightsAppender('code-server', null, () => new TelemetryClient() as any),
-+ new TelemetryLogAppender(accessor.get(ILoggerService), environmentService)
-+ ),
-+ sendErrorTelemetry: true,
-+ commonProperties: resolveCommonProperties(
-+ product.commit, product.version, machineId,
-+ [], environmentService.installSourcePath, 'code-server',
-+ ),
-+ piiPaths,
-+ }, configurationService);
-+ } else {
-+ telemetryService = NullTelemetryService;
-+ }
-+
-+ this.services.set(ITelemetryService, telemetryService);
-+
-+ this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
-+ this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
-+ this.services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
-+ this.services.set(INodeProxyService, new SyncDescriptor(NodeProxyService));
-+
-+ this.ipc.registerChannel('extensions', new ExtensionManagementChannel(
-+ accessor.get(IExtensionManagementService),
-+ (context) => getUriTransformer(context.remoteAuthority),
-+ ));
-+ this.ipc.registerChannel('remoteextensionsenvironment', new ExtensionEnvironmentChannel(
-+ environmentService, logService, telemetryService, '',
-+ ));
-+ this.ipc.registerChannel('request', new RequestChannel(accessor.get(IRequestService)));
-+ this.ipc.registerChannel('telemetry', new TelemetryChannel(telemetryService));
-+ this.ipc.registerChannel('nodeProxy', new NodeProxyChannel(accessor.get(INodeProxyService)));
-+ this.ipc.registerChannel('localizations', >createChannelReceiver(accessor.get(ILocalizationsService)));
-+ this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, new FileProviderChannel(environmentService, logService));
-+ this.ipc.registerChannel(REMOTE_TERMINAL_CHANNEL_NAME, new TerminalProviderChannel(logService));
-+ resolve(new ErrorTelemetry(telemetryService));
-+ });
-+ });
-+ }
-+
-+ /**
-+ * TODO: implement.
-+ */
-+ private async getDebugPort(): Promise {
-+ return undefined;
-+ }
-+}
-diff --git a/src/vs/server/node/util.ts b/src/vs/server/node/util.ts
-new file mode 100644
-index 0000000000000000000000000000000000000000..fa47e993b46802f1a26457649e9e8bc467a73bf2
---- /dev/null
-+++ b/src/vs/server/node/util.ts
-@@ -0,0 +1,13 @@
-+import { URITransformer } from 'vs/base/common/uriIpc';
-+
-+export const getUriTransformer = (remoteAuthority: string): URITransformer => {
-+ return new URITransformer(remoteAuthority);
-+};
-+
-+/**
-+ * Encode a path for opening via the folder or workspace query parameter. This
-+ * preserves slashes so it can be edited by hand more easily.
-+ */
-+export const encodePath = (path: string): string => {
-+ return path.split("/").map((p) => encodeURIComponent(p)).join("/");
-+};
-diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts
-index a4df8523631563a498c9ab6e51105074616a481a..f03da094e9080544102bbd3f037a71b348e5bd83 100644
---- a/src/vs/workbench/api/browser/extensionHost.contribution.ts
-+++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts
-@@ -61,6 +61,7 @@ import './mainThreadComments';
- import './mainThreadNotebook';
- import './mainThreadTask';
- import './mainThreadLabelService';
-+import 'vs/server/browser/mainThreadNodeProxy';
- import './mainThreadTunnelService';
- import './mainThreadAuthentication';
- import './mainThreadTimeline';
-diff --git a/src/vs/workbench/api/browser/mainThreadStorage.ts b/src/vs/workbench/api/browser/mainThreadStorage.ts
-index 57abf0e86a5edeeb2bc497af5e140ec13d9b5810..704d0f9ae19d436a7207ff735aabc289c422dd1e 100644
---- a/src/vs/workbench/api/browser/mainThreadStorage.ts
-+++ b/src/vs/workbench/api/browser/mainThreadStorage.ts
-@@ -62,11 +62,11 @@ export class MainThreadStorage implements MainThreadStorageShape {
- return JSON.parse(jsonValue);
- }
-
-- $setValue(shared: boolean, key: string, value: object): Promise {
-+ async $setValue(shared: boolean, key: string, value: object): Promise {
- let jsonValue: string;
- try {
- jsonValue = JSON.stringify(value);
-- this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
-+ await this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
- } catch (err) {
- return Promise.reject(err);
- }
-diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts
-index 284c6aff854a747d1202c34581a1419c35e9654f..f0173d80103ca91b5eab144a10935bc0990119c9 100644
---- a/src/vs/workbench/api/common/extHost.api.impl.ts
-+++ b/src/vs/workbench/api/common/extHost.api.impl.ts
-@@ -68,6 +68,7 @@ import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransf
- import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
- import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
- import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
-+import { IExtHostNodeProxy } from 'vs/server/browser/extHostNodeProxy';
- import { ExtHostTheming } from 'vs/workbench/api/common/extHostTheming';
- import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
- import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
-@@ -103,6 +104,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
- const extHostStorage = accessor.get(IExtHostStorage);
- const extensionStoragePaths = accessor.get(IExtensionStoragePaths);
- const extHostLogService = accessor.get(ILogService);
-+ const extHostNodeProxy = accessor.get(IExtHostNodeProxy);
- const extHostTunnelService = accessor.get(IExtHostTunnelService);
- const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService);
- const extHostWindow = accessor.get(IExtHostWindow);
-@@ -114,6 +116,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
- rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
- rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
- rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
-+ rpcProtocol.set(ExtHostContext.ExtHostNodeProxy, extHostNodeProxy);
- rpcProtocol.set(ExtHostContext.ExtHostTunnelService, extHostTunnelService);
- rpcProtocol.set(ExtHostContext.ExtHostWindow, extHostWindow);
-
-diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts
-index 77ef6577821399b150407e980c8fd35e9d005ca6..264e3361accec20e4e1eaae10ae8ca05e47b1fae 100644
---- a/src/vs/workbench/api/common/extHost.protocol.ts
-+++ b/src/vs/workbench/api/common/extHost.protocol.ts
-@@ -816,6 +816,17 @@ export interface MainThreadLabelServiceShape extends IDisposable {
- $unregisterResourceLabelFormatter(handle: number): void;
- }
-
-+export interface MainThreadNodeProxyShape extends IDisposable {
-+ $send(message: string): void;
-+ $fetchExtension(extensionUri: UriComponents): Promise;
-+}
-+export interface ExtHostNodeProxyShape {
-+ $onMessage(message: string): void;
-+ $onClose(): void;
-+ $onDown(): void;
-+ $onUp(): void;
-+}
-+
- export interface MainThreadSearchShape extends IDisposable {
- $registerFileSearchProvider(handle: number, scheme: string): void;
- $registerTextSearchProvider(handle: number, scheme: string): void;
-@@ -1796,6 +1807,7 @@ export const MainContext = {
- MainThreadWindow: createMainId('MainThreadWindow'),
- MainThreadLabelService: createMainId('MainThreadLabelService'),
- MainThreadNotebook: createMainId('MainThreadNotebook'),
-+ MainThreadNodeProxy: createMainId('MainThreadNodeProxy'),
- MainThreadTheming: createMainId('MainThreadTheming'),
- MainThreadTunnelService: createMainId('MainThreadTunnelService'),
- MainThreadTimeline: createMainId('MainThreadTimeline')
-@@ -1838,6 +1850,7 @@ export const ExtHostContext = {
- ExtHostOutputService: createMainId('ExtHostOutputService'),
- ExtHosLabelService: createMainId('ExtHostLabelService'),
- ExtHostNotebook: createMainId('ExtHostNotebook'),
-+ ExtHostNodeProxy: createMainId('ExtHostNodeProxy'),
- ExtHostTheming: createMainId('ExtHostTheming'),
- ExtHostTunnelService: createMainId('ExtHostTunnelService'),
- ExtHostAuthentication: createMainId('ExtHostAuthentication'),
-diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts
-index 328b9327207e4f2068bfab6cf374c622d8c5fc69..38963843095c9116011665027f46d3fb85c30ff8 100644
---- a/src/vs/workbench/api/common/extHostExtensionService.ts
-+++ b/src/vs/workbench/api/common/extHostExtensionService.ts
-@@ -31,6 +31,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData
- import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
- import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
- import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
-+import { IExtHostNodeProxy } from 'vs/server/browser/extHostNodeProxy';
- import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
- import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
- import { Emitter, Event } from 'vs/base/common/event';
-@@ -82,6 +83,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
- protected readonly _extHostWorkspace: ExtHostWorkspace;
- protected readonly _extHostConfiguration: ExtHostConfiguration;
- protected readonly _logService: ILogService;
-+ protected readonly _nodeProxy: IExtHostNodeProxy;
- protected readonly _extHostTunnelService: IExtHostTunnelService;
- protected readonly _extHostTerminalService: IExtHostTerminalService;
-
-@@ -114,6 +116,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
- @ILogService logService: ILogService,
- @IExtHostInitDataService initData: IExtHostInitDataService,
- @IExtensionStoragePaths storagePath: IExtensionStoragePaths,
-+ @IExtHostNodeProxy nodeProxy: IExtHostNodeProxy,
- @IExtHostTunnelService extHostTunnelService: IExtHostTunnelService,
- @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService
- ) {
-@@ -125,6 +128,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
- this._extHostWorkspace = extHostWorkspace;
- this._extHostConfiguration = extHostConfiguration;
- this._logService = logService;
-+ this._nodeProxy = nodeProxy;
- this._extHostTunnelService = extHostTunnelService;
- this._extHostTerminalService = extHostTerminalService;
- this._disposables = new DisposableStore();
-@@ -362,7 +366,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
-
- const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
- return Promise.all([
-- this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, entryPoint), activationTimesBuilder),
-+ this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, entryPoint), activationTimesBuilder, !extensionDescription.browser),
- this._loadExtensionContext(extensionDescription)
- ]).then(values => {
- return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder);
-@@ -754,7 +758,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
-
- protected abstract _beforeAlmostReadyToRunExtensions(): Promise;
- protected abstract _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined;
-- protected abstract _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise;
-+ protected abstract _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder, isRemote?: boolean): Promise;
- public abstract $setRemoteEnvironment(env: { [key: string]: string | null }): Promise;
- }
-
-diff --git a/src/vs/workbench/api/node/extHost.node.services.ts b/src/vs/workbench/api/node/extHost.node.services.ts
-index b3c89e51cfc25a53293a352a2a8ad50d5f26d595..e21abe4e13bc25a5b72f556bbfb61085842faeb7 100644
---- a/src/vs/workbench/api/node/extHost.node.services.ts
-+++ b/src/vs/workbench/api/node/extHost.node.services.ts
-@@ -3,6 +3,8 @@
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-+import { IExtHostNodeProxy } from 'vs/server/browser/extHostNodeProxy';
-+import { NotImplementedProxy } from 'vs/base/common/types';
- import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
- import { ExtHostOutputService2 } from 'vs/workbench/api/node/extHostOutputService';
- import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
-@@ -36,3 +38,4 @@ registerSingleton(IExtHostSearch, NativeExtHostSearch);
- registerSingleton(IExtHostTask, ExtHostTask);
- registerSingleton(IExtHostTerminalService, ExtHostTerminalService);
- registerSingleton(IExtHostTunnelService, ExtHostTunnelService);
-+registerSingleton(IExtHostNodeProxy, class extends NotImplementedProxy(String(IExtHostNodeProxy)) { whenReady = Promise.resolve(); });
-diff --git a/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts
-index b3857616f7006127c423dcef7020ae4653da5ff6..1c1b80a2767bf77f30ca5bfee715c337120d3625 100644
---- a/src/vs/workbench/api/node/extHostCLIServer.ts
-+++ b/src/vs/workbench/api/node/extHostCLIServer.ts
-@@ -11,6 +11,8 @@ import { IWindowOpenable, IOpenWindowOptions } from 'vs/platform/windows/common/
- import { URI } from 'vs/base/common/uri';
- import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
- import { ILogService } from 'vs/platform/log/common/log';
-+import { join } from 'vs/base/common/path';
-+import { tmpdir } from 'os';
-
- export interface OpenCommandPipeArgs {
- type: 'open';
-@@ -58,6 +60,11 @@ export class CLIServerBase {
- }
-
- private async setup(): Promise {
-+ // NOTE@coder: Write this out so we can get the most recent path.
-+ fs.promises.writeFile(join(tmpdir(), "vscode-ipc"), this._ipcHandlePath).catch((error) => {
-+ this.logService.error(error);
-+ });
-+
- try {
- this._server.listen(this.ipcHandlePath);
- this._server.on('error', err => this.logService.error(err));
-diff --git a/src/vs/workbench/api/worker/extHost.worker.services.ts b/src/vs/workbench/api/worker/extHost.worker.services.ts
-index 3843fdec386edc09a1d361b63de892a04e0070ed..8aac4df527857e964798362a69f5591bef07c165 100644
---- a/src/vs/workbench/api/worker/extHost.worker.services.ts
-+++ b/src/vs/workbench/api/worker/extHost.worker.services.ts
-@@ -8,6 +8,7 @@ import { ILogService } from 'vs/platform/log/common/log';
- import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
- import { ExtHostExtensionService } from 'vs/workbench/api/worker/extHostExtensionService';
- import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService';
-+import { ExtHostNodeProxy, IExtHostNodeProxy } from 'vs/server/browser/extHostNodeProxy';
-
- // #########################################################################
- // ### ###
-@@ -17,3 +18,4 @@ import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService';
-
- registerSingleton(IExtHostExtensionService, ExtHostExtensionService);
- registerSingleton(ILogService, ExtHostLogService);
-+registerSingleton(IExtHostNodeProxy, ExtHostNodeProxy);
-diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts
-index 021af6e0f8983c492f9cdd048ba2dcae7640bc1d..814dd0ff2fa7737e07833d8092c8f48953c73c47 100644
---- a/src/vs/workbench/api/worker/extHostExtensionService.ts
-+++ b/src/vs/workbench/api/worker/extHostExtensionService.ts
-@@ -11,6 +11,7 @@ import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterc
- import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
- import { ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes';
- import { timeout } from 'vs/base/common/async';
-+import { loadCommonJSModule } from 'vs/server/browser/worker';
-
- class WorkerRequireInterceptor extends RequireInterceptor {
-
-@@ -46,10 +47,15 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
- }
-
- protected _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined {
-- return extensionDescription.browser;
-+ // NOTE@coder: We can support regular Node modules as well. These will just
-+ // require the root of the extension.
-+ return extensionDescription.browser || ".";
- }
-
-- protected async _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise {
-+ protected async _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder, isRemote?: boolean): Promise {
-+ if (isRemote) {
-+ return loadCommonJSModule(module, activationTimesBuilder, this._nodeProxy, this._logService, this._fakeModules!.getModule('vscode', module));
-+ }
-
- module = module.with({ path: ensureSuffix(module.path, '.js') });
- const response = await fetch(module.toString(true));
-diff --git a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css
-index ced2d815834e40a1543e80516472799075980733..dfcae73e8a042307600c67f163aa00ba9e0762f4 100644
---- a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css
-+++ b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css
-@@ -55,6 +55,10 @@
- align-items: center;
- justify-content: center;
- order: -1;
-+
-+ /* NOTE@coder: Hide since it doesn't seem to do anything when used with
-+ code-server except open the VS Code repository. */
-+ display: none !important;
- }
-
- .monaco-workbench .activitybar > .content > .home-bar > .home-bar-icon-badge {
-diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts
-index 80544aab34c12bb42a36519885e9872ef2b24158..17b56856a0b3fd936dbc094ff39797d5b8ccaadf 100644
---- a/src/vs/workbench/browser/web.main.ts
-+++ b/src/vs/workbench/browser/web.main.ts
-@@ -43,6 +43,7 @@ import { FileLogService } from 'vs/platform/log/common/fileLogService';
- import { toLocalISOString } from 'vs/base/common/date';
- import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
- import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces';
-+import { initialize } from 'vs/server/browser/client';
- import { coalesce } from 'vs/base/common/arrays';
- import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
- import { ICommandService } from 'vs/platform/commands/common/commands';
-@@ -101,6 +102,8 @@ class BrowserMain extends Disposable {
- // Startup
- const instantiationService = workbench.startup();
-
-+ await initialize(services.serviceCollection);
-+
- // Return API Facade
- return instantiationService.invokeFunction(accessor => {
- const commandService = accessor.get(ICommandService);
-diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts
-index 94e7e7a4bac154c45078a1b5034e50634a7a43af..8164200dcef1efbc65b50eef9c270af3ca655fbd 100644
---- a/src/vs/workbench/common/resources.ts
-+++ b/src/vs/workbench/common/resources.ts
-@@ -15,6 +15,7 @@ import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob';
- import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
- import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
- import { withNullAsUndefined } from 'vs/base/common/types';
-+import { Schemas } from 'vs/base/common/network';
-
- export class ResourceContextKey extends Disposable implements IContextKey {
-
-@@ -74,7 +75,8 @@ export class ResourceContextKey extends Disposable implements IContextKey {
- if (!ResourceContextKey._uriEquals(this._resourceKey.get(), value)) {
- this._contextKeyService.bufferChangeEvents(() => {
- this._resourceKey.set(value);
-- this._schemeKey.set(value ? value.scheme : null);
-+ // NOTE@coder: Fixes source control context menus (#1104).
-+ this._schemeKey.set(value ? (value.scheme === Schemas.vscodeRemote ? Schemas.file : value.scheme) : null);
- this._filenameKey.set(value ? basename(value) : null);
- this._dirnameKey.set(value ? dirname(value).fsPath : null);
- this._pathKey.set(value ? value.fsPath : null);
-diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css
-index 74f6922e98b4bb6a7fb100f5aac015afe9fc171b..3243a97c2d378013d96ffbe87e9df6dd4a66776d 100644
---- a/src/vs/workbench/contrib/scm/browser/media/scm.css
-+++ b/src/vs/workbench/contrib/scm/browser/media/scm.css
-@@ -149,9 +149,11 @@
- margin-right: 8px;
- }
-
--.scm-view .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions {
-- flex-grow: 100;
--}
-+/* NOTE@coder: Causes the label to shrink to zero width in Firefox due to
-+ * overflow:hidden. This isn't right anyway, as far as I can tell. */
-+/* .scm-view .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions { */
-+/* flex-grow: 100; */
-+/* } */
-
- .scm-view .monaco-list .monaco-list-row .resource-group > .actions,
- .scm-view .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions {
-diff --git a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts
-index ed4f26407391bd62219a9f8245a5cd63a7cb7488..92f26d1b082f80475cf76409a4569e948e9e0bd9 100644
---- a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts
-+++ b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts
-@@ -130,6 +130,8 @@ export class SimpleNativeWorkbenchEnvironmentService implements INativeWorkbench
- extensionsPath?: string | undefined;
- extensionsDownloadPath: string = undefined!;
- builtinExtensionsPath: string = undefined!;
-+ extraExtensionPaths: string[] = undefined!;
-+ extraBuiltinExtensionPaths: string[] = undefined!;
-
- driverHandle?: string | undefined;
-
-diff --git a/src/vs/workbench/services/dialogs/browser/dialogService.ts b/src/vs/workbench/services/dialogs/browser/dialogService.ts
-index 85d83f37da179a1e39266cf72a02e971f590308e..0659738b36df1747c9afcabf8d9abf26c890990b 100644
---- a/src/vs/workbench/services/dialogs/browser/dialogService.ts
-+++ b/src/vs/workbench/services/dialogs/browser/dialogService.ts
-@@ -125,11 +125,12 @@ export class DialogService implements IDialogService {
- async about(): Promise {
- const detailString = (useAgo: boolean): string => {
- return nls.localize('aboutDetail',
-- "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
-+ "code-server: v{4}\n VS Code: v{0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
- this.productService.version || 'Unknown',
- this.productService.commit || 'Unknown',
- this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown',
-- navigator.userAgent
-+ navigator.userAgent,
-+ this.productService.codeServerVersion || 'Unknown',
- );
- };
-
-diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts
-index a8d43045ecc8cbe04b3f8440cff16d42aadbcad0..cd589c6f75eccbeefbf364d426ac882396b26fb4 100644
---- a/src/vs/workbench/services/environment/browser/environmentService.ts
-+++ b/src/vs/workbench/services/environment/browser/environmentService.ts
-@@ -119,8 +119,18 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
- @memoize
- get logFile(): URI { return joinPath(this.options.logsPath, 'window.log'); }
-
-+ // NOTE@coder: Use the regular path for extensions that write directly to disk
-+ // instead of using the VS Code API.
- @memoize
-- get userRoamingDataHome(): URI { return URI.file('/User').with({ scheme: Schemas.userData }); }
-+ get userRoamingDataHome(): URI { return URI.file(this.userDataPath).with({ scheme: Schemas.userData }); }
-+ @memoize
-+ get userDataPath(): string {
-+ const dataPath = this.payload?.get("userDataPath");
-+ if (!dataPath) {
-+ throw new Error("userDataPath was not provided to environment service");
-+ }
-+ return dataPath;
-+ }
-
- @memoize
- get settingsResource(): URI { return joinPath(this.userRoamingDataHome, 'settings.json'); }
-@@ -301,7 +311,12 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
- extensionHostDebugEnvironment.params.port = parseInt(value);
- break;
- case 'enableProposedApi':
-- extensionHostDebugEnvironment.extensionEnabledProposedApi = [];
-+ try {
-+ extensionHostDebugEnvironment.extensionEnabledProposedApi = JSON.parse(value);
-+ } catch (error) {
-+ console.error(error);
-+ extensionHostDebugEnvironment.extensionEnabledProposedApi = [];
-+ }
- break;
- }
- }
-diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts
-index 50d4d812b76f09435fcff8148aac4ceeaeb30873..faacf88fcef119f9f959739656d64a84c8f64cbf 100644
---- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts
-+++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts
-@@ -221,7 +221,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench
- }
- }
- }
-- return true;
-+ return false; // NOTE@coder: Don't disable anything by extensionKind.
- }
- return false;
- }
-diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts
-index de7e301d3f0c67ce662827f61427a5a7b3616b9f..877ea8e11e6e6d34b9a8fe16287af309e569285e 100644
---- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts
-+++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts
-@@ -251,7 +251,9 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
-
- // Install Language pack on all servers
- if (isLanguagePackExtension(manifest)) {
-- servers.push(...this.servers);
-+ // NOTE@coder: It does not appear language packs can be installed on the web
-+ // extension management server at this time. Filter out the web to fix this.
-+ servers.push(...this.servers.filter(s => s !== this.extensionManagementServerService.webExtensionManagementServer));
- } else {
- const server = this.getExtensionManagementServerToInstall(manifest);
- if (server) {
-@@ -320,6 +322,11 @@ export class ExtensionManagementService extends Disposable implements IWorkbench
- return this.extensionManagementServerService.webExtensionManagementServer;
- }
-
-+ // NOTE@coder: Fall back to installing on the remote server.
-+ if (this.extensionManagementServerService.remoteExtensionManagementServer) {
-+ return this.extensionManagementServerService.remoteExtensionManagementServer;
-+ }
-+
- return undefined;
- }
-
-diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts
-index 1dff19bf177eff24f722b748b79835a653241c4d..0f59ad290c82cc4c9d09c565c1018cc275ca0249 100644
---- a/src/vs/workbench/services/extensions/browser/extensionService.ts
-+++ b/src/vs/workbench/services/extensions/browser/extensionService.ts
-@@ -177,8 +177,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
- this._remoteAgentService.getEnvironment(),
- this._remoteAgentService.scanExtensions()
- ]);
-- localExtensions = this._checkEnabledAndProposedAPI(localExtensions);
- remoteExtensions = this._checkEnabledAndProposedAPI(remoteExtensions);
-+ // NOTE@coder: Include remotely hosted extensions that should run locally.
-+ localExtensions = this._checkEnabledAndProposedAPI(localExtensions)
-+ .concat(remoteExtensions.filter(ext => !ext.browser && ext.extensionKind && (ext.extensionKind === "web" || ext.extensionKind.includes("web"))));
-
- const remoteAgentConnection = this._remoteAgentService.getConnection();
- this._runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, remoteExtensions);
-diff --git a/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/common/extensionsUtil.ts
-index 65e532ee58dfc06ed944846d01b885cb8f260ebc..0b6282fde7ad03c7ea9872a777cbf487253abed1 100644
---- a/src/vs/workbench/services/extensions/common/extensionsUtil.ts
-+++ b/src/vs/workbench/services/extensions/common/extensionsUtil.ts
-@@ -37,7 +37,8 @@ export function canExecuteOnWorkspace(manifest: IExtensionManifest, productServi
-
- export function canExecuteOnWeb(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
- const extensionKind = getExtensionKind(manifest, productService, configurationService);
-- return extensionKind.some(kind => kind === 'web');
-+ // NOTE@coder: Hardcode vim for now.
-+ return extensionKind.some(kind => kind === 'web') || manifest.name === 'vim';
- }
-
- export function getExtensionKind(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): ExtensionKind[] {
-diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts
-index e39d131fe7b1dd4bd1093fedb8faba8e1fe969e8..94f2f1d7c4a0b3cb46eaaffe1181b3abbf997d7f 100644
---- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts
-+++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts
-@@ -16,7 +16,7 @@ import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
- import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage, IExtHostReduceGraceTimeMessage, ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
- import { ExtensionHostMain, IExitFn } from 'vs/workbench/services/extensions/common/extensionHostMain';
- import { VSBuffer } from 'vs/base/common/buffer';
--import { IURITransformer, URITransformer, IRawURITransformer } from 'vs/base/common/uriIpc';
-+import { IURITransformer, URITransformer } from 'vs/base/common/uriIpc';
- import { exists } from 'vs/base/node/pfs';
- import { realpath } from 'vs/base/node/extpath';
- import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
-@@ -57,12 +57,13 @@ const args = minimist(process.argv.slice(2), {
- const Module = require.__$__nodeRequire('module') as any;
- const originalLoad = Module._load;
-
-- Module._load = function (request: string) {
-+ Module._load = function (request: string, parent: object, isMain: boolean) {
- if (request === 'natives') {
- throw new Error('Either the extension or a NPM dependency is using the "natives" node module which is unsupported as it can cause a crash of the extension host. Click [here](https://go.microsoft.com/fwlink/?linkid=871887) to find out more');
- }
-
-- return originalLoad.apply(this, arguments);
-+ // NOTE@coder: Map node_module.asar requests to regular node_modules.
-+ return originalLoad.apply(this, [request.replace(/node_modules\.asar(\.unpacked)?/, 'node_modules'), parent, isMain]);
- };
- })();
-
-@@ -135,8 +136,11 @@ function _createExtHostProtocol(): Promise {
-
- // Wait for rich client to reconnect
- protocol.onSocketClose(() => {
-- // The socket has closed, let's give the renderer a certain amount of time to reconnect
-- disconnectRunner1.schedule();
-+ // NOTE@coder: Inform the server so we can manage offline
-+ // connections there instead. Our goal is to persist connections
-+ // forever (to a reasonable point) to account for things like
-+ // hibernating overnight.
-+ process.send!({ type: 'VSCODE_EXTHOST_DISCONNECTED' });
- });
- }
- }
-@@ -313,11 +317,9 @@ export async function startExtensionHostProcess(): Promise {
-
- // Attempt to load uri transformer
- let uriTransformer: IURITransformer | null = null;
-- if (initData.remote.authority && args.uriTransformerPath) {
-+ if (initData.remote.authority) {
- try {
-- const rawURITransformerFactory = require.__$__nodeRequire(args.uriTransformerPath);
-- const rawURITransformer = rawURITransformerFactory(initData.remote.authority);
-- uriTransformer = new URITransformer(rawURITransformer);
-+ uriTransformer = new URITransformer(initData.remote.authority);
- } catch (e) {
- console.error(e);
- }
-diff --git a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
-index b39a5cbb9eadbc046144d2e76d26a9b0e950ddaa..3b4cc7274e149ee10dba0dbbb09cf25939091f4b 100644
---- a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
-+++ b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
-@@ -15,7 +15,11 @@
- require.config({
- baseUrl: monacoBaseUrl,
- catchError: true,
-- createTrustedScriptURL: (value: string) => value
-+ createTrustedScriptURL: (value: string) => value,
-+ paths: {
-+ '@coder/node-browser': `../node_modules/@coder/node-browser/out/client/client.js`,
-+ '@coder/requirefs': `../node_modules/@coder/requirefs/out/requirefs.js`,
-+ }
- });
-
- require(['vs/workbench/services/extensions/worker/extensionHostWorker'], () => { }, err => console.error(err));
-diff --git a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts
-index d7aefde89c74bc6096d6e66c45368c8582594efa..9758f3bb96b48603251336e6a64e270ee89744f0 100644
---- a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts
-+++ b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts
-@@ -5,8 +5,8 @@
-
- import { createChannelSender } from 'vs/base/parts/ipc/common/ipc';
- import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
--import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
- import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
-+import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
-
- // @ts-ignore: interface is implemented via proxy
- export class LocalizationsService implements ILocalizationsService {
-@@ -14,9 +14,9 @@ export class LocalizationsService implements ILocalizationsService {
- declare readonly _serviceBrand: undefined;
-
- constructor(
-- @ISharedProcessService sharedProcessService: ISharedProcessService,
-+ @IRemoteAgentService remoteAgentService: IRemoteAgentService,
- ) {
-- return createChannelSender(sharedProcessService.getChannel('localizations'));
-+ return createChannelSender(remoteAgentService.getConnection()!.getChannel('localizations'));
- }
- }
-
-diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts
-index 509f8ac8ce3a689386e439302a53c27e4fdfcef7..2bf9a737bd0dbfa1e604acfc890be45823f02ebe 100644
---- a/src/vs/workbench/workbench.web.main.ts
-+++ b/src/vs/workbench/workbench.web.main.ts
-@@ -35,7 +35,8 @@ import 'vs/workbench/services/textfile/browser/browserTextFileService';
- import 'vs/workbench/services/keybinding/browser/keymapService';
- import 'vs/workbench/services/extensions/browser/extensionService';
- import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService';
--import 'vs/workbench/services/telemetry/browser/telemetryService';
-+// NOTE@coder: We send it all to the server side to be processed there instead.
-+// import 'vs/workbench/services/telemetry/browser/telemetryService';
- import 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
- import 'vs/workbench/services/credentials/browser/credentialsService';
- import 'vs/workbench/services/url/browser/urlService';
-diff --git a/yarn.lock b/yarn.lock
-index ff358cb6a10984868ed5a5aed5729ac6eb8ebeb7..69668d95ecad219da26ccc4d837913b9324a0e28 100644
---- a/yarn.lock
-+++ b/yarn.lock
-@@ -140,6 +140,23 @@
- lodash "^4.17.13"
- to-fast-properties "^2.0.0"
-
-+"@coder/logger@^1.1.12":
-+ version "1.1.12"
-+ resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.1.12.tgz#def113b7183abc35a8da2b57f0929f7e9626f4e0"
-+ integrity sha512-oM0j3lTVPqApUm3e0bKKcXpfAiJEys31fgEfQlHmvEA13ujsC4zDuXnt0uzDtph48eMoNRLOF/EE4mNShVJKVw==
-+
-+"@coder/node-browser@^1.0.8":
-+ version "1.0.8"
-+ resolved "https://registry.yarnpkg.com/@coder/node-browser/-/node-browser-1.0.8.tgz#c22f581b089ad7d95ad1362fd351c57b7fbc6e70"
-+ integrity sha512-NLF9sYMRCN9WK1C224pHax1Cay3qKypg25BhVg7VfNbo3Cpa3daata8RF/rT8JK3lPsu8PmFgDRQjzGC9X1Lrw==
-+
-+"@coder/requirefs@^1.1.5":
-+ version "1.1.5"
-+ resolved "https://registry.yarnpkg.com/@coder/requirefs/-/requirefs-1.1.5.tgz#259db370d563a79a96fb150bc9d69c7db6edc9fb"
-+ integrity sha512-3jB47OFCql9+9FI6Vc4YX0cfFnG5rxBfrZUH45S4XYtYGOz+/Xl4h4d2iMk50b7veHkeSWGlB4VHC3UZ16zuYQ==
-+ optionalDependencies:
-+ jszip "2.6.0"
-+
- "@electron/get@^1.0.1":
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.7.2.tgz#286436a9fb56ff1a1fcdf0e80131fd65f4d1e0fd"
-@@ -5403,6 +5420,13 @@ jsprim@^1.2.2:
- json-schema "0.2.3"
- verror "1.10.0"
-
-+jszip@2.6.0:
-+ version "2.6.0"
-+ resolved "https://registry.yarnpkg.com/jszip/-/jszip-2.6.0.tgz#7fb3e9c2f11c8a9840612db5dabbc8cf3a7534b7"
-+ integrity sha1-f7PpwvEciphAYS212rvIzzp1NLc=
-+ dependencies:
-+ pako "~1.0.0"
-+
- just-debounce@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea"
-@@ -5983,26 +6007,11 @@ minimatch@0.3:
- dependencies:
- brace-expansion "^1.1.7"
-
--minimist@0.0.8:
-- version "0.0.8"
-- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
-- integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
--
--minimist@^1.2.0:
-- version "1.2.0"
-- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
-- integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
--
--minimist@^1.2.5:
-+minimist@0.0.8, minimist@^1.2.0, minimist@^1.2.5, minimist@~0.0.1:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-
--minimist@~0.0.1:
-- version "0.0.10"
-- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
-- integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
--
- minipass@^2.2.1, minipass@^2.3.3:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233"
-@@ -6744,6 +6753,11 @@ p-try@^2.0.0:
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
- integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==
-
-+pako@~1.0.0:
-+ version "1.0.11"
-+ resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
-+ integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
-+
- pako@~1.0.5:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
diff --git a/ci/dev/vscode.sh b/ci/dev/vscode.sh
deleted file mode 100755
index 6c508747aa6f..000000000000
--- a/ci/dev/vscode.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-# 1. Ensures VS Code is cloned.
-# 2. Patches it.
-# 3. Installs it.
-main() {
- cd "$(dirname "$0")/../.."
-
- git submodule update --init
-
- # If the patch fails to apply, then it's likely already applied
- yarn vscode:patch &> /dev/null || true
-
- (
- cd lib/vscode
- # Install VS Code dependencies.
- yarn ${CI+--frozen-lockfile}
- )
-}
-
-main "$@"
diff --git a/ci/dev/watch.ts b/ci/dev/watch.ts
index 646da328b3f8..e48489ce69dc 100644
--- a/ci/dev/watch.ts
+++ b/ci/dev/watch.ts
@@ -1,193 +1,142 @@
-import * as cp from "child_process"
-import Bundler from "parcel-bundler"
+import { spawn, ChildProcess } from "child_process"
import * as path from "path"
-
-async function main(): Promise {
- try {
- const watcher = new Watcher()
- await watcher.watch()
- } catch (error) {
- console.error(error.message)
- process.exit(1)
- }
+import { onLine, OnLineCallback } from "../../src/node/util"
+
+interface DevelopmentCompilers {
+ [key: string]: ChildProcess | undefined
+ vscode: ChildProcess
+ vscodeWebExtensions: ChildProcess
+ codeServer: ChildProcess
+ plugins: ChildProcess | undefined
}
class Watcher {
- private readonly rootPath = path.resolve(__dirname, "../..")
- private readonly vscodeSourcePath = path.join(this.rootPath, "lib/vscode")
+ private rootPath = path.resolve(process.cwd())
+ private readonly paths = {
+ /** Path to uncompiled VS Code source. */
+ vscodeDir: path.join(this.rootPath, "lib/vscode"),
+ pluginDir: process.env.PLUGIN_DIR,
+ }
+
+ //#region Web Server
+
+ /** Development web server. */
+ private webServer: ChildProcess | undefined
- private static log(message: string, skipNewline = false): void {
- process.stdout.write(message)
- if (!skipNewline) {
- process.stdout.write("\n")
+ private reloadWebServer = (): void => {
+ if (this.webServer) {
+ this.webServer.kill()
}
+
+ // Pass CLI args, save for `node` and the initial script name.
+ const args = process.argv.slice(2)
+ this.webServer = spawn("node", [path.join(this.rootPath, "out/node/entry.js"), ...args])
+ onLine(this.webServer, (line) => console.log("[code-server]", line))
+ const { pid } = this.webServer
+
+ this.webServer.on("exit", () => console.log("[code-server]", `Web process ${pid} exited`))
+
+ console.log("\n[code-server]", `Spawned web server process ${pid}`)
}
- public async watch(): Promise {
- let server: cp.ChildProcess | undefined
- const restartServer = (): void => {
- if (server) {
- server.kill()
- }
- const s = cp.fork(path.join(this.rootPath, "out/node/entry.js"), process.argv.slice(2))
- console.log(`[server] spawned process ${s.pid}`)
- s.on("exit", () => console.log(`[server] process ${s.pid} exited`))
- server = s
+ //#endregion
+
+ //#region Compilers
+
+ private readonly compilers: DevelopmentCompilers = {
+ codeServer: spawn("tsc", ["--watch", "--pretty", "--preserveWatchOutput"], { cwd: this.rootPath }),
+ vscode: spawn("npm", ["run", "watch"], { cwd: this.paths.vscodeDir }),
+ vscodeWebExtensions: spawn("npm", ["run", "watch-web"], { cwd: this.paths.vscodeDir }),
+ plugins: this.paths.pluginDir
+ ? spawn("npm", ["run", "build", "--watch"], { cwd: this.paths.pluginDir })
+ : undefined,
+ }
+
+ public async initialize(): Promise {
+ for (const event of ["SIGINT", "SIGTERM"]) {
+ process.on(event, () => this.dispose(0))
}
- const vscode = cp.spawn("yarn", ["watch"], { cwd: this.vscodeSourcePath })
- const tsc = cp.spawn("tsc", ["--watch", "--pretty", "--preserveWatchOutput"], { cwd: this.rootPath })
- const plugin = process.env.PLUGIN_DIR
- ? cp.spawn("yarn", ["build", "--watch"], { cwd: process.env.PLUGIN_DIR })
- : undefined
- const bundler = this.createBundler()
-
- const cleanup = (code?: number | null): void => {
- Watcher.log("killing vs code watcher")
- vscode.removeAllListeners()
- vscode.kill()
-
- Watcher.log("killing tsc")
- tsc.removeAllListeners()
- tsc.kill()
-
- if (plugin) {
- Watcher.log("killing plugin")
- plugin.removeAllListeners()
- plugin.kill()
- }
+ for (const [processName, devProcess] of Object.entries(this.compilers)) {
+ if (!devProcess) continue
- if (server) {
- Watcher.log("killing server")
- server.removeAllListeners()
- server.kill()
+ devProcess.on("exit", (code) => {
+ console.log(`[${processName}]`, "Terminated unexpectedly")
+ this.dispose(code)
+ })
+
+ if (devProcess.stderr) {
+ devProcess.stderr.on("data", (d: string | Uint8Array) => process.stderr.write(d))
}
+ }
+
+ onLine(this.compilers.vscode, this.parseVSCodeLine)
+ onLine(this.compilers.codeServer, this.parseCodeServerLine)
- Watcher.log("killing bundler")
- process.exit(code || 0)
+ if (this.compilers.plugins) {
+ onLine(this.compilers.plugins, this.parsePluginLine)
}
+ }
- process.on("SIGINT", () => cleanup())
- process.on("SIGTERM", () => cleanup())
-
- vscode.on("exit", (code) => {
- Watcher.log("vs code watcher terminated unexpectedly")
- cleanup(code)
- })
- tsc.on("exit", (code) => {
- Watcher.log("tsc terminated unexpectedly")
- cleanup(code)
- })
- if (plugin) {
- plugin.on("exit", (code) => {
- Watcher.log("plugin terminated unexpectedly")
- cleanup(code)
- })
+ //#endregion
+
+ //#region Line Parsers
+
+ private parseVSCodeLine: OnLineCallback = (strippedLine, originalLine) => {
+ if (!strippedLine.length) return
+
+ console.log("[Code OSS]", originalLine)
+
+ if (strippedLine.includes("Finished compilation with")) {
+ console.log("[Code OSS] ✨ Finished compiling! ✨", "(Refresh your web browser ♻️)")
+ this.reloadWebServer()
}
- const bundle = bundler.bundle().catch(() => {
- Watcher.log("parcel watcher terminated unexpectedly")
- cleanup(1)
- })
- bundler.on("buildEnd", () => {
- console.log("[parcel] bundled")
- })
- bundler.on("buildError", (error) => {
- console.error("[parcel]", error)
- })
-
- vscode.stderr.on("data", (d) => process.stderr.write(d))
- tsc.stderr.on("data", (d) => process.stderr.write(d))
- if (plugin) {
- plugin.stderr.on("data", (d) => process.stderr.write(d))
+ }
+
+ private parseCodeServerLine: OnLineCallback = (strippedLine, originalLine) => {
+ if (!strippedLine.length) return
+
+ console.log("[Compiler][code-server]", originalLine)
+
+ if (strippedLine.includes("Watching for file changes")) {
+ console.log("[Compiler][code-server]", "Finished compiling!", "(Refresh your web browser ♻️)")
+ this.reloadWebServer()
}
+ }
- // From https://github.com/chalk/ansi-regex
- const pattern = [
- "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
- "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
- ].join("|")
- const re = new RegExp(pattern, "g")
-
- /**
- * Split stdout on newlines and strip ANSI codes.
- */
- const onLine = (proc: cp.ChildProcess, callback: (strippedLine: string, originalLine: string) => void): void => {
- let buffer = ""
- if (!proc.stdout) {
- throw new Error("no stdout")
- }
- proc.stdout.setEncoding("utf8")
- proc.stdout.on("data", (d) => {
- const data = buffer + d
- const split = data.split("\n")
- const last = split.length - 1
-
- for (let i = 0; i < last; ++i) {
- callback(split[i].replace(re, ""), split[i])
- }
-
- // The last item will either be an empty string (the data ended with a
- // newline) or a partial line (did not end with a newline) and we must
- // wait to parse it until we get a full line.
- buffer = split[last]
- })
+ private parsePluginLine: OnLineCallback = (strippedLine, originalLine) => {
+ if (!strippedLine.length) return
+
+ console.log("[Compiler][Plugin]", originalLine)
+
+ if (strippedLine.includes("Watching for file changes...")) {
+ this.reloadWebServer()
}
+ }
- let startingVscode = false
- let startedVscode = false
- onLine(vscode, (line, original) => {
- console.log("[vscode]", original)
- // Wait for watch-client since "Finished compilation" will appear multiple
- // times before the client starts building.
- if (!startingVscode && line.includes("Starting watch-client")) {
- startingVscode = true
- } else if (startingVscode && line.includes("Finished compilation")) {
- if (startedVscode) {
- bundle.then(restartServer)
- }
- startedVscode = true
- }
- })
+ //#endregion
- onLine(tsc, (line, original) => {
- // tsc outputs blank lines; skip them.
- if (line !== "") {
- console.log("[tsc]", original)
- }
- if (line.includes("Watching for file changes")) {
- bundle.then(restartServer)
- }
- })
-
- if (plugin) {
- onLine(plugin, (line, original) => {
- // tsc outputs blank lines; skip them.
- if (line !== "") {
- console.log("[plugin]", original)
- }
- if (line.includes("Watching for file changes")) {
- bundle.then(restartServer)
- }
- })
+ //#region Utilities
+
+ private dispose(code: number | null): void {
+ for (const [processName, devProcess] of Object.entries(this.compilers)) {
+ console.log(`[${processName}]`, "Killing...\n")
+ devProcess?.removeAllListeners()
+ devProcess?.kill()
}
+ process.exit(typeof code === "number" ? code : 0)
}
- private createBundler(out = "dist"): Bundler {
- return new Bundler(
- [
- path.join(this.rootPath, "src/browser/register.ts"),
- path.join(this.rootPath, "src/browser/serviceWorker.ts"),
- path.join(this.rootPath, "src/browser/pages/login.ts"),
- path.join(this.rootPath, "src/browser/pages/vscode.ts"),
- ],
- {
- outDir: path.join(this.rootPath, out),
- cacheDir: path.join(this.rootPath, ".cache"),
- minify: !!process.env.MINIFY,
- logLevel: 1,
- publicUrl: ".",
- },
- )
+ //#endregion
+}
+
+async function main(): Promise {
+ try {
+ const watcher = new Watcher()
+ await watcher.initialize()
+ } catch (error: any) {
+ console.error(error.message)
+ process.exit(1)
}
}
diff --git a/ci/helm-chart/Chart.yaml b/ci/helm-chart/Chart.yaml
index 089e03486abe..f9c3b1103d49 100644
--- a/ci/helm-chart/Chart.yaml
+++ b/ci/helm-chart/Chart.yaml
@@ -1,6 +1,6 @@
apiVersion: v2
name: code-server
-description: A Helm chart for cdr/code-server
+description: A Helm chart for coder/code-server
# A chart can be either an 'application' or a 'library' chart.
#
@@ -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: 1.0.1
+version: 3.36.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: 3.7.2
+appVersion: 4.121.0
diff --git a/ci/helm-chart/README.md b/ci/helm-chart/README.md
deleted file mode 100644
index aa6b506adffd..000000000000
--- a/ci/helm-chart/README.md
+++ /dev/null
@@ -1,117 +0,0 @@
-# code-server
-
-  
-
-[code-server](https://github.com/cdr/code-server) code-server is VS Code running
-on a remote server, accessible through the browser.
-
-This chart is community maintained by [@Matthew-Beckett](https://github.com/Matthew-Beckett) and [@alexgorbatchev](https://github.com/alexgorbatchev)
-
-## TL;DR;
-
-```console
-$ git clone https://github.com/cdr/code-server
-$ cd code-server
-$ helm upgrade --install code-server ci/helm-chart
-```
-
-## Introduction
-
-This chart bootstraps a code-server deployment on a
-[Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh)
-package manager.
-
-## Prerequisites
-
- - Kubernetes 1.6+
-
-## Installing the Chart
-
-To install the chart with the release name `code-server`:
-
-```console
-$ git clone https://github.com/cdr/code-server
-$ cd code-server
-$ helm upgrade --install code-server ci/helm-chart
-```
-
-The command deploys code-server on the Kubernetes cluster in the default
-configuration. The [configuration](#configuration) section lists the parameters
-that can be configured during installation.
-
-> **Tip**: List all releases using `helm list`
-
-## Uninstalling the Chart
-
-To uninstall/delete the `code-server` deployment:
-
-```console
-$ helm delete code-server
-```
-
-The command removes all the Kubernetes components associated with the chart and
-deletes the release.
-
-## Configuration
-
-The following table lists the configurable parameters of the code-server chart
-and their default values.
-
-## Values
-
-| Key | Type | Default | Description |
-|-----|------|---------|-------------|
-| affinity | object | `{}` | |
-| extraArgs | list | `[]` | |
-| extraConfigmapMounts | list | `[]` | |
-| extraContainers | string | `""` | |
-| extraSecretMounts | list | `[]` | |
-| extraVars | list | `[]` | |
-| extraVolumeMounts | list | `[]` | |
-| fullnameOverride | string | `""` | |
-| hostnameOverride | string | `""` | |
-| image.pullPolicy | string | `"Always"` | |
-| image.repository | string | `"codercom/code-server"` | |
-| image.tag | string | `"3.7.2"` | |
-| imagePullSecrets | list | `[]` | |
-| ingress.enabled | bool | `false` | |
-| nameOverride | string | `""` | |
-| nodeSelector | object | `{}` | |
-| persistence.accessMode | string | `"ReadWriteOnce"` | |
-| persistence.annotations | object | `{}` | |
-| persistence.enabled | bool | `true` | |
-| persistence.size | string | `"1Gi"` | |
-| podAnnotations | object | `{}` | |
-| podSecurityContext | object | `{}` | |
-| replicaCount | int | `1` | |
-| resources | object | `{}` | |
-| securityContext.enabled | bool | `true` | |
-| securityContext.fsGroup | int | `1000` | |
-| securityContext.runAsUser | int | `1000` | |
-| service.port | int | `8443` | |
-| service.type | string | `"ClusterIP"` | |
-| serviceAccount.create | bool | `true` | |
-| serviceAccount.name | string | `nil` | |
-| tolerations | list | `[]` | |
-| volumePermissions.enabled | bool | `true` | |
-| volumePermissions.securityContext.runAsUser | int | `0` | |
-
-Specify each parameter using the `--set key=value[,key=value]` argument to `helm
-install`. For example,
-
-```console
-$ helm upgrade --install code-server \
- ci/helm-chart \
- --set persistence.enabled=false
-```
-
-The above command sets the the persistence storage to false.
-
-Alternatively, a YAML file that specifies the values for the above parameters
-can be provided while installing the chart. For example,
-
-```console
-$ helm upgrade --install code-server ci/helm-chart -f values.yaml
-```
-
-> **Tip**: You can use the default [values.yaml](values.yaml)
diff --git a/ci/helm-chart/templates/NOTES.txt b/ci/helm-chart/templates/NOTES.txt
index 17c25f646dc2..45c9aed3881d 100644
--- a/ci/helm-chart/templates/NOTES.txt
+++ b/ci/helm-chart/templates/NOTES.txt
@@ -15,9 +15,8 @@
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "code-server.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
- export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "code-server.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
- kubectl port-forward $POD_NAME 8080:80
+ kubectl port-forward --namespace {{ .Release.Namespace }} service/{{ include "code-server.fullname" . }} 8080:http
{{- end }}
Administrator credentials:
diff --git a/ci/helm-chart/templates/deployment.yaml b/ci/helm-chart/templates/deployment.yaml
index 9364a4706aa3..18bece028fc6 100644
--- a/ci/helm-chart/templates/deployment.yaml
+++ b/ci/helm-chart/templates/deployment.yaml
@@ -3,33 +3,41 @@ kind: Deployment
metadata:
name: {{ include "code-server.fullname" . }}
labels:
- app.kubernetes.io/name: {{ include "code-server.name" . }}
- helm.sh/chart: {{ include "code-server.chart" . }}
- app.kubernetes.io/instance: {{ .Release.Name }}
- app.kubernetes.io/managed-by: {{ .Release.Service }}
+ {{- include "code-server.labels" . | nindent 4 }}
+ {{- if .Values.annotations }}
+ annotations: {{- toYaml .Values.annotations | nindent 4 }}
+ {{- end }}
spec:
- replicas: 1
+ {{- if ne .Values.replicaCount nil }}
+ replicas: {{ .Values.replicaCount }}
+ {{- end }}
strategy:
type: Recreate
selector:
matchLabels:
- app.kubernetes.io/name: {{ include "code-server.name" . }}
- app.kubernetes.io/instance: {{ .Release.Name }}
+ {{- include "code-server.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
- app.kubernetes.io/name: {{ include "code-server.name" . }}
- app.kubernetes.io/instance: {{ .Release.Name }}
+ {{- include "code-server.selectorLabels" . | nindent 8 }}
+ {{- if .Values.podAnnotations }}
+ annotations: {{- toYaml .Values.podAnnotations | nindent 8 }}
+ {{- end }}
spec:
+ imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }}
{{- if .Values.hostnameOverride }}
hostname: {{ .Values.hostnameOverride }}
{{- end }}
+ {{- if .Values.priorityClassName }}
+ priorityClassName: {{ .Values.priorityClassName }}
+ {{- end }}
{{- if .Values.securityContext.enabled }}
securityContext:
fsGroup: {{ .Values.securityContext.fsGroup }}
{{- end }}
- {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }}
+ {{- if or (and .Values.volumePermissions.enabled .Values.persistence.enabled) .Values.extraInitContainers }}
initContainers:
+ {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }}
- name: init-chmod-data
image: busybox:latest
imagePullPolicy: IfNotPresent
@@ -44,9 +52,13 @@ spec:
- name: data
mountPath: /home/coder
{{- end }}
+{{- if .Values.extraInitContainers }}
+{{ tpl .Values.extraInitContainers . | indent 6}}
+{{- end }}
+ {{- end }}
containers:
{{- if .Values.extraContainers }}
-{{ toYaml .Values.extraContainers | indent 8}}
+{{ tpl .Values.extraContainers . | indent 8}}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
@@ -55,6 +67,17 @@ spec:
securityContext:
runAsUser: {{ .Values.securityContext.runAsUser }}
{{- end }}
+ {{- if .Values.lifecycle.enabled }}
+ lifecycle:
+ {{- if .Values.lifecycle.postStart }}
+ postStart:
+ {{ toYaml .Values.lifecycle.postStart | nindent 14 }}
+ {{- end }}
+ {{- if .Values.lifecycle.preStop }}
+ preStop:
+ {{ toYaml .Values.lifecycle.preStop | nindent 14 }}
+ {{- end }}
+ {{- end }}
env:
{{- if .Values.extraVars }}
{{ toYaml .Values.extraVars | indent 10 }}
@@ -84,6 +107,7 @@ spec:
{{- range .Values.extraSecretMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
+ subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- range .Values.extraVolumeMounts }}
@@ -96,14 +120,23 @@ spec:
- name: http
containerPort: 8080
protocol: TCP
+ {{- range .Values.extraPorts }}
+ - name: {{ .name }}
+ containerPort: {{ .port }}
+ protocol: {{ .protocol }}
+ {{- end }}
+ {{- if ne .Values.livenessProbe.enabled false }}
livenessProbe:
httpGet:
- path: /
+ path: /healthz
port: http
+ {{- end }}
+ {{- if ne .Values.readinessProbe.enabled false }}
readinessProbe:
httpGet:
- path: /
+ path: /healthz
port: http
+ {{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
@@ -112,7 +145,7 @@ spec:
{{- end }}
{{- with .Values.affinity }}
affinity:
- {{- toYaml . | nindent 8 }}
+ {{- tpl . $ | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
@@ -139,14 +172,23 @@ spec:
secretName: {{ .secretName }}
defaultMode: {{ .defaultMode }}
{{- end }}
+ {{- range .Values.extraConfigmapMounts }}
+ - name: {{ .name }}
+ configMap:
+ name: {{ .configMap }}
+ defaultMode: {{ .defaultMode }}
+ {{- end }}
{{- range .Values.extraVolumeMounts }}
- name: {{ .name }}
{{- if .existingClaim }}
persistentVolumeClaim:
claimName: {{ .existingClaim }}
- {{- else }}
+ {{- else if .hostPath }}
hostPath:
path: {{ .hostPath }}
type: Directory
+ {{- else }}
+ emptyDir:
+ {{- toYaml .emptyDir | nindent 10 }}
{{- end }}
{{- end }}
diff --git a/ci/helm-chart/templates/ingress.yaml b/ci/helm-chart/templates/ingress.yaml
index 07a3abd0b693..1da432074b29 100644
--- a/ci/helm-chart/templates/ingress.yaml
+++ b/ci/helm-chart/templates/ingress.yaml
@@ -1,7 +1,9 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "code-server.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
-{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1
+{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
@@ -16,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 }}
@@ -27,6 +32,22 @@ spec:
{{- end }}
{{- end }}
rules:
+ {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion -}}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ .host | quote }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ . }}
+ pathType: Prefix
+ backend:
+ service:
+ name: {{ $fullName }}
+ port:
+ number: {{ $svcPort }}
+ {{- end }}
+ {{- end }}
+ {{- else -}}
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
@@ -39,3 +60,4 @@ spec:
{{- end }}
{{- end }}
{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/ci/helm-chart/templates/pvc.yaml b/ci/helm-chart/templates/pvc.yaml
index 2f1c87405886..206b834e930d 100644
--- a/ci/helm-chart/templates/pvc.yaml
+++ b/ci/helm-chart/templates/pvc.yaml
@@ -9,10 +9,7 @@ metadata:
{{ toYaml . | indent 4 }}
{{- end }}
labels:
- app.kubernetes.io/name: {{ include "code-server.name" . }}
- helm.sh/chart: {{ include "code-server.chart" . }}
- app.kubernetes.io/instance: {{ .Release.Name }}
- app.kubernetes.io/managed-by: {{ .Release.Service }}
+ {{- include "code-server.labels" . | nindent 4 }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
diff --git a/ci/helm-chart/templates/secrets.yaml b/ci/helm-chart/templates/secrets.yaml
index 6c600417a516..93e75800dffd 100644
--- a/ci/helm-chart/templates/secrets.yaml
+++ b/ci/helm-chart/templates/secrets.yaml
@@ -1,3 +1,4 @@
+{{- if not .Values.existingSecret }}
apiVersion: v1
kind: Secret
metadata:
@@ -5,14 +6,12 @@ metadata:
annotations:
"helm.sh/hook": "pre-install"
labels:
- app.kubernetes.io/name: {{ include "code-server.name" . }}
- helm.sh/chart: {{ include "code-server.chart" . }}
- app.kubernetes.io/instance: {{ .Release.Name }}
- app.kubernetes.io/managed-by: {{ .Release.Service }}
+ {{- include "code-server.labels" . | nindent 4 }}
type: Opaque
data:
- {{ if .Values.password }}
+ {{- if .Values.password }}
password: "{{ .Values.password | b64enc }}"
- {{ else }}
+ {{- else }}
password: "{{ randAlphaNum 24 | b64enc }}"
- {{ end }}
+ {{- end }}
+{{- end }}
diff --git a/ci/helm-chart/templates/service.yaml b/ci/helm-chart/templates/service.yaml
index 038b6cd0d23f..1b58af0b1acd 100644
--- a/ci/helm-chart/templates/service.yaml
+++ b/ci/helm-chart/templates/service.yaml
@@ -3,10 +3,7 @@ kind: Service
metadata:
name: {{ include "code-server.fullname" . }}
labels:
- app.kubernetes.io/name: {{ include "code-server.name" . }}
- helm.sh/chart: {{ include "code-server.chart" . }}
- app.kubernetes.io/instance: {{ .Release.Name }}
- app.kubernetes.io/managed-by: {{ .Release.Service }}
+ {{- include "code-server.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
@@ -14,6 +11,12 @@ spec:
targetPort: http
protocol: TCP
name: http
+ {{- range .Values.extraPorts }}
+ - port: {{ .port }}
+ targetPort: {{ .port }}
+ protocol: {{ .protocol }}
+ name: {{ .name }}
+ {{- end }}
selector:
app.kubernetes.io/name: {{ include "code-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
diff --git a/ci/helm-chart/templates/serviceaccount.yaml b/ci/helm-chart/templates/serviceaccount.yaml
index df9e1e37562b..2fa308fec172 100644
--- a/ci/helm-chart/templates/serviceaccount.yaml
+++ b/ci/helm-chart/templates/serviceaccount.yaml
@@ -3,9 +3,6 @@ apiVersion: v1
kind: ServiceAccount
metadata:
labels:
- app.kubernetes.io/name: {{ include "code-server.name" . }}
- helm.sh/chart: {{ include "code-server.chart" . }}
- app.kubernetes.io/instance: {{ .Release.Name }}
- app.kubernetes.io/managed-by: {{ .Release.Service }}
+ {{- include "code-server.labels" . | nindent 4 }}
name: {{ template "code-server.serviceAccountName" . }}
{{- end -}}
diff --git a/ci/helm-chart/templates/tests/test-connection.yaml b/ci/helm-chart/templates/tests/test-connection.yaml
index 2e67f56ec64c..dd81f8904e06 100644
--- a/ci/helm-chart/templates/tests/test-connection.yaml
+++ b/ci/helm-chart/templates/tests/test-connection.yaml
@@ -3,16 +3,13 @@ kind: Pod
metadata:
name: "{{ include "code-server.fullname" . }}-test-connection"
labels:
- app.kubernetes.io/name: {{ include "code-server.name" . }}
- helm.sh/chart: {{ include "code-server.chart" . }}
- app.kubernetes.io/instance: {{ .Release.Name }}
- app.kubernetes.io/managed-by: {{ .Release.Service }}
+ {{- include "code-server.labels" . | nindent 4 }}
annotations:
- "helm.sh/hook": test-success
+ "helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
- args: ['{{ include "code-server.fullname" . }}:{{ .Values.service.port }}']
+ args: ['{{ include "code-server.fullname" . }}:{{ .Values.service.port }}/healthz']
restartPolicy: Never
diff --git a/ci/helm-chart/values.yaml b/ci/helm-chart/values.yaml
index 5d2ba0299f2e..0b5a3311d6b0 100644
--- a/ci/helm-chart/values.yaml
+++ b/ci/helm-chart/values.yaml
@@ -6,14 +6,22 @@ replicaCount: 1
image:
repository: codercom/code-server
- tag: '3.7.2'
+ tag: '4.121.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: ""
+# The existing secret to use for code-server authentication in the frontend. the password is stored in the secret under the key `password`
+# existingSecret: ""
+
serviceAccount:
# Specifies whether a service account should be created
create: true
@@ -23,18 +31,15 @@ serviceAccount:
# If not set and create is true, a name is generated using the fullname template
name: ""
+# Specifies annotations for deployment
+annotations: {}
+
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
-securityContext: {}
- # capabilities:
- # drop:
- # - ALL
- # readOnlyRootFilesystem: true
- # runAsNonRoot: true
- # runAsUser: 1000
+priorityClassName: ""
service:
type: ClusterIP
@@ -43,13 +48,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:
@@ -57,13 +61,26 @@ ingress:
# Optional additional arguments
extraArgs: []
-# - --allow-http
-# - --no-auth
+ # These are the arguments normally passed to code-server; run
+ # code-server --help for a list of available options.
+ #
+ # Each argument and parameter must have its own entry; if you use
+ # --param value on the command line, then enter it here as:
+ #
+ # - --param
+ # - value
+ #
+ # If you receive an error like "Unknown option --param value", it may be
+ # because both the parameter and value are specified as a single argument,
+ # rather than two separate arguments (e.g. "- --param value" on a line).
# Optional additional environment variables
extraVars: []
# - name: DISABLE_TELEMETRY
-# value: true
+# value: "true"
+# if dind is desired:
+# - name: DOCKER_HOST
+# value: "tcp://localhost:2376"
##
## Init containers parameters:
@@ -94,6 +111,12 @@ resources: {}
# cpu: 100m
# memory: 1000Mi
+livenessProbe:
+ enabled: true
+
+readinessProbe:
+ enabled: true
+
nodeSelector: {}
tolerations: []
@@ -117,33 +140,73 @@ persistence:
# existingClaim: ""
# hostPath: /data
-serviceAccount:
- create: true
- name:
+lifecycle:
+ enabled: false
+ # postStart:
+ # exec:
+ # command:
+ # - /bin/bash
+ # - -c
+ # - curl -s -L SOME_SCRIPT | bash
+
+ # for dind, the following may be helpful
+ # postStart:
+ # exec:
+ # command:
+ # - /bin/sh
+ # - -c
+ # - |
+ # sudo apt-get update \
+ # && sudo apt-get install -y docker.io
## Enable an Specify container in extraContainers.
## This is meant to allow adding code-server dependencies, like docker-dind.
extraContainers: |
-#- name: docker-dind
-# image: docker:19.03-dind
-# imagePullPolicy: IfNotPresent
-# resources:
-# requests:
-# cpu: 250m
-# memory: 256M
-# securityContext:
-# privileged: true
-# procMount: Default
-# env:
-# - name: DOCKER_TLS_CERTDIR
-# value: ""
-# - name: DOCKER_DRIVER
-# value: "overlay2"
+# If docker-dind is used, DOCKER_HOST env is mandatory to set in "extraVars"
+# - name: docker-dind
+# image: docker:28.3.2-dind
+# imagePullPolicy: IfNotPresent
+# resources:
+# requests:
+# cpu: 1
+# ephemeral-storage: "50Gi"
+# memory: 10Gi
+# securityContext:
+# privileged: true
+# procMount: Default
+# env:
+# - name: DOCKER_TLS_CERTDIR
+# value: "" # disable TLS setup
+# command:
+# - dockerd
+# - --host=unix:///var/run/docker.sock
+# - --host=tcp://0.0.0.0:2376
+
+
+extraInitContainers: |
+# - name: customization
+# image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
+# imagePullPolicy: IfNotPresent
+# env:
+# - name: SERVICE_URL
+# value: https://open-vsx.org/vscode/gallery
+# - name: ITEM_URL
+# value: https://open-vsx.org/vscode/item
+# command:
+# - sh
+# - -c
+# - |
+# code-server --install-extension ms-python.python
+# code-server --install-extension golang.Go
+# volumeMounts:
+# - name: data
+# mountPath: /home/coder
## Additional code-server secret mounts
extraSecretMounts: []
# - name: secret-files
# mountPath: /etc/secrets
+ # subPath: private.key # (optional)
# secretName: code-server-secret-files
# readOnly: true
@@ -154,6 +217,7 @@ extraVolumeMounts: []
# readOnly: true
# existingClaim: volume-claim
# hostPath: ""
+ # emptyDir: {}
extraConfigmapMounts: []
# - name: certs-configmap
@@ -161,3 +225,8 @@ extraConfigmapMounts: []
# subPath: certificates.crt # (optional)
# configMap: certs-configmap
# readOnly: true
+
+extraPorts: []
+ # - name: minecraft
+ # port: 25565
+ # protocol: tcp
diff --git a/ci/images/centos7/Dockerfile b/ci/images/centos7/Dockerfile
deleted file mode 100644
index a37e590bb216..000000000000
--- a/ci/images/centos7/Dockerfile
+++ /dev/null
@@ -1,32 +0,0 @@
-FROM centos:7
-
-ARG NODE_VERSION=v12.18.4
-RUN ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')" && \
- curl -fsSL "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-linux-$ARCH.tar.xz" | tar -C /usr/local -xJ && \
- mv "/usr/local/node-$NODE_VERSION-linux-$ARCH" "/usr/local/node-$NODE_VERSION"
-ENV PATH=/usr/local/node-$NODE_VERSION/bin:$PATH
-RUN npm install -g yarn
-
-RUN yum groupinstall -y 'Development Tools'
-RUN yum install -y python2 libsecret-devel libX11-devel libxkbfile-devel
-
-RUN npm config set python python2
-
-RUN yum install -y epel-release && yum install -y jq
-RUN yum install -y rsync
-
-# Copied from ../debian10/Dockerfile
-# Install Go.
-RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \
- curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz
-ENV GOPATH=/gopath
-# Ensures running this image as another user works.
-RUN mkdir -p $GOPATH && chmod -R 777 $GOPATH
-ENV PATH=/usr/local/go/bin:$GOPATH/bin:$PATH
-
-# Install Go dependencies
-ENV GO111MODULE=on
-RUN go get mvdan.cc/sh/v3/cmd/shfmt
-RUN go get github.com/goreleaser/nfpm/cmd/nfpm@v1.9.0
-
-RUN curl -fsSL https://get.docker.com | sh
diff --git a/ci/images/debian10/Dockerfile b/ci/images/debian10/Dockerfile
deleted file mode 100644
index 5e4a5f85927b..000000000000
--- a/ci/images/debian10/Dockerfile
+++ /dev/null
@@ -1,54 +0,0 @@
-FROM debian:10
-
-RUN apt-get update
-
-# Needed for debian repositories added below.
-RUN apt-get install -y curl gnupg
-
-# Installs node.
-RUN curl -fsSL https://deb.nodesource.com/setup_12.x | bash - && \
- apt-get install -y nodejs
-
-# Installs yarn.
-RUN curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
- echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
- apt-get update && apt-get install -y yarn
-
-# Installs VS Code build deps.
-RUN apt-get install -y build-essential \
- libsecret-1-dev \
- libx11-dev \
- libxkbfile-dev
-
-# Installs envsubst.
-RUN apt-get install -y gettext-base
-
-# Misc build dependencies.
-RUN apt-get install -y git rsync unzip jq
-
-# Installs shellcheck.
-RUN curl -fsSL https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.$(uname -m).tar.xz | \
- tar -xJ && \
- mv shellcheck*/shellcheck /usr/local/bin && \
- rm -R shellcheck*
-
-# Install Go.
-RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \
- curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz
-ENV GOPATH=/gopath
-# Ensures running this image as another user works.
-RUN mkdir -p $GOPATH && chmod -R 777 $GOPATH
-ENV PATH=/usr/local/go/bin:$GOPATH/bin:$PATH
-
-# Install Go dependencies
-ENV GO111MODULE=on
-RUN go get mvdan.cc/sh/v3/cmd/shfmt
-RUN go get github.com/goreleaser/nfpm/cmd/nfpm@v1.9.0
-
-RUN VERSION="$(curl -fsSL https://storage.googleapis.com/kubernetes-release/release/stable.txt)" && \
- curl -fsSL "https://storage.googleapis.com/kubernetes-release/release/$VERSION/bin/linux/amd64/kubectl" > /usr/local/bin/kubectl \
- && chmod +x /usr/local/bin/kubectl
-RUN curl -fsSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
-RUN helm plugin install https://github.com/instrumenta/helm-kubeval
-
-RUN curl -fsSL https://get.docker.com | sh
diff --git a/ci/lib.sh b/ci/lib.sh
index d58c29cb1713..df38a9552891 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
+set -euo pipefail
pushd() {
builtin pushd "$@" > /dev/null
@@ -8,88 +9,114 @@ popd() {
builtin popd > /dev/null
}
-pkg_json_version() {
- jq -r .version package.json
-}
-
vscode_version() {
jq -r .version lib/vscode/package.json
}
os() {
- local os
- os=$(uname | tr '[:upper:]' '[:lower:]')
- if [[ $os == "linux" ]]; then
- # Alpine's ldd doesn't have a version flag but if you use an invalid flag
- # (like --version) it outputs the version to stderr and exits with 1.
- local ldd_output
- ldd_output=$(ldd --version 2>&1 || true)
- if echo "$ldd_output" | grep -iq musl; then
- os="alpine"
- fi
- elif [[ $os == "darwin" ]]; then
- os="macos"
- fi
- echo "$os"
+ osname=$(uname | tr '[:upper:]' '[:lower:]')
+ case $osname in
+ linux)
+ # Alpine's ldd doesn't have a version flag but if you use an invalid flag
+ # (like --version) it outputs the version to stderr and exits with 1.
+ # TODO: Better to check /etc/os-release; see ../install.sh.
+ ldd_output=$(ldd --version 2>&1 || true)
+ if echo "$ldd_output" | grep -iq musl; then
+ osname="alpine"
+ fi
+ ;;
+ darwin) osname="macos" ;;
+ cygwin* | mingw*) osname="windows" ;;
+ esac
+ echo "$osname"
}
arch() {
- case "$(uname -m)" in
- aarch64)
- echo arm64
- ;;
- x86_64)
- echo amd64
- ;;
- *)
- echo "unknown architecture $(uname -a)"
- exit 1
- ;;
+ cpu="$(uname -m)"
+ case "$cpu" in
+ aarch64) cpu=arm64 ;;
+ x86_64) cpu=amd64 ;;
esac
+ echo "$cpu"
}
-curl() {
- command curl -H "Authorization: token $GITHUB_TOKEN" "$@"
+rsync() {
+ command rsync -a --del "$@"
}
-# Grabs the most recent ci.yaml github workflow run that was successful and triggered from the same commit being pushd.
-# This will contain the artifacts we want.
-# https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs
-get_artifacts_url() {
- curl -fsSL 'https://api.github.com/repos/cdr/code-server/actions/workflows/ci.yaml/runs?status=success&event=push' | jq -r ".workflow_runs[] | select(.head_sha == \"$(git rev-parse HEAD)\") | .artifacts_url" | head -n 1
-}
+if [[ ! ${ARCH-} ]]; then
+ ARCH=$(arch)
+ export ARCH
+fi
-# Grabs the artifact's download url.
-# https://developer.github.com/v3/actions/artifacts/#list-workflow-run-artifacts
-get_artifact_url() {
- local artifact_name="$1"
- curl -fsSL "$(get_artifacts_url)" | jq -r ".artifacts[] | select(.name == \"$artifact_name\") | .archive_download_url" | head -n 1
-}
+if [[ ! ${OS-} ]]; then
+ OS=$(os)
+ export OS
+fi
+
+# RELEASE_PATH is the destination directory for the release from the root.
+# Defaults to release
+if [[ ! ${RELEASE_PATH-} ]]; then
+ RELEASE_PATH="release"
+ export RELEASE_PATH
+fi
-# Uses the above two functions to download a artifact into a directory.
-download_artifact() {
- local artifact_name="$1"
- local dst="$2"
+nodeOS() {
+ osname=$OS
+ case $osname in
+ macos) osname=darwin ;;
+ windows) osname=win32 ;;
+ esac
+ echo "$osname"
+}
- local tmp_file
- tmp_file="$(mktemp)"
+nodeArch() {
+ cpu=$ARCH
+ case $cpu in
+ amd64) cpu=x64 ;;
+ esac
+ echo "$cpu"
+}
- curl -fsSL "$(get_artifact_url "$artifact_name")" > "$tmp_file"
- unzip -q -o "$tmp_file" -d "$dst"
- rm "$tmp_file"
+run-steps() {
+ local -i failed=0
+ mkdir -p .cache
+ rm -f .cache/checklist
+ while (( $# )) ; do
+ local name=$1 ; shift
+ local fn=$1 ; shift
+ # Only run if an earlier step has not failed.
+ if [[ $failed == 0 ]] ; then
+ echo "$name..."
+ if $fn | indent ; then
+ echo "- [X] $name" >> .cache/checklist
+ else
+ ((failed++))
+ fi
+ fi
+ # For all failed steps, write out an empty checkbox.
+ if [[ $failed != 0 ]] ; then
+ echo "- [ ] $name" >> .cache/checklist
+ fi
+ done
+ if [[ $failed != 0 ]] ; then
+ return 1
+ fi
}
-rsync() {
- command rsync -a --del "$@"
+quiet() {
+ "$@" >/dev/null
}
-VERSION="$(pkg_json_version)"
-export VERSION
-ARCH="$(arch)"
-export ARCH
-OS=$(os)
-export OS
+indent() {
+ local count=2
+ local space
+ space=$(printf "%${count}s")
+ sed "s/^/$space| /g"
+}
-# RELEASE_PATH is the destination directory for the release from the root.
-# Defaults to release
-RELEASE_PATH="${RELEASE_PATH-release}"
+# See gulpfile.reh.ts for available targets.
+if [[ ! ${VSCODE_TARGET-} ]]; then
+ VSCODE_TARGET="$(nodeOS)-$(nodeArch)"
+ export VSCODE_TARGET
+fi
diff --git a/ci/release-image/Dockerfile b/ci/release-image/Dockerfile
index a0b6aed7167b..4c91e291e0e8 100644
--- a/ci/release-image/Dockerfile
+++ b/ci/release-image/Dockerfile
@@ -1,19 +1,29 @@
-FROM debian:10
+# syntax=docker/dockerfile:experimental
+
+ARG BASE=debian:13
+FROM scratch AS packages
+COPY release-packages/code-server*.deb /tmp/
+
+FROM $BASE
RUN apt-get update \
- && apt-get install -y \
+ && apt-get install -y \
curl \
dumb-init \
+ git \
+ git-lfs \
htop \
locales \
- man \
+ lsb-release \
+ man-db \
nano \
- git \
+ openssh-client \
procps \
- ssh \
sudo \
- vim \
- lsb-release \
+ vim-tiny \
+ wget \
+ zsh \
+ && git lfs install \
&& rm -rf /var/lib/apt/lists/*
# https://wiki.debian.org/Locale#Manually
@@ -21,22 +31,25 @@ RUN sed -i "s/# en_US.UTF-8/en_US.UTF-8/" /etc/locale.gen \
&& locale-gen
ENV LANG=en_US.UTF-8
-RUN chsh -s /bin/bash
-ENV SHELL=/bin/bash
-
-RUN adduser --gecos '' --disabled-password coder && \
- echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
+RUN if grep -q 1000 /etc/passwd; then \
+ userdel -r "$(id -un 1000)"; \
+ fi \
+ && adduser --gecos '' --disabled-password coder \
+ && echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
-RUN ARCH="$(dpkg --print-architecture)" && \
- curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.4.1/fixuid-0.4.1-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - && \
- chown root:root /usr/local/bin/fixuid && \
- chmod 4755 /usr/local/bin/fixuid && \
- mkdir -p /etc/fixuid && \
- printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
+RUN ARCH="$(dpkg --print-architecture)" \
+ && curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
+ && chown root:root /usr/local/bin/fixuid \
+ && chmod 4755 /usr/local/bin/fixuid \
+ && mkdir -p /etc/fixuid \
+ && printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
-COPY release-packages/code-server*.deb /tmp/
COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh
-RUN dpkg -i /tmp/code-server*$(dpkg --print-architecture).deb && rm /tmp/code-server*.deb
+RUN --mount=from=packages,src=/tmp,dst=/tmp/packages dpkg -i /tmp/packages/code-server*$(dpkg --print-architecture).deb
+
+# Allow users to have scripts run on container startup to prepare workspace.
+# https://github.com/coder/code-server/issues/5177
+ENV ENTRYPOINTD=${HOME}/entrypoint.d
EXPOSE 8080
# This way, if someone sets $DOCKER_USER, docker-exec will still work as
diff --git a/ci/release-image/Dockerfile.fedora b/ci/release-image/Dockerfile.fedora
new file mode 100644
index 000000000000..ec618530cb78
--- /dev/null
+++ b/ci/release-image/Dockerfile.fedora
@@ -0,0 +1,51 @@
+# syntax=docker/dockerfile:experimental
+
+ARG BASE=fedora:39
+FROM scratch AS packages
+COPY release-packages/code-server*.rpm /tmp/
+
+FROM $BASE
+
+RUN dnf update -y \
+ && dnf install -y \
+ curl \
+ git \
+ git-lfs \
+ htop \
+ nano \
+ openssh-clients \
+ procps \
+ wget \
+ zsh \
+ dumb-init \
+ glibc-langpack-en \
+ && rm -rf /var/cache/dnf
+RUN git lfs install
+
+ENV LANG=en_US.UTF-8
+RUN echo 'LANG="en_US.UTF-8"' > /etc/locale.conf
+
+RUN useradd -u 1000 coder && echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
+
+RUN ARCH="$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g')" \
+ && curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
+ && chown root:root /usr/local/bin/fixuid \
+ && chmod 4755 /usr/local/bin/fixuid \
+ && mkdir -p /etc/fixuid \
+ && printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
+
+COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh
+RUN --mount=from=packages,src=/tmp,dst=/tmp/packages rpm -i /tmp/packages/code-server*$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g').rpm
+
+# Allow users to have scripts run on container startup to prepare workspace.
+# https://github.com/coder/code-server/issues/5177
+ENV ENTRYPOINTD=${HOME}/entrypoint.d
+
+EXPOSE 8080
+# This way, if someone sets $DOCKER_USER, docker-exec will still work as
+# the uid will remain the same. note: only relevant if -u isn't passed to
+# docker-run.
+USER 1000
+ENV USER=coder
+WORKDIR /home/coder
+ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "."]
diff --git a/ci/release-image/Dockerfile.opensuse b/ci/release-image/Dockerfile.opensuse
new file mode 100644
index 000000000000..f445d45c27b1
--- /dev/null
+++ b/ci/release-image/Dockerfile.opensuse
@@ -0,0 +1,51 @@
+# syntax=docker/dockerfile:experimental
+
+ARG BASE=opensuse/tumbleweed
+FROM scratch AS packages
+COPY release-packages/code-server*.rpm /tmp/
+
+FROM $BASE
+
+RUN zypper dup -y \
+ && zypper in -y \
+ curl \
+ git \
+ git-lfs \
+ htop \
+ nano \
+ openssh-clients \
+ procps \
+ wget \
+ zsh \
+ sudo \
+ catatonit \
+ && rm -rf /var/cache/zypp /var/cache/zypper
+RUN git lfs install
+
+ENV LANG=en_US.UTF-8
+RUN echo 'LANG="en_US.UTF-8"' > /etc/locale.conf
+
+RUN useradd -u 1000 coder && echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
+
+RUN ARCH="$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g')" \
+ && curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - \
+ && chown root:root /usr/local/bin/fixuid \
+ && chmod 4755 /usr/local/bin/fixuid \
+ && mkdir -p /etc/fixuid \
+ && printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
+
+COPY ci/release-image/entrypoint-catatonit.sh /usr/bin/entrypoint-catatonit.sh
+RUN --mount=from=packages,src=/tmp,dst=/tmp/packages rpm -i /tmp/packages/code-server*$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g').rpm
+
+# Allow users to have scripts run on container startup to prepare workspace.
+# https://github.com/coder/code-server/issues/5177
+ENV ENTRYPOINTD=${HOME}/entrypoint.d
+
+EXPOSE 8080
+# This way, if someone sets $DOCKER_USER, docker-exec will still work as
+# the uid will remain the same. note: only relevant if -u isn't passed to
+# docker-run.
+USER 1000
+ENV USER=coder
+WORKDIR /home/coder
+ENTRYPOINT ["/usr/bin/entrypoint-catatonit.sh", "--bind-addr", "0.0.0.0:8080", "."]
diff --git a/ci/release-image/build.sh b/ci/release-image/build.sh
deleted file mode 100755
index 5969e15ae9a6..000000000000
--- a/ci/release-image/build.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
- source ./ci/lib.sh
-
- docker build -t "codercom/code-server-$ARCH:$VERSION" -f ./ci/release-image/Dockerfile .
-}
-
-main "$@"
diff --git a/ci/release-image/docker-bake.hcl b/ci/release-image/docker-bake.hcl
new file mode 100644
index 000000000000..ecb0c313daed
--- /dev/null
+++ b/ci/release-image/docker-bake.hcl
@@ -0,0 +1,130 @@
+# Use this file from the top of the repo, with `-f ci/release-image/docker-bake.hcl`
+
+# Uses env var VERSION if set;
+# normally, this is set by ci/lib.sh
+variable "VERSION" {
+ default = "latest"
+}
+
+variable "DOCKER_REGISTRY" {
+ default = "docker.io/codercom/code-server"
+}
+
+variable "GITHUB_REGISTRY" {
+ default = "ghcr.io/coder/code-server"
+}
+
+group "default" {
+ targets = [
+ "code-server-debian-13",
+ "code-server-debian-12",
+ "code-server-ubuntu-focal",
+ "code-server-ubuntu-noble",
+ "code-server-ubuntu-resolute",
+ "code-server-fedora-39",
+ "code-server-opensuse-tumbleweed",
+ ]
+}
+
+function "prepend_hyphen_if_not_null" {
+ params = [tag]
+ result = notequal("","${tag}") ? "-${tag}" : "${tag}"
+}
+
+# use empty tag (tag="") to generate default tags
+function "gen_tags" {
+ params = [registry, tag]
+ result = notequal("","${registry}") ? [
+ notequal("", "${tag}") ? "${registry}:${tag}" : "${registry}:latest",
+ notequal("latest",VERSION) ? "${registry}:${VERSION}${prepend_hyphen_if_not_null(tag)}" : "",
+ ] : []
+}
+
+# helper function to generate tags for docker registry and github registry.
+# set (DOCKER|GITHUB)_REGISTRY="" to disable corresponding registry
+function "gen_tags_for_docker_and_ghcr" {
+ params = [tag]
+ result = concat(
+ gen_tags("${DOCKER_REGISTRY}", "${tag}"),
+ gen_tags("${GITHUB_REGISTRY}", "${tag}"),
+ )
+}
+
+target "code-server-debian-13" {
+ dockerfile = "ci/release-image/Dockerfile"
+ tags = concat(
+ gen_tags_for_docker_and_ghcr(""),
+ gen_tags_for_docker_and_ghcr("debian"),
+ gen_tags_for_docker_and_ghcr("trixie"),
+ )
+ platforms = ["linux/amd64", "linux/arm64"]
+}
+
+target "code-server-debian-12" {
+ dockerfile = "ci/release-image/Dockerfile"
+ tags = concat(
+ gen_tags_for_docker_and_ghcr("bookworm"),
+ )
+ args = {
+ BASE = "debian:12"
+ }
+ platforms = ["linux/amd64", "linux/arm64"]
+}
+
+target "code-server-ubuntu-focal" {
+ dockerfile = "ci/release-image/Dockerfile"
+ tags = concat(
+ gen_tags_for_docker_and_ghcr("focal"),
+ )
+ args = {
+ BASE = "ubuntu:focal"
+ }
+ platforms = ["linux/amd64", "linux/arm64"]
+}
+
+target "code-server-ubuntu-noble" {
+ dockerfile = "ci/release-image/Dockerfile"
+ tags = concat(
+ gen_tags_for_docker_and_ghcr("noble"),
+ gen_tags_for_docker_and_ghcr("ubuntu"),
+ )
+ args = {
+ BASE = "ubuntu:noble"
+ }
+ platforms = ["linux/amd64", "linux/arm64"]
+}
+
+target "code-server-ubuntu-resolute" {
+ dockerfile = "ci/release-image/Dockerfile"
+ tags = concat(
+ gen_tags_for_docker_and_ghcr("resolute"),
+ )
+ args = {
+ BASE = "ubuntu:resolute"
+ }
+ platforms = ["linux/amd64", "linux/arm64"]
+}
+
+target "code-server-fedora-39" {
+ dockerfile = "ci/release-image/Dockerfile.fedora"
+ tags = concat(
+ gen_tags_for_docker_and_ghcr("fedora"),
+ gen_tags_for_docker_and_ghcr("39"),
+ )
+ args = {
+ BASE = "fedora:39"
+ }
+ platforms = ["linux/amd64", "linux/arm64"]
+}
+
+target "code-server-opensuse-tumbleweed" {
+ dockerfile = "ci/release-image/Dockerfile.opensuse"
+ tags = concat(
+ gen_tags_for_docker_and_ghcr("opensuse"),
+ gen_tags_for_docker_and_ghcr("tumbleweed"),
+ )
+ args = {
+ BASE = "opensuse/tumbleweed"
+ }
+ platforms = ["linux/amd64", "linux/arm64"]
+}
diff --git a/ci/release-image/entrypoint-catatonit.sh b/ci/release-image/entrypoint-catatonit.sh
new file mode 100755
index 000000000000..d22acc6d237b
--- /dev/null
+++ b/ci/release-image/entrypoint-catatonit.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+set -eu
+
+# We do this first to ensure sudo works below when renaming the user.
+# Otherwise the current container UID may not exist in the passwd database.
+eval "$(fixuid -q)"
+
+if [ "${DOCKER_USER-}" ]; then
+ USER="$DOCKER_USER"
+ if [ "$DOCKER_USER" != "$(whoami)" ]; then
+ echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
+ # Unfortunately we cannot change $HOME as we cannot move any bind mounts
+ # nor can we bind mount $HOME into a new home as that requires a privileged container.
+ sudo usermod --login "$DOCKER_USER" coder
+ sudo groupmod -n "$DOCKER_USER" coder
+
+ sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
+ fi
+fi
+
+# Allow users to have scripts run on container startup to prepare workspace.
+# https://github.com/coder/code-server/issues/5177
+if [ -d "${ENTRYPOINTD}" ]; then
+ find "${ENTRYPOINTD}" -type f -executable -print -exec {} \;
+fi
+
+exec catatonit -- /usr/bin/code-server "$@"
diff --git a/ci/release-image/entrypoint.sh b/ci/release-image/entrypoint.sh
index 4f2f7cfe2391..efe2f39d9bd9 100755
--- a/ci/release-image/entrypoint.sh
+++ b/ci/release-image/entrypoint.sh
@@ -6,15 +6,22 @@ set -eu
eval "$(fixuid -q)"
if [ "${DOCKER_USER-}" ]; then
- echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
- # Unfortunately we cannot change $HOME as we cannot move any bind mounts
- # nor can we bind mount $HOME into a new home as that requires a privileged container.
- sudo usermod --login "$DOCKER_USER" coder
- sudo groupmod -n "$DOCKER_USER" coder
-
USER="$DOCKER_USER"
+ if [ -z "$(id -u "$DOCKER_USER" 2>/dev/null)" ]; then
+ echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
+ # Unfortunately we cannot change $HOME as we cannot move any bind mounts
+ # nor can we bind mount $HOME into a new home as that requires a privileged container.
+ sudo usermod --login "$DOCKER_USER" coder
+ sudo groupmod -n "$DOCKER_USER" coder
+
+ sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
+ fi
+fi
- sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
+# Allow users to have scripts run on container startup to prepare workspace.
+# https://github.com/coder/code-server/issues/5177
+if [ -d "${ENTRYPOINTD}" ]; then
+ find "${ENTRYPOINTD}" -type f -executable -print -exec {} \;
fi
-dumb-init /usr/bin/code-server "$@"
+exec dumb-init /usr/bin/code-server "$@"
diff --git a/ci/steps/build-docker-image.sh b/ci/steps/build-docker-image.sh
deleted file mode 100755
index 16653a0e9ed2..000000000000
--- a/ci/steps/build-docker-image.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
- source ./ci/lib.sh
-
- ./ci/release-image/build.sh
-
- mkdir -p release-images
- docker save "codercom/code-server-$ARCH:$VERSION" > "release-images/code-server-$ARCH-$VERSION.tar"
-}
-
-main "$@"
diff --git a/ci/steps/docker-buildx-push.sh b/ci/steps/docker-buildx-push.sh
new file mode 100755
index 000000000000..6314063ffa54
--- /dev/null
+++ b/ci/steps/docker-buildx-push.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+main() {
+ cd "$(dirname "$0")/../.."
+ # NOTE@jsjoeio - this script assumes VERSION exists as an
+ # environment variable.
+
+ # NOTE@jsjoeio - this script assumes that you've downloaded
+ # the release-packages artifact to ./release-packages before
+ # running this docker buildx step
+ docker buildx bake -f ci/release-image/docker-bake.hcl --push
+}
+
+main "$@"
diff --git a/ci/steps/fmt.sh b/ci/steps/fmt.sh
deleted file mode 100755
index 5e323596cd59..000000000000
--- a/ci/steps/fmt.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- yarn --frozen-lockfile
-
- git submodule update --init
- # We do not `yarn vscode` to make test.sh faster.
- # If the patch fails to apply, then it's likely already applied
- yarn vscode:patch &> /dev/null || true
-
- yarn fmt
-}
-
-main "$@"
diff --git a/ci/steps/lint.sh b/ci/steps/lint.sh
deleted file mode 100755
index b493e160652f..000000000000
--- a/ci/steps/lint.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- yarn --frozen-lockfile
-
- git submodule update --init
- # We do not `yarn vscode` to make test.sh faster.
- # If the patch fails to apply, then it's likely already applied
- yarn vscode:patch &> /dev/null || true
-
- yarn lint
-}
-
-main "$@"
diff --git a/ci/steps/publish-npm.sh b/ci/steps/publish-npm.sh
deleted file mode 100755
index 7bd497d001cd..000000000000
--- a/ci/steps/publish-npm.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
- source ./ci/lib.sh
-
- if [[ ${CI-} ]]; then
- echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
- fi
-
- download_artifact npm-package ./release-npm-package
- # https://github.com/actions/upload-artifact/issues/38
- tar -xzf release-npm-package/package.tar.gz
- yarn publish --non-interactive release
-}
-
-main "$@"
diff --git a/ci/steps/push-docker-manifest.sh b/ci/steps/push-docker-manifest.sh
deleted file mode 100755
index 08d0fdacf2d1..000000000000
--- a/ci/steps/push-docker-manifest.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
- source ./ci/lib.sh
-
- download_artifact release-images ./release-images
- if [[ ${CI-} ]]; then
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- fi
-
- for img in ./release-images/*; do
- docker load -i "$img"
- done
-
- # We have to ensure the amd64 and arm64 images exist on the remote registry
- # in order to build the manifest.
- # We don't put the arch in the tag to avoid polluting the main repository.
- # These other repositories are private so they don't pollute our organization namespace.
- docker push "codercom/code-server-amd64:$VERSION"
- docker push "codercom/code-server-arm64:$VERSION"
-
- export DOCKER_CLI_EXPERIMENTAL=enabled
-
- docker manifest create "codercom/code-server:$VERSION" \
- "codercom/code-server-amd64:$VERSION" \
- "codercom/code-server-arm64:$VERSION"
- docker manifest push --purge "codercom/code-server:$VERSION"
-
- docker manifest create "codercom/code-server:latest" \
- "codercom/code-server-amd64:$VERSION" \
- "codercom/code-server-arm64:$VERSION"
- docker manifest push --purge "codercom/code-server:latest"
-}
-
-main "$@"
diff --git a/ci/steps/release-packages.sh b/ci/steps/release-packages.sh
deleted file mode 100755
index ba8d61d5ce6f..000000000000
--- a/ci/steps/release-packages.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- NODE_VERSION=v12.18.4
- NODE_OS="$(uname | tr '[:upper:]' '[:lower:]')"
- NODE_ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')"
- curl -L "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-$NODE_OS-$NODE_ARCH.tar.gz" | tar -xz
- PATH="$PWD/node-$NODE_VERSION-$NODE_OS-$NODE_ARCH/bin:$PATH"
-
- # https://github.com/actions/upload-artifact/issues/38
- tar -xzf release-npm-package/package.tar.gz
-
- yarn release:standalone
- yarn test:standalone-release
- yarn package
-}
-
-main "$@"
diff --git a/ci/steps/release.sh b/ci/steps/release.sh
deleted file mode 100755
index 80083c67f37b..000000000000
--- a/ci/steps/release.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- yarn --frozen-lockfile
- yarn vscode
- yarn build
- yarn build:vscode
- yarn release
-
- # https://github.com/actions/upload-artifact/issues/38
- mkdir -p release-npm-package
- tar -czf release-npm-package/package.tar.gz release
-}
-
-main "$@"
diff --git a/ci/steps/steps-lib.sh b/ci/steps/steps-lib.sh
new file mode 100755
index 000000000000..e71378e27f6c
--- /dev/null
+++ b/ci/steps/steps-lib.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+
+# This is a library which contains functions used inside ci/steps
+#
+# We separated it into it's own file so that we could easily unit test
+# these functions and helpers
+
+# Checks whether and environment variable is set.
+# Source: https://stackoverflow.com/a/62210688/3015595
+is_env_var_set() {
+ local name="${1:-}"
+ if test -n "${!name:-}"; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# Checks whether a directory exists.
+directory_exists() {
+ local dir="${1:-}"
+ if [[ -d "${dir:-}" ]]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# Checks whether a file exists.
+file_exists() {
+ local file="${1:-}"
+ if test -f "${file:-}"; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# Checks whether a file is executable.
+is_executable() {
+ local file="${1:-}"
+ if [ -f "${file}" ] && [ -r "${file}" ] && [ -x "${file}" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
diff --git a/ci/steps/test.sh b/ci/steps/test.sh
deleted file mode 100755
index 801b2adc83cd..000000000000
--- a/ci/steps/test.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-main() {
- cd "$(dirname "$0")/../.."
-
- yarn --frozen-lockfile
-
- git submodule update --init
- # We do not `yarn vscode` to make test.sh faster.
- # If the patch fails to apply, then it's likely already applied
- yarn vscode:patch &> /dev/null || true
-
- yarn test
-}
-
-main "$@"
diff --git a/doc/CONTRIBUTING.md b/doc/CONTRIBUTING.md
deleted file mode 100644
index 52b4153a5148..000000000000
--- a/doc/CONTRIBUTING.md
+++ /dev/null
@@ -1,162 +0,0 @@
-
-
-# Contributing
-
-- [Pull Requests](#pull-requests)
-- [Requirements](#requirements)
-- [Development Workflow](#development-workflow)
-- [Build](#build)
-- [Structure](#structure)
- - [VS Code Patch](#vs-code-patch)
- - [Currently Known Issues](#currently-known-issues)
-
-
-
-- [Detailed CI and build process docs](../ci)
-
-## Pull Requests
-
-Please create a [GitHub Issue](https://github.com/cdr/code-server/issues) for each issue
-you'd like to address unless the proposed fix is minor.
-
-In your Pull Requests (PR), link to the issue that the PR solves.
-
-Please ensure that the base of your PR is the **master** branch. (Note: The default
-GitHub branch is the latest release branch, though you should point all of your changes to be merged into
-master).
-
-## Requirements
-
-The prerequisites for contributing to code-server are almost the same as those for
-[VS Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
-There are several differences, however. You must:
-
-- Use Node.js version 12.x (or greater)
-- Have [nfpm](https://github.com/goreleaser/nfpm) (which is used to build `.deb` and `.rpm` packages and [jq](https://stedolan.github.io/jq/) (used to build code-server releases) installed
-
-The [CI container](../ci/images/debian8/Dockerfile) is a useful reference for all
-of the dependencies code-server uses.
-
-## Development Workflow
-
-```shell
-yarn
-yarn vscode
-yarn watch
-# Visit http://localhost:8080 once the build is completed.
-```
-
-To develop inside an isolated Docker container:
-
-```shell
-./ci/dev/image/run.sh yarn
-./ci/dev/image/run.sh yarn vscode
-./ci/dev/image/run.sh yarn watch
-```
-
-`yarn watch` will live reload changes to the source.
-
-If you introduce changes to the patch and you've previously built, you
-must (1) manually reset VS Code and (2) run `yarn vscode:patch`.
-
-## Build
-
-You can build using:
-
-```shell
-./ci/dev/image/run.sh ./ci/steps/release.sh
-```
-
-Run your build with:
-
-```shell
-cd release
-yarn --production
-# Runs the built JavaScript with Node.
-node .
-```
-
-Build the release packages (make sure that you run `./ci/steps/release.sh` first):
-
-```shell
-IMAGE=centos7 ./ci/dev/image/run.sh ./ci/steps/release-packages.sh
-# The standalone release is in ./release-standalone
-# .deb, .rpm and the standalone archive are in ./release-packages
-```
-
-The `release.sh` script is equal to running:
-
-```shell
-yarn
-yarn vscode
-yarn build
-yarn build:vscode
-yarn release
-```
-
-And `release-packages.sh` is equal to:
-
-```shell
-yarn release:standalone
-yarn test:standalone-release
-yarn package
-```
-
-For a faster release build, you can run instead:
-
-```shell
-KEEP_MODULES=1 ./ci/steps/release.sh
-node ./release
-```
-
-## Structure
-
-The `code-server` script serves an HTTP API for login and starting a remote VS Code process.
-
-The CLI code is in [./src/node](./src/node) and the HTTP routes are implemented in
-[./src/node/app](./src/node/app).
-
-Most of the meaty parts are in the VS Code patch, which we described next.
-
-### VS Code Patch
-
-In v1 of code-server, we had a patch of VS Code that split the codebase into a front-end
-and a server. The front-end consisted of all UI code, while the server ran the extensions
-and exposed an API to the front-end for file access and all UI needs.
-
-Over time, Microsoft added support to VS Code to run it on the web. They have made
-the front-end open source, but not the server. As such, code-server v2 (and later) uses
-the VS Code front-end and implements the server. You can find this in
-[./ci/dev/vscode.patch](../ci/dev/vscode.patch) under the path `src/vs/server`.
-
-Other notable changes in our patch include:
-
-- Adding our build file, which includes our code and VS Code's web code
-- Allowing multiple extension directories (both user and built-in)
-- Modifying the loader, websocket, webview, service worker, and asset requests to
- use the URL of the page as a base (and TLS, if necessary for the websocket)
-- Sending client-side telemetry through the server
-- Allowing modification of the display language
-- Making it possible for us to load code on the client
-- Making extensions work in the browser
-- Making it possible to install extensions of any kind
-- Fixing issue with getting disconnected when your machine sleeps or hibernates
-- Adding connection type to web socket query parameters
-
-As the web portion of VS Code matures, we'll be able to shrink and possibly
-eliminate our patch. In the meantime, upgrading the VS Code version requires
-us to ensure that the patch is applied and works as intended. In the future,
-we'd like to run VS Code unit tests against our builds to ensure that features
-work as expected.
-
-To generate a new patch, run `yarn vscode:diff`
-
-**Note**: We have [extension docs](../ci/README.md) on the CI and build system.
-
-If the functionality you're working on does NOT depend on code from VS Code, please
-move it out and into code-server.
-
-### Currently Known Issues
-
-- Creating custom VS Code extensions and debugging them doesn't work
-- Extension profiling and tips are currently disabled
diff --git a/doc/FAQ.md b/doc/FAQ.md
deleted file mode 100644
index 1a6a217d676c..000000000000
--- a/doc/FAQ.md
+++ /dev/null
@@ -1,322 +0,0 @@
-
-
-# FAQ
-
-- [Questions?](#questions)
-- [iPad Status?](#ipad-status)
-- [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration)
-- [Differences compared to VS Code?](#differences-compared-to-vs-code)
-- [How can I request a missing extension?](#how-can-i-request-a-missing-extension)
-- [How do I configure the marketplace URL?](#how-do-i-configure-the-marketplace-url)
-- [Where are extensions stored?](#where-are-extensions-stored)
-- [How is this different from VS Code Codespaces?](#how-is-this-different-from-vs-code-codespaces)
-- [How should I expose code-server to the internet?](#how-should-i-expose-code-server-to-the-internet)
-- [How do I securely access web services?](#how-do-i-securely-access-web-services)
- - [Sub-paths](#sub-paths)
- - [Sub-domains](#sub-domains)
-- [Multi-tenancy](#multi-tenancy)
-- [Docker in code-server container?](#docker-in-code-server-container)
-- [How can I disable telemetry?](#how-can-i-disable-telemetry)
-- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open)
-- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server)
-- [Heartbeat File](#heartbeat-file)
-- [Healthz endpoint](#healthz-endpoint)
-- [How does the config file work?](#how-does-the-config-file-work)
-- [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure)
-- [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work)
-- [Differences compared to Theia?](#differences-compared-to-theia)
-- [Enterprise](#enterprise)
-
-
-
-## Questions?
-
-Please file all questions and support requests at https://github.com/cdr/code-server/discussions.
-
-## iPad Status?
-
-Please see [./ipad.md](./ipad.md).
-
-## How can I reuse my VS Code configuration?
-
-The very popular [Settings Sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync) extension works.
-
-You can also pass `--user-data-dir ~/.vscode` to reuse your existing VS Code extensions and configuration.
-
-Or copy `~/.vscode` into `~/.local/share/code-server`.
-
-## Differences compared to VS Code?
-
-`code-server` takes the open source core of VS Code and allows you to run it in the browser.
-However, it is not entirely equivalent to Microsoft's VS Code.
-
-While the core of VS Code is open source, the marketplace and many published Microsoft extensions are not.
-
-Furthermore, Microsoft prohibits the use of any non-Microsoft VS Code from accessing their marketplace.
-
-See the [TOS](https://cdn.vsassets.io/v/M146_20190123.39/_content/Microsoft-Visual-Studio-Marketplace-Terms-of-Use.pdf).
-
-> Marketplace Offerings are intended for use only with Visual Studio Products and Services
-> and you may only install and use Marketplace Offerings with Visual Studio Products and Services.
-
-As a result, we cannot offer any extensions on the Microsoft marketplace. Instead,
-we have created our own marketplace for open source extensions.
-It works by scraping GitHub for VS Code extensions and building them. It's not perfect but getting
-better by the day with more and more extensions.
-
-These are the closed source extensions presently unavailable:
-
-1. [Live Share](https://visualstudio.microsoft.com/services/live-share)
- - We may implement something similar, see [#33](https://github.com/cdr/code-server/issues/33)
-1. [Remote Extensions (SSH, Containers, WSL)](https://github.com/microsoft/vscode-remote-release)
- - We may reimplement these at some point, see [#1315](https://github.com/cdr/code-server/issues/1315)
-
-For more about the closed source parts of VS Code, see [vscodium/vscodium](https://github.com/VSCodium/vscodium#why-does-this-exist).
-
-## How can I request a missing extension?
-
-Please open a new issue and select the `Extension request` template.
-
-If an extension is not available or does not work, you can grab its VSIX from its Github releases or
-build it yourself. Then run the `Extensions: Install from VSIX` command in the Command Palette and
-point to the .vsix file.
-
-See below for installing an extension from the cli.
-
-## How do I configure the marketplace URL?
-
-If you have your own marketplace that implements the VS Code Extension Gallery API, it is possible to
-point code-server to it by setting `$SERVICE_URL` and `$ITEM_URL`. These correspond directly
-to `serviceUrl` and `itemUrl` in VS Code's `product.json`.
-
-e.g. to use [open-vsx.org](https://open-vsx.org):
-
-```bash
-export SERVICE_URL=https://open-vsx.org/vscode/gallery
-export ITEM_URL=https://open-vsx.org/vscode/item
-```
-
-While you can technically use Microsoft's marketplace with these, please do not do so as it
-is against their terms of use. See [above](#differences-compared-to-vs-code) and this
-discussion regarding the use of the Microsoft URLs in forks:
-
-https://github.com/microsoft/vscode/issues/31168#issue-244533026
-
-These variables are most valuable to our enterprise customers for whom we have a self hosted marketplace product.
-
-## Where are extensions stored?
-
-Defaults to `~/.local/share/code-server/extensions`.
-
-If the `XDG_DATA_HOME` environment variable is set the data directory will be
-`$XDG_DATA_HOME/code-server/extensions`. In general we try to follow the XDG directory spec.
-
-You can install an extension on the CLI with:
-
-```bash
-# From the Coder extension marketplace
-code-server --install-extension ms-python.python
-
-# From a downloaded VSIX on the file system
-code-server --install-extension downloaded-ms-python.python.vsix
-```
-
-## How is this different from VS Code Codespaces?
-
-VS Code Codespaces is a closed source and paid service by Microsoft. It also allows you to access
-VS Code via the browser.
-
-However, code-server is free, open source and can be run on any machine without any limitations.
-
-While you can self host environments with VS Code Codespaces, you still need an Azure billing
-account and you have to access VS Code via the Codespaces web dashboard instead of directly
-connecting to your instance.
-
-## How should I expose code-server to the internet?
-
-Please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server.
-
-code-server only supports password authentication natively.
-
-**note**: code-server will rate limit password authentication attempts at 2 a minute and 12 an hour.
-
-If you want to use external authentication (i.e sign in with Google) you should handle this
-with a reverse proxy using something like [oauth2_proxy](https://github.com/pusher/oauth2_proxy)
-or [Cloudflare Access](https://teams.cloudflare.com/access).
-
-For HTTPS, you can use a self signed certificate by passing in just `--cert` or
-pass in an existing certificate by providing the path to `--cert` and the path to
-the key with `--cert-key`.
-
-The self signed certificate will be generated into
-`~/.local/share/code-server/self-signed.crt`.
-
-If `code-server` has been passed a certificate it will also respond to HTTPS
-requests and will redirect all HTTP requests to HTTPS.
-
-You can use [Let's Encrypt](https://letsencrypt.org/) to get a TLS certificate
-for free.
-
-Again, please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server.
-
-## How do I securely access web services?
-
-code-server is capable of proxying to any port using either a subdomain or a
-subpath which means you can securely access these services using code-server's
-built-in authentication.
-
-### Sub-paths
-
-Just browse to `/proxy//`.
-
-### Sub-domains
-
-You will need a DNS entry that points to your server for each port you want to
-access. You can either set up a wildcard DNS entry for `*.` if your domain
-name registrar supports it or you can create one for every port you want to
-access (`3000.`, `8080.`, etc).
-
-You should also set up TLS certificates for these subdomains, either using a
-wildcard certificate for `*.` or individual certificates for each port.
-
-Start code-server with the `--proxy-domain` flag set to your domain.
-
-```
-code-server --proxy-domain
-```
-
-Now you can browse to `.`. Note that this uses the host header so
-ensure your reverse proxy forwards that information if you are using one.
-
-## Multi-tenancy
-
-If you want to run multiple code-servers on shared infrastructure, we recommend using virtual
-machines with a VM per user. This will easily allow users to run a docker daemon. If you want
-to use kubernetes, you'll definitely want to use [kubevirt](https://kubevirt.io) to give each
-user a virtual machine instead of just a container.
-
-## Docker in code-server container?
-
-If you'd like to access docker inside of code-server, mount the docker socket in from `/var/run/docker.sock`.
-Install the docker CLI in the code-server container and you should be able to access the daemon!
-
-You can even make volume mounts work. Lets say you want to run a container and mount in
-`/home/coder/myproject` into it from inside the `code-server` container. You need to make sure
-the docker daemon's `/home/coder/myproject` is the same as the one mounted inside the `code-server`
-container and the mount will just work.
-
-## How can I disable telemetry?
-
-Use the `--disable-telemetry` flag to completely disable telemetry. We use the
-data collected only to improve code-server.
-
-## How does code-server decide what workspace or folder to open?
-
-code-server tries the following in order:
-
-1. The `workspace` query parameter.
-2. The `folder` query parameter.
-3. The workspace or directory passed on the command line.
-4. The last opened workspace or directory.
-
-## How do I debug issues with code-server?
-
-First run code-server with at least `debug` logging (or `trace` to be really
-thorough) by setting the `--log` flag or the `LOG_LEVEL` environment variable.
-`-vvv` and `--verbose` are aliases for `--log trace`.
-
-```
-code-server --log debug
-```
-
-Once this is done, replicate the issue you're having then collect logging
-information from the following places:
-
-1. stdout
-2. The most recently created directory in the `~/.local/share/code-server/logs` directory.
-3. The browser console and network tabs.
-
-Additionally, collecting core dumps (you may need to enable them first) if
-code-server crashes can be helpful.
-
-## Heartbeat File
-
-`code-server` touches `~/.local/share/code-server/heartbeat` once a minute as long
-as there is an active browser connection.
-
-If you want to shutdown `code-server` if there hasn't been an active connection in X minutes
-you can do so by continuously checking the last modified time on the heartbeat file and if it is
-older than X minutes, kill `code-server`.
-
-[#1636](https://github.com/cdr/code-server/issues/1636) will make the experience here better.
-
-## Healthz endpoint
-
-`code-server` exposes an endpoint at `/healthz` which can be used to check
-whether `code-server` is up without triggering a heartbeat. The response will
-include a status (`alive` or `expired`) and a timestamp for the last heartbeat
-(defaults to `0`). This endpoint does not require authentication.
-
-```json
-{
- "status": "alive",
- "lastHeartbeat": 1599166210566
-}
-```
-
-## How does the config file work?
-
-When `code-server` starts up, it creates a default config file in `~/.config/code-server/config.yaml` that looks
-like this:
-
-```yaml
-bind-addr: 127.0.0.1:8080
-auth: password
-password: mewkmdasosafuio3422 # This is randomly generated for each config.yaml
-cert: false
-```
-
-Each key in the file maps directly to a `code-server` flag. Run `code-server --help` to see
-a listing of all the flags.
-
-The default config here says to listen on the loopback IP port 8080, enable password authorization
-and no TLS. Any flags passed to `code-server` will take priority over the config file.
-
-The `--config` flag or `$CODE_SERVER_CONFIG` can be used to change the config file's location.
-
-The default location also respects `$XDG_CONFIG_HOME`.
-
-## Isn't an install script piped into sh insecure?
-
-Please give
-[this wonderful blogpost](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install) by
-[sandstorm.io](https://sandstorm.io) a read.
-
-## How do I make my keyboard shortcuts work?
-
-Many shortcuts will not work by default as they'll be caught by the browser.
-
-If you use Chrome you can get around this by installing the PWA.
-
-Once you've entered the editor, click the "plus" icon present in the URL toolbar area.
-This will install a Chrome PWA and now all keybindings will work!
-
-For other browsers you'll have to remap keybindings unfortunately.
-
-## Differences compared to Theia?
-
-[Theia](https://github.com/eclipse-theia/theia) is a browser IDE loosely based on VS Code. It uses the same
-text editor library named [Monaco](https://github.com/Microsoft/monaco-editor) and the same
-extension API but everything else is very different. It also uses [open-vsx.org](https://open-vsx.org)
-for extensions which has an order of magnitude less extensions than our marketplace.
-See [#1473](https://github.com/cdr/code-server/issues/1473).
-
-You can't just use your VS Code config in Theia like you can with code-server.
-
-To summarize, code-server is a patched fork of VS Code to run in the browser whereas
-Theia takes some parts of VS Code but is an entirely different editor.
-
-## Enterprise
-
-Visit [our enterprise page](https://coder.com) for more information about our
-enterprise offerings.
diff --git a/doc/assets/screenshot.png b/doc/assets/screenshot.png
deleted file mode 100644
index 7f76a21e4413..000000000000
Binary files a/doc/assets/screenshot.png and /dev/null differ
diff --git a/doc/guide.md b/doc/guide.md
deleted file mode 100644
index ce17a36144a7..000000000000
--- a/doc/guide.md
+++ /dev/null
@@ -1,304 +0,0 @@
-
-
-# Setup Guide
-
-- [1. Acquire a remote machine](#1-acquire-a-remote-machine)
- - [Requirements](#requirements)
- - [Google Cloud](#google-cloud)
-- [2. Install code-server](#2-install-code-server)
-- [3. Expose code-server](#3-expose-code-server)
- - [SSH forwarding](#ssh-forwarding)
- - [Let's Encrypt](#lets-encrypt)
- - [NGINX](#nginx)
- - [Self Signed Certificate](#self-signed-certificate)
- - [Change the password?](#change-the-password)
- - [How do I securely access development web services?](#how-do-i-securely-access-development-web-services)
-
-
-
-This guide demonstrates how to setup and use `code-server`.
-To reiterate, `code-server` lets you run VS Code on a remote server and then access it via a browser.
-
-Further docs are at:
-
-- [README](../README.md) for a general overview
-- [INSTALL](../doc/install.md) for installation
-- [FAQ](./FAQ.md) for common questions.
-- [CONTRIBUTING](../doc/CONTRIBUTING.md) for development docs
-
-We highly recommend reading the [FAQ](./FAQ.md) on the [Differences compared to VS Code](./FAQ.md#differences-compared-to-vs-code) before beginning.
-
-We'll walk you through acquiring a remote machine to run `code-server` on
-and then exposing `code-server` so you can securely access it.
-
-## 1. Acquire a remote machine
-
-First, you need a machine to run `code-server` on. You can use a physical
-machine you have lying around or use a VM on GCP/AWS.
-
-### Requirements
-
-For a good experience, we recommend at least:
-
-- 1 GB of RAM
-- 2 cores
-
-You can use whatever linux distribution floats your boat but in this guide we assume Debian on Google Cloud.
-
-### Google Cloud
-
-For demonstration purposes, this guide assumes you're using a VM on GCP but you should be
-able to easily use any machine or VM provider.
-
-You can sign up at https://console.cloud.google.com/getting-started. You'll get a 12 month \$300
-free trial.
-
-Once you've signed up and created a GCP project, create a new Compute Engine VM Instance.
-
-1. Navigate to `Compute Engine -> VM Instances` on the sidebar.
-2. Now click `Create Instance` to create a new instance.
-3. Name it whatever you want.
-4. Choose the region closest to you based on [gcping.com](http://www.gcping.com).
-5. Any zone is fine.
-6. We'd recommend a `E2` series instance from the General-purpose family.
- - Change the type to custom and set at least 2 cores and 2 GB of ram.
- - Add more vCPUs and memory as you prefer, you can edit after creating the instance as well.
- - https://cloud.google.com/compute/docs/machine-types#general_purpose
-7. We highly recommend switching the persistent disk to an SSD of at least 32 GB.
- - Click `Change` under `Boot Disk` and change the type to `SSD Persistent Disk` and the size
- to `32`.
- - You can always grow your disk later.
-8. Navigate to `Networking -> Network interfaces` and edit the existing interface
- to use a static external IP.
- - Click done to save network interface changes.
-9. If you do not have a [project wide SSH key](https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#project-wide), navigate to `Security -> SSH Keys` and add your public key there.
-10. Click create!
-
-Remember, you can shutdown your server when not in use to lower costs.
-
-We highly recommend learning to use the [`gcloud`](https://cloud.google.com/sdk/gcloud) cli
-to avoid the slow dashboard.
-
-## 2. Install code-server
-
-We have a [script](../install.sh) to install `code-server` for Linux, macOS and FreeBSD.
-
-It tries to use the system package manager if possible.
-
-First run to print out the install process:
-
-```bash
-curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
-```
-
-Now to actually install:
-
-```bash
-curl -fsSL https://code-server.dev/install.sh | sh
-```
-
-The install script will print out how to run and start using `code-server`.
-
-Docs on the install script, manual installation and docker image are at [./install.md](./install.md).
-
-## 3. Expose code-server
-
-**Never**, **ever** expose `code-server` directly to the internet without some form of authentication
-and encryption as someone can completely takeover your machine with the terminal.
-
-By default, `code-server` will enable password authentication which will require you to copy the
-password from the`code-server`config file to login. It will listen on`localhost` to avoid exposing
-itself to the world. This is fine for testing but will not work if you want to access `code-server`
-from a different machine.
-
-There are several approaches to securely operating and exposing `code-server`.
-
-**tip**: You can list the full set of `code-server` options with `code-server --help`
-
-### SSH forwarding
-
-We highly recommend this approach for not requiring any additional setup, you just need an
-SSH server on your remote machine. The downside is you won't be able to access `code-server`
-on any machine without an SSH client like on iPad. If that's important to you, skip to [Let's Encrypt](#lets-encrypt).
-
-First, ssh into your instance and edit your `code-server` config file to disable password authentication.
-
-```bash
-# Replaces "auth: password" with "auth: none" in the code-server config.
-sed -i.bak 's/auth: password/auth: none/' ~/.config/code-server/config.yaml
-```
-
-Restart `code-server` with (assuming you followed the guide):
-
-```bash
-sudo systemctl restart code-server@$USER
-```
-
-Now forward local port 8080 to `127.0.0.1:8080` on the remote instance by running the following command on your local machine.
-
-Recommended reading: https://help.ubuntu.com/community/SSH/OpenSSH/PortForwarding.
-
-```bash
-# -N disables executing a remote shell
-ssh -N -L 8080:127.0.0.1:8080 [user]@
-```
-
-Now if you access http://127.0.0.1:8080 locally, you should see `code-server`!
-
-If you want to make the SSH port forwarding persistent we recommend using
-[mutagen](https://mutagen.io/documentation/introduction/installation).
-
-```
-# Same as the above SSH command but runs in the background continuously.
-# Add `mutagen daemon start` to your ~/.bashrc to start the mutagen daemon when you open a shell.
-mutagen forward create --name=code-server tcp:127.0.0.1:8080 :tcp:127.0.0.1:8080
-```
-
-We also recommend adding the following lines to your `~/.ssh/config` to quickly detect bricked SSH connections:
-
-```bash
-Host *
-ServerAliveInterval 5
-ExitOnForwardFailure yes
-```
-
-You can also forward your SSH and GPG agent to the instance to securely access GitHub
-and sign commits without copying your keys.
-
-1. https://developer.github.com/v3/guides/using-ssh-agent-forwarding/
-2. https://wiki.gnupg.org/AgentForwarding
-
-### Let's Encrypt
-
-[Let's Encrypt](https://letsencrypt.org) is a great option if you want to access `code-server` on an iPad
-or do not want to use SSH forwarding. This does require that the remote machine be exposed to the internet.
-
-Assuming you have been following the guide, edit your instance and checkmark the allow HTTP/HTTPS traffic options.
-
-1. You'll need to buy a domain name. We recommend [Google Domains](https://domains.google.com).
-2. Add an A record to your domain with your instance's IP.
-3. Install caddy https://caddyserver.com/docs/download#debian-ubuntu-raspbian.
-
-```bash
-echo "deb [trusted=yes] https://apt.fury.io/caddy/ /" \
- | sudo tee -a /etc/apt/sources.list.d/caddy-fury.list
-sudo apt update
-sudo apt install caddy
-```
-
-4. Replace `/etc/caddy/Caddyfile` with sudo to look like this:
-
-```
-mydomain.com
-
-reverse_proxy 127.0.0.1:8080
-```
-
-Remember to replace `mydomain.com` with your domain name!
-
-5. Reload caddy with:
-
-```bash
-sudo systemctl reload caddy
-```
-
-Visit `https://` to access `code-server`. Congratulations!
-
-In a future release we plan to integrate Let's Encrypt directly with `code-server` to avoid
-the dependency on caddy.
-
-#### NGINX
-
-If you prefer to use NGINX instead of Caddy then please follow steps 1-2 above and then:
-
-3. Install `nginx`:
-
-```bash
-sudo apt update
-sudo apt install -y nginx certbot python-certbot-nginx
-```
-
-4. Put the following config into `/etc/nginx/sites-available/code-server` with sudo:
-
-```nginx
-server {
- listen 80;
- listen [::]:80;
- server_name mydomain.com;
-
- location / {
- proxy_pass http://localhost:8080/;
- proxy_set_header Host $host;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection upgrade;
- proxy_set_header Accept-Encoding gzip;
- }
-}
-```
-
-Remember to replace `mydomain.com` with your domain name!
-
-5. Enable the config:
-
-```bash
-sudo ln -s ../sites-available/code-server /etc/nginx/sites-enabled/code-server
-sudo certbot --non-interactive --redirect --agree-tos --nginx -d mydomain.com -m me@example.com
-```
-
-Make sure to substitute `me@example.com` with your actual email.
-
-Visit `https://` to access `code-server`. Congratulations!
-
-### Self Signed Certificate
-
-**note:** Self signed certificates do not work with iPad normally. See [./ipad.md](./ipad.md) for details.
-
-Recommended reading: https://security.stackexchange.com/a/8112.
-
-We recommend this as a last resort because self signed certificates do not work with iPads and can
-cause other bizarre issues. Not to mention all the warnings when you access `code-server`.
-Only use this if:
-
-1. You do not want to buy a domain or you cannot expose the remote machine to the internet.
-2. You do not want to use SSH forwarding.
-
-ssh into your instance and edit your code-server config file to use a randomly generated self signed certificate:
-
-```bash
-# Replaces "cert: false" with "cert: true" in the code-server config.
-sed -i.bak 's/cert: false/cert: true/' ~/.config/code-server/config.yaml
-# Replaces "bind-addr: 127.0.0.1:8080" with "bind-addr: 0.0.0.0:443" in the code-server config.
-sed -i.bak 's/bind-addr: 127.0.0.1:8080/bind-addr: 0.0.0.0:443/' ~/.config/code-server/config.yaml
-# Allows code-server to listen on port 443.
-sudo setcap cap_net_bind_service=+ep /usr/lib/code-server/lib/node
-```
-
-Assuming you have been following the guide, restart `code-server` with:
-
-```bash
-sudo systemctl restart code-server@$USER
-```
-
-Edit your instance and checkmark the allow HTTPS traffic option.
-
-Visit `https://` to access `code-server`.
-You'll get a warning when accessing but if you click through you should be good.
-
-To avoid the warnings, you can use [mkcert](https://mkcert.dev) to create a self signed certificate
-trusted by your OS and then pass it into `code-server` via the `cert` and `cert-key` config
-fields.
-
-### Change the password?
-
-Edit the `password` field in the `code-server` config file at `~/.config/code-server/config.yaml`
-and then restart `code-server` with:
-
-```bash
-sudo systemctl restart code-server@$USER
-```
-
-### How do I securely access development web services?
-
-If you're working on a web service and want to access it locally, `code-server` can proxy it for you.
-
-See the [FAQ](./FAQ.md#how-do-i-securely-access-web-services).
diff --git a/doc/install.md b/doc/install.md
deleted file mode 100644
index 7515db45aafb..000000000000
--- a/doc/install.md
+++ /dev/null
@@ -1,199 +0,0 @@
-
-
-# Install
-
-- [install.sh](#installsh)
- - [Flags](#flags)
- - [Detection Reference](#detection-reference)
-- [Debian, Ubuntu](#debian-ubuntu)
-- [Fedora, CentOS, RHEL, SUSE](#fedora-centos-rhel-suse)
-- [Arch Linux](#arch-linux)
-- [yarn, npm](#yarn-npm)
-- [macOS](#macos)
-- [Standalone Releases](#standalone-releases)
-- [Docker](#docker)
-- [helm](#helm)
-
-
-
-This document demonstrates how to install `code-server` on
-various distros and operating systems.
-
-## install.sh
-
-We have a [script](../install.sh) to install code-server for Linux, macOS and FreeBSD.
-
-It tries to use the system package manager if possible.
-
-First run to print out the install process:
-
-```bash
-curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
-```
-
-Now to actually install:
-
-```bash
-curl -fsSL https://code-server.dev/install.sh | sh
-```
-
-The script will print out how to run and start using code-server.
-
-If you believe an install script used with `curl | sh` is insecure, please give
-[this wonderful blogpost](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install) by
-[sandstorm.io](https://sandstorm.io) a read.
-
-If you'd still prefer manual installation despite the below [detection reference](#detection-reference) and `--dry-run`
-then continue on for docs on manual installation. The [`install.sh`](../install.sh) script runs the _exact_ same
-commands presented in the rest of this document.
-
-### Flags
-
-- `--dry-run` to echo the commands for the install process without running them.
-- `--method` to choose the installation method.
- - `--method=detect` to detect the package manager but fallback to `--method=standalone`.
- - `--method=standalone` to install a standalone release archive into `~/.local`.
-- `--prefix=/usr/local` to install a standalone release archive system wide.
-- `--version=X.X.X` to install version `X.X.X` instead of latest.
-- `--help` to see full usage docs.
-
-### Detection Reference
-
-- For Debian, Ubuntu and Raspbian it will install the latest deb package.
-- For Fedora, CentOS, RHEL and openSUSE it will install the latest rpm package.
-- For Arch Linux it will install the AUR package.
-- For any unrecognized Linux operating system it will install the latest standalone release into `~/.local`.
-
- - Add `~/.local/bin` to your `$PATH` to run code-server.
-
-- For macOS it will install the Homebrew package.
-
- - If Homebrew is not installed it will install the latest standalone release into `~/.local`.
- - Add `~/.local/bin` to your `$PATH` to run code-server.
-
-- For FreeBSD, it will install the [npm package](#yarn-npm) with `yarn` or `npm`.
-
-- If ran on an architecture with no releases, it will install the [npm package](#yarn-npm) with `yarn` or `npm`.
- - We only have releases for amd64 and arm64 presently.
- - The [npm package](#yarn-npm) builds the native modules on postinstall.
-
-## Debian, Ubuntu
-
-```bash
-curl -fOL https://github.com/cdr/code-server/releases/download/v3.7.2/code-server_3.7.2_amd64.deb
-sudo dpkg -i code-server_3.7.2_amd64.deb
-sudo systemctl enable --now code-server@$USER
-# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
-```
-
-## Fedora, CentOS, RHEL, SUSE
-
-```bash
-curl -fOL https://github.com/cdr/code-server/releases/download/v3.7.2/code-server-3.7.2-amd64.rpm
-sudo rpm -i code-server-3.7.2-amd64.rpm
-sudo systemctl enable --now code-server@$USER
-# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
-```
-
-## Arch Linux
-
-```bash
-# Installs code-server from the AUR using yay.
-yay -S code-server
-sudo systemctl enable --now code-server@$USER
-# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
-```
-
-```bash
-# Installs code-server from the AUR with plain makepkg.
-git clone https://aur.archlinux.org/code-server.git
-cd code-server
-makepkg -si
-sudo systemctl enable --now code-server@$USER
-# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
-```
-
-## yarn, npm
-
-We recommend installing with `yarn` or `npm` when:
-
-1. You aren't on `amd64` or `arm64`.
-2. If you're on Linux with glibc < v2.17 or glibcxx < v3.4.18
-
-**note:** Installing via `yarn` or `npm` builds native modules on install and so requires C dependencies.
-See [./npm.md](./npm.md) for installing these dependencies.
-
-You will need at least node v12 installed. See [#1633](https://github.com/cdr/code-server/issues/1633).
-
-```bash
-yarn global add code-server
-# Or: npm install -g code-server
-code-server
-# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
-```
-
-## macOS
-
-```bash
-brew install code-server
-brew services start code-server
-# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
-```
-
-## Standalone Releases
-
-We publish self contained `.tar.gz` archives for every release on [github](https://github.com/cdr/code-server/releases).
-They bundle the node binary and `node_modules`.
-
-These are created from the [npm package](#yarn-npm) and the rest of the releases are created from these.
-Only requirement is glibc >= 2.17 && glibcxx >= v3.4.18 on Linux and for macOS there is no minimum system requirement.
-
-1. Download the latest release archive for your system from [github](https://github.com/cdr/code-server/releases).
-2. Unpack the release.
-3. You can run code-server by executing `./bin/code-server`.
-
-You can add the code-server `bin` directory to your `$PATH` to easily execute `code-server`
-without the full path every time.
-
-Here is an example script for installing and using a standalone `code-server` release on Linux:
-
-```bash
-mkdir -p ~/.local/lib ~/.local/bin
-curl -fL https://github.com/cdr/code-server/releases/download/v3.7.2/code-server-3.7.2-linux-amd64.tar.gz \
- | tar -C ~/.local/lib -xz
-mv ~/.local/lib/code-server-3.7.2-linux-amd64 ~/.local/lib/code-server-3.7.2
-ln -s ~/.local/lib/code-server-3.7.2/bin/code-server ~/.local/bin/code-server
-PATH="~/.local/bin:$PATH"
-code-server
-# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
-```
-
-## Docker
-
-```bash
-# This will start a code-server container and expose it at http://127.0.0.1:8080.
-# It will also mount your current directory into the container as `/home/coder/project`
-# and forward your UID/GID so that all file system operations occur as your user outside
-# the container.
-#
-# Your $HOME/.config is mounted at $HOME/.config within the container to ensure you can
-# easily access/modify your code-server config in $HOME/.config/code-server/config.json
-# outside the container.
-mkdir -p ~/.config
-docker run -it --name code-server -p 127.0.0.1:8080:8080 \
- -v "$HOME/.config:/home/coder/.config" \
- -v "$PWD:/home/coder/project" \
- -u "$(id -u):$(id -g)" \
- -e "DOCKER_USER=$USER" \
- codercom/code-server:latest
-```
-
-Our official image supports `amd64` and `arm64`.
-
-For `arm32` support there is a popular community maintained alternative:
-
-https://hub.docker.com/r/linuxserver/code-server
-
-## helm
-
-See [the chart](../ci/helm-chart).
diff --git a/doc/ipad.md b/doc/ipad.md
deleted file mode 100644
index 9c1b4ac84b3f..000000000000
--- a/doc/ipad.md
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-# iPad
-
-- [Known Issues](#known-issues)
-- [How to access code-server with a self signed certificate on iPad?](#how-to-access-code-server-with-a-self-signed-certificate-on-ipad)
-
-
-
-## Known Issues
-
-- Getting self signed certificates certificates to work is involved, see below.
-- Keyboard may disappear sometimes [#1313](https://github.com/cdr/code-server/issues/1313), [#979](https://github.com/cdr/code-server/issues/979)
-- Trackpad scrolling does not work [#1455](https://github.com/cdr/code-server/issues/1455)
-- See [issues tagged with the iPad label](https://github.com/cdr/code-server/issues?q=is%3Aopen+is%3Aissue+label%3AiPad) for more.
-
-## How to access code-server with a self signed certificate on iPad?
-
-Accessing a self signed certificate on iPad isn't as easy as accepting through all
-the security warnings. Safari will prevent WebSocket connections unless the certificate
-is installed as a profile on the device.
-
-The below assumes you are using the self signed certificate that code-server
-generates for you. If not, that's fine but you'll have to make sure your certificate
-abides by the following guidelines from Apple: https://support.apple.com/en-us/HT210176
-
-**note**: Another undocumented requirement we noticed is that the certificate has to have `basicConstraints=CA:true`.
-
-The following instructions assume you have code-server installed and running
-with a self signed certificate. If not, please first go through [./guide.md](./guide.md)!
-
-**warning**: Your iPad must access code-server via a domain name. It could be local
-DNS like `mymacbookpro.local` but it must be a domain name. Otherwise Safari will
-refuse to allow WebSockets to connect.
-
-1. Your certificate **must** have a subject alt name that matches the hostname
- at which you will access code-server from your iPad. You can pass this to code-server
- so that it generates the certificate correctly with `--cert-host`.
-2. Share your self signed certificate with the iPad.
- - code-server will print the location of the certificate it has generated in the logs.
-
-```
-[2020-10-30T08:55:45.139Z] info - Using generated certificate and key for HTTPS: ~/.local/share/code-server/mymbp_local.crt
-```
-
-- You can mail it to yourself or if you have a Mac, it's easiest to just Airdrop to the iPad.
-
-3. When opening the `*.crt` file, you'll be prompted to go into settings to install.
-4. Go to `Settings -> General -> Profile`, select the profile and then hit `Install`.
- - It should say the profile is verified.
-5. Go to `Settings -> About -> Certificate Trust Settings` and enable full trust for
- the certificate.
-6. Now you can access code-server! 🍻
diff --git a/doc/npm.md b/doc/npm.md
deleted file mode 100644
index ce63fd5ea258..000000000000
--- a/doc/npm.md
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-# npm Install Requirements
-
-- [Ubuntu, Debian](#ubuntu-debian)
-- [Fedora, CentOS, RHEL](#fedora-centos-rhel)
-- [macOS](#macos)
-
-
-
-If you're installing the npm module you'll need certain dependencies to build
-the native modules used by VS Code.
-
-You also need at least node v12 installed. See [#1633](https://github.com/cdr/code-server/issues/1633).
-
-## Ubuntu, Debian
-
-```bash
-sudo apt-get install -y \
- build-essential \
- pkg-config \
- libx11-dev \
- libxkbfile-dev \
- libsecret-1-dev \
- python3
-npm config set python python3
-```
-
-## Fedora, CentOS, RHEL
-
-```bash
-sudo yum groupinstall -y 'Development Tools'
-sudo yum config-manager --set-enabled PowerTools # unnecessary on CentOS 7
-sudo yum install -y python2 libsecret-devel libX11-devel libxkbfile-devel
-npm config set python python2
-```
-
-## macOS
-
-Install [Xcode](https://developer.apple.com/xcode/downloads/) and run:
-
-```bash
-xcode-select --install
-```
diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000000..168eac481bb7
--- /dev/null
+++ b/docs/CODE_OF_CONDUCT.md
@@ -0,0 +1,92 @@
+
+
+
+# Contributor Covenant Code of Conduct
+
+- [Contributor Covenant Code of Conduct](#contributor-covenant-code-of-conduct)
+ - [Our Pledge](#our-pledge)
+ - [Our Standards](#our-standards)
+ - [Our Responsibilities](#our-responsibilities)
+ - [Scope](#scope)
+ - [Enforcement](#enforcement)
+ - [Attribution](#attribution)
+
+
+
+
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+- Using welcoming and inclusive language
+- Being respectful of differing viewpoints and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+- The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+- Trolling, insulting/derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at opensource@coder.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
new file mode 100644
index 000000000000..a2087ff17672
--- /dev/null
+++ b/docs/CONTRIBUTING.md
@@ -0,0 +1,288 @@
+
+
+
+# Contributing
+
+- [Requirements](#requirements)
+ - [Linux-specific requirements](#linux-specific-requirements)
+- [Development workflow](#development-workflow)
+ - [Version updates to Code](#version-updates-to-code)
+ - [Patching Code](#patching-code)
+ - [Build](#build)
+ - [Troubleshooting](#troubleshooting)
+ - [I see "Forbidden access" when I load code-server in the browser](#i-see-forbidden-access-when-i-load-code-server-in-the-browser)
+ - ["Can only have one anonymous define call per script"](#can-only-have-one-anonymous-define-call-per-script)
+ - [Help](#help)
+- [Test](#test)
+ - [Unit tests](#unit-tests)
+ - [Script tests](#script-tests)
+ - [Integration tests](#integration-tests)
+ - [End-to-end tests](#end-to-end-tests)
+- [Structure](#structure)
+ - [Modifications to Code](#modifications-to-code)
+ - [Currently Known Issues](#currently-known-issues)
+
+
+
+
+## Requirements
+
+The prerequisites for contributing to code-server are almost the same as those
+for [VS Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
+Here is what is needed:
+
+- `node` v22.x
+- `git` v2.x or greater
+- [`git-lfs`](https://git-lfs.github.com)
+- [`npm`](https://www.npmjs.com/)
+ - Used to install JS packages and run scripts
+- [`nfpm`](https://nfpm.goreleaser.com/)
+ - Used to build `.deb` and `.rpm` packages
+- [`jq`](https://stedolan.github.io/jq/)
+ - Used to build code-server releases
+- [`gnupg`](https://gnupg.org/index.html)
+ - All commits must be signed and verified; see GitHub's [Managing commit
+ signature
+ verification](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification)
+ or follow [this tutorial](https://joeprevite.com/verify-commits-on-github)
+- `quilt`
+ - Used to manage patches to Code
+- `rsync` and `unzip`
+ - Used for code-server releases
+- `bats`
+ - Used to run script unit tests
+
+### Linux-specific requirements
+
+If you're developing code-server on Linux, make sure you have installed or
+install the following dependencies:
+
+```shell
+sudo apt-get install build-essential g++ libx11-dev libxkbfile-dev libsecret-1-dev libkrb5-dev python-is-python3
+```
+
+These are required by Code. See [their Wiki](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites)
+for more information.
+
+## Development workflow
+
+1. `git clone https://github.com/coder/code-server.git` - Clone `code-server`
+2. `git submodule update --init` - Clone `vscode` submodule
+3. `quilt push -a` - Apply patches to the `vscode` submodule.
+4. `npm install` - Install dependencies
+5. `npm run watch` - Launch code-server localhost:8080. code-server will be live
+ reloaded when changes are made; the browser needs to be refreshed manually.
+
+When pulling down changes that include modifications to the patches you will
+need to apply them with `quilt`. If you pull down changes that update the
+`vscode` submodule you will need to run `git submodule update --init` and
+re-apply the patches.
+
+When you make a change that affects people deploying the marketplace please
+update the changelog as part of your PR.
+
+Note that building code-server takes a very, very long time, and loading it in
+the browser in development mode also takes a very, very long time.
+
+Display language (Spanish, etc) support only works in a full build; it will not
+work in development mode.
+
+Generally we prefer that PRs be squashed into `main` but you can rebase or merge
+if it is important to keep the individual commits (make sure to clean up the
+commits first if you are doing this).
+
+### Version updates to Code
+
+PRs will be automatically created with updates to VS Code. If a patch cannot be
+automatically resolved, it will be necessary to clone the branch, resolve the
+conflicts manually, and finish the update. To do this:
+
+1. Apply as many patches as possible `quilt push -a`.
+2. Once you hit a conflict, force apply with `quilt push -f`, manually add back
+ the rejected code, then run `quilt refresh`.
+3. Once all patches have been resolved, run `./ci/build/update.sh` to finish the
+ update process.
+4. Commit all changes, push them up to the branch, and update the checklist in
+ the PR description.
+
+Once the PR is ready, manually verify that the unreleased changelog section
+contains all the changes going into this version before merging.
+
+### Patching Code
+
+1. You can go through the patch stack with `quilt push` and `quilt pop`.
+2. Create a new patch (`quilt new {name}.diff`) or use an existing patch.
+3. Add the file(s) you are patching (`quilt add [-P patch] {file}`). A file
+ **must** be added before you make changes to it.
+4. Make your changes. Patches do not need to be independent of each other but
+ each patch must result in a working code-server without any broken in-between
+ states otherwise they are difficult to test and modify.
+5. Add your changes to the patch (`quilt refresh`)
+6. Add a comment in the patch about the reason for the patch and how to
+ reproduce the behavior it fixes or adds. Every patch should have an e2e test
+ as well.
+
+### Build
+
+You can build a full production release as follows:
+
+```shell
+git submodule update --init
+quilt push -a
+npm install
+npm run build
+VERSION=0.0.0 npm run build:vscode
+KEEP_MODULES=1 npm run release
+```
+
+You can omit `KEEP_MODULES` if you intend to use this in a platform-agnostic way
+(like for publishing to NPM), but since the VS Code build process does
+post-processing deletion of the modules, it is recommended to keep the modules
+when possible, since if you install them later you will have more than is
+required. `KEEP_MODULES` will also bundle Node and the code-server entry script.
+
+Run your build:
+
+```shell
+./release/bin/code-server
+```
+
+Or if you omitted `KEEP_MODULES`:
+
+```shell
+cd release
+npm install --omit=dev
+node .
+```
+
+Then, to package the release:
+
+```shell
+npm run package
+```
+
+> On Linux, the currently running distro will become the minimum supported
+> version. In our GitHub Actions CI, we use CentOS 8 for maximum compatibility.
+> If you need your builds to support older distros, run the build commands
+> inside a Docker container with all the build requirements installed.
+
+### Troubleshooting
+
+#### I see "Forbidden access" when I load code-server in the browser
+
+This means your patches didn't apply correctly. We have a patch to remove the
+auth from vanilla Code because we use our own.
+
+Try popping off the patches with `quilt pop -a` and reapplying with `quilt push
+-a`.
+
+#### "Can only have one anonymous define call per script"
+
+Code might be trying to use a dev or prod HTML in the wrong context. You can try
+re-running code-server and setting `VSCODE_DEV=1`.
+
+### Help
+
+If you get stuck or need help, you can always start a new GitHub Discussion
+[here](https://github.com/coder/code-server/discussions). One of the maintainers
+will respond and help you out.
+
+## Test
+
+There are four kinds of tests in code-server:
+
+1. Unit tests
+2. Script tests
+3. Integration tests
+4. End-to-end tests
+
+### Unit tests
+
+Our unit tests are written in TypeScript and run using
+[Jest](https://jestjs.io/), the testing framework].
+
+These live under [test/unit](../test/unit).
+
+We use unit tests for functions and things that can be tested in isolation. The
+file structure is modeled closely after `/src` so it's easy for people to know
+where test files should live.
+
+### Script tests
+
+Our script tests are written in bash and run using [bats](https://github.com/bats-core/bats-core).
+
+These tests live under `test/scripts`.
+
+We use these to test anything related to our scripts (most of which live under
+`ci`).
+
+### Integration tests
+
+These are a work in progress. We build code-server and run tests with `npm run
+test:integration`, which ensures that code-server builds work on their
+respective platforms.
+
+Our integration tests look at components that rely on one another. For example,
+testing the CLI requires us to build and package code-server.
+
+### End-to-end tests
+
+The end-to-end (e2e) tests are written in TypeScript and run using
+[Playwright](https://playwright.dev/).
+
+These live under [test/e2e](../test/e2e).
+
+Before the e2e tests run, we run `globalSetup`, which eliminates the need to log
+in before each test by preserving the authentication state.
+
+Take a look at `codeServer.test.ts` to see how you would use it (see
+`test.use`).
+
+We also have a model where you can create helpers to use within tests. See
+[models/CodeServer.ts](../test/e2e/models/CodeServer.ts) for an example.
+
+## Structure
+
+code-server essentially serves as an HTTP API for logging in and starting a
+remote Code process.
+
+The CLI code is in [src/node](../src/node) and the HTTP routes are implemented
+in [src/node/routes](../src/node/routes).
+
+Most of the meaty parts are in the Code portion of the codebase under
+[lib/vscode](../lib/vscode), which we describe next.
+
+### Modifications to Code
+
+Our modifications to Code can be found in the [patches](../patches) directory.
+We pull in Code as a submodule pointing to an upstream release branch.
+
+In v1 of code-server, we had Code as a submodule and used a single massive patch
+that split the codebase into a front-end and a server. The front-end consisted
+of the UI code, while the server ran the extensions and exposed an API to the
+front-end for file access and all UI needs.
+
+Over time, Microsoft added support to Code to run it on the web. They had made
+the front-end open source, but not the server. As such, code-server v2 (and
+later) uses the Code front-end and implements the server. We did this by using a
+Git subtree to fork and modify Code.
+
+Microsoft eventually made the server open source and we were able to reduce our
+changes significantly. Some time later we moved back to a submodule and patches
+(managed by `quilt` this time instead of the mega-patch).
+
+As the web portion of Code continues to mature, we'll be able to shrink and
+possibly eliminate our patches. In the meantime, upgrading the Code version
+requires us to ensure that our changes are still applied correctly and work as
+intended. In the future, we'd like to run Code unit tests against our builds to
+ensure that features work as expected.
+
+> We have [extension docs](../ci/README.md) on the CI and build system.
+
+If the functionality you're working on does NOT depend on code from Code, please
+move it out and into code-server.
+
+### Currently Known Issues
+
+- Creating custom Code extensions and debugging them doesn't work
+- Extension profiling and tips are currently disabled
diff --git a/docs/FAQ.md b/docs/FAQ.md
new file mode 100644
index 000000000000..4951acb9e8e5
--- /dev/null
+++ b/docs/FAQ.md
@@ -0,0 +1,528 @@
+
+
+
+# FAQ
+
+- [Questions?](#questions)
+- [How should I expose code-server to the internet?](#how-should-i-expose-code-server-to-the-internet)
+- [Can I use code-server on the iPad?](#can-i-use-code-server-on-the-ipad)
+- [How does the config file work?](#how-does-the-config-file-work)
+- [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work)
+- [Why can't code-server use Microsoft's extension marketplace?](#why-cant-code-server-use-microsofts-extension-marketplace)
+- [How can I request an extension that's missing from the marketplace?](#how-can-i-request-an-extension-thats-missing-from-the-marketplace)
+- [How do I install an extension?](#how-do-i-install-an-extension)
+- [How do I install an extension manually?](#how-do-i-install-an-extension-manually)
+- [How do I use my own extensions marketplace?](#how-do-i-use-my-own-extensions-marketplace)
+- [Where are extensions stored?](#where-are-extensions-stored)
+- [Where is VS Code configuration stored?](#where-is-vs-code-configuration-stored)
+- [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration)
+- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open)
+- [How do I access my Documents/Downloads/Desktop folders in code-server on macOS?](#how-do-i-access-my-documentsdownloadsdesktop-folders-in-code-server-on-macos)
+- [How do I direct server-side requests through a proxy?](#how-do-i-direct-server-side-requests-through-a-proxy)
+- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server)
+- [What is the healthz endpoint?](#what-is-the-healthz-endpoint)
+- [What is the heartbeat file?](#what-is-the-heartbeat-file)
+- [How do I change the reconnection grace time?](#how-do-i-change-the-reconnection-grace-time)
+- [How do I change the password?](#how-do-i-change-the-password)
+- [Can I store my password hashed?](#can-i-store-my-password-hashed)
+- [Is multi-tenancy possible?](#is-multi-tenancy-possible)
+- [Can I use Docker in a code-server container?](#can-i-use-docker-in-a-code-server-container)
+- [How do I disable telemetry?](#how-do-i-disable-telemetry)
+- [What's the difference between code-server and Coder?](#whats-the-difference-between-code-server-and-coder)
+- [What's the difference between code-server and Theia?](#whats-the-difference-between-code-server-and-theia)
+- [What's the difference between code-server and OpenVSCode-Server?](#whats-the-difference-between-code-server-and-openvscode-server)
+- [What's the difference between code-server and GitHub Codespaces?](#whats-the-difference-between-code-server-and-github-codespaces)
+- [What's the difference between code-server and VS Code web?](#whats-the-difference-between-code-server-and-vs-code-web)
+- [Does code-server have any security login validation?](#does-code-server-have-any-security-login-validation)
+- [Are there community projects involving code-server?](#are-there-community-projects-involving-code-server)
+- [How do I change the port?](#how-do-i-change-the-port)
+- [How do I hide the coder/coder promotion in Help: Getting Started?](#how-do-i-hide-the-codercoder-promotion-in-help-getting-started)
+- [How do I disable the proxy?](#how-do-i-disable-the-proxy)
+- [How do I disable file download?](#how-do-i-disable-file-download)
+- [Why do web views not work?](#why-do-web-views-not-work)
+
+
+
+
+## Questions?
+
+Please file all questions and support requests at
+.
+
+## How should I expose code-server to the internet?
+
+Please see [our instructions on exposing code-server safely to the
+internet](./guide.md).
+
+## Can I use code-server on the iPad?
+
+See [iPad](./ipad.md) for information on using code-server on the iPad.
+
+## How does the config file work?
+
+When `code-server` starts up, it creates a default config file in `~/.config/code-server/config.yaml`:
+
+```yaml
+bind-addr: 127.0.0.1:8080
+auth: password
+password: mew...22 # Randomly generated for each config.yaml
+cert: false
+```
+
+The default config defines the following behavior:
+
+- Listen on the loopback IP port 8080
+- Enable password authorization
+- Do not use TLS
+
+Each key in the file maps directly to a `code-server` flag (run `code-server --help` to see a listing of all the flags). Any flags passed to `code-server`
+will take priority over the config file.
+
+You can change the config file's location using the `--config` flag or
+`$CODE_SERVER_CONFIG` environment variable.
+
+The default location respects `$XDG_CONFIG_HOME`.
+
+## How do I make my keyboard shortcuts work?
+
+Many shortcuts will not work by default, since they'll be "caught" by the browser.
+
+If you use Chrome, you can work around this by installing the progressive web
+app (PWA):
+
+1. Start the editor
+2. Click the **plus** icon in the URL toolbar to install the PWA
+
+If you use Firefox, you can use the appropriate extension to install PWA.
+
+1. Go to the installation [website](https://addons.mozilla.org/en-US/firefox/addon/pwas-for-firefox/) of the add-on
+2. Add the add-on to Firefox
+3. Follow the os-specific instructions on how to install the runtime counterpart
+
+For other browsers, you'll have to remap keybindings for shortcuts to work.
+
+## Why can't code-server use Microsoft's extension marketplace?
+
+Though code-server takes the open-source core of VS Code and allows you to run
+it in the browser, it is not entirely equivalent to Microsoft's VS Code.
+
+One major difference is in regards to extensions and the marketplace. The core
+of VS code is open source, while the marketplace and many published Microsoft
+extensions are not. Furthermore, Microsoft prohibits the use of any
+non-Microsoft VS Code from accessing their marketplace. Per the [Terms of
+Service](https://cdn.vsassets.io/v/M146_20190123.39/_content/Microsoft-Visual-Studio-Marketplace-Terms-of-Use.pdf):
+
+> Marketplace Offerings are intended for use only with Visual Studio Products
+> and Services, and you may only install and use Marketplace Offerings with
+> Visual Studio Products and Services.
+
+Because of this, we can't offer any extensions on Microsoft's marketplace.
+Instead, we use the [Open-VSX extension gallery](https://open-vsx.org), which is also used by various other forks.
+It isn't perfect, but its getting better by the day with more and more extensions.
+
+We also offer our own marketplace for open source extensions, but plan to
+deprecate it at a future date and completely migrate to Open-VSX.
+
+These are the closed-source extensions that are presently unavailable:
+
+1. [Live Share](https://visualstudio.microsoft.com/services/live-share). We may
+ implement something similar (see
+ [#33](https://github.com/coder/code-server/issues/33))
+1. [Remote Extensions (SSH, Containers,
+ WSL)](https://github.com/microsoft/vscode-remote-release). We may implement
+ these again at some point, see
+ ([#1315](https://github.com/coder/code-server/issues/1315)).
+
+For more about the closed source portions of VS Code, see [vscodium/vscodium](https://github.com/VSCodium/vscodium#why-does-this-exist).
+
+## How can I request an extension that's missing from the marketplace?
+
+To add an extension to Open-VSX, please see [open-vsx/publish-extensions](https://github.com/open-vsx/publish-extensions).
+We no longer plan to add new extensions to our legacy extension gallery.
+
+## How do I install an extension?
+
+You can install extensions from the marketplace using the extensions sidebar in
+code-server or from the command line:
+
+```console
+code-server --install-extension
+# example: code-server --install-extension wesbos.theme-cobalt2
+
+# From the Coder extension marketplace
+code-server --install-extension ms-python.python
+
+# From a downloaded VSIX on the file system
+code-server --install-extension downloaded-ms-python.python.vsix
+```
+
+## How do I install an extension manually?
+
+If there's an extension unavailable in the marketplace or an extension that
+doesn't work, you can download the VSIX from its GitHub releases or build it
+yourself.
+
+Once you have downloaded the VSIX to the remote machine, you can either:
+
+- Run the **Extensions: Install from VSIX** command in the Command Palette.
+- Run `code-server --install-extension ` in the terminal
+
+You can also download extensions using the command line. For instance,
+downloading from OpenVSX can be done like this:
+
+```shell
+code-server --install-extension
+```
+
+## How do I use my own extensions marketplace?
+
+If you own a marketplace that implements the VS Code Extension Gallery API, you
+can point code-server to it by setting `$EXTENSIONS_GALLERY`.
+This corresponds directly with the `extensionsGallery` entry in in VS Code's `product.json`.
+
+For example:
+
+```bash
+export EXTENSIONS_GALLERY='{"serviceUrl": "https://my-extensions/api"}'
+```
+
+Though you can technically use Microsoft's marketplace in this manner, we
+strongly discourage you from doing so since this is [against their Terms of Use](#why-cant-code-server-use-microsofts-extension-marketplace).
+
+For further information, see [this
+discussion](https://github.com/microsoft/vscode/issues/31168#issue-244533026)
+regarding the use of the Microsoft URLs in forks, as well as [VSCodium's
+docs](https://github.com/VSCodium/vscodium/blob/master/DOCS.md#extensions--marketplace).
+
+## Where are extensions stored?
+
+Extensions are stored in `~/.local/share/code-server/extensions` by default.
+
+On Linux and macOS if you set the `XDG_DATA_HOME` environment variable, the
+extensions directory will be `$XDG_DATA_HOME/code-server/extensions`. In
+general, we try to follow the XDG directory spec.
+
+## Where is VS Code configuration stored?
+
+VS Code configuration such as settings and keybindings are stored in
+`~/.local/share/code-server` by default.
+
+On Linux and macOS if you set the `XDG_DATA_HOME` environment variable, the data
+directory will be `$XDG_DATA_HOME/code-server`. In general, we try to follow the
+XDG directory spec.
+
+## How can I reuse my VS Code configuration?
+
+You can use the [Settings
+Sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync)
+extension for this purpose.
+
+Alternatively, you can also pass `--user-data-dir ~/.vscode` or copy `~/.vscode`
+into `~/.local/share/code-server` to reuse your existing VS Code extensions and
+configuration.
+
+## How does code-server decide what workspace or folder to open?
+
+code-server tries the following in this order:
+
+1. The `workspace` query parameter
+2. The `folder` query parameter
+3. The workspace or directory passed via the command line
+4. The last opened workspace or directory
+
+## How do I access my Documents/Downloads/Desktop folders in code-server on macOS?
+
+Newer versions of macOS require permission through a non-UNIX mechanism for
+code-server to access the Desktop, Documents, Pictures, Downloads, and other folders.
+
+You may have to give Node.js full disk access, since it doesn't implement any of the macOS permission request features natively:
+
+1. Find where Node.js is installed on your machine
+
+ ```console
+ $ which node
+ /usr/local/bin/node
+ ```
+
+2. Grant Node.js full disk access. Open **System Preferences** > **Security &
+ Privacy** > **Privacy** > **Full Disk Access**. Then, click the 🔒 to unlock,
+ click **+**, and select the Node.js binary you located in the previous step.
+
+See [#2794](https://github.com/coder/code-server/issues/2794) for additional context.
+
+## How do I direct server-side requests through a proxy?
+
+> code-server proxies only server-side requests.
+
+To direct server-side requests through a proxy, code-server supports the
+following environment variables:
+
+- `$HTTP_PROXY`
+- `$HTTPS_PROXY`
+- `$NO_PROXY`
+
+```sh
+export HTTP_PROXY=https://134.8.5.4
+export HTTPS_PROXY=https://134.8.5.4
+# Now all of code-server's server side requests will go through
+# https://134.8.5.4 first.
+code-server
+```
+
+- See
+ [proxy-from-env](https://www.npmjs.com/package/proxy-from-env#environment-variables)
+ for a detailed reference on these environment variables and their syntax (note
+ that code-server only uses the `http` and `https` protocols).
+- See [proxy-agent](https://www.npmjs.com/package/proxy-agent) for information
+ on on the supported proxy protocols.
+
+## How do I debug issues with code-server?
+
+First, run code-server with the `debug` logging (or `trace` to be really
+thorough) by setting the `--log` flag or the `LOG_LEVEL` environment variable.
+`-vvv` and `--verbose` are aliases for `--log trace`.
+
+First, run code-server with `debug` logging (or `trace` logging for more
+thorough messages) by setting the `--log` flag or the `LOG_LEVEL` environment
+variable.
+
+```text
+code-server --log debug
+```
+
+> Note that the `-vvv` and `--verbose` flags are aliases for `--log trace`.
+
+Next, replicate the issue you're having so that you can collect logging
+information from the following places:
+
+1. The most recent files from `~/.local/share/code-server/coder-logs`
+2. The browser console
+3. The browser network tab
+
+Additionally, collecting core dumps (you may need to enable them first) if
+code-server crashes can be helpful.
+
+## What is the healthz endpoint?
+
+You can use the `/healthz` endpoint exposed by code-server to check whether
+code-server is running without triggering a heartbeat. The response includes a
+status (e.g., `alive` or `expired`) and a timestamp for the last heartbeat
+(the default is `0`).
+
+```json
+{
+ "status": "alive",
+ "lastHeartbeat": 1599166210566
+}
+```
+
+This endpoint doesn't require authentication.
+
+## What is the heartbeat file?
+
+As long as there is an active browser connection, code-server touches
+`~/.local/share/code-server/heartbeat` once a minute.
+
+If you want to shutdown code-server if there hasn't been an active connection
+after a predetermined amount of time, you can use the --idle-timeout-seconds flag
+or set an `CODE_SERVER_IDLE_TIMEOUT_SECONDS` environment variable.
+
+## How do I change the reconnection grace time?
+
+Pass `--reconnection-grace-time ` to `code-server`, set
+`CODE_SERVER_RECONNECTION_GRACE_TIME=`, or add
+`reconnection-grace-time: ` to
+`~/.config/code-server/config.yaml`.
+
+The default is `10800` (3 hours). If a client stays disconnected longer than
+this, it must reload the window.
+
+## How do I change the password?
+
+Edit the `password` field in the code-server config file at
+`~/.config/code-server/config.yaml`, then restart code-server:
+
+```bash
+sudo systemctl restart code-server@$USER
+```
+
+## Can I store my password hashed?
+
+Yes, you can do so by setting the value of `hashed-password` instead of `password`. Generate the hash with:
+
+```shell
+echo -n "thisismypassword" | npx argon2-cli -e
+$argon2i$v=19$m=4096,t=3,p=1$wst5qhbgk2lu1ih4dmuxvg$ls1alrvdiwtvzhwnzcm1dugg+5dto3dt1d5v9xtlws4
+```
+
+Replace `thisismypassword` with your actual password and **remember to put it
+inside quotes**! For example:
+
+```yaml
+auth: password
+hashed-password: "$argon2i$v=19$m=4096,t=3,p=1$wST5QhBgk2lu1ih4DMuxvg$LS1alrVdIWtvZHwnzCM1DUGg+5DTO3Dt1d5v9XtLws4"
+```
+
+The `hashed-password` field takes precedence over `password`.
+
+If you're using Docker Compose file, in order to make this work, you need to change all the single $ to $$. For example:
+
+```yaml
+- HASHED_PASSWORD=$$argon2i$$v=19$$m=4096,t=3,p=1$$wST5QhBgk2lu1ih4DMuxvg$$LS1alrVdIWtvZHwnzCM1DUGg+5DTO3Dt1d5v9XtLws4
+```
+
+## Is multi-tenancy possible?
+
+If you want to run multiple code-servers on shared infrastructure, we recommend
+using virtual machines (provide one VM per user). This will easily allow users
+to run a Docker daemon. If you want to use Kubernetes, you'll want to
+use [kubevirt](https://kubevirt.io) or
+[sysbox](https://github.com/nestybox/sysbox) to give each user a VM-like
+experience instead of just a container.
+
+## Can I use Docker in a code-server container?
+
+If you'd like to access Docker inside of code-server, mount the Docker socket in
+from `/var/run/docker.sock`. Then, install the Docker CLI in the code-server
+container, and you should be able to access the daemon.
+
+You can even make volume mounts work. Let's say you want to run a container and
+mount into `/home/coder/myproject` from inside the `code-server` container. You
+need to make sure the Docker daemon's `/home/coder/myproject` is the same as the
+one mounted inside the `code-server` container, and the mount will work.
+
+If you want Docker enabled when deploying on Kubernetes, look at the `values.yaml`
+file for the 3 fields: `extraVars`, `lifecycle.postStart`, and `extraContainers`.
+
+## How do I disable telemetry?
+
+Use the `--disable-telemetry` flag to disable telemetry.
+
+> We use the data collected only to improve code-server.
+
+## What's the difference between code-server and Coder?
+
+code-server and Coder are both applications that can be installed on any
+machine. The main difference is who they serve. Out of the box, code-server is
+simply VS Code in the browser while Coder is a tool for provisioning remote
+development environments via Terraform.
+
+code-server was built for individuals while Coder was built for teams. In Coder, you create Workspaces which can have applications like code-server. If you're looking for a team solution, you should reach for [Coder](https://github.com/coder/coder).
+
+## What's the difference between code-server and Theia?
+
+At a high level, code-server is a patched fork of VS Code that runs in the
+browser whereas Theia takes some parts of VS Code but is an entirely different
+editor.
+
+[Theia](https://github.com/eclipse-theia/theia) is a browser IDE loosely based
+on VS Code. It uses the same text editor library
+([Monaco](https://github.com/Microsoft/monaco-editor)) and extension API, but
+everything else is different. Theia also uses [Open VSX](https://open-vsx.org)
+for extensions.
+
+Theia doesn't allow you to reuse your existing VS Code config.
+
+## What's the difference between code-server and OpenVSCode-Server?
+
+code-server and OpenVSCode-Server both allow you to access VS Code via a
+browser. OpenVSCode-Server is a direct fork of VS Code with changes comitted
+directly while code-server pulls VS Code in via a submodule and makes changes
+via patch files.
+
+However, OpenVSCode-Server is scoped at only making VS Code available as-is in
+the web browser. code-server contains additional changes to make the self-hosted
+experience better (see the next section for details).
+
+## What's the difference between code-server and GitHub Codespaces?
+
+Both code-server and GitHub Codespaces allow you to access VS Code via a
+browser. GitHub Codespaces, however, is a closed-source, paid service offered by
+GitHub and Microsoft.
+
+On the other hand, code-server is self-hosted, free, open-source, and can be run
+on any machine with few limitations.
+
+Specific changes include:
+
+- Password authentication
+- The ability to host at sub-paths
+- Self-contained web views that do not call out to Microsoft's servers
+- The ability to use your own marketplace and collect your own telemetry
+- Built-in proxy for accessing ports on the remote machine integrated into
+ VS Code's ports panel
+- Settings are stored on disk like desktop VS Code, instead of in browser
+ storage (note that state is still stored in browser storage).
+- Wrapper process that spawns VS Code on-demand and has a separate CLI
+- Notification when updates are available
+- [Some other things](https://github.com/coder/code-server/tree/main/patches)
+
+Some of these changes appear very unlikely to ever be adopted by Microsoft.
+Some may make their way upstream, further closing the gap, but at the moment it
+looks like there will always be some subtle differences.
+
+## What's the difference between code-server and VS Code web?
+
+VS Code web (which can be ran using `code serve-web`) has the same differences
+as the Codespaces section above. VS Code web can be a better choice if you need
+access to the official Microsoft marketplace.
+
+## Does code-server have any security login validation?
+
+code-server supports setting a single password and limits logins to two per
+minute plus an additional twelve per hour.
+
+## Are there community projects involving code-server?
+
+Visit the [awesome-code-server](https://github.com/coder/awesome-code-server)
+repository to view community projects and guides with code-server! Feel free to
+add your own!
+
+## How do I change the port?
+
+There are two ways to change the port on which code-server runs:
+
+1. with an environment variable e.g. `PORT=3000 code-server`
+2. using the flag `--bind-addr` e.g. `code-server --bind-addr localhost:3000`
+
+## How do I hide the coder/coder promotion in Help: Getting Started?
+
+You can pass the flag `--disable-getting-started-override` to `code-server` or
+you can set the environment variable `CS_DISABLE_GETTING_STARTED_OVERRIDE=1` or
+`CS_DISABLE_GETTING_STARTED_OVERRIDE=true`.
+
+## How do I disable the proxy?
+
+You can pass the flag `--disable-proxy` to `code-server` or
+you can set the environment variable `CS_DISABLE_PROXY=1` or
+`CS_DISABLE_PROXY=true`.
+
+Note, this option currently only disables the proxy routes to forwarded ports, including
+the domain and path proxy routes over HTTP and WebSocket; however, it does not
+disable the automatic port forwarding in the VS Code workbench itself. In other words,
+user will still see the Ports tab and notifications, but will not be able to actually
+use access the ports. It is recommended to set `remote.autoForwardPorts` to `false`
+when using the option.
+
+## How do I disable file download?
+
+You can pass the flag `--disable-file-downloads` to `code-server`
+
+## Why do web views not work?
+
+Web views rely on service workers, and service workers are only available in a
+secure context, so most likely the answer is that you are using an insecure
+context (for example an IP address).
+
+If this happens, in the browser log you will see something like:
+
+> Error loading webview: Error: Could not register service workers: SecurityError: Failed to register a ServiceWorker for scope with script: An SSL certificate error occurred when fetching the script..
+
+To fix this, you must either:
+
+- Access over localhost/127.0.0.1 which is always considered secure.
+- Use a domain with a real certificate (for example with Let's Encrypt).
+- Use a trusted self-signed certificate with [mkcert](https://mkcert.dev) (or
+ create and trust a certificate manually).
+- Disable security if your browser allows it. For example, in Chromium see
+ `chrome://flags/#unsafely-treat-insecure-origin-as-secure`
diff --git a/docs/MAINTAINING.md b/docs/MAINTAINING.md
new file mode 100644
index 000000000000..69263576ec2c
--- /dev/null
+++ b/docs/MAINTAINING.md
@@ -0,0 +1,112 @@
+
+
+
+# Maintaining
+
+- [Releasing](#releasing)
+ - [Release Candidates](#release-candidates)
+ - [AUR](#aur)
+ - [Docker](#docker)
+ - [nixpkgs](#nixpkgs)
+ - [npm](#npm)
+- [Testing](#testing)
+- [Documentation](#documentation)
+ - [Troubleshooting](#troubleshooting)
+
+
+
+
+We keep code-server up to date with VS Code releases (there are usually two or
+three a month) but we are not generally actively developing code-server aside
+from fixing regressions.
+
+Most of the work is keeping on top of issues and discussions.
+
+## Releasing
+
+1. Check that the changelog lists all the important changes.
+2. Make sure the changelog entry lists the current version of VS Code.
+3. Go to GitHub Actions > Draft release > Run workflow on the commit you want to
+ release. For the version we match VS Code's minor and patch version. The
+ patch number may become temporarily out of sync if we need to put out a
+ patch, but if we make our own minor change then we will not release it until
+ the next minor VS Code release.
+4. CI will build an NPM package and platform-specific packages, and upload those
+ to a draft release.
+5. Update the resulting draft release with the changelog contents.
+6. Publish the draft release after validating it.
+7. Update the changelog with the release date and bump the Helm chart version
+ once the Docker images have published.
+8. Merge the PR submitted to coder/code-server-aur repo.
+
+#### Release Candidates
+
+We prefer to do release candidates so the community can test things before a
+full-blown release. To do this follow the same steps as above but:
+
+1. Add a `-rc.` suffix to the version.
+2. When you publish the release select "pre-release". CI will not automatically
+ publish pre-releases.
+3. Do not update the chart version or merge in the changelog until the final
+ release.
+
+#### AUR
+
+We publish to AUR as a package
+[here](https://aur.archlinux.org/packages/code-server/). This process is manual
+and can be done by following the steps in [this
+repo](https://github.com/coder/code-server-aur).
+
+#### Docker
+
+We publish code-server as a Docker image
+[here](https://hub.docker.com/r/codercom/code-server), tagging it both with the
+version and latest.
+
+This is currently automated with the release process.
+
+#### nixpkgs
+
+We publish code-server in nixpkgs but it must be updated manually.
+
+#### npm
+
+We publish code-server as a npm package
+[here](https://www.npmjs.com/package/code-server/v/latest).
+
+This is currently automated with the release process.
+
+## Testing
+
+Our testing structure is laid out under our [Contributing
+docs](https://coder.com/docs/code-server/latest/CONTRIBUTING#test).
+
+If you're ever looking to add more tests, here are a few ways to get started:
+
+- run `npm run test:unit` and look at the coverage chart. You'll see all the
+ uncovered lines. This is a good place to start.
+- look at `test/scripts` to see which scripts are tested. We can always use more
+ tests there.
+- look at `test/e2e`. We can always use more end-to-end tests.
+
+Otherwise, talk to a current maintainer and ask which part of the codebase is
+lacking most when it comes to tests.
+
+## Documentation
+
+### Troubleshooting
+
+Our docs are hosted on [Vercel](https://vercel.com/). Vercel only shows logs in
+realtime, which means you need to have the logs open in one tab and reproduce
+your error in another tab. Since our logs are private to Coder the organization,
+you can only follow these steps if you're a Coder employee. Ask a maintainer for
+help if you need it.
+
+Taking a real scenario, let's say you wanted to troubleshoot [this docs
+change](https://github.com/coder/code-server/pull/4042). Here is how you would
+do it:
+
+1. Go to https://vercel.com/codercom/codercom
+2. Click "View Function Logs"
+3. In a separate tab, open the preview link from github-actions-bot
+4. Now look at the function logs and see if there are errors in the logs
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 000000000000..470095071afd
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,82 @@
+# code-server
+
+[](https://github.com/coder/code-server/discussions) [](https://coder.com/community) [](https://twitter.com/coderhq) [](https://discord.com/invite/coder) [](https://codecov.io/gh/coder/code-server) [](https://coder.com/docs/code-server/latest)
+
+Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and
+access it in the browser.
+
+
+
+
+## Highlights
+
+- Code on any device with a consistent development environment
+- Use cloud servers to speed up tests, compilations, downloads, and more
+- Preserve battery life when you're on the go; all intensive tasks run on your
+ server
+
+## Requirements
+
+See [requirements](https://coder.com/docs/code-server/latest/requirements) for minimum specs, as well as instructions
+on how to set up a Google VM on which you can install code-server.
+
+**TL;DR:** Linux machine with WebSockets enabled, 1 GB RAM, and 2 vCPUs
+
+## Getting started
+
+There are five ways to get started:
+
+1. Using the [install
+ script](https://github.com/coder/code-server/blob/main/install.sh), which
+ automates most of the process. The script uses the system package manager if
+ possible.
+2. Manually [installing
+ code-server](https://coder.com/docs/code-server/latest/install)
+3. Deploy code-server to your team with [coder/coder](https://cdr.co/coder-github)
+4. Using our one-click buttons and guides to [deploy code-server to a cloud
+ provider](https://github.com/coder/deploy-code-server) ⚡
+5. Using the [code-server feature for
+ devcontainers](https://github.com/coder/devcontainer-features/blob/main/src/code-server/README.md),
+ if you already use devcontainers in your project.
+
+If you use the install script, you can preview what occurs during the install
+process:
+
+```bash
+curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
+```
+
+To install, run:
+
+```bash
+curl -fsSL https://code-server.dev/install.sh | sh
+```
+
+When done, the install script prints out instructions for running and starting
+code-server.
+
+> **Note**
+> To manage code-server for a team on your infrastructure, see: [coder/coder](https://cdr.co/coder-github)
+
+We also have an in-depth [setup and
+configuration](https://coder.com/docs/code-server/latest/guide) guide.
+
+## Questions?
+
+See answers to [frequently asked
+questions](https://coder.com/docs/code-server/latest/FAQ).
+
+## Want to help?
+
+See [Contributing](https://coder.com/docs/code-server/latest/CONTRIBUTING) for
+details.
+
+## Hiring
+
+Interested in [working at Coder](https://coder.com/careers)? Check out [our open
+positions](https://coder.com/careers#openings)!
+
+## For Teams
+
+We develop [coder/coder](https://cdr.co/coder-github) to help teams to
+adopt remote development.
diff --git a/docs/SECURITY.md b/docs/SECURITY.md
new file mode 100644
index 000000000000..9ff33e365c4b
--- /dev/null
+++ b/docs/SECURITY.md
@@ -0,0 +1,33 @@
+# Security Policy
+
+Coder and the code-server team want to keep the code-server project secure and safe for end-users.
+
+## Tools
+
+We use the following tools to help us stay on top of vulnerability mitigation.
+
+- [dependabot](https://dependabot.com/)
+ - Submits pull requests to upgrade dependencies. We use dependabot's version
+ upgrades as well as security updates.
+- code-scanning
+ - [CodeQL](https://securitylab.github.com/tools/codeql/)
+ - Semantic code analysis engine that runs on a regular schedule (see
+ `codeql-analysis.yml`)
+ - [trivy](https://github.com/aquasecurity/trivy)
+ - Comprehensive vulnerability scanner that runs on PRs into the default
+ branch and scans both our container image and repository code (see
+ `trivy-scan-repo` and `trivy-scan-image` jobs in `build.yaml`)
+- `npm audit`
+ - Audits NPM dependencies.
+
+## Supported Versions
+
+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 |
+| ------------------------------------------------------- | ------------------ |
+| [Latest](https://github.com/coder/code-server/releases) | :white_check_mark: |
+
+## Reporting a Vulnerability
+
+To report a vulnerability, please send an email to security[@]coder.com, and our security team will respond to you.
diff --git a/docs/android.md b/docs/android.md
new file mode 100644
index 000000000000..0b1dc24abf6e
--- /dev/null
+++ b/docs/android.md
@@ -0,0 +1,31 @@
+# Running code-server using UserLAnd
+
+1. Install UserLAnd from [Google Play](https://play.google.com/store/apps/details?id=tech.ula&hl=en_US&gl=US)
+2. Install an Ubuntu VM
+3. Start app
+4. Install Node.js and `curl` using `sudo apt install nodejs npm curl -y`
+5. Install `nvm`:
+
+```shell
+curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
+```
+
+6. Exit the terminal using `exit` and then reopen the terminal
+7. Install and use Node.js 22:
+
+```shell
+nvm install 22
+nvm use 22
+```
+
+8. Install code-server globally on device with: `npm install --global code-server`
+9. Run code-server with `code-server`
+10. Access on localhost:8080 in your browser
+
+# Running code-server using Nix-on-Droid
+
+1. Install Nix-on-Droid from [F-Droid](https://f-droid.org/packages/com.termux.nix/)
+2. Start app
+3. Spawn a shell with code-server by running `nix-shell -p code-server`
+4. Run code-server with `code-server`
+5. Access on localhost:8080 in your browser
diff --git a/docs/assets/images/icons/collab.svg b/docs/assets/images/icons/collab.svg
new file mode 100644
index 000000000000..239666a993bf
--- /dev/null
+++ b/docs/assets/images/icons/collab.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/assets/images/icons/contributing.svg b/docs/assets/images/icons/contributing.svg
new file mode 100644
index 000000000000..c814591e1c7f
--- /dev/null
+++ b/docs/assets/images/icons/contributing.svg
@@ -0,0 +1 @@
+
diff --git a/docs/assets/images/icons/faq.svg b/docs/assets/images/icons/faq.svg
new file mode 100644
index 000000000000..a3e196d298a9
--- /dev/null
+++ b/docs/assets/images/icons/faq.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/assets/images/icons/home.svg b/docs/assets/images/icons/home.svg
new file mode 100644
index 000000000000..0f7bee254cd3
--- /dev/null
+++ b/docs/assets/images/icons/home.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/assets/images/icons/requirements.svg b/docs/assets/images/icons/requirements.svg
new file mode 100644
index 000000000000..c3888f90274f
--- /dev/null
+++ b/docs/assets/images/icons/requirements.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/assets/images/icons/upgrade.svg b/docs/assets/images/icons/upgrade.svg
new file mode 100644
index 000000000000..28c35752f201
--- /dev/null
+++ b/docs/assets/images/icons/upgrade.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/assets/images/icons/usage.svg b/docs/assets/images/icons/usage.svg
new file mode 100644
index 000000000000..f38aa04813e3
--- /dev/null
+++ b/docs/assets/images/icons/usage.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/docs/assets/images/icons/wrench.svg b/docs/assets/images/icons/wrench.svg
new file mode 100644
index 000000000000..acca9b7614a1
--- /dev/null
+++ b/docs/assets/images/icons/wrench.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/assets/screenshot-1.png b/docs/assets/screenshot-1.png
new file mode 100644
index 000000000000..cacbc21bd771
Binary files /dev/null and b/docs/assets/screenshot-1.png differ
diff --git a/docs/assets/screenshot-2.png b/docs/assets/screenshot-2.png
new file mode 100644
index 000000000000..5861fac0b905
Binary files /dev/null and b/docs/assets/screenshot-2.png differ
diff --git a/docs/coder.md b/docs/coder.md
new file mode 100644
index 000000000000..eff3423b5b7a
--- /dev/null
+++ b/docs/coder.md
@@ -0,0 +1,48 @@
+# Coder
+
+To install and run code-server in a Coder workspace, we suggest using the `install.sh`
+script in your template like so:
+
+```terraform
+resource "coder_agent" "dev" {
+ arch = "amd64"
+ os = "linux"
+ startup_script = <
+
+
+# Setup Guide
+
+- [Expose code-server](#expose-code-server)
+ - [Port forwarding via SSH](#port-forwarding-via-ssh)
+ - [Using Let's Encrypt with Caddy](#using-lets-encrypt-with-caddy)
+ - [Using Let's Encrypt with NGINX](#using-lets-encrypt-with-nginx)
+ - [Using a self-signed certificate](#using-a-self-signed-certificate)
+ - [TLS 1.3 and Safari](#tls-13-and-safari)
+- [External authentication](#external-authentication)
+- [HTTPS and self-signed certificates](#https-and-self-signed-certificates)
+- [Accessing web services](#accessing-web-services)
+ - [Using a subdomain](#using-a-subdomain)
+ - [Using a subpath](#using-a-subpath)
+ - [Using your own proxy](#using-your-own-proxy)
+ - [Stripping `/proxy/` from the request path](#stripping-proxyport-from-the-request-path)
+ - [Proxying to create a React app](#proxying-to-create-a-react-app)
+ - [Proxying to a Vue app](#proxying-to-a-vue-app)
+ - [Proxying to an Angular app](#proxying-to-an-angular-app)
+ - [Proxying to a Svelte app](#proxying-to-a-svelte-app)
+ - [Prefixing `/absproxy/` with a path](#prefixing-absproxyport-with-a-path)
+ - [Preflight requests](#preflight-requests)
+- [Internationalization and customization](#internationalization-and-customization)
+ - [Available keys and placeholders](#available-keys-and-placeholders)
+ - [Legacy flag](#legacy-flag)
+
+
+
+
+This article will walk you through exposing code-server securely once you've
+completed the [installation process](install.md).
+
+## Expose code-server
+
+**Never** expose code-server directly to the internet without some form of
+authentication and encryption, otherwise someone can take over your machine via
+the terminal.
+
+By default, code-server uses password authentication. As such, you must copy the
+password from code-server's config file to log in. To avoid exposing itself
+unnecessarily, code-server listens on `localhost`; this practice is fine for
+testing, but it doesn't work if you want to access code-server from a different
+machine.
+
+> **Rate limits:** code-server rate limits password authentication attempts to
+> two per minute plus an additional twelve per hour.
+
+There are several approaches to operating and exposing code-server securely:
+
+- Port forwarding via SSH
+- Using Let's Encrypt with Caddy
+- Using Let's Encrypt with NGINX
+- Using a self-signed certificate
+
+### Port forwarding via SSH
+
+We highly recommend using [port forwarding via
+SSH](https://help.ubuntu.com/community/SSH/OpenSSH/PortForwarding) to access
+code-server. If you have an SSH server on your remote machine, this approach
+doesn't require any additional setup at all.
+
+The downside to SSH forwarding, however, is that you can't access code-server
+when using machines without SSH clients (such as iPads). If this applies to you,
+we recommend using another method, such as [Let's Encrypt](#let-encrypt) instead.
+
+> To work properly, your environment should have WebSockets enabled, which
+> code-server uses to communicate between the browser and server.
+
+1. SSH into your instance and edit the code-server config file to disable
+ password authentication:
+
+ ```console
+ # Replaces "auth: password" with "auth: none" in the code-server config.
+ sed -i.bak 's/auth: password/auth: none/' ~/.config/code-server/config.yaml
+ ```
+
+2. Restart code-server:
+
+ ```console
+ sudo systemctl restart code-server@$USER
+ ```
+
+3. Forward local port `8080` to `127.0.0.1:8080` on the remote instance by running the following command on your local machine:
+
+ ```console
+ # -N disables executing a remote shell
+ ssh -N -L 8080:127.0.0.1:8080 [user]@
+ ```
+
+4. At this point, you can access code-server by pointing your web browser to `http://127.0.0.1:8080`.
+
+5. If you'd like to make the port forwarding via SSH persistent, we recommend
+ using [mutagen](https://mutagen.io/documentation/introduction/installation)
+ to do so. Once you've installed mutagen, you can port forward as follows:
+
+ ```shell
+ # This is the same as the above SSH command, but it runs in the background
+ # continuously. Be sure to add `mutagen daemon start` to your ~/.bashrc to
+ # start the mutagen daemon when you open a shell.
+ mutagen forward create --name=code-server tcp:127.0.0.1:8080 < instance-ip > :tcp:127.0.0.1:8080
+ ```
+
+6. Optional, but highly recommended: add the following to `~/.ssh/config` so
+ that you can detect bricked SSH connections:
+
+ ```bash
+ Host *
+ ServerAliveInterval 5
+ ExitOnForwardFailure yes
+ ```
+
+> You can [forward your
+> SSH](https://developer.github.com/v3/guides/using-ssh-agent-forwarding/) and
+> [GPG agent](https://wiki.gnupg.org/AgentForwarding) to the instance to
+> securely access GitHub and sign commits without having to copy your keys.
+
+### Using Let's Encrypt with Caddy
+
+Using [Let's Encrypt](https://letsencrypt.org) is an option if you want to
+access code-server on an iPad or do not want to use SSH port forwarding.
+
+1. This option requires that the remote machine be exposed to the internet. Make sure that your instance allows HTTP/HTTPS traffic.
+
+2. You'll need a domain name (if you don't have one, you can purchase one from
+ [Google Domains](https://domains.google.com) or the domain service of your
+ choice). Once you have a domain name, add an A record to your domain that contains your
+ instance's IP address.
+
+3. Install [Caddy](https://caddyserver.com/docs/download#debian-ubuntu-raspbian):
+
+ ```console
+ sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
+ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
+ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
+ sudo apt update
+ sudo apt install caddy
+ ```
+
+4. Replace `/etc/caddy/Caddyfile` using `sudo` so that the file looks like this:
+
+ ```text
+ mydomain.com {
+ reverse_proxy 127.0.0.1:8080
+ }
+ ```
+
+ If you want to serve code-server from a sub-path, you can do so as follows:
+
+ ```text
+ mydomain.com/code/* {
+ uri strip_prefix /code
+ reverse_proxy 127.0.0.1:8080
+ }
+ ```
+
+ Remember to replace `mydomain.com` with your domain name!
+
+5. Reload Caddy:
+
+ ```console
+ sudo systemctl reload caddy
+ ```
+
+At this point, you should be able to access code-server via
+`https://mydomain.com`.
+
+### Using Let's Encrypt with NGINX
+
+1. This option requires that the remote machine be exposed to the internet. Make
+ sure that your instance allows HTTP/HTTPS traffic.
+
+2. You'll need a domain name (if you don't have one, you can purchase one from
+ [Google Domains](https://domains.google.com) or the domain service of your
+ choice). Once you have a domain name, add an A record to your domain that contains your
+ instance's IP address.
+
+3. Install NGINX:
+
+ ```bash
+ sudo apt update
+ sudo apt install -y nginx certbot python3-certbot-nginx
+ ```
+
+4. Update `/etc/nginx/sites-available/code-server` using sudo with the following
+ configuration:
+
+ ```text
+ server {
+ listen 80;
+ listen [::]:80;
+ server_name mydomain.com;
+
+ location / {
+ proxy_pass http://localhost:8080/;
+ proxy_set_header Host $http_host;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection upgrade;
+ proxy_set_header Accept-Encoding gzip;
+ }
+ }
+ ```
+
+ Be sure to replace `mydomain.com` with your domain name!
+
+5. Enable the config:
+ ```console
+ sudo ln -s ../sites-available/code-server /etc/nginx/sites-enabled/code-server
+ sudo certbot --non-interactive --redirect --agree-tos --nginx -d mydomain.com -m me@example.com
+ ```
+ Be sure to replace `me@example.com` with your actual email.
+
+At this point, you should be able to access code-server via
+`https://mydomain.com`.
+
+### Using a self-signed certificate
+
+> Self signed certificates do not work with iPad; see [./ipad.md](./ipad.md) for
+> more information.
+
+Before proceeding, we recommend familiarizing yourself with the [risks of
+self-signing a certificate for
+SSL](https://security.stackexchange.com/questions/8110).
+
+We recommend self-signed certificates as a last resort, since self-signed
+certificates do not work with iPads and may cause unexpected issues with
+code-server. You should only proceed with this option if:
+
+- You do not want to buy a domain or you cannot expose the remote machine to
+ the internet
+- You do not want to use port forwarding via SSH
+
+To use a self-signed certificate:
+
+1. This option requires that the remote machine be exposed to the internet. Make
+ sure that your instance allows HTTP/HTTPS traffic.
+
+1. SSH into your instance and edit your code-server config file to use a
+ randomly generated self-signed certificate:
+
+ ```console
+ # Replaces "cert: false" with "cert: true" in the code-server config.
+ sed -i.bak 's/cert: false/cert: true/' ~/.config/code-server/config.yaml
+ # Replaces "bind-addr: 127.0.0.1:8080" with "bind-addr: 0.0.0.0:443" in the code-server config.
+ sed -i.bak 's/bind-addr: 127.0.0.1:8080/bind-addr: 0.0.0.0:443/' ~/.config/code-server/config.yaml
+ # Allows code-server to listen on port 443.
+ sudo setcap cap_net_bind_service=+ep /usr/lib/code-server/lib/node
+ ```
+
+1. Restart code-server:
+
+ ```console
+ sudo systemctl restart code-server@$USER
+ ```
+
+At this point, you should be able to access code-server via
+`https://`.
+
+If you'd like to avoid the warnings displayed by code-server when using a
+self-signed certificate, you can use [mkcert](https://mkcert.dev) to create a
+self-signed certificate that's trusted by your operating system, then pass the
+certificate to code-server via the `cert` and `cert-key` config fields.
+
+### TLS 1.3 and Safari
+
+If you will be using Safari and your configuration does not allow anything less
+than TLS 1.3 you will need to add support for TLS 1.2 since Safari does not
+support TLS 1.3 for web sockets at the time of writing. If this is the case you
+should see OSSStatus: 9836 in the browser console.
+
+## External authentication
+
+If you want to use external authentication mechanism (e.g., Sign in with
+Google), you can do this with a reverse proxy such as:
+
+- [Pomerium](https://www.pomerium.com/docs/guides/code-server.html)
+- [oauth2-proxy](https://oauth2-proxy.github.io/oauth2-proxy/)
+- [Cloudflare Access](https://www.cloudflare.com/zero-trust/products/access/)
+
+## HTTPS and self-signed certificates
+
+For HTTPS, you can use a self-signed certificate by:
+
+- Passing in `--cert`
+- Passing in an existing certificate by providing the path to `--cert` and the
+ path to the key with `--cert-key`
+
+The self signed certificate will be generated to
+`~/.local/share/code-server/self-signed.crt`.
+
+If you pass a certificate to code-server, it will respond to HTTPS requests and
+redirect all HTTP requests to HTTPS.
+
+> You can use [Let's Encrypt](https://letsencrypt.org/) to get a TLS certificate
+> for free.
+
+Note: if you set `proxy_set_header Host $host;` in your reverse proxy config, it
+will change the address displayed in the green section of code-server in the
+bottom left to show the correct address.
+
+## Accessing web services
+
+If you're working on web services and want to access them locally, code-server
+can proxy to any port using either a subdomain or a subpath, allowing you to
+securely access these services using code-server's built-in authentication.
+
+### Using a subdomain
+
+You will need a DNS entry that points to your server for each port you want to
+access. You can either set up a wildcard DNS entry for `*.` if your
+domain name registrar supports it, or you can create one for every port you want
+to access (`3000.`, `8080.`, etc).
+
+You should also set up TLS certificates for these subdomains, either using a
+wildcard certificate for `*.` or individual certificates for each port.
+
+To set your domain, start code-server with the `--proxy-domain` flag:
+
+```console
+code-server --proxy-domain
+```
+
+For instance, if you have code-server exposed on `domain.tld` and a Python
+server running on port 8080 of the same machine code-server is running on, you
+could run code-server with `--proxy-domain domain.tld` and access the Python
+server via `8080.domain.tld`.
+
+Note that this uses the host header, so ensure your reverse proxy (if you're
+using one) forwards that information.
+
+### Using a subpath
+
+Simply browse to `/proxy//`. For instance, if you have code-server
+exposed on `domain.tld` and a Python server running on port 8080 of the same
+machine code-server is running on, you could access the Python server via
+`domain.tld/proxy/8000`.
+
+### Using your own proxy
+
+You can make extensions and the ports panel use your own proxy by setting
+`VSCODE_PROXY_URI`. For example if you set
+`VSCODE_PROXY_URI=https://{{port}}.kyle.dev` when an application is detected
+running on port 3000 of the same machine code-server is running on the ports
+panel will create a link to https://3000.kyle.dev instead of pointing to the
+built-in subpath-based proxy.
+
+Note: relative paths are also supported i.e.
+`VSCODE_PROXY_URI=./proxy/{{port}}`
+
+### Stripping `/proxy/` from the request path
+
+You may notice that the code-server proxy strips `/proxy/` from the
+request path.
+
+HTTP servers should use relative URLs to avoid the need to be coupled to the
+absolute path at which they are served. This means you must [use trailing
+slashes on all paths with
+subpaths](https://blog.cdivilly.com/2019/02/28/uri-trailing-slashes).
+
+This reasoning is why the default behavior is to strip `/proxy/` from the
+base path. If your application uses relative URLs and does not assume the
+absolute path at which it is being served, it will just work no matter what port
+you decide to serve it off or if you put it in behind code-server or any other
+proxy.
+
+However, some prefer the cleaner aesthetic of no trailing slashes. Omitting the
+trailing slashes couples you to the base path, since you cannot use relative
+redirects correctly anymore. If you're okay with this tradeoff, use `/absproxy`
+instead and the path will be passed as is (e.g., `/absproxy/3000/my-app-path`).
+
+### Proxying to create a React app
+
+You must use `/absproxy/` with `create-react-app` (see
+[#2565](https://github.com/coder/code-server/issues/2565) and
+[#2222](https://github.com/coder/code-server/issues/2222) for more information).
+You will need to inform `create-react-app` of the path at which you are serving
+via `$PUBLIC_URL` and webpack via `$WDS_SOCKET_PATH`:
+
+```sh
+PUBLIC_URL=/absproxy/3000 \
+ WDS_SOCKET_PATH=$PUBLIC_URL/sockjs-node \
+ BROWSER=none yarn start
+```
+
+You should then be able to visit
+`https://my-code-server-address.io/absproxy/3000` to see your app exposed
+through code-server.
+
+> We highly recommend using the subdomain approach instead to avoid this class of issue.
+
+### Proxying to a Vue app
+
+Similar to the situation with React apps, you have to make a few modifications
+to proxy a Vue app.
+
+1. add `vue.config.js`
+2. update the values to match this (you can use any free port):
+
+```js
+module.exports = {
+ devServer: {
+ port: 3454,
+ sockPath: "sockjs-node",
+ },
+ publicPath: "/absproxy/3454",
+}
+```
+
+3. access app at `/absproxy/3454` e.g. `http://localhost:8080/absproxy/3454`
+
+Read more about `publicPath` in the [Vue.js docs](https://cli.vuejs.org/config/#publicpath)
+
+### Proxying to an Angular app
+
+In order to use code-server's built-in proxy with Angular, you need to make the
+following changes in your app:
+
+1. use `` in `src/index.html`
+2. add `--serve-path /absproxy/4200` to `ng serve` in your `package.json`
+
+For additional context, see [this GitHub Discussion](https://github.com/coder/code-server/discussions/5439#discussioncomment-3371983).
+
+### Proxying to a Svelte app
+
+In order to use code-server's built-in proxy with Svelte, you need to make the
+following changes in your app:
+
+1. Add `svelte.config.js` if you don't already have one
+2. Update the values to match this (you can use any free port):
+
+```js
+const config = {
+ kit: {
+ paths: {
+ base: "/absproxy/5173",
+ },
+ },
+}
+```
+
+3. Access app at `/absproxy/5173/` e.g. `http://localhost:8080/absproxy/5173/
+
+For additional context, see [this Github Issue](https://github.com/sveltejs/kit/issues/2958)
+
+### Prefixing `/absproxy/` with a path
+
+This is a case where you need to serve an application via `absproxy` as
+explained above while serving code-server itself from a path other than the root
+in your domain.
+
+For example: `http://my-code-server.com/user/123/workspace/my-app`. To achieve
+this result:
+
+1. Start code-server with the switch `--abs-proxy-base-path=/user/123/workspace`
+2. Follow one of the instructions above for your framework.
+
+### Preflight requests
+
+By default, if you have auth enabled, code-server will authenticate all proxied
+requests including preflight requests. This can cause issues because preflight
+requests do not typically include credentials. To allow all preflight requests
+through the proxy without authentication, use `--skip-auth-preflight`.
+
+## Internationalization and customization
+
+code-server allows you to provide a JSON file to configure certain strings. This
+can be used for both internationalization and customization.
+
+Create a JSON file with your custom strings:
+
+```json
+{
+ "WELCOME": "Welcome to {{app}}",
+ "LOGIN_TITLE": "{{app}} Access Portal",
+ "LOGIN_BELOW": "Please log in to continue",
+ "PASSWORD_PLACEHOLDER": "Enter Password"
+}
+```
+
+Then reference the file:
+
+```shell
+code-server --i18n /path/to/custom-strings.json
+```
+
+Or this can be done in the config file:
+
+```yaml
+i18n: /path/to/custom-strings.json
+```
+
+You can combine this with the `--locale` flag to configure language support for
+both code-server and VS Code in cases where code-server has no support but VS
+Code does. If you are using this for internationalization, please consider
+sending us a pull request to contribute it to `src/node/i18n/locales`.
+
+### Available keys and placeholders
+
+Refer to [../src/node/i18n/locales/en.json](../src/node/i18n/locales/en.json)
+for a full list of the available keys for translations. Note that the only
+placeholders supported for each key are the ones used in the default string.
+
+The `--app-name` flag controls the `{{app}}` placeholder in templates. If you
+want to change the name, you can either:
+
+1. Set `--app-name` (potentially alongside `--i18n`)
+2. Use `--i18n` and hardcode the name in your strings
+
+### Legacy flag
+
+The `--welcome-text` flag is now deprecated. Use the `WELCOME` key instead.
diff --git a/docs/helm.md b/docs/helm.md
new file mode 100644
index 000000000000..cf33d82892cf
--- /dev/null
+++ b/docs/helm.md
@@ -0,0 +1,160 @@
+# 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.8.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.
+
+This chart is community maintained by [@Matthew-Beckett](https://github.com/Matthew-Beckett) and [@alexgorbatchev](https://github.com/alexgorbatchev)
+
+## Quickstart
+
+```console
+$ git clone https://github.com/coder/code-server
+$ cd code-server
+$ helm upgrade --install code-server ci/helm-chart
+```
+
+## Introduction
+
+This chart bootstraps a code-server deployment on a
+[Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh)
+package manager.
+
+## Prerequisites
+
+- Kubernetes 1.6+
+
+## Installing the Chart
+
+To install the chart with the release name `code-server`:
+
+```console
+$ git clone https://github.com/coder/code-server
+$ cd code-server
+$ helm upgrade --install code-server ci/helm-chart
+```
+
+The command deploys code-server on the Kubernetes cluster in the default
+configuration. The [configuration](#configuration) section lists the parameters
+that can be configured during installation.
+
+> **Tip**: List all releases using `helm list`
+
+## Uninstalling the Chart
+
+To uninstall/delete the `code-server` deployment:
+
+```console
+$ helm delete code-server
+```
+
+The command removes all the Kubernetes components associated with the chart and
+deletes the release.
+
+## Configuration
+
+The following table lists the configurable parameters of the code-server chart
+and their default values.
+
+## Values
+
+| Key | Type | Default |
+| ------------------------------------------- | ------ | ------------------------ |
+| affinity | object | `{}` |
+| extraArgs | list | `[]` |
+| extraConfigmapMounts | list | `[]` |
+| extraContainers | string | `""` |
+| extraInitContainers | string | `""` |
+| extraSecretMounts | list | `[]` |
+| extraVars | list | `[]` |
+| extraVolumeMounts | list | `[]` |
+| fullnameOverride | string | `""` |
+| hostnameOverride | string | `""` |
+| image.pullPolicy | string | `"Always"` |
+| image.repository | string | `"codercom/code-server"` |
+| image.tag | string | `"4.8.0"` |
+| imagePullSecrets | list | `[]` |
+| ingress.enabled | bool | `false` |
+| nameOverride | string | `""` |
+| nodeSelector | object | `{}` |
+| persistence.accessMode | string | `"ReadWriteOnce"` |
+| persistence.annotations | object | `{}` |
+| persistence.enabled | bool | `true` |
+| persistence.size | string | `"1Gi"` |
+| podAnnotations | object | `{}` |
+| podSecurityContext | object | `{}` |
+| replicaCount | int | `1` |
+| resources | object | `{}` |
+| securityContext.enabled | bool | `true` |
+| securityContext.fsGroup | int | `1000` |
+| securityContext.runAsUser | int | `1000` |
+| service.port | int | `8443` |
+| service.type | string | `"ClusterIP"` |
+| serviceAccount.create | bool | `true` |
+| serviceAccount.name | string | `nil` |
+| tolerations | list | `[]` |
+| volumePermissions.enabled | bool | `true` |
+| volumePermissions.securityContext.runAsUser | int | `0` |
+
+Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
+
+```console
+$ helm upgrade --install code-server \
+ ci/helm-chart \
+ --set persistence.enabled=false
+```
+
+The above command sets the the persistence storage to false.
+
+Alternatively, a YAML file that specifies the values for the above parameters
+can be provided while installing the chart. For example,
+
+```console
+$ helm upgrade --install code-server ci/helm-chart -f values.yaml
+```
+
+> **Tip**: You can use the default [values.yaml](values.yaml)
+
+# Extra Containers
+
+There are two parameters which allow to add more containers to pod.
+Use `extraContainers` to add regular containers
+and `extraInitContainers` to add init containers. You can read more
+about init containers in [k8s documentation](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).
+
+Both parameters accept strings and use them as a templates
+
+Example of using `extraInitContainers`:
+
+```yaml
+extraInitContainers: |
+ - name: customization
+ image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: SERVICE_URL
+ value: https://open-vsx.org/vscode/gallery
+ - name: ITEM_URL
+ value: https://open-vsx.org/vscode/item
+ command:
+ - sh
+ - -c
+ - |
+ code-server --install-extension ms-python.python
+ code-server --install-extension golang.Go
+ volumeMounts:
+ - name: data
+ mountPath: /home/coder
+```
+
+With this yaml in file `init.yaml`, you can execute
+
+```console
+$ helm upgrade --install code-server \
+ ci/helm-chart \
+ --values init.yaml
+```
+
+to deploy code-server with python and golang extensions preinstalled
+before main container have started.
diff --git a/docs/install.md b/docs/install.md
new file mode 100644
index 000000000000..30da4d415e77
--- /dev/null
+++ b/docs/install.md
@@ -0,0 +1,362 @@
+
+
+
+# Install
+
+- [install.sh](#installsh)
+ - [Detection reference](#detection-reference)
+- [npm](#npm)
+- [Standalone releases](#standalone-releases)
+- [Debian, Ubuntu](#debian-ubuntu)
+- [Fedora, CentOS, RHEL, SUSE](#fedora-centos-rhel-suse)
+- [Arch Linux](#arch-linux)
+- [Artix Linux](#artix-linux)
+- [macOS](#macos)
+- [Docker](#docker)
+- [Helm](#helm)
+- [Windows](#windows)
+- [Raspberry Pi](#raspberry-pi)
+- [Termux](#termux)
+- [Cloud providers](#cloud-providers)
+- [Uninstall](#uninstall)
+ - [install.sh](#installsh-1)
+ - [Homebrew](#homebrew)
+ - [npm](#npm-1)
+ - [Debian, Ubuntu](#debian-ubuntu-1)
+
+
+
+
+This document demonstrates how to install `code-server` on various distros and
+operating systems.
+
+## install.sh
+
+The easiest way to install code-server is to use our [install
+script](https://github.com/coder/code-server/blob/main/install.sh) for Linux, macOS and FreeBSD. The install script
+[attempts to use the system package manager](#detection-reference) if possible.
+
+You can preview what occurs during the install process:
+
+```bash
+curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
+```
+
+To install, run:
+
+```bash
+curl -fsSL https://code-server.dev/install.sh | sh
+```
+
+You can modify the installation process by including one or more of the
+following flags:
+
+- `--dry-run`: echo the commands for the install process without running them.
+- `--method`: choose the installation method.
+ - `--method=detect`: detect the package manager but fallback to
+ `--method=standalone`.
+ - `--method=standalone`: install a standalone release archive into `~/.local`.
+- `--prefix=/usr/local`: install a standalone release archive system-wide.
+- `--version=X.X.X`: install version `X.X.X` instead of latest version.
+- `--help`: see usage docs.
+- `--edge`: install the latest edge version (i.e. pre-release)
+
+When done, the install script prints out instructions for running and starting
+code-server.
+
+> If you're concerned about the install script's use of `curl | sh` and the
+> security implications, please see [this blog
+> post](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install)
+> by [sandstorm.io](https://sandstorm.io).
+
+If you prefer to install code-server manually, despite the [detection
+references](#detection-reference) and `--dry-run` feature, then continue on for
+information on how to do this. The [`install.sh`](https://github.com/coder/code-server/blob/main/install.sh) script runs the
+_exact_ same commands presented in the rest of this document.
+
+### Detection reference
+
+- For Debian and Ubuntu, code-server will install the latest deb package.
+- For Fedora, CentOS, RHEL and openSUSE, code-server will install the latest RPM
+ package.
+- For Arch Linux, code-server will install the AUR package.
+- For any unrecognized Linux operating system, code-server will install the
+ latest standalone release into `~/.local`.
+ - Ensure that you add `~/.local/bin` to your `$PATH` to run code-server.
+
+- For macOS, code-server will install the Homebrew package (if you don't have
+ Homebrew installed, code-server will install the latest standalone release
+ into `~/.local`).
+ - Ensure that you add `~/.local/bin` to your `$PATH` to run code-server.
+
+- For FreeBSD, code-server will install the [npm package](#npm) with `npm`
+
+- If you're installing code-server onto architecture with no releases,
+ code-server will install the [npm package](#npm) with `npm`
+ - We currently offer releases for amd64 and arm64.
+ - The [npm package](#npm) builds the native modules on post-install.
+
+## npm
+
+We recommend installing with `npm` when:
+
+1. You aren't using a machine with `amd64` or `arm64`.
+2. You are installing code-server on Windows.
+3. You're on Linux with `glibc` < v2.28 or `glibcxx` < v3.4.21.
+4. You're running Alpine Linux or are using a non-glibc libc. See
+ [#1430](https://github.com/coder/code-server/issues/1430#issuecomment-629883198)
+ for more information.
+
+Installing code-server with `npm` builds native modules on install.
+
+This process requires C dependencies; see our guide on [installing with npm](./npm.md) for more information.
+
+## Standalone releases
+
+We publish self-contained `.tar.gz` archives for every release on
+[GitHub](https://github.com/coder/code-server/releases). The archives bundle the
+node binary and node modules.
+
+We create the standalone releases using the [npm package](#npm), and we
+then create the remaining releases using the standalone version.
+
+The only requirement to use the standalone release is `glibc` >= 2.28 and
+`glibcxx` >= v3.4.21 on Linux (for macOS, there is no minimum system
+requirement).
+
+To use a standalone release:
+
+1. Download the latest release archive for your system from
+ [GitHub](https://github.com/coder/code-server/releases).
+2. Unpack the release.
+3. Run code-server by executing `./bin/code-server`.
+
+You can add `./bin/code-server` to your `$PATH` so that you can execute
+`code-server` without providing full path each time.
+
+Here is a sample script for installing and using a standalone code-server
+release on Linux:
+
+```bash
+mkdir -p ~/.local/lib ~/.local/bin
+curl -fL https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-linux-amd64.tar.gz \
+ | tar -C ~/.local/lib -xz
+mv ~/.local/lib/code-server-$VERSION-linux-amd64 ~/.local/lib/code-server-$VERSION
+ln -s ~/.local/lib/code-server-$VERSION/bin/code-server ~/.local/bin/code-server
+PATH="~/.local/bin:$PATH"
+code-server
+# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
+```
+
+## Debian, Ubuntu
+
+> The standalone arm64 .deb does not support Ubuntu 16.04 or earlier. Please
+> upgrade or [build with npm](#npm).
+
+```bash
+curl -fOL https://github.com/coder/code-server/releases/download/v$VERSION/code-server_${VERSION}_amd64.deb
+sudo dpkg -i code-server_${VERSION}_amd64.deb
+sudo systemctl enable --now code-server@$USER
+# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
+```
+
+## Fedora, CentOS, RHEL, SUSE
+
+> The standalone arm64 .rpm does not support CentOS 7. Please upgrade or [build
+> with npm](#npm).
+
+```bash
+curl -fOL https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-amd64.rpm
+sudo rpm -i code-server-$VERSION-amd64.rpm
+sudo systemctl enable --now code-server@$USER
+# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
+```
+
+## Arch Linux
+
+```bash
+# Install code-server from the AUR using yay.
+yay -S code-server
+sudo systemctl enable --now code-server@$USER
+# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
+```
+
+```bash
+# Install code-server from the AUR with plain makepkg.
+git clone https://aur.archlinux.org/code-server.git
+cd code-server
+makepkg -si
+sudo systemctl enable --now code-server@$USER
+# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
+```
+
+## Artix Linux
+
+```bash
+# Install code-server from the AUR
+git clone https://aur.archlinux.org/code-server.git
+cd code-server
+makepkg -si
+```
+
+Save the file as `code-server` in `/etc/init.d/` and make it executable with `chmod +x code-server`. Put your username in line 3.
+
+```bash
+#!/sbin/openrc-run
+name=$RC_SVCNAME
+description="$name - VS Code on a remote server"
+user="" # your username here
+homedir="/home/$user"
+command="$(which code-server)"
+# Just because you can do this does not mean you should. Use ~/.config/code-server/config.yaml instead
+#command_args="--extensions-dir $homedir/.local/share/$name/extensions --user-data-dir $homedir/.local/share/$name --disable-telemetry"
+command_user="$user:$user"
+pidfile="/run/$name/$name.pid"
+command_background="yes"
+extra_commands="report"
+
+depend() {
+ use logger dns
+ need net
+}
+
+start_pre() {
+ checkpath --directory --owner $command_user --mode 0755 /run/$name /var/log/$name
+}
+
+start() {
+ default_start
+ report
+}
+
+stop() {
+ default_stop
+}
+
+status() {
+ default_status
+ report
+}
+
+report() {
+ # Report to the user
+ einfo "Reading configuration from ~/.config/code-server/config.yaml"
+}
+```
+
+Start on boot with default runlevel
+
+```
+rc-update add code-server default
+```
+
+Start the service immediately
+
+```
+rc-service code-server start
+```
+
+## macOS
+
+```bash
+brew install code-server
+brew services start code-server
+# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
+```
+
+## Docker
+
+```bash
+# This will start a code-server container and expose it at http://127.0.0.1:8080.
+# It will also mount your current directory into the container as `/home/coder/project`
+# and forward your UID/GID so that all file system operations occur as your user outside
+# the container.
+#
+# Your $HOME/.config is mounted at $HOME/.config within the container to ensure you can
+# easily access/modify your code-server config in $HOME/.config/code-server/config.json
+# outside the container.
+mkdir -p ~/.config
+docker run -it --name code-server -p 127.0.0.1:8080:8080 \
+ -v "$HOME/.local:/home/coder/.local" \
+ -v "$HOME/.config:/home/coder/.config" \
+ -v "$PWD:/home/coder/project" \
+ -u "$(id -u):$(id -g)" \
+ -e "DOCKER_USER=$USER" \
+ codercom/code-server:latest
+```
+
+Our official image supports `amd64` and `arm64`. For `arm32` support, you can
+use a [community-maintained code-server
+alternative](https://hub.docker.com/r/linuxserver/code-server).
+
+## Helm
+
+You can install code-server using the [Helm package manager](https://coder.com/docs/code-server/latest/helm).
+
+## Windows
+
+We currently [do not publish Windows
+releases](https://github.com/coder/code-server/issues/1397). We recommend
+installing code-server onto Windows with [`npm`](#npm).
+
+## Raspberry Pi
+
+We recommend installing code-server onto Raspberry Pi with [`npm`](#npm).
+
+If you see an error related to `node-gyp` during installation, See [#5174](https://github.com/coder/code-server/issues/5174) for more information.
+
+## Termux
+
+Please see code-server's [Termux docs](./termux.md#installation) for more
+information.
+
+## Cloud providers
+
+We maintain [one-click apps and install scripts for cloud
+providers](https://github.com/coder/deploy-code-server) such as DigitalOcean,
+Railway, Heroku, and Azure.
+
+## Uninstall
+
+code-server can be completely uninstalled by removing the application directory, and your user configuration directory.
+
+To delete settings and data:
+
+```shell
+rm -rf ~/.local/share/code-server ~/.config/code-server
+```
+
+### install.sh
+
+If you installed with the install script, by default code-server will be in `~/.local/lib/code-server-` and you can remove it with `rm -rf`. e.g.
+
+```shell
+rm -rf ~/.local/lib/code-server-*
+```
+
+### Homebrew
+
+To remove the code-server homebrew package, run:
+
+```shell
+brew remove code-server
+
+# Alternatively
+brew uninstall code-server
+```
+
+### npm
+
+To remove the code-server global module, run:
+
+```shell
+npm uninstall --global code-server
+```
+
+### Debian, Ubuntu
+
+To uninstall, run:
+
+```shell
+sudo apt remove code-server
+```
diff --git a/docs/ios.md b/docs/ios.md
new file mode 100644
index 000000000000..fc484e19b0dd
--- /dev/null
+++ b/docs/ios.md
@@ -0,0 +1,9 @@
+# Using code-server on iOS with iSH
+
+1. Install iSH from the [App Store](https://apps.apple.com/us/app/ish-shell/id1436902243)
+2. Install `curl` and `nano` with `apk add curl nano`
+3. Configure iSH to use an earlier version of NodeJS with `nano /etc/apk/repositories` and edit `v3.14` to `v3.12` on both repository links.
+4. Install `nodejs` and `npm` with `apk add nodejs npm`
+5. Install code-server with `curl -fsSL https://code-server.dev/install.sh | sh`
+6. Run code-server with `code-server`
+7. Access on localhost:8080 in your browser
diff --git a/docs/ipad.md b/docs/ipad.md
new file mode 100644
index 000000000000..ef951cc4e6fe
--- /dev/null
+++ b/docs/ipad.md
@@ -0,0 +1,199 @@
+
+
+
+# iPad
+
+- [Using the code-server progressive web app (PWA)](#using-the-code-server-progressive-web-app-pwa)
+- [Access code-server using Servediter](#access-code-server-using-servediter)
+- [Raspberry Pi USB-C network](#raspberry-pi-usb-c-network)
+- [Recommendations](#recommendations)
+- [Known issues](#known-issues)
+ - [Workaround for issue with `ctrl+c` not stopping a running process in the terminal](#workaround-for-issue-with-ctrlc-not-stopping-a-running-process-in-the-terminal)
+- [Access code-server with a self-signed certificate on an iPad](#access-code-server-with-a-self-signed-certificate-on-an-ipad)
+ - [Certificate requirements](#certificate-requirements)
+ - [Sharing a self-signed certificate with an iPad](#sharing-a-self-signed-certificate-with-an-ipad)
+
+
+
+
+Once you've installed code-server, you can access it from an iPad.
+
+## Using the code-server progressive web app (PWA)
+
+To use code-server on an iPad, we recommend installing the code-server
+progressive web app (PWA):
+
+1. Open code-server in Safari.
+2. Click the **Share** icon.
+3. Click **Add to Home Screen**.
+
+You can now open code-server from the Home screen, and when you do, you'll be
+using the PWA. Running code-server as a PWA gets you more screen real estate and
+access to top-level keyboard shortcuts since its running like a native app.
+
+For example, you can use `cmd+w` to close an active file in the workbench. You
+can add this to `keybindings.json`:
+
+1. Open code-server
+2. Go to **Command Palette** > **Open Keyboard Shortcuts (JSON)**
+3. Add the following to `keybindings.json`
+
+ ```json
+ {
+ "key": "cmd+w",
+ "command": "workbench.action.closeActiveEditor"
+ }
+ ```
+
+4. Test the command by using `cmd+w` to close an active file.
+
+## Access code-server using Servediter
+
+If you are unable to get the self-signed certificate working, or you do not have a domain
+name to use, you can use [Servediter for code-server](https://apps.apple.com/us/app/servediter-for-code-server/id1504491325).
+
+> Servediter for code-server is **not** officially supported by the code-server team!
+
+To use Servediter:
+
+1. Download the app from the App Store.
+2. When prompted, provide your server information. If you are running a local
+ server or a [Raspberry Pi connected via USB-C](#raspberry-pi-usb-c-network), you will input your settings
+ into **Self Hosted Server**.
+
+## Raspberry Pi USB-C network
+
+We've heard of users having great success using code-server on an iPad connected
+to a Raspberry Pi via USB-C (the Raspberry Pi provides both power and direct
+network access). Setting this up requires you to turn on **Network over USB-C**
+on the Raspberry Pi, then continuing with code-server as usual on the iPad.
+
+For more information, see:
+
+- [General introduction to Pi as an iPad
+ accessory](https://www.youtube.com/watch?v=IR6sDcKo3V8)
+- [iPad with Pi FAQ](https://www.youtube.com/watch?v=SPSlyqo5Q2Q)
+- [Technical guide to connecting a Raspberry Pi to an
+ iPad](https://www.geeky-gadgets.com/connect-a-raspberry-pi-4-to-an-ipad-pro-21-01-2020/)
+
+You may also find the following tips from [Acker
+Apple](http://github.com/ackerapple/) helpful:
+
+> Here are my keys to success. I bought a 4" touch screen with fan included that
+> attaches as a case to the Pi. I use the touch screen for anytime I have
+> connection issues, otherwise I turn off the Pi screen. I gave my Pi a network
+> name so I can easily connect at home on wifi or when on go with 1 usb-c cable
+> that supplys both power and network connectivity. Lastly, not all usb-c cables
+> are equal and not all will work so try different usb-c cables if you are going
+> mad (confirm over wifi first then move to cable).
+
+## Recommendations
+
+Once you can access code-server on your iPad, you may find the following tips
+and tricks helpful:
+
+- Use multi-task mode to make code changes and see the browser at the same time
+ - This prevents the iOS background from dropping an app's state if you are
+ switching between code-server and browser (with both in full-screen)
+- Be sure you are using the debug/terminal that is built into VS Code so that
+ you don’t need another terminal app running
+ - This also prevents switching between full screen apps and losing your view
+ due to iOS' background app memory management
+
+## Known issues
+
+- Getting self-signed certificates to work [is an involved
+ process](#access-code-server-with-a-self-signed-certificate-on-an-ipad)
+- Keyboard issues:
+ - The keyboard disappear sometimes
+ [#979](https://github.com/coder/code-server/issues/979)
+ - Some expectations regarding shortcuts may not be met:
+ - `cmd + n` opens new browser window instead of new file, and it's difficult
+ to set alternative as a workaround
+ - In general, expect to edit your keyboard shortcuts
+ - There's no escape key by default on the Magic Keyboard, so most users set
+ the globe key to be an escape key
+- Trackpad scrolling does not work on iPadOS < 14.5
+ ([#1455](https://github.com/coder/code-server/issues/1455))
+ - [WebKit fix](https://bugs.webkit.org/show_bug.cgi?id=210071#c13)
+- Keyboard may lose focus in Safari / split view [#4182](https://github.com/coder/code-server/issues/4182)
+- Terminal text does not appear by default [#3824](https://github.com/coder/code-server/issues/3824)
+- Copy & paste in terminal does not work well with keyboard shortcuts [#3491](https://github.com/coder/code-server/issues/3491)
+- `ctrl+c` does not stop a long-running process in the browser
+ - Tracking upstream issue here:
+ [#114009](https://github.com/microsoft/vscode/issues/114009)
+ - See [workaround](#ctrl-c-workaround)
+
+Additionally, see [issues in the code-server repo that are tagged with the `os-ios`
+label](https://github.com/coder/code-server/issues?q=is%3Aopen+is%3Aissue+label%3Aos-ios)
+for more information.
+
+### Workaround for issue with `ctrl+c` not stopping a running process in the terminal
+
+This's currently an issue with `ctrl+c` not stopping a running process in the
+integrated terminal. We have filed an issue upstream and are tracking
+[here](https://github.com/microsoft/vscode/issues/114009).
+
+In the meantime, you can manually define a shortcut as a workaround:
+
+1. Open the Command Palette
+2. Look for **Preferences: Open Keyboard Shortcuts (JSON)**
+3. Add the following snippet:
+
+ ```json
+ {
+ "key": "ctrl+c",
+ "command": "workbench.action.terminal.sendSequence",
+ "args": {
+ "text": "\u0003"
+ },
+ "when": "terminalFocus"
+ }
+ ```
+
+_Source: [StackOverflow](https://stackoverflow.com/a/52735954/3015595)_
+
+## Access code-server with a self-signed certificate on an iPad
+
+If you've installed code-server and are [running it with a self-signed
+certificate](./guide.md#using-a-self-signed-certificate), you may see multiple
+security warnings from Safari. To fix this, you'll need to install the
+self-signed certificate generated by code-server as a profile on your device (you'll also need to do this to
+enable WebSocket connections).
+
+### Certificate requirements
+
+- We're assuming that you're using the self-signed certificate code-server
+ generates for you (if not, make sure that your certificate [abides by the
+ guidelines issued by Apple](https://support.apple.com/en-us/HT210176)).
+- We've noticed that the certificate has to include `basicConstraints=CA:true`.
+- Your certificate must have a subject alt name that matches the hostname you'll
+ use to access code-server from the iPad. You can pass this name to code-server
+ so that it generates the certificate correctly using `--cert-host`.
+
+### Sharing a self-signed certificate with an iPad
+
+To share a self-signed certificate with an iPad:
+
+1. Get the location of the certificate code-server generated; code-server prints
+ the certificate's location in its logs:
+
+ ```console
+ [2020-10-30T08:55:45.139Z] info - Using generated certificate and key for HTTPS: ~/.local/share/code-server/mymbp_local.crt
+ ```
+
+2. Send the certificate to the iPad, either by emailing it to yourself or using
+ Apple's Airdrop feature.
+
+3. Open the `*.crt` file so that you're prompted to go into Settings to install.
+
+4. Go to **Settings** > **General** > **Profile**, and select the profile. Tap **Install**.
+
+5. Go to **Settings** > **About** > **Certificate Trust Settings** and [enable
+ full trust for your certificate](https://support.apple.com/en-us/HT204477).
+
+You should be able to access code-server without all of Safari's warnings now.
+
+**warning**: Your iPad must access code-server via a domain name. It could be local
+DNS like `mymacbookpro.local`, but it must be a domain name. Otherwise, Safari will
+not allow WebSockets connections.
diff --git a/docs/manifest.json b/docs/manifest.json
new file mode 100644
index 000000000000..4e82dcd7d713
--- /dev/null
+++ b/docs/manifest.json
@@ -0,0 +1,114 @@
+{
+ "versions": ["v4.8.0"],
+ "routes": [
+ {
+ "title": "Home",
+ "description": "Learn how to install and run code-server.",
+ "path": "./README.md",
+ "icon_path": "assets/images/icons/home.svg"
+ },
+ {
+ "title": "Requirements",
+ "description": "Learn about what you need to run code-server.",
+ "icon_path": "assets/images/icons/requirements.svg",
+ "path": "./requirements.md"
+ },
+ {
+ "title": "Install",
+ "description": "How to install code-server.",
+ "icon_path": "assets/images/icons/wrench.svg",
+ "path": "./install.md",
+ "children": [
+ {
+ "title": "npm",
+ "description": "How to install code-server using npm",
+ "path": "./npm.md"
+ },
+ {
+ "title": "Helm",
+ "description": "How to install code-server using the Helm package manager",
+ "path": "./helm.md"
+ }
+ ]
+ },
+ {
+ "title": "Usage",
+ "description": "How to set up and use code-server.",
+ "icon_path": "assets/images/icons/usage.svg",
+ "path": "./guide.md",
+ "children": [
+ {
+ "title": "Coder",
+ "description": "How to run code-server in Coder",
+ "path": "./coder.md"
+ },
+ {
+ "title": "iPad",
+ "description": "How to access your code-server installation using an iPad.",
+ "path": "./ipad.md"
+ },
+ {
+ "title": "Termux",
+ "description": "How to install Termux to run code-server on an Android device.",
+ "path": "./termux.md"
+ },
+ {
+ "title": "iOS",
+ "description": "How to use code-server on iOS with iSH.",
+ "path": "./ios.md"
+ },
+ {
+ "title": "Android",
+ "description": "How to run code-server on an Android device using UserLAnd.",
+ "path": "./android.md"
+ }
+ ]
+ },
+ {
+ "title": "Collaboration",
+ "description": "How to setup real time collaboration using code server.",
+ "icon_path": "assets/images/icons/collab.svg",
+ "path": "./collaboration.md"
+ },
+ {
+ "title": "Upgrade",
+ "description": "How to upgrade code-server.",
+ "icon_path": "assets/images/icons/upgrade.svg",
+ "path": "./upgrade.md"
+ },
+ {
+ "title": "FAQ",
+ "description": "Frequently asked questions on installing and running code-server.",
+ "icon_path": "assets/images/icons/faq.svg",
+ "path": "./FAQ.md"
+ },
+ {
+ "title": "Contributing",
+ "description": "How to contribute to code-server.",
+ "icon_path": "assets/images/icons/contributing.svg",
+ "path": "./CONTRIBUTING.md",
+ "children": [
+ {
+ "title": "Code of conduct",
+ "description": "Coder expects contributors to code-server to behave in a manner that creates an open and welcoming environment.",
+ "path": "./CODE_OF_CONDUCT.md"
+ },
+ {
+ "title": "Maintenance",
+ "description": "Learn about the workflow followed by code-server's maintainers.",
+ "path": "./MAINTAINING.md"
+ },
+ {
+ "title": "Triage",
+ "description": "How the maintainers triage issues with code-server.",
+ "path": "./triage.md"
+ },
+ {
+ "title": "Security",
+ "description": "Learn about the tools used to detect vulnerabilities in code-server, and how you can report vulnerabilities.",
+ "path": "./SECURITY.md"
+ }
+ ]
+ }
+ ]
+}
diff --git a/docs/npm.md b/docs/npm.md
new file mode 100644
index 000000000000..8d3afd0be06a
--- /dev/null
+++ b/docs/npm.md
@@ -0,0 +1,150 @@
+
+
+
+# npm Install Requirements
+
+- [Node.js version](#nodejs-version)
+- [Ubuntu, Debian](#ubuntu-debian)
+- [Fedora, CentOS, RHEL](#fedora-centos-rhel)
+- [Alpine](#alpine)
+- [macOS](#macos)
+- [FreeBSD](#freebsd)
+- [Windows](#windows)
+- [Installing](#installing)
+- [Troubleshooting](#troubleshooting)
+ - [Issues with Node.js after version upgrades](#issues-with-nodejs-after-version-upgrades)
+ - [Debugging install issues with npm](#debugging-install-issues-with-npm)
+
+
+
+
+If you're installing code-server via `npm`, you'll need to install additional
+dependencies required to build the native modules used by VS Code. This article
+includes installing instructions based on your operating system.
+
+> **WARNING**: Do not use `yarn` to install code-server. Unlike `npm`, it does not respect
+> lockfiles for distributed applications. It will instead use the latest version
+> available at installation time - which might not be the one used for a given
+> code-server release, and [might lead to unexpected behavior](https://github.com/coder/code-server/issues/4927).
+
+## Node.js version
+
+We use the same major version of Node.js shipped with Code's remote, which is
+currently `22.x`. VS Code also [lists Node.js
+requirements](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites).
+
+Using other versions of Node.js [may lead to unexpected
+behavior](https://github.com/coder/code-server/issues/1633).
+
+## Ubuntu, Debian
+
+```bash
+sudo apt-get install -y \
+ build-essential \
+ pkg-config \
+ python3
+npm config set python python3
+```
+
+Proceed to [installing](#installing)
+
+## Fedora, CentOS, RHEL
+
+```bash
+sudo yum groupinstall -y 'Development Tools'
+sudo yum config-manager --set-enabled PowerTools # unnecessary on CentOS 7
+sudo yum install -y python2
+npm config set python python2
+```
+
+Proceed to [installing](#installing)
+
+## Alpine
+
+```bash
+apk add alpine-sdk bash libstdc++ libc6-compat python3 krb5-dev
+```
+
+Proceed to [installing](#installing)
+
+## macOS
+
+```bash
+xcode-select --install
+```
+
+Proceed to [installing](#installing)
+
+## FreeBSD
+
+```sh
+pkg install -y git python npm-node22 pkgconf
+pkg install -y libinotify
+```
+
+Proceed to [installing](#installing)
+
+## Windows
+
+Installing code-server requires all of the [prerequisites for VS Code development](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites). When installing the C++ compiler tool chain, we recommend using "Option 2: Visual Studio 2019" for best results.
+
+Next, install code-server with:
+
+```bash
+npm install --global code-server
+code-server
+# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
+```
+
+A `postinstall.sh` script will attempt to run. Select your terminal (e.g., Git bash) as the default shell for npm run-scripts. If an additional dialog does not appear, run the install command again.
+
+If the `code-server` command is not found, you'll need to [add a directory to your PATH](https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/). To find the directory, use the following command:
+
+```shell
+npm config get prefix
+```
+
+For help and additional troubleshooting, see [#1397](https://github.com/coder/code-server/issues/1397).
+
+## Installing
+
+After adding the dependencies for your OS, install the code-server package globally:
+
+```bash
+npm install --global code-server
+code-server
+# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
+```
+
+## Troubleshooting
+
+If you need further assistance, post on our [GitHub Discussions
+page](https://github.com/coder/code-server/discussions).
+
+### Issues with Node.js after version upgrades
+
+Occasionally, you may run into issues with Node.js.
+
+If you install code-server using `npm`, and you upgrade your Node.js
+version, you may need to reinstall code-server to recompile native modules.
+Sometimes, you can get around this by navigating into code-server's `lib/vscode`
+directory and running `npm rebuild` to recompile the modules.
+
+A step-by-step example of how you might do this is:
+
+1. Install code-server: `brew install code-server`
+2. Navigate into the directory: `cd /usr/local/Cellar/code-server//libexec/lib/vscode/`
+3. Recompile the native modules: `npm rebuild`
+4. Restart code-server
+
+### Debugging install issues with npm
+
+To debug installation issues, install with `npm`:
+
+```shell
+# Uninstall
+npm uninstall --global code-server > /dev/null 2>&1
+
+# Install with logging
+npm install --loglevel verbose --global code-server
+```
diff --git a/docs/requirements.md b/docs/requirements.md
new file mode 100644
index 000000000000..835fe5754bd1
--- /dev/null
+++ b/docs/requirements.md
@@ -0,0 +1,56 @@
+# Requirements
+
+You'll need a machine on which you can run code-server. You can use a physical
+machine you have, or you can use a VM on GCP/AWS.
+
+At the minimum, we recommend:
+
+- 1 GB of RAM
+- 2 CPU cores
+
+You can use any Linux distribution, but [our
+docs](https://coder.com/docs/code-server/latest/guide) assume that you're using
+Debian hosted by Google Cloud (see the following section for instructions on
+setting this up).
+
+Your environment must have WebSockets enabled, since code-server uses WebSockets
+for communication between the browser and the server.
+
+## Set up a VM on Google Cloud
+
+The following steps walk you through setting up a VM running Debian using Google
+Cloud (though you are welcome to use any machine or VM provider).
+
+If you're [signing up with Google](https://console.cloud.google.com/getting-started) for the first time, you should get a 3-month trial with
+\$300 of credits.
+
+After you sign up and create a new Google Cloud Provider (GCP) project, create a
+new Compute Engine VM instance:
+
+1. Using the sidebar, navigate to **Compute Engine** > **VM Instances**.
+2. Click **Create Instance**.
+3. Provide a **name** for new 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 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
+ your instance at a later point.
+8. Though optional, we highly recommend switching the persistent disk to an SSD
+ with at least 32 GB. To do so, click **change** under **Boot Disk**. Then,
+ change the type to **SSD Persistent Disk**, and set the size to **32**. (You
+ can also grow your disk at a later date).
+9. Go to **Networking** > **Networking Interfaces** and edit the existing
+ interface to use a static internal IP. Click **Done** to save.
+10. If you don't have a [project-wide SSH
+ key](https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#project-wide),
+ go to **Security** > **SSH Keys** to add your public key.
+11. Click **Create** to proceed.
+
+Notes:
+
+- To lower costs, you can shut down your server when you're not using it.
+- We recommend using the `gcloud cli` to avoid using the GCP Dashboard if possible.
+- For serving code-server over HTTPS, we recommend using an external domain name along with a service such as Let's Encrypt
diff --git a/docs/termux.md b/docs/termux.md
new file mode 100644
index 000000000000..db81cb57d1e1
--- /dev/null
+++ b/docs/termux.md
@@ -0,0 +1,203 @@
+
+
+
+# Termux
+
+- [Install](#install)
+- [NPM Installation](#npm-installation)
+- [Upgrade](#upgrade)
+- [Known Issues](#known-issues)
+ - [Git won't work in `/sdcard`](#git-wont-work-in-sdcard)
+ - [Many extensions including language packs fail to install](#many-extensions-including-language-packs-fail-to-install)
+- [Extra](#extra)
+ - [Keyboard Shortcuts and Tab Key](#keyboard-shortcuts-and-tab-key)
+ - [Create a new user](#create-a-new-user)
+ - [Install Go](#install-go)
+ - [Install Python](#install-python)
+
+
+
+
+## Install
+
+1. Get [Termux](https://f-droid.org/en/packages/com.termux/) from **F-Droid**.
+2. Run `pkg install tur-repo`
+3. Run `pkg install code-server`
+4. You can now start code server by simply running `code-server`.
+
+## NPM Installation
+
+1. Get [Termux](https://f-droid.org/en/packages/com.termux/) from **F-Droid**.
+
+2. We will now change using the following command.
+
+```sh
+termux-change-repo
+```
+
+Now select `Main Repository` then change repo to `Mirrors by Grimler Hosted on grimler.se`.
+
+3. After successfully updating of repository update and upgrade all the packages by the following command
+
+```sh
+pkg update
+pkg upgrade -y
+```
+
+4. Now let's install requirement dependancy.
+
+```sh
+pkg install -y \
+ build-essential \
+ binutils \
+ pkg-config \
+ python3 \
+ nodejs-lts
+npm config set python python3
+node -v
+```
+
+you will get Node version `v22`
+
+5. Now install code-server following our guide on [installing with npm](./npm.md)
+
+6. Congratulation code-server is installed on your device using the following command.
+
+```sh
+code-server --auth none
+```
+
+7. If already installed then use the following command for upgradation.
+
+```
+npm update --global code-server
+```
+
+## Upgrade
+
+1. Remove all previous installs `rm -rf ~/.local/lib/code-server-*`
+2. Run the install script again `curl -fsSL https://code-server.dev/install.sh | sh`
+
+## Known Issues
+
+### Git won't work in `/sdcard`
+
+Issue : Using git in the `/sdcard` directory will fail during cloning/commit/staging/etc...\
+Fix : None\
+Potential Workaround :
+
+1. Create a soft-link from the debian-fs to your folder in `/sdcard`
+2. Use git from termux (preferred)
+
+### Many extensions including language packs fail to install
+
+Issue: Android is not seen as a Linux environment but as a separate, unsupported platform, so code-server only allows [Web Extensions](https://code.visualstudio.com/api/extension-guides/web-extensions), refusing to download extensions that run on the server.\
+Fix: None\
+Potential workarounds :
+
+Either
+
+- Manually download extensions as `.vsix` file and install them via `Extensions: Install from VSIX...` in the Command Palette.
+
+- Use an override to pretend the platform is Linux:
+
+Create a JS script that patches `process.platform`:
+
+```js
+// android-as-linux.js
+Object.defineProperty(process, "platform", {
+ get() {
+ return "linux"
+ },
+})
+```
+
+Then use Node's `--require` option to make sure it is loaded before `code-server` starts:
+
+```sh
+NODE_OPTIONS="--require /path/to/android-as-linux.js" code-server
+```
+
+⚠️ Note that Android and Linux are not 100% compatible, so use these workarounds at your own risk. Extensions that have native dependencies other than Node or that directly interact with the OS might cause issues.
+
+## Extra
+
+### Keyboard Shortcuts and Tab Key
+
+In order to support the tab key and use keyboard shortcuts, add this to your
+settings.json:
+
+```json
+{
+ "keyboard.dispatch": "keyCode"
+}
+```
+
+### Create a new user
+
+To create a new user follow these simple steps -
+
+1. Create a new user by running `useradd -m`.
+2. Change the password by running `passwd `.
+3. Give your new user sudo access by running `visudo`, scroll down to `User privilege specification` and add the following line after root `username ALL=(ALL:ALL) ALL`.
+4. Now edit the `/etc/passwd` file with your command line editor of choice and at the end of the line that specifies your user change `/bin/sh` to `/bin/bash`.
+5. Now switch users by running `su - `
+
+- Remember the `-` betweeen `su` and username is required to execute `/etc/profile`,\
+ since `/etc/profile` may have some necessary things to be executed you should always add a `-`.
+
+### Install Go
+
+> From https://golang.org/doc/install
+
+1. Go to https://golang.org/dl/ and copy the download link for `linux arm` and run the following:
+
+```bash
+wget download_link
+```
+
+2. Extract the downloaded archive. (This step will erase all previous GO installs, make sure to create a backup if you have previously installed GO)
+
+```bash
+rm -rf /usr/local/go && tar -C /usr/local -xzf archive_name
+```
+
+3. Run `nano /etc/profile` and add the following line `export PATH=$PATH:/usr/local/go/bin`.
+4. Now run `exit` (depending on if you have switched users or not, you may have to run `exit` multiple times to get to normal termux shell) and start Debian again.
+5. Check if your install was successful by running `go version`
+
+### Install Python
+
+> Run these commands as root
+
+1. Run the following commands to install required packages to build python:
+
+```bash
+sudo apt-get update
+sudo apt-get install make build-essential libssl-dev zlib1g-dev \
+ libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
+ libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
+```
+
+2. Install [pyenv](https://github.com/pyenv/pyenv/) from [pyenv-installer](https://github.com/pyenv/pyenv-installer) by running:
+
+```bash
+curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
+```
+
+3. Run `nano /etc/profile` and add the following:
+
+```bash
+export PYENV_ROOT="/root/.pyenv"
+export PATH="/root/.pyenv/bin:$PATH"
+eval "$(pyenv init --path)"
+eval "$(pyenv virtualenv-init -)"
+```
+
+4. Exit and start Debian again.
+5. Run `pyenv versions` to list all installable versions.
+6. Run `pyenv install version` to install the desired python version.
+ > The build process may take some time (an hour or 2 depending on your device).
+7. Run `touch /root/.pyenv/version && echo "your_version_here" > /root/.pyenv/version`
+8. (You may have to start Debian again) Run `python3 -V` to verify if PATH works or not.
+ > If `python3` doesn't work but pyenv says that the install was successful in step 6 then try running `$PYENV_ROOT/versions/your_version/bin/python3`.
diff --git a/docs/triage.md b/docs/triage.md
new file mode 100644
index 000000000000..6d4120f97209
--- /dev/null
+++ b/docs/triage.md
@@ -0,0 +1,35 @@
+# Triage
+
+Triaging code-server issues is done with the following issue filter:
+
+```text
+is:issue is:open no:project sort:created-asc -label:blocked -label:upstream -label:waiting-for-info -label:extension-request
+```
+
+This will show issues that:
+
+1. Are open.
+1. Have no assigned project.
+1. Are not `blocked` or tagged for work by `upstream` (the VS Code core team).
+ If an upstream issue is detrimental to the code-server experience we may fix
+ it in our patch instead of waiting for the VS Code team to fix it. Someone
+ should periodically go through these issues to see if they can be unblocked!
+1. Are not labeled `waiting-for-info`.
+1. Are not extension requests.
+
+## Triage process
+
+1. If an issue is a question/discussion, it should be converted into a GitHub
+ discussion.
+1. Otherwise, give the issue the appropriate labels (feel free to create new
+ ones if necessary). There are no hard and set rules for labels. We don't have
+ many so look through and see how they've been used throughout the repository.
+ They all also have descriptions.
+1. If more information is required, please ask the submitter and tag as
+ `waiting-for-info` and wait.
+1. Finally, the issue should be moved into the
+ [code-server](https://github.com/coder/code-server/projects/1) project where we
+ pick out issues to fix and track their progress.
+
+We also use [milestones](https://github.com/coder/code-server/milestones) to track
+what issues are planned/or were closed for what release.
diff --git a/docs/upgrade.md b/docs/upgrade.md
new file mode 100644
index 000000000000..f4f90e6ce044
--- /dev/null
+++ b/docs/upgrade.md
@@ -0,0 +1,5 @@
+# Upgrade
+
+To upgrade code-server, install the new version over the old version. All user
+data is in `~/.local/share/code-server`, so they are preserved between
+installations.
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 000000000000..b13ebc0dc4de
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,84 @@
+import { fixupConfigRules } from "@eslint/compat"
+import globals from "globals"
+import tsParser from "@typescript-eslint/parser"
+import path from "node:path"
+import { fileURLToPath } from "node:url"
+import js from "@eslint/js"
+import { FlatCompat } from "@eslint/eslintrc"
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+const compat = new FlatCompat({
+ baseDirectory: __dirname,
+ recommendedConfig: js.configs.recommended,
+ allConfig: js.configs.all,
+})
+
+export default [
+ ...fixupConfigRules(
+ compat.extends(
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:import/recommended",
+ "plugin:import/typescript",
+ "plugin:prettier/recommended",
+ "prettier",
+ ),
+ ),
+ {
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ ...globals.jest,
+ ...globals.node,
+ },
+
+ parser: tsParser,
+ ecmaVersion: 2018,
+ sourceType: "module",
+ },
+
+ settings: {
+ "import/resolver": {
+ typescript: {
+ alwaysTryTypes: true,
+ },
+ },
+ },
+
+ rules: {
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ args: "none",
+ },
+ ],
+
+ "no-dupe-class-members": "off",
+ "@typescript-eslint/no-use-before-define": "off",
+ "@typescript-eslint/no-non-null-assertion": "off",
+ "@typescript-eslint/ban-types": "off",
+ "@typescript-eslint/no-var-requires": "off",
+ "@typescript-eslint/explicit-module-boundary-types": "off",
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/no-extra-semi": "off",
+ "@typescript-eslint/no-require-imports": "off",
+ "@typescript-eslint/no-unused-vars": "off", // TODO: Fix these.
+ "@typescript-eslint/no-empty-object-type": "off",
+ eqeqeq: "error",
+
+ "import/order": [
+ "error",
+ {
+ alphabetize: {
+ order: "asc",
+ },
+
+ groups: [["builtin", "external", "internal"], "parent", "sibling"],
+ },
+ ],
+
+ "no-async-promise-executor": "off",
+ },
+ },
+]
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 000000000000..948f73585131
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,61 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1739303263,
+ "narHash": "sha256-c/Z/6gZLN8BIpYh1B3qMzEn0TArjf4F2lmy59lDLVBM=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "6cc4213488e886db863878a1e3dc26cc932d38b8",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-unstable-small",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 000000000000..3a1f7efbc122
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,37 @@
+{
+ description = "code-server";
+
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable-small";
+ flake-utils.url = "github:numtide/flake-utils";
+ };
+
+ outputs = { self, nixpkgs, flake-utils }:
+ flake-utils.lib.eachDefaultSystem
+ (system:
+ let pkgs = nixpkgs.legacyPackages.${system};
+ nodejs = pkgs.nodejs_22;
+ in {
+ devShells.default = pkgs.mkShell {
+ nativeBuildInputs = with pkgs; [
+ imagemagick
+ nodejs
+ python3
+ pkg-config
+ git
+ rsync
+ jq
+ moreutils
+ quilt
+ bats
+ openssl
+ ];
+ buildInputs = with pkgs; (lib.optionals (!stdenv.isDarwin) [ libsecret libkrb5 ]
+ ++ (with xorg; [ libX11 libxkbfile ])
+ ++ lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [
+ AppKit Cocoa CoreServices Security xcbuild
+ ]));
+ };
+ }
+ );
+}
diff --git a/install.sh b/install.sh
index 2c0240297a22..81c1ce68edcd 100755
--- a/install.sh
+++ b/install.sh
@@ -2,7 +2,7 @@
set -eu
# code-server's automatic install script.
-# See https://github.com/cdr/code-server/blob/master/doc/install.md
+# See https://coder.com/docs/code-server/latest/install
usage() {
arg0="$0"
@@ -14,7 +14,7 @@ usage() {
fi
cath << EOF
-Installs code-server for Linux, macOS and FreeBSD.
+Installs code-server.
It tries to use the system package manager if possible.
After successful installation it explains how to start using code-server.
@@ -23,7 +23,7 @@ The remote host must have internet access.
${not_curl_usage-}
Usage:
- $arg0 [--dry-run] [--version X.X.X] [--method detect] \
+ $arg0 [--dry-run] [--version X.X.X] [--edge] [--method detect] \
[--prefix ~/.local] [--rsh ssh] [user@host]
--dry-run
@@ -32,6 +32,9 @@ Usage:
--version X.X.X
Install a specific version instead of the latest.
+ --edge
+ Install the latest edge version instead of the latest stable version.
+
--method [detect | standalone]
Choose the installation method. Defaults to detect.
- detect detects the system package manager and tries to use it.
@@ -43,49 +46,75 @@ Usage:
Sets the prefix used by standalone release archives. Defaults to ~/.local
The release is unarchived into ~/.local/lib/code-server-X.X.X
and the binary symlinked into ~/.local/bin/code-server
- To install system wide pass ---prefix=/usr/local
+ To install system wide pass --prefix=/usr/local
--rsh
Specifies the remote shell for remote installation. Defaults to ssh.
-- For Debian, Ubuntu and Raspbian it will install the latest deb package.
-- For Fedora, CentOS, RHEL and openSUSE it will install the latest rpm package.
-- For Arch Linux it will install the AUR package.
-- For any unrecognized Linux operating system it will install the latest standalone
- release into ~/.local
-
-- For macOS it will install the Homebrew package.
- - If Homebrew is not installed it will install the latest standalone release
- into ~/.local
+The detection method works as follows:
+ - Debian, Ubuntu, Raspbian: install the deb package from GitHub.
+ - Fedora, CentOS, RHEL, openSUSE: install the rpm package from GitHub.
+ - Arch Linux: install from the AUR (which pulls releases from GitHub).
+ - FreeBSD, Alpine: install from npm.
+ - macOS: install using Homebrew if installed otherwise install from GitHub.
+ - All others: install the release from GitHub.
-- For FreeBSD, it will install the npm package with yarn or npm.
+We only build releases on GitHub for amd64 and arm64 on Linux and amd64 for
+macOS. When the detection method tries to pull a release from GitHub it will
+fall back to installing from npm when there is no matching release for the
+system's operating system and architecture.
-- If ran on an architecture with no releases, it will install the
- npm package with yarn or npm.
- - We only have releases for amd64 and arm64 presently.
- - The npm package builds the native modules on postinstall.
+The standalone method will force installion using GitHub releases. It will not
+fall back to npm so on architectures without pre-built releases this will error.
-It will cache all downloaded assets into ~/.cache/code-server
+The installer will cache all downloaded assets into ~/.cache/code-server
-More installation docs are at https://github.com/cdr/code-server/blob/master/doc/install.md
+More installation docs are at https://coder.com/docs/code-server/latest/install
EOF
}
echo_latest_version() {
- # https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860
- version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/cdr/code-server/releases/latest)"
- version="${version#https://github.com/cdr/code-server/releases/tag/}"
+ if [ "${EDGE-}" ]; then
+ version="$(curl -fsSL https://api.github.com/repos/coder/code-server/releases | awk 'match($0,/.*"html_url": "(.*\/releases\/tag\/.*)".*/)' | head -n 1 | awk -F '"' '{print $4}')"
+ else
+ # https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860
+ version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/coder/code-server/releases/latest)"
+ fi
+ version="${version#https://github.com/coder/code-server/releases/tag/}"
version="${version#v}"
echo "$version"
}
+echo_npm_postinstall() {
+ echoh
+ cath << EOF
+npm package has been installed.
+
+Extend your path to use code-server:
+ PATH="$NPM_BIN_DIR:\$PATH"
+Then run with:
+ code-server
+EOF
+}
+
echo_standalone_postinstall() {
echoh
cath << EOF
Standalone release has been installed into $STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION
-Please extend your path to use code-server:
+
+Extend your path to use code-server:
PATH="$STANDALONE_INSTALL_PREFIX/bin:\$PATH"
-Then you can run:
+Then run with:
+ code-server
+EOF
+}
+
+echo_brew_postinstall() {
+ echoh
+ cath << EOF
+Brew release has been installed.
+
+Run with:
code-server
EOF
}
@@ -93,6 +122,8 @@ EOF
echo_systemd_postinstall() {
echoh
cath << EOF
+$1 package has been installed.
+
To have systemd start code-server now and restart on boot:
sudo systemctl enable --now code-server@\$USER
Or, if you don't want/need a background service you can run:
@@ -100,6 +131,11 @@ Or, if you don't want/need a background service you can run:
EOF
}
+echo_coder_postinstall() {
+ echoh
+ echoh "Deploy code-server for your team with Coder: https://github.com/coder/coder"
+}
+
main() {
if [ "${TRACE-}" ]; then
set -x
@@ -108,73 +144,75 @@ main() {
unset \
DRY_RUN \
METHOD \
- STANDALONE_INSTALL_PREFIX \
- VERSION \
OPTIONAL \
ALL_FLAGS \
RSH_ARGS \
+ EDGE \
RSH
ALL_FLAGS=""
while [ "$#" -gt 0 ]; do
case "$1" in
- -*)
- ALL_FLAGS="${ALL_FLAGS} $1"
- ;;
+ -*)
+ ALL_FLAGS="${ALL_FLAGS} $1"
+ ;;
esac
case "$1" in
- --dry-run)
- DRY_RUN=1
- ;;
- --method)
- METHOD="$(parse_arg "$@")"
- shift
- ;;
- --method=*)
- METHOD="$(parse_arg "$@")"
- ;;
- --prefix)
- STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
- shift
- ;;
- --prefix=*)
- STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
- ;;
- --version)
- VERSION="$(parse_arg "$@")"
- shift
- ;;
- --version=*)
- VERSION="$(parse_arg "$@")"
- ;;
- --rsh)
- RSH="$(parse_arg "$@")"
- shift
- ;;
- --rsh=*)
- RSH="$(parse_arg "$@")"
- ;;
- -h | --h | -help | --help)
- usage
- exit 0
- ;;
- --)
- shift
- # We remove the -- added above.
- ALL_FLAGS="${ALL_FLAGS% --}"
- RSH_ARGS="$*"
- break
- ;;
- -*)
- echoerr "Unknown flag $1"
- echoerr "Run with --help to see usage."
- exit 1
- ;;
- *)
- RSH_ARGS="$*"
- break
- ;;
+ --dry-run)
+ DRY_RUN=1
+ ;;
+ --method)
+ METHOD="$(parse_arg "$@")"
+ shift
+ ;;
+ --method=*)
+ METHOD="$(parse_arg "$@")"
+ ;;
+ --prefix)
+ STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
+ shift
+ ;;
+ --prefix=*)
+ STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
+ ;;
+ --version)
+ VERSION="$(parse_arg "$@")"
+ shift
+ ;;
+ --version=*)
+ VERSION="$(parse_arg "$@")"
+ ;;
+ --edge)
+ EDGE=1
+ ;;
+ --rsh)
+ RSH="$(parse_arg "$@")"
+ shift
+ ;;
+ --rsh=*)
+ RSH="$(parse_arg "$@")"
+ ;;
+ -h | --h | -help | --help)
+ usage
+ exit 0
+ ;;
+ --)
+ shift
+ # We remove the -- added above.
+ ALL_FLAGS="${ALL_FLAGS% --}"
+ RSH_ARGS="$*"
+ break
+ ;;
+ -*)
+ echoerr "Unknown flag $1"
+ echoerr "Run with --help to see usage."
+ exit 1
+ ;;
+ *)
+ RSH_ARGS="$*"
+ break
+ ;;
esac
shift
@@ -187,102 +225,106 @@ main() {
return
fi
- VERSION="${VERSION-$(echo_latest_version)}"
METHOD="${METHOD-detect}"
if [ "$METHOD" != detect ] && [ "$METHOD" != standalone ]; then
echoerr "Unknown install method \"$METHOD\""
echoerr "Run with --help to see usage."
exit 1
fi
- STANDALONE_INSTALL_PREFIX="${STANDALONE_INSTALL_PREFIX-$HOME/.local}"
- OS="$(os)"
- if [ ! "$OS" ]; then
- echoerr "Unsupported OS $(uname)."
- exit 1
- fi
+ # These are used by the various install_* functions that make use of GitHub
+ # releases in order to download and unpack the right release.
+ CACHE_DIR=$(echo_cache_dir)
+ STANDALONE_INSTALL_PREFIX=${STANDALONE_INSTALL_PREFIX:-$HOME/.local}
+ VERSION=${VERSION:-$(echo_latest_version)}
+ # These can be overridden for testing but shouldn't normally be used as it can
+ # result in a broken code-server.
+ OS=${OS:-$(os)}
+ ARCH=${ARCH:-$(arch)}
distro_name
- ARCH="$(arch)"
- if [ ! "$ARCH" ]; then
- if [ "$METHOD" = standalone ]; then
- echoerr "No precompiled releases for $(uname -m)."
- echoerr 'Please rerun without the "--method standalone" flag to install from npm.'
- exit 1
- fi
- echoh "No precompiled releases for $(uname -m)."
- install_npm
- return
- fi
-
- if [ "$OS" = "freebsd" ]; then
- if [ "$METHOD" = standalone ]; then
- echoerr "No precompiled releases available for $OS."
- echoerr 'Please rerun without the "--method standalone" flag to install from npm.'
+ # Standalone installs by pulling pre-built releases from GitHub.
+ if [ "$METHOD" = standalone ]; then
+ if has_standalone; then
+ install_standalone
+ echo_coder_postinstall
+ exit 0
+ else
+ echoerr "There are no standalone releases for $ARCH"
+ echoerr "Please try again without '--method standalone'"
exit 1
fi
- echoh "No precompiled releases available for $OS."
- install_npm
- return
- fi
-
- CACHE_DIR="$(echo_cache_dir)"
-
- if [ "$METHOD" = standalone ]; then
- install_standalone
- return
fi
- case "$(distro)" in
- macos)
- install_macos
- ;;
- ubuntu | debian | raspbian)
- install_deb
- ;;
- centos | fedora | rhel | opensuse)
- install_rpm
- ;;
- arch)
- install_aur
- ;;
- *)
- echoh "Unsupported package manager."
- install_standalone
- ;;
+ # DISTRO can be overridden for testing but shouldn't normally be used as it
+ # can result in a broken code-server.
+ DISTRO=${DISTRO:-$(distro)}
+
+ case $DISTRO in
+ # macOS uses brew when available and falls back to standalone. We only have
+ # amd64 for macOS so for anything else use npm.
+ macos)
+ BREW_PATH="${BREW_PATH-brew}"
+ if command_exists "$BREW_PATH"; then
+ install_brew
+ else
+ echoh "Homebrew not installed."
+ echoh "Falling back to standalone installation."
+ npm_fallback install_standalone
+ fi
+ ;;
+ # The .deb and .rpm files are pulled from GitHub and we only have amd64 and
+ # arm64 there and need to fall back to npm otherwise.
+ debian) npm_fallback install_deb ;;
+ fedora | opensuse) npm_fallback install_rpm ;;
+ # Arch uses the AUR package which only supports amd64 and arm64 since it
+ # pulls releases from GitHub so we need to fall back to npm.
+ arch) npm_fallback install_aur ;;
+ # We don't have GitHub releases that work on Alpine or FreeBSD so we have no
+ # choice but to use npm here.
+ alpine | freebsd) install_npm ;;
+ # For anything else we'll try to install standalone but fall back to npm if
+ # we don't have releases for the architecture.
+ *)
+ echoh "Unsupported package manager."
+ echoh "Falling back to standalone installation."
+ npm_fallback install_standalone
+ ;;
esac
+
+ echo_coder_postinstall
}
parse_arg() {
case "$1" in
- *=*)
- # Remove everything after first equal sign.
- opt="${1%%=*}"
- # Remove everything before first equal sign.
- optarg="${1#*=}"
- if [ ! "$optarg" ] && [ ! "${OPTIONAL-}" ]; then
- echoerr "$opt requires an argument"
- echoerr "Run with --help to see usage."
- exit 1
- fi
- echo "$optarg"
- return
- ;;
+ *=*)
+ # Remove everything after first equal sign.
+ opt="${1%%=*}"
+ # Remove everything before first equal sign.
+ optarg="${1#*=}"
+ if [ ! "$optarg" ] && [ ! "${OPTIONAL-}" ]; then
+ echoerr "$opt requires an argument"
+ echoerr "Run with --help to see usage."
+ exit 1
+ fi
+ echo "$optarg"
+ return
+ ;;
esac
case "${2-}" in
- "" | -*)
- if [ ! "${OPTIONAL-}" ]; then
- echoerr "$1 requires an argument"
- echoerr "Run with --help to see usage."
- exit 1
- fi
- ;;
- *)
- echo "$2"
- return
- ;;
+ "" | -*)
+ if [ ! "${OPTIONAL-}" ]; then
+ echoerr "$1 requires an argument"
+ echoerr "Run with --help to see usage."
+ exit 1
+ fi
+ ;;
+ *)
+ echo "$2"
+ return
+ ;;
esac
}
@@ -304,45 +346,39 @@ fetch() {
sh_c mv "$FILE.incomplete" "$FILE"
}
-install_macos() {
- if command_exists brew; then
- echoh "Installing from Homebrew."
- echoh
-
- sh_c brew install code-server
-
- return
- fi
+install_brew() {
+ echoh "Installing latest from Homebrew."
+ echoh
- echoh "Homebrew not installed."
+ sh_c "$BREW_PATH" install code-server
- install_standalone
+ echo_brew_postinstall
}
install_deb() {
- echoh "Installing v$VERSION deb package from GitHub releases."
+ echoh "Installing v$VERSION of the $ARCH deb package from GitHub."
echoh
- fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server_${VERSION}_$ARCH.deb" \
+ fetch "https://github.com/coder/code-server/releases/download/v$VERSION/code-server_${VERSION}_$ARCH.deb" \
"$CACHE_DIR/code-server_${VERSION}_$ARCH.deb"
sudo_sh_c dpkg -i "$CACHE_DIR/code-server_${VERSION}_$ARCH.deb"
- echo_systemd_postinstall
+ echo_systemd_postinstall deb
}
install_rpm() {
- echoh "Installing v$VERSION rpm package from GitHub releases."
+ echoh "Installing v$VERSION of the $ARCH rpm package from GitHub."
echoh
- fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$ARCH.rpm" \
+ fetch "https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-$ARCH.rpm" \
"$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"
- sudo_sh_c rpm -i "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"
+ sudo_sh_c rpm -U "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"
- echo_systemd_postinstall
+ echo_systemd_postinstall rpm
}
install_aur() {
- echoh "Installing from the AUR."
+ echoh "Installing latest from the AUR."
echoh
sh_c mkdir -p "$CACHE_DIR/code-server-aur"
@@ -351,18 +387,22 @@ install_aur() {
if [ ! "${DRY_RUN-}" ]; then
cd "$CACHE_DIR/code-server-aur"
fi
- sh_c makepkg -si
+ sh_c makepkg -si --noconfirm
- echo_systemd_postinstall
+ echo_systemd_postinstall AUR
}
install_standalone() {
- echoh "Installing standalone release archive v$VERSION from GitHub releases."
+ echoh "Installing v$VERSION of the $ARCH release from GitHub."
echoh
- fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$OS-$ARCH.tar.gz" \
+ fetch "https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-$OS-$ARCH.tar.gz" \
"$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz"
+ # -w only works if the directory exists so try creating it first. If this
+ # fails we can ignore the error as the -w check will then swap us to sudo.
+ sh_c mkdir -p "$STANDALONE_INSTALL_PREFIX" 2> /dev/null || true
+
sh_c="sh_c"
if [ ! -w "$STANDALONE_INSTALL_PREFIX" ]; then
sh_c="sudo_sh_c"
@@ -384,55 +424,73 @@ install_standalone() {
}
install_npm() {
- if command_exists yarn; then
- sh_c="sh_c"
- if [ ! -w "$(yarn global bin)" ]; then
- sh_c="sudo_sh_c"
- fi
- echoh "Installing with yarn."
- echoh
- "$sh_c" yarn global add code-server --unsafe-perm
- return
- elif command_exists npm; then
+ echoh "Installing v$VERSION from npm."
+ echoh
+
+ NPM_PATH="${YARN_PATH-npm}"
+
+ if command_exists "$NPM_PATH"; then
sh_c="sh_c"
- if [ ! -w "$(npm config get prefix)" ]; then
+ if [ ! "${DRY_RUN-}" ] && [ ! -w "$(NPM_PATH config get prefix)" ]; then
sh_c="sudo_sh_c"
fi
echoh "Installing with npm."
echoh
- "$sh_c" npm install -g code-server --unsafe-perm
+ "$sh_c" "$NPM_PATH" install -g "code-server@$VERSION" --unsafe-perm
+ NPM_BIN_DIR="\$($NPM_PATH bin -g)" echo_npm_postinstall
return
fi
- echoh
- echoerr "Please install npm or yarn to install code-server!"
- echoerr "You will need at least node v12 and a few C dependencies."
- echoerr "See the docs https://github.com/cdr/code-server#yarn-npm"
+ echoerr "Please install npm to install code-server!"
+ echoerr "You will need at least node v20 and a few C dependencies."
+ echoerr "See the docs https://coder.com/docs/code-server/latest/install#npm"
+
exit 1
}
+# Run $1 if we have a standalone otherwise run install_npm.
+npm_fallback() {
+ if has_standalone; then
+ $1
+ else
+ echoh "No standalone releases for $ARCH."
+ echoh "Falling back to installation from npm."
+ install_npm
+ fi
+}
+
+# Determine if we have standalone releases on GitHub for the system's arch.
+has_standalone() {
+ case $ARCH in
+ arm64) return 0 ;;
+ # We only have arm64 for macOS.
+ amd64)
+ [ "$(distro)" != macos ]
+ return
+ ;;
+ *) return 1 ;;
+ esac
+}
+
os() {
- case "$(uname)" in
- Linux)
- echo linux
- ;;
- Darwin)
- echo macos
- ;;
- FreeBSD)
- echo freebsd
- ;;
+ uname="$(uname)"
+ case $uname in
+ Linux) echo linux ;;
+ Darwin) echo macos ;;
+ FreeBSD) echo freebsd ;;
+ *) echo "$uname" ;;
esac
}
-# distro prints the detected operating system including linux distros.
+# Print the detected Linux distro, otherwise print the OS name.
#
# Example outputs:
-# - macos
-# - debian, ubuntu, raspbian
-# - centos, fedora, rhel, opensuse
-# - alpine
-# - arch
-# - freebsd
+# - macos -> macos
+# - freebsd -> freebsd
+# - ubuntu, raspbian, debian ... -> debian
+# - amzn, centos, rhel, fedora, ... -> fedora
+# - opensuse-{leap,tumbleweed} -> opensuse
+# - alpine -> alpine
+# - arch, manjaro, endeavouros, ... -> arch
#
# Inspired by https://github.com/docker/docker-install/blob/26ff363bcf3b3f5a00498ac43694bf1c7d9ce16c/install.sh#L111-L120.
distro() {
@@ -444,12 +502,15 @@ distro() {
if [ -f /etc/os-release ]; then
(
. /etc/os-release
- case "$ID" in opensuse-*)
- # opensuse's ID's look like opensuse-leap and opensuse-tumbleweed.
- echo "opensuse"
- return
- ;;
- esac
+ if [ "${ID_LIKE-}" ]; then
+ for id_like in $ID_LIKE; do
+ case "$id_like" in debian | fedora | opensuse | arch)
+ echo "$id_like"
+ return
+ ;;
+ esac
+ done
+ fi
echo "$ID"
)
@@ -457,7 +518,7 @@ distro() {
fi
}
-# os_name prints a pretty human readable name for the OS/Distro.
+# Print a human-readable name for the OS/distro.
distro_name() {
if [ "$(uname)" = "Darwin" ]; then
echo "macOS v$(sw_vers -productVersion)"
@@ -477,20 +538,16 @@ distro_name() {
}
arch() {
- case "$(uname -m)" in
- aarch64)
- echo arm64
- ;;
- x86_64)
- echo amd64
- ;;
- amd64) # FreeBSD.
- echo amd64
- ;;
+ uname_m=$(uname -m)
+ case $uname_m in
+ aarch64) echo arm64 ;;
+ x86_64) echo amd64 ;;
+ *) echo "$uname_m" ;;
esac
}
command_exists() {
+ if [ ! "$1" ]; then return 1; fi
command -v "$@" > /dev/null
}
@@ -504,15 +561,17 @@ sh_c() {
sudo_sh_c() {
if [ "$(id -u)" = 0 ]; then
sh_c "$@"
+ elif command_exists doas; then
+ sh_c "doas $*"
elif command_exists sudo; then
sh_c "sudo $*"
elif command_exists su; then
- sh_c "su -c '$*'"
+ sh_c "su root -c '$*'"
else
echoh
echoerr "This script needs to run the following command as root."
echoerr " $*"
- echoerr "Please install sudo or su."
+ echoerr "Please install doas, sudo, or su."
exit 1
fi
}
@@ -539,8 +598,8 @@ echoerr() {
echoh "$@" >&2
}
-# humanpath replaces all occurances of " $HOME" with " ~"
-# and all occurances of '"$HOME' with the literal '"$HOME'.
+# humanpath replaces all occurrences of " $HOME" with " ~"
+# and all occurrences of '"$HOME' with the literal '"$HOME'.
humanpath() {
sed "s# $HOME# ~#g; s#\"$HOME#\"\$HOME#g"
}
diff --git a/lib/vscode b/lib/vscode
index e5a624b788d9..987c95975162 160000
--- a/lib/vscode
+++ b/lib/vscode
@@ -1 +1 @@
-Subproject commit e5a624b788d92b8d34d1392e4c4d9789406efe8f
+Subproject commit 987c9597516278c9fcf10d963a0592ce1384ab93
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000000..7eb7efe953d4
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6680 @@
+{
+ "name": "code-server",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "code-server",
+ "version": "0.0.0",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@coder/logger": "^3.0.1",
+ "argon2": "^0.44.0",
+ "compression": "^1.7.4",
+ "cookie-parser": "^1.4.6",
+ "env-paths": "^2.2.1",
+ "express": "^5.0.1",
+ "http-proxy": "^1.18.1",
+ "httpolyglot": "^0.1.2",
+ "i18next": "^25.8.3",
+ "js-yaml": "^4.1.0",
+ "limiter": "^2.1.0",
+ "pem": "^1.14.8",
+ "proxy-agent": "^6.3.1",
+ "qs": "^6.15.0",
+ "rotating-file-stream": "^3.1.1",
+ "safe-compare": "^1.1.4",
+ "semver": "^7.5.4",
+ "ws": "^8.14.2",
+ "xdg-basedir": "^4.0.0"
+ },
+ "bin": {
+ "code-server": "out/node/entry.js"
+ },
+ "devDependencies": {
+ "@eslint/compat": "^1.2.0",
+ "@eslint/eslintrc": "^3.1.0",
+ "@eslint/js": "^9.12.0",
+ "@schemastore/package": "^0.0.10",
+ "@types/compression": "^1.7.3",
+ "@types/cookie-parser": "^1.4.4",
+ "@types/eslint__js": "^8.42.3",
+ "@types/express": "^5.0.0",
+ "@types/http-proxy": "1.17.7",
+ "@types/js-yaml": "^4.0.6",
+ "@types/node": "22.x",
+ "@types/pem": "^1.14.1",
+ "@types/proxy-from-env": "^1.0.1",
+ "@types/safe-compare": "^1.1.0",
+ "@types/semver": "^7.5.2",
+ "@types/trusted-types": "^2.0.4",
+ "@types/ws": "^8.5.5",
+ "doctoc": "^2.2.1",
+ "eslint": "^9.12.0",
+ "eslint-config-prettier": "^10.1.8",
+ "eslint-import-resolver-typescript": "^4.4.4",
+ "eslint-plugin-import": "^2.28.1",
+ "eslint-plugin-prettier": "^5.0.0",
+ "globals": "^16.1.0",
+ "prettier": "3.8.3",
+ "prettier-plugin-sh": "^0.18.0",
+ "ts-node": "^10.9.1",
+ "typescript": "^5.6.2",
+ "typescript-eslint": "^8.8.0"
+ },
+ "engines": {
+ "node": "22"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
+ "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@coder/logger": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@coder/logger/-/logger-3.0.1.tgz",
+ "integrity": "sha512-G/wWSaNZW8HvQZWXlXdbZbp/MOQBPH4W1AKSEI3PBfr0qc9G+pdLrXvm3XakQpNVqmD6WFAbLfcjdG0BuoAO0g==",
+ "license": "MIT"
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@emnapi/core": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz",
+ "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.1.0",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
+ "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
+ "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@epic-web/invariant": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
+ "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
+ "license": "MIT"
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/compat": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.4.1.tgz",
+ "integrity": "sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "peerDependencies": {
+ "eslint": "^8.40 || 9"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.21.1",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
+ "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.7",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
+ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.4.tgz",
+ "integrity": "sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.14.0",
+ "debug": "^4.3.2",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.1",
+ "minimatch": "^3.1.3",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "9.39.3",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz",
+ "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
+ "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
+ "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.7",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
+ "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.1",
+ "@humanwhocodes/retry": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
+ "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.4.3",
+ "@emnapi/runtime": "^1.4.3",
+ "@tybys/wasm-util": "^0.10.0"
+ }
+ },
+ "node_modules/@phc/format": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz",
+ "integrity": "sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@pkgr/core": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
+ "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/pkgr"
+ }
+ },
+ "node_modules/@reteps/dockerfmt": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/@reteps/dockerfmt/-/dockerfmt-0.3.6.tgz",
+ "integrity": "sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^v12.20.0 || ^14.13.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@rtsao/scc": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
+ "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@schemastore/package": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/@schemastore/package/-/package-0.0.10.tgz",
+ "integrity": "sha512-D3LxMCnkgsb4LO5sDKf6E+yahM2SqpEHmkqMPDSJis5Cy/j2MgWo/g/iq0lECK0mrPWfx3hqKm2ZJlqxwbRJQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@textlint/ast-node-types": {
+ "version": "12.6.1",
+ "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-12.6.1.tgz",
+ "integrity": "sha512-uzlJ+ZsCAyJm+lBi7j0UeBbj+Oy6w/VWoGJ3iHRHE5eZ8Z4iK66mq+PG/spupmbllLtz77OJbY89BYqgFyjXmA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@textlint/markdown-to-ast": {
+ "version": "12.6.1",
+ "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-12.6.1.tgz",
+ "integrity": "sha512-T0HO+VrU9VbLRiEx/kH4+gwGMHNMIGkp0Pok+p0I33saOOLyhfGvwOKQgvt2qkxzQEV2L5MtGB8EnW4r5d3CqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@textlint/ast-node-types": "^12.6.1",
+ "debug": "^4.3.4",
+ "mdast-util-gfm-autolink-literal": "^0.1.3",
+ "remark-footnotes": "^3.0.0",
+ "remark-frontmatter": "^3.0.0",
+ "remark-gfm": "^1.0.0",
+ "remark-parse": "^9.0.0",
+ "traverse": "^0.6.7",
+ "unified": "^9.2.2"
+ }
+ },
+ "node_modules/@tootallnate/quickjs-emscripten": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
+ "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
+ "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
+ "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.6",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
+ "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/compression": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.1.tgz",
+ "integrity": "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/cookie-parser": {
+ "version": "1.4.10",
+ "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.10.tgz",
+ "integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/express": "*"
+ }
+ },
+ "node_modules/@types/eslint": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
+ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "*",
+ "@types/json-schema": "*"
+ }
+ },
+ "node_modules/@types/eslint__js": {
+ "version": "8.42.3",
+ "resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz",
+ "integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/eslint": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/express": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz",
+ "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^5.0.0",
+ "@types/serve-static": "^2"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz",
+ "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
+ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/http-proxy": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz",
+ "integrity": "sha512-9hdj6iXH64tHSLTY+Vt2eYOGzSogC+JQ2H7bdPWkuh7KXP5qLllWx++t+K9Wk556c3dkDdPws/SpMRi0sdCT1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/js-yaml": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
+ "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json5": {
+ "version": "0.0.29",
+ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/mdast": {
+ "version": "3.0.15",
+ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz",
+ "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^2"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.19.13",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz",
+ "integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/pem": {
+ "version": "1.14.4",
+ "resolved": "https://registry.npmjs.org/@types/pem/-/pem-1.14.4.tgz",
+ "integrity": "sha512-Xt6qY6kX1RD4UmYNhWCCf3OSJrRcwbQIaJ/mQSjjAHxIjXMHx/vHNPOgEU3HdVKS1k/U5CZ6ClQlRo8egkl8xg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/proxy-from-env": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@types/proxy-from-env/-/proxy-from-env-1.0.4.tgz",
+ "integrity": "sha512-TPR9/bCZAr3V1eHN4G3LD3OLicdJjqX1QRXWuNcCYgE66f/K8jO2ZRtHxI2D9MbnuUP6+qiKSS8eUHp6TFHGCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/safe-compare": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@types/safe-compare/-/safe-compare-1.1.2.tgz",
+ "integrity": "sha512-kK/IM1+pvwCMom+Kezt/UlP8LMEwm8rP6UgGbRc6zUnhU/csoBQ5rWgmD2CJuHxiMiX+H1VqPGpo0kDluJGXYA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/semver": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/unist": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
+ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/ws": {
+ "version": "8.18.1",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
+ "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz",
+ "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.56.1",
+ "@typescript-eslint/type-utils": "8.56.1",
+ "@typescript-eslint/utils": "8.56.1",
+ "@typescript-eslint/visitor-keys": "8.56.1",
+ "ignore": "^7.0.5",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.4.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.56.1",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+ "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz",
+ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.56.1",
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/typescript-estree": "8.56.1",
+ "@typescript-eslint/visitor-keys": "8.56.1",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz",
+ "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.56.1",
+ "@typescript-eslint/types": "^8.56.1",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz",
+ "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/visitor-keys": "8.56.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/tsconfig-utils": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz",
+ "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz",
+ "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/typescript-estree": "8.56.1",
+ "@typescript-eslint/utils": "8.56.1",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.4.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz",
+ "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz",
+ "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.56.1",
+ "@typescript-eslint/tsconfig-utils": "8.56.1",
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/visitor-keys": "8.56.1",
+ "debug": "^4.4.3",
+ "minimatch": "^10.2.2",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.4.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "10.2.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
+ "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz",
+ "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.56.1",
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/typescript-estree": "8.56.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz",
+ "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.56.1",
+ "eslint-visitor-keys": "^5.0.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@unrs/resolver-binding-android-arm-eabi": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
+ "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-android-arm64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz",
+ "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-darwin-arm64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz",
+ "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-darwin-x64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz",
+ "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-freebsd-x64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz",
+ "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz",
+ "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz",
+ "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz",
+ "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm64-musl": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz",
+ "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz",
+ "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz",
+ "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz",
+ "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz",
+ "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-x64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz",
+ "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-x64-musl": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz",
+ "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-wasm32-wasi": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz",
+ "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@napi-rs/wasm-runtime": "^0.2.11"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz",
+ "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz",
+ "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-win32-x64-msvc": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz",
+ "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/accepts/node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.5",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
+ "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.11.0"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
+ "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/anchor-markdown-header": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/anchor-markdown-header/-/anchor-markdown-header-0.8.2.tgz",
+ "integrity": "sha512-ix0Hx6ARkHOsQRmt1++ZmjURq4Pr5MGXQJjh0lQ/l5jTpTURn4aqhbZ+AJMpZ/Sd3JiyNwi7KaeiF64OsMGCPg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "~10.6.0",
+ "remove-markdown": "^0.6.2"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/argon2": {
+ "version": "0.44.0",
+ "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.44.0.tgz",
+ "integrity": "sha512-zHPGN3S55sihSQo0dBbK0A5qpi2R31z7HZDZnry3ifOyj8bZZnpZND2gpmhnRGO1V/d555RwBqIK5W4Mrmv3ig==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@phc/format": "^1.0.0",
+ "cross-env": "^10.0.0",
+ "node-addon-api": "^8.5.0",
+ "node-gyp-build": "^4.8.4"
+ },
+ "engines": {
+ "node": ">=16.17.0"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "license": "Python-2.0"
+ },
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+ "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "is-array-buffer": "^3.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-includes": {
+ "version": "3.1.9",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
+ "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.24.0",
+ "es-object-atoms": "^1.1.1",
+ "get-intrinsic": "^1.3.0",
+ "is-string": "^1.1.1",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.findlastindex": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
+ "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "es-shim-unscopables": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flat": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
+ "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flatmap": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
+ "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/arraybuffer.prototype.slice": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+ "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "is-array-buffer": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ast-types": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
+ "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/async-function": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
+ "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/bail": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+ "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/basic-ftp": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.0.tgz",
+ "integrity": "sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
+ "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.3",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.7.0",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.1",
+ "raw-body": "^3.0.1",
+ "type-is": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
+ "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/buffer-alloc": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+ "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-alloc-unsafe": "^1.1.0",
+ "buffer-fill": "^1.0.0"
+ }
+ },
+ "node_modules/buffer-alloc-unsafe": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+ "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
+ "license": "MIT"
+ },
+ "node_modules/buffer-fill": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+ "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==",
+ "license": "MIT"
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
+ "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.0",
+ "es-define-property": "^1.0.0",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ccount": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz",
+ "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/character-entities": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+ "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/character-entities-legacy": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+ "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/character-reference-invalid": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+ "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/charenc": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+ "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/compressible": {
+ "version": "2.0.18",
+ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
+ "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": ">= 1.43.0 < 2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/compression": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
+ "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "compressible": "~2.0.18",
+ "debug": "2.6.9",
+ "negotiator": "~0.6.4",
+ "on-headers": "~1.1.0",
+ "safe-buffer": "5.2.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/compression/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/compression/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/content-disposition": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
+ "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-parser": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+ "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "0.7.2",
+ "cookie-signature": "1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
+ "license": "MIT"
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-env": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
+ "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
+ "license": "MIT",
+ "dependencies": {
+ "@epic-web/invariant": "^1.0.0",
+ "cross-spawn": "^7.0.6"
+ },
+ "bin": {
+ "cross-env": "dist/bin/cross-env.js",
+ "cross-env-shell": "dist/bin/cross-env-shell.js"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/crypt": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+ "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/data-uri-to-buffer": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
+ "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/data-view-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+ "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+ "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/inspect-js"
+ }
+ },
+ "node_modules/data-view-byte-offset": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+ "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/degenerator": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
+ "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ast-types": "^0.13.4",
+ "escodegen": "^2.1.0",
+ "esprima": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/diff": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz",
+ "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/doctoc": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/doctoc/-/doctoc-2.3.0.tgz",
+ "integrity": "sha512-duuDNVnRHE5mFGYlI+oDf1vguML8PIhKnbUCs7iKPHIEdzYhkCldk6MQeX3ZeXQStRtZxGspSHImtgOMQPIS4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@textlint/markdown-to-ast": "^12.1.1",
+ "anchor-markdown-header": "^0.8.2",
+ "htmlparser2": "^7.2.0",
+ "minimist": "^1.2.6",
+ "underscore": "^1.13.2",
+ "update-section": "^0.3.3"
+ },
+ "bin": {
+ "doctoc": "doctoc.js"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+ "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.0",
+ "entities": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/dom-serializer/node_modules/entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+ "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.2.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+ "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^1.0.1",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/emoji-regex": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+ "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/entities": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/es-abstract": {
+ "version": "1.24.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz",
+ "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.2",
+ "arraybuffer.prototype.slice": "^1.0.4",
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "data-view-buffer": "^1.0.2",
+ "data-view-byte-length": "^1.0.2",
+ "data-view-byte-offset": "^1.0.1",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "es-set-tostringtag": "^2.1.0",
+ "es-to-primitive": "^1.3.0",
+ "function.prototype.name": "^1.1.8",
+ "get-intrinsic": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "get-symbol-description": "^1.1.0",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "internal-slot": "^1.1.0",
+ "is-array-buffer": "^3.0.5",
+ "is-callable": "^1.2.7",
+ "is-data-view": "^1.0.2",
+ "is-negative-zero": "^2.0.3",
+ "is-regex": "^1.2.1",
+ "is-set": "^2.0.3",
+ "is-shared-array-buffer": "^1.0.4",
+ "is-string": "^1.1.1",
+ "is-typed-array": "^1.1.15",
+ "is-weakref": "^1.1.1",
+ "math-intrinsics": "^1.1.0",
+ "object-inspect": "^1.13.4",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.7",
+ "own-keys": "^1.0.1",
+ "regexp.prototype.flags": "^1.5.4",
+ "safe-array-concat": "^1.1.3",
+ "safe-push-apply": "^1.0.0",
+ "safe-regex-test": "^1.1.0",
+ "set-proto": "^1.0.0",
+ "stop-iteration-iterator": "^1.1.0",
+ "string.prototype.trim": "^1.2.10",
+ "string.prototype.trimend": "^1.0.9",
+ "string.prototype.trimstart": "^1.0.8",
+ "typed-array-buffer": "^1.0.3",
+ "typed-array-byte-length": "^1.0.3",
+ "typed-array-byte-offset": "^1.0.4",
+ "typed-array-length": "^1.0.7",
+ "unbox-primitive": "^1.1.0",
+ "which-typed-array": "^1.1.19"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-shim-unscopables": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
+ "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
+ "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7",
+ "is-date-object": "^1.0.5",
+ "is-symbol": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es6-promisify": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-7.0.0.tgz",
+ "integrity": "sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/escodegen": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+ "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esprima": "^4.0.1",
+ "estraverse": "^5.2.0",
+ "esutils": "^2.0.2"
+ },
+ "bin": {
+ "escodegen": "bin/escodegen.js",
+ "esgenerate": "bin/esgenerate.js"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "optionalDependencies": {
+ "source-map": "~0.6.1"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "9.39.3",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz",
+ "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.21.1",
+ "@eslint/config-helpers": "^0.4.2",
+ "@eslint/core": "^0.17.0",
+ "@eslint/eslintrc": "^3.3.1",
+ "@eslint/js": "9.39.3",
+ "@eslint/plugin-kit": "^0.4.1",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
+ "esquery": "^1.5.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "10.1.8",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
+ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint-config-prettier"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-import-context": {
+ "version": "0.1.9",
+ "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz",
+ "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-tsconfig": "^4.10.1",
+ "stable-hash-x": "^0.2.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint-import-context"
+ },
+ "peerDependencies": {
+ "unrs-resolver": "^1.0.0"
+ },
+ "peerDependenciesMeta": {
+ "unrs-resolver": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-import-resolver-node": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
+ "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^3.2.7",
+ "is-core-module": "^2.13.0",
+ "resolve": "^1.22.4"
+ }
+ },
+ "node_modules/eslint-import-resolver-node/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-import-resolver-typescript": {
+ "version": "4.4.4",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz",
+ "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "debug": "^4.4.1",
+ "eslint-import-context": "^0.1.8",
+ "get-tsconfig": "^4.10.1",
+ "is-bun-module": "^2.0.0",
+ "stable-hash-x": "^0.2.0",
+ "tinyglobby": "^0.2.14",
+ "unrs-resolver": "^1.7.11"
+ },
+ "engines": {
+ "node": "^16.17.0 || >=18.6.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint-import-resolver-typescript"
+ },
+ "peerDependencies": {
+ "eslint": "*",
+ "eslint-plugin-import": "*",
+ "eslint-plugin-import-x": "*"
+ },
+ "peerDependenciesMeta": {
+ "eslint-plugin-import": {
+ "optional": true
+ },
+ "eslint-plugin-import-x": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-module-utils": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
+ "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^3.2.7"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-module-utils/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-import": {
+ "version": "2.32.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
+ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rtsao/scc": "^1.1.0",
+ "array-includes": "^3.1.9",
+ "array.prototype.findlastindex": "^1.2.6",
+ "array.prototype.flat": "^1.3.3",
+ "array.prototype.flatmap": "^1.3.3",
+ "debug": "^3.2.7",
+ "doctrine": "^2.1.0",
+ "eslint-import-resolver-node": "^0.3.9",
+ "eslint-module-utils": "^2.12.1",
+ "hasown": "^2.0.2",
+ "is-core-module": "^2.16.1",
+ "is-glob": "^4.0.3",
+ "minimatch": "^3.1.2",
+ "object.fromentries": "^2.0.8",
+ "object.groupby": "^1.0.3",
+ "object.values": "^1.2.1",
+ "semver": "^6.3.1",
+ "string.prototype.trimend": "^1.0.9",
+ "tsconfig-paths": "^3.15.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/eslint-plugin-prettier": {
+ "version": "5.5.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz",
+ "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prettier-linter-helpers": "^1.0.1",
+ "synckit": "^0.11.12"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint-plugin-prettier"
+ },
+ "peerDependencies": {
+ "@types/eslint": ">=8.0.0",
+ "eslint": ">=8.0.0",
+ "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
+ "prettier": ">=3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/eslint": {
+ "optional": true
+ },
+ "eslint-config-prettier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^4.2.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "license": "MIT"
+ },
+ "node_modules/express": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
+ "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.1",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/express/node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-diff": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
+ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fault": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz",
+ "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "format": "^0.2.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
+ "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
+ "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/for-each": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/format": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
+ "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.x"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/function.prototype.name": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
+ "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "functions-have-names": "^1.2.3",
+ "hasown": "^2.0.2",
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/generator-function": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
+ "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-symbol-description": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+ "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-tsconfig": {
+ "version": "4.13.6",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz",
+ "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
+ "node_modules/get-uri": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz",
+ "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==",
+ "license": "MIT",
+ "dependencies": {
+ "basic-ftp": "^5.0.2",
+ "data-uri-to-buffer": "^6.0.2",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "16.5.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz",
+ "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-bigints": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
+ "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
+ "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
+ "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
+ "dev": true,
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.2",
+ "domutils": "^2.8.0",
+ "entities": "^3.0.1"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "license": "MIT",
+ "dependencies": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/httpolyglot": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/httpolyglot/-/httpolyglot-0.1.2.tgz",
+ "integrity": "sha512-ouHI1AaQMLgn4L224527S5+vq6hgvqPteurVfbm7ChViM3He2Wa8KP1Ny7pTYd7QKnDSPKcN8JYfC8r/lmsE3A==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/i18next": {
+ "version": "25.8.13",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.13.tgz",
+ "integrity": "sha512-E0vzjBY1yM+nsFrtgkjLhST2NBkirkvOVoQa0MSldhsuZ3jUge7ZNpuwG0Cfc74zwo5ZwRzg3uOgT+McBn32iA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://locize.com"
+ },
+ {
+ "type": "individual",
+ "url": "https://locize.com/i18next.html"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4"
+ },
+ "peerDependencies": {
+ "typescript": "^5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
+ "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/internal-slot": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
+ "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.2",
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ip-address": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
+ "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-alphabetical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+ "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-alphanumerical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+ "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-array-buffer": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+ "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-async-function": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
+ "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "async-function": "^1.0.0",
+ "call-bound": "^1.0.3",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
+ "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-bigints": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-boolean-object": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
+ "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "license": "MIT"
+ },
+ "node_modules/is-bun-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
+ "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.7.1"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-data-view": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
+ "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "get-intrinsic": "^1.2.6",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
+ "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-decimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+ "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-finalizationregistry": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+ "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-generator-function": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
+ "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.4",
+ "generator-function": "^2.0.0",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-hexadecimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+ "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+ "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+ "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-number-object": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
+ "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "license": "MIT"
+ },
+ "node_modules/is-regex": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-set": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+ "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+ "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-string": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+ "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
+ "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakmap": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+ "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
+ "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakset": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
+ "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "license": "ISC"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/just-performance": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/just-performance/-/just-performance-4.3.0.tgz",
+ "integrity": "sha512-L7RjvtJsL0QO8xFs5wEoDDzzJwoiowRw6Rn/GnvldlchS2JQr9wFYPiwZcDfrbbujEKqKN0tvENdbjXdYhDp5Q==",
+ "license": "MIT"
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/limiter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/limiter/-/limiter-2.1.0.tgz",
+ "integrity": "sha512-361TYz6iay6n+9KvUUImqdLuFigK+K79qrUtBsXhJTLdH4rIt/r1y8r1iozwh8KbZNpujbFTSh74mJ7bwbAMOw==",
+ "license": "MIT",
+ "dependencies": {
+ "just-performance": "4.3.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/longest-streak": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
+ "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+ "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/markdown-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
+ "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "repeat-string": "^1.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/md5": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
+ "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "charenc": "0.0.2",
+ "crypt": "0.0.2",
+ "is-buffer": "~1.1.6"
+ }
+ },
+ "node_modules/mdast-util-find-and-replace": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz",
+ "integrity": "sha512-9cKl33Y21lyckGzpSmEQnIDjEfeeWelN5s1kUW1LwdB0Fkuq2u+4GdqcGEygYxJE8GVqCl0741bYXHgamfWAZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^4.0.0",
+ "unist-util-is": "^4.0.0",
+ "unist-util-visit-parents": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-footnote": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/mdast-util-footnote/-/mdast-util-footnote-0.1.7.tgz",
+ "integrity": "sha512-QxNdO8qSxqbO2e3m09KwDKfWiLgqyCurdWTQ198NpbZ2hxntdc+VKS4fDJCmNWbAroUdYnSthu+XbZ8ovh8C3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-to-markdown": "^0.6.0",
+ "micromark": "~2.11.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-from-markdown": {
+ "version": "0.8.5",
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz",
+ "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-to-string": "^2.0.0",
+ "micromark": "~2.11.0",
+ "parse-entities": "^2.0.0",
+ "unist-util-stringify-position": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-frontmatter": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-0.2.0.tgz",
+ "integrity": "sha512-FHKL4w4S5fdt1KjJCwB0178WJ0evnyyQr5kXTM3wrOVpytD0hrkvd+AOOjU9Td8onOejCkmZ+HQRT3CZ3coHHQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "micromark-extension-frontmatter": "^0.2.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-0.1.2.tgz",
+ "integrity": "sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-gfm-autolink-literal": "^0.1.0",
+ "mdast-util-gfm-strikethrough": "^0.2.0",
+ "mdast-util-gfm-table": "^0.1.0",
+ "mdast-util-gfm-task-list-item": "^0.1.0",
+ "mdast-util-to-markdown": "^0.6.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-autolink-literal": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.3.tgz",
+ "integrity": "sha512-GjmLjWrXg1wqMIO9+ZsRik/s7PLwTaeCHVB7vRxUwLntZc8mzmTsLVr6HW1yLokcnhfURsn5zmSVdi3/xWWu1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ccount": "^1.0.0",
+ "mdast-util-find-and-replace": "^1.1.0",
+ "micromark": "^2.11.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-strikethrough": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz",
+ "integrity": "sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-to-markdown": "^0.6.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-table": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz",
+ "integrity": "sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "markdown-table": "^2.0.0",
+ "mdast-util-to-markdown": "~0.6.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-task-list-item": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz",
+ "integrity": "sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-to-markdown": "~0.6.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-markdown": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz",
+ "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "longest-streak": "^2.0.0",
+ "mdast-util-to-string": "^2.0.0",
+ "parse-entities": "^2.0.0",
+ "repeat-string": "^1.0.0",
+ "zwitch": "^1.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz",
+ "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/micromark": {
+ "version": "2.11.4",
+ "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz",
+ "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.0.0",
+ "parse-entities": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-extension-footnote": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/micromark-extension-footnote/-/micromark-extension-footnote-0.3.2.tgz",
+ "integrity": "sha512-gr/BeIxbIWQoUm02cIfK7mdMZ/fbroRpLsck4kvFtjbzP4yi+OPVbnukTc/zy0i7spC2xYE/dbX1Sur8BEDJsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "micromark": "~2.11.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-frontmatter": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-0.2.2.tgz",
+ "integrity": "sha512-q6nPLFCMTLtfsctAuS0Xh4vaolxSFUWUWR6PZSrXXiRy+SANGllpcqdXFv2z07l0Xz/6Hl40hK0ffNCJPH2n1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fault": "^1.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-0.3.3.tgz",
+ "integrity": "sha512-oVN4zv5/tAIA+l3GbMi7lWeYpJ14oQyJ3uEim20ktYFAcfX1x3LNlFGGlmrZHt7u9YlKExmyJdDGaTt6cMSR/A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "micromark": "~2.11.0",
+ "micromark-extension-gfm-autolink-literal": "~0.5.0",
+ "micromark-extension-gfm-strikethrough": "~0.6.5",
+ "micromark-extension-gfm-table": "~0.4.0",
+ "micromark-extension-gfm-tagfilter": "~0.3.0",
+ "micromark-extension-gfm-task-list-item": "~0.3.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-autolink-literal": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.7.tgz",
+ "integrity": "sha512-ePiDGH0/lhcngCe8FtH4ARFoxKTUelMp4L7Gg2pujYD5CSMb9PbblnyL+AAMud/SNMyusbS2XDSiPIRcQoNFAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "micromark": "~2.11.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-strikethrough": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.5.tgz",
+ "integrity": "sha512-PpOKlgokpQRwUesRwWEp+fHjGGkZEejj83k9gU5iXCbDG+XBA92BqnRKYJdfqfkrRcZRgGuPuXb7DaK/DmxOhw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "micromark": "~2.11.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-table": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.3.tgz",
+ "integrity": "sha512-hVGvESPq0fk6ALWtomcwmgLvH8ZSVpcPjzi0AjPclB9FsVRgMtGZkUcpE0zgjOCFAznKepF4z3hX8z6e3HODdA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "micromark": "~2.11.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-tagfilter": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz",
+ "integrity": "sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-task-list-item": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.3.tgz",
+ "integrity": "sha512-0zvM5iSLKrc/NQl84pZSjGo66aTGd57C1idmlWmE87lkMcXrTxg1uXa/nXomxJytoje9trP0NDLvw4bZ/Z/XCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "micromark": "~2.11.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
+ "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/napi-postinstall": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz",
+ "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "napi-postinstall": "lib/cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/napi-postinstall"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.4",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
+ "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/netmask": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
+ "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.6.0.tgz",
+ "integrity": "sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==",
+ "license": "MIT",
+ "engines": {
+ "node": "^18 || ^20 || >= 21"
+ }
+ },
+ "node_modules/node-gyp-build": {
+ "version": "4.8.4",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
+ "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
+ "license": "MIT",
+ "bin": {
+ "node-gyp-build": "bin.js",
+ "node-gyp-build-optional": "optional.js",
+ "node-gyp-build-test": "build-test.js"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+ "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.fromentries": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+ "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.groupby": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+ "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
+ "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/on-headers": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
+ "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/own-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
+ "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.2.6",
+ "object-keys": "^1.1.1",
+ "safe-push-apply": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pac-proxy-agent": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
+ "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
+ "license": "MIT",
+ "dependencies": {
+ "@tootallnate/quickjs-emscripten": "^0.23.0",
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "get-uri": "^6.0.1",
+ "http-proxy-agent": "^7.0.0",
+ "https-proxy-agent": "^7.0.6",
+ "pac-resolver": "^7.0.1",
+ "socks-proxy-agent": "^8.0.5"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/pac-resolver": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
+ "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
+ "license": "MIT",
+ "dependencies": {
+ "degenerator": "^5.0.0",
+ "netmask": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-entities": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
+ "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "character-entities": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "character-reference-invalid": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-hexadecimal": "^1.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/path-to-regexp": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
+ "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/pem": {
+ "version": "1.14.8",
+ "resolved": "https://registry.npmjs.org/pem/-/pem-1.14.8.tgz",
+ "integrity": "sha512-ZpbOf4dj9/fQg5tQzTqv4jSKJQsK7tPl0pm4/pvPcZVjZcJg7TMfr3PBk6gJH97lnpJDu4e4v8UUqEz5daipCg==",
+ "license": "MIT",
+ "dependencies": {
+ "es6-promisify": "^7.0.0",
+ "md5": "^2.3.0",
+ "os-tmpdir": "^1.0.2",
+ "which": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/possible-typed-array-names": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
+ "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-linter-helpers": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz",
+ "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-diff": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/prettier-plugin-sh": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.18.0.tgz",
+ "integrity": "sha512-cW1XL27FOJQ/qGHOW6IHwdCiNWQsAgK+feA8V6+xUTaH0cD3Mh+tFAtBvEEWvuY6hTDzRV943Fzeii+qMOh7nQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@reteps/dockerfmt": "^0.3.6",
+ "sh-syntax": "^0.5.8"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/unts"
+ },
+ "peerDependencies": {
+ "prettier": "^3.6.0"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/proxy-agent": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
+ "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "http-proxy-agent": "^7.0.1",
+ "https-proxy-agent": "^7.0.6",
+ "lru-cache": "^7.14.1",
+ "pac-proxy-agent": "^7.1.0",
+ "proxy-from-env": "^1.1.0",
+ "socks-proxy-agent": "^8.0.5"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "license": "MIT"
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
+ "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
+ "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "~3.1.2",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.7.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/reflect.getprototypeof": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
+ "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.7",
+ "get-proto": "^1.0.1",
+ "which-builtin-type": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
+ "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-errors": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "set-function-name": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/remark-footnotes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-3.0.0.tgz",
+ "integrity": "sha512-ZssAvH9FjGYlJ/PBVKdSmfyPc3Cz4rTWgZLI4iE/SX8Nt5l3o3oEjv3wwG5VD7xOjktzdwp5coac+kJV9l4jgg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-footnote": "^0.1.0",
+ "micromark-extension-footnote": "^0.3.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-frontmatter": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-3.0.0.tgz",
+ "integrity": "sha512-mSuDd3svCHs+2PyO29h7iijIZx4plX0fheacJcAoYAASfgzgVIcXGYSq9GFyYocFLftQs8IOmmkgtOovs6d4oA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-frontmatter": "^0.2.0",
+ "micromark-extension-frontmatter": "^0.2.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-gfm": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-1.0.0.tgz",
+ "integrity": "sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-gfm": "^0.1.0",
+ "micromark-extension-gfm": "^0.3.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-parse": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz",
+ "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-from-markdown": "^0.8.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remove-markdown": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/remove-markdown/-/remove-markdown-0.6.3.tgz",
+ "integrity": "sha512-Qvp2p0Q1irE7AaJO7QemJe04HdObHylJrG+q4hszvPlYp7q4EvfINpEIaIEFdB+3XTDp1h6fiyT60ae00gmRow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "license": "MIT"
+ },
+ "node_modules/resolve": {
+ "version": "1.22.11",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
+ "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.16.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/resolve-pkg-maps": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
+ "node_modules/rotating-file-stream": {
+ "version": "3.2.9",
+ "resolved": "https://registry.npmjs.org/rotating-file-stream/-/rotating-file-stream-3.2.9.tgz",
+ "integrity": "sha512-i9i0KkHh12ryl4xtELg+0gyoFre2PJ9RcQQLzquWsiqygyYsrZLckrqqYrthhnJZGZb4g+KUHtcoWYVq34gaug==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0"
+ },
+ "funding": {
+ "url": "https://www.blockchain.com/btc/address/12p1p5q7sK75tPyuesZmssiMYr4TKzpSCN"
+ }
+ },
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/safe-array-concat": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
+ "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "get-intrinsic": "^1.2.6",
+ "has-symbols": "^1.1.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safe-compare": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/safe-compare/-/safe-compare-1.1.4.tgz",
+ "integrity": "sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-alloc": "^1.2.0"
+ }
+ },
+ "node_modules/safe-push-apply": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
+ "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.3",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.1",
+ "mime-types": "^3.0.2",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
+ "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-function-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-proto": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
+ "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/sh-syntax": {
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.5.8.tgz",
+ "integrity": "sha512-JfVoxf4FxQI5qpsPbkHhZo+n6N9YMJobyl4oGEUBb/31oQYlgTjkXQD8PBiafS2UbWoxrTO0Z5PJUBXEPAG1Zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/sh-syntax"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks": {
+ "version": "2.8.7",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
+ "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
+ "license": "MIT",
+ "dependencies": {
+ "ip-address": "^10.0.1",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
+ "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "socks": "^2.8.3"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stable-hash-x": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz",
+ "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/stop-iteration-iterator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
+ "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "internal-slot": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.trim": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
+ "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "define-data-property": "^1.1.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-object-atoms": "^1.0.0",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
+ "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+ "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/synckit": {
+ "version": "0.11.12",
+ "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz",
+ "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@pkgr/core": "^0.2.9"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/synckit"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/traverse": {
+ "version": "0.6.11",
+ "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.11.tgz",
+ "integrity": "sha512-vxXDZg8/+p3gblxB6BhhG5yWVn1kGRlaL8O78UDXc3wRnPizB5g83dcvWV1jpDMIPnjZjOFuxlMmE82XJ4407w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "gopd": "^1.2.0",
+ "typedarray.prototype.slice": "^1.0.5",
+ "which-typed-array": "^1.1.18"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/trough": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+ "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/ts-api-utils": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
+ "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4"
+ }
+ },
+ "node_modules/ts-node": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
+ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tsconfig-paths": {
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/typed-array-byte-length": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+ "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-byte-offset": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+ "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.15",
+ "reflect.getprototypeof": "^1.0.9"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-length": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
+ "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "is-typed-array": "^1.1.13",
+ "possible-typed-array-names": "^1.0.0",
+ "reflect.getprototypeof": "^1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typedarray.prototype.slice": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.5.tgz",
+ "integrity": "sha512-q7QNVDGTdl702bVFiI5eY4l/HkgCM6at9KhcFbgUAzezHFbOVy4+0O/lCjsABEQwbZPravVfBIiBVGo89yzHFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "math-intrinsics": "^1.1.0",
+ "typed-array-buffer": "^1.0.3",
+ "typed-array-byte-offset": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-eslint": {
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz",
+ "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.56.1",
+ "@typescript-eslint/parser": "8.56.1",
+ "@typescript-eslint/typescript-estree": "8.56.1",
+ "@typescript-eslint/utils": "8.56.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+ "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-bigints": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "which-boxed-primitive": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/underscore": {
+ "version": "1.13.8",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz",
+ "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unified": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz",
+ "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bail": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-buffer": "^2.0.0",
+ "is-plain-obj": "^2.0.0",
+ "trough": "^1.0.0",
+ "vfile": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unified/node_modules/is-buffer": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unist-util-is": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz",
+ "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-stringify-position": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+ "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^2.0.2"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-visit-parents": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz",
+ "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/unrs-resolver": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
+ "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "napi-postinstall": "^0.3.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/unrs-resolver"
+ },
+ "optionalDependencies": {
+ "@unrs/resolver-binding-android-arm-eabi": "1.11.1",
+ "@unrs/resolver-binding-android-arm64": "1.11.1",
+ "@unrs/resolver-binding-darwin-arm64": "1.11.1",
+ "@unrs/resolver-binding-darwin-x64": "1.11.1",
+ "@unrs/resolver-binding-freebsd-x64": "1.11.1",
+ "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1",
+ "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1",
+ "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-arm64-musl": "1.11.1",
+ "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1",
+ "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-x64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-x64-musl": "1.11.1",
+ "@unrs/resolver-binding-wasm32-wasi": "1.11.1",
+ "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1",
+ "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1",
+ "@unrs/resolver-binding-win32-x64-msvc": "1.11.1"
+ }
+ },
+ "node_modules/update-section": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/update-section/-/update-section-0.3.3.tgz",
+ "integrity": "sha512-BpRZMZpgXLuTiKeiu7kK0nIPwGdyrqrs6EDSaXtjD/aQ2T+qVo9a5hRC3HN3iJjCMxNT/VxoLGQ7E/OzE5ucnw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/vfile": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz",
+ "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "is-buffer": "^2.0.0",
+ "unist-util-stringify-position": "^2.0.0",
+ "vfile-message": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/vfile-message": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
+ "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "unist-util-stringify-position": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/vfile/node_modules/is-buffer": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which-boxed-primitive": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+ "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-bigint": "^1.1.0",
+ "is-boolean-object": "^1.2.1",
+ "is-number-object": "^1.1.1",
+ "is-string": "^1.1.1",
+ "is-symbol": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-builtin-type": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+ "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "function.prototype.name": "^1.1.6",
+ "has-tostringtag": "^1.0.2",
+ "is-async-function": "^2.0.0",
+ "is-date-object": "^1.1.0",
+ "is-finalizationregistry": "^1.1.0",
+ "is-generator-function": "^1.0.10",
+ "is-regex": "^1.2.1",
+ "is-weakref": "^1.0.2",
+ "isarray": "^2.0.5",
+ "which-boxed-primitive": "^1.1.0",
+ "which-collection": "^1.0.2",
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-collection": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+ "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-map": "^2.0.3",
+ "is-set": "^2.0.3",
+ "is-weakmap": "^2.0.2",
+ "is-weakset": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.20",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
+ "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "for-each": "^0.3.5",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "node_modules/ws": {
+ "version": "8.20.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
+ "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xdg-basedir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
+ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zwitch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz",
+ "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index 9f41af56f63b..b229efb3f5e5 100644
--- a/package.json
+++ b/package.json
@@ -1,97 +1,94 @@
{
"name": "code-server",
"license": "MIT",
- "version": "3.7.2",
+ "version": "0.0.0",
"description": "Run VS Code on a remote server.",
- "homepage": "https://github.com/cdr/code-server",
+ "homepage": "https://github.com/coder/code-server",
"bugs": {
- "url": "https://github.com/cdr/code-server/issues"
+ "url": "https://github.com/coder/code-server/issues"
},
- "repository": "https://github.com/cdr/code-server",
+ "repository": "https://github.com/coder/code-server",
"scripts": {
"clean": "./ci/build/clean.sh",
- "vscode": "./ci/dev/vscode.sh",
- "vscode:patch": "./ci/dev/patch-vscode.sh",
- "vscode:diff": "./ci/dev/diff-vscode.sh",
"build": "./ci/build/build-code-server.sh",
"build:vscode": "./ci/build/build-vscode.sh",
+ "doctoc": "./ci/dev/doctoc.sh",
"release": "./ci/build/build-release.sh",
- "release:standalone": "./ci/build/build-standalone-release.sh",
- "release:github-draft": "./ci/build/release-github-draft.sh",
- "release:github-assets": "./ci/build/release-github-assets.sh",
- "test:standalone-release": "./ci/build/test-standalone-release.sh",
+ "release:prep": "./ci/build/release-prep.sh",
+ "test:e2e": "VSCODE_IPC_HOOK_CLI= ./ci/dev/test-e2e.sh",
+ "test:e2e:proxy": "USE_PROXY=1 ./ci/dev/test-e2e.sh",
+ "test:unit": "./ci/dev/test-unit.sh --forceExit --detectOpenHandles",
+ "test:integration": "./ci/dev/test-integration.sh",
+ "test:native": "./ci/dev/test-native.sh",
+ "test:scripts": "./ci/dev/test-scripts.sh",
"package": "./ci/build/build-packages.sh",
- "_____": "",
- "fmt": "./ci/dev/fmt.sh",
- "lint": "./ci/dev/lint.sh",
- "test": "./ci/dev/test.sh",
- "ci": "./ci/dev/ci.sh",
- "watch": "VSCODE_IPC_HOOK_CLI= NODE_OPTIONS=--max_old_space_size=32384 ts-node ./ci/dev/watch.ts"
+ "prettier": "prettier --write --log-level=warn --cache .",
+ "preinstall": "node ./ci/dev/preinstall.js",
+ "postinstall": "./ci/dev/postinstall.sh",
+ "publish:npm": "./ci/steps/publish-npm.sh",
+ "publish:docker": "./ci/steps/docker-buildx-push.sh",
+ "fmt": "npm run prettier && ./ci/dev/doctoc.sh",
+ "lint:scripts": "./ci/dev/lint-scripts.sh",
+ "lint:ts": "eslint --max-warnings=0 --fix $(git ls-files '*.ts' '*.js' | grep -v 'lib/vscode')",
+ "test": "echo 'Run npm run test:unit or npm run test:e2e' && exit 1",
+ "watch": "VSCODE_DEV=1 VSCODE_IPC_HOOK_CLI= NODE_OPTIONS='--max_old_space_size=32384 --trace-warnings' ts-node ./ci/dev/watch.ts",
+ "icons": "./ci/dev/gen_icons.sh"
},
"main": "out/node/entry.js",
"devDependencies": {
- "@types/body-parser": "^1.19.0",
- "@types/cookie-parser": "^1.4.2",
- "@types/express": "^4.17.8",
- "@types/fs-extra": "^8.0.1",
- "@types/http-proxy": "^1.17.4",
- "@types/js-yaml": "^3.12.3",
- "@types/mocha": "^8.0.3",
- "@types/node": "^12.12.7",
- "@types/parcel-bundler": "^1.12.1",
- "@types/pem": "^1.9.5",
+ "@eslint/compat": "^1.2.0",
+ "@eslint/eslintrc": "^3.1.0",
+ "@eslint/js": "^9.12.0",
+ "@schemastore/package": "^0.0.10",
+ "@types/compression": "^1.7.3",
+ "@types/cookie-parser": "^1.4.4",
+ "@types/eslint__js": "^8.42.3",
+ "@types/express": "^5.0.0",
+ "@types/http-proxy": "1.17.7",
+ "@types/js-yaml": "^4.0.6",
+ "@types/node": "22.x",
+ "@types/pem": "^1.14.1",
+ "@types/proxy-from-env": "^1.0.1",
"@types/safe-compare": "^1.1.0",
- "@types/semver": "^7.1.0",
- "@types/split2": "^2.1.6",
- "@types/supertest": "^2.0.10",
- "@types/tar-fs": "^2.0.0",
- "@types/tar-stream": "^2.1.0",
- "@types/ws": "^7.2.6",
- "@typescript-eslint/eslint-plugin": "^4.7.0",
- "@typescript-eslint/parser": "^4.7.0",
- "doctoc": "^1.4.0",
- "eslint": "^7.7.0",
- "eslint-config-prettier": "^6.0.0",
- "eslint-plugin-import": "^2.18.2",
- "eslint-plugin-prettier": "^3.1.0",
- "leaked-handles": "^5.2.0",
- "mocha": "^8.1.2",
- "parcel-bundler": "^1.12.4",
- "prettier": "^2.0.5",
- "stylelint": "^13.0.0",
- "stylelint-config-recommended": "^3.0.0",
- "supertest": "^6.0.1",
- "ts-node": "^9.0.0",
- "typescript": "4.0.2"
- },
- "resolutions": {
- "@types/node": "^12.12.7",
- "safe-buffer": "^5.1.1",
- "vfile-message": "^2.0.2"
+ "@types/semver": "^7.5.2",
+ "@types/trusted-types": "^2.0.4",
+ "@types/ws": "^8.5.5",
+ "doctoc": "^2.2.1",
+ "eslint": "^9.12.0",
+ "eslint-config-prettier": "^10.1.8",
+ "eslint-import-resolver-typescript": "^4.4.4",
+ "eslint-plugin-import": "^2.28.1",
+ "eslint-plugin-prettier": "^5.0.0",
+ "globals": "^16.1.0",
+ "prettier": "3.8.3",
+ "prettier-plugin-sh": "^0.18.0",
+ "ts-node": "^10.9.1",
+ "typescript": "^5.6.2",
+ "typescript-eslint": "^8.8.0"
},
"dependencies": {
- "@coder/logger": "1.1.16",
- "body-parser": "^1.19.0",
- "cookie-parser": "^1.4.5",
- "env-paths": "^2.2.0",
- "express": "^5.0.0-alpha.8",
- "fs-extra": "^9.0.1",
- "http-proxy": "^1.18.0",
+ "@coder/logger": "^3.0.1",
+ "argon2": "^0.44.0",
+ "compression": "^1.7.4",
+ "cookie-parser": "^1.4.6",
+ "env-paths": "^2.2.1",
+ "express": "^5.0.1",
+ "http-proxy": "^1.18.1",
"httpolyglot": "^0.1.2",
- "js-yaml": "^3.13.1",
- "limiter": "^1.1.5",
- "pem": "^1.14.2",
- "qs": "6.7.0",
- "rotating-file-stream": "^2.1.1",
- "safe-buffer": "^5.1.1",
+ "i18next": "^25.8.3",
+ "js-yaml": "^4.1.0",
+ "limiter": "^2.1.0",
+ "pem": "^1.14.8",
+ "proxy-agent": "^6.3.1",
+ "qs": "^6.15.0",
+ "rotating-file-stream": "^3.1.1",
"safe-compare": "^1.1.4",
- "semver": "^7.1.3",
- "split2": "^3.2.2",
- "tar": "^6.0.1",
- "tar-fs": "^2.0.0",
- "ws": "^7.2.0",
- "xdg-basedir": "^4.0.0",
- "yarn": "^1.22.4"
+ "semver": "^7.5.4",
+ "ws": "^8.14.2",
+ "xdg-basedir": "^4.0.0"
+ },
+ "resolutions": {
+ "@types/node": "22.x"
},
"bin": {
"code-server": "out/node/entry.js"
@@ -102,9 +99,54 @@
"ide",
"coder",
"vscode-remote",
- "browser-ide"
+ "browser-ide",
+ "remote-development"
],
"engines": {
- "node": ">= 12"
+ "node": "22"
+ },
+ "jest": {
+ "transform": {
+ "^.+\\.ts$": "