feat: Add virtual microphone for linux screen share

Signed-off-by: Jacob Schlecht <dadadah@echoha.us>
This commit is contained in:
Jacob Schlecht 2026-08-02 19:09:22 -06:00
parent 703381739a
commit 9dca60cd40
17 changed files with 557 additions and 69 deletions

View File

@ -20,12 +20,22 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Mise
uses: immich-app/devtools/actions/use-mise@7b8610a904d57da241e4ddba17fa62b62b15aed4 # use-mise-action-v2.0.2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install pipewire library
run: sudo apt install -y libpipewire-0.3-dev
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Checkout assets
run: mise assets

View File

@ -42,7 +42,7 @@ jobs:
cache: "pnpm"
- name: Install dependencies
run: pnpm ci
run: pnpm ci -F stoat-desktop
- name: Build
run: pnpm package

View File

@ -48,6 +48,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Checkout assets
run: git -c submodule."assets".update=checkout submodule update --init assets
@ -63,8 +65,22 @@ jobs:
node-version: 26
cache: "pnpm"
- name: Install Flatpak Tooling and Runtimes and Pipewire dev
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y flatpak flatpak-builder libpipewire-0.3-dev
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install -y --user flathub org.freedesktop.Platform//25.08 org.freedesktop.Sdk//25.08
flatpak install -y --user flathub org.electronjs.Electron2.BaseApp//stable
- name: Install dependencies
run: pnpm install
if: matrix.os == 'ubuntu-latest'
run: pnpm ci
- name: Install dependencies
if: matrix.os != 'ubuntu-latest'
run: pnpm ci -F stoat-desktop
- name: Publish
run: |
@ -80,15 +96,6 @@ jobs:
PLATFORM: ${{ matrix.os }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install Flatpak Tooling and Runtimes
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y flatpak flatpak-builder
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install -y --user flathub org.freedesktop.Platform//25.08 org.freedesktop.Sdk//25.08
flatpak install -y --user flathub org.electronjs.Electron2.BaseApp//stable
- name: Publish Linux arm64
if: matrix.os == 'ubuntu-latest'
run: pnpm run publish --arch=arm64

5
.gitmodules vendored
View File

@ -1,4 +1,7 @@
[submodule "assets"]
path = assets
url = https://github.com/stoatchat/assets
update = none
update = none
[submodule "node-pipewire"]
path = node-pipewire
url = git@github.com:Dadadah/node-pipewire.git

View File

@ -2,4 +2,4 @@
#MISE description="Build desktop app"
set -e
pnpm run package
pnpm run -F stoat-desktop package

5
.mise/tasks/build/deps Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
#MISE description="Build node-pipewire dependency"
set -e
pnpm -F node-pipewire build-release

View File

@ -31,6 +31,7 @@ Before getting started, you'll want to install:
- [Git](https://git-scm.com/install/)
- [mise-en-place](https://mise.jdx.dev/getting-started.html)
- rust
Then proceed to setup:
@ -45,6 +46,9 @@ mise install
# install all packages
mise install:frozen
# build the dependencies
mise build:deps
# start the application
mise dev
# ... or build the bundle

1
node-pipewire Submodule

@ -0,0 +1 @@
Subproject commit b6d06b12259cc7929520b8f09261b96efc28abc9

View File

@ -29,7 +29,6 @@
"@electron-forge/maker-flatpak": "^7.11.2",
"@electron-forge/maker-squirrel": "^7.11.2",
"@electron-forge/maker-zip": "^7.11.2",
"@electron-forge/plugin-auto-unpack-natives": "^7.11.2",
"@electron-forge/plugin-fuses": "^7.11.2",
"@electron-forge/plugin-vite": "^7.11.2",
"@electron-forge/publisher-github": "^7.11.2",
@ -40,7 +39,7 @@
"@types/electron-squirrel-startup": "^1.0.2",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"electron": "^40.8.3",
"electron": "^43.2.0",
"electron-vite": "^5.0.0",
"electron-windows-store": "^2.1.0",
"eslint": "^8.57.1",
@ -49,7 +48,8 @@
"lodash": "^4.17.21",
"prettier": "^3.6.2",
"typescript": "~4.5.4",
"vite": "^5.4.20"
"vite": "^5.4.20",
"vite-plugin-native-modules": "^2.3.1"
},
"dependencies": {
"@homebridge/dbus-native": "^0.7.2",
@ -61,5 +61,8 @@
"update-electron-app": "^3.1.1",
"utf-8-validate": "^6.0.5"
},
"optionalDependencies": {
"node-pipewire": "workspace:^"
},
"packageManager": "pnpm@11.17.0+sha512.cca3cea332ad254bb84145f966d19f4879615210346fc92c79a047f23a0d7b3cca3c3792f0076ba1f1831d277efbcf0a9119b31a9a60eca7fb3d6231f331ef72"
}

View File

@ -54,9 +54,6 @@ importers:
'@electron-forge/maker-zip':
specifier: ^7.11.2
version: 7.11.2(bluebird@3.7.2)(supports-color@8.1.1)
'@electron-forge/plugin-auto-unpack-natives':
specifier: ^7.11.2
version: 7.11.2(bluebird@3.7.2)(supports-color@8.1.1)
'@electron-forge/plugin-fuses':
specifier: ^7.11.2
version: 7.11.2(@electron/fuses@1.8.0)(bluebird@3.7.2)(supports-color@8.1.1)
@ -88,8 +85,8 @@ importers:
specifier: ^5.62.0
version: 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.5.5)
electron:
specifier: ^40.8.3
version: 40.8.3(supports-color@8.1.1)
specifier: ^43.2.0
version: 43.2.0(supports-color@8.1.1)
electron-vite:
specifier: ^5.0.0
version: 5.0.0(supports-color@8.1.1)(vite@5.4.20(@types/node@24.10.13)(terser@5.49.0))
@ -117,6 +114,41 @@ importers:
vite:
specifier: ^5.4.20
version: 5.4.20(@types/node@24.10.13)(terser@5.49.0)
vite-plugin-native-modules:
specifier: ^2.3.1
version: 2.3.1(vite@5.4.20(@types/node@24.10.13)(terser@5.49.0))
optionalDependencies:
node-pipewire:
specifier: workspace:^
version: link:node-pipewire
node-pipewire:
dependencies:
'@mapbox/node-pre-gyp':
specifier: ^1.0.10
version: 1.0.11(encoding@0.1.13)(supports-color@8.1.1)
cargo-cp-artifact:
specifier: ^0.1.9
version: 0.1.9
typescript:
specifier: ^4.8.4
version: 4.9.5
devDependencies:
'@types/node':
specifier: ^18.11.9
version: 18.19.130
'@typescript-eslint/eslint-plugin':
specifier: ^5.42.1
version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)
'@typescript-eslint/parser':
specifier: ^5.42.1
version: 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)
eslint:
specifier: ^8.27.0
version: 8.57.1(supports-color@8.1.1)
node-pre-gyp-github:
specifier: ^1.4.4
version: 1.4.6
packages:
@ -271,10 +303,6 @@ packages:
resolution: {integrity: sha512-FWnOm2MORX/nt8psnEtID3Vnt8Blby1NkzjU3KjXBPF9kave71C3lI8KbBbCeKKyTQ/S00i2FiglKdRWQ1WNTw==}
engines: {node: '>= 16.4.0'}
'@electron-forge/plugin-auto-unpack-natives@7.11.2':
resolution: {integrity: sha512-ktMQxO80vGjqVXVSFha+kWJscBmJaWud4Kqu7rKkbrCphr1zqaG+8EDNbkpGzV/+mhKOLuA5qII1hJ69gFNpdA==}
engines: {node: '>= 16.4.0'}
'@electron-forge/plugin-base@7.11.2':
resolution: {integrity: sha512-tIFzEE2+D9NnCAn/rLwSkh8H59IqN+G973JNl7xmCzquO6qa7/veitZOQFGO79Zmmgkc8R/fmiCbh7LIdLS9Tg==}
engines: {node: '>= 16.4.0'}
@ -325,6 +353,10 @@ packages:
resolution: {integrity: sha512-U8j5Hyj2Zt7I5PciJvPJfmEv69Gb/Da9v+k655z3Jj1cuY0UnToEJ61IhXrzlTYqo+jUKC+fgAjDJ6vltJTS0A==}
engines: {node: '>= 14.17.5'}
'@electron-internal/extract-zip@1.0.5':
resolution: {integrity: sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA==}
engines: {node: '>=22.12.0'}
'@electron/asar@3.4.1':
resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==}
engines: {node: '>=10.12.0'}
@ -334,14 +366,14 @@ packages:
resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==}
hasBin: true
'@electron/get@2.0.3':
resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==}
engines: {node: '>=12'}
'@electron/get@3.1.0':
resolution: {integrity: sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==}
engines: {node: '>=14'}
'@electron/get@5.1.0':
resolution: {integrity: sha512-3kSBtG8ObcTVfXanm5vVJ6UnBLEVmVsRk1M+vGqCuMBV+XLCbJYuWQful+yIy0GQDsSlK0kHEriEHn7SPk4EnA==}
engines: {node: '>=22.12.0'}
'@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2':
resolution: {gitHosted: true, tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2}
version: 10.2.0-electron.1
@ -811,6 +843,10 @@ packages:
resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==}
engines: {node: '>= 10.0.0'}
'@mapbox/node-pre-gyp@1.0.11':
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
hasBin: true
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -854,6 +890,12 @@ packages:
'@octokit/openapi-types@24.2.0':
resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==}
'@octokit/plugin-paginate-rest@11.3.1':
resolution: {integrity: sha512-ryqobs26cLtM1kQxqeZui4v8FeznirUsksiA+RYemMPJ7Micju0WSkv50dBksTuZks9O5cg4wp+t8fZ/cLY56g==}
engines: {node: '>= 18'}
peerDependencies:
'@octokit/core': '5'
'@octokit/plugin-paginate-rest@11.4.4-cjs.2':
resolution: {integrity: sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==}
engines: {node: '>= 18'}
@ -866,6 +908,12 @@ packages:
peerDependencies:
'@octokit/core': '5'
'@octokit/plugin-rest-endpoint-methods@13.2.2':
resolution: {integrity: sha512-EI7kXWidkt3Xlok5uN43suK99VWqc8OaIMktY9d9+RNKl69juoTyxmLoWPIZgJYzi41qj/9zU7G/ljnNOJ5AFA==}
engines: {node: '>= 18'}
peerDependencies:
'@octokit/core': ^5
'@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1':
resolution: {integrity: sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==}
engines: {node: '>= 18'}
@ -886,6 +934,10 @@ packages:
resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==}
engines: {node: '>= 18'}
'@octokit/rest@20.1.1':
resolution: {integrity: sha512-MB4AYDsM5jhIHro/dq4ix1iWTLGToIGk6cWF5L6vanFaMble5jTX/UBQyiv05HsWnwUtY8JrfHy2LWfKwihqMw==}
engines: {node: '>= 18'}
'@octokit/rest@20.1.2':
resolution: {integrity: sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==}
engines: {node: '>= 18'}
@ -1084,15 +1136,15 @@ packages:
'@types/mute-stream@0.0.4':
resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==}
'@types/node@18.19.130':
resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==}
'@types/node@22.18.6':
resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==}
'@types/node@24.10.13':
resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==}
'@types/node@24.5.2':
resolution: {integrity: sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==}
'@types/responselike@1.0.3':
resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
@ -1332,6 +1384,14 @@ packages:
applescript@1.0.0:
resolution: {integrity: sha512-yvtNHdWvtbYEiIazXAdp/NY+BBb65/DAseqlNiJQjOx9DynuzOYDbVLBJvuc0ve0VL9x6B3OHF6eH52y9hCBtQ==}
aproba@2.1.0:
resolution: {integrity: sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==}
are-we-there-yet@2.0.0:
resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
engines: {node: '>=10'}
deprecated: This package is no longer supported.
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@ -1476,6 +1536,10 @@ packages:
caniuse-lite@1.0.30001806:
resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==}
cargo-cp-artifact@0.1.9:
resolution: {integrity: sha512-6F+UYzTaGB+awsTXg0uSJA1/b/B3DDJzpKVRu0UmyI7DmNeaAl2RFHuTGIN6fEgpadRxoXGb7gbC1xo4C3IdyA==}
hasBin: true
chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
@ -1553,6 +1617,10 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
color-support@1.1.3:
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
hasBin: true
colorette@2.0.20:
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
@ -1560,6 +1628,10 @@ packages:
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
engines: {node: '>=16'}
commander@12.0.0:
resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==}
engines: {node: '>=18'}
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
@ -1582,6 +1654,9 @@ packages:
resolution: {integrity: sha512-L6BuueHTRuJHQvQVc6YXYZRtN5vJUtOdCTLn0tRYYV5azfbAFcPghB5zEE40mVrV6w7slMTqUfkDomutIK14fw==}
engines: {node: '>=20'}
console-control-strings@1.1.0:
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
@ -1663,6 +1738,9 @@ packages:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
delegates@1.0.0:
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
deprecation@2.3.1:
resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==}
@ -1745,9 +1823,9 @@ packages:
resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==}
engines: {node: '>=8.0.0'}
electron@40.8.3:
resolution: {integrity: sha512-MH6LK4xM6VVmmtz0nRE0Fe8l2jTKSYTvH1t0ZfbNLw3o6dlBCVTRqQha6uL8ZQVoMy74JyLguGwK7dU7rCKIhw==}
engines: {node: '>= 12.20.55'}
electron@43.2.0:
resolution: {integrity: sha512-80zvrgG7ZRXD+tD0IyLvrnN9n+veSxadMRsMaC9wKKP3iUbtC7rGM8+dVuCmOb0Rrwwv8ESW4awnUZh9Hbp1fA==}
engines: {node: '>= 22.12.0'}
hasBin: true
emoji-regex@8.0.0:
@ -2060,6 +2138,11 @@ packages:
resolution: {integrity: sha512-w4n9cPWyP7aHxKxYHFQMegj7WIAsL/YX/C4Bs5Rr8s1H9M1rNtRWRsw+ovYMkXDQ5S4ZbYHsHAPmevPjPgw44w==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
gauge@3.0.2:
resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
engines: {node: '>=10'}
deprecated: This package is no longer supported.
gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
@ -2177,6 +2260,9 @@ packages:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
has-unicode@2.0.1:
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
@ -2536,6 +2622,10 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
make-dir@3.1.0:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
make-fetch-happen@10.2.1:
resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
@ -2762,10 +2852,20 @@ packages:
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
hasBin: true
node-pre-gyp-github@1.4.6:
resolution: {integrity: sha512-+s+4hEv0O/AsmV+96O7Pkw5/82IipeW4SQ84pNudF42jy6Ec38KCe29t55y+TbJqvgfTbWVHVrg+yb89ef/1XA==}
deprecated: Since Node.js v18 is now required this version introduces breaking changes, so we are moving this to v2.0.0.
hasBin: true
node-releases@2.0.51:
resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==}
engines: {node: '>=18'}
nopt@5.0.0:
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
engines: {node: '>=6'}
hasBin: true
nopt@6.0.0:
resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
@ -2782,6 +2882,14 @@ packages:
resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
engines: {node: '>=4'}
npmlog@5.0.1:
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
deprecated: This package is no longer supported.
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
object-inspect@1.13.4:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
@ -3154,6 +3262,9 @@ packages:
resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==}
engines: {node: '>=10'}
set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
set-function-length@1.2.2:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
@ -3457,6 +3568,11 @@ packages:
engines: {node: '>=4.2.0'}
hasBin: true
typescript@4.9.5:
resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==}
engines: {node: '>=4.2.0'}
hasBin: true
typescript@5.4.5:
resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
engines: {node: '>=14.17'}
@ -3470,15 +3586,19 @@ packages:
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
engines: {node: '>= 0.4'}
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
undici-types@7.12.0:
resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==}
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
undici@7.29.0:
resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==}
engines: {node: '>=20.18.1'}
unique-filename@2.0.1:
resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
@ -3528,6 +3648,11 @@ packages:
validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
vite-plugin-native-modules@2.3.1:
resolution: {integrity: sha512-Vm/nJAuvUrE4XnjvqhDlFKRUNCPytylyr/2rivF0pXC3Vdg1r5jW3JbbR1PKefKoyVrTwU1F0vHruCFUhicflw==}
peerDependencies:
vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
vite@5.4.20:
resolution: {integrity: sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==}
engines: {node: ^18.0.0 || >=20.0.0}
@ -3614,6 +3739,9 @@ packages:
engines: {node: '>= 8'}
hasBin: true
wide-align@1.1.5:
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
winreg@1.2.4:
resolution: {integrity: sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA==}
@ -4023,14 +4151,6 @@ snapshots:
- bluebird
- supports-color
'@electron-forge/plugin-auto-unpack-natives@7.11.2(bluebird@3.7.2)(supports-color@8.1.1)':
dependencies:
'@electron-forge/plugin-base': 7.11.2(bluebird@3.7.2)(supports-color@8.1.1)
'@electron-forge/shared-types': 7.11.2(bluebird@3.7.2)(supports-color@8.1.1)
transitivePeerDependencies:
- bluebird
- supports-color
'@electron-forge/plugin-base@7.11.2(bluebird@3.7.2)(supports-color@8.1.1)':
dependencies:
'@electron-forge/shared-types': 7.11.2(bluebird@3.7.2)(supports-color@8.1.1)
@ -4162,6 +4282,8 @@ snapshots:
dependencies:
chrome-trace-event: 1.0.4
'@electron-internal/extract-zip@1.0.5': {}
'@electron/asar@3.4.1':
dependencies:
commander: 5.1.0
@ -4174,7 +4296,7 @@ snapshots:
fs-extra: 9.1.0
minimist: 1.2.8
'@electron/get@2.0.3(supports-color@8.1.1)':
'@electron/get@3.1.0(supports-color@8.1.1)':
dependencies:
debug: 4.4.3(supports-color@8.1.1)
env-paths: 2.2.1
@ -4188,17 +4310,16 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@electron/get@3.1.0(supports-color@8.1.1)':
'@electron/get@5.1.0(supports-color@8.1.1)':
dependencies:
debug: 4.4.3(supports-color@8.1.1)
env-paths: 2.2.1
fs-extra: 8.1.0
got: 11.8.6
env-paths: 3.0.0
graceful-fs: 4.2.11
progress: 2.0.3
semver: 6.3.1
semver: 7.7.2
sumchecker: 3.0.1(supports-color@8.1.1)
optionalDependencies:
global-agent: 3.0.0
undici: 7.29.0
transitivePeerDependencies:
- supports-color
@ -4658,6 +4779,21 @@ snapshots:
- supports-color
optional: true
'@mapbox/node-pre-gyp@1.0.11(encoding@0.1.13)(supports-color@8.1.1)':
dependencies:
detect-libc: 2.1.1
https-proxy-agent: 5.0.1(supports-color@8.1.1)
make-dir: 3.1.0
node-fetch: 2.7.0(encoding@0.1.13)
nopt: 5.0.0
npmlog: 5.0.1
rimraf: 3.0.2
semver: 7.7.2
tar: 6.2.1
transitivePeerDependencies:
- encoding
- supports-color
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
@ -4707,6 +4843,11 @@ snapshots:
'@octokit/openapi-types@24.2.0': {}
'@octokit/plugin-paginate-rest@11.3.1(@octokit/core@5.2.2)':
dependencies:
'@octokit/core': 5.2.2
'@octokit/types': 13.10.0
'@octokit/plugin-paginate-rest@11.4.4-cjs.2(@octokit/core@5.2.2)':
dependencies:
'@octokit/core': 5.2.2
@ -4716,6 +4857,11 @@ snapshots:
dependencies:
'@octokit/core': 5.2.2
'@octokit/plugin-rest-endpoint-methods@13.2.2(@octokit/core@5.2.2)':
dependencies:
'@octokit/core': 5.2.2
'@octokit/types': 13.10.0
'@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1(@octokit/core@5.2.2)':
dependencies:
'@octokit/core': 5.2.2
@ -4741,6 +4887,13 @@ snapshots:
'@octokit/types': 13.10.0
universal-user-agent: 6.0.1
'@octokit/rest@20.1.1':
dependencies:
'@octokit/core': 5.2.2
'@octokit/plugin-paginate-rest': 11.3.1(@octokit/core@5.2.2)
'@octokit/plugin-request-log': 4.0.1(@octokit/core@5.2.2)
'@octokit/plugin-rest-endpoint-methods': 13.2.2(@octokit/core@5.2.2)
'@octokit/rest@20.1.2':
dependencies:
'@octokit/core': 5.2.2
@ -4850,7 +5003,7 @@ snapshots:
dependencies:
'@types/http-cache-semantics': 4.0.4
'@types/keyv': 3.1.4
'@types/node': 24.5.2
'@types/node': 24.10.13
'@types/responselike': 1.0.3
'@types/discord-rpc@4.0.9':
@ -4882,6 +5035,10 @@ snapshots:
dependencies:
'@types/node': 24.10.13
'@types/node@18.19.130':
dependencies:
undici-types: 5.26.5
'@types/node@22.18.6':
dependencies:
undici-types: 6.21.0
@ -4890,13 +5047,9 @@ snapshots:
dependencies:
undici-types: 7.16.0
'@types/node@24.5.2':
dependencies:
undici-types: 7.12.0
'@types/responselike@1.0.3':
dependencies:
'@types/node': 24.5.2
'@types/node': 24.10.13
'@types/semver@7.7.1': {}
@ -4926,6 +5079,25 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5))(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)':
dependencies:
'@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)
'@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)
'@typescript-eslint/utils': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)
debug: 4.4.3(supports-color@8.1.1)
eslint: 8.57.1(supports-color@8.1.1)
graphemer: 1.4.0
ignore: 5.3.2
natural-compare-lite: 1.4.0
semver: 7.7.2
tsutils: 3.21.0(typescript@4.9.5)
optionalDependencies:
typescript: 4.9.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.5.5)':
dependencies:
'@typescript-eslint/scope-manager': 5.62.0
@ -4938,6 +5110,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)':
dependencies:
'@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/types': 5.62.0
'@typescript-eslint/typescript-estree': 5.62.0(supports-color@8.1.1)(typescript@4.9.5)
debug: 4.4.3(supports-color@8.1.1)
eslint: 8.57.1(supports-color@8.1.1)
optionalDependencies:
typescript: 4.9.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@5.62.0':
dependencies:
'@typescript-eslint/types': 5.62.0
@ -4955,6 +5139,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/type-utils@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)':
dependencies:
'@typescript-eslint/typescript-estree': 5.62.0(supports-color@8.1.1)(typescript@4.9.5)
'@typescript-eslint/utils': 5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)
debug: 4.4.3(supports-color@8.1.1)
eslint: 8.57.1(supports-color@8.1.1)
tsutils: 3.21.0(typescript@4.9.5)
optionalDependencies:
typescript: 4.9.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@5.62.0': {}
'@typescript-eslint/typescript-estree@5.62.0(supports-color@8.1.1)(typescript@4.5.5)':
@ -4971,6 +5167,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/typescript-estree@5.62.0(supports-color@8.1.1)(typescript@4.9.5)':
dependencies:
'@typescript-eslint/types': 5.62.0
'@typescript-eslint/visitor-keys': 5.62.0
debug: 4.4.3(supports-color@8.1.1)
globby: 11.1.0
is-glob: 4.0.3
semver: 7.7.2
tsutils: 3.21.0(typescript@4.9.5)
optionalDependencies:
typescript: 4.9.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.5.5)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1(supports-color@8.1.1))
@ -4986,6 +5196,21 @@ snapshots:
- supports-color
- typescript
'@typescript-eslint/utils@5.62.0(eslint@8.57.1(supports-color@8.1.1))(supports-color@8.1.1)(typescript@4.9.5)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1(supports-color@8.1.1))
'@types/json-schema': 7.0.15
'@types/semver': 7.7.1
'@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/types': 5.62.0
'@typescript-eslint/typescript-estree': 5.62.0(supports-color@8.1.1)(typescript@4.9.5)
eslint: 8.57.1(supports-color@8.1.1)
eslint-scope: 5.1.1
semver: 7.7.2
transitivePeerDependencies:
- supports-color
- typescript
'@typescript-eslint/visitor-keys@5.62.0':
dependencies:
'@typescript-eslint/types': 5.62.0
@ -5163,6 +5388,13 @@ snapshots:
applescript@1.0.0: {}
aproba@2.1.0: {}
are-we-there-yet@2.0.0:
dependencies:
delegates: 1.0.0
readable-stream: 3.6.2
argparse@2.0.1: {}
array-buffer-byte-length@1.0.2:
@ -5356,6 +5588,8 @@ snapshots:
caniuse-lite@1.0.30001806: {}
cargo-cp-artifact@0.1.9: {}
chalk@2.4.2:
dependencies:
ansi-styles: 3.2.1
@ -5429,10 +5663,14 @@ snapshots:
color-name@1.1.4: {}
color-support@1.1.3: {}
colorette@2.0.20: {}
commander@11.1.0: {}
commander@12.0.0: {}
commander@2.20.3: {}
commander@5.1.0: {}
@ -5455,6 +5693,8 @@ snapshots:
semver: 7.7.2
uint8array-extras: 1.5.0
console-control-strings@1.1.0: {}
convert-source-map@2.0.0: {}
cross-dirname@0.1.0: {}
@ -5539,6 +5779,8 @@ snapshots:
has-property-descriptors: 1.0.2
object-keys: 1.1.1
delegates@1.0.0: {}
deprecation@2.3.1: {}
detect-libc@2.1.1: {}
@ -5671,11 +5913,11 @@ snapshots:
- supports-color
optional: true
electron@40.8.3(supports-color@8.1.1):
electron@43.2.0(supports-color@8.1.1):
dependencies:
'@electron/get': 2.0.3(supports-color@8.1.1)
'@electron-internal/extract-zip': 1.0.5
'@electron/get': 5.1.0(supports-color@8.1.1)
'@types/node': 24.10.13
extract-zip: 2.0.1(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
@ -6158,6 +6400,18 @@ snapshots:
gar@1.0.4:
optional: true
gauge@3.0.2:
dependencies:
aproba: 2.1.0
color-support: 1.1.3
console-control-strings: 1.1.0
has-unicode: 2.0.1
object-assign: 4.1.1
signal-exit: 3.0.7
string-width: 4.2.3
strip-ansi: 6.0.1
wide-align: 1.1.5
gensync@1.0.0-beta.2: {}
get-caller-file@2.0.5: {}
@ -6310,6 +6564,8 @@ snapshots:
dependencies:
has-symbols: 1.1.0
has-unicode@2.0.1: {}
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
@ -6656,6 +6912,10 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
make-dir@3.1.0:
dependencies:
semver: 6.3.1
make-fetch-happen@10.2.1(bluebird@3.7.2)(supports-color@8.1.1):
dependencies:
agentkeepalive: 4.6.0
@ -6833,8 +7093,17 @@ snapshots:
node-gyp-build@4.8.4: {}
node-pre-gyp-github@1.4.6:
dependencies:
'@octokit/rest': 20.1.1
commander: 12.0.0
node-releases@2.0.51: {}
nopt@5.0.0:
dependencies:
abbrev: 1.1.1
nopt@6.0.0:
dependencies:
abbrev: 1.1.1
@ -6852,6 +7121,15 @@ snapshots:
dependencies:
path-key: 2.0.1
npmlog@5.0.1:
dependencies:
are-we-there-yet: 2.0.0
console-control-strings: 1.1.0
gauge: 3.0.2
set-blocking: 2.0.0
object-assign@4.1.1: {}
object-inspect@1.13.4: {}
object-keys@1.1.1: {}
@ -7245,6 +7523,8 @@ snapshots:
type-fest: 0.13.1
optional: true
set-blocking@2.0.0: {}
set-function-length@1.2.2:
dependencies:
define-data-property: 1.1.4
@ -7538,6 +7818,11 @@ snapshots:
tslib: 1.14.1
typescript: 4.5.5
tsutils@3.21.0(typescript@4.9.5):
dependencies:
tslib: 1.14.1
typescript: 4.9.5
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
@ -7588,6 +7873,8 @@ snapshots:
typescript@4.5.5: {}
typescript@4.9.5: {}
typescript@5.4.5: {}
uint8array-extras@1.5.0: {}
@ -7599,12 +7886,15 @@ snapshots:
has-symbols: 1.1.0
which-boxed-primitive: 1.1.1
undici-types@5.26.5: {}
undici-types@6.21.0: {}
undici-types@7.12.0: {}
undici-types@7.16.0: {}
undici@7.29.0:
optional: true
unique-filename@2.0.1:
dependencies:
unique-slug: 3.0.0
@ -7652,6 +7942,10 @@ snapshots:
spdx-correct: 3.2.0
spdx-expression-parse: 3.0.1
vite-plugin-native-modules@2.3.1(vite@5.4.20(@types/node@24.10.13)(terser@5.49.0)):
dependencies:
vite: 5.4.20(@types/node@24.10.13)(terser@5.49.0)
vite@5.4.20(@types/node@24.10.13)(terser@5.49.0):
dependencies:
esbuild: 0.21.5
@ -7768,6 +8062,10 @@ snapshots:
dependencies:
isexe: 2.0.0
wide-align@1.1.5:
dependencies:
string-width: 4.2.3
winreg@1.2.4: {}
word-wrap@1.2.5: {}

View File

@ -1,3 +1,6 @@
packages:
- 'node-pipewire'
allowBuilds:
bufferutil: true
electron: true
@ -8,8 +11,8 @@ allowBuilds:
nodeLinker: hoisted
blockExoticSubdeps: false # required to make discord-rpc work
blockExoticSubdeps: false # required to make discord-rpc work
# Override for node 26 bug
overrides:
yauzl: ^3.3.1
yauzl: ^3.3.1

2
src/constants.ts Normal file
View File

@ -0,0 +1,2 @@
export const sinkName = "stoat-virtual-sink";
export const sourceName = "stoat-virtual-source";

View File

@ -6,6 +6,7 @@ import started from "electron-squirrel-startup";
import { config } from "./native/config";
import { initDiscordRpc } from "./native/discordRpc";
import { initTray } from "./native/tray";
import { initVirtualMic } from "./native/virtualMic";
import { BUILD_URL, createMainWindow, mainWindow } from "./native/window";
// Squirrel-specific logic
@ -51,6 +52,7 @@ if (acquiredLock) {
initTray();
initDiscordRpc();
initVirtualMic();
// Windows specific fix for notifications
if (process.platform === "win32") {

139
src/native/virtualMic.ts Normal file
View File

@ -0,0 +1,139 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// Disable any checks because node-pipewire doesn't have types for our submodule
import { app, ipcMain } from "electron";
import { sinkName, sourceName } from "../constants";
const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
function getPids() {
return app.getAppMetrics().map((proc) => proc.pid ?? -1);
}
export const isWayland =
process.platform === "linux" &&
(process.env.XDG_SESSION_TYPE === "wayland" || !!process.env.WAYLAND_DISPLAY);
ipcMain.handle("getIsWayland", () => isWayland);
export async function initVirtualMic() {
// Only available on Wayland
if (!isWayland) return;
try {
const {
createPwThread,
createSink,
createSource,
getClients,
getNodes,
linkNodesNameToId,
//@ts-expect-error This module may not be found on non-linux builds.
} = await import("node-pipewire"); //eslint-disable-line
createPwThread();
// Wait for pipewire thread to start and gather neccessary data
await delay(100);
let nodes = getNodes();
let sinkFound = false;
let sourceFound = false;
for (const node of nodes) {
if (node.name === sinkName) {
sinkFound = true;
}
if (node.name === sourceName) {
sourceFound = true;
}
}
if (!sinkFound) {
createSink(sinkName, ["FL", "FR"], false);
}
if (!sourceFound) {
createSource(sourceName, ["FL", "FR"], false);
}
// Wait for source and sink to save
await delay(100);
const appName = app.getName();
nodes = getNodes();
const savedNodes: Record<number, any> = {};
const sourceNode = nodes.filter((node: any) => node.name === sourceName)[0];
const sinkNode = nodes.filter((node: any) => node.name === sinkName)[0];
linkNodesNameToId(sinkNode.name, sourceNode.id, false);
setInterval(() => {
const ourClients: Record<number, any> = {};
const paClients: any[] = [];
const pids = getPids();
const clients = getClients();
for (const client of clients) {
// If the client belongs to one of the electton processes
if (pids.includes(client.pid)) {
ourClients[client.pid] = client;
}
// If the client is a pulse audio client made on behalf of this app
if (client.application_name === appName) {
paClients.push(client);
}
}
nodes = getNodes()
// Only choose output streams
.filter(
(node: any) => node.props["media.class"] === "Stream/Output/Audio",
)
// Ignore any nodes from electron's processes
.filter(
(node: any) =>
!Object.values(ourClients)
.map((client) => client.id)
.includes(Number(node.props["client.id"])),
)
// Ignore any nodes from pulse audio processes for the app
.filter(
(node: any) =>
!paClients
.map((client) => client.id)
.includes(Number(node.props["client.id"])),
);
for (const node of nodes) {
const idAsNum = Number(node.id);
// If this node hasn't been seen before (ie. new node)
if (!savedNodes[idAsNum]) {
// Link all of the new node's outputs to our virtual sink
linkNodesNameToId(node.name, sinkNode.id, false);
savedNodes[idAsNum] = node;
}
}
// Cleanup savedNodes for nodes that are gone
for (const id in savedNodes) {
const asNum = Number(id);
let found = false;
for (const node of nodes) {
if (node.id === asNum) {
found = true;
break;
}
}
if (!found) {
savedNodes[asNum] = void 0;
}
}
}, 1000);
} catch {
console.log(
"node-pipewire failed to load. Screen share audio will not work on linux wayland.",
);
}
}

View File

@ -200,8 +200,6 @@ export function createMainWindow() {
.then((sources) => {
// Shortcut for linux wayland.
if (sources.length == 1) {
// TODO: Get audio to work with wayland
// See vencord for an implementation using a virtual microphone.
request.audioRequested
? callback({
video: sources[0],

View File

@ -32,4 +32,6 @@ contextBridge.exposeInMainWorld("native", {
},
screenPickerCallback: (idx: number, audio: boolean) =>
ipcRenderer.send("screenPickerCallback", idx, audio),
isWayland: () => ipcRenderer.invoke("getIsWayland"),
});

View File

@ -1,4 +1,15 @@
import { defineConfig } from "vite";
import nativePlugin from "vite-plugin-native-modules";
// https://vitejs.dev/config
export default defineConfig({});
export default defineConfig({
plugins: [nativePlugin()],
build: {
commonjsOptions: {
include: [/node-pipewire/, /node_modules/],
},
rollupOptions: {
external: ["node-pipewire"],
},
},
});